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

source code of qtbase/src/corelib/io/qdir.cpp