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()));
54 QFileInfo priorFile(fileName);
55 if (!priorFile.isWritable() && priorFile.exists()) {
56 setError(QFileDevice::WriteError,
57 QSaveFile::tr(
"Existing file %1 is not writable").arg(fileName));
58 writeError = QFileDevice::WriteError;
62 if (priorFile.isDir()) {
63 setError(QFileDevice::WriteError, QSaveFile::tr(
"Filename refers to a directory"));
64 writeError = QFileDevice::WriteError;
70 if (!finalPermissions && priorFile.exists())
71 finalPermissions = priorFile.permissions();
76 finalFileName = fileName;
77 if (priorFile.isSymLink()) {
79 while (--maxDepth && priorFile.isSymLink())
80 priorFile.setFile(priorFile.symLinkTarget());
82 finalFileName = priorFile.filePath();
85 auto openDirectly = [
this, mode]() {
86 fileEngine = QAbstractFileEngine::create(finalFileName);
87 if (fileEngine->open(mode | QIODevice::Unbuffered)) {
88 useTemporaryFile =
false;
94 const char *directWriteReason =
nullptr;
97 if (finalFileName == fileName && fileName.indexOf(u':', 2) > 1)
98 directWriteReason = QT_TRANSLATE_NOOP(
"QSaveFile",
"target is an Alternate Data Stream");
99#elif defined(Q_OS_ANDROID)
101 if (fileName.startsWith(
"content://"_L1))
102 directWriteReason = QT_TRANSLATE_NOOP(
"QSaveFile",
"target is a content:// virtual file");
105#if defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
106 !directWriteReason &&
108 priorFile.exists() && !priorFile.isFile()) {
109 directWriteReason = QT_TRANSLATE_NOOP(
"QSaveFile",
"target exists and is not a regular file");
111 if (directWriteReason) {
113 if (directWriteFallback) {
116 setError(fileEngine->error(), fileEngine->errorString());
119 setError(QFileDevice::OpenError,
120 QSaveFile::tr(
"QSaveFile cannot open '%1' "
121 "without direct write fallback enabled: %2.")
122 .arg(QDir::toNativeSeparators(fileName),
123 QSaveFile::tr(directWriteReason)));
128 fileEngine.reset(
new QTemporaryFileEngine(&finalFileName,
129 QTemporaryFileEngine::Win32NonShared));
135 if (!finalPermissions) {
136 Q_ASSERT(!priorFile.exists());
138 static_cast<QTemporaryFileEngine *>(fileEngine.get())->initialize(finalFileName, 0666);
139 if (fileEngine->open(mode | QIODevice::Unbuffered)) {
140 finalPermissions = QFileDevicePrivate::permissions();
143 fileEngine->remove();
148 static_cast<QTemporaryFileEngine *>(fileEngine.get())->initialize(finalFileName, 0600);
151 if (!fileEngine->open(mode | QIODevice::Unbuffered)) {
152 QFileDevice::FileError err = fileEngine->error();
154 if (directWriteFallback && err == QFileDevice::OpenError && errno == EACCES) {
157 err = fileEngine->error();
160 if (err == QFileDevice::UnspecifiedError)
161 err = QFileDevice::OpenError;
162 setError(err, fileEngine->errorString());
166 useTemporaryFile =
true;
170QFileDevice::Permissions QSaveFilePrivate::permissions()
const
172 if (finalPermissions)
173 return *finalPermissions;
174 return QFileDevicePrivate::permissions();
177bool QSaveFilePrivate::setPermissions(QFileDevice::Permissions perms)
179 finalPermissions = perms;
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
222
223
224
225QSaveFile::QSaveFile(QObject *parent)
226 : QFileDevice(*
new QSaveFilePrivate, parent)
231
232
233
234QSaveFile::QSaveFile(
const QString &name, QObject *parent)
235 : QFileDevice(*
new QSaveFilePrivate, parent)
242
243
244
245
246
247
250
251
252QSaveFile::~QSaveFile()
256 QFileDevice::close();
257 Q_ASSERT(d->fileEngine);
258 d->fileEngine->remove();
263
264
265
266
267
268QString QSaveFile::fileName()
const
270 return d_func()->fileName;
274
275
276
277
280
281
282
283
284
285void QSaveFile::setFileName(
const QString &name)
287 d_func()->fileName = name;
291
292
293
294
297
298
299
300
301
302
303
304
305
306
307
308bool QSaveFile::open(OpenMode mode)
312 qWarning(
"QSaveFile::open: File (%ls) already open", qUtf16Printable(fileName()));
318 return QFileDevice::open(mode);
322
323
324
325
326
327void QSaveFile::close()
329 qFatal(
"QSaveFile::close called");
333
334
335
336
337
338
339
340
343
344
345
346
347
350
351
352
353
354
355
356
357
358
359
360
361bool QSaveFile::commit()
368 qWarning(
"QSaveFile::commit: File (%ls) is not open", qUtf16Printable(fileName()));
371 if (d->finalPermissions)
372 d->QFileDevicePrivate::setPermissions(*d->finalPermissions);
373 QFileDevice::close();
375 const auto &fe = d->fileEngine;
382 if (d->error == QFileDevice::NoError)
383 d->error = d->writeError;
384 d->writeError = QFileDevice::NoError;
386 if (d->useTemporaryFile) {
387 if (d->error != QFileDevice::NoError) {
394 if (!fe->renameOverwrite(d->finalFileName)) {
395 d->setError(fe->error(), fe->errorString());
403 return d->error == QFileDevice::NoError;
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424void QSaveFile::cancelWriting()
429 d->setError(QFileDevice::WriteError, QSaveFile::tr(
"Writing canceled by application"));
430 d->writeError = QFileDevice::WriteError;
434
435
436qint64 QSaveFile::writeData(
const char *data, qint64 len)
439 if (d->writeError != QFileDevice::NoError)
442 const qint64 ret = QFileDevice::writeData(data, len);
444 if (d->error != QFileDevice::NoError)
445 d->writeError = d->error;
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473void QSaveFile::setDirectWriteFallback(
bool enabled)
476 d->directWriteFallback = enabled;
480
481
482
483
484
485bool QSaveFile::directWriteFallback()
const
487 Q_D(
const QSaveFile);
488 return d->directWriteFallback;
493#include "moc_qsavefile.cpp"