summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfile.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@digia.com>2013-01-11 17:30:44 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-05-07 22:43:14 +0200
commitbbf1e1a66733dd95e34534bd6025fff8c0f3e4eb (patch)
treed0451060cf2876d56fe86b48569b99b975317150 /src/corelib/io/qfile.cpp
parenta2a8a9ea0159cc6239737de2d745129f01c94d37 (diff)
Add workaround for case-changing renaming of files on Linux/FAT32.
The underlying rename() of the operating system simply does nothing when renaming 'foo' to 'Foo' in a case insensitive file system. Work around by moving in 2 steps. Change-Id: Ibc73724bfca402a5ce7fcf2a83e8fea32ff71093 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com> Reviewed-by: David Faure (KDE) <faure@kde.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io/qfile.cpp')
-rw-r--r--src/corelib/io/qfile.cpp43
1 files changed, 36 insertions, 7 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index afa62a075f..e46ba28f47 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -559,14 +559,43 @@ QFile::rename(const QString &newName)
}
// If the file exists and it is a case-changing rename ("foo" -> "Foo"),
// compare Ids to make sure it really is a different file.
- if (QFile::exists(newName)
- && (d->fileName.compare(newName, Qt::CaseInsensitive)
- || QFileSystemEngine::id(QFileSystemEntry(d->fileName)) != QFileSystemEngine::id(QFileSystemEntry(newName)))) {
- // ### Race condition. If a file is moved in after this, it /will/ be
- // overwritten. On Unix, the proper solution is to use hardlinks:
- // return ::link(old, new) && ::remove(old);
- d->setError(QFile::RenameError, tr("Destination file exists"));
+ if (QFile::exists(newName)) {
+ if (d->fileName.compare(newName, Qt::CaseInsensitive)
+ || QFileSystemEngine::id(QFileSystemEntry(d->fileName)) != QFileSystemEngine::id(QFileSystemEntry(newName))) {
+ // ### Race condition. If a file is moved in after this, it /will/ be
+ // overwritten. On Unix, the proper solution is to use hardlinks:
+ // return ::link(old, new) && ::remove(old);
+ d->setError(QFile::RenameError, tr("Destination file exists"));
+ return false;
+ }
+#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 + QStringLiteral(".XXXXXX"));
+ tempFile.setAutoRemove(false);
+ if (!tempFile.open(QIODevice::ReadWrite)) {
+ d->setError(QFile::RenameError, tempFile.errorString());
+ return false;
+ }
+ tempFile.close();
+ if (!d->engine()->rename(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')
+ + tr("Unable to restore from %1: %2").
+ arg(QDir::toNativeSeparators(tempFile.fileName()), tempFile.errorString()));
+ }
return false;
+#endif
}
unsetError();
close();