7#if QT_CONFIG(temporaryfile)
9#include "qplatformdefs.h"
10#include "private/qsavefile_p.h"
12#include "qabstractfileengine_p.h"
14#include "qtemporaryfile.h"
15#include "private/qiodevice_p.h"
16#include "private/qtemporaryfile_p.h"
23using namespace Qt::StringLiterals;
25QSaveFilePrivate::QSaveFilePrivate()
26 : writeError(QFileDevice::NoError),
27 useTemporaryFile(
true),
28 directWriteFallback(
false)
32QSaveFilePrivate::~QSaveFilePrivate()
36bool QSaveFilePrivate::open(QIODevice::OpenMode mode)
38 writeError = QFileDevice::NoError;
39 if ((mode & (QIODevice::ReadOnly | QIODevice::WriteOnly)) == 0) {
40 qWarning(
"QSaveFile::open: Open mode not specified");
45 if (mode & (QIODevice::ReadOnly | QIODevice::Append | QIODevice::NewOnly
46 | QIODevice::ExistingOnly)) {
47 qWarning(
"QSaveFile::open: Unsupported open mode 0x%x", uint(mode.toInt()));
52 QFileInfo priorFile(fileName);
53 if (!priorFile.isWritable() && priorFile.exists()) {
54 setError(QFileDevice::WriteError,
55 QSaveFile::tr(
"Existing file %1 is not writable").arg(fileName));
56 writeError = QFileDevice::WriteError;
60 if (priorFile.isDir()) {
61 setError(QFileDevice::WriteError, QSaveFile::tr(
"Filename refers to a directory"));
62 writeError = QFileDevice::WriteError;
68 if (!finalPermissions && priorFile.exists())
69 finalPermissions = priorFile.permissions();
74 finalFileName = fileName;
75 if (priorFile.isSymLink()) {
77 while (--maxDepth && priorFile.isSymLink())
78 priorFile.setFile(priorFile.symLinkTarget());
80 finalFileName = priorFile.filePath();
83 auto openDirectly = [
this, mode]() {
84 fileEngine = QAbstractFileEngine::create(finalFileName);
85 if (fileEngine->open(mode | QIODevice::Unbuffered)) {
86 useTemporaryFile =
false;
92 const char *directWriteReason =
nullptr;
95 if (finalFileName == fileName && fileName.indexOf(u':', 2) > 1)
96 directWriteReason = QT_TR_NOOP(
"target is an Alternate Data Stream");
97#elif defined(Q_OS_ANDROID)
99 if (fileName.startsWith(
"content://"_L1))
100 directWriteReason = QT_TR_NOOP(
"target is a content:// virtual file");
103#if defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
104 !directWriteReason &&
106 priorFile.exists() && !priorFile.isFile()) {
107 directWriteReason = QT_TR_NOOP(
"target exists and is not a regular file");
109 if (directWriteReason) {
111 if (directWriteFallback) {
114 setError(fileEngine->error(), fileEngine->errorString());
117 QString msg = QSaveFile::tr(
118 "QSaveFile cannot open '%1' without direct write fallback enabled: %2.")
119 .arg(QDir::toNativeSeparators(fileName)).arg(directWriteReason);
120 setError(QFileDevice::OpenError, msg);
125 fileEngine.reset(
new QTemporaryFileEngine(&finalFileName,
126 QTemporaryFileEngine::Win32NonShared));
132 if (!finalPermissions) {
133 Q_ASSERT(!priorFile.exists());
135 static_cast<QTemporaryFileEngine *>(fileEngine.get())->initialize(finalFileName, 0666);
136 if (fileEngine->open(mode | QIODevice::Unbuffered)) {
138 finalPermissions = q->QFileDevice::permissions();
141 fileEngine->remove();
146 static_cast<QTemporaryFileEngine *>(fileEngine.get())->initialize(finalFileName, 0600);
149 if (!fileEngine->open(mode | QIODevice::Unbuffered)) {
150 QFileDevice::FileError err = fileEngine->error();
152 if (directWriteFallback && err == QFileDevice::OpenError && errno == EACCES) {
155 err = fileEngine->error();
158 if (err == QFileDevice::UnspecifiedError)
159 err = QFileDevice::OpenError;
160 setError(err, fileEngine->errorString());
164 useTemporaryFile =
true;
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
207
208
209
210QSaveFile::QSaveFile(QObject *parent)
211 : QFileDevice(*
new QSaveFilePrivate, parent)
216
217
218
219QSaveFile::QSaveFile(
const QString &name, QObject *parent)
220 : QFileDevice(*
new QSaveFilePrivate, parent)
227
228
229
230
231
232
235
236
237QSaveFile::~QSaveFile()
241 QFileDevice::close();
242 Q_ASSERT(d->fileEngine);
243 d->fileEngine->remove();
248
249
250
251
252
253QString QSaveFile::fileName()
const
255 return d_func()->fileName;
259
260
261
262
265
266
267
268
269
270void QSaveFile::setFileName(
const QString &name)
272 d_func()->fileName = name;
276
277
278
279
282
283
284
285
286
287
288
289
290
291
292
293bool QSaveFile::open(OpenMode mode)
297 qWarning(
"QSaveFile::open: File (%ls) already open", qUtf16Printable(fileName()));
303 return QFileDevice::open(mode);
307
308
309
310
311
312void QSaveFile::close()
314 qFatal(
"QSaveFile::close called");
318
319
320
321
322
323
324bool QSaveFile::setPermissions(Permissions permissions)
327 d->finalPermissions = permissions;
332
333
334
335QFileDevice::Permissions QSaveFile::permissions()
const
337 if (d_func()->finalPermissions)
338 return *d_func()->finalPermissions;
339 return QFileDevice::permissions();
343
344
345
346
347
348
349
350
351
352
353
354bool QSaveFile::commit()
361 qWarning(
"QSaveFile::commit: File (%ls) is not open", qUtf16Printable(fileName()));
364 if (d->finalPermissions)
365 QFileDevice::setPermissions(*d->finalPermissions);
366 QFileDevice::close();
368 const auto &fe = d->fileEngine;
375 if (d->error == QFileDevice::NoError)
376 d->error = d->writeError;
377 d->writeError = QFileDevice::NoError;
379 if (d->useTemporaryFile) {
380 if (d->error != QFileDevice::NoError) {
387 if (!fe->renameOverwrite(d->finalFileName)) {
388 d->setError(fe->error(), fe->errorString());
396 return d->error == QFileDevice::NoError;
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417void QSaveFile::cancelWriting()
422 d->setError(QFileDevice::WriteError, QSaveFile::tr(
"Writing canceled by application"));
423 d->writeError = QFileDevice::WriteError;
427
428
429qint64 QSaveFile::writeData(
const char *data, qint64 len)
432 if (d->writeError != QFileDevice::NoError)
435 const qint64 ret = QFileDevice::writeData(data, len);
437 if (d->error != QFileDevice::NoError)
438 d->writeError = d->error;
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466void QSaveFile::setDirectWriteFallback(
bool enabled)
469 d->directWriteFallback = enabled;
473
474
475
476
477
478bool QSaveFile::directWriteFallback()
const
480 Q_D(
const QSaveFile);
481 return d->directWriteFallback;
486#include "moc_qsavefile.cpp"