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