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