diff --git a/src/dfm-io/dfm-io/denumerator.cpp b/src/dfm-io/dfm-io/denumerator.cpp index 6c129566..36531169 100644 --- a/src/dfm-io/dfm-io/denumerator.cpp +++ b/src/dfm-io/dfm-io/denumerator.cpp @@ -446,12 +446,29 @@ char *DEnumeratorPrivate::filePath(const QUrl &url) QUrl DEnumeratorPrivate::buildUrl(const QUrl &url, const char *fileName) { - QString path; - if (url.path() == "/") { - path = "/" + QString(fileName); + // 防御空指针,避免std::string或QByteArray构造时崩溃 + if (!fileName) { + return QUrl(); + } + + // 拦截路径遍历攻击,防止恶意文件名越权 + QByteArray fileNameBa(fileName); + if (fileNameBa.contains('/') || fileNameBa.contains('\\') || fileNameBa == "." || fileNameBa == "..") { + return QUrl(); + } + + QByteArray path; + QString urlPath = url.path(); + + if (urlPath == "/" || urlPath.isEmpty()) { + path = QByteArray("/") + fileNameBa; } else { - QString dirPath = url.path(); - path = dirPath.endsWith('/') ? dirPath + QString(fileName) : dirPath + "/" + QString(fileName); + QByteArray dirPath = urlPath.toUtf8(); + if (!dirPath.endsWith('/')) { + dirPath.append('/'); + } + // 使用QByteArray进行底层字节数组拼接,避免QString剥离BOM (efbbbf) + path = dirPath + fileNameBa; } // 保留原始 URL 的 scheme 和 host,而不是假定为本地文件 diff --git a/src/dfm-io/dfm-io/dfileinfo.cpp b/src/dfm-io/dfm-io/dfileinfo.cpp index 25533406..ceb1e97c 100644 --- a/src/dfm-io/dfm-io/dfileinfo.cpp +++ b/src/dfm-io/dfm-io/dfileinfo.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include @@ -281,6 +280,24 @@ void DFileInfoPrivate::queryInfoAsync(int ioPriority, DFileInfo::InitQuerierAsyn g_file_query_info_async(this->gfile, attributes, GFileQueryInfoFlags(flag), ioPriority, gcancellable, queryInfoAsyncCallback, dataOp); } +bool DFileInfoPrivate::ensureStatxCached() const +{ + if (statxCached) + return statxValid; + + statxCached = true; + + const QUrl &url = q->uri(); + if (!url.isLocalFile()) + return false; + + unsigned mask = STATX_BASIC_STATS | STATX_BTIME; + int ret = statx(AT_FDCWD, url.path().toStdString().data(), + AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, mask, &statxBuf); + statxValid = (ret == 0); + return statxValid; +} + QVariant DFileInfoPrivate::attributesBySelf(DFileInfo::AttributeID id) { QVariant retValue; @@ -295,16 +312,10 @@ QVariant DFileInfoPrivate::attributesBySelf(DFileInfo::AttributeID id) return QVariant(); uint64_t ret = g_file_info_get_attribute_uint64(gfileinfo, key.c_str()); if (ret == 0) { - struct statx statxBuffer; - unsigned mask = STATX_BASIC_STATS | STATX_BTIME; - const QUrl &url = q->uri(); - if (!url.isLocalFile()) - return QVariant(); - int ret = statx(AT_FDCWD, url.path().toStdString().data(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, mask, &statxBuffer); - if (ret != 0) + if (!ensureStatxCached()) return QVariant(); - return quint64(statxBuffer.stx_btime.tv_sec); + return quint64(statxBuf.stx_btime.tv_sec); } return qulonglong(ret); } @@ -314,16 +325,10 @@ QVariant DFileInfoPrivate::attributesBySelf(DFileInfo::AttributeID id) return QVariant(); uint32_t ret = g_file_info_get_attribute_uint32(gfileinfo, key.c_str()); if (ret == 0) { - struct statx statxBuffer; - unsigned mask = STATX_BASIC_STATS | STATX_BTIME; - const QUrl &url = q->uri(); - if (!url.isLocalFile()) - return QVariant(); - int ret = statx(AT_FDCWD, url.path().toStdString().data(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, mask, &statxBuffer); - if (ret != 0) + if (!ensureStatxCached()) return QVariant(); - return statxBuffer.stx_btime.tv_nsec / 1000000; + return statxBuf.stx_btime.tv_nsec / 1000000; } return QVariant(ret); } @@ -333,16 +338,10 @@ QVariant DFileInfoPrivate::attributesBySelf(DFileInfo::AttributeID id) return QVariant(); uint64_t ret = g_file_info_get_attribute_uint64(gfileinfo, key.c_str()); if (ret == 0) { - struct statx statxBuffer; - unsigned mask = STATX_BASIC_STATS | STATX_BTIME; - const QUrl &url = q->uri(); - if (!url.isLocalFile()) - return QVariant(); - int ret = statx(AT_FDCWD, url.path().toStdString().data(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, mask, &statxBuffer); - if (ret != 0) + if (!ensureStatxCached()) return QVariant(); - return quint64(statxBuffer.stx_mtime.tv_sec); + return quint64(statxBuf.stx_mtime.tv_sec); } return qulonglong(ret); } @@ -352,16 +351,10 @@ QVariant DFileInfoPrivate::attributesBySelf(DFileInfo::AttributeID id) return QVariant(); uint32_t ret = g_file_info_get_attribute_uint32(gfileinfo, key.c_str()); if (ret == 0) { - struct statx statxBuffer; - unsigned mask = STATX_BASIC_STATS | STATX_BTIME; - const QUrl &url = q->uri(); - if (!url.isLocalFile()) - return QVariant(); - int ret = statx(AT_FDCWD, url.path().toStdString().data(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, mask, &statxBuffer); - if (ret != 0) + if (!ensureStatxCached()) return QVariant(); - return statxBuffer.stx_mtime.tv_nsec / 1000000; + return statxBuf.stx_mtime.tv_nsec / 1000000; } return QVariant(ret); } @@ -371,16 +364,10 @@ QVariant DFileInfoPrivate::attributesBySelf(DFileInfo::AttributeID id) return QVariant(); uint64_t ret = g_file_info_get_attribute_uint64(gfileinfo, key.c_str()); if (ret == 0) { - struct statx statxBuffer; - unsigned mask = STATX_BASIC_STATS | STATX_BTIME; - const QUrl &url = q->uri(); - if (!url.isLocalFile()) - return QVariant(); - int ret = statx(AT_FDCWD, url.path().toStdString().data(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, mask, &statxBuffer); - if (ret != 0) + if (!ensureStatxCached()) return QVariant(); - return quint64(statxBuffer.stx_atime.tv_sec); + return quint64(statxBuf.stx_atime.tv_sec); } return qulonglong(ret); } @@ -390,16 +377,10 @@ QVariant DFileInfoPrivate::attributesBySelf(DFileInfo::AttributeID id) return QVariant(); uint32_t ret = g_file_info_get_attribute_uint32(gfileinfo, key.c_str()); if (ret == 0) { - struct statx statxBuffer; - unsigned mask = STATX_BASIC_STATS | STATX_BTIME; - const QUrl &url = q->uri(); - if (!url.isLocalFile()) - return QVariant(); - int ret = statx(AT_FDCWD, url.path().toStdString().data(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, mask, &statxBuffer); - if (ret != 0) + if (!ensureStatxCached()) return QVariant(); - return statxBuffer.stx_atime.tv_nsec / 1000000; + return statxBuf.stx_atime.tv_nsec / 1000000; } return QVariant(ret); } diff --git a/src/dfm-io/dfm-io/private/dfileinfo_p.h b/src/dfm-io/dfm-io/private/dfileinfo_p.h index 348ed6df..1547a6b9 100644 --- a/src/dfm-io/dfm-io/private/dfileinfo_p.h +++ b/src/dfm-io/dfm-io/private/dfileinfo_p.h @@ -19,6 +19,7 @@ #include #include +#include BEGIN_IO_NAMESPACE @@ -55,6 +56,7 @@ class DFileInfoPrivate : public QObject, public QSharedData QVariant attributesBySelf(DFileInfo::AttributeID id); QVariant attributesFromUrl(DFileInfo::AttributeID id); void checkAndResetCancel(); + [[nodiscard]] bool ensureStatxCached() const; [[nodiscard]] DFileFuture *initQuerierAsync(int ioPriority, QObject *parent = nullptr) const; [[nodiscard]] QFuture refreshAsync(); @@ -94,6 +96,11 @@ class DFileInfoPrivate : public QObject, public QSharedData std::atomic_bool stoped { false }; std::atomic_bool fileExists { false }; QMap caches; + + // statx 缓存:6 个时间属性 case 共享一次 statx 调用,避免重复系统调用 + mutable struct statx statxBuf {}; + mutable bool statxCached { false }; + mutable bool statxValid { false }; std::atomic_bool cacheing { false }; std::atomic_bool refreshing { false }; QMutex mutex;