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