summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qfile.cpp15
-rw-r--r--src/corelib/io/qfilesystemengine_p.h1
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp16
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp75
4 files changed, 106 insertions, 1 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index d9f2c5c605..24f0eba1b7 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -48,6 +48,7 @@
#include "qfileinfo.h"
#include "private/qiodevice_p.h"
#include "private/qfile_p.h"
+#include "private/qfilesystemengine_p.h"
#include "private/qsystemerror_p.h"
#if defined(QT_BUILD_CORE_LIB)
# include "qcoreapplication.h"
@@ -548,7 +549,19 @@ QFile::rename(const QString &newName)
qWarning("QFile::rename: Empty or null file name");
return false;
}
- if (QFile(newName).exists()) {
+ if (d->fileName == newName) {
+ d->setError(QFile::RenameError, tr("Destination file is the same file."));
+ return false;
+ }
+ if (!exists()) {
+ d->setError(QFile::RenameError, tr("Source file does not exist."));
+ return false;
+ }
+ // 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);
diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h
index bb91cf1142..9d03a6b459 100644
--- a/src/corelib/io/qfilesystemengine_p.h
+++ b/src/corelib/io/qfilesystemengine_p.h
@@ -75,6 +75,7 @@ public:
static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry);
+ static QByteArray id(const QFileSystemEntry &entry);
static QString resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
static QString resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index f8cb130997..fa0e07b045 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -46,6 +46,8 @@
#include <QtCore/qvarlengtharray.h>
#include <stdlib.h> // for realpath()
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
@@ -259,6 +261,20 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
}
//static
+QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
+{
+ struct stat statResult;
+ if (stat(entry.nativeFilePath().constData(), &statResult)) {
+ qErrnoWarning("stat() failed for '%s'", entry.nativeFilePath().constData());
+ return QByteArray();
+ }
+ QByteArray result = QByteArray::number(quint64(statResult.st_dev), 16);
+ result += ':';
+ result += QByteArray::number(quint64(statResult.st_ino), 16);
+ return result;
+}
+
+//static
QString QFileSystemEngine::resolveUserName(uint userId)
{
#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 5364a44f91..cc40d4af3f 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -42,6 +42,7 @@
#include "qfilesystemengine_p.h"
#include "qplatformdefs.h"
+#include "qsysinfo.h"
#include "private/qabstractfileengine_p.h"
#include "private/qfsfileengine_p.h"
#include <private/qsystemlibrary_p.h>
@@ -563,6 +564,80 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
return QFileSystemEntry(ret, QFileSystemEntry::FromInternalPath());
}
+#ifndef Q_OS_WINCE
+
+// FILE_INFO_BY_HANDLE_CLASS has been extended by FileIdInfo = 18 as of VS2012.
+typedef enum { Q_FileIdInfo = 18 } Q_FILE_INFO_BY_HANDLE_CLASS;
+
+# if defined(Q_CC_MINGW) || (defined(Q_CC_MSVC) && _MSC_VER < 1700)
+
+typedef struct _FILE_ID_128 {
+ BYTE Identifier[16];
+} FILE_ID_128, *PFILE_ID_128;
+
+typedef struct _FILE_ID_INFO {
+ ULONGLONG VolumeSerialNumber;
+ FILE_ID_128 FileId;
+} FILE_ID_INFO, *PFILE_ID_INFO;
+# endif // if defined (Q_CC_MINGW) || (defined(Q_CC_MSVC) && _MSC_VER < 1700))
+
+// File ID for Windows up to version 7.
+static inline QByteArray fileId(HANDLE handle)
+{
+ QByteArray result;
+ BY_HANDLE_FILE_INFORMATION info;
+ if (GetFileInformationByHandle(handle, &info)) {
+ result = QByteArray::number(uint(info.nFileIndexLow), 16);
+ result += ':';
+ result += QByteArray::number(uint(info.nFileIndexHigh), 16);
+ }
+ return result;
+}
+
+// File ID for Windows starting from version 8.
+QByteArray fileIdWin8(HANDLE handle)
+{
+ typedef BOOL (WINAPI* GetFileInformationByHandleExType)(HANDLE, Q_FILE_INFO_BY_HANDLE_CLASS, void *, DWORD);
+
+ // Dynamically resolve GetFileInformationByHandleEx (Vista onwards).
+ static GetFileInformationByHandleExType getFileInformationByHandleEx = 0;
+ if (!getFileInformationByHandleEx) {
+ QSystemLibrary library(QLatin1String("kernel32"));
+ getFileInformationByHandleEx = (GetFileInformationByHandleExType)library.resolve("GetFileInformationByHandleEx");
+ }
+ QByteArray result;
+ if (getFileInformationByHandleEx) {
+ FILE_ID_INFO infoEx;
+ if (getFileInformationByHandleEx(handle, Q_FileIdInfo,
+ &infoEx, sizeof(FILE_ID_INFO))) {
+ result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
+ result += ':';
+ result += QByteArray((char *)infoEx.FileId.Identifier, sizeof(infoEx.FileId.Identifier)).toHex();
+ }
+ }
+ return result;
+}
+#endif // !Q_OS_WINCE
+
+//static
+QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
+{
+#ifndef Q_OS_WINCE
+ QByteArray result;
+ const HANDLE handle =
+ CreateFile((wchar_t*)entry.nativeFilePath().utf16(), GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (handle) {
+ result = QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 ?
+ fileIdWin8(handle) : fileId(handle);
+ CloseHandle(handle);
+ }
+ return result;
+#else // !Q_OS_WINCE
+ return entry.nativeFilePath().toLower().toLatin1();
+#endif
+}
+
//static
QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own)
{