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
805
806
807QString QDir::canonicalPath()
const
810 if (!d->fileEngine) {
811 QMutexLocker locker(&d->fileCache.mutex);
812 QFileSystemEntry answer =
813 QFileSystemEngine::canonicalName(d->dirEntry, d->fileCache.metaData);
814 return answer.filePath();
816 return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
820
821
822
823
824
825
826
827
828
829
830QString QDir::dirName()
const
833 if (!d_ptr->fileEngine)
834 return d->dirEntry.fileName();
835 return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
840static qsizetype drivePrefixLength(QStringView path)
843 const qsizetype size = path.size();
845 if (size > 1 && path.at(1).unicode() ==
':') {
846 if (Q_UNLIKELY(!path.at(0).isLetter()))
848 }
else if (path.startsWith(
"//"_L1)) {
851 for (
int i = 0 ; i < 2 ; ++i) {
852 while (drive < size && path.at(drive).unicode() ==
'/')
855 qWarning(
"Base directory starts with neither a drive nor a UNC share: %s",
856 qUtf8Printable(QDir::toNativeSeparators(path.toString())));
859 while (drive < size && path.at(drive).unicode() !=
'/')
880 return (path.contains(u':') && QFileInfo(path).isAbsolute())
881 || QFileSystemEntry(path).isAbsolute();
885
886
887
888
889
890
891
892
893QString QDir::filePath(
const QString &fileName)
const
895 if (treatAsAbsolute(fileName))
899 QString ret = d->dirEntry.filePath();
900 if (fileName.isEmpty())
904 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
906 const qsizetype drive = drivePrefixLength(ret);
907 return drive > 0 ? QStringView{ret}.left(drive) % fileName : fileName;
911 if (ret.isEmpty() || ret.endsWith(u'/'))
912 return ret % fileName;
913 return ret % u'/' % fileName;
917
918
919
920
921
922
923
924QString QDir::absoluteFilePath(
const QString &fileName)
const
926 if (treatAsAbsolute(fileName))
930 QString absoluteDirPath = d->resolveAbsoluteEntry();
931 if (fileName.isEmpty())
932 return absoluteDirPath;
935 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
937 const qsizetype drive = drivePrefixLength(absoluteDirPath);
939 return QStringView{absoluteDirPath}.left(drive) % fileName;
941 qWarning(
"Base directory's drive is not a letter: %s",
942 qUtf8Printable(QDir::toNativeSeparators(absoluteDirPath)));
946 if (!absoluteDirPath.endsWith(u'/'))
947 return absoluteDirPath % u'/' % fileName;
948 return absoluteDirPath % fileName;
952
953
954
955
956
957
958QString QDir::relativeFilePath(
const QString &fileName)
const
960 QString dir = cleanPath(absolutePath());
961 QString file = cleanPath(fileName);
963 if (isRelativePath(file) || isRelativePath(dir))
967 QString dirDrive = driveSpec(dir);
968 QString fileDrive = driveSpec(file);
970 bool fileDriveMissing =
false;
971 if (fileDrive.isEmpty()) {
972 fileDrive = dirDrive;
973 fileDriveMissing =
true;
976 if (fileDrive.toLower() != dirDrive.toLower()
977 || (file.startsWith(
"//"_L1)
978 && !dir.startsWith(
"//"_L1))) {
982 dir.remove(0, dirDrive.size());
983 if (!fileDriveMissing)
984 file.remove(0, fileDrive.size());
988 const auto dirElts = dir.tokenize(u'/', Qt::SkipEmptyParts);
989 const auto fileElts = file.tokenize(u'/', Qt::SkipEmptyParts);
991 const auto dend = dirElts.end();
992 const auto fend = fileElts.end();
993 auto dit = dirElts.begin();
994 auto fit = fileElts.begin();
996 const auto eq = [](QStringView lhs, QStringView rhs) {
999 lhs.compare(rhs, Qt::CaseInsensitive) == 0;
1006 while (dit != dend && fit != fend && eq(*dit, *fit)) {
1011 while (dit != dend) {
1017 while (fit != fend) {
1024 if (result.isEmpty())
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044QString QDir::toNativeSeparators(
const QString &pathName)
1046#if defined(Q_OS_WIN)
1047 qsizetype i = pathName.indexOf(u'/');
1049 QString n(pathName);
1051 QChar *
const data = n.data();
1054 for (; i < n.length(); ++i) {
1055 if (data[i] == u'/')
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077QString QDir::fromNativeSeparators(
const QString &pathName)
1079#if defined(Q_OS_WIN)
1080 return QFileSystemEntry::removeUncOrLongPathPrefix(pathName).replace(u'\\', u'/');
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099bool QDir::cd(
const QString &dirName)
1102 const QDirPrivate *
const d = d_ptr.constData();
1104 if (dirName.isEmpty() || dirName == u'.')
1107 if (isAbsolutePath(dirName)) {
1109 qt_cleanPath(&newPath);
1111 newPath = d->dirEntry.filePath();
1112 if (!newPath.endsWith(u'/'))
1115 if (dirName.indexOf(u'/') >= 0
1116 || dirName ==
".."_L1
1117 || d->dirEntry.filePath() == u'.') {
1118 if (!qt_cleanPath(&newPath))
1121
1122
1123
1124
1125
1126
1127
1128 if (newPath.startsWith(
".."_L1)) {
1129 newPath = QFileInfo(newPath).absoluteFilePath();
1134 std::unique_ptr<QDirPrivate> dir(
new QDirPrivate(*d_ptr.constData()));
1135 dir->setPath(newPath);
1139 d_ptr = dir.release();
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1158 return cd(QString::fromLatin1(
".."));
1162
1163
1164QStringList QDir::nameFilters()
const
1167 return d->nameFilters;
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185void QDir::setNameFilters(
const QStringList &nameFilters)
1188 d->clearCache(QDirPrivate::KeepMetaData);
1189 d->nameFilters = nameFilters;
1192#ifndef QT_BOOTSTRAPPED
1195struct DirSearchPaths {
1196 mutable QReadWriteLock mutex;
1197 QHash<QString, QStringList> paths;
1201Q_GLOBAL_STATIC(DirSearchPaths, dirSearchPaths)
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223void QDir::setSearchPaths(
const QString &prefix,
const QStringList &searchPaths)
1225 if (prefix.size() < 2) {
1226 qWarning(
"QDir::setSearchPaths: Prefix must be longer than 1 character");
1230 for (QChar ch : prefix) {
1231 if (!ch.isLetterOrNumber()) {
1232 qWarning(
"QDir::setSearchPaths: Prefix can only contain letters or numbers");
1237 DirSearchPaths &conf = *dirSearchPaths;
1238 const QWriteLocker lock(&conf.mutex);
1239 if (searchPaths.isEmpty()) {
1240 conf.paths.remove(prefix);
1242 conf.paths.insert(prefix, searchPaths);
1247
1248
1249
1250
1251
1252
1253void QDir::addSearchPath(
const QString &prefix,
const QString &path)
1258 DirSearchPaths &conf = *dirSearchPaths;
1259 const QWriteLocker lock(&conf.mutex);
1260 conf.paths[prefix] += path;
1264
1265
1266
1267
1268
1269
1270QStringList QDir::searchPaths(
const QString &prefix)
1272 if (!dirSearchPaths.exists())
1273 return QStringList();
1275 const DirSearchPaths &conf = *dirSearchPaths;
1276 const QReadLocker lock(&conf.mutex);
1277 return conf.paths.value(prefix);
1283
1284
1285QDir::Filters QDir::filter()
const
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
1352
1353
1356
1357
1358
1359
1360
1361
1362
1363void QDir::setFilter(Filters filters)
1366 d->clearCache(QDirPrivate::KeepMetaData);
1367 d->filters = filters;
1371
1372
1373
1374
1375QDir::SortFlags QDir::sorting()
const
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
1407
1408
1410#ifndef QT_BOOTSTRAPPED
1412
1413
1414
1415
1416
1417
1418
1419void QDir::setSorting(SortFlags sort)
1422 d->clearCache(QDirPrivate::KeepMetaData);
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436qsizetype QDir::count(QT6_IMPL_NEW_OVERLOAD)
const
1439 d->initFileLists(*
this);
1440 return d->fileCache.files.size();
1444
1445
1446
1447
1448
1449
1450
1451
1452QString QDir::operator[](qsizetype pos)
const
1455 d->initFileLists(*
this);
1456 return d->fileCache.files[pos];
1460
1461
1462
1463
1464
1465
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488QStringList QDir::entryList(Filters filters, SortFlags sort)
const
1491 return entryList(d->nameFilters, filters, sort);
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort)
const
1516 return entryInfoList(d->nameFilters, filters, sort);
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537QStringList QDir::entryList(
const QStringList &nameFilters, Filters filters,
1538 SortFlags sort)
const
1542 if (filters == NoFilter)
1543 filters = d->filters;
1547 const bool needsSorting = (sort & QDir::SortByMask) != QDir::Unsorted;
1549 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1551 if (needsSorting || d->fileCache.fileListsInitialized) {
1552 d->initFileLists(*
this);
1553 return d->fileCache.files;
1557 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1558 QDirListing dirList(d->dirEntry.filePath(), nameFilters, flags);
1562 for (
const auto &dirEntry : dirList)
1563 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1564 d->sortFileList(sort, l, &ret,
nullptr);
1566 for (
const auto &dirEntry : dirList)
1567 ret.emplace_back(dirEntry.fileName());
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590QFileInfoList QDir::entryInfoList(
const QStringList &nameFilters, Filters filters,
1591 SortFlags sort)
const
1595 if (filters == NoFilter)
1596 filters = d->filters;
1600 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1601 d->initFileLists(*
this);
1602 return d->fileCache.fileInfos;
1606 const QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
1607 for (
const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, flags))
1608 appendIfMatchesNonDirListingFlags(dirEntry, filters, l);
1610 d->sortFileList(sort, l,
nullptr, &ret);
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
1648
1649
1650bool QDir::mkdir(
const QString &dirName, std::optional<QFile::Permissions> permissions)
const
1654 if (dirName.isEmpty()) {
1655 qWarning(
"QDir::mkdir: Empty or null file name");
1659 QString fn = filePath(dirName);
1661 return QFileSystemEngine::mkdir(QFileSystemEntry(fn), permissions);
1662 return d->fileEngine->mkdir(fn,
false, permissions);
1666
1667
1668
1669
1670
1671
1672
1673
1674bool QDir::rmdir(
const QString &dirName)
const
1678 if (dirName.isEmpty()) {
1679 qWarning(
"QDir::rmdir: Empty or null file name");
1683 QString fn = filePath(dirName);
1685 return QFileSystemEngine::rmdir(QFileSystemEntry(fn));
1687 return d->fileEngine->rmdir(fn,
false);
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715bool QDir::mkpath(
const QString &dirPath, std::optional<QFile::Permissions> permissions)
const
1719 if (dirPath.isEmpty()) {
1720 qWarning(
"QDir::mkpath: Empty or null file name");
1724 QString fn = filePath(dirPath);
1726 return QFileSystemEngine::mkpath(QFileSystemEntry(fn), permissions);
1727 return d->fileEngine->mkdir(fn,
true, permissions);
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741bool QDir::rmpath(
const QString &dirPath)
const
1745 if (dirPath.isEmpty()) {
1746 qWarning(
"QDir::rmpath: Empty or null file name");
1750 QString fn = filePath(dirPath);
1752 return QFileSystemEngine::rmpath(QFileSystemEntry(fn));
1753 return d->fileEngine->rmdir(fn,
true);
1756#ifndef QT_BOOTSTRAPPED
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777bool QDir::removeRecursively()
1779 if (!d_ptr->fileEngine && QFileSystemEngine::supportsRmdirRecursively()) {
1781 return QFileSystemEngine::rmdirRecursively(QFileSystemEntry(absolutePath()), error);
1784 if (!d_ptr->exists())
1793 bool success =
true;
1795 std::stack<DirInfo, std::vector<DirInfo>> dirsToRemove;
1796 dirsToRemove.push({absolutePath(),
false});
1798 while (!dirsToRemove.empty()) {
1799 auto &info = dirsToRemove.top();
1802 for (
const auto &dirEntry : QDirListing(info.path, QDirListing::IteratorFlag::IncludeHidden)) {
1803 const QString &filePath = dirEntry.filePath();
1804 if (dirEntry.isDir() && !dirEntry.isSymLink()) {
1805 dirsToRemove.push({filePath,
false});
1807 bool ok = QFile::remove(filePath);
1809 const QFile::Permissions permissions = QFile::permissions(filePath);
1810 if (!(permissions & QFile::WriteUser))
1811 ok = QFile::setPermissions(filePath, permissions | QFile::WriteUser)
1812 && QFile::remove(filePath);
1819 if (!rmdir(info.path))
1830
1831
1832
1833
1834
1835
1836
1837
1838bool QDir::isReadable()
const
1842 if (!d->fileEngine) {
1843 QMutexLocker locker(&d->fileCache.mutex);
1844 if (!d->fileCache.metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) {
1845 QFileSystemEngine::fillMetaData(d->dirEntry, d->fileCache.metaData,
1846 QFileSystemMetaData::UserReadPermission);
1848 return d->fileCache.metaData.permissions().testAnyFlag(QFile::ReadUser);
1851 const QAbstractFileEngine::FileFlags info =
1852 d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
1853 | QAbstractFileEngine::PermsMask);
1854 if (!(info & QAbstractFileEngine::DirectoryType))
1856 return info.testAnyFlag(QAbstractFileEngine::ReadUserPerm);
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870bool QDir::exists()
const
1872 return d_ptr->exists();
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887bool QDir::isRoot()
const
1889 if (!d_ptr->fileEngine)
1890 return d_ptr->dirEntry.isRoot();
1891 return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask).testAnyFlag(QAbstractFileEngine::RootFlag);
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928bool QDir::isRelative()
const
1930 if (!d_ptr->fileEngine)
1931 return d_ptr->dirEntry.isRelative();
1932 return d_ptr->fileEngine->isRelativePath();
1937
1938
1939
1940
1941
1942
1943bool QDir::makeAbsolute()
1946 std::unique_ptr<QDirPrivate> dir;
1947 if (!!d->fileEngine) {
1948 QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
1949 if (QDir::isRelativePath(absolutePath))
1952 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1953 dir->setPath(absolutePath);
1955 QString absoluteFilePath = d->resolveAbsoluteEntry();
1956 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1957 dir->setPath(absoluteFilePath);
1959 d_ptr = dir.release();
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1981 Qt::CaseSensitivity sensitive;
1982 if (!d->fileEngine || !other->fileEngine) {
1983 if (d->fileEngine.get() != other->fileEngine.get())
1986 QOrderedMutexLocker locker(&d->fileCache.mutex, &other->fileCache.mutex);
1987 const bool thisCaseSensitive = QFileSystemEngine::isCaseSensitive(d->dirEntry, d->fileCache.metaData);
1988 if (thisCaseSensitive != QFileSystemEngine::isCaseSensitive(other->dirEntry, other->fileCache.metaData))
1991 sensitive = thisCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
1993 if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
1995 sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1998 if (d->filters == other->filters
1999 && d->sort == other->sort
2000 && d->nameFilters == other->nameFilters) {
2003 if (d->dirEntry.filePath() == other->dirEntry.filePath())
2010 return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0;
2015 QString thisFilePath = d->resolveAbsoluteEntry();
2016 QString otherFilePath = other->resolveAbsoluteEntry();
2017 return thisFilePath.compare(otherFilePath, sensitive) == 0;
2024
2025
2026
2027QDir &QDir::operator=(
const QDir &dir)
2034
2035
2036
2037
2040
2041
2042
2043
2044
2045
2046
2047
2048
2051
2052
2053
2054
2055
2056bool QDir::remove(
const QString &fileName)
2058 if (fileName.isEmpty()) {
2059 qWarning(
"QDir::remove: Empty or null file name");
2062 return QFile::remove(filePath(fileName));
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081bool QDir::rename(
const QString &oldName,
const QString &newName)
2083 if (oldName.isEmpty() || newName.isEmpty()) {
2084 qWarning(
"QDir::rename: Empty or null file name(s)");
2088 QFile file(filePath(oldName));
2091 return file.rename(filePath(newName));
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104bool QDir::exists(
const QString &name)
const
2106 if (name.isEmpty()) {
2107 qWarning(
"QDir::exists: Empty or null file name");
2110 return QFileInfo::exists(filePath(name));
2113#ifndef QT_BOOTSTRAPPED
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127bool QDir::isEmpty(Filters filters)
const
2131 QDirListing::IteratorFlags flags = QDirPrivate::toDirListingFlags(filters);
2132 for (
const auto &dirEntry : QDirListing(d->dirEntry.filePath(), d->nameFilters, flags)) {
2133 if (QDirPrivate::checkNonDirListingFlags(dirEntry, filters))
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150QFileInfoList QDir::drives()
2152#ifdef QT_NO_FSFILEENGINE
2153 return QFileInfoList();
2155 return QFSFileEngine::drives();
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2175
2176
2177
2178
2179
2180
2181
2182
2185
2186
2187
2188
2189
2190
2191
2192
2193bool QDir::setCurrent(
const QString &path)
2195 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
2199
2200
2201
2202
2203
2204
2205
2206
2207
2210
2211
2212
2213
2214
2215
2216
2217QString QDir::currentPath()
2219 return QFileSystemEngine::currentPath().filePath();
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
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
2264
2265
2266QString QDir::homePath()
2268 return QFileSystemEngine::homePath();
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296QString QDir::tempPath()
2298 return QFileSystemEngine::tempPath();
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2315
2316
2317
2318
2319
2320
2321
2322QString QDir::rootPath()
2324 return QFileSystemEngine::rootPath();
2327#if QT_CONFIG(regularexpression)
2329
2330
2331
2332
2333
2334
2335
2336
2337bool QDir::match(
const QStringList &filters,
const QString &fileName)
2339 for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
2341 auto rx = QRegularExpression::fromWildcard(*sit, Qt::CaseInsensitive);
2342 if (rx.match(fileName).hasMatch())
2349
2350
2351
2352
2353
2354
2355
2356bool QDir::match(
const QString &filter,
const QString &fileName)
2358 return match(nameFiltersFromString(filter), fileName);
2363 QDirPrivate::PathNormalizations flags)
noexcept
2369 for (
bool lastWasSlash =
true; i < n; ++i) {
2370 if (lastWasSlash && in[i] == u'.') {
2371 if (i + 1 == n || in[i + 1] == u'/')
2373 if (in[i + 1] == u'.' && (i + 2 == n || in[i + 2] == u'/'))
2376 if (!isRemote && lastWasSlash && in[i] == u'/' && i > 0) {
2382 lastWasSlash = in[i] == u'/';
2389 const qsizetype prefixLength = rootLength(path, flags);
2390 qsizetype where = findStartOfNonNormalizedPath(path.constBegin(), prefixLength, path.size(), flags);
2391 return where == path.size();
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2419 const qsizetype prefixLength = rootLength(*path, flags);
2424 const QChar *in = path->constBegin();
2426 qsizetype n = path->size();
2427 qsizetype i = findStartOfNonNormalizedPath(in, prefixLength, n, flags);
2431 QChar *out = path->data();
2432 const QChar *start = out + prefixLength;
2433 const QChar *end = out + path->size();
2441 QString output = QStringView(path->constBegin(), out).toString();
2442 QStringView input(in, end);
2448 if (in[0] == u'/') {
2450 while (in < end && in[0] == u'/') {
2464 enum { Nothing, Dot, DotDot } type = Nothing;
2465 if (in[0] == u'.') {
2466 if (in + 1 == end || in[1] == u'/')
2468 else if (in[1] == u'.' && (in + 2 == end || in[2] == u'/'))
2471 if (type == Nothing) {
2473 while (in < end && in[0] != u'/')
2482 if (type == DotDot) {
2483 if (Q_UNLIKELY(out == start)) {
2490 if (in + 2 != end) {
2491 Q_ASSERT(in[2] == u'/');
2504 while (out > start && out[-1] != u'/')
2515 if (in != end && out > start && out[-1] == u'/')
2522 if (in != end && in[0] == u'/')
2524 while (prefixLength == 0 && in != end && in[0] == u'/')
2529 path->truncate(out - path->constBegin());
2530 if (!isRemote && path->isEmpty())
2534 return ok || prefixLength == 0;
2539 if (path->isEmpty())
2542 QString &ret = *path;
2543 ret = QDir::fromNativeSeparators(ret);
2544 bool ok = qt_normalizePathSegments(&ret, QDirPrivate::DefaultNormalization);
2547 if (ret.size() > 1 && ret.endsWith(u'/')) {
2548#if defined (Q_OS_WIN)
2549 if (!(ret.length() == 3 && ret.at(1) == u':'))
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569QString QDir::cleanPath(
const QString &path)
2577
2578
2579
2580
2581
2582
2583
2584
2585bool QDir::isRelativePath(
const QString &path)
2587 return QFileInfo(path).isRelative();
2591
2592
2593void QDir::refresh()
const
2595 QDirPrivate *d =
const_cast<QDir *>(
this)->d_func();
2596 d->clearCache(QDirPrivate::IncludingMetaData);
2600
2601
2602QDirPrivate* QDir::d_func()
2604 return d_ptr.data();
2608
2609
2610
2611
2612
2613
2614QStringList QDir::nameFiltersFromString(
const QString &nameFilter)
2616 return QDirPrivate::splitFilters(nameFilter);
2619#ifndef QT_NO_DEBUG_STREAM
2622 QDebugStateSaver save(debug);
2623 debug.resetFormat();
2625 if (filters == QDir::NoFilter) {
2626 flags <<
"NoFilter"_L1;
2628 if (filters & QDir::Dirs) flags <<
"Dirs"_L1;
2629 if (filters & QDir::AllDirs) flags <<
"AllDirs"_L1;
2630 if (filters & QDir::Files) flags <<
"Files"_L1;
2631 if (filters & QDir::Drives) flags <<
"Drives"_L1;
2632 if (filters & QDir::NoSymLinks) flags <<
"NoSymLinks"_L1;
2633 if (filters & QDir::NoDot) flags <<
"NoDot"_L1;
2634 if (filters & QDir::NoDotDot) flags <<
"NoDotDot"_L1;
2635 if ((filters & QDir::AllEntries) == QDir::AllEntries) flags <<
"AllEntries"_L1;
2636 if (filters & QDir::Readable) flags <<
"Readable"_L1;
2637 if (filters & QDir::Writable) flags <<
"Writable"_L1;
2638 if (filters & QDir::Executable) flags <<
"Executable"_L1;
2639 if (filters & QDir::Hidden) flags <<
"Hidden"_L1;
2640 if (filters & QDir::System) flags <<
"System"_L1;
2641 if (filters & QDir::CaseSensitive) flags <<
"CaseSensitive"_L1;
2643 debug.noquote() <<
"QDir::Filters(" << flags.join(u'|') <<
')';
2649 QDebugStateSaver save(debug);
2650 debug.resetFormat();
2651 if (sorting == QDir::NoSort) {
2652 debug <<
"QDir::SortFlags(NoSort)";
2655 if ((sorting & QDir::SortByMask) == QDir::Name) type =
"Name"_L1;
2656 if ((sorting & QDir::SortByMask) == QDir::Time) type =
"Time"_L1;
2657 if ((sorting & QDir::SortByMask) == QDir::Size) type =
"Size"_L1;
2658 if ((sorting & QDir::SortByMask) == QDir::Unsorted) type =
"Unsorted"_L1;
2661 if (sorting & QDir::DirsFirst) flags <<
"DirsFirst"_L1;
2662 if (sorting & QDir::DirsLast) flags <<
"DirsLast"_L1;
2663 if (sorting & QDir::IgnoreCase) flags <<
"IgnoreCase"_L1;
2664 if (sorting & QDir::LocaleAware) flags <<
"LocaleAware"_L1;
2665 if (sorting & QDir::Type) flags <<
"Type"_L1;
2666 debug.noquote() <<
"QDir::SortFlags(" << type <<
'|' << flags.join(u'|') <<
')';
2673 QDebugStateSaver save(debug);
2674 debug.resetFormat();
2675 debug <<
"QDir(" << dir.path() <<
", nameFilters = {"
2676 << dir.nameFilters().join(u',')
2687
2688
2689
2690
2691
2692
2693
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2719
2720
2721
2722
2724
2725
2726
2727
2729
2730
2731
2732
2733
2735
2736
2737
2738
2739
2741
2742
2743
2744
2745
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)