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