5#include "qplatformdefs.h"
10#ifndef QT_NO_DEBUG_STREAM
16#if QT_CONFIG(regularexpression)
17# include <qregularexpression.h>
23#include <qstringbuilder.h>
25#ifndef QT_BOOTSTRAPPED
26# include <qcollator.h>
31#include <private/qorderedmutexlocker_p.h>
39using namespace Qt::StringLiterals;
42static QString driveSpec(
const QString &path)
46 char c = path.at(0).toLatin1();
47 if ((c <
'a' || c >
'z') && (c <
'A' || c >
'Z'))
49 if (path.at(1).toLatin1() !=
':')
51 return path.mid(0, 2);
58 constexpr bool UseWindowsRules =
false
63 const qsizetype len = name.size();
64 char16_t firstChar = len > 0 ? name.at(0).unicode() : u'\0';
65 char16_t secondChar = len > 1 ? name.at(1).unicode() : u'\0';
66 if constexpr (UseWindowsRules) {
69 if (firstChar == u'/' && secondChar == u'/' && !urlMode) {
71 const qsizetype nextSlash = name.indexOf(u'/', 2);
72 return nextSlash >= 0 ? nextSlash + 1 : len;
76 qsizetype driveLength = 2;
77 if (firstChar == u'/' && urlMode && len > 2 && name.at(2) == u':') {
82 if (secondChar == u':') {
83 if (len > driveLength && name.at(driveLength) == u'/')
84 return driveLength + 1;
89 return firstChar == u'/' ? 1 : 0;
93QDirPrivate::QDirPrivate(
const QString &path,
const QStringList &nameFilters_,
94 QDir::SortFlags sort_, QDir::Filters filters_)
95 : QSharedData(), nameFilters(nameFilters_), sort(sort_), filters(filters_)
97 setPath(path.isEmpty() ? QString::fromLatin1(
".") : path);
99 auto isEmpty = [](
const auto &e) {
return e.isEmpty(); };
100 const bool empty = std::all_of(nameFilters.cbegin(), nameFilters.cend(), isEmpty);
102 nameFilters = QStringList(QString::fromLatin1(
"*"));
115 fileCache.fileListsInitialized = copy.fileCache.fileListsInitialized.load();
116 fileCache.files = copy.fileCache.files;
117 fileCache.fileInfos = copy.fileCache.fileInfos;
118 fileCache.absoluteDirEntry = copy.fileCache.absoluteDirEntry;
119 fileCache.metaData = copy.fileCache.metaData;
126 QFileSystemEngine::fillMetaData(
127 dirEntry, fileCache.metaData,
128 QFileSystemMetaData::ExistsAttribute
129 | QFileSystemMetaData::DirectoryType);
130 return fileCache.metaData.exists() && fileCache.metaData.isDirectory();
132 const QAbstractFileEngine::FileFlags info =
133 fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
134 | QAbstractFileEngine::ExistsFlag
135 | QAbstractFileEngine::Refresh);
136 if (!(info & QAbstractFileEngine::DirectoryType))
138 return info.testAnyFlag(QAbstractFileEngine::ExistsFlag);
142inline QChar
QDirPrivate::getFilterSepChar(
const QString &nameFilter)
145 qsizetype i = nameFilter.indexOf(sep, 0);
146 if (i == -1 && nameFilter.indexOf(u' ', 0) != -1)
152inline QStringList
QDirPrivate::splitFilters(
const QString &nameFilter, QChar sep)
155 sep = getFilterSepChar(nameFilter);
157 for (
auto e : qTokenize(nameFilter, sep))
158 ret.append(e.trimmed().toString());
164 QString p = QDir::fromNativeSeparators(path);
168 && (!(p.length() == 3 && p.at(1).unicode() ==
':' && p.at(0).isLetter()))
171 p.truncate(p.size() - 1);
173 dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
175 fileCache.absoluteDirEntry = QFileSystemEntry();
181 if (!fileCache.absoluteDirEntry.isEmpty())
182 return fileCache.absoluteDirEntry.filePath();
184 if (dirEntry.isEmpty())
185 return dirEntry.filePath();
187 QString absoluteName;
189 if (!dirEntry.isRelative() && dirEntry.isClean()) {
190 fileCache.absoluteDirEntry = dirEntry;
191 return dirEntry.filePath();
194 absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath();
196 absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
198 auto absoluteFileSystemEntry =
199 QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
200 fileCache.absoluteDirEntry = absoluteFileSystemEntry;
201 return absoluteFileSystemEntry.filePath();
214 if (sort.testAnyFlag(QDir::Type))
215 suffix_cache = item.suffix();
225 QDir::SortFlags qt_cmp_si_sort_flags;
227#ifndef QT_BOOTSTRAPPED
228 QCollator *collator =
nullptr;
231#ifndef QT_BOOTSTRAPPED
235 Q_ASSERT(!qt_cmp_si_sort_flags.testAnyFlag(QDir::LocaleAware) || collator);
237 if (collator && qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase))
238 collator->setCaseSensitivity(Qt::CaseInsensitive);
248 int compareStrings(
const QString &a,
const QString &b, Qt::CaseSensitivity cs)
const
250#ifndef QT_BOOTSTRAPPED
252 return collator->compare(a, b);
254 return a.compare(b, cs);
263 if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir()))
264 return f1->item.isDir();
265 if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
266 return !f1->item.isDir();
268 const bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
269 const auto qtcase = ic ? Qt::CaseInsensitive : Qt::CaseSensitive;
272 int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask)
273 | (qt_cmp_si_sort_flags & QDir::Type)).toInt();
277 const QDateTime firstModified = f1->item.lastModified(QTimeZone::UTC);
278 const QDateTime secondModified = f2->item.lastModified(QTimeZone::UTC);
279 r = firstModified.msecsTo(secondModified);
283 r = f2->item.size() - f1->item.size();
286 r = compareStrings(f1->suffix_cache, f2->suffix_cache, qtcase);
292 if (r == 0 && sortBy != QDir::Unsorted) {
295 if (f1->filename_cache.isNull())
296 f1->filename_cache = f1->item.fileName();
297 if (f2->filename_cache.isNull())
298 f2->filename_cache = f2->item.fileName();
300 r = compareStrings(f1->filename_cache, f2->filename_cache, qtcase);
302 if (qt_cmp_si_sort_flags & QDir::Reversed)
307inline void QDirPrivate::sortFileList(QDir::SortFlags sort,
const QFileInfoList &l,
308 QStringList *names, QFileInfoList *infos)
310 Q_ASSERT(names || infos);
311 Q_ASSERT(!infos || infos->isEmpty());
312 Q_ASSERT(!names || names->isEmpty());
314 const qsizetype n = l.size();
318 if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
323 for (
const QFileInfo &fi : l)
324 names->append(fi.fileName());
327 QVarLengthArray<QDirSortItem, 64> si;
329 for (qsizetype i = 0; i < n; ++i)
330 si.emplace_back(l.at(i), sort);
332#ifndef QT_BOOTSTRAPPED
333 if (sort.testAnyFlag(QDir::LocaleAware)) {
335 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort, &coll));
337 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
340 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
344 for (qsizetype i = 0; i < n; ++i) {
345 auto &fileInfo = si[i].item;
347 infos->append(fileInfo);
349 const bool cached = !si[i].filename_cache.isNull();
350 names->append(cached ? si[i].filename_cache : fileInfo.fileName());
356#ifndef QT_BOOTSTRAPPED
358
359
360
361
362
363
366 const auto perms = filters & QDir::PermissionMask;
367 const bool filterByPermissions = perms != 0 && perms != QDir::PermissionMask;
368 if (filterByPermissions) {
369 const QFileInfo fileInfo = dirEntry.fileInfo();
370 if (filters.testFlags(QDir::Readable) && !fileInfo.isReadable())
372 if (filters.testFlags(QDir::Writable) && !fileInfo.isWritable())
374 if (filters.testFlags(QDir::Executable) && !fileInfo.isExecutable())
382 const QString fileName = dirEntry.fileName();
383 if ((filters & QDir::NoDot) && fileName == u".")
385 if ((filters & QDir::NoDotDot) && fileName == u"..")
391
392
393
394
395
397 QDir::Filters filters)
399 return checkPermissions(dirEntry, filters) && checkDotOrDotDot(dirEntry, filters);
403 QDir::Filters filters, QFileInfoList &l)
405 if (QDirPrivate::checkNonDirListingFlags(dirEntry, filters))
406 l.emplace_back(dirEntry.fileInfo());
410
411
412
413
414
415
416
417QDirListing::IteratorFlags
QDirPrivate::toDirListingFlags(QDir::Filters filters)
419 if (filters == QDir::NoFilter)
420 filters = QDir::AllEntries;
422 using F = QDirListing::IteratorFlag;
423 QDirListing::IteratorFlags flags;
424 if (!(filters & QDir::Dirs) && !(filters & QDir::AllDirs))
425 flags |= F::ExcludeDirs;
426 if (!(filters & QDir::Files))
427 flags |= F::ExcludeFiles;
428 if (!(filters & QDir::NoSymLinks))
429 flags |= F::ResolveSymlinks;
430 if (filters & QDir::Hidden)
431 flags |= F::IncludeHidden;
433 if (!(filters & QDir::System))
434 flags |= F::ExcludeOther;
436 flags |= F::IncludeBrokenSymlinks;
439 if (filters & QDir::AllDirs)
440 flags |= F::NoNameFiltersForDirs;
441 if (filters & QDir::CaseSensitive)
442 flags |= F::CaseSensitive;
447 if (!(filters & QDir::NoDot) || !(filters & QDir::NoDotDot)) {
448 if (!(flags & F::ExcludeDirs))
449 flags |= F::IncludeDotAndDotDot;
458 if (!fileCache.fileListsInitialized) {
460 QDirListing::IteratorFlags flags = toDirListingFlags(dir.filter());
461 for (
const auto &dirEntry : QDirListing(dir.path(), dir.nameFilters(), flags))
462 appendIfMatchesNonDirListingFlags(dirEntry, dir.filter(), l);
464 sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos);
465 fileCache.fileListsInitialized =
true;
473 if (mode == IncludingMetaData)
474 fileCache.metaData.clear();
475 fileCache.fileListsInitialized =
false;
476 fileCache.files.clear();
477 fileCache.fileInfos.clear();
478 fileEngine = QFileSystemEngine::createLegacyEngine(dirEntry, fileCache.metaData);
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
667
668
669
670
671
672
675
676
677QDir::QDir(QDirPrivate &p) : d_ptr(&p)
682
683
684
685
686
687QDir::QDir(
const QString &path) : d_ptr(
new QDirPrivate(path))
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709QDir::QDir(
const QString &path,
const QString &nameFilter,
710 SortFlags sort, Filters filters)
711 : d_ptr(
new QDirPrivate(path, QDir::nameFiltersFromString(nameFilter), sort, filters))
716
717
718
719
720
721QDir::QDir(
const QDir &dir)
727
728
729
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750void QDir::setPath(
const QString &path)
752 d_ptr->setPath(path);
756
757
758
759
760
761
762
763
764
765QString QDir::path()
const
768 return d->dirEntry.filePath();
772
773
774
775
776
777
778
779QString QDir::absolutePath()
const
783 return d->resolveAbsoluteEntry();
785 return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804QString QDir::canonicalPath()
const
807 if (!d->fileEngine) {
808 QMutexLocker locker(&d->fileCache.mutex);
809 QFileSystemEntry answer =
810 QFileSystemEngine::canonicalName(d->dirEntry, d->fileCache.metaData);
811 return answer.filePath();
813 return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
817
818
819
820
821
822
823
824
825
826
827QString QDir::dirName()
const
830 if (!d_ptr->fileEngine)
831 return d->dirEntry.fileName();
832 return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
837static qsizetype drivePrefixLength(QStringView path)
840 const qsizetype size = path.size();
842 if (size > 1 && path.at(1).unicode() ==
':') {
843 if (Q_UNLIKELY(!path.at(0).isLetter()))
845 }
else if (path.startsWith(
"//"_L1)) {
848 for (
int i = 0 ; i < 2 ; ++i) {
849 while (drive < size && path.at(drive).unicode() ==
'/')
852 qWarning(
"Base directory starts with neither a drive nor a UNC share: %s",
853 qUtf8Printable(QDir::toNativeSeparators(path.toString())));
856 while (drive < size && path.at(drive).unicode() !=
'/')
877 return (path.contains(u':') && QFileInfo(path).isAbsolute())
878 || QFileSystemEntry(path).isAbsolute();
882
883
884
885
886
887
888
889
890QString QDir::filePath(
const QString &fileName)
const
892 if (treatAsAbsolute(fileName))
896 QString ret = d->dirEntry.filePath();
897 if (fileName.isEmpty())
901 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
903 const qsizetype drive = drivePrefixLength(ret);
904 return drive > 0 ? QStringView{ret}.left(drive) % fileName : fileName;
908 if (ret.isEmpty() || ret.endsWith(u'/'))
909 return ret % fileName;
910 return ret % u'/' % fileName;
914
915
916
917
918
919
920
921QString QDir::absoluteFilePath(
const QString &fileName)
const
923 if (treatAsAbsolute(fileName))
927 QString absoluteDirPath = d->resolveAbsoluteEntry();
928 if (fileName.isEmpty())
929 return absoluteDirPath;
932 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
934 const qsizetype drive = drivePrefixLength(absoluteDirPath);
936 return QStringView{absoluteDirPath}.left(drive) % fileName;
938 qWarning(
"Base directory's drive is not a letter: %s",
939 qUtf8Printable(QDir::toNativeSeparators(absoluteDirPath)));
943 if (!absoluteDirPath.endsWith(u'/'))
944 return absoluteDirPath % u'/' % fileName;
945 return absoluteDirPath % fileName;
949
950
951
952
953
954
955QString QDir::relativeFilePath(
const QString &fileName)
const
957 QString dir = cleanPath(absolutePath());
958 QString file = cleanPath(fileName);
960 if (isRelativePath(file) || isRelativePath(dir))
964 QString dirDrive = driveSpec(dir);
965 QString fileDrive = driveSpec(file);
967 bool fileDriveMissing =
false;
968 if (fileDrive.isEmpty()) {
969 fileDrive = dirDrive;
970 fileDriveMissing =
true;
973 if (fileDrive.toLower() != dirDrive.toLower()
974 || (file.startsWith(
"//"_L1)
975 && !dir.startsWith(
"//"_L1))) {
979 dir.remove(0, dirDrive.size());
980 if (!fileDriveMissing)
981 file.remove(0, fileDrive.size());
985 const auto dirElts = dir.tokenize(u'/', Qt::SkipEmptyParts);
986 const auto fileElts = file.tokenize(u'/', Qt::SkipEmptyParts);
988 const auto dend = dirElts.end();
989 const auto fend = fileElts.end();
990 auto dit = dirElts.begin();
991 auto fit = fileElts.begin();
993 const auto eq = [](QStringView lhs, QStringView rhs) {
996 lhs.compare(rhs, Qt::CaseInsensitive) == 0;
1003 while (dit != dend && fit != fend && eq(*dit, *fit)) {
1008 while (dit != dend) {
1014 while (fit != fend) {
1021 if (result.isEmpty())
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041QString QDir::toNativeSeparators(
const QString &pathName)
1043#if defined(Q_OS_WIN)
1044 qsizetype i = pathName.indexOf(u'/');
1046 QString n(pathName);
1048 QChar *
const data = n.data();
1051 for (; i < n.length(); ++i) {
1052 if (data[i] == u'/')
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074QString QDir::fromNativeSeparators(
const QString &pathName)
1076#if defined(Q_OS_WIN)
1077 return QFileSystemEntry::removeUncOrLongPathPrefix(pathName).replace(u'\\', u'/');
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096bool QDir::cd(
const QString &dirName)
1099 const QDirPrivate *
const d = d_ptr.constData();
1101 if (dirName.isEmpty() || dirName == u'.')
1104 if (isAbsolutePath(dirName)) {
1106 qt_cleanPath(&newPath);
1108 newPath = d->dirEntry.filePath();
1109 if (!newPath.endsWith(u'/'))
1112 if (dirName.indexOf(u'/') >= 0
1113 || dirName ==
".."_L1
1114 || d->dirEntry.filePath() == u'.') {
1115 if (!qt_cleanPath(&newPath))
1118
1119
1120
1121
1122
1123
1124
1125 if (newPath.startsWith(
".."_L1)) {
1126 newPath = QFileInfo(newPath).absoluteFilePath();
1131 std::unique_ptr<QDirPrivate> dir(
new QDirPrivate(*d_ptr.constData()));
1132 dir->setPath(newPath);
1136 d_ptr = dir.release();
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1155 return cd(QString::fromLatin1(
".."));
1159
1160
1161QStringList QDir::nameFilters()
const
1164 return d->nameFilters;
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182void QDir::setNameFilters(
const QStringList &nameFilters)
1185 d->clearCache(QDirPrivate::KeepMetaData);
1186 d->nameFilters = nameFilters;
1189#ifndef QT_BOOTSTRAPPED
1192struct DirSearchPaths {
1193 mutable QReadWriteLock mutex;
1194 QHash<QString, QStringList> paths;
1198Q_GLOBAL_STATIC(DirSearchPaths, dirSearchPaths)
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220void QDir::setSearchPaths(
const QString &prefix,
const QStringList &searchPaths)
1222 if (prefix.size() < 2) {
1223 qWarning(
"QDir::setSearchPaths: Prefix must be longer than 1 character");
1227 for (QChar ch : prefix) {
1228 if (!ch.isLetterOrNumber()) {
1229 qWarning(
"QDir::setSearchPaths: Prefix can only contain letters or numbers");
1234 DirSearchPaths &conf = *dirSearchPaths;
1235 const QWriteLocker lock(&conf.mutex);
1236 if (searchPaths.isEmpty()) {
1237 conf.paths.remove(prefix);
1239 conf.paths.insert(prefix, searchPaths);
1244
1245
1246
1247
1248
1249
1250void QDir::addSearchPath(
const QString &prefix,
const QString &path)
1255 DirSearchPaths &conf = *dirSearchPaths;
1256 const QWriteLocker lock(&conf.mutex);
1257 conf.paths[prefix] += path;
1261
1262
1263
1264
1265
1266
1267QStringList QDir::searchPaths(
const QString &prefix)
1269 if (!dirSearchPaths.exists())
1270 return QStringList();
1272 const DirSearchPaths &conf = *dirSearchPaths;
1273 const QReadLocker lock(&conf.mutex);
1274 return conf.paths.value(prefix);
1280
1281
1282QDir::Filters QDir::filter()
const
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1353
1354
1355
1356
1357
1358
1359
1360void QDir::setFilter(Filters filters)
1363 d->clearCache(QDirPrivate::KeepMetaData);
1364 d->filters = filters;
1368
1369
1370
1371
1372QDir::SortFlags QDir::sorting()
const
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1407#ifndef QT_BOOTSTRAPPED
1409
1410
1411
1412
1413
1414
1415
1416void QDir::setSorting(SortFlags sort)
1419 d->clearCache(QDirPrivate::KeepMetaData);
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433qsizetype QDir::count(QT6_IMPL_NEW_OVERLOAD)
const
1436 d->initFileLists(*
this);
1437 return d->fileCache.files.size();
1441
1442
1443
1444
1445
1446
1447
1448
1449QString QDir::operator[](qsizetype pos)
const
1452 d->initFileLists(*
this);
1453 return d->fileCache.files[pos];
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475QStringList QDir::entryList(Filters filters, SortFlags sort)
const
1478 return entryList(d->nameFilters, filters, sort);
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort)
const
1501 return entryInfoList(d->nameFilters, filters, sort);
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520QStringList QDir::entryList(
const QStringList &nameFilters, Filters filters,
1521 SortFlags sort)
const
1525 if (filters == NoFilter)
1526 filters = d->filters;
1530 const bool needsSorting = (sort & QDir::SortByMask) != QDir::Unsorted;
1532 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1534 if (needsSorting || d->fileCache.fileListsInitialized) {
1535 d->initFileLists(*
this);
1536 return d->fileCache.files;
1540 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1541 QDirListing dirList(d->dirEntry.filePath(), nameFilters, flags);
1545 for (
const auto &dirEntry : dirList)
1546 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1547 d->sortFileList(sort, l, &ret,
nullptr);
1549 for (
const auto &dirEntry : dirList)
1550 ret.emplace_back(dirEntry.fileName());
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571QFileInfoList QDir::entryInfoList(
const QStringList &nameFilters, Filters filters,
1572 SortFlags sort)
const
1576 if (filters == NoFilter)
1577 filters = d->filters;
1581 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1582 d->initFileLists(*
this);
1583 return d->fileCache.fileInfos;
1587 const QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1588 for (
const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, flags))
1589 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1591 d->sortFileList(sort, l,
nullptr, &ret);
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631bool QDir::mkdir(
const QString &dirName, std::optional<QFile::Permissions> permissions)
const
1635 if (dirName.isEmpty()) {
1636 qWarning(
"QDir::mkdir: Empty or null file name");
1640 QString fn = filePath(dirName);
1642 return QFileSystemEngine::mkdir(QFileSystemEntry(fn), permissions);
1643 return d->fileEngine->mkdir(fn,
false, permissions);
1647
1648
1649
1650
1651
1652
1653
1654
1655bool QDir::rmdir(
const QString &dirName)
const
1659 if (dirName.isEmpty()) {
1660 qWarning(
"QDir::rmdir: Empty or null file name");
1664 QString fn = filePath(dirName);
1666 return QFileSystemEngine::rmdir(QFileSystemEntry(fn));
1668 return d->fileEngine->rmdir(fn,
false);
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696bool QDir::mkpath(
const QString &dirPath, std::optional<QFile::Permissions> permissions)
const
1700 if (dirPath.isEmpty()) {
1701 qWarning(
"QDir::mkpath: Empty or null file name");
1705 QString fn = filePath(dirPath);
1707 return QFileSystemEngine::mkpath(QFileSystemEntry(fn), permissions);
1708 return d->fileEngine->mkdir(fn,
true, permissions);
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722bool QDir::rmpath(
const QString &dirPath)
const
1726 if (dirPath.isEmpty()) {
1727 qWarning(
"QDir::rmpath: Empty or null file name");
1731 QString fn = filePath(dirPath);
1733 return QFileSystemEngine::rmpath(QFileSystemEntry(fn));
1734 return d->fileEngine->rmdir(fn,
true);
1737#ifndef QT_BOOTSTRAPPED
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758bool QDir::removeRecursively()
1760 if (!d_ptr->exists())
1763 bool success =
true;
1764 const QString dirPath = path();
1766 for (
const auto &dirEntry : QDirListing(dirPath, QDirListing::IteratorFlag::IncludeHidden)) {
1767 const QString &filePath = dirEntry.filePath();
1769 if (dirEntry.isDir() && !dirEntry.isSymLink()) {
1770 ok = QDir(filePath).removeRecursively();
1772 ok = QFile::remove(filePath);
1774 const QFile::Permissions permissions = QFile::permissions(filePath);
1775 if (!(permissions & QFile::WriteUser))
1776 ok = QFile::setPermissions(filePath, permissions | QFile::WriteUser)
1777 && QFile::remove(filePath);
1785 success = rmdir(absolutePath());
1792
1793
1794
1795
1796
1797
1798
1799
1800bool QDir::isReadable()
const
1804 if (!d->fileEngine) {
1805 QMutexLocker locker(&d->fileCache.mutex);
1806 if (!d->fileCache.metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) {
1807 QFileSystemEngine::fillMetaData(d->dirEntry, d->fileCache.metaData,
1808 QFileSystemMetaData::UserReadPermission);
1810 return d->fileCache.metaData.permissions().testAnyFlag(QFile::ReadUser);
1813 const QAbstractFileEngine::FileFlags info =
1814 d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
1815 | QAbstractFileEngine::PermsMask);
1816 if (!(info & QAbstractFileEngine::DirectoryType))
1818 return info.testAnyFlag(QAbstractFileEngine::ReadUserPerm);
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832bool QDir::exists()
const
1834 return d_ptr->exists();
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849bool QDir::isRoot()
const
1851 if (!d_ptr->fileEngine)
1852 return d_ptr->dirEntry.isRoot();
1853 return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask).testAnyFlag(QAbstractFileEngine::RootFlag);
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890bool QDir::isRelative()
const
1892 if (!d_ptr->fileEngine)
1893 return d_ptr->dirEntry.isRelative();
1894 return d_ptr->fileEngine->isRelativePath();
1899
1900
1901
1902
1903
1904
1905bool QDir::makeAbsolute()
1908 std::unique_ptr<QDirPrivate> dir;
1909 if (!!d->fileEngine) {
1910 QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
1911 if (QDir::isRelativePath(absolutePath))
1914 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1915 dir->setPath(absolutePath);
1917 QString absoluteFilePath = d->resolveAbsoluteEntry();
1918 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1919 dir->setPath(absoluteFilePath);
1921 d_ptr = dir.release();
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1943 Qt::CaseSensitivity sensitive;
1944 if (!d->fileEngine || !other->fileEngine) {
1945 if (d->fileEngine.get() != other->fileEngine.get())
1948 QOrderedMutexLocker locker(&d->fileCache.mutex, &other->fileCache.mutex);
1949 const bool thisCaseSensitive = QFileSystemEngine::isCaseSensitive(d->dirEntry, d->fileCache.metaData);
1950 if (thisCaseSensitive != QFileSystemEngine::isCaseSensitive(other->dirEntry, other->fileCache.metaData))
1953 sensitive = thisCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
1955 if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
1957 sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1960 if (d->filters == other->filters
1961 && d->sort == other->sort
1962 && d->nameFilters == other->nameFilters) {
1965 if (d->dirEntry.filePath() == other->dirEntry.filePath())
1972 return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0;
1977 QString thisFilePath = d->resolveAbsoluteEntry();
1978 QString otherFilePath = other->resolveAbsoluteEntry();
1979 return thisFilePath.compare(otherFilePath, sensitive) == 0;
1986
1987
1988
1989QDir &QDir::operator=(
const QDir &dir)
1996
1997
1998
1999
2002
2003
2004
2005
2006
2007
2008
2009
2010
2013
2014
2015
2016
2017
2018bool QDir::remove(
const QString &fileName)
2020 if (fileName.isEmpty()) {
2021 qWarning(
"QDir::remove: Empty or null file name");
2024 return QFile::remove(filePath(fileName));
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043bool QDir::rename(
const QString &oldName,
const QString &newName)
2045 if (oldName.isEmpty() || newName.isEmpty()) {
2046 qWarning(
"QDir::rename: Empty or null file name(s)");
2050 QFile file(filePath(oldName));
2053 return file.rename(filePath(newName));
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066bool QDir::exists(
const QString &name)
const
2068 if (name.isEmpty()) {
2069 qWarning(
"QDir::exists: Empty or null file name");
2072 return QFileInfo::exists(filePath(name));
2075#ifndef QT_BOOTSTRAPPED
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089bool QDir::isEmpty(Filters filters)
const
2093 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
2094 for (
const auto &dirEntry : QDirListing(d->dirEntry.filePath(), d->nameFilters, flags)) {
2095 if (QDirPrivate::checkNonDirListingFlags(dirEntry, filters))
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112QFileInfoList QDir::drives()
2114#ifdef QT_NO_FSFILEENGINE
2115 return QFileInfoList();
2117 return QFSFileEngine::drives();
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2137
2138
2139
2140
2141
2142
2143
2144
2147
2148
2149
2150
2151
2152
2153
2154
2155bool QDir::setCurrent(
const QString &path)
2157 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
2161
2162
2163
2164
2165
2166
2167
2168
2169
2172
2173
2174
2175
2176
2177
2178
2179QString QDir::currentPath()
2181 return QFileSystemEngine::currentPath().filePath();
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228QString QDir::homePath()
2230 return QFileSystemEngine::homePath();
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258QString QDir::tempPath()
2260 return QFileSystemEngine::tempPath();
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2277
2278
2279
2280
2281
2282
2283
2284QString QDir::rootPath()
2286 return QFileSystemEngine::rootPath();
2289#if QT_CONFIG(regularexpression)
2291
2292
2293
2294
2295
2296
2297
2298
2299bool QDir::match(
const QStringList &filters,
const QString &fileName)
2301 for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
2303 auto rx = QRegularExpression::fromWildcard(*sit, Qt::CaseInsensitive);
2304 if (rx.match(fileName).hasMatch())
2311
2312
2313
2314
2315
2316
2317
2318bool QDir::match(
const QString &filter,
const QString &fileName)
2320 return match(nameFiltersFromString(filter), fileName);
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2349 const qsizetype prefixLength = rootLength(*path, flags);
2354 const QChar *in = path->constBegin();
2359 qsizetype i = prefixLength;
2360 qsizetype n = path->size();
2361 for (
bool lastWasSlash =
true; i < n; ++i) {
2362 if (lastWasSlash && in[i] == u'.') {
2363 if (i + 1 == n || in[i + 1] == u'/')
2365 if (in[i + 1] == u'.' && (i + 2 == n || in[i + 2] == u'/'))
2368 if (!isRemote && lastWasSlash && in[i] == u'/' && i > 0) {
2374 lastWasSlash = in[i] == u'/';
2379 QChar *out = path->data();
2380 const QChar *start = out + prefixLength;
2381 const QChar *end = out + path->size();
2389 QString output = QStringView(path->constBegin(), out).toString();
2390 QStringView input(in, end);
2396 if (in[0] == u'/') {
2398 while (in < end && in[0] == u'/') {
2412 enum { Nothing, Dot, DotDot } type = Nothing;
2413 if (in[0] == u'.') {
2414 if (in + 1 == end || in[1] == u'/')
2416 else if (in[1] == u'.' && (in + 2 == end || in[2] == u'/'))
2419 if (type == Nothing) {
2421 while (in < end && in[0] != u'/')
2430 if (type == DotDot) {
2431 if (Q_UNLIKELY(out == start)) {
2438 if (in + 2 != end) {
2439 Q_ASSERT(in[2] == u'/');
2452 while (out > start && out[-1] != u'/')
2463 if (in != end && out > start && out[-1] == u'/')
2470 if (in != end && in[0] == u'/')
2472 while (prefixLength == 0 && in != end && in[0] == u'/')
2477 path->truncate(out - path->constBegin());
2478 if (!isRemote && path->isEmpty())
2482 return ok || prefixLength == 0;
2487 if (path->isEmpty())
2490 QString &ret = *path;
2491 ret = QDir::fromNativeSeparators(ret);
2492 bool ok = qt_normalizePathSegments(&ret, QDirPrivate::DefaultNormalization);
2495 if (ret.size() > 1 && ret.endsWith(u'/')) {
2496#if defined (Q_OS_WIN)
2497 if (!(ret.length() == 3 && ret.at(1) == u':'))
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517QString QDir::cleanPath(
const QString &path)
2525
2526
2527
2528
2529
2530
2531
2532
2533bool QDir::isRelativePath(
const QString &path)
2535 return QFileInfo(path).isRelative();
2539
2540
2541void QDir::refresh()
const
2543 QDirPrivate *d =
const_cast<QDir *>(
this)->d_func();
2544 d->clearCache(QDirPrivate::IncludingMetaData);
2548
2549
2550QDirPrivate* QDir::d_func()
2552 return d_ptr.data();
2556
2557
2558
2559
2560
2561
2562QStringList QDir::nameFiltersFromString(
const QString &nameFilter)
2564 return QDirPrivate::splitFilters(nameFilter);
2567#ifndef QT_NO_DEBUG_STREAM
2568QDebug operator<<(QDebug debug, QDir::Filters filters)
2570 QDebugStateSaver save(debug);
2571 debug.resetFormat();
2573 if (filters == QDir::NoFilter) {
2574 flags <<
"NoFilter"_L1;
2576 if (filters & QDir::Dirs) flags <<
"Dirs"_L1;
2577 if (filters & QDir::AllDirs) flags <<
"AllDirs"_L1;
2578 if (filters & QDir::Files) flags <<
"Files"_L1;
2579 if (filters & QDir::Drives) flags <<
"Drives"_L1;
2580 if (filters & QDir::NoSymLinks) flags <<
"NoSymLinks"_L1;
2581 if (filters & QDir::NoDot) flags <<
"NoDot"_L1;
2582 if (filters & QDir::NoDotDot) flags <<
"NoDotDot"_L1;
2583 if ((filters & QDir::AllEntries) == QDir::AllEntries) flags <<
"AllEntries"_L1;
2584 if (filters & QDir::Readable) flags <<
"Readable"_L1;
2585 if (filters & QDir::Writable) flags <<
"Writable"_L1;
2586 if (filters & QDir::Executable) flags <<
"Executable"_L1;
2587 if (filters & QDir::Hidden) flags <<
"Hidden"_L1;
2588 if (filters & QDir::System) flags <<
"System"_L1;
2589 if (filters & QDir::CaseSensitive) flags <<
"CaseSensitive"_L1;
2591 debug.noquote() <<
"QDir::Filters(" << flags.join(u'|') <<
')';
2595static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
2597 QDebugStateSaver save(debug);
2598 debug.resetFormat();
2599 if (sorting == QDir::NoSort) {
2600 debug <<
"QDir::SortFlags(NoSort)";
2603 if ((sorting & QDir::SortByMask) == QDir::Name) type =
"Name"_L1;
2604 if ((sorting & QDir::SortByMask) == QDir::Time) type =
"Time"_L1;
2605 if ((sorting & QDir::SortByMask) == QDir::Size) type =
"Size"_L1;
2606 if ((sorting & QDir::SortByMask) == QDir::Unsorted) type =
"Unsorted"_L1;
2609 if (sorting & QDir::DirsFirst) flags <<
"DirsFirst"_L1;
2610 if (sorting & QDir::DirsLast) flags <<
"DirsLast"_L1;
2611 if (sorting & QDir::IgnoreCase) flags <<
"IgnoreCase"_L1;
2612 if (sorting & QDir::LocaleAware) flags <<
"LocaleAware"_L1;
2613 if (sorting & QDir::Type) flags <<
"Type"_L1;
2614 debug.noquote() <<
"QDir::SortFlags(" << type <<
'|' << flags.join(u'|') <<
')';
2619QDebug operator<<(QDebug debug,
const QDir &dir)
2621 QDebugStateSaver save(debug);
2622 debug.resetFormat();
2623 debug <<
"QDir(" << dir.path() <<
", nameFilters = {"
2624 << dir.nameFilters().join(u',')
2635
2636
2637
2638
2639
2640
2641
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2667
2668
2669
2670
2672
2673
2674
2675
2677
2678
2679
2680
2681
2683
2684
2685
2686
2687
2689
2690
2691
2692
2693
QDirPrivate(const QDirPrivate ©)
void clearCache(MetaDataClearing mode)
void initFileLists(const QDir &dir) const
QString resolveAbsoluteEntry() const
bool operator()(const QDirSortItem &, const QDirSortItem &) const
QDirSortItemComparator(QDir::SortFlags flags, QCollator *coll=nullptr)
int compareStrings(const QString &a, const QString &b, Qt::CaseSensitivity cs) const
static void appendIfMatchesNonDirListingFlags(const QDirListing::DirEntry &dirEntry, QDir::Filters filters, QFileInfoList &l)
static qsizetype rootLength(QStringView name, QDirPrivate::PathNormalizations flags)
static bool qt_cleanPath(QString *path)
bool comparesEqual(const QDir &lhs, const QDir &rhs)
static bool treatAsAbsolute(const QString &path)
static bool checkPermissions(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
static bool checkDotOrDotDot(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
QDirSortItem(const QFileInfo &fi, QDir::SortFlags sort)