diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index b5df6179272..4e43b4e6bd7 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -314,9 +314,9 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t) const QStringList sourceFilesFilter = sourceFilesForImplicitRulesFilter(); QStringList fixifiedSourceDirs = fileFixify(QList(source_directories.constBegin(), source_directories.constEnd()), FileFixifyAbsolute); fixifiedSourceDirs.removeDuplicates(); - constexpr auto filters = QDir::Files | QDir::NoDotAndDotDot; + using F = QDirListing::IteratorFlag; for (const QString &sourceDir : std::as_const(fixifiedSourceDirs)) { - for (const auto &dirEntry : QDirListing(sourceDir, sourceFilesFilter, filters)) { + for (const auto &dirEntry : QDirListing(sourceDir, sourceFilesFilter, F::FilesOnly)) { QString &duplicate = fileNames[dirEntry.completeBaseName()]; if (duplicate.isNull()) { duplicate = dirEntry.filePath(); diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 21925358677..82d47f59811 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -1293,9 +1293,8 @@ void VcprojGenerator::initDeploymentTool() } int pathSize = searchPath.size(); - constexpr auto filters = QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks; using F = QDirListing::IteratorFlag; - QDirListing dirList(searchPath, QStringList{nameFilter}, filters, F::Recursive); + QDirListing dirList(searchPath, QStringList{nameFilter}, F::FilesOnly | F::Recursive); // foreach dirIterator-entry in d for (const auto &dirEntry : dirList) { const QString absoluteItemPath = Option::fixPathToTargetOS(dirEntry.absolutePath()); diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp index 231bf48d26b..0694daa6cba 100644 --- a/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp @@ -35,7 +35,8 @@ for (const auto &dirEntry : dirList) { { //! [2] -QDirListing audioFileIt(u"/home/johndoe/"_s, {"*.mp3", "*.wav"}, QDir::Files); +QDirListing audioFileIt(u"/home/johndoe/"_s, QStringList{u"*.mp3"_s, u"*.wav"_s}, + QDirListing::IteratorFlag::FilesOnly); //! [2] } diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index ea5ce13b5eb..70e68be21c1 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -590,6 +590,21 @@ bool QAbstractFileEngine::isRelativePath() const \sa setFileName() */ QStringList QAbstractFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const +{ + QStringList ret; +#ifdef QT_BOOTSTRAPPED + Q_UNUSED(filters); + Q_UNUSED(filterNames); + Q_UNREACHABLE_RETURN(ret); +#else + for (const auto &dirEntry : QDirListing(fileName(), filterNames, filters.toInt())) + ret.emplace_back(dirEntry.fileName()); + return ret; +#endif +} + +QStringList QAbstractFileEngine::entryList(QDirListing::IteratorFlags filters, + const QStringList &filterNames) const { QStringList ret; #ifdef QT_BOOTSTRAPPED @@ -902,6 +917,15 @@ QAbstractFileEngineIterator::QAbstractFileEngineIterator(const QString &path, QD { } +QAbstractFileEngineIterator::QAbstractFileEngineIterator(const QString &path, + QDirListing::IteratorFlags filters, + const QStringList &nameFilters) + : m_listingFilters(filters), + m_nameFilters(nameFilters), + m_path(appendSlashIfNeeded(path)) +{ +} + /*! Destroys the QAbstractFileEngineIterator. @@ -1017,6 +1041,16 @@ QAbstractFileEngine::beginEntryList(const QString &path, QDir::Filters filters, return {}; } +QAbstractFileEngine::IteratorUniquePtr +QAbstractFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) +{ + Q_UNUSED(path); + Q_UNUSED(filters); + Q_UNUSED(filterNames); + return {}; +} + /*! Reads a number of characters from the file into \a data. At most \a maxlen characters will be read. diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index b2e0b248da7..5e6232af71a 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -18,6 +18,7 @@ #include #include "QtCore/qfile.h" #include "QtCore/qdir.h" +#include "QtCore/qdirlisting.h" #include #include @@ -106,6 +107,8 @@ public: virtual bool caseSensitive() const; virtual bool isRelativePath() const; virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const; + virtual QStringList entryList(QDirListing::IteratorFlags filters, + const QStringList &filterNames) const; virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const; virtual bool setPermissions(uint perms); virtual QByteArray id() const; @@ -128,6 +131,10 @@ public: beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames); virtual IteratorUniquePtr endEntryList() { return {}; } + virtual IteratorUniquePtr + beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames); + virtual qint64 read(char *data, qint64 maxlen); virtual qint64 readLine(char *data, qint64 maxlen); virtual qint64 write(const char *data, qint64 len); @@ -203,6 +210,8 @@ class Q_CORE_EXPORT QAbstractFileEngineIterator public: QAbstractFileEngineIterator(const QString &path, QDir::Filters filters, const QStringList &nameFilters); + QAbstractFileEngineIterator(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &nameFilters); virtual ~QAbstractFileEngineIterator(); virtual bool advance() = 0; @@ -225,6 +234,7 @@ private: friend class QDirListingPrivate; QDir::Filters m_filters; + QDirListing::IteratorFlags m_listingFilters; QStringList m_nameFilters; QString m_path; }; diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 05947f33804..3e1c778e98b 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -347,8 +347,10 @@ inline void QDirPrivate::initFileLists(const QDir &dir) const QMutexLocker locker(&fileCache.mutex); if (!fileCache.fileListsInitialized) { QFileInfoList l; - for (const auto &dirEntry : QDirListing(dir)) + for (const auto &dirEntry : QDirListing(dir.path(), dir.nameFilters(), + dir.filter().toInt())) { l.emplace_back(dirEntry.fileInfo()); + } sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos); fileCache.fileListsInitialized = true; @@ -1427,7 +1429,7 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters, } } - QDirListing dirList(d->dirEntry.filePath(), nameFilters, filters); + QDirListing dirList(d->dirEntry.filePath(), nameFilters, filters.toInt()); QStringList ret; if (needsSorting) { QFileInfoList l; @@ -1473,7 +1475,7 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter } QFileInfoList l; - for (const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, filters)) + for (const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, filters.toInt())) l.emplace_back(dirEntry.fileInfo()); QFileInfoList ret; d->sortFileList(sort, l, nullptr, &ret); @@ -1645,8 +1647,7 @@ bool QDir::removeRecursively() bool success = true; const QString dirPath = path(); // not empty -- we must empty it first - constexpr auto dirFilters = QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot; - for (const auto &dirEntry : QDirListing(dirPath, dirFilters)) { + for (const auto &dirEntry : QDirListing(dirPath, QDirListing::IteratorFlag::IncludeHidden)) { const QString &filePath = dirEntry.filePath(); bool ok; if (dirEntry.isDir() && !dirEntry.isSymLink()) { @@ -1969,7 +1970,7 @@ bool QDir::exists(const QString &name) const bool QDir::isEmpty(Filters filters) const { Q_D(const QDir); - QDirListing dirList(d->dirEntry.filePath(), d->nameFilters, filters); + QDirListing dirList(d->dirEntry.filePath(), d->nameFilters, filters.toInt()); return dirList.cbegin() == dirList.cend(); } #endif // !QT_BOOTSTRAPPED diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h index 53c0900f95c..9430149e1c1 100644 --- a/src/corelib/io/qdir.h +++ b/src/corelib/io/qdir.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -244,6 +245,7 @@ private: Q_DECLARE_EQUALITY_COMPARABLE(QDir) friend class QDirIterator; friend class QDirListing; + friend class QDirListingPrivate; // Q_DECLARE_PRIVATE equivalent for shared data pointers QDirPrivate *d_func(); const QDirPrivate *d_func() const { return d_ptr.constData(); } diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index 3604e673e2f..f539fd3bfaf 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -86,44 +86,12 @@ using namespace Qt::StringLiterals; class QDirIteratorPrivate { - static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags) - { - using F = QDirListing::IteratorFlag; - QDirListing::IteratorFlags listerFlags; - - if (flags & QDirIterator::NoIteratorFlags) - listerFlags.setFlag(F::NoFlag); - if (flags & QDirIterator::FollowSymlinks) - listerFlags.setFlag(F::FollowSymlinks); - if (flags & QDirIterator::Subdirectories) - listerFlags.setFlag(F::Recursive); - - return listerFlags; - } - public: - QDirIteratorPrivate(const QDir &dir, QDirIterator::IteratorFlags flags) - : lister(dir, toDirListingFlags(flags)) - { - init(); - } - QDirIteratorPrivate(const QString &path, QDirIterator::IteratorFlags flags) - : lister(path, toDirListingFlags(flags)) - { - init(); - } - QDirIteratorPrivate(const QString &path, QDir::Filters filters, - QDirIterator::IteratorFlags flags) - : lister(path, filters, toDirListingFlags(flags)) - { - init(); - } - QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, QDir::Filters filters, - QDirIterator::IteratorFlags flags) - : lister(path, nameFilters, filters, toDirListingFlags(flags)) - { - init(); - } + QDirIteratorPrivate(const QString &path, const QStringList &nameFilters = {}, + QDir::Filters filters = QDir::NoFilter, + QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags) + : lister(path, nameFilters, filters.toInt(), flags.toInt()) + { init(); } void init() { @@ -162,7 +130,7 @@ public: \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) - : d(new QDirIteratorPrivate(dir, flags)) + : d(new QDirIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags)) { } @@ -180,7 +148,7 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, filters, flags)) + : d(new QDirIteratorPrivate(path, {}, filters, flags)) { } @@ -197,7 +165,7 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, flags)) + : d(new QDirIteratorPrivate(path, {}, QDir::NoFilter, flags)) { } diff --git a/src/corelib/io/qdirlisting.cpp b/src/corelib/io/qdirlisting.cpp index 9bfd414a6a9..408cccaaf56 100644 --- a/src/corelib/io/qdirlisting.cpp +++ b/src/corelib/io/qdirlisting.cpp @@ -15,7 +15,7 @@ directory contents recursively, and following symbolic links. Unlike QDir::entryList(), QDirListing does not support sorting. - The QDirListing constructor takes a QDir or a directory path as + The QDirListing constructor takes a directory path string as argument. Here's how to iterate over all entries recursively: \snippet code/src_corelib_io_qdirlisting.cpp 0 @@ -45,24 +45,73 @@ /*! \enum QDirListing::IteratorFlag - This enum class describes flags can be used to configure the behavior of - QDirListing. These flags can be bitwise OR'ed together. + This enum class describes flags that can be used to configure the behavior + of QDirListing. Values from this enumerator can be bitwise OR'ed together. - \value NoFlag The default value, representing no flags. The iterator - will return entries for the assigned path. + \value Default + List all files, directories and symbolic links, including broken + symlinks (where the target doesn't exist). + Hidden files and directories and the special entries \c{.} and \c{..} + aren't listed by default. - \value FollowSymlinks When combined with Recursive, this flag enables - iterating through all subdirectories of the assigned path, following - all symbolic links. Symbolic link loops (e.g., link => . or link => - ..) are automatically detected and ignored. + \value ExcludeFiles + Don't list regular files. When combined with ResolveSymlinks, symbolic + links to regular files will be excluded too. - \value Recursive List entries inside all subdirectories as well. + \value ExcludeDirs + Don't list directories. When combined with ResolveSymlinks, symbolic + links to directories will be excluded too. + + \value ExcludeSpecial + Don't list special system files: + \list + \li On Unix: an entry that is not a directory, regular file or + symbolic link (including broken symlinks). That is, FIFO, + socket, character device, or block device. + \li On Windows: \c {.lnk}. + \endlist + + \value ResolveSymlinks + Filter symbolic links based on the type of the target of the link, + rather than the symbolic link itself. With this flag, broken symbolic + links (where the target doesn't exist) are excluded. This flag is + ignored on operating systems that don't support symbolic links. + + \value FilesOnly + Only regular files will be listed. When combined with ResolveSymlinks, + symbolic links to files will also be listed. + + \value DirsOnly + Only directories will be listed. When combined with ResolveSymlinks, + symbolic links to directories will also be listed. + + \value IncludeHidden + List hidden entries. When combined with Recursive, the iteration will + recurse into hidden sub-directories as well. + + \value IncludeDotAndDotDot + List the \c {.} and \c{..} special entries. + + \value CaseSensitive + The file glob patterns in the name filters passed to the QDirListing + constructor, will be matched case sensitively (for details, see + QDir::setNameFilters()). + + \value Recursive + List entries inside all sub-directories as well. When combined with + FollowDirSymlinks, symbolic links to directories will be iterated too. + + \value FollowDirSymlinks + When combined with Recursive, symbolic links to directories will be + iterated too. Symbolic link loops (e.g., link => . or link => ..) are + automatically detected and ignored. */ #include "qdirlisting.h" #include "qdirentryinfo_p.h" #include "qdir_p.h" +#include "qdiriterator.h" #include "qabstractfileengine_p.h" #include @@ -85,6 +134,21 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags) +{ + using F = QDirListing::IteratorFlag; + QDirListing::IteratorFlags listerFlags; + + if (flags & QDirIterator::NoIteratorFlags) + listerFlags.setFlag(F::Default); + if (flags & QDirIterator::FollowSymlinks) + listerFlags.setFlag(F::FollowDirSymlinks); + if (flags & QDirIterator::Subdirectories) + listerFlags.setFlag(F::Recursive); + + return listerFlags; +} + class QDirListingPrivate { public: @@ -100,15 +164,32 @@ public: bool matchesFilters(QDirEntryInfo &data) const; bool hasIterators() const; + bool matchesLegacyFilters(QDirEntryInfo &data) const; + void setLegacyFilters(QDir::Filters dirFilters, QDirIterator::IteratorFlags dirIteratorFlags) + { + useLegacyFilters = true; + legacyDirFilters = dirFilters; + iteratorFlags = toDirListingFlags(dirIteratorFlags); + } + std::unique_ptr engine; QDirEntryInfo initialEntryInfo; QStringList nameFilters; - QDir::Filters filters; QDirListing::IteratorFlags iteratorFlags; QDirEntryInfo currentEntryInfo; + bool useLegacyFilters = false; + QDir::Filters legacyDirFilters; + #if QT_CONFIG(regularexpression) QList nameRegExps; + bool regexMatchesName(const QString &fileName) const + { + if (nameRegExps.isEmpty()) + return true; + auto hasMatch = [&fileName](const auto &re) { return re.match(fileName).hasMatch(); }; + return std::any_of(nameRegExps.cbegin(), nameRegExps.cend(), hasMatch); + } #endif using FEngineIteratorPtr = std::unique_ptr; @@ -127,13 +208,21 @@ void QDirListingPrivate::init(bool resolveEngine = true) if (nameFilters.contains("*"_L1)) nameFilters.clear(); - if (filters == QDir::NoFilter) - filters = QDir::AllEntries; + if (useLegacyFilters) { + if (legacyDirFilters == QDir::NoFilter) + legacyDirFilters = QDir::AllEntries; + } #if QT_CONFIG(regularexpression) nameRegExps.reserve(nameFilters.size()); - const auto cs = filters.testAnyFlags(QDir::CaseSensitive) ? Qt::CaseSensitive - : Qt::CaseInsensitive; + + const bool isCase = [this] { + if (useLegacyFilters) + return legacyDirFilters.testAnyFlags(QDir::CaseSensitive); + return iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::CaseSensitive); + }(); + + const auto cs = isCase ? Qt::CaseSensitive : Qt::CaseInsensitive; for (const auto &filter : nameFilters) nameRegExps.emplace_back(QRegularExpression::fromWildcard(filter, cs)); #endif @@ -171,7 +260,7 @@ void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo) }(); - if (iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::FollowSymlinks)) { + if (iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::FollowDirSymlinks)) { // Stop link loops if (visitedLinks.hasSeen(entryInfo.canonicalFilePath())) return; @@ -179,7 +268,7 @@ void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo) if (engine) { engine->setFileName(path); - if (auto it = engine->beginEntryList(path, filters, nameFilters)) { + if (auto it = engine->beginEntryList(path, iteratorFlags, nameFilters)) { fileEngineIterators.emplace_back(std::move(it)); } else { // No iterator; no entry list. @@ -191,7 +280,7 @@ void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo) fentry = &entryInfo.fileInfoOpt->d_ptr->fileEntry; else fentry = &entryInfo.entry; - nativeIterators.emplace_back(std::make_unique(*fentry, filters)); + nativeIterators.emplace_back(std::make_unique(*fentry, iteratorFlags)); #else qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!"); #endif @@ -201,6 +290,8 @@ void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo) bool QDirListingPrivate::entryMatches(QDirEntryInfo &entryInfo) { checkAndPushDirectory(entryInfo); + if (useLegacyFilters) + return matchesLegacyFilters(entryInfo); return matchesFilters(entryInfo); } @@ -260,6 +351,11 @@ void QDirListingPrivate::advance() } } +static bool isDotOrDotDot(QStringView fileName) +{ + return fileName == "."_L1 || fileName == ".."_L1; +} + void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo) { using F = QDirListing::IteratorFlag; @@ -272,16 +368,20 @@ void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo) return; // Follow symlinks only when asked - if (!iteratorFlags.testAnyFlags(F::FollowSymlinks) && entryInfo.isSymLink()) + if (!iteratorFlags.testAnyFlags(F::FollowDirSymlinks) && entryInfo.isSymLink()) return; // Never follow . and .. - const QString &fileName = entryInfo.fileName(); - if ("."_L1 == fileName || ".."_L1 == fileName) + if (isDotOrDotDot(entryInfo.fileName())) return; // No hidden directories unless requested - if (!filters.testAnyFlags(QDir::AllDirs | QDir::Hidden) && entryInfo.isHidden()) + const bool includeHidden = [this]() { + if (useLegacyFilters) + return legacyDirFilters.testAnyFlags(QDir::AllDirs | QDir::Hidden); + return iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::IncludeHidden); + }(); + if (!includeHidden && entryInfo.isHidden()) return; pushDirectory(entryInfo); @@ -290,21 +390,21 @@ void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo) /*! \internal - This functions returns \c true if the current entry matches the filters - (i.e., the current entry will be returned as part of the directory - iteration); otherwise, \c false is returned. + Works the same as matchesFilters() but for the old QDir::Filters. */ -bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const +bool QDirListingPrivate::matchesLegacyFilters(QDirEntryInfo &entryInfo) const { + Q_ASSERT(useLegacyFilters); + const QString &fileName = entryInfo.fileName(); if (fileName.isEmpty()) return false; + auto &filters = legacyDirFilters; + // filter . and ..? + const bool dotOrDotDot = isDotOrDotDot(fileName); const qsizetype fileNameSize = fileName.size(); - const bool dotOrDotDot = fileName[0] == u'.' - && ((fileNameSize == 1) - ||(fileNameSize == 2 && fileName[1] == u'.')); if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1) return false; if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2) @@ -313,11 +413,8 @@ bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const // name filter #if QT_CONFIG(regularexpression) // Pass all entries through name filters, except dirs if AllDirs is set - if (!nameRegExps.isEmpty() && !(filters.testAnyFlags(QDir::AllDirs) && entryInfo.isDir())) { - auto regexMatchesName = [&fileName](const auto &re) { - return re.match(fileName).hasMatch(); - }; - if (std::none_of(nameRegExps.cbegin(), nameRegExps.cend(), regexMatchesName)) + if (!(filters.testAnyFlags(QDir::AllDirs) && entryInfo.isDir())) { + if (!regexMatchesName(fileName)) return false; } #endif @@ -371,6 +468,59 @@ bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const return true; } +/*! + \internal + + This function returns \c true if the current entry matches the filters + (i.e., the current entry will be returned as part of the directory + iteration); otherwise, \c false is returned. +*/ +bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const +{ + using F = QDirListing::IteratorFlag; + + const QString &fileName = entryInfo.fileName(); + if (fileName.isEmpty()) + return false; + + if (isDotOrDotDot(fileName)) // All done, other checks below don't matter in this case + return iteratorFlags.testAnyFlags(F::IncludeDotAndDotDot); + + // name filter +#if QT_CONFIG(regularexpression) + if (!regexMatchesName(fileName)) + return false; +#endif // QT_CONFIG(regularexpression) + + if (!iteratorFlags.testAnyFlag(F::IncludeHidden) && entryInfo.isHidden()) + return false; + + if (entryInfo.isSymLink()) { + // With ResolveSymlinks, we look at the type of the link's target, + // and exclude broken symlinks (where the target doesn't exist). + if (iteratorFlags.testAnyFlag(F::ResolveSymlinks)) { + if (!entryInfo.exists()) + return false; + } else if (iteratorFlags.testAnyFlags(F::FilesOnly) + || iteratorFlags.testAnyFlags(F::DirsOnly)) { + return false; // symlink is not a file or dir + } + } + + if (iteratorFlags.testAnyFlag(F::ExcludeSpecial) + && !entryInfo.isFile() && !entryInfo.isDir() && !entryInfo.isSymLink()) { + return false; + } + + if (iteratorFlags.testAnyFlags(F::ExcludeDirs) && entryInfo.isDir()) + return false; + + if (iteratorFlags.testAnyFlags(F::ExcludeFiles) && entryInfo.isFile()) + return false; + + return true; +} + bool QDirListingPrivate::hasIterators() const { if (engine) @@ -384,60 +534,12 @@ bool QDirListingPrivate::hasIterators() const } /*! - Constructs a QDirListing that can iterate over \a dir's entries, using - \a dir's name filters and the QDir::Filters set in \a dir. You can pass - options via \a flags to decide how the directory should be iterated. + Constructs a QDirListing that can iterate over \a path. - By default, \a flags is NoIteratorFlags, which provides the same behavior - as in QDir::entryList(). + You can pass options via \a flags to control how the directory should + be iterated. - The sorting in \a dir is ignored. - - \note To list symlinks that point to non existing files, QDir::System - must be set in \a dir's QDir::Filters. - - \sa IteratorFlags -*/ -QDirListing::QDirListing(const QDir &dir, IteratorFlags flags) - : d(new QDirListingPrivate) -{ - const QDirPrivate *other = dir.d_ptr.constData(); - d->initialEntryInfo.entry = other->dirEntry; - d->nameFilters = other->nameFilters; - d->filters = other->filters; - d->iteratorFlags = flags; - const bool resolveEngine = other->fileEngine ? true : false; - d->init(resolveEngine); -} - -/*! - Constructs a QDirListing that can iterate over \a path. Entries are - filtered according to \a filters. You can pass options via \a flags to - decide how the directory should be iterated. - - By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags, - which provides the same behavior as in QDir::entryList(). - - \note To list symlinks that point to non existing files, QDir::System - must be set in \a filters. - - \sa IteratorFlags -*/ -QDirListing::QDirListing(const QString &path, QDir::Filters filters, IteratorFlags flags) - : d(new QDirListingPrivate) -{ - d->initialEntryInfo.entry = QFileSystemEntry(path); - d->filters = filters; - d->iteratorFlags = flags; - d->init(); -} - -/*! - Constructs a QDirListing that can iterate over \a path. You can pass - options via \a flags to decide how the directory should be iterated. - - By default, \a flags is NoIteratorFlags, which provides the same behavior - as in QDir::entryList(). + By default, \a flags is IteratorFlag::Default. \sa IteratorFlags */ @@ -445,40 +547,57 @@ QDirListing::QDirListing(const QString &path, IteratorFlags flags) : d(new QDirListingPrivate) { d->initialEntryInfo.entry = QFileSystemEntry(path); - d->filters = QDir::NoFilter; d->iteratorFlags = flags; d->init(); } /*! - Constructs a QDirListing that can iterate over \a path, using \a - nameFilters and \a filters. You can pass options via \a flags to decide - how the directory should be iterated. + Constructs a QDirListing that can iterate over \a path. - By default, \a flags is NoIteratorFlags, which provides the same behavior - as QDir::entryList(). + You can pass options via \a flags to control how the directory should + be iterated. By default, \a flags is IteratorFlag::Default. + + The listed entries will be filtered according to the file glob patterns + in \a nameFilters (see QDir::setNameFilters() for more details). For example, the following iterator could be used to iterate over audio files: \snippet code/src_corelib_io_qdirlisting.cpp 2 - \note To list symlinks that point to non existing files, QDir::System - must be set in \a flags. - \sa IteratorFlags, QDir::setNameFilters() */ -QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, QDir::Filters filters, - IteratorFlags flags) +QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, IteratorFlags flags) : d(new QDirListingPrivate) { d->initialEntryInfo.entry = QFileSystemEntry(path); d->nameFilters = nameFilters; - d->filters = filters; d->iteratorFlags = flags; d->init(); } +/*! + \internal + + Only used by classes that still have to use QDir::Filters; for example, + QDir, such usage may be deprecated at some point. + + \a qdirFilters is converted to QDir::Filters and \a qdirIteratorFlags is + converted to QDirIterator::IteratorFlags (qdirlisting.h can't include + qdir.h or qdiriterator.h) and used to control the filtering of the + dir entries. +*/ +QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, uint qdirFilters, + uint qdirIteratorFlags) + : d(new QDirListingPrivate) +{ + d->initialEntryInfo.entry = QFileSystemEntry(path); + d->nameFilters = nameFilters; + d->setLegacyFilters(QDir::Filters::fromInt(qdirFilters), + QDirIterator::IteratorFlags::fromInt(qdirIteratorFlags)); + d->init(); +} + /*! Move constructor. Moves \a other into this QDirListing. @@ -497,6 +616,7 @@ QDirListing::QDirListing(QDirListing &&other) = default; */ QDirListing &QDirListing::operator=(QDirListing &&other) = default; + /*! Destroys the QDirListing. */ diff --git a/src/corelib/io/qdirlisting.h b/src/corelib/io/qdirlisting.h index 7b6ca470c48..3d462277811 100644 --- a/src/corelib/io/qdirlisting.h +++ b/src/corelib/io/qdirlisting.h @@ -5,7 +5,11 @@ #ifndef QDILISTING_H #define QDILISTING_H -#include +#include +#include +#include +#include +#include #include #include @@ -13,24 +17,32 @@ QT_BEGIN_NAMESPACE class QDirListingPrivate; +class QFileInfo; +class QDir; +class QTimeZone; class Q_CORE_EXPORT QDirListing { public: enum class IteratorFlag { - NoFlag = 0x0, - FollowSymlinks = 0x1, - Recursive = 0x2 + Default = 0x000000, + ExcludeFiles = 0x000004, + ExcludeDirs = 0x000008, + ExcludeSpecial = 0x000010, + ResolveSymlinks = 0x000020, + FilesOnly = ExcludeDirs | ExcludeSpecial, + DirsOnly = ExcludeFiles | ExcludeSpecial, + IncludeHidden = 0x000040, + IncludeDotAndDotDot = 0x000080, + CaseSensitive = 0x000100, + Recursive = 0x000400, + FollowDirSymlinks = 0x000800, }; Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag) - QDirListing(const QDir &dir, IteratorFlags flags = IteratorFlag::NoFlag); - QDirListing(const QString &path, IteratorFlags flags = IteratorFlag::NoFlag); - QDirListing(const QString &path, QDir::Filters filter, - IteratorFlags flags = IteratorFlag::NoFlag); - QDirListing(const QString &path, const QStringList &nameFilters, - QDir::Filters filters = QDir::NoFilter, - IteratorFlags flags = IteratorFlag::NoFlag); + explicit QDirListing(const QString &path, IteratorFlags flags = IteratorFlag::Default); + explicit QDirListing(const QString &path, const QStringList &nameFilters, + IteratorFlags flags = IteratorFlag::Default); QDirListing(QDirListing &&); QDirListing &operator=(QDirListing &&); @@ -65,11 +77,15 @@ public: QString absolutePath() const; qint64 size() const; - QDateTime birthTime(const QTimeZone &tz) const { return fileTime(QFile::FileBirthTime, tz); } - QDateTime metadataChangeTime(const QTimeZone &tz) const { return fileTime(QFile::FileMetadataChangeTime, tz); } - QDateTime lastModified(const QTimeZone &tz) const { return fileTime(QFile::FileModificationTime, tz); } - QDateTime lastRead(const QTimeZone &tz) const { return fileTime(QFile::FileAccessTime, tz); } - QDateTime fileTime(QFile::FileTime type, const QTimeZone &tz) const; + QDateTime birthTime(const QTimeZone &tz) const + { return fileTime(QFileDevice::FileBirthTime, tz); } + QDateTime metadataChangeTime(const QTimeZone &tz) const + { return fileTime(QFileDevice::FileMetadataChangeTime, tz); } + QDateTime lastModified(const QTimeZone &tz) const + { return fileTime(QFileDevice::FileModificationTime, tz); } + QDateTime lastRead(const QTimeZone &tz) const + { return fileTime(QFileDevice::FileAccessTime, tz); } + QDateTime fileTime(QFileDevice::FileTime type, const QTimeZone &tz) const; }; class const_iterator @@ -111,8 +127,19 @@ public: private: Q_DISABLE_COPY(QDirListing) + // Private constructor that is used in deprecated code paths. + // `uint` instead of QDir::Filters and QDirIterator::IteratorFlags + // because qdir.h can't be included here; qdiriterator.h can't included + // either, because it includes qdir.h + QDirListing(const QString &path, const QStringList &nameFilters, uint dirFilters, + uint qdirIteratorFlags = 0); // QDirIterator::NoIteratorFlags == 0x0 + std::unique_ptr d; friend class QDir; + friend class QDirPrivate; + friend class QDirIteratorPrivate; + friend class QAbstractFileEngine; + friend class QFileInfoGatherer; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QDirListing::IteratorFlags) diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h index c55d5c6d317..59577f0a2a0 100644 --- a/src/corelib/io/qfilesystemiterator_p.h +++ b/src/corelib/io/qfilesystemiterator_p.h @@ -38,6 +38,7 @@ class QFileSystemIterator public: QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters); QFileSystemIterator(const QFileSystemEntry &entry); + QFileSystemIterator(const QFileSystemEntry &entry, QDirListing::IteratorFlags filters); ~QFileSystemIterator(); bool advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData); diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp index f06ff253442..774cf72b6f8 100644 --- a/src/corelib/io/qfilesystemiterator_unix.cpp +++ b/src/corelib/io/qfilesystemiterator_unix.cpp @@ -32,6 +32,10 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry) } } +QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDirListing::IteratorFlags) + : QFileSystemIterator(entry) +{} + QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters) : QFileSystemIterator(entry) { diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp index d2e3904af6d..1be8854d81a 100644 --- a/src/corelib/io/qfilesystemiterator_win.cpp +++ b/src/corelib/io/qfilesystemiterator_win.cpp @@ -42,6 +42,13 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi onlyDirs = true; } +QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, + QDirListing::IteratorFlags flags) + : QFileSystemIterator(entry) +{ + onlyDirs = flags.testAnyFlags(QDirListing::IteratorFlag::DirsOnly); +} + QFileSystemIterator::~QFileSystemIterator() { if (findFileHandle != INVALID_HANDLE_VALUE) diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 3d3af7468b3..2f9087bf6a3 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -798,6 +798,12 @@ QFSFileEngine::beginEntryList(const QString &path, QDir::Filters filters, return std::make_unique(path, filters, filterNames); } +QAbstractFileEngine::IteratorUniquePtr +QFSFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) +{ + return std::make_unique(path, filters, filterNames); +} #endif // QT_NO_FILESYSTEMITERATOR /*! diff --git a/src/corelib/io/qfsfileengine_iterator.cpp b/src/corelib/io/qfsfileengine_iterator.cpp index fb0332f7f33..bdb2ecdafe7 100644 --- a/src/corelib/io/qfsfileengine_iterator.cpp +++ b/src/corelib/io/qfsfileengine_iterator.cpp @@ -16,6 +16,13 @@ QFSFileEngineIterator::QFSFileEngineIterator(const QString &path, QDir::Filters { } +QFSFileEngineIterator::QFSFileEngineIterator(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) + : QAbstractFileEngineIterator(path, filters, filterNames), + nativeIterator(new QFileSystemIterator(QFileSystemEntry(path), filters)) +{ +} + QFSFileEngineIterator::~QFSFileEngineIterator() { } diff --git a/src/corelib/io/qfsfileengine_iterator_p.h b/src/corelib/io/qfsfileengine_iterator_p.h index b91c5d99734..22400abb7db 100644 --- a/src/corelib/io/qfsfileengine_iterator_p.h +++ b/src/corelib/io/qfsfileengine_iterator_p.h @@ -27,6 +27,8 @@ class QFSFileEngineIterator : public QAbstractFileEngineIterator { public: QFSFileEngineIterator(const QString &path, QDir::Filters filters, const QStringList &filterNames); + QFSFileEngineIterator(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames); ~QFSFileEngineIterator(); bool advance() override; diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index ba1ed0aadfb..5e77804606a 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -88,6 +88,8 @@ public: #ifndef QT_NO_FILESYSTEMITERATOR IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) override; + IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) override; #endif qint64 read(char *data, qint64 maxlen) override; diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 581e1e75ef1..83df4e1aec1 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -1589,6 +1589,13 @@ QResourceFileEngine::beginEntryList(const QString &path, QDir::Filters filters, return std::make_unique(path, filters, filterNames); } +QAbstractFileEngine::IteratorUniquePtr +QResourceFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) +{ + return std::make_unique(path, filters, filterNames); +} + bool QResourceFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output) { Q_D(QResourceFileEngine); diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp index abb61d3b462..fdd5942fe47 100644 --- a/src/corelib/io/qresource_iterator.cpp +++ b/src/corelib/io/qresource_iterator.cpp @@ -15,6 +15,14 @@ QResourceFileEngineIterator::QResourceFileEngineIterator(const QString &path, QD { } +QResourceFileEngineIterator::QResourceFileEngineIterator(const QString &path, + QDirListing::IteratorFlags filters, + const QStringList &filterNames) + : QAbstractFileEngineIterator(path, filters, filterNames), + index(-1) +{ +} + QResourceFileEngineIterator::~QResourceFileEngineIterator() { } diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h index bcbbc46b51c..c4fd9f278db 100644 --- a/src/corelib/io/qresource_iterator_p.h +++ b/src/corelib/io/qresource_iterator_p.h @@ -26,6 +26,8 @@ class QResourceFileEngineIterator : public QAbstractFileEngineIterator public: QResourceFileEngineIterator(const QString &path, QDir::Filters filters, const QStringList &filterNames); + QResourceFileEngineIterator(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames); ~QResourceFileEngineIterator(); bool advance() override; diff --git a/src/corelib/io/qresource_p.h b/src/corelib/io/qresource_p.h index 37fddd7a415..00b6bddf3ec 100644 --- a/src/corelib/io/qresource_p.h +++ b/src/corelib/io/qresource_p.h @@ -51,6 +51,8 @@ public: IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) override; + IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) override; bool extension(Extension extension, const ExtensionOption *option = nullptr, ExtensionReturn *output = nullptr) override; bool supportsExtension(Extension extension) const override; diff --git a/src/corelib/io/qstorageinfo_linux.cpp b/src/corelib/io/qstorageinfo_linux.cpp index b4360f91648..b7ca498e9c4 100644 --- a/src/corelib/io/qstorageinfo_linux.cpp +++ b/src/corelib/io/qstorageinfo_linux.cpp @@ -140,9 +140,7 @@ static inline quint64 retrieveDeviceId(const QByteArray &device, quint64 deviceI static QDirListing devicesByLabel() { static const char pathDiskByLabel[] = "/dev/disk/by-label"; - static constexpr auto LabelFileFilter = - QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot; - + static constexpr auto LabelFileFilter = QDirListing::IteratorFlag::IncludeHidden; return QDirListing(QLatin1StringView(pathDiskByLabel), LabelFileFilter); } diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 169d11d45ad..842bd676cde 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -309,7 +309,7 @@ inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path) #elif defined(Q_OS_ANDROID) QStringList("libplugins_%1_*.so"_L1.arg(suffix)), #endif - QDir::Files); + QDirListing::IteratorFlag::FilesOnly); for (const auto &dirEntry : plugins) { const QString &fileName = dirEntry.fileName(); diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp index 8d14e75193d..c31b4dc9656 100644 --- a/src/corelib/time/qtimezoneprivate_tz.cpp +++ b/src/corelib/time/qtimezoneprivate_tz.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -113,14 +114,16 @@ static QTzTimeZoneHash loadTzTimeZones() } } - const QString path = tzif.fileName(); + QString path = tzif.fileName(); const qsizetype cut = path.lastIndexOf(u'/'); Q_ASSERT(cut > 0); - const QDir zoneDir = QDir(path.first(cut)); - for (const auto &info : QDirListing(zoneDir, QDirListing::IteratorFlag::Recursive)) { + path.truncate(cut + 1); + const qsizetype prefixLen = path.size(); + for (const auto &info : QDirListing(path, QDirListing::IteratorFlag::Recursive)) { if (!(info.isFile() || info.isSymLink())) continue; - const QString name = zoneDir.relativeFilePath(info.filePath()); + const QString infoAbsolutePath = info.absoluteFilePath(); + const QString name = infoAbsolutePath.sliced(prefixLen); // Two sub-directories containing (more or less) copies of the zoneinfo tree. if (info.isDir() ? name == "posix"_L1 || name == "right"_L1 : name.startsWith("posix/"_L1) || name.startsWith("right/"_L1)) { @@ -130,7 +133,7 @@ static QTzTimeZoneHash loadTzTimeZones() // isTzFile() check; in practice current (2023) zoneinfo/ contains only // actual zone files and matches to that filter. const QByteArray id = QFile::encodeName(name); - if (!zonesHash.contains(id) && isTzFile(zoneDir.absoluteFilePath(name))) + if (!zonesHash.contains(id) && isTzFile(infoAbsolutePath)) zonesHash.insert(id, QTzTimeZone()); } return zonesHash; diff --git a/src/gui/itemmodels/qfileinfogatherer.cpp b/src/gui/itemmodels/qfileinfogatherer.cpp index 41fb0a0db5e..a0192c99828 100644 --- a/src/gui/itemmodels/qfileinfogatherer.cpp +++ b/src/gui/itemmodels/qfileinfogatherer.cpp @@ -419,8 +419,10 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil QStringList allFiles; if (files.isEmpty()) { + // Use QDirListing::IteratorFlags when QFileSystemModel is + // changed to use them too constexpr auto dirFilters = QDir::AllEntries | QDir::System | QDir::Hidden; - for (const auto &dirEntry : QDirListing(path, dirFilters)) { + for (const auto &dirEntry : QDirListing(path, {}, dirFilters.toInt())) { if (isInterruptionRequested()) break; fileInfo = dirEntry.fileInfo(); diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index b39924025e8..69e35cea279 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -473,8 +473,6 @@ qint64 QNetworkDiskCache::expire() // close file handle to prevent "in use" error when QFile::remove() is called d->lastItem.reset(); - const QDir::Filters filters = QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot; - struct CacheItem { std::chrono::milliseconds msecs; @@ -484,7 +482,7 @@ qint64 QNetworkDiskCache::expire() std::vector cacheItems; qint64 totalSize = 0; using F = QDirListing::IteratorFlag; - for (const auto &dirEntry : QDirListing(cacheDirectory(), filters, F::Recursive)) { + for (const auto &dirEntry : QDirListing(cacheDirectory(), F::FilesOnly | F::Recursive)) { if (!dirEntry.fileName().endsWith(CACHE_POSTFIX)) continue; diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index 9878c603b6c..a424bfd1b94 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -681,8 +681,8 @@ QList QSslCertificate::fromPath(const QString &path, #endif using F = QDirListing::IteratorFlag; - constexpr auto iterFlags = F::FollowSymlinks | F::Recursive; - for (const auto &dirEntry : QDirListing(pathPrefixString, QDir::Files, iterFlags)) { + constexpr auto iterFlags = F::FollowDirSymlinks | F::Recursive | F::FilesOnly; + for (const auto &dirEntry : QDirListing(pathPrefixString, iterFlags)) { QString filePath = dirEntry.filePath(); if (startIndex > 0) filePath.remove(0, startIndex); diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp index f4afb3789a0..b66bbf1e6eb 100644 --- a/src/plugins/platforms/android/androidcontentfileengine.cpp +++ b/src/plugins/platforms/android/androidcontentfileengine.cpp @@ -245,7 +245,7 @@ QString AndroidContentFileEngine::fileName(FileName f) const } QAbstractFileEngine::IteratorUniquePtr -AndroidContentFileEngine::beginEntryList(const QString &path, QDir::Filters filters, +AndroidContentFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) { return std::make_unique(path, filters, filterNames); @@ -265,7 +265,7 @@ AndroidContentFileEngineHandler::create(const QString &fileName) const } AndroidContentFileEngineIterator::AndroidContentFileEngineIterator( - const QString &path, QDir::Filters filters, const QStringList &filterNames) + const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) : QAbstractFileEngineIterator(path, filters, filterNames) { } diff --git a/src/plugins/platforms/android/androidcontentfileengine.h b/src/plugins/platforms/android/androidcontentfileengine.h index a5dd1b30f33..a93ea3373a0 100644 --- a/src/plugins/platforms/android/androidcontentfileengine.h +++ b/src/plugins/platforms/android/androidcontentfileengine.h @@ -30,7 +30,7 @@ public: QDateTime fileTime(QFile::FileTime time) const override; FileFlags fileFlags(FileFlags type = FileInfoAll) const override; QString fileName(FileName file = DefaultName) const override; - IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, + IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override; private: @@ -53,7 +53,7 @@ public: class AndroidContentFileEngineIterator : public QAbstractFileEngineIterator { public: - AndroidContentFileEngineIterator(const QString &path, QDir::Filters filters, + AndroidContentFileEngineIterator(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames); ~AndroidContentFileEngineIterator(); diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index 4ea6536cef2..1c7364cd229 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -164,7 +164,7 @@ Q_CONSTINIT QMutex FolderIterator::m_assetsCacheMutex; class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator { public: - AndroidAbstractFileEngineIterator(QDir::Filters filters, + AndroidAbstractFileEngineIterator(QDirListing::IteratorFlags filters, const QStringList &nameFilters, const QString &path) : QAbstractFileEngineIterator(path, filters, nameFilters) @@ -351,8 +351,8 @@ public: m_assetsInfoCache.insert(m_fileName, newAssetInfoPtr); } - IteratorUniquePtr - beginEntryList(const QString &, QDir::Filters filters, const QStringList &filterNames) override + IteratorUniquePtr beginEntryList(const QString &, QDirListing::IteratorFlags filters, + const QStringList &filterNames) override { // AndroidAbstractFileEngineIterator use `m_fileName` as the path if (m_assetInfo && m_assetInfo->type == AssetItem::Type::Folder) diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h index 0ad54a9e114..62d50db7662 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h @@ -29,7 +29,7 @@ public: void setFileName(const QString &file) override; #ifndef QT_NO_FILESYSTEMITERATOR - IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, + IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override; #endif diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm index f7e112ab81f..61780718a3f 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm @@ -258,7 +258,7 @@ public: QIOSAssetEnumerator *m_enumerator; QIOSFileEngineIteratorAssetsLibrary( - const QString &path, QDir::Filters filters, const QStringList &nameFilters) + const QString &path, QDirListing::IteratorFlags filters, const QStringList &nameFilters) : QAbstractFileEngineIterator(path, filters, nameFilters) , m_enumerator(new QIOSAssetEnumerator([[[ALAssetsLibrary alloc] init] autorelease], ALAssetsGroupAll)) { @@ -440,7 +440,7 @@ void QIOSFileEngineAssetsLibrary::setFileName(const QString &file) QAbstractFileEngine::IteratorUniquePtr QIOSFileEngineAssetsLibrary::beginEntryList( - const QString &path, QDir::Filters filters, const QStringList &filterNames) + const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) { return std::make_unique(path, filters, filterNames); } diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp index d73515724bb..f9bebaa8121 100644 --- a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp +++ b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp @@ -207,7 +207,8 @@ void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded() const const QStringList symLinkFilter{ u"[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]"_s}; for (const auto &dir : dirs) { - QDirListing dirList(QString::fromLatin1(dir), symLinkFilter, QDir::Files); + QDirListing dirList(QString::fromLatin1(dir), symLinkFilter, + QDirListing::IteratorFlag::FilesOnly); if (dirList.cbegin() != dirList.cend()) { // Not empty QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true); break; @@ -390,11 +391,9 @@ QList systemCaCertificates() QStringLiteral("/etc/pki/tls/certs/ca-bundle.crt"), // Fedora, Mandriva QStringLiteral("/usr/local/share/certs/ca-root-nss.crt") // FreeBSD's ca_root_nss }; - QDir currentDir; - currentDir.setNameFilters(QStringList{QStringLiteral("*.pem"), QStringLiteral("*.crt")}); + static const QStringList nameFilters = {u"*.pem"_s, u"*.crt"_s}; for (const auto &directory : directories) { - currentDir.setPath(QLatin1StringView(directory)); - for (const auto &dirEntry : QDirListing(currentDir)) { + for (const auto &dirEntry : QDirListing(directory, nameFilters)) { // use canonical path here to not load the same certificate twice if symlinked certFiles.insert(dirEntry.canonicalFilePath()); } diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index f9a645aadb7..f4c96edc55d 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -2870,7 +2870,7 @@ void checkAndWarnGradleLongPaths(const QString &outputDirectory) QStringList longFileNames; using F = QDirListing::IteratorFlag; for (const auto &dirEntry : QDirListing(outputDirectory, QStringList(u"*.java"_s), - QDir::Files, F::Recursive)) { + F::FilesOnly | F::Recursive)) { if (dirEntry.size() >= MAX_PATH) longFileNames.append(dirEntry.filePath()); } diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index a1089914fd2..27435485284 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -635,13 +635,13 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, absFileName.prepend(currentPath); QFileInfo file(absFileName); if (file.isDir()) { - QDir dir(file.filePath()); if (!alias.endsWith(slash)) alias += slash; QStringList filePaths; using F = QDirListing::IteratorFlag; - for (const auto &entry : QDirListing(dir, F::FollowSymlinks | F::Recursive)) { + constexpr auto flags = F::FollowDirSymlinks | F::Recursive; + for (const auto &entry : QDirListing(file.filePath(), flags)) { const QString &fileName = entry.fileName(); if (fileName == "."_L1 || fileName == ".."_L1) continue; diff --git a/src/tools/windeployqt/qtmoduleinfo.cpp b/src/tools/windeployqt/qtmoduleinfo.cpp index b928a644784..e03da339401 100644 --- a/src/tools/windeployqt/qtmoduleinfo.cpp +++ b/src/tools/windeployqt/qtmoduleinfo.cpp @@ -133,8 +133,9 @@ bool QtModuleInfoStore::populate(const QString &modulesDir, const QString &trans } } + using F = QDirListing::IteratorFlag; // Read modules, and assign a bit as ID. - for (const auto &dirEntry : QDirListing(modulesDir, {u"*.json"_s}, QDir::Files)) { + for (const auto &dirEntry : QDirListing(modulesDir, {u"*.json"_s}, F::FilesOnly)) { QtModule module = moduleFromJsonFile(dirEntry.filePath(), errorString); if (!errorString->isEmpty()) return false; diff --git a/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp index cf00c1525c5..3a54e74981c 100644 --- a/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp +++ b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp @@ -432,7 +432,7 @@ public: class Iterator : public QAbstractFileEngineIterator { public: - Iterator(const QString &path, QDir::Filters filters, const QStringList &filterNames) + Iterator(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) : QAbstractFileEngineIterator(path, filters, filterNames) { names.append("foo"); @@ -463,8 +463,8 @@ public: { } - IteratorUniquePtr - beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) override + IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) override { return std::make_unique(path, filters, filterNames); } diff --git a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp index e2ac1858dae..5b31d335f98 100644 --- a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp +++ b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp @@ -26,7 +26,6 @@ using namespace Qt::StringLiterals; Q_DECLARE_METATYPE(QDirListing::IteratorFlags) -Q_DECLARE_METATYPE(QDir::Filters) using ItFlag = QDirListing::IteratorFlag; @@ -187,183 +186,259 @@ void tst_QDirListing::iterateRelativeDirectory_data() { QTest::addColumn("dirName"); // relative from current path or abs QTest::addColumn("flags"); - QTest::addColumn("filters"); QTest::addColumn("nameFilters"); QTest::addColumn("entries"); - QTest::newRow("no flags") - << QString("entrylist") << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::NoFilter) << QStringList("*") - << QString( - "entrylist/.," - "entrylist/..," - "entrylist/file," -#ifndef Q_NO_SYMLINKS - "entrylist/linktofile.lnk," + const QStringList allSymlinks = { +#if !defined(Q_NO_SYMLINKS) + "entrylist/linktofile.lnk"_L1, + "entrylist/brokenlink.lnk"_L1, +# if !defined(Q_NO_SYMLINKS_TO_DIRS) + "entrylist/linktodirectory.lnk"_L1, +# endif #endif - "entrylist/directory," -#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) - "entrylist/linktodirectory.lnk," -#endif - "entrylist/writable").split(','); + }; - QTest::newRow("NoDot") - << QString("entrylist") << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::AllEntries | QDir::NoDot) << QStringList("*") - << QString( - "entrylist/..," - "entrylist/file," -#ifndef Q_NO_SYMLINKS - "entrylist/linktofile.lnk," + const QStringList nonBrokenSymlinks = { +#if !defined(Q_NO_SYMLINKS) + "entrylist/linktofile.lnk"_L1, +# if !defined(Q_NO_SYMLINKS_TO_DIRS) + "entrylist/linktodirectory.lnk"_L1, +# endif #endif - "entrylist/directory," -#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) - "entrylist/linktodirectory.lnk," -#endif - "entrylist/writable").split(','); + }; - QTest::newRow("NoDotDot") - << QString("entrylist") << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::AllEntries | QDir::NoDotDot) << QStringList("*") - << QString( - "entrylist/.," - "entrylist/file," -#ifndef Q_NO_SYMLINKS - "entrylist/linktofile.lnk," -#endif - "entrylist/directory," -#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) - "entrylist/linktodirectory.lnk," -#endif - "entrylist/writable").split(','); + using F = QDirListing::IteratorFlag; + QTest::newRow("Default_Flag") + << QString("entrylist") << QDirListing::IteratorFlags{F::Default} + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/writable"_L1, + } + allSymlinks; - QTest::newRow("NoDotAndDotDot") - << QString("entrylist") << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::AllEntries | QDir::NoDotAndDotDot) << QStringList("*") - << QString( - "entrylist/file," -#ifndef Q_NO_SYMLINKS - "entrylist/linktofile.lnk," -#endif - "entrylist/directory," -#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) - "entrylist/linktodirectory.lnk," -#endif - "entrylist/writable").split(','); + QTest::newRow("IncludeDotAndDotDot") + << QString("entrylist") + << QDirListing::IteratorFlags{F::IncludeDotAndDotDot} + << QStringList("*") + << QStringList{ + "entrylist/."_L1, + "entrylist/.."_L1, + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/writable"_L1, + } + allSymlinks; - QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks") - << QString("entrylist") << QDirListing::IteratorFlags(ItFlag::Recursive | ItFlag::FollowSymlinks) - << QDir::Filters(QDir::NoFilter) << QStringList("*") - << QString( - "entrylist/.," - "entrylist/..," - "entrylist/directory/.," - "entrylist/directory/..," - "entrylist/file," -#ifndef Q_NO_SYMLINKS - "entrylist/linktofile.lnk," -#endif - "entrylist/directory," - "entrylist/directory/dummy," -#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) - "entrylist/linktodirectory.lnk," -#endif - "entrylist/writable").split(','); + QTest::newRow("Recursive-IncludeDotAndDotDot") + << QString("entrylist") + << QDirListing::IteratorFlags{F::Recursive | F::IncludeDotAndDotDot} + << QStringList("*") + << QStringList{ + "entrylist/."_L1, + "entrylist/.."_L1, + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/directory/."_L1, + "entrylist/directory/.."_L1, + "entrylist/directory/dummy"_L1, + "entrylist/writable"_L1, + } + allSymlinks; - QTest::newRow("QDir::Subdirectories / QDir::Files") - << QString("entrylist") << QDirListing::IteratorFlags(ItFlag::Recursive) - << QDir::Filters(QDir::Files) << QStringList("*") - << QString("entrylist/directory/dummy," - "entrylist/file," -#ifndef Q_NO_SYMLINKS - "entrylist/linktofile.lnk," + QTest::newRow("Recursive") + << QString("entrylist") + << QDirListing::IteratorFlags(F::Recursive) + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/directory/dummy"_L1, + "entrylist/writable"_L1, + } + allSymlinks; + + QTest::newRow("ResolveSymlinks") + << QString("entrylist") + << QDirListing::IteratorFlags{F::ResolveSymlinks} + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/writable"_L1, + } + nonBrokenSymlinks; + + QTest::newRow("Recursive-ResolveSymlinks") + << QString("entrylist") + << QDirListing::IteratorFlags(F::Recursive | F::ResolveSymlinks) + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/directory/dummy"_L1, + "entrylist/writable"_L1, + } + nonBrokenSymlinks; + + QTest::newRow("Recursive-FilesOnly") + << QString("entrylist") + << QDirListing::IteratorFlags(F::Recursive | F::FilesOnly) + << QStringList("*") + << QStringList{ + "entrylist/directory/dummy"_L1, + "entrylist/file"_L1, + "entrylist/writable"_L1, + }; + + QTest::newRow("Recursive-FilesOnly-ResolveSymlinks") + << QString("entrylist") + << QDirListing::IteratorFlags(F::Recursive | F::FilesOnly | F::ResolveSymlinks) + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory/dummy"_L1, + "entrylist/writable"_L1, +#if !defined(Q_NO_SYMLINKS) + "entrylist/linktofile.lnk"_L1, #endif - "entrylist/writable").split(','); + }; - QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks / QDir::Files") - << QString("entrylist") << QDirListing::IteratorFlags(ItFlag::Recursive | QDirListing::IteratorFlag::FollowSymlinks) - << QDir::Filters(QDir::Files) << QStringList("*") - << QString("entrylist/file," -#ifndef Q_NO_SYMLINKS - "entrylist/linktofile.lnk," + QTest::newRow("Recursive-DirsOnly") + << QString("entrylist") + << QDirListing::IteratorFlags(F::Recursive | F::DirsOnly) + << QStringList("*") + << QStringList{ "entrylist/directory"_L1, }; + + QTest::newRow("Recursive-DirsOnly-ResolveSymlinks") + << QString("entrylist") + << QDirListing::IteratorFlags(F::Recursive | F::DirsOnly | F::ResolveSymlinks) + << QStringList("*") + << QStringList{ + "entrylist/directory"_L1, +#if !defined(Q_NO_SYMLINKS) + "entrylist/linktodirectory.lnk"_L1, #endif - "entrylist/directory/dummy," - "entrylist/writable").split(','); + }; - QTest::newRow("empty, default") - << QString("empty") << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::NoFilter) << QStringList("*") - << QString("empty/.,empty/..").split(','); + QTest::newRow("FollowDirSymlinks") + << QString("entrylist") + << QDirListing::IteratorFlags{F::FollowDirSymlinks} + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/writable"_L1, + } + allSymlinks; - QTest::newRow("empty, QDir::NoDotAndDotDot") + QTest::newRow("FollowDirSymlinks-Recursive") + << QString("entrylist") + << QDirListing::IteratorFlags{F::FollowDirSymlinks | F::Recursive} + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/directory/dummy"_L1, + "entrylist/writable"_L1, + } + allSymlinks; + + QTest::newRow("FollowDirSymlinks-Recursive-ResolveSymlinks") + << QString("entrylist") + << QDirListing::IteratorFlags{F::FollowDirSymlinks | F::Recursive | F::ResolveSymlinks} + << QStringList("*") + << QStringList{ + "entrylist/file"_L1, + "entrylist/directory"_L1, + "entrylist/directory/dummy"_L1, + "entrylist/writable"_L1, + } + nonBrokenSymlinks; + + QTest::newRow("empty-dir-IncludeDotAndDotDot") + << QString("empty") + << QDirListing::IteratorFlags{F::IncludeDotAndDotDot} + << QStringList("*") + << QStringList{ + "empty/."_L1, + "empty/.."_L1 + }; + + QTest::newRow("empty-dir-Default-Flag") << QString("empty") << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::NoDotAndDotDot) << QStringList("*") + << QStringList("*") << QStringList(); + + QTest::newRow("Recursive-nameFilter") + << u"entrylist"_s + << QDirListing::IteratorFlags(F::Recursive) + << QStringList{"dummy"_L1} + << QStringList{"entrylist/directory/dummy"_L1}; } void tst_QDirListing::iterateRelativeDirectory() { QFETCH(QString, dirName); QFETCH(QDirListing::IteratorFlags, flags); - QFETCH(QDir::Filters, filters); QFETCH(QStringList, nameFilters); QFETCH(const QStringList, entries); + // If canonicalFilePath is empty (e.g. for broken symlinks), use absoluteFilePath() QStringList list; - for (const auto &dirEntry : QDirListing(dirName, nameFilters, filters, flags)) { - // Using canonical file paths for final comparison - list << dirEntry.fileInfo().canonicalFilePath(); + for (const auto &dirEntry : QDirListing(dirName, nameFilters, flags)) { + QString filePath = dirEntry.canonicalFilePath(); + list.emplace_back(!filePath.isEmpty()? filePath : dirEntry.absoluteFilePath()); } // The order of items returned by QDirListing is not guaranteed. list.sort(); QStringList sortedEntries; - for (const QString &item : entries) - sortedEntries.append(QFileInfo(item).canonicalFilePath()); + for (const QString &item : entries) { + QFileInfo fi(item); + QString filePath = fi.canonicalFilePath(); + sortedEntries.emplace_back(!filePath.isEmpty()? filePath : fi.absoluteFilePath()); + } sortedEntries.sort(); - if (sortedEntries != list) { - qDebug() << "ACTUAL: " << list; - qDebug() << "EXPECTED:" << sortedEntries; - } - - QCOMPARE(list, sortedEntries); + QCOMPARE_EQ(list, sortedEntries); } void tst_QDirListing::iterateResource_data() { QTest::addColumn("dirName"); // relative from current path or abs QTest::addColumn("flags"); - QTest::addColumn("filters"); QTest::addColumn("nameFilters"); QTest::addColumn("entries"); - QTest::newRow("invalid") << QString::fromLatin1(":/testdata/burpaburpa") << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QStringList(); + QTest::newRow("invalid") << QString::fromLatin1(":/testdata/burpaburpa") + << QDirListing::IteratorFlags{ItFlag::Default} + << QStringList{u"*"_s} << QStringList(); + QTest::newRow("qrc:/testdata") << u":/testdata/"_s << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/testdata/entrylist").split(QLatin1String(",")); - QTest::newRow("qrc:/testdata/entrylist") << u":/testdata/entrylist"_s << QDirListing::IteratorFlags{} - << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/testdata/entrylist/directory,:/testdata/entrylist/file").split(QLatin1String(",")); - QTest::newRow("qrc:/testdata recursive") << u":/testdata"_s - << QDirListing::IteratorFlags(ItFlag::Recursive) - << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/testdata/entrylist,:/testdata/entrylist/directory,:/testdata/entrylist/directory/dummy,:/testdata/entrylist/file").split(QLatin1String(",")); + << QStringList(QLatin1String("*")) + << QStringList{u":/testdata/entrylist"_s}; + + QTest::newRow("qrc:/testdata/entrylist") + << u":/testdata/entrylist"_s + << QDirListing::IteratorFlags{} + << QStringList(QLatin1String("*")) + << QStringList{u":/testdata/entrylist/directory"_s, + u":/testdata/entrylist/file"_s}; + + QTest::newRow("qrc:/testdata recursive") + << u":/testdata"_s + << QDirListing::IteratorFlags(ItFlag::Recursive) + << QStringList(QLatin1String("*")) + << QStringList{u":/testdata/entrylist"_s, + u":/testdata/entrylist/directory"_s, + u":/testdata/entrylist/directory/dummy"_s, + u":/testdata/entrylist/file"_s}; } void tst_QDirListing::iterateResource() { QFETCH(QString, dirName); QFETCH(QDirListing::IteratorFlags, flags); - QFETCH(QDir::Filters, filters); QFETCH(QStringList, nameFilters); QFETCH(QStringList, entries); QStringList list; - for (const auto &dirEntry : QDirListing(dirName, nameFilters, filters, flags)) { + for (const auto &dirEntry : QDirListing(dirName, nameFilters, flags)) { QString dir = dirEntry.fileInfo().filePath(); if (!dir.startsWith(":/qt-project.org")) list.emplace_back(std::move(dir)); @@ -404,7 +479,7 @@ void tst_QDirListing::stopLinkLoop() createLink("..", "entrylist/directory/entrylist4.lnk"); #endif - constexpr auto flags = ItFlag::Recursive | ItFlag::FollowSymlinks; + constexpr auto flags = ItFlag::Recursive | ItFlag::FollowDirSymlinks; QDirListing dirIter(u"entrylist"_s, flags); QStringList list; int max = 200; @@ -424,7 +499,8 @@ public: : QFSFileEngine(fileName) { } - IteratorUniquePtr beginEntryList(const QString &, QDir::Filters, const QStringList &) override + IteratorUniquePtr beginEntryList(const QString &, QDirListing::IteratorFlags, + const QStringList &) override { return nullptr; } }; @@ -468,7 +544,6 @@ void tst_QDirListing::testQFsFileEngineIterator() { QFETCH(QString, dirName); QFETCH(QStringList, nameFilters); - QFETCH(QDir::Filters, filters); QFETCH(QDirListing::IteratorFlags, flags); if (dirName == u"empty") @@ -476,7 +551,7 @@ void tst_QDirListing::testQFsFileEngineIterator() CustomEngineHandler handler; bool isEmpty = true; - for (const auto &dirEntry : QDirListing(u"entrylist"_s, nameFilters, filters, flags)) { + for (const auto &dirEntry : QDirListing(u"entrylist"_s, nameFilters, flags)) { if (dirEntry.filePath().contains(u"entrylist")) isEmpty = false; // At least one entry in `entrylist` dir } @@ -486,7 +561,7 @@ void tst_QDirListing::testQFsFileEngineIterator() void tst_QDirListing::absoluteFilePathsFromRelativeIteratorPath() { - for (const auto &dirEntry : QDirListing(u"entrylist/"_s, QDir::NoDotAndDotDot)) + for (const auto &dirEntry : QDirListing(u"entrylist/"_s, QDirListing::IteratorFlag::Recursive)) QVERIFY(dirEntry.absoluteFilePath().contains("entrylist")); } @@ -497,12 +572,11 @@ void tst_QDirListing::recurseWithFilters() const expectedEntries.insert(QString::fromLatin1("recursiveDirs/dir1/textFileB.txt")); expectedEntries.insert(QString::fromLatin1("recursiveDirs/textFileA.txt")); - for (const auto &dirEntry : QDirListing(u"recursiveDirs/"_s, QStringList{u"*.txt"_s}, - QDir::Files, ItFlag::Recursive)) { + constexpr auto flags = ItFlag::ExcludeDirs | ItFlag::ExcludeSpecial| ItFlag::Recursive; + for (const auto &dirEntry : QDirListing(u"recursiveDirs/"_s, QStringList{u"*.txt"_s}, flags)) actualEntries.insert(dirEntry.filePath()); - } - QCOMPARE(actualEntries, expectedEntries); + QCOMPARE_EQ(actualEntries, expectedEntries); } void tst_QDirListing::longPath() @@ -518,7 +592,8 @@ void tst_QDirListing::longPath() dirName.append('x'); } - QDirListing dirList(dir.absolutePath(), QDir::NoDotAndDotDot|QDir::Dirs, ItFlag::Recursive); + constexpr auto flags = ItFlag::ExcludeFiles | ItFlag::ExcludeSpecial| ItFlag::Recursive; + QDirListing dirList(dir.absolutePath(), flags); qsizetype m = 0; for (auto it = dirList.begin(); it != dirList.end(); ++it) ++m; @@ -562,8 +637,7 @@ void tst_QDirListing::uncPaths_data() void tst_QDirListing::uncPaths() { QFETCH(QString, dirName); - constexpr auto dirFilters = QDir::AllEntries | QDir::NoDotAndDotDot; - for (const auto &dirEntry : QDirListing(dirName, dirFilters, ItFlag::Recursive)) { + for (const auto &dirEntry : QDirListing(dirName, ItFlag::Recursive)) { const QString &filePath = dirEntry.filePath(); QCOMPARE(filePath, QDir::cleanPath(filePath)); } @@ -588,15 +662,13 @@ void tst_QDirListing::hiddenFiles() }; expected.sort(); - constexpr auto filters = QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot; + constexpr auto flags = ItFlag::ExcludeDirs | ItFlag::IncludeHidden | ItFlag::Recursive; QStringList list; list.reserve(expected.size()); - for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, filters, - ItFlag::Recursive)) { + for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, flags)) { QVERIFY(dirEntry.isFile()); list.emplace_back(dirEntry.filePath()); } - list.sort(); QCOMPARE_EQ(list, expected); @@ -614,11 +686,10 @@ void tst_QDirListing::hiddenDirs() }; expected.sort(); - constexpr auto filters = QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot; + constexpr auto flags = ItFlag::ExcludeFiles | ItFlag::IncludeHidden | ItFlag::Recursive; QStringList list; list.reserve(expected.size()); - for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, filters, - ItFlag::Recursive)) { + for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, flags)) { QVERIFY(dirEntry.isDir()); list.emplace_back(dirEntry.filePath()); } @@ -631,7 +702,7 @@ void tst_QDirListing::hiddenDirs() void tst_QDirListing::withStdAlgorithms() { - QDirListing dirList(u"entrylist"_s, QDir::AllEntries | QDir::NoDotAndDotDot, ItFlag::Recursive); + QDirListing dirList(u"entrylist"_s, ItFlag::Recursive); std::for_each(dirList.cbegin(), dirList.cend(), [](const auto &dirEntry) { QVERIFY(dirEntry.absoluteFilePath().contains("entrylist")); diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 87736fdfc5a..2748df5e7ba 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -2327,7 +2327,8 @@ public: MyEngine(int n) { number = n; } qint64 size() const override { return 123 + number; } - QStringList entryList(QDir::Filters, const QStringList &) const override { return QStringList(); } + QStringList entryList(QDirListing::IteratorFlags, const QStringList &) const override + { return QStringList(); } QString fileName(FileName) const override { return name; } private: diff --git a/tests/benchmarks/corelib/io/qdiriterator/tst_bench_qdiriterator.cpp b/tests/benchmarks/corelib/io/qdiriterator/tst_bench_qdiriterator.cpp index 66448bf838f..aeb5d9a0df2 100644 --- a/tests/benchmarks/corelib/io/qdiriterator/tst_bench_qdiriterator.cpp +++ b/tests/benchmarks/corelib/io/qdiriterator/tst_bench_qdiriterator.cpp @@ -206,12 +206,14 @@ void tst_QDirIterator::dirlisting() { QFETCH(QByteArray, dirpath); + using F = QDirListing::IteratorFlag; + int count = 0; QBENCHMARK { int c = 0; - QDirListing dir(dirpath, dirFilters, QDirListing::IteratorFlag::Recursive); + QDirListing dir(dirpath, F::Recursive | F::IncludeHidden); for (const auto &dirEntry : dir) { const auto path = dirEntry.filePath();