Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdir.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "qplatformdefs.h"
6#include "qdir.h"
7#include "qdir_p.h"
10#ifndef QT_NO_DEBUG_STREAM
11#include "qdebug.h"
12#endif
13#include "qdirlisting.h"
14#include "qdatetime.h"
15#include "qstring.h"
16#if QT_CONFIG(regularexpression)
17# include <qregularexpression.h>
18#endif
23#include <qstringbuilder.h>
24
25#ifndef QT_BOOTSTRAPPED
26# include <qcollator.h>
27# include "qreadwritelock.h"
28# include "qmutex.h"
29#endif
30
31#include <private/qorderedmutexlocker_p.h>
32
33#include <algorithm>
34#include <memory>
35#include <stdlib.h>
36
38
39using namespace Qt::StringLiterals;
40
41#if defined(Q_OS_WIN)
42static QString driveSpec(const QString &path)
43{
44 if (path.size() < 2)
45 return QString();
46 char c = path.at(0).toLatin1();
47 if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z'))
48 return QString();
49 if (path.at(1).toLatin1() != ':')
50 return QString();
51 return path.mid(0, 2);
52}
53#endif
54
55// Return the length of the root part of an absolute path, for use by cleanPath(), cd().
56static qsizetype rootLength(QStringView name, QDirPrivate::PathNormalizations flags)
57{
58 constexpr bool UseWindowsRules = false // So we don't #include <QOperatingSystemVersion>
59#if defined(Q_OS_WIN)
60 || true
61#endif
62 ;
63 const qsizetype len = name.size();
64 char16_t firstChar = len > 0 ? name.at(0).unicode() : u'\0';
65 char16_t secondChar = len > 1 ? name.at(1).unicode() : u'\0';
66 if constexpr (UseWindowsRules) {
67 // Handle possible UNC paths which start with double slash
68 bool urlMode = flags.testAnyFlags(QDirPrivate::UrlNormalizationMode);
69 if (firstChar == u'/' && secondChar == u'/' && !urlMode) {
70 // Server name '//server/path' is part of the prefix.
71 const qsizetype nextSlash = name.indexOf(u'/', 2);
72 return nextSlash >= 0 ? nextSlash + 1 : len;
73 }
74
75 // Handle a possible drive letter
76 qsizetype driveLength = 2;
77 if (firstChar == u'/' && urlMode && len > 2 && name.at(2) == u':') {
78 // Drive-in-URL-Path mode, e.g. "/c:" or "/c:/autoexec.bat"
79 ++driveLength;
80 secondChar = u':';
81 }
82 if (secondChar == u':') {
83 if (len > driveLength && name.at(driveLength) == u'/')
84 return driveLength + 1; // absolute drive path, e.g. "c:/config.sys"
85 return driveLength; // relative drive path, e.g. "c:" or "d:swapfile.sys"
86 }
87 }
88
89 return firstChar == u'/' ? 1 : 0;
90}
91
92//************* QDirPrivate
93QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_,
94 QDir::SortFlags sort_, QDir::Filters filters_)
95 : QSharedData(), nameFilters(nameFilters_), sort(sort_), filters(filters_)
96{
97 setPath(path.isEmpty() ? QString::fromLatin1(".") : path);
98
99 auto isEmpty = [](const auto &e) { return e.isEmpty(); };
100 const bool empty = std::all_of(nameFilters.cbegin(), nameFilters.cend(), isEmpty);
101 if (empty)
102 nameFilters = QStringList(QString::fromLatin1("*"));
103}
104
106 : QSharedData(copy),
107 // mutex is not copied
109 sort(copy.sort),
111 // fileEngine is not copied
113{
114 QMutexLocker locker(&copy.fileCache.mutex);
115 fileCache.fileListsInitialized = copy.fileCache.fileListsInitialized.load();
116 fileCache.files = copy.fileCache.files;
117 fileCache.fileInfos = copy.fileCache.fileInfos;
118 fileCache.absoluteDirEntry = copy.fileCache.absoluteDirEntry;
119 fileCache.metaData = copy.fileCache.metaData;
120}
121
122bool QDirPrivate::exists() const
123{
124 if (!fileEngine) {
125 QMutexLocker locker(&fileCache.mutex);
126 QFileSystemEngine::fillMetaData(
127 dirEntry, fileCache.metaData,
128 QFileSystemMetaData::ExistsAttribute
129 | QFileSystemMetaData::DirectoryType); // always stat
130 return fileCache.metaData.exists() && fileCache.metaData.isDirectory();
131 }
132 const QAbstractFileEngine::FileFlags info =
133 fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
134 | QAbstractFileEngine::ExistsFlag
135 | QAbstractFileEngine::Refresh);
136 if (!(info & QAbstractFileEngine::DirectoryType))
137 return false;
138 return info.testAnyFlag(QAbstractFileEngine::ExistsFlag);
139}
140
141// static
142inline QChar QDirPrivate::getFilterSepChar(const QString &nameFilter)
143{
144 QChar sep(u';');
145 qsizetype i = nameFilter.indexOf(sep, 0);
146 if (i == -1 && nameFilter.indexOf(u' ', 0) != -1)
147 sep = QChar(u' ');
148 return sep;
149}
150
151// static
152inline QStringList QDirPrivate::splitFilters(const QString &nameFilter, QChar sep)
153{
154 if (sep.isNull())
155 sep = getFilterSepChar(nameFilter);
156 QStringList ret;
157 for (auto e : qTokenize(nameFilter, sep))
158 ret.append(e.trimmed().toString());
159 return ret;
160}
161
162inline void QDirPrivate::setPath(const QString &path)
163{
164 QString p = QDir::fromNativeSeparators(path);
165 if (p.endsWith(u'/')
166 && p.size() > 1
167#if defined(Q_OS_WIN)
168 && (!(p.length() == 3 && p.at(1).unicode() == ':' && p.at(0).isLetter()))
169#endif
170 ) {
171 p.truncate(p.size() - 1);
172 }
173 dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
175 fileCache.absoluteDirEntry = QFileSystemEntry();
176}
177
178inline QString QDirPrivate::resolveAbsoluteEntry() const
179{
180 QMutexLocker locker(&fileCache.mutex);
181 if (!fileCache.absoluteDirEntry.isEmpty())
182 return fileCache.absoluteDirEntry.filePath();
183
184 if (dirEntry.isEmpty())
185 return dirEntry.filePath();
186
187 QString absoluteName;
188 if (!fileEngine) {
189 if (!dirEntry.isRelative() && dirEntry.isClean()) {
190 fileCache.absoluteDirEntry = dirEntry;
191 return dirEntry.filePath();
192 }
193
194 absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath();
195 } else {
196 absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
197 }
198 auto absoluteFileSystemEntry =
199 QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
200 fileCache.absoluteDirEntry = absoluteFileSystemEntry;
201 return absoluteFileSystemEntry.filePath();
202}
203
204/* For sorting */
206{
207 QDirSortItem() = default;
208 QDirSortItem(const QFileInfo &fi, QDir::SortFlags sort)
209 : item(fi)
210 {
211 // A dir e.g. "dirA.bar" doesn't have actually have an extension/suffix, when
212 // sorting by type such "suffix" should be ignored but that would complicate
213 // the code and uses can change the behavior by setting DirsFirst/DirsLast
214 if (sort.testAnyFlag(QDir::Type))
215 suffix_cache = item.suffix();
216 }
217
218 mutable QString filename_cache;
220 QFileInfo item;
221};
222
224{
225 QDir::SortFlags qt_cmp_si_sort_flags;
226
227#ifndef QT_BOOTSTRAPPED
228 QCollator *collator = nullptr;
229#endif
230public:
231#ifndef QT_BOOTSTRAPPED
232 QDirSortItemComparator(QDir::SortFlags flags, QCollator *coll = nullptr)
234 {
235 Q_ASSERT(!qt_cmp_si_sort_flags.testAnyFlag(QDir::LocaleAware) || collator);
236
237 if (collator && qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase))
238 collator->setCaseSensitivity(Qt::CaseInsensitive);
239 }
240#else
243 {
244 }
245#endif
246 bool operator()(const QDirSortItem &, const QDirSortItem &) const;
247
248 int compareStrings(const QString &a, const QString &b, Qt::CaseSensitivity cs) const
249 {
250#ifndef QT_BOOTSTRAPPED
251 if (collator)
252 return collator->compare(a, b);
253#endif
254 return a.compare(b, cs);
255 }
256};
257
258bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2) const
259{
260 const QDirSortItem* f1 = &n1;
261 const QDirSortItem* f2 = &n2;
262
263 if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir()))
264 return f1->item.isDir();
265 if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
266 return !f1->item.isDir();
267
268 const bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
269 const auto qtcase = ic ? Qt::CaseInsensitive : Qt::CaseSensitive;
270
271 qint64 r = 0;
272 int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask)
273 | (qt_cmp_si_sort_flags & QDir::Type)).toInt();
274
275 switch (sortBy) {
276 case QDir::Time: {
277 const QDateTime firstModified = f1->item.lastModified(QTimeZone::UTC);
278 const QDateTime secondModified = f2->item.lastModified(QTimeZone::UTC);
279 r = firstModified.msecsTo(secondModified);
280 break;
281 }
282 case QDir::Size:
283 r = f2->item.size() - f1->item.size();
284 break;
285 case QDir::Type:
286 r = compareStrings(f1->suffix_cache, f2->suffix_cache, qtcase);
287 break;
288 default:
289 ;
290 }
291
292 if (r == 0 && sortBy != QDir::Unsorted) {
293 // Still not sorted - sort by name
294
295 if (f1->filename_cache.isNull())
296 f1->filename_cache = f1->item.fileName();
297 if (f2->filename_cache.isNull())
298 f2->filename_cache = f2->item.fileName();
299
300 r = compareStrings(f1->filename_cache, f2->filename_cache, qtcase);
301 }
302 if (qt_cmp_si_sort_flags & QDir::Reversed)
303 return r > 0;
304 return r < 0;
305}
306
307inline void QDirPrivate::sortFileList(QDir::SortFlags sort, const QFileInfoList &l,
308 QStringList *names, QFileInfoList *infos)
309{
310 Q_ASSERT(names || infos);
311 Q_ASSERT(!infos || infos->isEmpty());
312 Q_ASSERT(!names || names->isEmpty());
313
314 const qsizetype n = l.size();
315 if (n == 0)
316 return;
317
318 if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
319 if (infos)
320 *infos = l;
321
322 if (names) {
323 for (const QFileInfo &fi : l)
324 names->append(fi.fileName());
325 }
326 } else {
327 QVarLengthArray<QDirSortItem, 64> si;
328 si.reserve(n);
329 for (qsizetype i = 0; i < n; ++i)
330 si.emplace_back(l.at(i), sort);
331
332#ifndef QT_BOOTSTRAPPED
333 if (sort.testAnyFlag(QDir::LocaleAware)) {
334 QCollator coll;
335 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort, &coll));
336 } else {
337 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
338 }
339#else
340 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
341#endif // QT_BOOTSTRAPPED
342
343 // put them back in the list(s)
344 for (qsizetype i = 0; i < n; ++i) {
345 auto &fileInfo = si[i].item;
346 if (infos)
347 infos->append(fileInfo);
348 if (names) {
349 const bool cached = !si[i].filename_cache.isNull();
350 names->append(cached ? si[i].filename_cache : fileInfo.fileName());
351 }
352 }
353 }
354}
355
356#ifndef QT_BOOTSTRAPPED
357/*! \internal
358
359 Returns \c true if the permissions flags set in \a filters match the
360 permissions of \a fileInfo; otherwise returns \c false.
361
362 If there are no permissions set in \a filters this method returns \c true.
363*/
364static bool checkPermissions(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
365{
366 const auto perms = filters & QDir::PermissionMask;
367 const bool filterByPermissions = perms != 0 && perms != QDir::PermissionMask;
368 if (filterByPermissions) {
369 const QFileInfo fileInfo = dirEntry.fileInfo();
370 if (filters.testFlags(QDir::Readable) && !fileInfo.isReadable())
371 return false;
372 if (filters.testFlags(QDir::Writable) && !fileInfo.isWritable())
373 return false;
374 if (filters.testFlags(QDir::Executable) && !fileInfo.isExecutable())
375 return false;
376 }
377 return true;
378}
379
380static bool checkDotOrDotDot(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
381{
382 const QString fileName = dirEntry.fileName();
383 if ((filters & QDir::NoDot) && fileName == u".")
384 return false;
385 if ((filters & QDir::NoDotDot) && fileName == u"..")
386 return false;
387 return true;
388}
389
390/*! \internal
391
392 Returns \c true if \a dirEntry matches the flags set in \a filters, otherwise
393 returns \c false. Note that this method only checks the flags in \a filters
394 that can't be represented by QDirListing::IteratorFlags, see toDirListingFlags().
395*/
396bool QDirPrivate::checkNonDirListingFlags(const QDirListing::DirEntry &dirEntry,
397 QDir::Filters filters)
398{
399 return checkPermissions(dirEntry, filters) && checkDotOrDotDot(dirEntry, filters);
400}
401
403 QDir::Filters filters, QFileInfoList &l)
404{
405 if (QDirPrivate::checkNonDirListingFlags(dirEntry, filters))
406 l.emplace_back(dirEntry.fileInfo());
407}
408
409/*! \internal
410
411 Returns a set of QDirListing::IteratorFlags representing the flags in \a filters
412 that can be represented by QDirListing::IteratorFlags.
413
414 Note that not all QDir::Filter values are supported, some flags have to be checked
415 separately (see checkNonDirListingFlags()).
416*/
417QDirListing::IteratorFlags QDirPrivate::toDirListingFlags(QDir::Filters filters)
418{
419 if (filters == QDir::NoFilter)
420 filters = QDir::AllEntries;
421
422 using F = QDirListing::IteratorFlag;
423 QDirListing::IteratorFlags flags;
424 if (!(filters & QDir::Dirs) && !(filters & QDir::AllDirs))
425 flags |= F::ExcludeDirs;
426 if (!(filters & QDir::Files))
427 flags |= F::ExcludeFiles;
428 if (!(filters & QDir::NoSymLinks))
429 flags |= F::ResolveSymlinks;
430 if (filters & QDir::Hidden)
431 flags |= F::IncludeHidden;
432
433 if (!(filters & QDir::System))
434 flags |= F::ExcludeOther;
435 else
436 flags |= F::IncludeBrokenSymlinks; // QDir::System lists broken symlinks...
437
438
439 if (filters & QDir::AllDirs)
440 flags |= F::NoNameFiltersForDirs;
441 if (filters & QDir::CaseSensitive)
442 flags |= F::CaseSensitive;
443
444 // QDir::Filter has NoDot and NoDotDot; QDirListing has only one,
445 // F::IncludeDotAndDotDot. If either of the QDir::Filter values are
446 // not set, list both and use checkDotOrDotDot() to filter it later.
447 if (!(filters & QDir::NoDot) || !(filters & QDir::NoDotDot)) {
448 if (!(flags & F::ExcludeDirs)) // treat '.' and '..' as dirs
449 flags |= F::IncludeDotAndDotDot;
450 }
451
452 return flags;
453}
454
455inline void QDirPrivate::initFileLists(const QDir &dir) const
456{
457 QMutexLocker locker(&fileCache.mutex);
458 if (!fileCache.fileListsInitialized) {
459 QFileInfoList l;
460 QDirListing::IteratorFlags flags = toDirListingFlags(dir.filter());
461 for (const auto &dirEntry : QDirListing(dir.path(), dir.nameFilters(), flags))
462 appendIfMatchesNonDirListingFlags(dirEntry, dir.filter(), l);
463
464 sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos);
465 fileCache.fileListsInitialized = true;
466 }
467}
468#endif // !QT_BOOTSTRAPPED
469
471{
472 QMutexLocker locker(&fileCache.mutex);
473 if (mode == IncludingMetaData)
474 fileCache.metaData.clear();
475 fileCache.fileListsInitialized = false;
476 fileCache.files.clear();
477 fileCache.fileInfos.clear();
478 fileEngine = QFileSystemEngine::createLegacyEngine(dirEntry, fileCache.metaData);
479}
480
481/*!
482 \class QDir
483 \inmodule QtCore
484 \brief The QDir class provides access to directory structures and their contents.
485
486 \ingroup io
487 \ingroup shared
488 \reentrant
489
490 \compares equality
491
492 A QDir is used to manipulate path names, access information
493 regarding paths and files, and manipulate the underlying file
494 system. It can also be used to access Qt's \l{resource system}.
495
496 Qt uses "/" as a universal directory separator in the same way
497 that "/" is used as a path separator in URLs. If you always use
498 "/" as a directory separator, Qt will translate your paths to
499 conform to the underlying operating system.
500
501 A QDir can point to a file using either a relative or an absolute
502 path. Absolute paths begin with the directory separator
503 (optionally preceded by a drive specification under Windows).
504 Relative file names begin with a directory name or a file name and
505 specify a path relative to the current directory.
506
507 Examples of absolute paths:
508
509 \snippet code/src_corelib_io_qdir.cpp 0
510
511 On Windows, the second example above will be translated to
512 \c{C:\Users} when used to access files.
513
514 Examples of relative paths:
515
516 \snippet code/src_corelib_io_qdir.cpp 1
517
518 You can use the isRelative() or isAbsolute() functions to check if
519 a QDir is using a relative or an absolute file path. Call
520 makeAbsolute() to convert a relative QDir to an absolute one.
521
522 \note Paths starting with a colon (\e{:}) are always considered
523 absolute, as they denote a QResource.
524
525 \section1 Navigation and Directory Operations
526
527 A directory's path can be obtained with the path() function, and
528 a new path set with the setPath() function. The absolute path to
529 a directory is found by calling absolutePath().
530
531 The name of a directory is found using the dirName() function. This
532 typically returns the last element in the absolute path that specifies
533 the location of the directory. However, it can also return "." if
534 the QDir represents the current directory.
535
536 \snippet code/src_corelib_io_qdir.cpp 2
537
538 The path for a directory can also be changed with the cd() and cdUp()
539 functions, both of which operate like familiar shell commands.
540 When cd() is called with the name of an existing directory, the QDir
541 object changes directory so that it represents that directory instead.
542 The cdUp() function changes the directory of the QDir object so that
543 it refers to its parent directory; i.e. cd("..") is equivalent to
544 cdUp().
545
546 Directories can be created with mkdir(), renamed with rename(), and
547 removed with rmdir().
548
549 You can test for the presence of a directory with a given name by
550 using exists(), and the properties of a directory can be tested with
551 isReadable(), isAbsolute(), isRelative(), and isRoot().
552
553 The refresh() function re-reads the directory's data from disk.
554
555 \section1 Files and Directory Contents
556
557 Directories contain a number of entries, representing files,
558 directories, and symbolic links. The number of entries in a
559 directory is returned by count().
560 A string list of the names of all the entries in a directory can be
561 obtained with entryList(). If you need information about each
562 entry, use entryInfoList() to obtain a list of QFileInfo objects.
563
564 Paths to files and directories within a directory can be
565 constructed using filePath() and absoluteFilePath().
566 The filePath() function returns a path to the specified file
567 or directory relative to the path of the QDir object;
568 absoluteFilePath() returns an absolute path to the specified
569 file or directory. Neither of these functions checks for the
570 existence of files or directory; they only construct paths.
571
572 \snippet code/src_corelib_io_qdir.cpp 3
573
574 Files can be removed by using the remove() function. Directories
575 cannot be removed in the same way as files; use rmdir() to remove
576 them instead.
577
578 It is possible to reduce the number of entries returned by
579 entryList() and entryInfoList() by applying filters to a QDir object.
580 You can apply a name filter to specify a pattern with wildcards that
581 file names need to match, an attribute filter that selects properties
582 of entries and can distinguish between files and directories, and a
583 sort order.
584
585 Name filters are lists of strings that are passed to setNameFilters().
586 Attribute filters consist of a bitwise OR combination of Filters, and
587 these are specified when calling setFilter().
588 The sort order is specified using setSorting() with a bitwise OR
589 combination of SortFlags.
590
591 You can test to see if a filename matches a filter using the match()
592 function.
593
594 Filter and sort order flags may also be specified when calling
595 entryList() and entryInfoList() in order to override previously defined
596 behavior.
597
598 \section1 The Current Directory and Other Special Paths
599
600 Access to some common directories is provided with a number of static
601 functions that return QDir objects. There are also corresponding functions
602 for these that return strings:
603
604 \table
605 \header \li QDir \li QString \li Return Value
606 \row \li current() \li currentPath() \li The application's working directory
607 \row \li home() \li homePath() \li The user's home directory
608 \row \li root() \li rootPath() \li The root directory
609 \row \li temp() \li tempPath() \li The system's temporary directory
610 \endtable
611
612 The setCurrent() static function can also be used to set the application's
613 working directory.
614
615 If you want to find the directory containing the application's executable,
616 see \l{QCoreApplication::applicationDirPath()}.
617
618 The drives() static function provides a list of root directories for each
619 device that contains a filing system. On Unix systems this returns a list
620 containing a single root directory "/"; on Windows the list will usually
621 contain \c{C:/}, and possibly other drive letters such as \c{D:/}, depending
622 on the configuration of the user's system.
623
624 \section1 Path Manipulation and Strings
625
626 Paths containing "." elements that reference the current directory at that
627 point in the path, ".." elements that reference the parent directory, and
628 symbolic links can be reduced to a canonical form using the canonicalPath()
629 function.
630
631 Paths can also be simplified by using cleanPath() to remove redundant "/"
632 and ".." elements.
633
634 It is sometimes necessary to be able to show a path in the native
635 representation for the user's platform. The static toNativeSeparators()
636 function returns a copy of the specified path in which each directory
637 separator is replaced by the appropriate separator for the underlying
638 operating system.
639
640 \section1 Examples
641
642 Check if a directory exists:
643
644 \snippet code/src_corelib_io_qdir.cpp 4
645
646 (We could also use one of the static convenience functions
647 QFileInfo::exists() or QFile::exists().)
648
649 Traversing directories and reading a file:
650
651 \snippet code/src_corelib_io_qdir.cpp 5
652
653 A program that lists all the files in the current directory
654 (excluding symbolic links), sorted by size, smallest first:
655
656 \snippet qdir-listfiles/main.cpp 0
657
658 \section1 Platform Specific Issues
659
660 \include android-content-uri-limitations.qdocinc
661
662 \sa QFileInfo, QFile, QFileDialog, QCoreApplication::applicationDirPath(),
663 {Fetch More Example}
664*/
665
666/*!
667 \fn QDir &QDir::operator=(QDir &&other)
668
669 Move-assigns \a other to this QDir instance.
670
671 \since 5.2
672*/
673
674/*!
675 \internal
676*/
677QDir::QDir(QDirPrivate &p) : d_ptr(&p)
678{
679}
680
681/*!
682 Constructs a QDir pointing to the given directory \a path. If path
683 is empty the program's working directory, ("."), is used.
684
685 \sa currentPath()
686*/
687QDir::QDir(const QString &path) : d_ptr(new QDirPrivate(path))
688{
689}
690
691/*!
692 Constructs a QDir with path \a path, that filters its entries by
693 name using \a nameFilter and by attributes using \a filters. It
694 also sorts the names using \a sort.
695
696 The default \a nameFilter is an empty string, which excludes
697 nothing; the default \a filters is \l AllEntries, which also
698 excludes nothing. The default \a sort is \l Name | \l IgnoreCase,
699 i.e. sort by name case-insensitively.
700
701 If \a path is an empty string, QDir uses "." (the current
702 directory). If \a nameFilter is an empty string, QDir uses the
703 name filter "*" (all files).
704
705 \note \a path need not exist.
706
707 \sa exists(), setPath(), setNameFilters(), setFilter(), setSorting()
708*/
709QDir::QDir(const QString &path, const QString &nameFilter,
710 SortFlags sort, Filters filters)
711 : d_ptr(new QDirPrivate(path, QDir::nameFiltersFromString(nameFilter), sort, filters))
712{
713}
714
715/*!
716 Constructs a QDir object that is a copy of the QDir object for
717 directory \a dir.
718
719 \sa operator=()
720*/
721QDir::QDir(const QDir &dir)
722 : d_ptr(dir.d_ptr)
723{
724}
725
726/*!
727 Destroys the QDir object frees up its resources. This has no
728 effect on the underlying directory in the file system.
729*/
730QDir::~QDir()
731{
732}
733
734/*!
735 Sets the path of the directory to \a path. The path is cleaned of
736 redundant ".", ".." and of multiple separators. No check is made
737 to see whether a directory with this path actually exists; but you
738 can check for yourself using exists().
739
740 The path can be either absolute or relative. Absolute paths begin
741 with the directory separator "/" (optionally preceded by a drive
742 specification under Windows). Relative file names begin with a
743 directory name or a file name and specify a path relative to the
744 current directory. An example of an absolute path is the string
745 "/tmp/quartz", a relative path might look like "src/fatlib".
746
747 \sa path(), absolutePath(), exists(), cleanPath(), dirName(),
748 absoluteFilePath(), isRelative(), makeAbsolute()
749*/
750void QDir::setPath(const QString &path)
751{
752 d_ptr->setPath(path);
753}
754
755/*!
756 Returns the path. This may contain symbolic links, but never
757 contains redundant ".", ".." or multiple separators.
758
759 The returned path can be either absolute or relative (see
760 setPath()).
761
762 \sa setPath(), absolutePath(), exists(), cleanPath(), dirName(),
763 absoluteFilePath(), toNativeSeparators(), makeAbsolute()
764*/
765QString QDir::path() const
766{
767 Q_D(const QDir);
768 return d->dirEntry.filePath();
769}
770
771/*!
772 Returns the absolute path (a path that starts with "/" or with a
773 drive specification), which may contain symbolic links, but never
774 contains redundant ".", ".." or multiple separators.
775
776 \sa setPath(), canonicalPath(), exists(), cleanPath(),
777 dirName(), absoluteFilePath()
778*/
779QString QDir::absolutePath() const
780{
781 Q_D(const QDir);
782 if (!d->fileEngine)
783 return d->resolveAbsoluteEntry();
784
785 return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
786}
787
788/*!
789 Returns the canonical path, i.e. a path without symbolic links or
790 redundant "." or ".." elements.
791
792 On systems that do not have symbolic links this function will
793 always return the same string that absolutePath() returns. If the
794 canonical path does not exist (normally due to dangling symbolic
795 links) canonicalPath() returns an empty string.
796
797 Example:
798
799 \snippet code/src_corelib_io_qdir.cpp 6
800
801 \sa path(), absolutePath(), exists(), cleanPath(), dirName(),
802 absoluteFilePath()
803*/
804QString QDir::canonicalPath() const
805{
806 Q_D(const QDir);
807 if (!d->fileEngine) {
808 QMutexLocker locker(&d->fileCache.mutex);
809 QFileSystemEntry answer =
810 QFileSystemEngine::canonicalName(d->dirEntry, d->fileCache.metaData);
811 return answer.filePath();
812 }
813 return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
814}
815
816/*!
817 Returns the name of the directory; this is \e not the same as the
818 path, e.g. a directory with the name "mail", might have the path
819 "/var/spool/mail". If the directory has no name (e.g. it is the
820 root directory) an empty string is returned.
821
822 No check is made to ensure that a directory with this name
823 actually exists; but see exists().
824
825 \sa path(), filePath(), absolutePath(), absoluteFilePath()
826*/
827QString QDir::dirName() const
828{
829 Q_D(const QDir);
830 if (!d_ptr->fileEngine)
831 return d->dirEntry.fileName();
832 return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
833}
834
835
836#ifdef Q_OS_WIN
837static qsizetype drivePrefixLength(QStringView path)
838{
839 // Used to extract path's drive for use as prefix for an "absolute except for drive" path
840 const qsizetype size = path.size();
841 qsizetype drive = 2; // length of drive prefix
842 if (size > 1 && path.at(1).unicode() == ':') {
843 if (Q_UNLIKELY(!path.at(0).isLetter()))
844 return 0;
845 } else if (path.startsWith("//"_L1)) {
846 // UNC path; use its //server/share part as "drive" - it's as sane a
847 // thing as we can do.
848 for (int i = 0 ; i < 2 ; ++i) { // Scan two "path fragments":
849 while (drive < size && path.at(drive).unicode() == '/')
850 drive++;
851 if (drive >= size) {
852 qWarning("Base directory starts with neither a drive nor a UNC share: %s",
853 qUtf8Printable(QDir::toNativeSeparators(path.toString())));
854 return 0;
855 }
856 while (drive < size && path.at(drive).unicode() != '/')
857 drive++;
858 }
859 } else {
860 return 0;
861 }
862 return drive;
863}
864#endif // Q_OS_WIN
865
866static bool treatAsAbsolute(const QString &path)
867{
868 // ### Qt 6: be consistent about absolute paths
869
870 // QFileInfo will use the right FS-engine for virtual file-systems
871 // (e.g. resource paths). Unfortunately, for real file-systems, it relies
872 // on QFileSystemEntry's isRelative(), which is flawed on MS-Win, ignoring
873 // its (correct) isAbsolute(). So only use that isAbsolute() unless there's
874 // a colon in the path.
875 // FIXME: relies on virtual file-systems having colons in their prefixes.
876 // The case of an MS-absolute C:/... path happens to work either way.
877 return (path.contains(u':') && QFileInfo(path).isAbsolute())
878 || QFileSystemEntry(path).isAbsolute();
879}
880
881/*!
882 Returns the path name of a file in the directory. Does \e not
883 check if the file actually exists in the directory; but see
884 exists(). If the QDir is relative the returned path name will also
885 be relative. Redundant multiple separators or "." and ".."
886 directories in \a fileName are not removed (see cleanPath()).
887
888 \sa dirName(), absoluteFilePath(), isRelative(), canonicalPath()
889*/
890QString QDir::filePath(const QString &fileName) const
891{
892 if (treatAsAbsolute(fileName))
893 return fileName;
894
895 Q_D(const QDir);
896 QString ret = d->dirEntry.filePath();
897 if (fileName.isEmpty())
898 return ret;
899
900#ifdef Q_OS_WIN
901 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
902 // Handle the "absolute except for drive" case (i.e. \blah not c:\blah):
903 const qsizetype drive = drivePrefixLength(ret);
904 return drive > 0 ? QStringView{ret}.left(drive) % fileName : fileName;
905 }
906#endif // Q_OS_WIN
907
908 if (ret.isEmpty() || ret.endsWith(u'/'))
909 return ret % fileName;
910 return ret % u'/' % fileName;
911}
912
913/*!
914 Returns the absolute path name of a file in the directory. Does \e
915 not check if the file actually exists in the directory; but see
916 exists(). Redundant multiple separators or "." and ".."
917 directories in \a fileName are not removed (see cleanPath()).
918
919 \sa relativeFilePath(), filePath(), canonicalPath()
920*/
921QString QDir::absoluteFilePath(const QString &fileName) const
922{
923 if (treatAsAbsolute(fileName))
924 return fileName;
925
926 Q_D(const QDir);
927 QString absoluteDirPath = d->resolveAbsoluteEntry();
928 if (fileName.isEmpty())
929 return absoluteDirPath;
930#ifdef Q_OS_WIN
931 // Handle the "absolute except for drive" case (i.e. \blah not c:\blah):
932 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
933 // Combine absoluteDirPath's drive with fileName
934 const qsizetype drive = drivePrefixLength(absoluteDirPath);
935 if (Q_LIKELY(drive))
936 return QStringView{absoluteDirPath}.left(drive) % fileName;
937
938 qWarning("Base directory's drive is not a letter: %s",
939 qUtf8Printable(QDir::toNativeSeparators(absoluteDirPath)));
940 return QString();
941 }
942#endif // Q_OS_WIN
943 if (!absoluteDirPath.endsWith(u'/'))
944 return absoluteDirPath % u'/' % fileName;
945 return absoluteDirPath % fileName;
946}
947
948/*!
949 Returns the path to \a fileName relative to the directory.
950
951 \snippet code/src_corelib_io_qdir.cpp 7
952
953 \sa absoluteFilePath(), filePath(), canonicalPath()
954*/
955QString QDir::relativeFilePath(const QString &fileName) const
956{
957 QString dir = cleanPath(absolutePath());
958 QString file = cleanPath(fileName);
959
960 if (isRelativePath(file) || isRelativePath(dir))
961 return file;
962
963#ifdef Q_OS_WIN
964 QString dirDrive = driveSpec(dir);
965 QString fileDrive = driveSpec(file);
966
967 bool fileDriveMissing = false;
968 if (fileDrive.isEmpty()) {
969 fileDrive = dirDrive;
970 fileDriveMissing = true;
971 }
972
973 if (fileDrive.toLower() != dirDrive.toLower()
974 || (file.startsWith("//"_L1)
975 && !dir.startsWith("//"_L1))) {
976 return file;
977 }
978
979 dir.remove(0, dirDrive.size());
980 if (!fileDriveMissing)
981 file.remove(0, fileDrive.size());
982#endif
983
984 QString result;
985 const auto dirElts = dir.tokenize(u'/', Qt::SkipEmptyParts);
986 const auto fileElts = file.tokenize(u'/', Qt::SkipEmptyParts);
987
988 const auto dend = dirElts.end();
989 const auto fend = fileElts.end();
990 auto dit = dirElts.begin();
991 auto fit = fileElts.begin();
992
993 const auto eq = [](QStringView lhs, QStringView rhs) {
994 return
995#if defined(Q_OS_WIN)
996 lhs.compare(rhs, Qt::CaseInsensitive) == 0;
997#else
998 lhs == rhs;
999#endif
1000 };
1001
1002 // std::ranges::mismatch
1003 while (dit != dend && fit != fend && eq(*dit, *fit)) {
1004 ++dit;
1005 ++fit;
1006 }
1007
1008 while (dit != dend) {
1009 result += "../"_L1;
1010 ++dit;
1011 }
1012
1013 if (fit != fend) {
1014 while (fit != fend) {
1015 result += *fit++;
1016 result += u'/';
1017 }
1018 result.chop(1);
1019 }
1020
1021 if (result.isEmpty())
1022 result = "."_L1;
1023 return result;
1024}
1025
1026/*!
1027 \since 4.2
1028
1029 Returns \a pathName with the '/' separators converted to
1030 separators that are appropriate for the underlying operating
1031 system.
1032
1033 On Windows, toNativeSeparators("c:/winnt/system32") returns
1034 "c:\\winnt\\system32".
1035
1036 The returned string may be the same as the argument on some
1037 operating systems, for example on Unix.
1038
1039 \sa fromNativeSeparators(), separator()
1040*/
1041QString QDir::toNativeSeparators(const QString &pathName)
1042{
1043#if defined(Q_OS_WIN)
1044 qsizetype i = pathName.indexOf(u'/');
1045 if (i != -1) {
1046 QString n(pathName);
1047
1048 QChar * const data = n.data();
1049 data[i++] = u'\\';
1050
1051 for (; i < n.length(); ++i) {
1052 if (data[i] == u'/')
1053 data[i] = u'\\';
1054 }
1055
1056 return n;
1057 }
1058#endif
1059 return pathName;
1060}
1061
1062/*!
1063 \since 4.2
1064
1065 Returns \a pathName using '/' as file separator. On Windows,
1066 for instance, fromNativeSeparators("\c{c:\\winnt\\system32}") returns
1067 "c:/winnt/system32".
1068
1069 The returned string may be the same as the argument on some
1070 operating systems, for example on Unix.
1071
1072 \sa toNativeSeparators(), separator()
1073*/
1074QString QDir::fromNativeSeparators(const QString &pathName)
1075{
1076#if defined(Q_OS_WIN)
1077 return QFileSystemEntry::removeUncOrLongPathPrefix(pathName).replace(u'\\', u'/');
1078#else
1079 return pathName;
1080#endif
1081}
1082
1083static bool qt_cleanPath(QString *path);
1084
1085/*!
1086 Changes the QDir's directory to \a dirName.
1087
1088 Returns \c true if the new directory exists;
1089 otherwise returns \c false. Note that the logical cd() operation is
1090 not performed if the new directory does not exist.
1091
1092 Calling cd("..") is equivalent to calling cdUp().
1093
1094 \sa cdUp(), isReadable(), exists(), path()
1095*/
1096bool QDir::cd(const QString &dirName)
1097{
1098 // Don't detach just yet.
1099 const QDirPrivate * const d = d_ptr.constData();
1100
1101 if (dirName.isEmpty() || dirName == u'.')
1102 return true;
1103 QString newPath;
1104 if (isAbsolutePath(dirName)) {
1105 newPath = dirName;
1106 qt_cleanPath(&newPath);
1107 } else {
1108 newPath = d->dirEntry.filePath();
1109 if (!newPath.endsWith(u'/'))
1110 newPath += u'/';
1111 newPath += dirName;
1112 if (dirName.indexOf(u'/') >= 0
1113 || dirName == ".."_L1
1114 || d->dirEntry.filePath() == u'.') {
1115 if (!qt_cleanPath(&newPath))
1116 return false;
1117 /*
1118 If newPath starts with .., we convert it to absolute to
1119 avoid infinite looping on
1120
1121 QDir dir(".");
1122 while (dir.cdUp())
1123 ;
1124 */
1125 if (newPath.startsWith(".."_L1)) {
1126 newPath = QFileInfo(newPath).absoluteFilePath();
1127 }
1128 }
1129 }
1130
1131 std::unique_ptr<QDirPrivate> dir(new QDirPrivate(*d_ptr.constData()));
1132 dir->setPath(newPath);
1133 if (!dir->exists())
1134 return false;
1135
1136 d_ptr = dir.release();
1137 return true;
1138}
1139
1140/*!
1141 Changes directory by moving one directory up from the QDir's
1142 current directory.
1143
1144 Returns \c true if the new directory exists;
1145 otherwise returns \c false. Note that the logical cdUp() operation is
1146 not performed if the new directory does not exist.
1147
1148 \note On Android, this is not supported for content URIs. For more information,
1149 see \l {Android: DocumentFile.getParentFile()}{DocumentFile.getParentFile()}.
1150
1151 \sa cd(), isReadable(), exists(), path()
1152*/
1153bool QDir::cdUp()
1154{
1155 return cd(QString::fromLatin1(".."));
1156}
1157
1158/*!
1159 Returns the string list set by setNameFilters()
1160*/
1161QStringList QDir::nameFilters() const
1162{
1163 Q_D(const QDir);
1164 return d->nameFilters;
1165}
1166
1167/*!
1168 Sets the name filters used by entryList() and entryInfoList() to the
1169 list of filters specified by \a nameFilters.
1170
1171 Each name filter is a wildcard (globbing) filter that understands
1172 \c{*} and \c{?} wildcards. See \l{QRegularExpression::fromWildcard()}.
1173
1174 For example, the following code sets three name filters on a QDir
1175 to ensure that only files with extensions typically used for C++
1176 source files are listed:
1177
1178 \snippet qdir-namefilters/main.cpp 0
1179
1180 \sa nameFilters(), setFilter()
1181*/
1182void QDir::setNameFilters(const QStringList &nameFilters)
1183{
1184 Q_D(QDir);
1185 d->clearCache(QDirPrivate::KeepMetaData);
1186 d->nameFilters = nameFilters;
1187}
1188
1189#ifndef QT_BOOTSTRAPPED
1190
1191namespace {
1192struct DirSearchPaths {
1193 mutable QReadWriteLock mutex;
1194 QHash<QString, QStringList> paths;
1195};
1196}
1197
1198Q_GLOBAL_STATIC(DirSearchPaths, dirSearchPaths)
1199
1200/*!
1201 \since 4.3
1202
1203 Sets or replaces Qt's search paths for file names with the prefix \a prefix
1204 to \a searchPaths.
1205
1206 To specify a prefix for a file name, prepend the prefix followed by a single
1207 colon (e.g., "images:undo.png", "xmldocs:books.xml"). \a prefix can only
1208 contain letters or numbers (e.g., it cannot contain a colon, nor a slash).
1209
1210 Qt uses this search path to locate files with a known prefix. The search
1211 path entries are tested in order, starting with the first entry.
1212
1213 \snippet code/src_corelib_io_qdir.cpp 8
1214
1215 File name prefix must be at least 2 characters long to avoid conflicts with
1216 Windows drive letters.
1217
1218 Search paths may contain paths to \l{The Qt Resource System}.
1219*/
1220void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
1221{
1222 if (prefix.size() < 2) {
1223 qWarning("QDir::setSearchPaths: Prefix must be longer than 1 character");
1224 return;
1225 }
1226
1227 for (QChar ch : prefix) {
1228 if (!ch.isLetterOrNumber()) {
1229 qWarning("QDir::setSearchPaths: Prefix can only contain letters or numbers");
1230 return;
1231 }
1232 }
1233
1234 DirSearchPaths &conf = *dirSearchPaths;
1235 const QWriteLocker lock(&conf.mutex);
1236 if (searchPaths.isEmpty()) {
1237 conf.paths.remove(prefix);
1238 } else {
1239 conf.paths.insert(prefix, searchPaths);
1240 }
1241}
1242
1243/*!
1244 \since 4.3
1245
1246 Adds \a path to the search path for \a prefix.
1247
1248 \sa setSearchPaths()
1249*/
1250void QDir::addSearchPath(const QString &prefix, const QString &path)
1251{
1252 if (path.isEmpty())
1253 return;
1254
1255 DirSearchPaths &conf = *dirSearchPaths;
1256 const QWriteLocker lock(&conf.mutex);
1257 conf.paths[prefix] += path;
1258}
1259
1260/*!
1261 \since 4.3
1262
1263 Returns the search paths for \a prefix.
1264
1265 \sa setSearchPaths(), addSearchPath()
1266*/
1267QStringList QDir::searchPaths(const QString &prefix)
1268{
1269 if (!dirSearchPaths.exists())
1270 return QStringList();
1271
1272 const DirSearchPaths &conf = *dirSearchPaths;
1273 const QReadLocker lock(&conf.mutex);
1274 return conf.paths.value(prefix);
1275}
1276
1277#endif // QT_BOOTSTRAPPED
1278
1279/*!
1280 Returns the value set by setFilter()
1281*/
1282QDir::Filters QDir::filter() const
1283{
1284 Q_D(const QDir);
1285 return d->filters;
1286}
1287
1288/*!
1289 \enum QDir::Filter
1290
1291 This enum describes the filtering options available to QDir; e.g.
1292 for entryList() and entryInfoList(). The filter value is specified
1293 by combining values from the following list using the bitwise OR
1294 operator:
1295
1296 \value Dirs List directories that match the filters.
1297 \value AllDirs List all directories; i.e. don't apply the filters
1298 to directory names.
1299 \value Files List files.
1300 \value Drives List disk drives (ignored under Unix).
1301 \value NoSymLinks Do not list symbolic links (ignored by operating
1302 systems that don't support symbolic links).
1303 \value NoDotAndDotDot Do not list the special entries "." and "..".
1304 \value NoDot Do not list the special entry ".".
1305 \value NoDotDot Do not list the special entry "..".
1306 \value AllEntries List directories, files, drives and symlinks (this does not list
1307 broken symlinks unless you specify System).
1308 \value Readable List files for which the application has read
1309 access. The Readable value needs to be combined
1310 with Dirs or Files.
1311 \value Writable List files for which the application has write
1312 access. The Writable value needs to be combined
1313 with Dirs or Files.
1314 \value Executable List files for which the application has
1315 execute access. The Executable value needs to be
1316 combined with Dirs or Files.
1317 \value Hidden List hidden files (on Unix, files starting with a ".").
1318 \value System List system files (on Unix, FIFOs, sockets and
1319 device files are included; on Windows, \c {.lnk}
1320 files are included)
1321 \value CaseSensitive The filter should be case sensitive.
1322
1323 \omitvalue TypeMask
1324 \omitvalue AccessMask
1325 \omitvalue PermissionMask
1326 \omitvalue Modified
1327 \omitvalue NoFilter
1328
1329 Functions that use Filter enum values to filter lists of files
1330 and directories will include symbolic links to files and directories
1331 unless you set the NoSymLinks value.
1332
1333 A default constructed QDir will not filter out files based on
1334 their permissions, so entryList() and entryInfoList() will return
1335 all files that are readable, writable, executable, or any
1336 combination of the three. This makes the default easy to write,
1337 and at the same time useful.
1338
1339 For example, setting the \c Readable, \c Writable, and \c Files
1340 flags allows all files to be listed for which the application has read
1341 access, write access or both. If the \c Dirs and \c Drives flags are
1342 also included in this combination then all drives, directories, all
1343 files that the application can read, write, or execute, and symlinks
1344 to such files/directories can be listed.
1345
1346 To retrieve the permissions for a directory, use the
1347 entryInfoList() function to get the associated QFileInfo objects
1348 and then use the QFileInfo::permissions() to obtain the permissions
1349 and ownership for each file.
1350*/
1351
1352/*!
1353 Sets the filter used by entryList() and entryInfoList() to \a
1354 filters. The filter is used to specify the kind of files that
1355 should be returned by entryList() and entryInfoList(). See
1356 \l{QDir::Filter}.
1357
1358 \sa filter(), setNameFilters()
1359*/
1360void QDir::setFilter(Filters filters)
1361{
1362 Q_D(QDir);
1363 d->clearCache(QDirPrivate::KeepMetaData);
1364 d->filters = filters;
1365}
1366
1367/*!
1368 Returns the value set by setSorting()
1369
1370 \sa setSorting(), SortFlag
1371*/
1372QDir::SortFlags QDir::sorting() const
1373{
1374 Q_D(const QDir);
1375 return d->sort;
1376}
1377
1378/*!
1379 \enum QDir::SortFlag
1380
1381 This enum describes the sort options available to QDir, e.g. for
1382 entryList() and entryInfoList(). The sort value is specified by
1383 OR-ing together values from the following list:
1384
1385 \value Name Sort by name.
1386 \value Time Sort by time (modification time).
1387 \value Size Sort by file size.
1388 \value Type Sort by file type (extension).
1389 \value Unsorted Do not sort.
1390 \value NoSort Not sorted by default.
1391
1392 \value DirsFirst Put the directories first, then the files.
1393 \value DirsLast Put the files first, then the directories.
1394 \value Reversed Reverse the sort order.
1395 \value IgnoreCase Sort case-insensitively.
1396 \value LocaleAware Sort items appropriately using the current locale settings.
1397
1398 \omitvalue SortByMask
1399
1400 You can only specify one of the first four.
1401
1402 If you specify both DirsFirst and Reversed, directories are
1403 still put first, but in reverse order; the files will be listed
1404 after the directories, again in reverse order.
1405*/
1406
1407#ifndef QT_BOOTSTRAPPED
1408/*!
1409 Sets the sort order used by entryList() and entryInfoList().
1410
1411 The \a sort is specified by OR-ing values from the enum
1412 \l{QDir::SortFlag}.
1413
1414 \sa sorting(), SortFlag
1415*/
1416void QDir::setSorting(SortFlags sort)
1417{
1418 Q_D(QDir);
1419 d->clearCache(QDirPrivate::KeepMetaData);
1420 d->sort = sort;
1421}
1422
1423/*!
1424 Returns the total number of directories and files in the directory.
1425
1426 Equivalent to entryList().count().
1427
1428 \note In Qt versions prior to 6.5, this function returned \c{uint}, not
1429 \c{qsizetype}.
1430
1431 \sa operator[](), entryList()
1432*/
1433qsizetype QDir::count(QT6_IMPL_NEW_OVERLOAD) const
1434{
1435 Q_D(const QDir);
1436 d->initFileLists(*this);
1437 return d->fileCache.files.size();
1438}
1439
1440/*!
1441 Returns the file name at position \a pos in the list of file
1442 names. Equivalent to entryList().at(index).
1443 \a pos must be a valid index position in the list (i.e., 0 <= pos < count()).
1444
1445 \note In Qt versions prior to 6.5, \a pos was an \c{int}, not \c{qsizetype}.
1446
1447 \sa count(), entryList()
1448*/
1449QString QDir::operator[](qsizetype pos) const
1450{
1451 Q_D(const QDir);
1452 d->initFileLists(*this);
1453 return d->fileCache.files[pos];
1454}
1455
1456/*
1457//! [entrylist_memory_spike]
1458 For large directories this function may cause a memory spike because it
1459 creates an instance of a \1 per each entry in the directory. Consider
1460 using QDirListing if the goal is to iterate over the items one-by-one.
1461//! [entrylist_memory_spike]
1462*/
1463
1464/*!
1465 \overload
1466
1467 Returns a list of the names of all the files and directories in
1468 the directory, ordered according to the name and attribute filters
1469 previously set with setNameFilters() and setFilter(), and sorted according
1470 to the flags set with setSorting().
1471
1472 The attribute filter and sorting specifications can be overridden using the
1473 \a filters and \a sort arguments.
1474
1475 Returns an empty list if the directory is unreadable, does not
1476 exist, or if nothing matches the specification.
1477
1478 \note To list symlinks that point to non existing files, \l System must be
1479 passed to the filter.
1480
1481 \include qdir.cpp {entrylist_memory_spike} {QString}
1482
1483 \sa entryInfoList(), setNameFilters(), setSorting(), setFilter()
1484*/
1485QStringList QDir::entryList(Filters filters, SortFlags sort) const
1486{
1487 Q_D(const QDir);
1488 return entryList(d->nameFilters, filters, sort);
1489}
1490
1491
1492/*!
1493 \overload
1494
1495 Returns a list of QFileInfo objects for all the files and directories in
1496 the directory, ordered according to the name and attribute filters
1497 previously set with setNameFilters() and setFilter(), and sorted according
1498 to the flags set with setSorting().
1499
1500 The attribute filter and sorting specifications can be overridden using the
1501 \a filters and \a sort arguments.
1502
1503 Returns an empty list if the directory is unreadable, does not
1504 exist, or if nothing matches the specification.
1505
1506 \include qdir.cpp {entrylist_memory_spike} {QFileInfo}
1507
1508 \sa entryList(), setNameFilters(), setSorting(), setFilter(), isReadable(), exists()
1509*/
1510QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
1511{
1512 Q_D(const QDir);
1513 return entryInfoList(d->nameFilters, filters, sort);
1514}
1515
1516/*!
1517 Returns a list of the names of all the files and
1518 directories in the directory, ordered according to the name
1519 and attribute filters previously set with setNameFilters()
1520 and setFilter(), and sorted according to the flags set with
1521 setSorting().
1522
1523 The name filter, file attribute filter, and sorting specification
1524 can be overridden using the \a nameFilters, \a filters, and \a sort
1525 arguments.
1526
1527 Returns an empty list if the directory is unreadable, does not
1528 exist, or if nothing matches the specification.
1529
1530 \include qdir.cpp {entrylist_memory_spike} {QString}
1531
1532 \sa entryInfoList(), setNameFilters(), setSorting(), setFilter()
1533*/
1534QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
1535 SortFlags sort) const
1536{
1537 Q_D(const QDir);
1538
1539 if (filters == NoFilter)
1540 filters = d->filters;
1541 if (sort == NoSort)
1542 sort = d->sort;
1543
1544 const bool needsSorting = (sort & QDir::SortByMask) != QDir::Unsorted;
1545
1546 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1547 // Don't fill a QFileInfo cache if we just need names
1548 if (needsSorting || d->fileCache.fileListsInitialized) {
1549 d->initFileLists(*this);
1550 return d->fileCache.files;
1551 }
1552 }
1553
1554 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1555 QDirListing dirList(d->dirEntry.filePath(), nameFilters, flags);
1556 QStringList ret;
1557 if (needsSorting) {
1558 QFileInfoList l;
1559 for (const auto &dirEntry : dirList)
1560 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1561 d->sortFileList(sort, l, &ret, nullptr);
1562 } else {
1563 for (const auto &dirEntry : dirList)
1564 ret.emplace_back(dirEntry.fileName());
1565 }
1566 return ret;
1567}
1568
1569/*!
1570 Returns a list of QFileInfo objects for all the files and
1571 directories in the directory, ordered according to the name
1572 and attribute filters previously set with setNameFilters()
1573 and setFilter(), and sorted according to the flags set with
1574 setSorting().
1575
1576 The name filter, file attribute filter, and sorting specification
1577 can be overridden using the \a nameFilters, \a filters, and \a sort
1578 arguments.
1579
1580 Returns an empty list if the directory is unreadable, does not
1581 exist, or if nothing matches the specification.
1582
1583 \include qdir.cpp {entrylist_memory_spike} {QFileInfo}
1584
1585 \sa entryList(), setNameFilters(), setSorting(), setFilter(), isReadable(), exists()
1586*/
1587QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filters,
1588 SortFlags sort) const
1589{
1590 Q_D(const QDir);
1591
1592 if (filters == NoFilter)
1593 filters = d->filters;
1594 if (sort == NoSort)
1595 sort = d->sort;
1596
1597 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1598 d->initFileLists(*this);
1599 return d->fileCache.fileInfos;
1600 }
1601
1602 QFileInfoList l;
1603 const QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1604 for (const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, flags))
1605 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1606 QFileInfoList ret;
1607 d->sortFileList(sort, l, nullptr, &ret);
1608 return ret;
1609}
1610#endif // !QT_BOOTSTRAPPED
1611
1612/*!
1613 Creates a sub-directory called \a dirName with the given \a permissions.
1614
1615 If \a permissions is \c std::nullopt (the default) this function will
1616 set the default permissions.
1617
1618 Returns \c true on success; returns \c false if the operation failed or
1619 \a dirName already existed.
1620
1621 If \a dirName already existed, this method won't change its permissions.
1622
1623//! [dir-creation-mode-bits-unix]
1624 On POSIX systems \a permissions are modified by the
1625 \l{https://pubs.opengroup.org/onlinepubs/9799919799/functions/umask.html}{\c umask}
1626 (file creation mask) of the current process, which means some permission
1627 bits might be disabled.
1628//! [dir-creation-mode-bits-unix]
1629
1630//! [windows-permissions-acls]
1631 On Windows, by default, a new directory inherits its permissions from its
1632 parent directory. \a permissions are emulated using ACLs. These ACLs may
1633 be in non-canonical order when the group is granted less permissions than
1634 others. Files and directories with such permissions will generate warnings
1635 when the Security tab of the Properties dialog is opened. Granting the
1636 group all permissions granted to others avoids such warnings.
1637//! [windows-permissions-acls]
1638
1639 \note Qt 6.10 added the \a permissions parameter. To get the old behavior
1640 (using the default platform-specific permissions) of \c{mkdir(const QString &)}
1641 set \a permissions to \c std::nullopt (the default). This new method also
1642 transparently replaces the \c {mkdir(const QString &, QFile::Permissions)}
1643 overload.
1644
1645 \sa rmdir(), mkpath(), rmpath()
1646*/
1647bool QDir::mkdir(const QString &dirName, std::optional<QFile::Permissions> permissions) const
1648{
1649 Q_D(const QDir);
1650
1651 if (dirName.isEmpty()) {
1652 qWarning("QDir::mkdir: Empty or null file name");
1653 return false;
1654 }
1655
1656 QString fn = filePath(dirName);
1657 if (!d->fileEngine)
1658 return QFileSystemEngine::mkdir(QFileSystemEntry(fn), permissions);
1659 return d->fileEngine->mkdir(fn, false, permissions);
1660}
1661
1662/*!
1663 Removes the directory specified by \a dirName.
1664
1665 The directory must be empty for rmdir() to succeed.
1666
1667 Returns \c true if successful; otherwise returns \c false.
1668
1669 \sa mkdir()
1670*/
1671bool QDir::rmdir(const QString &dirName) const
1672{
1673 Q_D(const QDir);
1674
1675 if (dirName.isEmpty()) {
1676 qWarning("QDir::rmdir: Empty or null file name");
1677 return false;
1678 }
1679
1680 QString fn = filePath(dirName);
1681 if (!d->fileEngine)
1682 return QFileSystemEngine::rmdir(QFileSystemEntry(fn));
1683
1684 return d->fileEngine->rmdir(fn, false);
1685}
1686
1687/*!
1688 Creates a directory named \a dirPath.
1689
1690 If \a dirPath doesn't already exist, this method will create it - along with
1691 any nonexistent parent directories - with \a permissions.
1692
1693 If \a dirPath already existed, this method won't change its permissions;
1694 the same goes for any already existing parent directories.
1695
1696 If \a permissions is \c std::nullopt (the default value) this function will
1697 set the default permissions.
1698
1699 Returns \c true on success or if \a dirPath already existed; otherwise
1700 returns \c false.
1701
1702 \include qdir.cpp dir-creation-mode-bits-unix
1703
1704 \include qdir.cpp windows-permissions-acls
1705
1706 \note Qt 6.10 added the \a permissions parameter. To get the old behavior
1707 (using the default platform-specific permissions) of \c{mkpath(const QString &)}
1708 set \a permissions to \c std::nullopt (the default).
1709
1710 \sa rmpath(), mkdir(), rmdir()
1711*/
1712bool QDir::mkpath(const QString &dirPath, std::optional<QFile::Permissions> permissions) const
1713{
1714 Q_D(const QDir);
1715
1716 if (dirPath.isEmpty()) {
1717 qWarning("QDir::mkpath: Empty or null file name");
1718 return false;
1719 }
1720
1721 QString fn = filePath(dirPath);
1722 if (!d->fileEngine)
1723 return QFileSystemEngine::mkpath(QFileSystemEntry(fn), permissions);
1724 return d->fileEngine->mkdir(fn, true, permissions);
1725}
1726
1727/*!
1728 Removes the directory path \a dirPath.
1729
1730 The function will remove all parent directories in \a dirPath,
1731 provided that they are empty. This is the opposite of
1732 mkpath(dirPath).
1733
1734 Returns \c true if successful; otherwise returns \c false.
1735
1736 \sa mkpath()
1737*/
1738bool QDir::rmpath(const QString &dirPath) const
1739{
1740 Q_D(const QDir);
1741
1742 if (dirPath.isEmpty()) {
1743 qWarning("QDir::rmpath: Empty or null file name");
1744 return false;
1745 }
1746
1747 QString fn = filePath(dirPath);
1748 if (!d->fileEngine)
1749 return QFileSystemEngine::rmpath(QFileSystemEntry(fn));
1750 return d->fileEngine->rmdir(fn, true);
1751}
1752
1753#ifndef QT_BOOTSTRAPPED
1754/*!
1755 \since 5.0
1756 Removes the directory, including all its contents.
1757
1758 Returns \c true if successful, otherwise false.
1759
1760 If a file or directory cannot be removed, removeRecursively() keeps going
1761 and attempts to delete as many files and sub-directories as possible,
1762 then returns \c false.
1763
1764 If the directory was already removed, the method returns \c true
1765 (expected result already reached).
1766
1767 \note This function is meant for removing a small application-internal
1768 directory (such as a temporary directory), but not user-visible
1769 directories. For user-visible operations, it is rather recommended
1770 to report errors more precisely to the user, to offer solutions
1771 in case of errors, to show progress during the deletion since it
1772 could take several minutes, etc.
1773*/
1774bool QDir::removeRecursively()
1775{
1776 if (!d_ptr->exists())
1777 return true;
1778
1779 bool success = true;
1780 const QString dirPath = path();
1781 // not empty -- we must empty it first
1782 for (const auto &dirEntry : QDirListing(dirPath, QDirListing::IteratorFlag::IncludeHidden)) {
1783 const QString &filePath = dirEntry.filePath();
1784 bool ok;
1785 if (dirEntry.isDir() && !dirEntry.isSymLink()) {
1786 ok = QDir(filePath).removeRecursively(); // recursive
1787 } else {
1788 ok = QFile::remove(filePath);
1789 if (!ok) { // Read-only files prevent directory deletion on Windows, retry with Write permission.
1790 const QFile::Permissions permissions = QFile::permissions(filePath);
1791 if (!(permissions & QFile::WriteUser))
1792 ok = QFile::setPermissions(filePath, permissions | QFile::WriteUser)
1793 && QFile::remove(filePath);
1794 }
1795 }
1796 if (!ok)
1797 success = false;
1798 }
1799
1800 if (success)
1801 success = rmdir(absolutePath());
1802
1803 return success;
1804}
1805#endif // !QT_BOOTSTRAPPED
1806
1807/*!
1808 Returns \c true if the directory is readable \e and we can open files
1809 by name; otherwise returns \c false.
1810
1811 \warning A false value from this function is not a guarantee that
1812 files in the directory are not accessible.
1813
1814 \sa QFileInfo::isReadable()
1815*/
1816bool QDir::isReadable() const
1817{
1818 Q_D(const QDir);
1819
1820 if (!d->fileEngine) {
1821 QMutexLocker locker(&d->fileCache.mutex);
1822 if (!d->fileCache.metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) {
1823 QFileSystemEngine::fillMetaData(d->dirEntry, d->fileCache.metaData,
1824 QFileSystemMetaData::UserReadPermission);
1825 }
1826 return d->fileCache.metaData.permissions().testAnyFlag(QFile::ReadUser);
1827 }
1828
1829 const QAbstractFileEngine::FileFlags info =
1830 d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
1831 | QAbstractFileEngine::PermsMask);
1832 if (!(info & QAbstractFileEngine::DirectoryType))
1833 return false;
1834 return info.testAnyFlag(QAbstractFileEngine::ReadUserPerm);
1835}
1836
1837/*!
1838 \overload
1839
1840 Returns \c true if the directory exists; otherwise returns \c false.
1841 (If a file with the same name is found this function will return false).
1842
1843 The overload of this function that accepts an argument is used to test
1844 for the presence of files and directories within a directory.
1845
1846 \sa QFileInfo::exists(), QFile::exists()
1847*/
1848bool QDir::exists() const
1849{
1850 return d_ptr->exists();
1851}
1852
1853/*!
1854 Returns \c true if the directory is the root directory; otherwise
1855 returns \c false.
1856
1857 \note If the directory is a symbolic link to the root directory
1858 this function returns \c false. If you want to test for this use
1859 canonicalPath(), e.g.
1860
1861 \snippet code/src_corelib_io_qdir.cpp 9
1862
1863 \sa root(), rootPath()
1864*/
1865bool QDir::isRoot() const
1866{
1867 if (!d_ptr->fileEngine)
1868 return d_ptr->dirEntry.isRoot();
1869 return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask).testAnyFlag(QAbstractFileEngine::RootFlag);
1870}
1871
1872/*!
1873 \fn bool QDir::isAbsolute() const
1874
1875 Returns \c true if the directory's path is absolute; otherwise
1876 returns \c false. See isAbsolutePath().
1877
1878 \note Paths starting with a colon (\e{:}) are always considered
1879 absolute, as they denote a QResource.
1880
1881 \sa isRelative(), makeAbsolute(), cleanPath()
1882*/
1883
1884/*!
1885 \fn bool QDir::isAbsolutePath(const QString &)
1886
1887 Returns \c true if \a path is absolute; returns \c false if it is
1888 relative.
1889
1890 \note Paths starting with a colon (\e{:}) are always considered
1891 absolute, as they denote a QResource.
1892
1893 \sa isAbsolute(), isRelativePath(), makeAbsolute(), cleanPath(), QResource
1894*/
1895
1896/*!
1897 Returns \c true if the directory path is relative; otherwise returns
1898 false. (Under Unix a path is relative if it does not start with a
1899 "/").
1900
1901 \note Paths starting with a colon (\e{:}) are always considered
1902 absolute, as they denote a QResource.
1903
1904 \sa makeAbsolute(), isAbsolute(), isAbsolutePath(), cleanPath()
1905*/
1906bool QDir::isRelative() const
1907{
1908 if (!d_ptr->fileEngine)
1909 return d_ptr->dirEntry.isRelative();
1910 return d_ptr->fileEngine->isRelativePath();
1911}
1912
1913
1914/*!
1915 Converts the directory path to an absolute path. If it is already
1916 absolute nothing happens. Returns \c true if the conversion
1917 succeeded; otherwise returns \c false.
1918
1919 \sa isAbsolute(), isAbsolutePath(), isRelative(), cleanPath()
1920*/
1921bool QDir::makeAbsolute()
1922{
1923 Q_D(const QDir);
1924 std::unique_ptr<QDirPrivate> dir;
1925 if (!!d->fileEngine) {
1926 QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
1927 if (QDir::isRelativePath(absolutePath))
1928 return false;
1929
1930 dir.reset(new QDirPrivate(*d_ptr.constData()));
1931 dir->setPath(absolutePath);
1932 } else { // native FS
1933 QString absoluteFilePath = d->resolveAbsoluteEntry();
1934 dir.reset(new QDirPrivate(*d_ptr.constData()));
1935 dir->setPath(absoluteFilePath);
1936 }
1937 d_ptr = dir.release(); // actually detach
1938 return true;
1939}
1940
1941/*!
1942 \fn bool QDir::operator==(const QDir &lhs, const QDir &rhs)
1943
1944 Returns \c true if directory \a lhs and directory \a rhs have the same
1945 path and their sort and filter settings are the same; otherwise
1946 returns \c false.
1947
1948 Example:
1949
1950 \snippet code/src_corelib_io_qdir.cpp 10
1951*/
1952bool comparesEqual(const QDir &lhs, const QDir &rhs)
1953{
1954 const QDirPrivate *d = lhs.d_ptr.constData();
1955 const QDirPrivate *other = rhs.d_ptr.constData();
1956
1957 if (d == other)
1958 return true;
1959 Qt::CaseSensitivity sensitive;
1960 if (!d->fileEngine || !other->fileEngine) {
1961 if (d->fileEngine.get() != other->fileEngine.get()) // one is native, the other is a custom file-engine
1962 return false;
1963
1964 QOrderedMutexLocker locker(&d->fileCache.mutex, &other->fileCache.mutex);
1965 const bool thisCaseSensitive = QFileSystemEngine::isCaseSensitive(d->dirEntry, d->fileCache.metaData);
1966 if (thisCaseSensitive != QFileSystemEngine::isCaseSensitive(other->dirEntry, other->fileCache.metaData))
1967 return false;
1968
1969 sensitive = thisCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
1970 } else {
1971 if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
1972 return false;
1973 sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1974 }
1975
1976 if (d->filters == other->filters
1977 && d->sort == other->sort
1978 && d->nameFilters == other->nameFilters) {
1979
1980 // Assume directories are the same if path is the same
1981 if (d->dirEntry.filePath() == other->dirEntry.filePath())
1982 return true;
1983
1984 if (lhs.exists()) {
1985 if (!rhs.exists())
1986 return false; //can't be equal if only one exists
1987 // Both exist, fallback to expensive canonical path computation
1988 return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0;
1989 } else {
1990 if (rhs.exists())
1991 return false; //can't be equal if only one exists
1992 // Neither exists, compare absolute paths rather than canonical (which would be empty strings)
1993 QString thisFilePath = d->resolveAbsoluteEntry();
1994 QString otherFilePath = other->resolveAbsoluteEntry();
1995 return thisFilePath.compare(otherFilePath, sensitive) == 0;
1996 }
1997 }
1998 return false;
1999}
2000
2001/*!
2002 Makes a copy of the \a dir object and assigns it to this QDir
2003 object.
2004*/
2005QDir &QDir::operator=(const QDir &dir)
2006{
2007 d_ptr = dir.d_ptr;
2008 return *this;
2009}
2010
2011/*!
2012 \fn void QDir::swap(QDir &other)
2013 \since 5.0
2014 \memberswap{QDir instance}
2015*/
2016
2017/*!
2018 \fn bool QDir::operator!=(const QDir &lhs, const QDir &rhs)
2019
2020 Returns \c true if directory \a lhs and directory \a rhs have different
2021 paths or different sort or filter settings; otherwise returns \c false.
2022
2023 Example:
2024
2025 \snippet code/src_corelib_io_qdir.cpp 11
2026*/
2027
2028/*!
2029 Removes the file, \a fileName.
2030
2031 Returns \c true if the file is removed successfully; otherwise
2032 returns \c false.
2033*/
2034bool QDir::remove(const QString &fileName)
2035{
2036 if (fileName.isEmpty()) {
2037 qWarning("QDir::remove: Empty or null file name");
2038 return false;
2039 }
2040 return QFile::remove(filePath(fileName));
2041}
2042
2043/*!
2044 Renames a file or directory from \a oldName to \a newName, and returns
2045 true if successful; otherwise returns \c false.
2046
2047 On most file systems, rename() fails only if \a oldName does not
2048 exist, or if a file with the new name already exists.
2049 However, there are also other reasons why rename() can
2050 fail. For example, on at least one file system rename() fails if
2051 \a newName points to an open file.
2052
2053 If \a oldName is a file (not a directory) that can't be renamed
2054 right away, Qt will try to copy \a oldName to \a newName and remove
2055 \a oldName.
2056
2057 \sa QFile::rename()
2058*/
2059bool QDir::rename(const QString &oldName, const QString &newName)
2060{
2061 if (oldName.isEmpty() || newName.isEmpty()) {
2062 qWarning("QDir::rename: Empty or null file name(s)");
2063 return false;
2064 }
2065
2066 QFile file(filePath(oldName));
2067 if (!file.exists())
2068 return false;
2069 return file.rename(filePath(newName));
2070}
2071
2072/*!
2073 Returns \c true if the file called \a name exists; otherwise returns
2074 false.
2075
2076 Unless \a name contains an absolute file path, the file name is assumed
2077 to be relative to the directory itself, so this function is typically used
2078 to check for the presence of files within a directory.
2079
2080 \sa QFileInfo::exists(), QFile::exists()
2081*/
2082bool QDir::exists(const QString &name) const
2083{
2084 if (name.isEmpty()) {
2085 qWarning("QDir::exists: Empty or null file name");
2086 return false;
2087 }
2088 return QFileInfo::exists(filePath(name));
2089}
2090
2091#ifndef QT_BOOTSTRAPPED
2092/*!
2093 Returns whether the directory is empty.
2094
2095 Equivalent to \c{count() == 0} with filters
2096 \c{QDir::AllEntries | QDir::NoDotAndDotDot}, but faster as it just checks
2097 whether the directory contains at least one entry.
2098
2099 \note Unless you set the \a filters flags to include \c{QDir::NoDotAndDotDot}
2100 (as the default value does), no directory is empty.
2101
2102 \sa count(), entryList(), setFilter()
2103 \since 5.9
2104*/
2105bool QDir::isEmpty(Filters filters) const
2106{
2107 Q_D(const QDir);
2108
2109 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
2110 for (const auto &dirEntry : QDirListing(d->dirEntry.filePath(), d->nameFilters, flags)) {
2111 if (QDirPrivate::checkNonDirListingFlags(dirEntry, filters))
2112 return false;
2113 }
2114 return true;
2115}
2116#endif // !QT_BOOTSTRAPPED
2117
2118/*!
2119 Returns a list of the root directories on this system.
2120
2121 On Windows this returns a list of QFileInfo objects containing "C:/",
2122 "D:/", etc. This does not return drives with ejectable media that are empty.
2123 On other operating systems, it returns a list containing
2124 just one root directory (i.e. "/").
2125
2126 \sa root(), rootPath()
2127*/
2128QFileInfoList QDir::drives()
2129{
2130#ifdef QT_NO_FSFILEENGINE
2131 return QFileInfoList();
2132#else
2133 return QFSFileEngine::drives();
2134#endif
2135}
2136
2137/*!
2138 \fn QChar QDir::separator()
2139
2140 Returns the native directory separator: "/" under Unix
2141 and "\\" under Windows.
2142
2143 You do not need to use this function to build file paths. If you
2144 always use "/", Qt will translate your paths to conform to the
2145 underlying operating system. If you want to display paths to the
2146 user using their operating system's separator use
2147 toNativeSeparators().
2148
2149 \sa listSeparator()
2150*/
2151
2152/*!
2153 \fn QDir::listSeparator()
2154 \since 5.6
2155
2156 Returns the native path list separator: ':' under Unix
2157 and ';' under Windows.
2158
2159 \sa separator()
2160*/
2161
2162/*!
2163 Sets the application's current working directory to \a path.
2164 Returns \c true if the directory was successfully changed; otherwise
2165 returns \c false.
2166
2167 \snippet code/src_corelib_io_qdir.cpp 16
2168
2169 \sa current(), currentPath(), home(), root(), temp()
2170*/
2171bool QDir::setCurrent(const QString &path)
2172{
2173 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
2174}
2175
2176/*!
2177 \fn QDir QDir::current()
2178
2179 Returns the application's current directory.
2180
2181 The directory is constructed using the absolute path of the current directory,
2182 ensuring that its path() will be the same as its absolutePath().
2183
2184 \sa currentPath(), setCurrent(), home(), root(), temp()
2185*/
2186
2187/*!
2188 Returns the absolute path of the application's current directory. The
2189 current directory is the last directory set with QDir::setCurrent() or, if
2190 that was never called, the directory at which this application was started
2191 at by the parent process.
2192
2193 \sa current(), setCurrent(), homePath(), rootPath(), tempPath(), QCoreApplication::applicationDirPath()
2194*/
2195QString QDir::currentPath()
2196{
2197 return QFileSystemEngine::currentPath().filePath();
2198}
2199
2200/*!
2201 \fn QDir QDir::home()
2202
2203 Returns the user's home directory.
2204
2205 The directory is constructed using the absolute path of the home directory,
2206 ensuring that its path() will be the same as its absolutePath().
2207
2208 See homePath() for details.
2209
2210 \sa drives(), current(), root(), temp()
2211*/
2212
2213/*!
2214 Returns the absolute path of the user's home directory.
2215
2216 Under Windows this function will return the directory of the
2217 current user's profile. Typically, this is:
2218
2219 \snippet code/src_corelib_io_qdir.cpp 12
2220
2221 Use the toNativeSeparators() function to convert the separators to
2222 the ones that are appropriate for the underlying operating system.
2223
2224 If the directory of the current user's profile does not exist or
2225 cannot be retrieved, the following alternatives will be checked (in
2226 the given order) until an existing and available path is found:
2227
2228 \list 1
2229 \li The path specified by the \c USERPROFILE environment variable.
2230 \li The path formed by concatenating the \c HOMEDRIVE and \c HOMEPATH
2231 environment variables.
2232 \li The path specified by the \c HOME environment variable.
2233 \li The path returned by the rootPath() function (which uses the \c SystemDrive
2234 environment variable)
2235 \li The \c{C:/} directory.
2236 \endlist
2237
2238 Under non-Windows operating systems the \c HOME environment
2239 variable is used if it exists, otherwise the path returned by the
2240 rootPath().
2241
2242 \sa home(), currentPath(), rootPath(), tempPath()
2243*/
2244QString QDir::homePath()
2245{
2246 return QFileSystemEngine::homePath();
2247}
2248
2249/*!
2250 \fn QDir QDir::temp()
2251
2252 Returns the system's temporary directory.
2253
2254 The directory is constructed using the absolute canonical path of the temporary directory,
2255 ensuring that its path() will be the same as its absolutePath().
2256
2257 See tempPath() for details.
2258
2259 \sa drives(), current(), home(), root()
2260*/
2261
2262/*!
2263 Returns the absolute canonical path of the system's temporary directory.
2264
2265 On Unix/Linux systems this is the path in the \c TMPDIR environment
2266 variable or \c{/tmp} if \c TMPDIR is not defined. On Windows this is
2267 usually the path in the \c TEMP or \c TMP environment
2268 variable.
2269 The path returned by this method doesn't end with a directory separator
2270 unless it is the root directory (of a drive).
2271
2272 \sa temp(), currentPath(), homePath(), rootPath()
2273*/
2274QString QDir::tempPath()
2275{
2276 return QFileSystemEngine::tempPath();
2277}
2278
2279/*!
2280 \fn QDir QDir::root()
2281
2282 Returns the root directory.
2283
2284 The directory is constructed using the absolute path of the root directory,
2285 ensuring that its path() will be the same as its absolutePath().
2286
2287 See rootPath() for details.
2288
2289 \sa drives(), current(), home(), temp()
2290*/
2291
2292/*!
2293 Returns the absolute path of the root directory.
2294
2295 For Unix operating systems this returns "/". For Windows file
2296 systems this normally returns "c:/".
2297
2298 \sa root(), drives(), currentPath(), homePath(), tempPath()
2299*/
2300QString QDir::rootPath()
2301{
2302 return QFileSystemEngine::rootPath();
2303}
2304
2305#if QT_CONFIG(regularexpression)
2306/*!
2307 \overload
2308
2309 Returns \c true if the \a fileName matches any of the wildcard (glob)
2310 patterns in the list of \a filters; otherwise returns \c false. The
2311 matching is case insensitive.
2312
2313 \sa QRegularExpression::fromWildcard(), entryList(), entryInfoList()
2314*/
2315bool QDir::match(const QStringList &filters, const QString &fileName)
2316{
2317 for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
2318 // Insensitive exact match
2319 auto rx = QRegularExpression::fromWildcard(*sit, Qt::CaseInsensitive);
2320 if (rx.match(fileName).hasMatch())
2321 return true;
2322 }
2323 return false;
2324}
2325
2326/*!
2327 Returns \c true if the \a fileName matches the wildcard (glob)
2328 pattern \a filter; otherwise returns \c false. The \a filter may
2329 contain multiple patterns separated by spaces or semicolons.
2330 The matching is case insensitive.
2331
2332 \sa QRegularExpression::fromWildcard(), entryList(), entryInfoList()
2333*/
2334bool QDir::match(const QString &filter, const QString &fileName)
2335{
2336 return match(nameFiltersFromString(filter), fileName);
2337}
2338#endif // QT_CONFIG(regularexpression)
2339
2340static qsizetype findStartOfNonNormalizedPath(const QChar *in, qsizetype i, qsizetype n,
2341 QDirPrivate::PathNormalizations flags) noexcept
2342{
2343 // Scan the input for a "." or ".." segment. If there isn't any, we may not
2344 // need to modify this path at all. Also scan for "//" segments, which
2345 // will be normalized if the path is local.
2346 const bool isRemote = flags.testAnyFlag(QDirPrivate::RemotePath);
2347 for (bool lastWasSlash = true; i < n; ++i) {
2348 if (lastWasSlash && in[i] == u'.') {
2349 if (i + 1 == n || in[i + 1] == u'/')
2350 break;
2351 if (in[i + 1] == u'.' && (i + 2 == n || in[i + 2] == u'/'))
2352 break;
2353 }
2354 if (!isRemote && lastWasSlash && in[i] == u'/' && i > 0) {
2355 // backtrack one, so the algorithm below gobbles up the remaining
2356 // slashes
2357 --i;
2358 break;
2359 }
2360 lastWasSlash = in[i] == u'/';
2361 }
2362 return i;
2363}
2364
2365bool qt_isPathNormalized(const QString &path, QDirPrivate::PathNormalizations flags) noexcept
2366{
2367 const qsizetype prefixLength = rootLength(path, flags);
2368 qsizetype where = findStartOfNonNormalizedPath(path.constBegin(), prefixLength, path.size(), flags);
2369 return where == path.size();
2370}
2371
2372/*!
2373 \internal
2374
2375 Updates \a path with redundant directory separators removed, and "."s and
2376 ".."s resolved (as far as possible). It returns \c false if there were ".."
2377 segments left over, attempt to go up past the root (only applies to
2378 absolute paths), or \c true otherwise.
2379
2380 This method is shared with QUrl, so it doesn't deal with QDir::separator(),
2381 nor does it remove the trailing slash, if any.
2382
2383 When dealing with URLs, we are following the "Remove dot segments"
2384 algorithm from https://www.ietf.org/rfc/rfc3986.html#section-5.2.4
2385 URL mode differs from local path mode in these ways:
2386 1) it can set *path to empty ("." becomes "")
2387 2) directory path outputs end in / ("a/.." becomes "a/" instead of "a")
2388 3) a sequence of "//" is treated as multiple path levels ("a/b//.." becomes
2389 "a/b/" and "a/b//../.." becomes "a/"), which matches the behavior
2390 observed in web browsers.
2391
2392 As a Qt extension, for local URLs we treat multiple slashes as one slash.
2393*/
2394bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
2395{
2396 const bool isRemote = flags.testAnyFlag(QDirPrivate::RemotePath);
2397 const qsizetype prefixLength = rootLength(*path, flags);
2398
2399 // RFC 3986 says: "The input buffer is initialized with the now-appended
2400 // path components and the output buffer is initialized to the empty
2401 // string."
2402 const QChar *in = path->constBegin();
2403
2404 qsizetype n = path->size();
2405 qsizetype i = findStartOfNonNormalizedPath(in, prefixLength, n, flags);
2406 if (i == n)
2407 return true;
2408
2409 QChar *out = path->data(); // detaches
2410 const QChar *start = out + prefixLength;
2411 const QChar *end = out + path->size();
2412 out += i;
2413 in = out;
2414
2415 // We implement a modified algorithm compared to RFC 3986, for efficiency.
2416 bool ok = true;
2417 do {
2418#if 0 // to see in the debugger
2419 QString output = QStringView(path->constBegin(), out).toString();
2420 QStringView input(in, end);
2421#endif
2422
2423 // First, copy the preceding slashes, so we can look at the segment's
2424 // content. If the path is part of a URL, we copy all slashes, otherwise
2425 // just one.
2426 if (in[0] == u'/') {
2427 *out++ = *in++;
2428 while (in < end && in[0] == u'/') {
2429 if (isRemote)
2430 *out++ = *in++;
2431 else
2432 ++in; // Skip multiple slashes for local URLs
2433
2434 // Note: we may exit this loop with in == end, in which case we
2435 // *shouldn't* dereference *in. But since we are pointing to a
2436 // detached, non-empty QString, we know there's a u'\0' at the
2437 // end, so dereferencing is safe.
2438 }
2439 }
2440
2441 // Is this path segment either "." or ".."?
2442 enum { Nothing, Dot, DotDot } type = Nothing;
2443 if (in[0] == u'.') {
2444 if (in + 1 == end || in[1] == u'/')
2445 type = Dot;
2446 else if (in[1] == u'.' && (in + 2 == end || in[2] == u'/'))
2447 type = DotDot;
2448 }
2449 if (type == Nothing) {
2450 // If it is neither, then we copy this segment.
2451 while (in < end && in[0] != u'/')
2452 *out++ = *in++;
2453 continue;
2454 }
2455
2456 // Otherwise, we skip it and remove preceding slashes (if
2457 // any, exactly one if part of a URL, all otherwise) from the
2458 // output. If it is "..", we remove the segment before that and
2459 // preceding slashes too in a similar fashion, if they are there.
2460 if (type == DotDot) {
2461 if (Q_UNLIKELY(out == start)) {
2462 // we can't go further up from here, so we "re-root"
2463 // without cleaning this segment
2464 ok = false;
2465 if (!isRemote) {
2466 *out++ = u'.';
2467 *out++ = u'.';
2468 if (in + 2 != end) {
2469 Q_ASSERT(in[2] == u'/');
2470 *out++ = u'/';
2471 ++in;
2472 }
2473 start = out;
2474 in += 2;
2475 continue;
2476 }
2477 }
2478
2479 if (out > start)
2480 --out; // backtrack the first dot
2481 // backtrack the previous path segment
2482 while (out > start && out[-1] != u'/')
2483 --out;
2484 in += 2; // the two dots
2485 } else {
2486 ++in; // the one dot
2487 }
2488
2489 // Not at 'end' yet, prepare for the next loop iteration by backtracking one slash.
2490 // E.g.: /a/b/../c >>> /a/b/../c
2491 // ^out ^out
2492 // the next iteration will copy '/c' to the output buffer >>> /a/c
2493 if (in != end && out > start && out[-1] == u'/')
2494 --out;
2495 if (out == start) {
2496 // We've reached the root. Make sure we don't turn a relative path
2497 // to absolute or, in the case of local paths that are already
2498 // absolute, into UNC.
2499 // Note: this will turn ".//a" into "a" even for URLs!
2500 if (in != end && in[0] == u'/')
2501 ++in;
2502 while (prefixLength == 0 && in != end && in[0] == u'/')
2503 ++in;
2504 }
2505 } while (in < end);
2506
2507 path->truncate(out - path->constBegin());
2508 if (!isRemote && path->isEmpty())
2509 *path = u"."_s;
2510
2511 // we return false only if the path was absolute
2512 return ok || prefixLength == 0;
2513}
2514
2515static bool qt_cleanPath(QString *path)
2516{
2517 if (path->isEmpty())
2518 return true;
2519
2520 QString &ret = *path;
2521 ret = QDir::fromNativeSeparators(ret);
2522 bool ok = qt_normalizePathSegments(&ret, QDirPrivate::DefaultNormalization);
2523
2524 // Strip away last slash except for root directories
2525 if (ret.size() > 1 && ret.endsWith(u'/')) {
2526#if defined (Q_OS_WIN)
2527 if (!(ret.length() == 3 && ret.at(1) == u':'))
2528#endif
2529 ret.chop(1);
2530 }
2531
2532 return ok;
2533}
2534
2535/*!
2536 Returns \a path with directory separators normalized (that is, platform-native
2537 separators converted to "/") and redundant ones removed, and "."s and ".."s
2538 resolved (as far as possible).
2539
2540 Symbolic links are kept. This function does not return the
2541 canonical path, but rather the simplest version of the input.
2542 For example, "./local" becomes "local", "local/../bin" becomes
2543 "bin" and "/local/usr/../bin" becomes "/local/bin".
2544
2545 \sa absolutePath(), canonicalPath()
2546*/
2547QString QDir::cleanPath(const QString &path)
2548{
2549 QString ret = path;
2550 qt_cleanPath(&ret);
2551 return ret;
2552}
2553
2554/*!
2555 Returns \c true if \a path is relative; returns \c false if it is
2556 absolute.
2557
2558 \note Paths starting with a colon (\e{:}) are always considered
2559 absolute, as they denote a QResource.
2560
2561 \sa isRelative(), isAbsolutePath(), makeAbsolute()
2562*/
2563bool QDir::isRelativePath(const QString &path)
2564{
2565 return QFileInfo(path).isRelative();
2566}
2567
2568/*!
2569 Refreshes the directory information.
2570*/
2571void QDir::refresh() const
2572{
2573 QDirPrivate *d = const_cast<QDir *>(this)->d_func();
2574 d->clearCache(QDirPrivate::IncludingMetaData);
2575}
2576
2577/*!
2578 \internal
2579*/
2580QDirPrivate* QDir::d_func()
2581{
2582 return d_ptr.data();
2583}
2584
2585/*!
2586 \internal
2587
2588 Returns a list of name filters from the given \a nameFilter. (If
2589 there is more than one filter, each pair of filters is separated
2590 by a space or by a semicolon.)
2591*/
2592QStringList QDir::nameFiltersFromString(const QString &nameFilter)
2593{
2594 return QDirPrivate::splitFilters(nameFilter);
2595}
2596
2597#ifndef QT_NO_DEBUG_STREAM
2598QDebug operator<<(QDebug debug, QDir::Filters filters)
2599{
2600 QDebugStateSaver save(debug);
2601 debug.resetFormat();
2602 QStringList flags;
2603 if (filters == QDir::NoFilter) {
2604 flags << "NoFilter"_L1;
2605 } else {
2606 if (filters & QDir::Dirs) flags << "Dirs"_L1;
2607 if (filters & QDir::AllDirs) flags << "AllDirs"_L1;
2608 if (filters & QDir::Files) flags << "Files"_L1;
2609 if (filters & QDir::Drives) flags << "Drives"_L1;
2610 if (filters & QDir::NoSymLinks) flags << "NoSymLinks"_L1;
2611 if (filters & QDir::NoDot) flags << "NoDot"_L1;
2612 if (filters & QDir::NoDotDot) flags << "NoDotDot"_L1;
2613 if ((filters & QDir::AllEntries) == QDir::AllEntries) flags << "AllEntries"_L1;
2614 if (filters & QDir::Readable) flags << "Readable"_L1;
2615 if (filters & QDir::Writable) flags << "Writable"_L1;
2616 if (filters & QDir::Executable) flags << "Executable"_L1;
2617 if (filters & QDir::Hidden) flags << "Hidden"_L1;
2618 if (filters & QDir::System) flags << "System"_L1;
2619 if (filters & QDir::CaseSensitive) flags << "CaseSensitive"_L1;
2620 }
2621 debug.noquote() << "QDir::Filters(" << flags.join(u'|') << ')';
2622 return debug;
2623}
2624
2625static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
2626{
2627 QDebugStateSaver save(debug);
2628 debug.resetFormat();
2629 if (sorting == QDir::NoSort) {
2630 debug << "QDir::SortFlags(NoSort)";
2631 } else {
2632 QString type;
2633 if ((sorting & QDir::SortByMask) == QDir::Name) type = "Name"_L1;
2634 if ((sorting & QDir::SortByMask) == QDir::Time) type = "Time"_L1;
2635 if ((sorting & QDir::SortByMask) == QDir::Size) type = "Size"_L1;
2636 if ((sorting & QDir::SortByMask) == QDir::Unsorted) type = "Unsorted"_L1;
2637
2638 QStringList flags;
2639 if (sorting & QDir::DirsFirst) flags << "DirsFirst"_L1;
2640 if (sorting & QDir::DirsLast) flags << "DirsLast"_L1;
2641 if (sorting & QDir::IgnoreCase) flags << "IgnoreCase"_L1;
2642 if (sorting & QDir::LocaleAware) flags << "LocaleAware"_L1;
2643 if (sorting & QDir::Type) flags << "Type"_L1;
2644 debug.noquote() << "QDir::SortFlags(" << type << '|' << flags.join(u'|') << ')';
2645 }
2646 return debug;
2647}
2648
2649QDebug operator<<(QDebug debug, const QDir &dir)
2650{
2651 QDebugStateSaver save(debug);
2652 debug.resetFormat();
2653 debug << "QDir(" << dir.path() << ", nameFilters = {"
2654 << dir.nameFilters().join(u',')
2655 << "}, "
2656 << dir.sorting()
2657 << ','
2658 << dir.filter()
2659 << ')';
2660 return debug;
2661}
2662#endif // QT_NO_DEBUG_STREAM
2663
2664/*!
2665 \fn QDir::QDir(const std::filesystem::path &path)
2666 \since 6.0
2667 Constructs a QDir pointing to the given directory \a path. If path
2668 is empty the program's working directory, ("."), is used.
2669
2670 \sa currentPath()
2671*/
2672/*!
2673 \fn QDir::QDir(const std::filesystem::path &path,
2674 const QString &nameFilter,
2675 SortFlags sort,
2676 Filters filters)
2677 \since 6.0
2678
2679 Constructs a QDir with path \a path, that filters its entries by
2680 name using \a nameFilter and by attributes using \a filters. It
2681 also sorts the names using \a sort.
2682
2683 The default \a nameFilter is an empty string, which excludes
2684 nothing; the default \a filters is \l AllEntries, which also
2685 excludes nothing. The default \a sort is \l Name | \l IgnoreCase,
2686 i.e. sort by name case-insensitively.
2687
2688 If \a path is empty, QDir uses "." (the current
2689 directory). If \a nameFilter is an empty string, QDir uses the
2690 name filter "*" (all files).
2691
2692 \note \a path need not exist.
2693
2694 \sa exists(), setPath(), setNameFilters(), setFilter(), setSorting()
2695*/
2696/*!
2697 \fn void QDir::setPath(const std::filesystem::path &path)
2698 \since 6.0
2699 \overload
2700*/
2701/*!
2702 \fn void QDir::addSearchPath(const QString &prefix, const std::filesystem::path &path)
2703 \since 6.0
2704 \overload
2705*/
2706/*!
2707 \fn std::filesystem::path QDir::filesystemPath() const
2708 \since 6.0
2709 Returns path() as \c{std::filesystem::path}.
2710 \sa path()
2711*/
2712/*!
2713 \fn std::filesystem::path QDir::filesystemAbsolutePath() const
2714 \since 6.0
2715 Returns absolutePath() as \c{std::filesystem::path}.
2716 \sa absolutePath()
2717*/
2718/*!
2719 \fn std::filesystem::path QDir::filesystemCanonicalPath() const
2720 \since 6.0
2721 Returns canonicalPath() as \c{std::filesystem::path}.
2722 \sa canonicalPath()
2723*/
2724
2725QT_END_NAMESPACE
\inmodule QtCore
Definition qdirlisting.h:71
QDirPrivate(const QDirPrivate &copy)
Definition qdir.cpp:105
@ UrlNormalizationMode
Definition qdir_p.h:34
@ RemotePath
Definition qdir_p.h:35
MetaDataClearing
Definition qdir_p.h:64
@ IncludingMetaData
Definition qdir_p.h:64
void clearCache(MetaDataClearing mode)
Definition qdir.cpp:470
void initFileLists(const QDir &dir) const
Definition qdir.cpp:455
bool exists() const
Definition qdir.cpp:122
QString resolveAbsoluteEntry() const
Definition qdir.cpp:178
bool operator()(const QDirSortItem &, const QDirSortItem &) const
Definition qdir.cpp:258
QDirSortItemComparator(QDir::SortFlags flags, QCollator *coll=nullptr)
Definition qdir.cpp:232
int compareStrings(const QString &a, const QString &b, Qt::CaseSensitivity cs) const
Definition qdir.cpp:248
\inmodule QtCore
Definition qmutex.h:346
Combined button and popup list for selecting options.
static void appendIfMatchesNonDirListingFlags(const QDirListing::DirEntry &dirEntry, QDir::Filters filters, QFileInfoList &l)
Definition qdir.cpp:402
static qsizetype rootLength(QStringView name, QDirPrivate::PathNormalizations flags)
Definition qdir.cpp:56
static bool qt_cleanPath(QString *path)
Definition qdir.cpp:2515
QDebug operator<<(QDebug debug, QDir::Filters filters)
Definition qdir.cpp:2598
QDebug operator<<(QDebug debug, const QDir &dir)
Definition qdir.cpp:2649
static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
Definition qdir.cpp:2625
bool qt_isPathNormalized(const QString &path, QDirPrivate::PathNormalizations flags) noexcept
Definition qdir.cpp:2365
bool comparesEqual(const QDir &lhs, const QDir &rhs)
Definition qdir.cpp:1952
static bool treatAsAbsolute(const QString &path)
Definition qdir.cpp:866
static bool checkPermissions(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
Definition qdir.cpp:364
bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
Definition qdir.cpp:2394
static qsizetype findStartOfNonNormalizedPath(const QChar *in, qsizetype i, qsizetype n, QDirPrivate::PathNormalizations flags) noexcept
Definition qdir.cpp:2340
static bool checkDotOrDotDot(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
Definition qdir.cpp:380
QFileInfo item
Definition qdir.cpp:220
QString suffix_cache
Definition qdir.cpp:219
QDirSortItem(const QFileInfo &fi, QDir::SortFlags sort)
Definition qdir.cpp:208
QDirSortItem()=default
QString filename_cache
Definition qdir.cpp:218