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