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