7#if QT_CONFIG(temporaryfile)
9#include "qplatformdefs.h"
10#include "private/qsavefile_p.h"
12#include "qabstractfileengine_p.h"
13#include <QtCore/qcoreapplication.h>
15#include "qtemporaryfile.h"
16#include <QtCore/qttranslation.h>
17#include "private/qiodevice_p.h"
18#include "private/qtemporaryfile_p.h"
25using namespace Qt::StringLiterals;
27QSaveFilePrivate::QSaveFilePrivate()
28 : writeError(QFileDevice::NoError),
29 useTemporaryFile(
true),
30 directWriteFallback(
false)
34QSaveFilePrivate::~QSaveFilePrivate()
38bool QSaveFilePrivate::open(QIODevice::OpenMode mode)
40 writeError = QFileDevice::NoError;
41 if ((mode & (QIODevice::ReadOnly | QIODevice::WriteOnly)) == 0) {
42 qWarning(
"QSaveFile::open: Open mode not specified");
47 if (mode & (QIODevice::ReadOnly | QIODevice::Append | QIODevice::NewOnly
48 | QIODevice::ExistingOnly)) {
49 qWarning(
"QSaveFile::open: Unsupported open mode 0x%x", uint(mode.toInt()));
53 QFileInfo priorFile(fileName);
59 QFile::Permissions perms = priorFile.permissions();
67 if (!finalPermissions)
68 finalPermissions = perms;
70 exists = priorFile.exists();
75 if (exists && !perms.testAnyFlag(QFile::WriteUser)) {
76 setError(QFileDevice::WriteError,
77 QSaveFile::tr(
"Existing file %1 is not writable").arg(fileName));
78 writeError = QFileDevice::WriteError;
83 if (priorFile.isDir()) {
84 setError(QFileDevice::WriteError, QSaveFile::tr(
"Filename refers to a directory"));
85 writeError = QFileDevice::WriteError;
91 finalFileName = fileName;
92 if (priorFile.isSymLink()) {
94 for (QString target; maxDepth; --maxDepth) {
95 target = priorFile.symLinkTarget();
98 priorFile.setFile(target);
101 finalFileName = priorFile.filePath();
104 auto openDirectly = [
this, mode]() {
105 fileEngine = QAbstractFileEngine::create(finalFileName);
106 if (fileEngine->open(mode | QIODevice::Unbuffered)) {
107 useTemporaryFile =
false;
113 const char *directWriteReason =
nullptr;
116 if (finalFileName == fileName && fileName.indexOf(u':', 2) > 1)
117 directWriteReason = QT_TRANSLATE_NOOP(
"QSaveFile",
"target is an Alternate Data Stream");
118#elif defined(Q_OS_ANDROID)
120 if (fileName.startsWith(
"content://"_L1))
121 directWriteReason = QT_TRANSLATE_NOOP(
"QSaveFile",
"target is a content:// virtual file");
124#if defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
125 !directWriteReason &&
127 priorFile.exists() && !priorFile.isFile()) {
128 directWriteReason = QT_TRANSLATE_NOOP(
"QSaveFile",
"target exists and is not a regular file");
130 if (directWriteReason) {
132 if (directWriteFallback) {
135 setError(fileEngine->error(), fileEngine->errorString());
138 setError(QFileDevice::OpenError,
139 QSaveFile::tr(
"QSaveFile cannot open '%1' "
140 "without direct write fallback enabled: %2.")
141 .arg(QDir::toNativeSeparators(fileName),
142 QSaveFile::tr(directWriteReason)));
147 fileEngine.reset(
new QTemporaryFileEngine(&finalFileName,
148 QTemporaryFileEngine::Win32NonShared));
154 if (!finalPermissions && QTemporaryFileEngine::CreatesWithFileMode) {
155 Q_ASSERT(!priorFile.exists());
157 static_cast<QTemporaryFileEngine *>(fileEngine.get())->initialize(finalFileName, 0666);
158 if (fileEngine->open(mode | QIODevice::Unbuffered)) {
159 finalPermissions = QFileDevicePrivate::permissions();
162 fileEngine->remove();
167 static_cast<QTemporaryFileEngine *>(fileEngine.get())->initialize(finalFileName, 0600);
170 if (!fileEngine->open(mode | QIODevice::Unbuffered)) {
171 QFileDevice::FileError err = fileEngine->error();
173 if (directWriteFallback && err == QFileDevice::OpenError && errno == EACCES) {
176 err = fileEngine->error();
179 if (err == QFileDevice::UnspecifiedError)
180 err = QFileDevice::OpenError;
181 setError(err, fileEngine->errorString());
185 useTemporaryFile =
true;
189QFileDevice::Permissions QSaveFilePrivate::permissions()
const
191 if (finalPermissions)
192 return *finalPermissions;
193 return QFileDevicePrivate::permissions();
196bool QSaveFilePrivate::setPermissions(QFileDevice::Permissions perms)
198 finalPermissions = perms;
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
229
230
231
232
233
234
235
236
237
238
241
242
243
244QSaveFile::QSaveFile(QObject *parent)
245 : QFileDevice(*
new QSaveFilePrivate, parent)
250
251
252
253QSaveFile::QSaveFile(
const QString &name, QObject *parent)
254 : QFileDevice(*
new QSaveFilePrivate, parent)
261
262
263
264
265
266
269
270
271QSaveFile::~QSaveFile()
275 QFileDevice::close();
276 Q_ASSERT(d->fileEngine);
277 d->fileEngine->remove();
282
283
284
285
286
287QString QSaveFile::fileName()
const
289 return d_func()->fileName;
293
294
295
296
299
300
301
302
303
304void QSaveFile::setFileName(
const QString &name)
306 d_func()->fileName = name;
310
311
312
313
316
317
318
319
320
321
322
323
324
325
326
327bool QSaveFile::open(OpenMode mode)
331 qWarning(
"QSaveFile::open: File (%ls) already open", qUtf16Printable(fileName()));
337 return QFileDevice::open(mode);
341
342
343
344
345
346void QSaveFile::close()
348 qFatal(
"QSaveFile::close called");
352
353
354
355
356
357
358
359
362
363
364
365
366
369
370
371
372
373
374
375
376
377
378
379
380bool QSaveFile::commit()
387 qWarning(
"QSaveFile::commit: File (%ls) is not open", qUtf16Printable(fileName()));
390 if (d->finalPermissions)
391 d->QFileDevicePrivate::setPermissions(*d->finalPermissions);
392 QFileDevice::close();
394 const auto &fe = d->fileEngine;
401 if (d->error == QFileDevice::NoError)
402 d->error = d->writeError;
403 d->writeError = QFileDevice::NoError;
405 if (d->useTemporaryFile) {
406 if (d->error != QFileDevice::NoError) {
413 if (!fe->renameOverwrite(d->finalFileName)) {
414 d->setError(fe->error(), fe->errorString());
422 return d->error == QFileDevice::NoError;
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443void QSaveFile::cancelWriting()
448 d->setError(QFileDevice::WriteError, QSaveFile::tr(
"Writing canceled by application"));
449 d->writeError = QFileDevice::WriteError;
453
454
455qint64 QSaveFile::writeData(
const char *data, qint64 len)
458 if (d->writeError != QFileDevice::NoError)
461 const qint64 ret = QFileDevice::writeData(data, len);
463 if (d->error != QFileDevice::NoError)
464 d->writeError = d->error;
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492void QSaveFile::setDirectWriteFallback(
bool enabled)
495 d->directWriteFallback = enabled;
499
500
501
502
503
504bool QSaveFile::directWriteFallback()
const
506 Q_D(
const QSaveFile);
507 return d->directWriteFallback;
512#include "moc_qsavefile.cpp"