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