summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfile.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-06-29 20:13:44 -0700
committerThiago Macieira <thiago.macieira@intel.com>2017-08-04 17:30:07 +0000
commita06fb55dcb0820e078588c6a6d96c74b712dd380 (patch)
tree1548b642c4669d3cf44a53770d693ce064499dce /src/corelib/io/qfile.cpp
parent3d6cbe3409d52e5ca63b8d04261b8fd531d89c98 (diff)
QFile::rename: use QTemporaryFileName instead of QTemporaryFile
This means the workaround for Linux's behavior now works even if QTemporaryFile is disabled. We also avoid the creation of an otherwise unused temporary file just so we can take its name. Tested with tests/manual/filetest. Strace shows: renameat2(AT_FDCWD, "a", AT_FDCWD, "/var/run/media/tjmaciei/B852-6088/a.EBG705", RENAME_NOREPLACE) = 0 renameat2(AT_FDCWD, "/var/run/media/tjmaciei/B852-6088/a.EBG705", AT_FDCWD, "A", RENAME_NOREPLACE) = 0 Before it was: open("/var/run/media/tjmaciei/B852-6088/a.VuL412", O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, 0600) = 4 fcntl(4, F_SETFD, FD_CLOEXEC) = 0 lseek(4, 0, SEEK_SET) = 0 rename("a", "/var/run/media/tjmaciei/B852-6088/a.VuL412") = 0 stat("A", 0x7fff13260f00) = -1 ENOENT (No such file or directory) close(4) = 0 renameat2(AT_FDCWD, "/var/run/media/tjmaciei/B852-6088/a.VuL412", AT_FDCWD, "A", RENAME_NOREPLACE) = 0 (the absolute path comes from fd61059d359f0bee1c37d6bf08bf4b83381658ca and it seems it was needed for Symbian) Change-Id: I1eba2b016de74620bfc8fffd14ccc7c4ded009c8 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io/qfile.cpp')
-rw-r--r--src/corelib/io/qfile.cpp57
1 files changed, 33 insertions, 24 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index ce99ac96c0..c1d5abdf7b 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -49,6 +50,7 @@
#include "private/qfile_p.h"
#include "private/qfilesystemengine_p.h"
#include "private/qsystemerror_p.h"
+#include "private/qtemporaryfile_p.h"
#if defined(QT_BUILD_CORE_LIB)
# include "qcoreapplication.h"
#endif
@@ -581,37 +583,44 @@ QFile::rename(const QString &newName)
d->setError(QFile::RenameError, tr("Destination file exists"));
return false;
}
-#ifndef QT_NO_TEMPORARYFILE
- // This #ifndef disables the workaround it encloses. Therefore, this configuration is not recommended.
+
#ifdef Q_OS_LINUX
// rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive
// FS, such as FAT32. Move the file away and rename in 2 steps to work around.
- QTemporaryFile tempFile(d->fileName + QLatin1String(".XXXXXX"));
- tempFile.setAutoRemove(false);
- if (!tempFile.open(QIODevice::ReadWrite)) {
- d->setError(QFile::RenameError, tempFile.errorString());
- return false;
- }
- tempFile.close();
- if (!d->engine()->renameOverwrite(tempFile.fileName())) {
- d->setError(QFile::RenameError, tr("Error while renaming."));
- return false;
- }
- if (tempFile.rename(newName)) {
- d->fileEngine->setFileName(newName);
- d->fileName = newName;
- return true;
- }
- d->setError(QFile::RenameError, tempFile.errorString());
- // We need to restore the original file.
- if (!tempFile.rename(d->fileName)) {
- d->setError(QFile::RenameError, errorString() + QLatin1Char('\n')
+ QTemporaryFileName tfn(d->fileName);
+ QFileSystemEntry src(d->fileName);
+ QSystemError error;
+ for (int attempt = 0; attempt < 16; ++attempt) {
+ QFileSystemEntry tmp(tfn.generateNext(), QFileSystemEntry::FromNativePath());
+
+ // rename to temporary name
+ if (!QFileSystemEngine::renameFile(src, tmp, error))
+ continue;
+
+ // rename to final name
+ if (QFileSystemEngine::renameFile(tmp, QFileSystemEntry(newName), error)) {
+ d->fileEngine->setFileName(newName);
+ d->fileName = newName;
+ return true;
+ }
+
+ // We need to restore the original file.
+ QSystemError error2;
+ if (QFileSystemEngine::renameFile(tmp, src, error2))
+ break; // report the original error, below
+
+ // report both errors
+ d->setError(QFile::RenameError,
+ tr("Error while renaming: %1").arg(error.toString())
+ + QLatin1Char('\n')
+ tr("Unable to restore from %1: %2").
- arg(QDir::toNativeSeparators(tempFile.fileName()), tempFile.errorString()));
+ arg(QDir::toNativeSeparators(tmp.filePath()), error2.toString()));
+ return false;
}
+ d->setError(QFile::RenameError,
+ tr("Error while renaming: %1").arg(error.toString()));
return false;
#endif // Q_OS_LINUX
-#endif // QT_NO_TEMPORARYFILE
}
unsetError();
close();