1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qplatformdefs.h"
41#include "qdir.h"
42#include "qdir_p.h"
43#include "qabstractfileengine_p.h"
44#include "qfsfileengine_p.h"
45#ifndef QT_NO_DEBUG_STREAM
46#include "qdebug.h"
47#endif
48#include "qdiriterator.h"
49#include "qdatetime.h"
50#include "qstring.h"
51#if QT_CONFIG(regularexpression)
52# include <qregularexpression.h>
53#endif
54#include "qvector.h"
55#include "qvarlengtharray.h"
56#include "qfilesystementry_p.h"
57#include "qfilesystemmetadata_p.h"
58#include "qfilesystemengine_p.h"
59#include <qstringbuilder.h>
60
61#ifdef QT_BUILD_CORE_LIB
62# include "qresource.h"
63# include "private/qcoreglobaldata_p.h"
64#endif
65
66#include <algorithm>
67#include <stdlib.h>
68
69QT_BEGIN_NAMESPACE
70
71#if defined(Q_OS_WIN)
72static QString driveSpec(const QString &path)
73{
74 if (path.size() < 2)
75 return QString();
76 char c = path.at(0).toLatin1();
77 if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z'))
78 return QString();
79 if (path.at(1).toLatin1() != ':')
80 return QString();
81 return path.mid(0, 2);
82}
83#endif
84
85enum {
86#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
87 OSSupportsUncPaths = true
88#else
89 OSSupportsUncPaths = false
90#endif
91};
92
93// Return the length of the root part of an absolute path, for use by cleanPath(), cd().
94static int rootLength(const QString &name, bool allowUncPaths)
95{
96 const int len = name.length();
97 // starts with double slash
98 if (allowUncPaths && name.startsWith(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
120QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_, QDir::SortFlags sort_, QDir::Filters filters_)
121 : QSharedData()
122 , fileListsInitialized(false)
123 , nameFilters(nameFilters_)
124 , sort(sort_)
125 , filters(filters_)
126{
127 setPath(path.isEmpty() ? QString::fromLatin1(".") : 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
143QDirPrivate::QDirPrivate(const QDirPrivate &copy)
144 : QSharedData(copy)
145 , fileListsInitialized(false)
146 , nameFilters(copy.nameFilters)
147 , sort(copy.sort)
148 , filters(copy.filters)
149 , dirEntry(copy.dirEntry)
150 , metaData(copy.metaData)
151{
152}
153
154bool QDirPrivate::exists() const
155{
156 if (!fileEngine) {
157 QFileSystemEngine::fillMetaData(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
171inline 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
181inline QStringList QDirPrivate::splitFilters(const QString &nameFilter, QChar sep)
182{
183 if (sep.isNull())
184 sep = getFilterSepChar(nameFilter);
185 const QVector<QStringRef> split = nameFilter.splitRef(sep);
186 QStringList ret;
187 ret.reserve(split.size());
188 for (const auto &e : split)
189 ret.append(e.trimmed().toString());
190 return ret;
191}
192
193inline 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
216inline void QDirPrivate::clearFileLists()
217{
218 fileListsInitialized = false;
219 files.clear();
220 fileInfos.clear();
221}
222
223inline void QDirPrivate::resolveAbsoluteEntry() const
224{
225 if (!absoluteDirEntry.isEmpty() || dirEntry.isEmpty())
226 return;
227
228 QString absoluteName;
229 if (!fileEngine) {
230 if (!dirEntry.isRelative() && dirEntry.isClean()) {
231 absoluteDirEntry = dirEntry;
232 return;
233 }
234
235 absoluteName = QFileSystemEngine::absoluteName(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 */
244struct QDirSortItem
245{
246 mutable QString filename_cache;
247 mutable QString suffix_cache;
248 QFileInfo item;
249};
250
251
252class QDirSortItemComparator
253{
254 int qt_cmp_si_sort_flags;
255public:
256 QDirSortItemComparator(int flags) : qt_cmp_si_sort_flags(flags) {}
257 bool operator()(const QDirSortItem &, const QDirSortItem &) const;
258};
259
260bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2) const
261{
262 const QDirSortItem* f1 = &n1;
263 const QDirSortItem* f2 = &n2;
264
265 if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir()))
266 return f1->item.isDir();
267 if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
268 return !f1->item.isDir();
269
270 qint64 r = 0;
271 int sortBy = (qt_cmp_si_sort_flags & QDir::SortByMask)
272 | (qt_cmp_si_sort_flags & QDir::Type);
273
274 switch (sortBy) {
275 case QDir::Time: {
276 QDateTime firstModified = f1->item.lastModified();
277 QDateTime secondModified = f2->item.lastModified();
278
279 // QDateTime by default will do all sorts of conversions on these to
280 // find timezones, which is incredibly expensive. As we aren't
281 // presenting these to the user, we don't care (at all) about the
282 // local timezone, so force them to UTC to avoid that conversion.
283 firstModified.setTimeSpec(Qt::UTC);
284 secondModified.setTimeSpec(Qt::UTC);
285
286 r = firstModified.msecsTo(secondModified);
287 break;
288 }
289 case QDir::Size:
290 r = f2->item.size() - f1->item.size();
291 break;
292 case QDir::Type:
293 {
294 bool ic = qt_cmp_si_sort_flags & QDir::IgnoreCase;
295
296 if (f1->suffix_cache.isNull())
297 f1->suffix_cache = ic ? f1->item.suffix().toLower()
298 : f1->item.suffix();
299 if (f2->suffix_cache.isNull())
300 f2->suffix_cache = ic ? f2->item.suffix().toLower()
301 : f2->item.suffix();
302
303 r = qt_cmp_si_sort_flags & QDir::LocaleAware
304 ? f1->suffix_cache.localeAwareCompare(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
332inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l,
333 QStringList *names, QFileInfoList *infos)
334{
335 // names and infos are always empty lists or 0 here
336 int n = l.size();
337 if (n > 0) {
338 if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
339 if (infos)
340 *infos = l;
341 if (names) {
342 for (int i = 0; i < n; ++i)
343 names->append(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}
362inline void QDirPrivate::initFileLists(const QDir &dir) const
363{
364 if (!fileListsInitialized) {
365 QFileInfoList l;
366 QDirIterator it(dir);
367 while (it.hasNext()) {
368 it.next();
369 l.append(it.fileInfo());
370 }
371 sortFileList(sort, l, &files, &fileInfos);
372 fileListsInitialized = true;
373 }
374}
375
376inline 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*/
568QDir::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*/
578QDir::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*/
600QDir::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*/
612QDir::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*/
621QDir::~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*/
641void 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*/
656QString 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*/
670QString 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*/
693QString 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*/
714QString QDir::dirName() const
715{
716 const QDirPrivate* d = d_ptr.constData();
717 return d->dirEntry.fileName();
718}
719
720
721#ifdef Q_OS_WIN
722static 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
751static 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*/
775QString 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*/
806QString 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*/
841QString 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('/'), QString::SkipEmptyParts);
871 QVector<QStringRef> fileElts = file.splitRef(QLatin1Char('/'), QString::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*/
911QString 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*/
944QString 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
971static 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*/
984bool 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*/
1039bool QDir::cdUp()
1040{
1041 return cd(QString::fromLatin1(".."));
1042}
1043
1044/*!
1045 Returns the string list set by setNameFilters()
1046*/
1047QStringList 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*/
1069void 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*/
1090void QDir::addResourceSearchPath(const QString &path)
1091{
1092#ifdef QT_BUILD_CORE_LIB
1093QT_WARNING_PUSH
1094QT_WARNING_DISABLE_DEPRECATED
1095 QResource::addSearchPath(path);
1096QT_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*/
1124void 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*/
1154void 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*/
1170QStringList 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*/
1181QDir::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*/
1260void 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*/
1274QDir::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*/
1317void 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*/
1333uint 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*/
1347QString 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*/
1373QStringList 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*/
1396QFileInfoList 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*/
1418QStringList 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*/
1460QFileInfoList 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*/
1495bool 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*/
1519bool 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*/
1547bool 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*/
1573bool 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*/
1608bool 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*/
1652bool 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*/
1682bool 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*/
1699bool 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 \sa isAbsolute(), isRelativePath(), makeAbsolute(), cleanPath()
1722*/
1723
1724/*!
1725 Returns \c true if the directory path is relative; otherwise returns
1726 false. (Under Unix a path is relative if it does not start with a
1727 "/").
1728
1729 \sa makeAbsolute(), isAbsolute(), isAbsolutePath(), cleanPath()
1730*/
1731bool QDir::isRelative() const
1732{
1733 if (!d_ptr->fileEngine)
1734 return d_ptr->dirEntry.isRelative();
1735 return d_ptr->fileEngine->isRelativePath();
1736}
1737
1738
1739/*!
1740 Converts the directory path to an absolute path. If it is already
1741 absolute nothing happens. Returns \c true if the conversion
1742 succeeded; otherwise returns \c false.
1743
1744 \sa isAbsolute(), isAbsolutePath(), isRelative(), cleanPath()
1745*/
1746bool QDir::makeAbsolute()
1747{
1748 const QDirPrivate *d = d_ptr.constData();
1749 QScopedPointer<QDirPrivate> dir;
1750 if (!!d->fileEngine) {
1751 QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
1752 if (QDir::isRelativePath(absolutePath))
1753 return false;
1754
1755 dir.reset(new QDirPrivate(*d_ptr.constData()));
1756 dir->setPath(absolutePath);
1757 } else { // native FS
1758 d->resolveAbsoluteEntry();
1759 dir.reset(new QDirPrivate(*d_ptr.constData()));
1760 dir->setPath(d->absoluteDirEntry.filePath());
1761 }
1762 d_ptr = dir.take(); // actually detach
1763 return true;
1764}
1765
1766/*!
1767 Returns \c true if directory \a dir and this directory have the same
1768 path and their sort and filter settings are the same; otherwise
1769 returns \c false.
1770
1771 Example:
1772
1773 \snippet code/src_corelib_io_qdir.cpp 10
1774*/
1775bool QDir::operator==(const QDir &dir) const
1776{
1777 const QDirPrivate *d = d_ptr.constData();
1778 const QDirPrivate *other = dir.d_ptr.constData();
1779
1780 if (d == other)
1781 return true;
1782 Qt::CaseSensitivity sensitive;
1783 if (!d->fileEngine || !other->fileEngine) {
1784 if (d->fileEngine.get() != other->fileEngine.get()) // one is native, the other is a custom file-engine
1785 return false;
1786
1787 sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1788 } else {
1789 if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
1790 return false;
1791 sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1792 }
1793
1794 if (d->filters == other->filters
1795 && d->sort == other->sort
1796 && d->nameFilters == other->nameFilters) {
1797
1798 // Assume directories are the same if path is the same
1799 if (d->dirEntry.filePath() == other->dirEntry.filePath())
1800 return true;
1801
1802 if (exists()) {
1803 if (!dir.exists())
1804 return false; //can't be equal if only one exists
1805 // Both exist, fallback to expensive canonical path computation
1806 return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0;
1807 } else {
1808 if (dir.exists())
1809 return false; //can't be equal if only one exists
1810 // Neither exists, compare absolute paths rather than canonical (which would be empty strings)
1811 d->resolveAbsoluteEntry();
1812 other->resolveAbsoluteEntry();
1813 return d->absoluteDirEntry.filePath().compare(other->absoluteDirEntry.filePath(), sensitive) == 0;
1814 }
1815 }
1816 return false;
1817}
1818
1819/*!
1820 Makes a copy of the \a dir object and assigns it to this QDir
1821 object.
1822*/
1823QDir &QDir::operator=(const QDir &dir)
1824{
1825 d_ptr = dir.d_ptr;
1826 return *this;
1827}
1828
1829#if QT_DEPRECATED_SINCE(5, 13)
1830/*!
1831 \overload
1832 \obsolete
1833
1834 Sets the directory path to the given \a path.
1835
1836 Use setPath() instead.
1837*/
1838QDir &QDir::operator=(const QString &path)
1839{
1840 d_ptr->setPath(path);
1841 return *this;
1842}
1843#endif
1844
1845/*!
1846 \fn void QDir::swap(QDir &other)
1847 \since 5.0
1848
1849 Swaps this QDir instance with \a other. This function is very fast
1850 and never fails.
1851*/
1852
1853/*!
1854 \fn bool QDir::operator!=(const QDir &dir) const
1855
1856 Returns \c true if directory \a dir and this directory have different
1857 paths or different sort or filter settings; otherwise returns
1858 false.
1859
1860 Example:
1861
1862 \snippet code/src_corelib_io_qdir.cpp 11
1863*/
1864
1865/*!
1866 Removes the file, \a fileName.
1867
1868 Returns \c true if the file is removed successfully; otherwise
1869 returns \c false.
1870*/
1871bool QDir::remove(const QString &fileName)
1872{
1873 if (fileName.isEmpty()) {
1874 qWarning("QDir::remove: Empty or null file name");
1875 return false;
1876 }
1877 return QFile::remove(filePath(fileName));
1878}
1879
1880/*!
1881 Renames a file or directory from \a oldName to \a newName, and returns
1882 true if successful; otherwise returns \c false.
1883
1884 On most file systems, rename() fails only if \a oldName does not
1885 exist, or if a file with the new name already exists.
1886 However, there are also other reasons why rename() can
1887 fail. For example, on at least one file system rename() fails if
1888 \a newName points to an open file.
1889
1890 If \a oldName is a file (not a directory) that can't be renamed
1891 right away, Qt will try to copy \a oldName to \a newName and remove
1892 \a oldName.
1893
1894 \sa QFile::rename()
1895*/
1896bool QDir::rename(const QString &oldName, const QString &newName)
1897{
1898 if (oldName.isEmpty() || newName.isEmpty()) {
1899 qWarning("QDir::rename: Empty or null file name(s)");
1900 return false;
1901 }
1902
1903 QFile file(filePath(oldName));
1904 if (!file.exists())
1905 return false;
1906 return file.rename(filePath(newName));
1907}
1908
1909/*!
1910 Returns \c true if the file called \a name exists; otherwise returns
1911 false.
1912
1913 Unless \a name contains an absolute file path, the file name is assumed
1914 to be relative to the directory itself, so this function is typically used
1915 to check for the presence of files within a directory.
1916
1917 \sa QFileInfo::exists(), QFile::exists()
1918*/
1919bool QDir::exists(const QString &name) const
1920{
1921 if (name.isEmpty()) {
1922 qWarning("QDir::exists: Empty or null file name");
1923 return false;
1924 }
1925 return QFile::exists(filePath(name));
1926}
1927
1928/*!
1929 Returns whether the directory is empty.
1930
1931 Equivalent to \c{count() == 0} with filters
1932 \c{QDir::AllEntries | QDir::NoDotAndDotDot}, but faster as it just checks
1933 whether the directory contains at least one entry.
1934
1935 \note Unless you set the \a filters flags to include \c{QDir::NoDotAndDotDot}
1936 (as the default value does), no directory is empty.
1937
1938 \sa count(), entryList(), setFilter()
1939 \since 5.9
1940*/
1941bool QDir::isEmpty(Filters filters) const
1942{
1943 const auto d = d_ptr.constData();
1944 QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters);
1945 return !it.hasNext();
1946}
1947
1948/*!
1949 Returns a list of the root directories on this system.
1950
1951 On Windows this returns a list of QFileInfo objects containing "C:/",
1952 "D:/", etc. On other operating systems, it returns a list containing
1953 just one root directory (i.e. "/").
1954
1955 \sa root(), rootPath()
1956*/
1957QFileInfoList QDir::drives()
1958{
1959#ifdef QT_NO_FSFILEENGINE
1960 return QFileInfoList();
1961#else
1962 return QFSFileEngine::drives();
1963#endif
1964}
1965
1966/*!
1967 Returns the native directory separator: "/" under Unix
1968 and "\\" under Windows.
1969
1970 You do not need to use this function to build file paths. If you
1971 always use "/", Qt will translate your paths to conform to the
1972 underlying operating system. If you want to display paths to the
1973 user using their operating system's separator use
1974 toNativeSeparators().
1975
1976 \sa listSeparator()
1977*/
1978QChar QDir::separator()
1979{
1980#if defined(Q_OS_WIN)
1981 return QLatin1Char('\\');
1982#else
1983 return QLatin1Char('/');
1984#endif
1985}
1986
1987/*!
1988 \fn QDir::listSeparator()
1989 \since 5.6
1990
1991 Returns the native path list separator: ':' under Unix
1992 and ';' under Windows.
1993
1994 \sa separator()
1995*/
1996
1997/*!
1998 Sets the application's current working directory to \a path.
1999 Returns \c true if the directory was successfully changed; otherwise
2000 returns \c false.
2001
2002 \sa current(), currentPath(), home(), root(), temp()
2003*/
2004bool QDir::setCurrent(const QString &path)
2005{
2006 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
2007}
2008
2009/*!
2010 \fn QDir QDir::current()
2011
2012 Returns the application's current directory.
2013
2014 The directory is constructed using the absolute path of the current directory,
2015 ensuring that its path() will be the same as its absolutePath().
2016
2017 \sa currentPath(), setCurrent(), home(), root(), temp()
2018*/
2019
2020/*!
2021 Returns the absolute path of the application's current directory. The
2022 current directory is the last directory set with QDir::setCurrent() or, if
2023 that was never called, the directory at which this application was started
2024 at by the parent process.
2025
2026 \sa current(), setCurrent(), homePath(), rootPath(), tempPath(), QCoreApplication::applicationDirPath()
2027*/
2028QString QDir::currentPath()
2029{
2030 return QFileSystemEngine::currentPath().filePath();
2031}
2032
2033/*!
2034 \fn QDir QDir::home()
2035
2036 Returns the user's home directory.
2037
2038 The directory is constructed using the absolute path of the home directory,
2039 ensuring that its path() will be the same as its absolutePath().
2040
2041 See homePath() for details.
2042
2043 \sa drives(), current(), root(), temp()
2044*/
2045
2046/*!
2047 Returns the absolute path of the user's home directory.
2048
2049 Under Windows this function will return the directory of the
2050 current user's profile. Typically, this is:
2051
2052 \snippet code/src_corelib_io_qdir.cpp 12
2053
2054 Use the toNativeSeparators() function to convert the separators to
2055 the ones that are appropriate for the underlying operating system.
2056
2057 If the directory of the current user's profile does not exist or
2058 cannot be retrieved, the following alternatives will be checked (in
2059 the given order) until an existing and available path is found:
2060
2061 \list 1
2062 \li The path specified by the \c USERPROFILE environment variable.
2063 \li The path formed by concatenating the \c HOMEDRIVE and \c HOMEPATH
2064 environment variables.
2065 \li The path specified by the \c HOME environment variable.
2066 \li The path returned by the rootPath() function (which uses the \c SystemDrive
2067 environment variable)
2068 \li The \c{C:/} directory.
2069 \endlist
2070
2071 Under non-Windows operating systems the \c HOME environment
2072 variable is used if it exists, otherwise the path returned by the
2073 rootPath().
2074
2075 \sa home(), currentPath(), rootPath(), tempPath()
2076*/
2077QString QDir::homePath()
2078{
2079 return QFileSystemEngine::homePath();
2080}
2081
2082/*!
2083 \fn QDir QDir::temp()
2084
2085 Returns the system's temporary directory.
2086
2087 The directory is constructed using the absolute canonical path of the temporary directory,
2088 ensuring that its path() will be the same as its absolutePath().
2089
2090 See tempPath() for details.
2091
2092 \sa drives(), current(), home(), root()
2093*/
2094
2095/*!
2096 Returns the absolute canonical path of the system's temporary directory.
2097
2098 On Unix/Linux systems this is the path in the \c TMPDIR environment
2099 variable or \c{/tmp} if \c TMPDIR is not defined. On Windows this is
2100 usually the path in the \c TEMP or \c TMP environment
2101 variable.
2102 The path returned by this method doesn't end with a directory separator
2103 unless it is the root directory (of a drive).
2104
2105 \sa temp(), currentPath(), homePath(), rootPath()
2106*/
2107QString QDir::tempPath()
2108{
2109 return QFileSystemEngine::tempPath();
2110}
2111
2112/*!
2113 \fn QDir QDir::root()
2114
2115 Returns the root directory.
2116
2117 The directory is constructed using the absolute path of the root directory,
2118 ensuring that its path() will be the same as its absolutePath().
2119
2120 See rootPath() for details.
2121
2122 \sa drives(), current(), home(), temp()
2123*/
2124
2125/*!
2126 Returns the absolute path of the root directory.
2127
2128 For Unix operating systems this returns "/". For Windows file
2129 systems this normally returns "c:/".
2130
2131 \sa root(), drives(), currentPath(), homePath(), tempPath()
2132*/
2133QString QDir::rootPath()
2134{
2135 return QFileSystemEngine::rootPath();
2136}
2137
2138#if QT_CONFIG(regularexpression)
2139/*!
2140 \overload
2141
2142 Returns \c true if the \a fileName matches any of the wildcard (glob)
2143 patterns in the list of \a filters; otherwise returns \c false. The
2144 matching is case insensitive.
2145
2146 \sa {QRegularExpression#Wildcard matching}{QRegularExpression Wildcard Matching},
2147 entryList(), entryInfoList()
2148*/
2149bool QDir::match(const QStringList &filters, const QString &fileName)
2150{
2151 for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
2152 // Insensitive exact match
2153 // (see Notes for QRegExp Users in QRegularExpression's documentation)
2154 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(*sit),
2155 QRegularExpression::CaseInsensitiveOption);
2156 if (rx.match(fileName).hasMatch())
2157 return true;
2158 }
2159 return false;
2160}
2161
2162/*!
2163 Returns \c true if the \a fileName matches the wildcard (glob)
2164 pattern \a filter; otherwise returns \c false. The \a filter may
2165 contain multiple patterns separated by spaces or semicolons.
2166 The matching is case insensitive.
2167
2168 \sa {QRegularExpression#Wildcard matching}{QRegularExpression Wildcard Matching},
2169 entryList(), entryInfoList()
2170*/
2171bool QDir::match(const QString &filter, const QString &fileName)
2172{
2173 return match(nameFiltersFromString(filter), fileName);
2174}
2175#endif // QT_CONFIG(regularexpression)
2176
2177/*!
2178 \internal
2179 Returns \a path with redundant directory separators removed,
2180 and "."s and ".."s resolved (as far as possible).
2181
2182 This method is shared with QUrl, so it doesn't deal with QDir::separator(),
2183 nor does it remove the trailing slash, if any.
2184*/
2185QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormalizations flags, bool *ok)
2186{
2187 const bool allowUncPaths = QDirPrivate::AllowUncPaths & flags;
2188 const bool isRemote = QDirPrivate::RemotePath & flags;
2189 const int len = name.length();
2190
2191 if (ok)
2192 *ok = false;
2193
2194 if (len == 0)
2195 return name;
2196
2197 int i = len - 1;
2198 QVarLengthArray<ushort> outVector(len);
2199 int used = len;
2200 ushort *out = outVector.data();
2201 const ushort *p = name.utf16();
2202 const ushort *prefix = p;
2203 int up = 0;
2204
2205 const int prefixLength = rootLength(name, allowUncPaths);
2206 p += prefixLength;
2207 i -= prefixLength;
2208
2209 // replicate trailing slash (i > 0 checks for emptiness of input string p)
2210 // except for remote paths because there can be /../ or /./ ending
2211 if (i > 0 && p[i] == '/' && !isRemote) {
2212 out[--used] = '/';
2213 --i;
2214 }
2215
2216 auto isDot = [](const ushort *p, int i) {
2217 return i > 1 && p[i - 1] == '.' && p[i - 2] == '/';
2218 };
2219 auto isDotDot = [](const ushort *p, int i) {
2220 return i > 2 && p[i - 1] == '.' && p[i - 2] == '.' && p[i - 3] == '/';
2221 };
2222
2223 while (i >= 0) {
2224 // copy trailing slashes for remote urls
2225 if (p[i] == '/') {
2226 if (isRemote && !up) {
2227 if (isDot(p, i)) {
2228 i -= 2;
2229 continue;
2230 }
2231 out[--used] = p[i];
2232 }
2233
2234 --i;
2235 continue;
2236 }
2237
2238 // remove current directory
2239 if (p[i] == '.' && (i == 0 || p[i-1] == '/')) {
2240 --i;
2241 continue;
2242 }
2243
2244 // detect up dir
2245 if (i >= 1 && p[i] == '.' && p[i-1] == '.' && (i < 2 || p[i - 2] == '/')) {
2246 ++up;
2247 i -= i >= 2 ? 3 : 2;
2248
2249 if (isRemote) {
2250 // moving up should consider empty path segments too (/path//../ -> /path/)
2251 while (i > 0 && up && p[i] == '/') {
2252 --up;
2253 --i;
2254 }
2255 }
2256 continue;
2257 }
2258
2259 // prepend a slash before copying when not empty
2260 if (!up && used != len && out[used] != '/')
2261 out[--used] = '/';
2262
2263 // skip or copy
2264 while (i >= 0) {
2265 if (p[i] == '/') {
2266 // copy all slashes as is for remote urls if they are not part of /./ or /../
2267 if (isRemote && !up) {
2268 while (i > 0 && p[i] == '/' && !isDotDot(p, i)) {
2269
2270 if (isDot(p, i)) {
2271 i -= 2;
2272 continue;
2273 }
2274
2275 out[--used] = p[i];
2276 --i;
2277 }
2278
2279 // in case of /./, jump over
2280 if (isDot(p, i))
2281 i -= 2;
2282
2283 break;
2284 }
2285
2286 --i;
2287 break;
2288 }
2289
2290 // actual copy
2291 if (!up)
2292 out[--used] = p[i];
2293 --i;
2294 }
2295
2296 // decrement up after copying/skipping
2297 if (up)
2298 --up;
2299 }
2300
2301 // Indicate failure when ".." are left over for an absolute path.
2302 if (ok)
2303 *ok = prefixLength == 0 || up == 0;
2304
2305 // add remaining '..'
2306 while (up && !isRemote) {
2307 if (used != len && out[used] != '/') // is not empty and there isn't already a '/'
2308 out[--used] = '/';
2309 out[--used] = '.';
2310 out[--used] = '.';
2311 --up;
2312 }
2313
2314 bool isEmpty = used == len;
2315
2316 if (prefixLength) {
2317 if (!isEmpty && out[used] == '/') {
2318 // Eventhough there is a prefix the out string is a slash. This happens, if the input
2319 // string only consists of a prefix followed by one or more slashes. Just skip the slash.
2320 ++used;
2321 }
2322 for (int i = prefixLength - 1; i >= 0; --i)
2323 out[--used] = prefix[i];
2324 } else {
2325 if (isEmpty) {
2326 // After resolving the input path, the resulting string is empty (e.g. "foo/.."). Return
2327 // a dot in that case.
2328 out[--used] = '.';
2329 } else if (out[used] == '/') {
2330 // After parsing the input string, out only contains a slash. That happens whenever all
2331 // parts are resolved and there is a trailing slash ("./" or "foo/../" for example).
2332 // Prepend a dot to have the correct return value.
2333 out[--used] = '.';
2334 }
2335 }
2336
2337 // If path was not modified return the original value
2338 if (used == 0)
2339 return name;
2340 return QString::fromUtf16(out + used, len - used);
2341}
2342
2343static QString qt_cleanPath(const QString &path, bool *ok)
2344{
2345 if (path.isEmpty())
2346 return path;
2347 QString name = path;
2348#if defined (Q_OS_WIN)
2349 if (name.startsWith(QLatin1String("\\\\?\\")))
2350 name.remove(0, 4);
2351#endif
2352
2353 QChar dir_separator = QDir::separator();
2354 if (dir_separator != QLatin1Char('/'))
2355 name.replace(dir_separator, QLatin1Char('/'));
2356
2357 QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths ? QDirPrivate::AllowUncPaths : QDirPrivate::DefaultNormalization, ok);
2358
2359 // Strip away last slash except for root directories
2360 if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) {
2361#if defined (Q_OS_WIN)
2362# if defined(Q_OS_WINRT)
2363 if (!((ret.length() == 3 || ret.length() == QDir::rootPath().length()) && ret.at(1) == QLatin1Char(':')))
2364# else
2365 if (!(ret.length() == 3 && ret.at(1) == QLatin1Char(':')))
2366# endif
2367#endif
2368 ret.chop(1);
2369 }
2370
2371 return ret;
2372}
2373
2374/*!
2375 Returns \a path with directory separators normalized (converted to "/") and
2376 redundant ones removed, and "."s and ".."s resolved (as far as possible).
2377
2378 Symbolic links are kept. This function does not return the
2379 canonical path, but rather the simplest version of the input.
2380 For example, "./local" becomes "local", "local/../bin" becomes
2381 "bin" and "/local/usr/../bin" becomes "/local/bin".
2382
2383 \sa absolutePath(), canonicalPath()
2384*/
2385QString QDir::cleanPath(const QString &path)
2386{
2387 return qt_cleanPath(path);
2388}
2389
2390/*!
2391 Returns \c true if \a path is relative; returns \c false if it is
2392 absolute.
2393
2394 \sa isRelative(), isAbsolutePath(), makeAbsolute()
2395*/
2396bool QDir::isRelativePath(const QString &path)
2397{
2398 return QFileInfo(path).isRelative();
2399}
2400
2401/*!
2402 Refreshes the directory information.
2403*/
2404void QDir::refresh() const
2405{
2406 QDirPrivate *d = const_cast<QDir*>(this)->d_ptr.data();
2407 d->metaData.clear();
2408 d->initFileEngine();
2409 d->clearFileLists();
2410}
2411
2412/*!
2413 \internal
2414*/
2415QDirPrivate* QDir::d_func()
2416{
2417 return d_ptr.data();
2418}
2419
2420/*!
2421 \internal
2422
2423 Returns a list of name filters from the given \a nameFilter. (If
2424 there is more than one filter, each pair of filters is separated
2425 by a space or by a semicolon.)
2426*/
2427QStringList QDir::nameFiltersFromString(const QString &nameFilter)
2428{
2429 return QDirPrivate::splitFilters(nameFilter);
2430}
2431
2432/*!
2433 \macro void Q_INIT_RESOURCE(name)
2434 \relates QDir
2435
2436 Initializes the resources specified by the \c .qrc file with the
2437 specified base \a name. Normally, when resources are built as part
2438 of the application, the resources are loaded automatically at
2439 startup. The Q_INIT_RESOURCE() macro is necessary on some platforms
2440 for resources stored in a static library.
2441
2442 For example, if your application's resources are listed in a file
2443 called \c myapp.qrc, you can ensure that the resources are
2444 initialized at startup by adding this line to your \c main()
2445 function:
2446
2447 \snippet code/src_corelib_io_qdir.cpp 13
2448
2449 If the file name contains characters that cannot be part of a valid C++ function name
2450 (such as '-'), they have to be replaced by the underscore character ('_').
2451
2452 Note: This macro cannot be used in a namespace. It should be called from
2453 main(). If that is not possible, the following workaround can be used
2454 to init the resource \c myapp from the function \c{MyNamespace::myFunction}:
2455
2456 \snippet code/src_corelib_io_qdir.cpp 14
2457
2458 \sa Q_CLEANUP_RESOURCE(), {The Qt Resource System}
2459*/
2460
2461/*!
2462 \since 4.1
2463 \macro void Q_CLEANUP_RESOURCE(name)
2464 \relates QDir
2465
2466 Unloads the resources specified by the \c .qrc file with the base
2467 name \a name.
2468
2469 Normally, Qt resources are unloaded automatically when the
2470 application terminates, but if the resources are located in a
2471 plugin that is being unloaded, call Q_CLEANUP_RESOURCE() to force
2472 removal of your resources.
2473
2474 Note: This macro cannot be used in a namespace. Please see the
2475 Q_INIT_RESOURCE documentation for a workaround.
2476
2477 Example:
2478
2479 \snippet code/src_corelib_io_qdir.cpp 15
2480
2481 \sa Q_INIT_RESOURCE(), {The Qt Resource System}
2482*/
2483
2484
2485#ifndef QT_NO_DEBUG_STREAM
2486QDebug operator<<(QDebug debug, QDir::Filters filters)
2487{
2488 QDebugStateSaver save(debug);
2489 debug.resetFormat();
2490 QStringList flags;
2491 if (filters == QDir::NoFilter) {
2492 flags << QLatin1String("NoFilter");
2493 } else {
2494 if (filters & QDir::Dirs) flags << QLatin1String("Dirs");
2495 if (filters & QDir::AllDirs) flags << QLatin1String("AllDirs");
2496 if (filters & QDir::Files) flags << QLatin1String("Files");
2497 if (filters & QDir::Drives) flags << QLatin1String("Drives");
2498 if (filters & QDir::NoSymLinks) flags << QLatin1String("NoSymLinks");
2499 if (filters & QDir::NoDot) flags << QLatin1String("NoDot");
2500 if (filters & QDir::NoDotDot) flags << QLatin1String("NoDotDot");
2501 if ((filters & QDir::AllEntries) == QDir::AllEntries) flags << QLatin1String("AllEntries");
2502 if (filters & QDir::Readable) flags << QLatin1String("Readable");
2503 if (filters & QDir::Writable) flags << QLatin1String("Writable");
2504 if (filters & QDir::Executable) flags << QLatin1String("Executable");
2505 if (filters & QDir::Modified) flags << QLatin1String("Modified");
2506 if (filters & QDir::Hidden) flags << QLatin1String("Hidden");
2507 if (filters & QDir::System) flags << QLatin1String("System");
2508 if (filters & QDir::CaseSensitive) flags << QLatin1String("CaseSensitive");
2509 }
2510 debug.noquote() << "QDir::Filters(" << flags.join(QLatin1Char('|')) << ')';
2511 return debug;
2512}
2513
2514static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
2515{
2516 QDebugStateSaver save(debug);
2517 debug.resetFormat();
2518 if (sorting == QDir::NoSort) {
2519 debug << "QDir::SortFlags(NoSort)";
2520 } else {
2521 QString type;
2522 if ((sorting & 3) == QDir::Name) type = QLatin1String("Name");
2523 if ((sorting & 3) == QDir::Time) type = QLatin1String("Time");
2524 if ((sorting & 3) == QDir::Size) type = QLatin1String("Size");
2525 if ((sorting & 3) == QDir::Unsorted) type = QLatin1String("Unsorted");
2526
2527 QStringList flags;
2528 if (sorting & QDir::DirsFirst) flags << QLatin1String("DirsFirst");
2529 if (sorting & QDir::DirsLast) flags << QLatin1String("DirsLast");
2530 if (sorting & QDir::IgnoreCase) flags << QLatin1String("IgnoreCase");
2531 if (sorting & QDir::LocaleAware) flags << QLatin1String("LocaleAware");
2532 if (sorting & QDir::Type) flags << QLatin1String("Type");
2533 debug.noquote() << "QDir::SortFlags(" << type << '|' << flags.join(QLatin1Char('|')) << ')';
2534 }
2535 return debug;
2536}
2537
2538QDebug operator<<(QDebug debug, const QDir &dir)
2539{
2540 QDebugStateSaver save(debug);
2541 debug.resetFormat();
2542 debug << "QDir(" << dir.path() << ", nameFilters = {"
2543 << dir.nameFilters().join(QLatin1Char(','))
2544 << "}, "
2545 << dir.sorting()
2546 << ','
2547 << dir.filter()
2548 << ')';
2549 return debug;
2550}
2551#endif // QT_NO_DEBUG_STREAM
2552
2553QT_END_NAMESPACE
2554