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>
40using namespace Qt::StringLiterals;
43static QString driveSpec(
const QString &path)
47 char c = path.at(0).toLatin1();
48 if ((c <
'a' || c >
'z') && (c <
'A' || c >
'Z'))
50 if (path.at(1).toLatin1() !=
':')
52 return path.mid(0, 2);
59 constexpr bool UseWindowsRules =
false
64 const qsizetype len = name.size();
65 char16_t firstChar = len > 0 ? name.at(0).unicode() : u'\0';
66 char16_t secondChar = len > 1 ? name.at(1).unicode() : u'\0';
67 if constexpr (UseWindowsRules) {
70 if (firstChar == u'/' && secondChar == u'/' && !urlMode) {
72 const qsizetype nextSlash = name.indexOf(u'/', 2);
73 return nextSlash >= 0 ? nextSlash + 1 : len;
77 qsizetype driveLength = 2;
78 if (firstChar == u'/' && urlMode && len > 2 && name.at(2) == u':') {
83 if (secondChar == u':') {
84 if (len > driveLength && name.at(driveLength) == u'/')
85 return driveLength + 1;
90 return firstChar == u'/' ? 1 : 0;
94QDirPrivate::QDirPrivate(
const QString &path,
const QStringList &nameFilters_,
95 QDir::SortFlags sort_, QDir::Filters filters_)
96 : QSharedData(), nameFilters(nameFilters_), sort(sort_), filters(filters_)
98 setPath(path.isEmpty() ? QString::fromLatin1(
".") : path);
100 auto isEmpty = [](
const auto &e) {
return e.isEmpty(); };
101 const bool empty =
std::all_of(nameFilters.cbegin(), nameFilters.cend(), isEmpty);
103 nameFilters = QStringList(QString::fromLatin1(
"*"));
116 fileCache.fileListsInitialized = copy.fileCache.fileListsInitialized.load();
117 fileCache.files = copy.fileCache.files;
118 fileCache.fileInfos = copy.fileCache.fileInfos;
119 fileCache.absoluteDirEntry = copy.fileCache.absoluteDirEntry;
120 fileCache.metaData = copy.fileCache.metaData;
127 QFileSystemEngine::fillMetaData(
128 dirEntry, fileCache.metaData,
129 QFileSystemMetaData::ExistsAttribute
130 | QFileSystemMetaData::DirectoryType);
131 return fileCache.metaData.exists() && fileCache.metaData.isDirectory();
133 const QAbstractFileEngine::FileFlags info =
134 fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
135 | QAbstractFileEngine::ExistsFlag
136 | QAbstractFileEngine::Refresh);
137 if (!(info & QAbstractFileEngine::DirectoryType))
139 return info.testAnyFlag(QAbstractFileEngine::ExistsFlag);
143inline QChar
QDirPrivate::getFilterSepChar(
const QString &nameFilter)
146 qsizetype i = nameFilter.indexOf(sep, 0);
147 if (i == -1 && nameFilter.indexOf(u' ', 0) != -1)
153inline QStringList
QDirPrivate::splitFilters(
const QString &nameFilter, QChar sep)
156 sep = getFilterSepChar(nameFilter);
158 for (
auto e : qTokenize(nameFilter, sep))
159 ret.append(e.trimmed().toString());
165 QString p = QDir::fromNativeSeparators(path);
169 && (!(p.length() == 3 && p.at(1).unicode() ==
':' && p.at(0).isLetter()))
172 p.truncate(p.size() - 1);
174 dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
176 fileCache.absoluteDirEntry = QFileSystemEntry();
182 if (!fileCache.absoluteDirEntry.isEmpty())
183 return fileCache.absoluteDirEntry.filePath();
185 if (dirEntry.isEmpty())
186 return dirEntry.filePath();
188 QString absoluteName;
190 if (!dirEntry.isRelative() && dirEntry.isClean()) {
191 fileCache.absoluteDirEntry = dirEntry;
192 return dirEntry.filePath();
195 absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath();
197 absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
199 auto absoluteFileSystemEntry =
200 QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
201 fileCache.absoluteDirEntry = absoluteFileSystemEntry;
202 return absoluteFileSystemEntry.filePath();
215 if (sort.testAnyFlag(QDir::Type))
216 suffix_cache = item.suffix();
226 QDir::SortFlags qt_cmp_si_sort_flags;
228#ifndef QT_BOOTSTRAPPED
229 QCollator *collator =
nullptr;
232#ifndef QT_BOOTSTRAPPED
236 Q_ASSERT(!qt_cmp_si_sort_flags.testAnyFlag(QDir::LocaleAware) || collator);
238 if (collator && qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase))
239 collator->setCaseSensitivity(Qt::CaseInsensitive);
249 int compareStrings(
const QString &a,
const QString &b, Qt::CaseSensitivity cs)
const
251#ifndef QT_BOOTSTRAPPED
253 return collator->compare(a, b);
255 return a.compare(b, cs);
264 if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir()))
265 return f1->item.isDir();
266 if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
267 return !f1->item.isDir();
269 const bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
270 const auto qtcase = ic ? Qt::CaseInsensitive : Qt::CaseSensitive;
273 int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask)
274 | (qt_cmp_si_sort_flags & QDir::Type)).toInt();
278 const QDateTime firstModified = f1->item.lastModified(QTimeZone::UTC);
279 const QDateTime secondModified = f2->item.lastModified(QTimeZone::UTC);
280 r = firstModified.msecsTo(secondModified);
284 r = f2->item.size() - f1->item.size();
287 r = compareStrings(f1->suffix_cache, f2->suffix_cache, qtcase);
293 if (r == 0 && sortBy != QDir::Unsorted) {
296 if (f1->filename_cache.isNull())
297 f1->filename_cache = f1->item.fileName();
298 if (f2->filename_cache.isNull())
299 f2->filename_cache = f2->item.fileName();
301 r = compareStrings(f1->filename_cache, f2->filename_cache, qtcase);
303 if (qt_cmp_si_sort_flags & QDir::Reversed)
308inline void QDirPrivate::sortFileList(QDir::SortFlags sort,
const QFileInfoList &l,
309 QStringList *names, QFileInfoList *infos)
311 Q_ASSERT(names || infos);
312 Q_ASSERT(!infos || infos->isEmpty());
313 Q_ASSERT(!names || names->isEmpty());
315 const qsizetype n = l.size();
319 if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
324 for (
const QFileInfo &fi : l)
325 names->append(fi.fileName());
328 QVarLengthArray<QDirSortItem, 64> si;
330 for (qsizetype i = 0; i < n; ++i)
331 si.emplace_back(l.at(i), sort);
333#ifndef QT_BOOTSTRAPPED
334 if (sort.testAnyFlag(QDir::LocaleAware)) {
336 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort, &coll));
338 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
341 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
345 for (qsizetype i = 0; i < n; ++i) {
346 auto &fileInfo = si[i].item;
348 infos->append(fileInfo);
350 const bool cached = !si[i].filename_cache.isNull();
351 names->append(cached ? si[i].filename_cache : fileInfo.fileName());
357#ifndef QT_BOOTSTRAPPED
359
360
361
362
363
364
367 const auto perms = filters & QDir::PermissionMask;
368 const bool filterByPermissions = perms != 0 && perms != QDir::PermissionMask;
369 if (filterByPermissions) {
370 const QFileInfo fileInfo = dirEntry.fileInfo();
371 if (filters.testFlags(QDir::Readable) && !fileInfo.isReadable())
373 if (filters.testFlags(QDir::Writable) && !fileInfo.isWritable())
375 if (filters.testFlags(QDir::Executable) && !fileInfo.isExecutable())
383 const QString fileName = dirEntry.fileName();
384 if ((filters & QDir::NoDot) && fileName == u".")
386 if ((filters & QDir::NoDotDot) && fileName == u"..")
392
393
394
395
396
398 QDir::Filters filters)
400 return checkPermissions(dirEntry, filters) && checkDotOrDotDot(dirEntry, filters);
404 QDir::Filters filters, QFileInfoList &l)
406 if (QDirPrivate::checkNonDirListingFlags(dirEntry, filters))
407 l.emplace_back(dirEntry.fileInfo());
411
412
413
414
415
416
417
418QDirListing::IteratorFlags
QDirPrivate::toDirListingFlags(QDir::Filters filters)
420 if (filters == QDir::NoFilter)
421 filters = QDir::AllEntries;
423 using F = QDirListing::IteratorFlag;
424 QDirListing::IteratorFlags flags;
425 if (!(filters & QDir::Dirs) && !(filters & QDir::AllDirs))
426 flags |= F::ExcludeDirs;
427 if (!(filters & QDir::Files))
428 flags |= F::ExcludeFiles;
429 if (!(filters & QDir::NoSymLinks))
430 flags |= F::ResolveSymlinks;
431 if (filters & QDir::Hidden)
432 flags |= F::IncludeHidden;
434 if (!(filters & QDir::System))
435 flags |= F::ExcludeOther;
437 flags |= F::IncludeBrokenSymlinks;
440 if (filters & QDir::AllDirs)
441 flags |= F::NoNameFiltersForDirs;
442 if (filters & QDir::CaseSensitive)
443 flags |= F::CaseSensitive;
448 if (!(filters & QDir::NoDot) || !(filters & QDir::NoDotDot)) {
449 if (!(flags & F::ExcludeDirs))
450 flags |= F::IncludeDotAndDotDot;
459 if (!fileCache.fileListsInitialized) {
461 QDirListing::IteratorFlags flags = toDirListingFlags(dir.filter());
462 for (
const auto &dirEntry : QDirListing(dir.path(), dir.nameFilters(), flags))
463 appendIfMatchesNonDirListingFlags(dirEntry, dir.filter(), l);
465 sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos);
466 fileCache.fileListsInitialized =
true;
474 if (mode == IncludingMetaData)
475 fileCache.metaData.clear();
476 fileCache.fileListsInitialized =
false;
477 fileCache.files.clear();
478 fileCache.fileInfos.clear();
479 fileEngine = QFileSystemEngine::createLegacyEngine(dirEntry, fileCache.metaData);
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
665
668
669
670
671
672
673
676
677
678QDir::QDir(QDirPrivate &p) : d_ptr(&p)
683
684
685
686
687
688QDir::QDir(
const QString &path) : d_ptr(
new QDirPrivate(path))
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710QDir::QDir(
const QString &path,
const QString &nameFilter,
711 SortFlags sort, Filters filters)
712 : d_ptr(
new QDirPrivate(path, QDir::nameFiltersFromString(nameFilter), sort, filters))
717
718
719
720
721
722QDir::QDir(
const QDir &dir)
728
729
730
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751void QDir::setPath(
const QString &path)
753 d_ptr->setPath(path);
757
758
759
760
761
762
763
764
765
766QString QDir::path()
const
769 return d->dirEntry.filePath();
773
774
775
776
777
778
779
780QString QDir::absolutePath()
const
784 return d->resolveAbsoluteEntry();
786 return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805QString QDir::canonicalPath()
const
808 if (!d->fileEngine) {
809 QMutexLocker locker(&d->fileCache.mutex);
810 QFileSystemEntry answer =
811 QFileSystemEngine::canonicalName(d->dirEntry, d->fileCache.metaData);
812 return answer.filePath();
814 return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
818
819
820
821
822
823
824
825
826
827
828QString QDir::dirName()
const
831 if (!d_ptr->fileEngine)
832 return d->dirEntry.fileName();
833 return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
838static qsizetype drivePrefixLength(QStringView path)
841 const qsizetype size = path.size();
843 if (size > 1 && path.at(1).unicode() ==
':') {
844 if (Q_UNLIKELY(!path.at(0).isLetter()))
846 }
else if (path.startsWith(
"//"_L1)) {
849 for (
int i = 0 ; i < 2 ; ++i) {
850 while (drive < size && path.at(drive).unicode() ==
'/')
853 qWarning(
"Base directory starts with neither a drive nor a UNC share: %s",
854 qUtf8Printable(QDir::toNativeSeparators(path.toString())));
857 while (drive < size && path.at(drive).unicode() !=
'/')
878 return (path.contains(u':') && QFileInfo(path).isAbsolute())
879 || QFileSystemEntry(path).isAbsolute();
883
884
885
886
887
888
889
890
891QString QDir::filePath(
const QString &fileName)
const
893 if (treatAsAbsolute(fileName))
897 QString ret = d->dirEntry.filePath();
898 if (fileName.isEmpty())
902 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
904 const qsizetype drive = drivePrefixLength(ret);
905 return drive > 0 ? QStringView{ret}.left(drive) % fileName : fileName;
909 if (ret.isEmpty() || ret.endsWith(u'/'))
910 return ret % fileName;
911 return ret % u'/' % fileName;
915
916
917
918
919
920
921
922QString QDir::absoluteFilePath(
const QString &fileName)
const
924 if (treatAsAbsolute(fileName))
928 QString absoluteDirPath = d->resolveAbsoluteEntry();
929 if (fileName.isEmpty())
930 return absoluteDirPath;
933 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
935 const qsizetype drive = drivePrefixLength(absoluteDirPath);
937 return QStringView{absoluteDirPath}.left(drive) % fileName;
939 qWarning(
"Base directory's drive is not a letter: %s",
940 qUtf8Printable(QDir::toNativeSeparators(absoluteDirPath)));
944 if (!absoluteDirPath.endsWith(u'/'))
945 return absoluteDirPath % u'/' % fileName;
946 return absoluteDirPath % fileName;
950
951
952
953
954
955
956QString QDir::relativeFilePath(
const QString &fileName)
const
958 QString dir = cleanPath(absolutePath());
959 QString file = cleanPath(fileName);
961 if (isRelativePath(file) || isRelativePath(dir))
965 QString dirDrive = driveSpec(dir);
966 QString fileDrive = driveSpec(file);
968 bool fileDriveMissing =
false;
969 if (fileDrive.isEmpty()) {
970 fileDrive = dirDrive;
971 fileDriveMissing =
true;
974 if (fileDrive.toLower() != dirDrive.toLower()
975 || (file.startsWith(
"//"_L1)
976 && !dir.startsWith(
"//"_L1))) {
980 dir.remove(0, dirDrive.size());
981 if (!fileDriveMissing)
982 file.remove(0, fileDrive.size());
986 const auto dirElts = dir.tokenize(u'/', Qt::SkipEmptyParts);
987 const auto fileElts = file.tokenize(u'/', Qt::SkipEmptyParts);
989 const auto dend = dirElts.end();
990 const auto fend = fileElts.end();
991 auto dit = dirElts.begin();
992 auto fit = fileElts.begin();
994 const auto eq = [](QStringView lhs, QStringView rhs) {
997 lhs.compare(rhs, Qt::CaseInsensitive) == 0;
1004 while (dit != dend && fit != fend && eq(*dit, *fit)) {
1009 while (dit != dend) {
1015 while (fit != fend) {
1022 if (result.isEmpty())
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042QString QDir::toNativeSeparators(
const QString &pathName)
1044#if defined(Q_OS_WIN)
1045 qsizetype i = pathName.indexOf(u'/');
1047 QString n(pathName);
1049 QChar *
const data = n.data();
1052 for (; i < n.length(); ++i) {
1053 if (data[i] == u'/')
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075QString QDir::fromNativeSeparators(
const QString &pathName)
1077#if defined(Q_OS_WIN)
1078 return QFileSystemEntry::removeUncOrLongPathPrefix(pathName).replace(u'\\', u'/');
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097bool QDir::cd(
const QString &dirName)
1100 const QDirPrivate *
const d = d_ptr.constData();
1102 if (dirName.isEmpty() || dirName == u'.')
1105 if (isAbsolutePath(dirName)) {
1107 qt_cleanPath(&newPath);
1109 newPath = d->dirEntry.filePath();
1110 if (!newPath.endsWith(u'/'))
1113 if (dirName.indexOf(u'/') >= 0
1114 || dirName ==
".."_L1
1115 || d->dirEntry.filePath() == u'.') {
1116 if (!qt_cleanPath(&newPath))
1119
1120
1121
1122
1123
1124
1125
1126 if (newPath.startsWith(
".."_L1)) {
1127 newPath = QFileInfo(newPath).absoluteFilePath();
1132 std::unique_ptr<QDirPrivate> dir(
new QDirPrivate(*d_ptr.constData()));
1133 dir->setPath(newPath);
1137 d_ptr = dir.release();
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1156 return cd(QString::fromLatin1(
".."));
1160
1161
1162QStringList QDir::nameFilters()
const
1165 return d->nameFilters;
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183void QDir::setNameFilters(
const QStringList &nameFilters)
1186 d->clearCache(QDirPrivate::KeepMetaData);
1187 d->nameFilters = nameFilters;
1190#ifndef QT_BOOTSTRAPPED
1193struct DirSearchPaths {
1194 mutable QReadWriteLock mutex;
1195 QHash<QString, QStringList> paths;
1199Q_GLOBAL_STATIC(DirSearchPaths, dirSearchPaths)
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221void QDir::setSearchPaths(
const QString &prefix,
const QStringList &searchPaths)
1223 if (prefix.size() < 2) {
1224 qWarning(
"QDir::setSearchPaths: Prefix must be longer than 1 character");
1228 for (QChar ch : prefix) {
1229 if (!ch.isLetterOrNumber()) {
1230 qWarning(
"QDir::setSearchPaths: Prefix can only contain letters or numbers");
1235 DirSearchPaths &conf = *dirSearchPaths;
1236 const QWriteLocker lock(&conf.mutex);
1237 if (searchPaths.isEmpty()) {
1238 conf.paths.remove(prefix);
1240 conf.paths.insert(prefix, searchPaths);
1245
1246
1247
1248
1249
1250
1251void QDir::addSearchPath(
const QString &prefix,
const QString &path)
1256 DirSearchPaths &conf = *dirSearchPaths;
1257 const QWriteLocker lock(&conf.mutex);
1258 conf.paths[prefix] += path;
1262
1263
1264
1265
1266
1267
1268QStringList QDir::searchPaths(
const QString &prefix)
1270 if (!dirSearchPaths.exists())
1271 return QStringList();
1273 const DirSearchPaths &conf = *dirSearchPaths;
1274 const QReadLocker lock(&conf.mutex);
1275 return conf.paths.value(prefix);
1281
1282
1283QDir::Filters QDir::filter()
const
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
1351
1354
1355
1356
1357
1358
1359
1360
1361void QDir::setFilter(Filters filters)
1364 d->clearCache(QDirPrivate::KeepMetaData);
1365 d->filters = filters;
1369
1370
1371
1372
1373QDir::SortFlags QDir::sorting()
const
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
1406
1408#ifndef QT_BOOTSTRAPPED
1410
1411
1412
1413
1414
1415
1416
1417void QDir::setSorting(SortFlags sort)
1420 d->clearCache(QDirPrivate::KeepMetaData);
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434qsizetype QDir::count(QT6_IMPL_NEW_OVERLOAD)
const
1437 d->initFileLists(*
this);
1438 return d->fileCache.files.size();
1442
1443
1444
1445
1446
1447
1448
1449
1450QString QDir::operator[](qsizetype pos)
const
1453 d->initFileLists(*
this);
1454 return d->fileCache.files[pos];
1458
1459
1460
1461
1462
1463
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486QStringList QDir::entryList(Filters filters, SortFlags sort)
const
1489 return entryList(d->nameFilters, filters, sort);
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort)
const
1514 return entryInfoList(d->nameFilters, filters, sort);
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535QStringList QDir::entryList(
const QStringList &nameFilters, Filters filters,
1536 SortFlags sort)
const
1540 if (filters == NoFilter)
1541 filters = d->filters;
1545 const bool needsSorting = (sort & QDir::SortByMask) != QDir::Unsorted;
1547 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1549 if (needsSorting || d->fileCache.fileListsInitialized) {
1550 d->initFileLists(*
this);
1551 return d->fileCache.files;
1555 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1556 QDirListing dirList(d->dirEntry.filePath(), nameFilters, flags);
1560 for (
const auto &dirEntry : dirList)
1561 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1562 d->sortFileList(sort, l, &ret,
nullptr);
1564 for (
const auto &dirEntry : dirList)
1565 ret.emplace_back(dirEntry.fileName());
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588QFileInfoList QDir::entryInfoList(
const QStringList &nameFilters, Filters filters,
1589 SortFlags sort)
const
1593 if (filters == NoFilter)
1594 filters = d->filters;
1598 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1599 d->initFileLists(*
this);
1600 return d->fileCache.fileInfos;
1604 const QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1605 for (
const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, flags))
1606 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1608 d->sortFileList(sort, l,
nullptr, &ret);
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648bool QDir::mkdir(
const QString &dirName, std::optional<QFile::Permissions> permissions)
const
1652 if (dirName.isEmpty()) {
1653 qWarning(
"QDir::mkdir: Empty or null file name");
1657 QString fn = filePath(dirName);
1659 return QFileSystemEngine::mkdir(QFileSystemEntry(fn), permissions);
1660 return d->fileEngine->mkdir(fn,
false, permissions);
1664
1665
1666
1667
1668
1669
1670
1671
1672bool QDir::rmdir(
const QString &dirName)
const
1676 if (dirName.isEmpty()) {
1677 qWarning(
"QDir::rmdir: Empty or null file name");
1681 QString fn = filePath(dirName);
1683 return QFileSystemEngine::rmdir(QFileSystemEntry(fn));
1685 return d->fileEngine->rmdir(fn,
false);
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713bool QDir::mkpath(
const QString &dirPath, std::optional<QFile::Permissions> permissions)
const
1717 if (dirPath.isEmpty()) {
1718 qWarning(
"QDir::mkpath: Empty or null file name");
1722 QString fn = filePath(dirPath);
1724 return QFileSystemEngine::mkpath(QFileSystemEntry(fn), permissions);
1725 return d->fileEngine->mkdir(fn,
true, permissions);
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739bool QDir::rmpath(
const QString &dirPath)
const
1743 if (dirPath.isEmpty()) {
1744 qWarning(
"QDir::rmpath: Empty or null file name");
1748 QString fn = filePath(dirPath);
1750 return QFileSystemEngine::rmpath(QFileSystemEntry(fn));
1751 return d->fileEngine->rmdir(fn,
true);
1754#ifndef QT_BOOTSTRAPPED
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775bool QDir::removeRecursively()
1777 if (!d_ptr->fileEngine && QFileSystemEngine::supportsRmdirRecursively()) {
1779 return QFileSystemEngine::rmdirRecursively(QFileSystemEntry(absolutePath()), error);
1782 if (!d_ptr->exists())
1791 bool success =
true;
1793 std::stack<DirInfo, std::vector<DirInfo>> dirsToRemove;
1794 dirsToRemove.push({absolutePath(),
false});
1796 while (!dirsToRemove.empty()) {
1797 auto &info = dirsToRemove.top();
1800 for (
const auto &dirEntry : QDirListing(info.path, QDirListing::IteratorFlag::IncludeHidden)) {
1801 const QString &filePath = dirEntry.filePath();
1802 if (dirEntry.isDir() && !dirEntry.isSymLink()) {
1803 dirsToRemove.push({filePath,
false});
1805 bool ok = QFile::remove(filePath);
1807 const QFile::Permissions permissions = QFile::permissions(filePath);
1808 if (!(permissions & QFile::WriteUser))
1809 ok = QFile::setPermissions(filePath, permissions | QFile::WriteUser)
1810 && QFile::remove(filePath);
1817 if (!rmdir(info.path))
1828
1829
1830
1831
1832
1833
1834
1835
1836bool QDir::isReadable()
const
1840 if (!d->fileEngine) {
1841 QMutexLocker locker(&d->fileCache.mutex);
1842 if (!d->fileCache.metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) {
1843 QFileSystemEngine::fillMetaData(d->dirEntry, d->fileCache.metaData,
1844 QFileSystemMetaData::UserReadPermission);
1846 return d->fileCache.metaData.permissions().testAnyFlag(QFile::ReadUser);
1849 const QAbstractFileEngine::FileFlags info =
1850 d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
1851 | QAbstractFileEngine::PermsMask);
1852 if (!(info & QAbstractFileEngine::DirectoryType))
1854 return info.testAnyFlag(QAbstractFileEngine::ReadUserPerm);
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868bool QDir::exists()
const
1870 return d_ptr->exists();
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885bool QDir::isRoot()
const
1887 if (!d_ptr->fileEngine)
1888 return d_ptr->dirEntry.isRoot();
1889 return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask).testAnyFlag(QAbstractFileEngine::RootFlag);
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926bool QDir::isRelative()
const
1928 if (!d_ptr->fileEngine)
1929 return d_ptr->dirEntry.isRelative();
1930 return d_ptr->fileEngine->isRelativePath();
1935
1936
1937
1938
1939
1940
1941bool QDir::makeAbsolute()
1944 std::unique_ptr<QDirPrivate> dir;
1945 if (!!d->fileEngine) {
1946 QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
1947 if (QDir::isRelativePath(absolutePath))
1950 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1951 dir->setPath(absolutePath);
1953 QString absoluteFilePath = d->resolveAbsoluteEntry();
1954 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1955 dir->setPath(absoluteFilePath);
1957 d_ptr = dir.release();
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1979 Qt::CaseSensitivity sensitive;
1980 if (!d->fileEngine || !other->fileEngine) {
1981 if (d->fileEngine.get() != other->fileEngine.get())
1984 QOrderedMutexLocker locker(&d->fileCache.mutex, &other->fileCache.mutex);
1985 const bool thisCaseSensitive = QFileSystemEngine::isCaseSensitive(d->dirEntry, d->fileCache.metaData);
1986 if (thisCaseSensitive != QFileSystemEngine::isCaseSensitive(other->dirEntry, other->fileCache.metaData))
1989 sensitive = thisCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
1991 if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
1993 sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1996 if (d->filters == other->filters
1997 && d->sort == other->sort
1998 && d->nameFilters == other->nameFilters) {
2001 if (d->dirEntry.filePath() == other->dirEntry.filePath())
2008 return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0;
2013 QString thisFilePath = d->resolveAbsoluteEntry();
2014 QString otherFilePath = other->resolveAbsoluteEntry();
2015 return thisFilePath.compare(otherFilePath, sensitive) == 0;
2022
2023
2024
2025QDir &QDir::operator=(
const QDir &dir)
2032
2033
2034
2035
2038
2039
2040
2041
2042
2043
2044
2045
2046
2049
2050
2051
2052
2053
2054bool QDir::remove(
const QString &fileName)
2056 if (fileName.isEmpty()) {
2057 qWarning(
"QDir::remove: Empty or null file name");
2060 return QFile::remove(filePath(fileName));
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079bool QDir::rename(
const QString &oldName,
const QString &newName)
2081 if (oldName.isEmpty() || newName.isEmpty()) {
2082 qWarning(
"QDir::rename: Empty or null file name(s)");
2086 QFile file(filePath(oldName));
2089 return file.rename(filePath(newName));
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102bool QDir::exists(
const QString &name)
const
2104 if (name.isEmpty()) {
2105 qWarning(
"QDir::exists: Empty or null file name");
2108 return QFileInfo::exists(filePath(name));
2111#ifndef QT_BOOTSTRAPPED
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125bool QDir::isEmpty(Filters filters)
const
2129 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
2130 for (
const auto &dirEntry : QDirListing(d->dirEntry.filePath(), d->nameFilters, flags)) {
2131 if (QDirPrivate::checkNonDirListingFlags(dirEntry, filters))
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148QFileInfoList QDir::drives()
2150#ifdef QT_NO_FSFILEENGINE
2151 return QFileInfoList();
2153 return QFSFileEngine::drives();
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2173
2174
2175
2176
2177
2178
2179
2180
2183
2184
2185
2186
2187
2188
2189
2190
2191bool QDir::setCurrent(
const QString &path)
2193 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
2197
2198
2199
2200
2201
2202
2203
2204
2205
2208
2209
2210
2211
2212
2213
2214
2215QString QDir::currentPath()
2217 return QFileSystemEngine::currentPath().filePath();
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264QString QDir::homePath()
2266 return QFileSystemEngine::homePath();
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294QString QDir::tempPath()
2296 return QFileSystemEngine::tempPath();
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2313
2314
2315
2316
2317
2318
2319
2320QString QDir::rootPath()
2322 return QFileSystemEngine::rootPath();
2325#if QT_CONFIG(regularexpression)
2327
2328
2329
2330
2331
2332
2333
2334
2335bool QDir::match(
const QStringList &filters,
const QString &fileName)
2337 for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
2339 auto rx = QRegularExpression::fromWildcard(*sit, Qt::CaseInsensitive);
2340 if (rx.match(fileName).hasMatch())
2347
2348
2349
2350
2351
2352
2353
2354bool QDir::match(
const QString &filter,
const QString &fileName)
2356 return match(nameFiltersFromString(filter), fileName);
2361 QDirPrivate::PathNormalizations flags)
noexcept
2367 for (
bool lastWasSlash =
true; i < n; ++i) {
2368 if (lastWasSlash && in[i] == u'.') {
2369 if (i + 1 == n || in[i + 1] == u'/')
2371 if (in[i + 1] == u'.' && (i + 2 == n || in[i + 2] == u'/'))
2374 if (!isRemote && lastWasSlash && in[i] == u'/' && i > 0) {
2380 lastWasSlash = in[i] == u'/';
2387 const qsizetype prefixLength = rootLength(path, flags);
2388 qsizetype where = findStartOfNonNormalizedPath(path.constBegin(), prefixLength, path.size(), flags);
2389 return where == path.size();
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2417 const qsizetype prefixLength = rootLength(*path, flags);
2422 const QChar *in = path->constBegin();
2424 qsizetype n = path->size();
2425 qsizetype i = findStartOfNonNormalizedPath(in, prefixLength, n, flags);
2429 QChar *out = path->data();
2430 const QChar *start = out + prefixLength;
2431 const QChar *end = out + path->size();
2439 QString output = QStringView(path->constBegin(), out).toString();
2440 QStringView input(in, end);
2446 if (in[0] == u'/') {
2448 while (in < end && in[0] == u'/') {
2462 enum { Nothing, Dot, DotDot } type = Nothing;
2463 if (in[0] == u'.') {
2464 if (in + 1 == end || in[1] == u'/')
2466 else if (in[1] == u'.' && (in + 2 == end || in[2] == u'/'))
2469 if (type == Nothing) {
2471 while (in < end && in[0] != u'/')
2480 if (type == DotDot) {
2481 if (Q_UNLIKELY(out == start)) {
2488 if (in + 2 != end) {
2489 Q_ASSERT(in[2] == u'/');
2502 while (out > start && out[-1] != u'/')
2513 if (in != end && out > start && out[-1] == u'/')
2520 if (in != end && in[0] == u'/')
2522 while (prefixLength == 0 && in != end && in[0] == u'/')
2527 path->truncate(out - path->constBegin());
2528 if (!isRemote && path->isEmpty())
2532 return ok || prefixLength == 0;
2537 if (path->isEmpty())
2540 QString &ret = *path;
2541 ret = QDir::fromNativeSeparators(ret);
2542 bool ok = qt_normalizePathSegments(&ret, QDirPrivate::DefaultNormalization);
2545 if (ret.size() > 1 && ret.endsWith(u'/')) {
2546#if defined (Q_OS_WIN)
2547 if (!(ret.length() == 3 && ret.at(1) == u':'))
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567QString QDir::cleanPath(
const QString &path)
2575
2576
2577
2578
2579
2580
2581
2582
2583bool QDir::isRelativePath(
const QString &path)
2585 return QFileInfo(path).isRelative();
2589
2590
2591void QDir::refresh()
const
2593 QDirPrivate *d =
const_cast<QDir *>(
this)->d_func();
2594 d->clearCache(QDirPrivate::IncludingMetaData);
2598
2599
2600QDirPrivate* QDir::d_func()
2602 return d_ptr.data();
2606
2607
2608
2609
2610
2611
2612QStringList QDir::nameFiltersFromString(
const QString &nameFilter)
2614 return QDirPrivate::splitFilters(nameFilter);
2617#ifndef QT_NO_DEBUG_STREAM
2620 QDebugStateSaver save(debug);
2621 debug.resetFormat();
2623 if (filters == QDir::NoFilter) {
2624 flags <<
"NoFilter"_L1;
2626 if (filters & QDir::Dirs) flags <<
"Dirs"_L1;
2627 if (filters & QDir::AllDirs) flags <<
"AllDirs"_L1;
2628 if (filters & QDir::Files) flags <<
"Files"_L1;
2629 if (filters & QDir::Drives) flags <<
"Drives"_L1;
2630 if (filters & QDir::NoSymLinks) flags <<
"NoSymLinks"_L1;
2631 if (filters & QDir::NoDot) flags <<
"NoDot"_L1;
2632 if (filters & QDir::NoDotDot) flags <<
"NoDotDot"_L1;
2633 if ((filters & QDir::AllEntries) == QDir::AllEntries) flags <<
"AllEntries"_L1;
2634 if (filters & QDir::Readable) flags <<
"Readable"_L1;
2635 if (filters & QDir::Writable) flags <<
"Writable"_L1;
2636 if (filters & QDir::Executable) flags <<
"Executable"_L1;
2637 if (filters & QDir::Hidden) flags <<
"Hidden"_L1;
2638 if (filters & QDir::System) flags <<
"System"_L1;
2639 if (filters & QDir::CaseSensitive) flags <<
"CaseSensitive"_L1;
2641 debug.noquote() <<
"QDir::Filters(" << flags.join(u'|') <<
')';
2647 QDebugStateSaver save(debug);
2648 debug.resetFormat();
2649 if (sorting == QDir::NoSort) {
2650 debug <<
"QDir::SortFlags(NoSort)";
2653 if ((sorting & QDir::SortByMask) == QDir::Name) type =
"Name"_L1;
2654 if ((sorting & QDir::SortByMask) == QDir::Time) type =
"Time"_L1;
2655 if ((sorting & QDir::SortByMask) == QDir::Size) type =
"Size"_L1;
2656 if ((sorting & QDir::SortByMask) == QDir::Unsorted) type =
"Unsorted"_L1;
2659 if (sorting & QDir::DirsFirst) flags <<
"DirsFirst"_L1;
2660 if (sorting & QDir::DirsLast) flags <<
"DirsLast"_L1;
2661 if (sorting & QDir::IgnoreCase) flags <<
"IgnoreCase"_L1;
2662 if (sorting & QDir::LocaleAware) flags <<
"LocaleAware"_L1;
2663 if (sorting & QDir::Type) flags <<
"Type"_L1;
2664 debug.noquote() <<
"QDir::SortFlags(" << type <<
'|' << flags.join(u'|') <<
')';
2671 QDebugStateSaver save(debug);
2672 debug.resetFormat();
2673 debug <<
"QDir(" << dir.path() <<
", nameFilters = {"
2674 << dir.nameFilters().join(u',')
2685
2686
2687
2688
2689
2690
2691
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2717
2718
2719
2720
2722
2723
2724
2725
2727
2728
2729
2730
2731
2733
2734
2735
2736
2737
2739
2740
2741
2742
2743
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)
QDebug operator<<(QDebug debug, QDir::Filters filters)
QDebug operator<<(QDebug debug, const QDir &dir)
static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
bool qt_isPathNormalized(const QString &path, QDirPrivate::PathNormalizations flags) noexcept
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 qsizetype findStartOfNonNormalizedPath(const QChar *in, qsizetype i, qsizetype n, QDirPrivate::PathNormalizations flags) noexcept
static bool checkDotOrDotDot(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
QDirSortItem(const QFileInfo &fi, QDir::SortFlags sort)