diff options
author | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2013-01-11 17:30:44 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-05-07 22:43:14 +0200 |
commit | bbf1e1a66733dd95e34534bd6025fff8c0f3e4eb (patch) | |
tree | d0451060cf2876d56fe86b48569b99b975317150 /src/corelib/io/qfile.cpp | |
parent | a2a8a9ea0159cc6239737de2d745129f01c94d37 (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.cpp | 43 |
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(); |