4#include "qplatformdefs.h"
9#ifndef QT_NO_DEBUG_STREAM
15#if QT_CONFIG(regularexpression)
16# include <qregularexpression.h>
22#include <qstringbuilder.h>
24#ifndef QT_BOOTSTRAPPED
25# include <qcollator.h>
30#include <private/qorderedmutexlocker_p.h>
38using namespace Qt::StringLiterals;
41static QString driveSpec(
const QString &path)
45 char c = path.at(0).toLatin1();
46 if ((c <
'a' || c >
'z') && (c <
'A' || c >
'Z'))
48 if (path.at(1).toLatin1() !=
':')
50 return path.mid(0, 2);
57 constexpr bool UseWindowsRules =
false
62 const qsizetype len = name.size();
63 char16_t firstChar = len > 0 ? name.at(0).unicode() : u'\0';
64 char16_t secondChar = len > 1 ? name.at(1).unicode() : u'\0';
65 if constexpr (UseWindowsRules) {
68 if (firstChar == u'/' && secondChar == u'/' && !urlMode) {
70 const qsizetype nextSlash = name.indexOf(u'/', 2);
71 return nextSlash >= 0 ? nextSlash + 1 : len;
75 qsizetype driveLength = 2;
76 if (firstChar == u'/' && urlMode && len > 2 && name.at(2) == u':') {
81 if (secondChar == u':') {
82 if (len > driveLength && name.at(driveLength) == u'/')
83 return driveLength + 1;
88 return firstChar == u'/' ? 1 : 0;
92QDirPrivate::QDirPrivate(
const QString &path,
const QStringList &nameFilters_,
93 QDir::SortFlags sort_, QDir::Filters filters_)
94 : QSharedData(), nameFilters(nameFilters_), sort(sort_), filters(filters_)
96 setPath(path.isEmpty() ? QString::fromLatin1(
".") : path);
98 auto isEmpty = [](
const auto &e) {
return e.isEmpty(); };
99 const bool empty = std::all_of(nameFilters.cbegin(), nameFilters.cend(), isEmpty);
101 nameFilters = QStringList(QString::fromLatin1(
"*"));
114 fileCache.fileListsInitialized = copy.fileCache.fileListsInitialized.load();
115 fileCache.files = copy.fileCache.files;
116 fileCache.fileInfos = copy.fileCache.fileInfos;
117 fileCache.absoluteDirEntry = copy.fileCache.absoluteDirEntry;
118 fileCache.metaData = copy.fileCache.metaData;
125 QFileSystemEngine::fillMetaData(
126 dirEntry, fileCache.metaData,
127 QFileSystemMetaData::ExistsAttribute
128 | QFileSystemMetaData::DirectoryType);
129 return fileCache.metaData.exists() && fileCache.metaData.isDirectory();
131 const QAbstractFileEngine::FileFlags info =
132 fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
133 | QAbstractFileEngine::ExistsFlag
134 | QAbstractFileEngine::Refresh);
135 if (!(info & QAbstractFileEngine::DirectoryType))
137 return info.testAnyFlag(QAbstractFileEngine::ExistsFlag);
141inline QChar
QDirPrivate::getFilterSepChar(
const QString &nameFilter)
144 qsizetype i = nameFilter.indexOf(sep, 0);
145 if (i == -1 && nameFilter.indexOf(u' ', 0) != -1)
151inline QStringList
QDirPrivate::splitFilters(
const QString &nameFilter, QChar sep)
154 sep = getFilterSepChar(nameFilter);
156 for (
auto e : qTokenize(nameFilter, sep))
157 ret.append(e.trimmed().toString());
163 QString p = QDir::fromNativeSeparators(path);
167 && (!(p.length() == 3 && p.at(1).unicode() ==
':' && p.at(0).isLetter()))
170 p.truncate(p.size() - 1);
172 dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
174 fileCache.absoluteDirEntry = QFileSystemEntry();
180 if (!fileCache.absoluteDirEntry.isEmpty())
181 return fileCache.absoluteDirEntry.filePath();
183 if (dirEntry.isEmpty())
184 return dirEntry.filePath();
186 QString absoluteName;
188 if (!dirEntry.isRelative() && dirEntry.isClean()) {
189 fileCache.absoluteDirEntry = dirEntry;
190 return dirEntry.filePath();
193 absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath();
195 absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
197 auto absoluteFileSystemEntry =
198 QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
199 fileCache.absoluteDirEntry = absoluteFileSystemEntry;
200 return absoluteFileSystemEntry.filePath();
213 if (sort.testAnyFlag(QDir::Type))
214 suffix_cache = item.suffix();
224 QDir::SortFlags qt_cmp_si_sort_flags;
226#ifndef QT_BOOTSTRAPPED
227 QCollator *collator =
nullptr;
230#ifndef QT_BOOTSTRAPPED
234 Q_ASSERT(!qt_cmp_si_sort_flags.testAnyFlag(QDir::LocaleAware) || collator);
236 if (collator && qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase))
237 collator->setCaseSensitivity(Qt::CaseInsensitive);
247 int compareStrings(
const QString &a,
const QString &b, Qt::CaseSensitivity cs)
const
249#ifndef QT_BOOTSTRAPPED
251 return collator->compare(a, b);
253 return a.compare(b, cs);
262 if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir()))
263 return f1->item.isDir();
264 if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
265 return !f1->item.isDir();
267 const bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
268 const auto qtcase = ic ? Qt::CaseInsensitive : Qt::CaseSensitive;
271 int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask)
272 | (qt_cmp_si_sort_flags & QDir::Type)).toInt();
276 const QDateTime firstModified = f1->item.lastModified(QTimeZone::UTC);
277 const QDateTime secondModified = f2->item.lastModified(QTimeZone::UTC);
278 r = firstModified.msecsTo(secondModified);
282 r = f2->item.size() - f1->item.size();
285 r = compareStrings(f1->suffix_cache, f2->suffix_cache, qtcase);
291 if (r == 0 && sortBy != QDir::Unsorted) {
294 if (f1->filename_cache.isNull())
295 f1->filename_cache = f1->item.fileName();
296 if (f2->filename_cache.isNull())
297 f2->filename_cache = f2->item.fileName();
299 r = compareStrings(f1->filename_cache, f2->filename_cache, qtcase);
301 if (qt_cmp_si_sort_flags & QDir::Reversed)
306inline void QDirPrivate::sortFileList(QDir::SortFlags sort,
const QFileInfoList &l,
307 QStringList *names, QFileInfoList *infos)
309 Q_ASSERT(names || infos);
310 Q_ASSERT(!infos || infos->isEmpty());
311 Q_ASSERT(!names || names->isEmpty());
313 const qsizetype n = l.size();
317 if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
322 for (
const QFileInfo &fi : l)
323 names->append(fi.fileName());
328 for (qsizetype i = 0; i < n; ++i)
329 si.emplace_back(l.at(i), sort);
331#ifndef QT_BOOTSTRAPPED
332 if (sort.testAnyFlag(QDir::LocaleAware)) {
334 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort, &coll));
339 std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
343 for (qsizetype i = 0; i < n; ++i) {
344 auto &fileInfo = si[i].item;
346 infos->append(fileInfo);
348 const bool cached = !si[i].filename_cache.isNull();
349 names->append(cached ? si[i].filename_cache : fileInfo.fileName());
358 if (!fileCache.fileListsInitialized) {
360 for (
const auto &dirEntry : QDirListing(dir.path(), dir.nameFilters(),
361 dir.filter().toInt())) {
362 l.emplace_back(dirEntry.fileInfo());
365 sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos);
366 fileCache.fileListsInitialized =
true;
373 if (mode == IncludingMetaData)
374 fileCache.metaData.clear();
375 fileCache.fileListsInitialized =
false;
376 fileCache.files.clear();
377 fileCache.fileInfos.clear();
378 fileEngine = QFileSystemEngine::createLegacyEngine(dirEntry, fileCache.metaData);
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
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
567
568
569
570
571
572
575
576
577QDir::QDir(QDirPrivate &p) : d_ptr(&p)
582
583
584
585
586
587QDir::QDir(
const QString &path) : d_ptr(
new QDirPrivate(path))
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609QDir::QDir(
const QString &path,
const QString &nameFilter,
610 SortFlags sort, Filters filters)
611 : d_ptr(
new QDirPrivate(path, QDir::nameFiltersFromString(nameFilter), sort, filters))
616
617
618
619
620
621QDir::QDir(
const QDir &dir)
627
628
629
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650void QDir::setPath(
const QString &path)
652 d_ptr->setPath(path);
656
657
658
659
660
661
662
663
664
665QString QDir::path()
const
668 return d->dirEntry.filePath();
672
673
674
675
676
677
678
679QString QDir::absolutePath()
const
683 return d->resolveAbsoluteEntry();
685 return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704QString QDir::canonicalPath()
const
707 if (!d->fileEngine) {
708 QMutexLocker locker(&d->fileCache.mutex);
709 QFileSystemEntry answer =
710 QFileSystemEngine::canonicalName(d->dirEntry, d->fileCache.metaData);
711 return answer.filePath();
713 return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
717
718
719
720
721
722
723
724
725
726
727QString QDir::dirName()
const
730 if (!d_ptr->fileEngine)
731 return d->dirEntry.fileName();
732 return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
737static qsizetype drivePrefixLength(QStringView path)
740 const qsizetype size = path.size();
742 if (size > 1 && path.at(1).unicode() ==
':') {
743 if (Q_UNLIKELY(!path.at(0).isLetter()))
745 }
else if (path.startsWith(
"//"_L1)) {
748 for (
int i = 0 ; i < 2 ; ++i) {
749 while (drive < size && path.at(drive).unicode() ==
'/')
752 qWarning(
"Base directory starts with neither a drive nor a UNC share: %s",
753 qUtf8Printable(QDir::toNativeSeparators(path.toString())));
756 while (drive < size && path.at(drive).unicode() !=
'/')
777 return (path.contains(u':') && QFileInfo(path).isAbsolute())
778 || QFileSystemEntry(path).isAbsolute();
782
783
784
785
786
787
788
789
790QString QDir::filePath(
const QString &fileName)
const
792 if (treatAsAbsolute(fileName))
796 QString ret = d->dirEntry.filePath();
797 if (fileName.isEmpty())
801 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
803 const qsizetype drive = drivePrefixLength(ret);
804 return drive > 0 ? QStringView{ret}.left(drive) % fileName : fileName;
808 if (ret.isEmpty() || ret.endsWith(u'/'))
809 return ret % fileName;
810 return ret % u'/' % fileName;
814
815
816
817
818
819
820
821QString QDir::absoluteFilePath(
const QString &fileName)
const
823 if (treatAsAbsolute(fileName))
827 QString absoluteDirPath = d->resolveAbsoluteEntry();
828 if (fileName.isEmpty())
829 return absoluteDirPath;
832 if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
834 const qsizetype drive = drivePrefixLength(absoluteDirPath);
836 return QStringView{absoluteDirPath}.left(drive) % fileName;
838 qWarning(
"Base directory's drive is not a letter: %s",
839 qUtf8Printable(QDir::toNativeSeparators(absoluteDirPath)));
843 if (!absoluteDirPath.endsWith(u'/'))
844 return absoluteDirPath % u'/' % fileName;
845 return absoluteDirPath % fileName;
849
850
851
852
853
854
855QString QDir::relativeFilePath(
const QString &fileName)
const
857 QString dir = cleanPath(absolutePath());
858 QString file = cleanPath(fileName);
860 if (isRelativePath(file) || isRelativePath(dir))
864 QString dirDrive = driveSpec(dir);
865 QString fileDrive = driveSpec(file);
867 bool fileDriveMissing =
false;
868 if (fileDrive.isEmpty()) {
869 fileDrive = dirDrive;
870 fileDriveMissing =
true;
873 if (fileDrive.toLower() != dirDrive.toLower()
874 || (file.startsWith(
"//"_L1)
875 && !dir.startsWith(
"//"_L1))) {
879 dir.remove(0, dirDrive.size());
880 if (!fileDriveMissing)
881 file.remove(0, fileDrive.size());
885 const auto dirElts = dir.tokenize(u'/', Qt::SkipEmptyParts);
886 const auto fileElts = file.tokenize(u'/', Qt::SkipEmptyParts);
888 const auto dend = dirElts.end();
889 const auto fend = fileElts.end();
890 auto dit = dirElts.begin();
891 auto fit = fileElts.begin();
893 const auto eq = [](QStringView lhs, QStringView rhs) {
896 lhs.compare(rhs, Qt::CaseInsensitive) == 0;
903 while (dit != dend && fit != fend && eq(*dit, *fit)) {
908 while (dit != dend) {
914 while (fit != fend) {
921 if (result.isEmpty())
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941QString QDir::toNativeSeparators(
const QString &pathName)
944 qsizetype i = pathName.indexOf(u'/');
948 QChar *
const data = n.data();
951 for (; i < n.length(); ++i) {
963
964
965
966
967
968
969
970
971
972
973
974QString QDir::fromNativeSeparators(
const QString &pathName)
977 return QFileSystemEntry::removeUncOrLongPathPrefix(pathName).replace(u'\\', u'/');
986
987
988
989
990
991
992
993
994
995
996bool QDir::cd(
const QString &dirName)
999 const QDirPrivate *
const d = d_ptr.constData();
1001 if (dirName.isEmpty() || dirName == u'.')
1004 if (isAbsolutePath(dirName)) {
1006 qt_cleanPath(&newPath);
1008 newPath = d->dirEntry.filePath();
1009 if (!newPath.endsWith(u'/'))
1012 if (dirName.indexOf(u'/') >= 0
1013 || dirName ==
".."_L1
1014 || d->dirEntry.filePath() == u'.') {
1015 if (!qt_cleanPath(&newPath))
1018
1019
1020
1021
1022
1023
1024
1025 if (newPath.startsWith(
".."_L1)) {
1026 newPath = QFileInfo(newPath).absoluteFilePath();
1031 std::unique_ptr<QDirPrivate> dir(
new QDirPrivate(*d_ptr.constData()));
1032 dir->setPath(newPath);
1036 d_ptr = dir.release();
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1055 return cd(QString::fromLatin1(
".."));
1059
1060
1061QStringList QDir::nameFilters()
const
1064 return d->nameFilters;
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082void QDir::setNameFilters(
const QStringList &nameFilters)
1085 d->clearCache(QDirPrivate::KeepMetaData);
1086 d->nameFilters = nameFilters;
1089#ifndef QT_BOOTSTRAPPED
1092struct DirSearchPaths {
1093 mutable QReadWriteLock mutex;
1094 QHash<QString, QStringList> paths;
1098Q_GLOBAL_STATIC(DirSearchPaths, dirSearchPaths)
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120void QDir::setSearchPaths(
const QString &prefix,
const QStringList &searchPaths)
1122 if (prefix.size() < 2) {
1123 qWarning(
"QDir::setSearchPaths: Prefix must be longer than 1 character");
1127 for (QChar ch : prefix) {
1128 if (!ch.isLetterOrNumber()) {
1129 qWarning(
"QDir::setSearchPaths: Prefix can only contain letters or numbers");
1134 DirSearchPaths &conf = *dirSearchPaths;
1135 const QWriteLocker lock(&conf.mutex);
1136 if (searchPaths.isEmpty()) {
1137 conf.paths.remove(prefix);
1139 conf.paths.insert(prefix, searchPaths);
1144
1145
1146
1147
1148
1149
1150void QDir::addSearchPath(
const QString &prefix,
const QString &path)
1155 DirSearchPaths &conf = *dirSearchPaths;
1156 const QWriteLocker lock(&conf.mutex);
1157 conf.paths[prefix] += path;
1161
1162
1163
1164
1165
1166
1167QStringList QDir::searchPaths(
const QString &prefix)
1169 if (!dirSearchPaths.exists())
1170 return QStringList();
1172 const DirSearchPaths &conf = *dirSearchPaths;
1173 const QReadLocker lock(&conf.mutex);
1174 return conf.paths.value(prefix);
1180
1181
1182QDir::Filters QDir::filter()
const
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1254
1255
1256
1257
1258
1259
1260
1261void QDir::setFilter(Filters filters)
1264 d->clearCache(QDirPrivate::KeepMetaData);
1265 d->filters = filters;
1269
1270
1271
1272
1273QDir::SortFlags QDir::sorting()
const
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1308#ifndef QT_BOOTSTRAPPED
1310
1311
1312
1313
1314
1315
1316
1317void QDir::setSorting(SortFlags sort)
1320 d->clearCache(QDirPrivate::KeepMetaData);
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334qsizetype QDir::count(QT6_IMPL_NEW_OVERLOAD)
const
1337 d->initFileLists(*
this);
1338 return d->fileCache.files.size();
1342
1343
1344
1345
1346
1347
1348
1349
1350QString QDir::operator[](qsizetype pos)
const
1353 d->initFileLists(*
this);
1354 return d->fileCache.files[pos];
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376QStringList QDir::entryList(Filters filters, SortFlags sort)
const
1379 return entryList(d->nameFilters, filters, sort);
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort)
const
1402 return entryInfoList(d->nameFilters, filters, sort);
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421QStringList QDir::entryList(
const QStringList &nameFilters, Filters filters,
1422 SortFlags sort)
const
1426 if (filters == NoFilter)
1427 filters = d->filters;
1431 const bool needsSorting = (sort & QDir::SortByMask) != QDir::Unsorted;
1433 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1435 if (needsSorting || d->fileCache.fileListsInitialized) {
1436 d->initFileLists(*
this);
1437 return d->fileCache.files;
1441 QDirListing dirList(d->dirEntry.filePath(), nameFilters, filters.toInt());
1445 for (
const auto &dirEntry : dirList)
1446 l.emplace_back(dirEntry.fileInfo());
1447 d->sortFileList(sort, l, &ret,
nullptr);
1449 for (
const auto &dirEntry : dirList)
1450 ret.emplace_back(dirEntry.fileName());
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471QFileInfoList QDir::entryInfoList(
const QStringList &nameFilters, Filters filters,
1472 SortFlags sort)
const
1476 if (filters == NoFilter)
1477 filters = d->filters;
1481 if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1482 d->initFileLists(*
this);
1483 return d->fileCache.fileInfos;
1487 for (
const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, filters.toInt()))
1488 l.emplace_back(dirEntry.fileInfo());
1490 d->sortFileList(sort, l,
nullptr, &ret);
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530bool QDir::mkdir(
const QString &dirName, std::optional<QFile::Permissions> permissions)
const
1534 if (dirName.isEmpty()) {
1535 qWarning(
"QDir::mkdir: Empty or null file name");
1539 QString fn = filePath(dirName);
1541 return QFileSystemEngine::mkdir(QFileSystemEntry(fn), permissions);
1542 return d->fileEngine->mkdir(fn,
false, permissions);
1546
1547
1548
1549
1550
1551
1552
1553
1554bool QDir::rmdir(
const QString &dirName)
const
1558 if (dirName.isEmpty()) {
1559 qWarning(
"QDir::rmdir: Empty or null file name");
1563 QString fn = filePath(dirName);
1565 return QFileSystemEngine::rmdir(QFileSystemEntry(fn));
1567 return d->fileEngine->rmdir(fn,
false);
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595bool QDir::mkpath(
const QString &dirPath, std::optional<QFile::Permissions> permissions)
const
1599 if (dirPath.isEmpty()) {
1600 qWarning(
"QDir::mkpath: Empty or null file name");
1604 QString fn = filePath(dirPath);
1606 return QFileSystemEngine::mkpath(QFileSystemEntry(fn), permissions);
1607 return d->fileEngine->mkdir(fn,
true, permissions);
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621bool QDir::rmpath(
const QString &dirPath)
const
1625 if (dirPath.isEmpty()) {
1626 qWarning(
"QDir::rmpath: Empty or null file name");
1630 QString fn = filePath(dirPath);
1632 return QFileSystemEngine::rmpath(QFileSystemEntry(fn));
1633 return d->fileEngine->rmdir(fn,
true);
1636#ifndef QT_BOOTSTRAPPED
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657bool QDir::removeRecursively()
1659 if (!d_ptr->exists())
1662 bool success =
true;
1663 const QString dirPath = path();
1665 for (
const auto &dirEntry : QDirListing(dirPath, QDirListing::IteratorFlag::IncludeHidden)) {
1666 const QString &filePath = dirEntry.filePath();
1668 if (dirEntry.isDir() && !dirEntry.isSymLink()) {
1669 ok = QDir(filePath).removeRecursively();
1671 ok = QFile::remove(filePath);
1673 const QFile::Permissions permissions = QFile::permissions(filePath);
1674 if (!(permissions & QFile::WriteUser))
1675 ok = QFile::setPermissions(filePath, permissions | QFile::WriteUser)
1676 && QFile::remove(filePath);
1684 success = rmdir(absolutePath());
1691
1692
1693
1694
1695
1696
1697
1698
1699bool QDir::isReadable()
const
1703 if (!d->fileEngine) {
1704 QMutexLocker locker(&d->fileCache.mutex);
1705 if (!d->fileCache.metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) {
1706 QFileSystemEngine::fillMetaData(d->dirEntry, d->fileCache.metaData,
1707 QFileSystemMetaData::UserReadPermission);
1709 return d->fileCache.metaData.permissions().testAnyFlag(QFile::ReadUser);
1712 const QAbstractFileEngine::FileFlags info =
1713 d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
1714 | QAbstractFileEngine::PermsMask);
1715 if (!(info & QAbstractFileEngine::DirectoryType))
1717 return info.testAnyFlag(QAbstractFileEngine::ReadUserPerm);
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731bool QDir::exists()
const
1733 return d_ptr->exists();
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748bool QDir::isRoot()
const
1750 if (!d_ptr->fileEngine)
1751 return d_ptr->dirEntry.isRoot();
1752 return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask).testAnyFlag(QAbstractFileEngine::RootFlag);
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789bool QDir::isRelative()
const
1791 if (!d_ptr->fileEngine)
1792 return d_ptr->dirEntry.isRelative();
1793 return d_ptr->fileEngine->isRelativePath();
1798
1799
1800
1801
1802
1803
1804bool QDir::makeAbsolute()
1807 std::unique_ptr<QDirPrivate> dir;
1808 if (!!d->fileEngine) {
1809 QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
1810 if (QDir::isRelativePath(absolutePath))
1813 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1814 dir->setPath(absolutePath);
1816 QString absoluteFilePath = d->resolveAbsoluteEntry();
1817 dir.reset(
new QDirPrivate(*d_ptr.constData()));
1818 dir->setPath(absoluteFilePath);
1820 d_ptr = dir.release();
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1842 Qt::CaseSensitivity sensitive;
1843 if (!d->fileEngine || !other->fileEngine) {
1844 if (d->fileEngine.get() != other->fileEngine.get())
1847 QOrderedMutexLocker locker(&d->fileCache.mutex, &other->fileCache.mutex);
1848 const bool thisCaseSensitive = QFileSystemEngine::isCaseSensitive(d->dirEntry, d->fileCache.metaData);
1849 if (thisCaseSensitive != QFileSystemEngine::isCaseSensitive(other->dirEntry, other->fileCache.metaData))
1852 sensitive = thisCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
1854 if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
1856 sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1859 if (d->filters == other->filters
1860 && d->sort == other->sort
1861 && d->nameFilters == other->nameFilters) {
1864 if (d->dirEntry.filePath() == other->dirEntry.filePath())
1871 return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0;
1876 QString thisFilePath = d->resolveAbsoluteEntry();
1877 QString otherFilePath = other->resolveAbsoluteEntry();
1878 return thisFilePath.compare(otherFilePath, sensitive) == 0;
1885
1886
1887
1888QDir &QDir::operator=(
const QDir &dir)
1895
1896
1897
1898
1901
1902
1903
1904
1905
1906
1907
1908
1909
1912
1913
1914
1915
1916
1917bool QDir::remove(
const QString &fileName)
1919 if (fileName.isEmpty()) {
1920 qWarning(
"QDir::remove: Empty or null file name");
1923 return QFile::remove(filePath(fileName));
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942bool QDir::rename(
const QString &oldName,
const QString &newName)
1944 if (oldName.isEmpty() || newName.isEmpty()) {
1945 qWarning(
"QDir::rename: Empty or null file name(s)");
1949 QFile file(filePath(oldName));
1952 return file.rename(filePath(newName));
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965bool QDir::exists(
const QString &name)
const
1967 if (name.isEmpty()) {
1968 qWarning(
"QDir::exists: Empty or null file name");
1971 return QFileInfo::exists(filePath(name));
1974#ifndef QT_BOOTSTRAPPED
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988bool QDir::isEmpty(Filters filters)
const
1991 QDirListing dirList(d->dirEntry.filePath(), d->nameFilters, filters.toInt());
1992 return dirList.cbegin() == dirList.cend();
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006QFileInfoList QDir::drives()
2008#ifdef QT_NO_FSFILEENGINE
2009 return QFileInfoList();
2011 return QFSFileEngine::drives();
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2031
2032
2033
2034
2035
2036
2037
2038
2041
2042
2043
2044
2045
2046
2047
2048
2049bool QDir::setCurrent(
const QString &path)
2051 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
2055
2056
2057
2058
2059
2060
2061
2062
2063
2066
2067
2068
2069
2070
2071
2072
2073QString QDir::currentPath()
2075 return QFileSystemEngine::currentPath().filePath();
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122QString QDir::homePath()
2124 return QFileSystemEngine::homePath();
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152QString QDir::tempPath()
2154 return QFileSystemEngine::tempPath();
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2171
2172
2173
2174
2175
2176
2177
2178QString QDir::rootPath()
2180 return QFileSystemEngine::rootPath();
2183#if QT_CONFIG(regularexpression)
2185
2186
2187
2188
2189
2190
2191
2192
2193bool QDir::match(
const QStringList &filters,
const QString &fileName)
2195 for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
2197 auto rx = QRegularExpression::fromWildcard(*sit, Qt::CaseInsensitive);
2198 if (rx.match(fileName).hasMatch())
2205
2206
2207
2208
2209
2210
2211
2212bool QDir::match(
const QString &filter,
const QString &fileName)
2214 return match(nameFiltersFromString(filter), fileName);
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2243 const qsizetype prefixLength = rootLength(*path, flags);
2248 const QChar *in = path->constBegin();
2253 qsizetype i = prefixLength;
2254 qsizetype n = path->size();
2255 for (
bool lastWasSlash =
true; i < n; ++i) {
2256 if (lastWasSlash && in[i] == u'.') {
2257 if (i + 1 == n || in[i + 1] == u'/')
2259 if (in[i + 1] == u'.' && (i + 2 == n || in[i + 2] == u'/'))
2262 if (!isRemote && lastWasSlash && in[i] == u'/' && i > 0) {
2268 lastWasSlash = in[i] == u'/';
2273 QChar *out = path->data();
2274 const QChar *start = out + prefixLength;
2275 const QChar *end = out + path->size();
2283 QString output = QStringView(path->constBegin(), out).toString();
2284 QStringView input(in, end);
2290 if (in[0] == u'/') {
2292 while (in < end && in[0] == u'/') {
2306 enum { Nothing, Dot, DotDot } type = Nothing;
2307 if (in[0] == u'.') {
2308 if (in + 1 == end || in[1] == u'/')
2310 else if (in[1] == u'.' && (in + 2 == end || in[2] == u'/'))
2313 if (type == Nothing) {
2315 while (in < end && in[0] != u'/')
2324 if (type == DotDot) {
2325 if (Q_UNLIKELY(out == start)) {
2332 if (in + 2 != end) {
2333 Q_ASSERT(in[2] == u'/');
2346 while (out > start && out[-1] != u'/')
2357 if (in != end && out > start && out[-1] == u'/')
2364 if (in != end && in[0] == u'/')
2366 while (prefixLength == 0 && in != end && in[0] == u'/')
2371 path->truncate(out - path->constBegin());
2372 if (!isRemote && path->isEmpty())
2376 return ok || prefixLength == 0;
2381 if (path->isEmpty())
2384 QString &ret = *path;
2385 ret = QDir::fromNativeSeparators(ret);
2386 bool ok = qt_normalizePathSegments(&ret, QDirPrivate::DefaultNormalization);
2389 if (ret.size() > 1 && ret.endsWith(u'/')) {
2390#if defined (Q_OS_WIN)
2391 if (!(ret.length() == 3 && ret.at(1) == u':'))
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411QString QDir::cleanPath(
const QString &path)
2419
2420
2421
2422
2423
2424
2425
2426
2427bool QDir::isRelativePath(
const QString &path)
2429 return QFileInfo(path).isRelative();
2433
2434
2435void QDir::refresh()
const
2437 QDirPrivate *d =
const_cast<QDir *>(
this)->d_func();
2438 d->clearCache(QDirPrivate::IncludingMetaData);
2442
2443
2444QDirPrivate* QDir::d_func()
2446 return d_ptr.data();
2450
2451
2452
2453
2454
2455
2456QStringList QDir::nameFiltersFromString(
const QString &nameFilter)
2458 return QDirPrivate::splitFilters(nameFilter);
2461#ifndef QT_NO_DEBUG_STREAM
2464 QDebugStateSaver save(debug);
2465 debug.resetFormat();
2467 if (filters == QDir::NoFilter) {
2468 flags <<
"NoFilter"_L1;
2470 if (filters & QDir::Dirs) flags <<
"Dirs"_L1;
2471 if (filters & QDir::AllDirs) flags <<
"AllDirs"_L1;
2472 if (filters & QDir::Files) flags <<
"Files"_L1;
2473 if (filters & QDir::Drives) flags <<
"Drives"_L1;
2474 if (filters & QDir::NoSymLinks) flags <<
"NoSymLinks"_L1;
2475 if (filters & QDir::NoDot) flags <<
"NoDot"_L1;
2476 if (filters & QDir::NoDotDot) flags <<
"NoDotDot"_L1;
2477 if ((filters & QDir::AllEntries) == QDir::AllEntries) flags <<
"AllEntries"_L1;
2478 if (filters & QDir::Readable) flags <<
"Readable"_L1;
2479 if (filters & QDir::Writable) flags <<
"Writable"_L1;
2480 if (filters & QDir::Executable) flags <<
"Executable"_L1;
2481 if (filters & QDir::Modified) flags <<
"Modified"_L1;
2482 if (filters & QDir::Hidden) flags <<
"Hidden"_L1;
2483 if (filters & QDir::System) flags <<
"System"_L1;
2484 if (filters & QDir::CaseSensitive) flags <<
"CaseSensitive"_L1;
2486 debug.noquote() <<
"QDir::Filters(" << flags.join(u'|') <<
')';
2492 QDebugStateSaver save(debug);
2493 debug.resetFormat();
2494 if (sorting == QDir::NoSort) {
2495 debug <<
"QDir::SortFlags(NoSort)";
2498 if ((sorting & QDir::SortByMask) == QDir::Name) type =
"Name"_L1;
2499 if ((sorting & QDir::SortByMask) == QDir::Time) type =
"Time"_L1;
2500 if ((sorting & QDir::SortByMask) == QDir::Size) type =
"Size"_L1;
2501 if ((sorting & QDir::SortByMask) == QDir::Unsorted) type =
"Unsorted"_L1;
2504 if (sorting & QDir::DirsFirst) flags <<
"DirsFirst"_L1;
2505 if (sorting & QDir::DirsLast) flags <<
"DirsLast"_L1;
2506 if (sorting & QDir::IgnoreCase) flags <<
"IgnoreCase"_L1;
2507 if (sorting & QDir::LocaleAware) flags <<
"LocaleAware"_L1;
2508 if (sorting & QDir::Type) flags <<
"Type"_L1;
2509 debug.noquote() <<
"QDir::SortFlags(" << type <<
'|' << flags.join(u'|') <<
')';
2516 QDebugStateSaver save(debug);
2517 debug.resetFormat();
2518 debug <<
"QDir(" << dir.path() <<
", nameFilters = {"
2519 << dir.nameFilters().join(u',')
2530
2531
2532
2533
2534
2535
2536
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2562
2563
2564
2565
2567
2568
2569
2570
2572
2573
2574
2575
2576
2578
2579
2580
2581
2582
2584
2585
2586
2587
2588
QDirPrivate(const QDirPrivate ©)
void clearCache(MetaDataClearing mode)
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
Combined button and popup list for selecting options.
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 comparesEqual(const QDir &lhs, const QDir &rhs)
static bool treatAsAbsolute(const QString &path)
bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
QDirSortItem(const QFileInfo &fi, QDir::SortFlags sort)