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)) {
141 finalPermissions = q->QFileDevice::permissions();
144 fileEngine->remove();
149 static_cast<QTemporaryFileEngine *>(fileEngine.get())->initialize(finalFileName, 0600);
152 if (!fileEngine->open(mode | QIODevice::Unbuffered)) {
153 QFileDevice::FileError err = fileEngine->error();
155 if (directWriteFallback && err == QFileDevice::OpenError && errno == EACCES) {
158 err = fileEngine->error();
161 if (err == QFileDevice::UnspecifiedError)
162 err = QFileDevice::OpenError;
163 setError(err, fileEngine->errorString());
167 useTemporaryFile =
true;
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
210
211
212
213QSaveFile::QSaveFile(QObject *parent)
214 : QFileDevice(*
new QSaveFilePrivate, parent)
219
220
221
222QSaveFile::QSaveFile(
const QString &name, QObject *parent)
223 : QFileDevice(*
new QSaveFilePrivate, parent)
230
231
232
233
234
235
238
239
240QSaveFile::~QSaveFile()
244 QFileDevice::close();
245 Q_ASSERT(d->fileEngine);
246 d->fileEngine->remove();
251
252
253
254
255
256QString QSaveFile::fileName()
const
258 return d_func()->fileName;
262
263
264
265
268
269
270
271
272
273void QSaveFile::setFileName(
const QString &name)
275 d_func()->fileName = name;
279
280
281
282
285
286
287
288
289
290
291
292
293
294
295
296bool QSaveFile::open(OpenMode mode)
300 qWarning(
"QSaveFile::open: File (%ls) already open", qUtf16Printable(fileName()));
306 return QFileDevice::open(mode);
310
311
312
313
314
315void QSaveFile::close()
317 qFatal(
"QSaveFile::close called");
321
322
323
324
325
326
327bool QSaveFile::setPermissions(Permissions permissions)
330 d->finalPermissions = permissions;
335
336
337
338QFileDevice::Permissions QSaveFile::permissions()
const
340 if (d_func()->finalPermissions)
341 return *d_func()->finalPermissions;
342 return QFileDevice::permissions();
346
347
348
349
350
351
352
353
354
355
356
357bool QSaveFile::commit()
364 qWarning(
"QSaveFile::commit: File (%ls) is not open", qUtf16Printable(fileName()));
367 if (d->finalPermissions)
368 QFileDevice::setPermissions(*d->finalPermissions);
369 QFileDevice::close();
371 const auto &fe = d->fileEngine;
378 if (d->error == QFileDevice::NoError)
379 d->error = d->writeError;
380 d->writeError = QFileDevice::NoError;
382 if (d->useTemporaryFile) {
383 if (d->error != QFileDevice::NoError) {
390 if (!fe->renameOverwrite(d->finalFileName)) {
391 d->setError(fe->error(), fe->errorString());
399 return d->error == QFileDevice::NoError;
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420void QSaveFile::cancelWriting()
425 d->setError(QFileDevice::WriteError, QSaveFile::tr(
"Writing canceled by application"));
426 d->writeError = QFileDevice::WriteError;
430
431
432qint64 QSaveFile::writeData(
const char *data, qint64 len)
435 if (d->writeError != QFileDevice::NoError)
438 const qint64 ret = QFileDevice::writeData(data, len);
440 if (d->error != QFileDevice::NoError)
441 d->writeError = d->error;
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469void QSaveFile::setDirectWriteFallback(
bool enabled)
472 d->directWriteFallback = enabled;
476
477
478
479
480
481bool QSaveFile::directWriteFallback()
const
483 Q_D(
const QSaveFile);
484 return d->directWriteFallback;
489#include "moc_qsavefile.cpp"