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
327
328bool QSaveFile::setPermissions(Permissions permissions)
331 d->finalPermissions = permissions;
336
337
338
339
340QFileDevice::Permissions QSaveFile::permissions()
const
342 if (d_func()->finalPermissions)
343 return *d_func()->finalPermissions;
344 return QFileDevice::permissions();
348
349
350
351
352
353
354
355
356
357
358
359bool QSaveFile::commit()
366 qWarning(
"QSaveFile::commit: File (%ls) is not open", qUtf16Printable(fileName()));
369 if (d->finalPermissions)
370 QFileDevice::setPermissions(*d->finalPermissions);
371 QFileDevice::close();
373 const auto &fe = d->fileEngine;
380 if (d->error == QFileDevice::NoError)
381 d->error = d->writeError;
382 d->writeError = QFileDevice::NoError;
384 if (d->useTemporaryFile) {
385 if (d->error != QFileDevice::NoError) {
392 if (!fe->renameOverwrite(d->finalFileName)) {
393 d->setError(fe->error(), fe->errorString());
401 return d->error == QFileDevice::NoError;
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422void QSaveFile::cancelWriting()
427 d->setError(QFileDevice::WriteError, QSaveFile::tr(
"Writing canceled by application"));
428 d->writeError = QFileDevice::WriteError;
432
433
434qint64 QSaveFile::writeData(
const char *data, qint64 len)
437 if (d->writeError != QFileDevice::NoError)
440 const qint64 ret = QFileDevice::writeData(data, len);
442 if (d->error != QFileDevice::NoError)
443 d->writeError = d->error;
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471void QSaveFile::setDirectWriteFallback(
bool enabled)
474 d->directWriteFallback = enabled;
478
479
480
481
482
483bool QSaveFile::directWriteFallback()
const
485 Q_D(
const QSaveFile);
486 return d->directWriteFallback;
491#include "moc_qsavefile.cpp"