diff options
author | Jake Petroules <jake.petroules@qt.io> | 2016-12-04 16:33:27 -0800 |
---|---|---|
committer | Jake Petroules <jake.petroules@qt.io> | 2016-12-05 18:54:41 +0000 |
commit | 063c459054e228c27676b0b41478697c0db9f66e (patch) | |
tree | 1651e9fdf941f1564787e1554ca72e072a21de91 | |
parent | d5b4d35659265013d2695f9de87d661d8101280c (diff) |
Make Win32 API usage long-path aware
Most Win32 API functions are limited to working with paths which are
up to MAX_PATH (260) characters long by default. Windows 10 version 1607
allows this limit to be exceeded by setting a LongPathsEnabled registry
key and manifesting the application with the longPathAware=true setting.
We cannot rely on this being the case since we support older Windows
versions and the registry key is set to off by default.
Fortunately, most Win32 API functions allow prepending the \\?\ prefix
which raises the path length limit to UNICODE_STRING_MAX_CHARS (32767)
characters. This works on all Windows versions.
For the FileInfo class in particular, this resolves potential false
negatives for file existence, inability to retrieve modification times,
and misidentification of directories as files.
Task-number: QBS-1068
Change-Id: Ia4a37fa75ede803e3e2ecb63ae1ab12d2dae33bd
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r-- | src/lib/corelib/tools/fileinfo.cpp | 16 | ||||
-rw-r--r-- | src/lib/corelib/tools/processutils.cpp | 2 | ||||
-rw-r--r-- | src/lib/corelib/tools/vsenvironmentdetector.cpp | 2 |
3 files changed, 16 insertions, 4 deletions
diff --git a/src/lib/corelib/tools/fileinfo.cpp b/src/lib/corelib/tools/fileinfo.cpp index 82b06ff0c..dee37c7e9 100644 --- a/src/lib/corelib/tools/fileinfo.cpp +++ b/src/lib/corelib/tools/fileinfo.cpp @@ -223,12 +223,16 @@ bool FileInfo::globMatches(const QRegExp ®exp, const QString &fileName) return regexp.exactMatch(fileName); } +#ifdef Q_OS_WIN +static const QString win32LongPathPrefix = QStringLiteral("\\\\?\\"); +#endif + bool FileInfo::isFileCaseCorrect(const QString &filePath) { #if defined(Q_OS_WIN) // QFileInfo::canonicalFilePath() does not return the real case of the file path on Windows. QFileInfo fi(filePath); - const QString absolute = fi.absoluteFilePath(); + const QString absolute = win32LongPathPrefix + QDir::toNativeSeparators(fi.absoluteFilePath()); WIN32_FIND_DATA fd; HANDLE hFindFile = ::FindFirstFile((wchar_t*)absolute.utf16(), &fd); if (hFindFile == INVALID_HANDLE_VALUE) @@ -263,7 +267,15 @@ FileInfo::FileInfo(const QString &fileName) sizeof(FileInfo::InternalStatType) == sizeof(WIN32_FILE_ATTRIBUTE_DATA) > internal_type_has_wrong_size; Q_UNUSED(internal_type_has_wrong_size); - if (!GetFileAttributesEx(reinterpret_cast<const WCHAR*>(fileName.utf16()), + + QString filePath = fileName; + + // The extended-length path prefix cannot be used with a relative path, so make it absolute + if (!isAbsolute(filePath)) + filePath = QDir::currentPath() + QDir::separator() + filePath; + + filePath = win32LongPathPrefix + QDir::toNativeSeparators(filePath); + if (!GetFileAttributesEx(reinterpret_cast<const WCHAR*>(filePath.utf16()), GetFileExInfoStandard, &m_stat)) { ZeroMemory(z(m_stat), sizeof(WIN32_FILE_ATTRIBUTE_DATA)); diff --git a/src/lib/corelib/tools/processutils.cpp b/src/lib/corelib/tools/processutils.cpp index 60bb9b473..2f8254ab6 100644 --- a/src/lib/corelib/tools/processutils.cpp +++ b/src/lib/corelib/tools/processutils.cpp @@ -70,7 +70,7 @@ QString processNameByPid(qint64 pid) HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, DWORD(pid)); if (!hProcess) return QString(); - wchar_t buf[MAX_PATH]; + wchar_t buf[UNICODE_STRING_MAX_CHARS]; const DWORD length = GetModuleFileNameEx(hProcess, NULL, buf, sizeof(buf) / sizeof(wchar_t)); CloseHandle(hProcess); if (!length) diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp index 291c150c9..4d359f85c 100644 --- a/src/lib/corelib/tools/vsenvironmentdetector.cpp +++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp @@ -59,7 +59,7 @@ namespace Internal { static QString windowsSystem32Path() { #ifdef Q_OS_WIN - wchar_t str[MAX_PATH]; + wchar_t str[UNICODE_STRING_MAX_CHARS]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_SYSTEM, NULL, 0, str))) return QString::fromUtf16(reinterpret_cast<ushort*>(str)); #endif |