6#include "qplatformdefs.h"
14#include "private/qiodevice_p.h"
15#include "private/qfile_p.h"
16#include "private/qfilesystemengine_p.h"
17#include "private/qsavefile_p.h"
18#include "private/qsystemerror_p.h"
19#include "private/qtemporaryfile_p.h"
20#if defined(QT_BUILD_CORE_LIB)
21# include "qcoreapplication.h"
25#define tr(X) QString::fromLatin1(X)
30using namespace Qt::StringLiterals;
35 qWarning(
"QFile::%s: File (%ls) already open", where ? where :
"open", qUtf16Printable(file.fileName()));
40QFilePrivate::QFilePrivate()
44QFilePrivate::~QFilePrivate()
49QFilePrivate::openExternalFile(QIODevice::OpenMode flags,
int fd, QFile::FileHandleFlags handleFlags)
51#ifdef QT_NO_FSFILEENGINE
56 auto fs = std::make_unique<QFSFileEngine>();
58 fileEngine = std::move(fs);
59 return fe->open(flags, fd, handleFlags);
64QFilePrivate::openExternalFile(QIODevice::OpenMode flags, FILE *fh, QFile::FileHandleFlags handleFlags)
66#ifdef QT_NO_FSFILEENGINE
71 auto fs = std::make_unique<QFSFileEngine>();
73 fileEngine = std::move(fs);
74 return fe->open(flags, fh, handleFlags);
78QAbstractFileEngine *QFilePrivate::engine()
const
81 fileEngine = QAbstractFileEngine::create(fileName);
82 return fileEngine.get();
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
232 : QFileDevice(*
new QFilePrivate)
235QFile::QFile(
const QString &name)
236 : QFileDevice(*
new QFilePrivate)
238 d_func()->fileName = name;
240QFile::QFile(QFilePrivate &dd)
246
247
249 : QFileDevice(*
new QFilePrivate,
nullptr)
253
254
255QFile::QFile(QObject *parent)
256 : QFileDevice(*
new QFilePrivate, parent)
260
261
262
263
264
265
266
267
268
269
270
271QFile::QFile(
const QString &name)
272 : QFileDevice(*
new QFilePrivate,
nullptr)
278
279
280
281QFile::QFile(
const QString &name, QObject *parent)
282 : QFileDevice(*
new QFilePrivate, parent)
288
289
290QFile::QFile(QFilePrivate &dd, QObject *parent)
291 : QFileDevice(dd, parent)
297
298
304
305
306
307
308
309QString QFile::fileName()
const
312 return d->engine()->fileName(QAbstractFileEngine::DefaultName);
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
334QFile::setFileName(
const QString &name)
338 file_already_open(*
this,
"setFileName");
341 d->fileEngine.reset();
346
347
348
349
350
351
352
355
356
357
358
359
360
361
362
363
366
367
368
369
370
371
374
375
376
377
378
379
380
387 return d->engine()->fileFlags(QAbstractFileEngine::FlagsMask
388 | QAbstractFileEngine::Refresh).testAnyFlag(QAbstractFileEngine::ExistsFlag);
392
393
394
395
396
397
400QFile::exists(
const QString &fileName)
402 return QFileInfo::exists(fileName);
406
407
408
409
410
411
412
413
414
415
416
417
418
419QString QFile::symLinkTarget()
const
422 return d->engine()->fileName(QAbstractFileEngine::AbsoluteLinkTarget);
426
427
428
429
430
431
432
433
434
435
436QString QFile::symLinkTarget(
const QString &fileName)
438 return QFileInfo(fileName).symLinkTarget();
442
443
444
445
446
447
448
449
450
456 if (d->fileName.isEmpty() &&
457 !
static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) {
458 qWarning(
"QFile::remove: Empty or null file name");
463 if (error() == QFile::NoError) {
464 if (d->engine()->remove()) {
468 d->setError(QFile::RemoveError, d->fileEngine->errorString());
474
475
476
477
478
479
480
481
482
485QFile::remove(
const QString &fileName)
487 return QFile(fileName).remove();
491
492
493
494
495
496
497
498
499
500
501bool QFile::supportsMoveToTrash()
503 return QFileSystemEngine::supportsMoveFileToTrash();
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
544 if (d->fileName.isEmpty() &&
545 !
static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) {
546 qWarning(
"QFile::remove: Empty or null file name");
551 if (error() == QFile::NoError) {
552 QFileSystemEntry fileEntry(d->fileName);
553 QFileSystemEntry trashEntry;
555 if (QFileSystemEngine::moveFileToTrash(fileEntry, trashEntry, error)) {
556 setFileName(trashEntry.filePath());
560 d->setError(QFile::RenameError, error.toString());
566
567
568
569
570
571
572
573
574
575
576
577
578
579
581QFile::moveToTrash(
const QString &fileName, QString *pathInTrash)
583 QFile file(fileName);
584 if (file.moveToTrash()) {
586 *pathInTrash = file.fileName();
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
610QFile::rename(
const QString &newName)
615 if (fileName().isEmpty()) {
616 qWarning(
"QFile::rename: Empty or null file name");
619 if (d->fileName == newName) {
620 d->setError(QFile::RenameError, tr(
"Destination file is the same file."));
624 d->setError(QFile::RenameError, tr(
"Source file does not exist."));
630 auto targetEngine = QFileSystemEngine::createLegacyEngine(newName);
635 bool changingCase =
false;
636 QByteArray targetId = QFileSystemEngine::id(QFileSystemEntry(newName));
637 if (!targetId.isNull()) {
638 QByteArray fileId = d->fileEngine ?
639 d->fileEngine->id() :
640 QFileSystemEngine::id(QFileSystemEntry(d->fileName));
641 changingCase = (fileId == targetId && d->fileName.compare(newName, Qt::CaseInsensitive) == 0);
643 d->setError(QFile::RenameError, tr(
"Destination file exists"));
647#if defined(Q_OS_LINUX) && QT_CONFIG(temporaryfile)
650 QTemporaryFileName tfn(d->fileName);
651 QFileSystemEntry src(d->fileName);
653 for (
int attempt = 0; attempt < 16; ++attempt) {
654 QFileSystemEntry tmp(tfn.generateNext(), QFileSystemEntry::FromNativePath());
657 if (!QFileSystemEngine::renameFile(src, tmp, error))
661 if (QFileSystemEngine::renameFile(tmp, QFileSystemEntry(newName), error)) {
662 d->fileEngine->setFileName(newName);
663 d->fileName = newName;
669 if (QFileSystemEngine::renameFile(tmp, src, error2))
673 d->setError(QFile::RenameError,
674 tr(
"Error while renaming: %1").arg(error.toString())
676 + tr(
"Unable to restore from %1: %2").
677 arg(QDir::toNativeSeparators(tmp.filePath()), error2.toString()));
680 d->setError(QFile::RenameError,
681 tr(
"Error while renaming: %1").arg(error.toString()));
687 if (error() == QFile::NoError) {
688 if (changingCase ? d->engine()->renameOverwrite(newName) : d->engine()->rename(newName)) {
691 d->fileEngine->setFileName(newName);
692 d->fileName = newName;
699 d->setError(QFile::RenameError, d->fileEngine->errorString());
703 if (isSequential()) {
704 d->setError(QFile::RenameError, tr(
"Will not rename sequential file using block copy"));
708#if QT_CONFIG(temporaryfile)
710 if (d->copy(newName, permissions())) {
713 d->setError(QFile::RenameError, tr(
"Cannot remove source file: %1").arg(errorString()));
716 out.setPermissions(ReadUser | WriteUser);
720 d->fileEngine->setFileName(newName);
722 setFileName(newName);
726 d->setError(QFile::RenameError, errorString());
730 d->setError(QFile::RenameError, d->fileEngine->errorString());
737
738
739
740
741
742
743
744
745
746
749QFile::rename(
const QString &oldName,
const QString &newName)
751 return QFile(oldName).rename(newName);
755
756
757
758
759
760
761
762
763
764
765
766
767
768
771QFile::link(
const QString &linkName)
774 if (fileName().isEmpty()) {
775 qWarning(
"QFile::link: Empty or null file name");
781 auto targetEngine = QFileSystemEngine::createLegacyEngine(linkName);
783 QFileInfo fi(linkName);
784 if (d->engine()->link(fi.absoluteFilePath())) {
788 d->setError(QFile::RenameError, d->fileEngine->errorString());
793
794
795
796
797
798
799
800
801
804QFile::link(
const QString &fileName,
const QString &linkName)
806 return QFile(fileName).link(linkName);
809#if QT_CONFIG(temporaryfile)
810bool QFilePrivate::copy(
const QString &newName, QFileDevice::Permissions permissions)
813 Q_ASSERT(error == QFile::NoError);
814 Q_ASSERT(!q->isOpen());
818 auto targetEngine = QFileSystemEngine::createLegacyEngine(newName);
822 if (engine()->copy(newName))
825 if (!q->open(QFile::ReadOnly | QFile::Unbuffered)) {
826 setError(QFile::CopyError, QFile::tr(
"Cannot open %1 for input").arg(fileName));
830 QSaveFile out(newName);
831 out.setDirectWriteFallback(
true);
832 if (!out.open(QIODevice::WriteOnly | QIODevice::Unbuffered)) {
834 setError(QFile::CopyError, QFile::tr(
"Cannot open for output: %1").arg(out.errorString()));
839 QAbstractFileEngine::TriStateResult r = engine()->cloneTo(out.d_func()->engine());
840 if (r == QAbstractFileEngine::TriStateResult::Failed) {
842 setError(QFile::CopyError, QFile::tr(
"Could not copy to %1: %2")
843 .arg(newName, engine()->errorString()));
847 while (r == QAbstractFileEngine::TriStateResult::NotSupported) {
851 qint64 in = q->read(block,
sizeof(block));
856 QString s = std::move(errorString);
858 setError(QFile::CopyError, std::move(s));
861 if (in != out.write(block, in)) {
863 setError(QFile::CopyError, QFile::tr(
"Failure to write block: %1")
864 .arg(out.errorString()));
870 out.setPermissions(permissions);
876 setError(out.error(), out.errorString());
881
882
883
884
885
886
887
888
891QFile::copy(
const QString &newName, std::optional<QFileDevice::Permissions> perm)
894 if (fileName().isEmpty()) {
895 qWarning(
"QFile::copy: Empty or null file name");
898 if (QFile::exists(newName)) {
902 d->setError(QFile::CopyError, tr(
"Destination file exists"));
907 if (error() == QFile::NoError)
908 return d->copy(newName, perm ? *perm : permissions());
913
914
915
916
917
918
919
920
923QFile::copy(
const QString &fileName,
const QString &newName,
924 std::optional<QFileDevice::Permissions> perm)
926 return QFile(fileName).copy(newName, perm);
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949bool QFile::open(OpenMode mode)
953 return file_already_open(*
this);
955 if (mode & (Append | NewOnly))
958 if ((mode & (ReadOnly | WriteOnly)) == 0) {
959 qWarning(
"QIODevice::open: File access not specified");
964 if (d->engine()->open(mode | QIODevice::Unbuffered)) {
965 QIODevice::open(mode);
970 QFile::FileError err = d->fileEngine->error();
971 if (err == QFile::UnspecifiedError)
972 err = QFile::OpenError;
973 d->setError(err, d->fileEngine->errorString());
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994bool QFile::open(OpenMode mode, QFile::Permissions permissions)
998 return file_already_open(*
this);
1000 if (mode & (Append | NewOnly))
1003 if ((mode & (ReadOnly | WriteOnly)) == 0) {
1004 qWarning(
"QIODevice::open: File access not specified");
1009 if (d->engine()->open(mode | QIODevice::Unbuffered, permissions)) {
1010 QIODevice::open(mode);
1015 QFile::FileError err = d->fileEngine->error();
1016 if (err == QFile::UnspecifiedError)
1017 err = QFile::OpenError;
1018 d->setError(err, d->fileEngine->errorString());
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
1068 return file_already_open(*
this);
1070 if (mode & (Append | NewOnly))
1073 if ((mode & (ReadOnly | WriteOnly)) == 0) {
1074 qWarning(
"QFile::open: File access not specified");
1079 if (d->openExternalFile(mode | Unbuffered, fh, handleFlags)) {
1080 QIODevice::open(mode);
1081 if (!(mode & Append) && !isSequential()) {
1082 qint64 pos = (qint64)QT_FTELL(fh);
1085 QIODevice::seek(pos);
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116bool QFile::open(
int fd, OpenMode mode, FileHandleFlags handleFlags)
1120 return file_already_open(*
this);
1122 if (mode & (Append | NewOnly))
1125 if ((mode & (ReadOnly | WriteOnly)) == 0) {
1126 qWarning(
"QFile::open: File access not specified");
1131 if (d->openExternalFile(mode | Unbuffered, fd, handleFlags)) {
1132 QIODevice::open(mode);
1133 if (!(mode & Append) && !isSequential()) {
1134 qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR);
1137 QIODevice::seek(pos);
1146
1147
1148bool QFile::resize(qint64 sz)
1150 return QFileDevice::resize(sz);
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1167QFile::resize(
const QString &fileName, qint64 sz)
1169 return QFile(fileName).resize(sz);
1173
1174
1175QFile::Permissions QFile::permissions()
const
1177 return QFileDevice::permissions();
1181
1182
1183
1184
1185
1188QFile::permissions(
const QString &fileName)
1190 return QFile(fileName).permissions();
1194
1195
1196
1197
1198
1199
1200
1201
1202
1204bool QFile::setPermissions(Permissions permissions)
1206 return QFileDevice::setPermissions(permissions);
1210
1211
1212
1213
1216QFile::setPermissions(
const QString &fileName, Permissions permissions)
1218 return QFile(fileName).setPermissions(permissions);
1222
1223
1224qint64 QFile::size()
const
1226 return QFileDevice::size();
1230
1231
1232
1233
1234
1235
1236
1238
1239
1240
1241
1242
1243
1245
1246
1247
1248
1250
1251
1252
1253
1255
1256
1257
1258
1260
1261
1262
1263
1265
1266
1267
1268
1270
1271
1272
1273
1275
1276
1277
1278
1280
1281
1282
1283
1285
1286
1287
1288
1290
1291
1292
1293
1295
1296
1297
1298
1300
1301
1302
1303
1305
1306
1307
1308
1310
1311
1312
1313
1315
1316
1317
1318
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
1360
1361
1362
1363
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1422#ifndef QT_NO_DEBUG_STREAM
1423void QFilePrivate::writeToDebugStream(QDebug &dbg)
const
1427 dbg <<
"QFile(" << q->fileName() <<
')';
1433#ifndef QT_NO_QOBJECT
1434#include "moc_qfile.cpp"
static Q_DECL_COLD_FUNCTION bool file_already_open(QFile &file, const char *where=nullptr)