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

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