diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index f1e5f43a378..6c9fe8e2ac2 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -34,12 +34,6 @@ #include #include -#ifdef Q_OS_UNIX -#include -#include -#include -#endif - Q_GLOBAL_STATIC_WITH_ARGS(Utils::Environment, staticSystemEnvironment, (QProcessEnvironment::systemEnvironment().toStringList())) @@ -435,23 +429,6 @@ QStringList Environment::appendExeExtensions(const QString &executable) const return execs; } -static bool hasSameInode(const QString &file1, const QString &file2) -{ -#ifdef Q_OS_UNIX - struct stat stat1; - if (stat(file1.toLocal8Bit().constData(), &stat1) < 0) - return false; - struct stat stat2; - if (stat(file2.toLocal8Bit().constData(), &stat2) < 0) - return false; - return stat1.st_ino == stat2.st_ino; -#else - Q_UNUSED(file1) - Q_UNUSED(file2) - return false; -#endif -} - bool Environment::isSameExecutable(const QString &exe1, const QString &exe2) const { const QStringList exe1List = appendExeExtensions(exe1); @@ -464,7 +441,7 @@ bool Environment::isSameExecutable(const QString &exe1, const QString &exe2) con return true; if (FileUtils::resolveSymlinks(f1) == FileUtils::resolveSymlinks(f2)) return true; - if (hasSameInode(f1.toString(), f2.toString())) + if (FileUtils::fileId(f1) == FileUtils::fileId(f2)) return true; } } diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 411dbf777d9..cb5537a26da 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -33,9 +33,11 @@ #include #include #include +#include #include #include #include +#include #ifdef QT_GUI_LIB #include @@ -355,6 +357,82 @@ FileName FileUtils::commonPath(const FileName &oldCommonPath, const FileName &fi return canonicalPath(newCommonPath); } +// Copied from qfilesystemengine_win.cpp +#ifdef Q_OS_WIN +#if WINVER < 0x0602 // Windows 8 onwards + +typedef struct _FILE_ID_INFO { + ULONGLONG VolumeSerialNumber; + FILE_ID_128 FileId; +} FILE_ID_INFO, *PFILE_ID_INFO; + +#endif // if WINVER < 0x0602 + +// File ID for Windows up to version 7. +static inline QByteArray fileIdWin7(HANDLE handle) +{ + BY_HANDLE_FILE_INFORMATION info; + if (GetFileInformationByHandle(handle, &info)) { + char buffer[sizeof "01234567:0123456701234567\0"]; + qsnprintf(buffer, sizeof(buffer), "%lx:%08lx%08lx", + info.dwVolumeSerialNumber, + info.nFileIndexHigh, + info.nFileIndexLow); + return QByteArray(buffer); + } + return QByteArray(); +} + +// File ID for Windows starting from version 8. +static QByteArray fileIdWin8(HANDLE handle) +{ + QByteArray result; + FILE_ID_INFO infoEx; + if (GetFileInformationByHandleEx(handle, + static_cast(18), // FileIdInfo in Windows 8 + &infoEx, sizeof(FILE_ID_INFO))) { + result = QByteArray::number(infoEx.VolumeSerialNumber, 16); + result += ':'; + // Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one. + result += QByteArray(reinterpret_cast(&infoEx.FileId), int(sizeof(infoEx.FileId))).toHex(); + } + return result; +} + +static QByteArray fileIdWin(HANDLE fHandle) +{ + return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ? + fileIdWin8(HANDLE(fHandle)) : fileIdWin7(HANDLE(fHandle)); +} +#endif + +QByteArray FileUtils::fileId(const FileName &fileName) +{ + QByteArray result; + +#ifdef Q_OS_WIN + const HANDLE handle = + CreateFile((wchar_t*)fileName.toUserOutput().utf16(), 0, + FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (handle != INVALID_HANDLE_VALUE) { + result = fileIdWin(handle); + CloseHandle(handle); + } +#else // Copied from qfilesystemengine_unix.cpp + if (Q_UNLIKELY(fileName.isEmpty())) + return result; + + QT_STATBUF statResult; + if (QT_STAT(fileName.toString().toLocal8Bit().constData(), &statResult)) + return result; + result = QByteArray::number(quint64(statResult.st_dev), 16); + result += ':'; + result += QByteArray::number(quint64(statResult.st_ino)); +#endif + return result; +} + QByteArray FileReader::fetchQrc(const QString &fileName) { QTC_ASSERT(fileName.startsWith(QLatin1Char(':')), return QByteArray()); diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 00278a55a19..5ff7cf8b674 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -130,6 +130,7 @@ public: static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); } static QString resolvePath(const QString &baseDir, const QString &fileName); static FileName commonPath(const FileName &oldCommonPath, const FileName &fileName); + static QByteArray fileId(const FileName &fileName); }; // for actually finding out if e.g. directories are writable on Windows