summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qdir.cpp4
-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.cpp27
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp75
5 files changed, 117 insertions, 5 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 5463adaeb9..cb334ed741 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -2005,8 +2005,8 @@ bool QDir::match(const QString &filter, const QString &fileName)
#endif // QT_NO_REGEXP
/*!
- Removes all multiple directory separators "/" and resolves any
- "."s or ".."s found in the path, \a path.
+ Returns \a path with directory separators normalized (converted to "/") and
+ redundant ones removed, and "."s and ".."s resolved (as far as possible).
Symbolic links are kept. This function does not return the
canonical path, but rather the simplest version of the input.
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 5870cdf7de..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>
@@ -174,9 +176,16 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
#else
char *ret = 0;
# if defined(Q_OS_MAC) && !defined(Q_OS_IOS)
- // Mac OS X 10.5.x doesn't support the realpath(X,0) extension we use here.
+ // When using -mmacosx-version-min=10.4, we get the legacy realpath implementation,
+ // which does not work properly with the realpath(X,0) form. See QTBUG-28282.
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) {
- ret = realpath(entry.nativeFilePath().constData(), (char*)0);
+ ret = (char*)malloc(PATH_MAX + 1);
+ if (ret && realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) {
+ const int savedErrno = errno; // errno is checked below, and free() might change it
+ free(ret);
+ errno = savedErrno;
+ ret = 0;
+ }
} else {
// on 10.5 we can use FSRef to resolve the file path.
QString path = QDir::cleanPath(entry.filePath());
@@ -252,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)
{