From fd95ef765afa3b0fd9996a31546d098465b927fe Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 29 Jun 2017 12:35:01 -0700 Subject: QFile::rename: avoid two stat(2)/CreateFile in a row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QFileSystemEngine::id() will stat(2)/CreateFile in order to get the ID of the file anyway, so we don't need to use QFile::exists() to check if the destination exists. Instead, rely on id() returning a null value to indicate error. On Windows, it's possible that the calls to either GetFileInformationByHandle or GetFileInformationByHandleEx might fail, but we ignore those. Change-Id: I1eba2b016de74620bfc8fffd14ccaebcbed64419 Reviewed-by: Jędrzej Nowacki --- src/corelib/io/qfile.cpp | 8 +++++--- src/corelib/io/qfilesystemengine_unix.cpp | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 06d706b915..a840307145 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -567,9 +567,11 @@ 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)) { - if (d->fileName.compare(newName, Qt::CaseInsensitive) - || QFileSystemEngine::id(QFileSystemEntry(d->fileName)) != QFileSystemEngine::id(QFileSystemEntry(newName))) { + // Note: this does not take file engines into account. + QByteArray targetId = QFileSystemEngine::id(QFileSystemEntry(newName)); + if (!targetId.isNull()) { + QByteArray fileId = QFileSystemEngine::id(QFileSystemEntry(d->fileName)); + if (fileId != targetId || d->fileName.compare(newName, Qt::CaseInsensitive)) { // ### 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); diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 90e4faaf50..c3906c3207 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -338,7 +338,8 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry) { QT_STATBUF statResult; if (QT_STAT(entry.nativeFilePath().constData(), &statResult)) { - qErrnoWarning("stat() failed for '%s'", entry.nativeFilePath().constData()); + if (errno != ENOENT) + qErrnoWarning("stat() failed for '%s'", entry.nativeFilePath().constData()); return QByteArray(); } QByteArray result = QByteArray::number(quint64(statResult.st_dev), 16); -- cgit v1.2.3