From f05c597ae506ea6163394dbb6b70ecc77fae3b3c Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 11 Dec 2015 13:42:28 +0100 Subject: winrt: msvc2015: refactor file handling msvc2015 reintroduced a couple of functions from the win32 API towards WinRT. Enable usage of those and simplify the file system engine. Furthermore update the autotests. Change-Id: I9eafffba0ddfd05917c184c4a6b9e166f86d71d9 Reviewed-by: Oliver Wolff --- src/corelib/io/qdir.cpp | 11 ++++++++++ src/corelib/io/qfileinfo.cpp | 2 +- src/corelib/io/qfilesystemengine_win.cpp | 33 ++++++++++++++++++++++-------- src/corelib/io/qfilesystementry.cpp | 10 +++++++++ src/corelib/io/qfilesystemiterator_win.cpp | 3 ++- src/corelib/io/qfsfileengine_win.cpp | 2 +- 6 files changed, 49 insertions(+), 12 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 4d2b36632f..2c2bdd579e 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -152,7 +152,11 @@ inline void QDirPrivate::setPath(const QString &path) if (p.endsWith(QLatin1Char('/')) && p.length() > 1 #if defined(Q_OS_WIN) +# if defined (Q_OS_WINRT) + && (!(p.toLower() == QDir::rootPath().toLower())) +# else && (!(p.length() == 3 && p.at(1).unicode() == ':' && p.at(0).isLetter())) +# endif #endif ) { p.truncate(p.length() - 1); @@ -885,6 +889,9 @@ bool QDir::cd(const QString &dirName) #if defined (Q_OS_UNIX) //After cleanPath() if path is "/.." or starts with "/../" it means trying to cd above root. if (newPath.startsWith(QLatin1String("/../")) || newPath == QLatin1String("/..")) +#elif defined (Q_OS_WINRT) + const QString rootPath = QDir::rootPath(); + if (newPath.size() < rootPath.size() && rootPath.startsWith(newPath)) #else /* cleanPath() already took care of replacing '\' with '/'. @@ -2187,7 +2194,11 @@ QString QDir::cleanPath(const QString &path) // Strip away last slash except for root directories if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) { #if defined (Q_OS_WIN) +# if defined(Q_OS_WINRT) + if (!((ret.length() == 3 || ret.length() == QDir::rootPath().length()) && ret.at(1) == QLatin1Char(':'))) +# else if (!(ret.length() == 3 && ret.at(1) == QLatin1Char(':'))) +# endif #endif ret.chop(1); } diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 51b39b1114..dd194594c9 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -1095,7 +1095,7 @@ bool QFileInfo::isRoot() const return true; if (d->fileEngine == 0) { if (d->fileEntry.isRoot()) { -#if defined(Q_OS_WIN) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) //the path is a drive root, but the drive may not exist //for backward compatibility, return true only if the drive exists if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ExistsAttribute)) diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 379095a83d..f1a6019094 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -78,6 +78,11 @@ using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Storage; using namespace ABI::Windows::ApplicationModel; + +#if _MSC_VER < 1900 +#define Q_OS_WINRT_WIN81 +#endif + #endif // Q_OS_WINRT #ifndef SPI_GETPLATFORMTYPE @@ -522,7 +527,7 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path) { // can be //server or //server/share QString absPath; -#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT_WIN81) QVarLengthArray buf(qMax(MAX_PATH, path.size() + 1)); wchar_t *fileName = 0; DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); @@ -532,6 +537,16 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path) } if (retLen != 0) absPath = QString::fromWCharArray(buf.data(), retLen); +# if defined(Q_OS_WINRT) + // Win32 returns eg C:/ as root directory with a trailing /. + // WinRT returns the sandbox root without /. + // Also C:/../.. returns C:/ on Win32, while for WinRT it steps outside the package + // and goes beyond package root. Hence force the engine to stay inside + // the package. + const QString rootPath = QDir::toNativeSeparators(QDir::rootPath()); + if (absPath.size() < rootPath.size() && rootPath.startsWith(absPath)) + absPath = rootPath; +# endif // Q_OS_WINRT #elif !defined(Q_OS_WINCE) if (QDir::isRelativePath(path)) absPath = QDir::toNativeSeparators(QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + path)); @@ -569,7 +584,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) ret = entry.filePath(); #endif } else { -#ifndef Q_OS_WINRT +#ifndef Q_OS_WINRT_WIN81 ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath()); #else // Some WinRT APIs do not support absolute paths (due to sandboxing). @@ -1218,8 +1233,8 @@ QString QFileSystemEngine::rootPath() if (FAILED(item->get_Path(finalWinPath.GetAddressOf()))) return ret; - ret = QDir::fromNativeSeparators(QString::fromWCharArray(finalWinPath.GetRawBuffer(nullptr))); - + const QString qtWinPath = QDir::fromNativeSeparators(QString::fromWCharArray(finalWinPath.GetRawBuffer(nullptr))); + ret = qtWinPath.endsWith(QLatin1Char('/')) ? qtWinPath : qtWinPath + QLatin1Char('/'); #else QString ret = QString::fromLatin1(qgetenv("SystemDrive")); if (ret.isEmpty()) @@ -1337,7 +1352,7 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry) if(!(meta.exists() && meta.isDirectory())) return false; -#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT_WIN81) //TODO: this should really be using nativeFilePath(), but that returns a path in long format \\?\c:\foo //which causes many problems later on when it's returned through currentPath() return ::SetCurrentDirectory(reinterpret_cast(QDir::toNativeSeparators(entry.filePath()).utf16())) != 0; @@ -1350,7 +1365,7 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry) QFileSystemEntry QFileSystemEngine::currentPath() { QString ret; -#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT_WIN81) DWORD size = 0; wchar_t currentName[PATH_MAX]; size = ::GetCurrentDirectory(PATH_MAX, currentName); @@ -1366,17 +1381,17 @@ QFileSystemEntry QFileSystemEngine::currentPath() } if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. -#else // !Q_OS_WINCE && !Q_OS_WINRT +#else // !Q_OS_WINCE && !Q_OS_WINRT_WIN81 //TODO - a race condition exists when using currentPath / setCurrentPath from multiple threads if (qfsPrivateCurrentDir.isEmpty()) -#ifndef Q_OS_WINRT +#ifndef Q_OS_WINRT_WIN81 qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); #else qfsPrivateCurrentDir = QDir::rootPath(); #endif ret = qfsPrivateCurrentDir; -#endif // Q_OS_WINCE || Q_OS_WINRT +#endif // Q_OS_WINCE || Q_OS_WINRT_WIN81 return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath()); } diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp index 709970e3ac..c590d81f7a 100644 --- a/src/corelib/io/qfilesystementry.cpp +++ b/src/corelib/io/qfilesystementry.cpp @@ -166,6 +166,12 @@ void QFileSystemEntry::resolveNativeFilePath() const m_nativeFilePath.remove(0,1); if (m_nativeFilePath.isEmpty()) m_nativeFilePath.append(QLatin1Char('.')); + // WinRT/MSVC2015 allows a maximum of 256 characters for a filepath + // unless //?/ is prepended which extends the rule to have a maximum + // of 256 characters in the filename plus the preprending path +#if _MSC_VER >= 1900 + m_nativeFilePath.prepend("\\\\?\\"); +#endif #endif } } @@ -283,9 +289,13 @@ bool QFileSystemEntry::isAbsolute() const bool QFileSystemEntry::isDriveRoot() const { resolveFilePath(); +#ifndef Q_OS_WINRT return (m_filePath.length() == 3 && m_filePath.at(0).isLetter() && m_filePath.at(1) == QLatin1Char(':') && m_filePath.at(2) == QLatin1Char('/')); +#else // !Q_OS_WINRT + return m_filePath == QDir::rootPath(); +#endif // !Q_OS_WINRT } #endif diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp index 6351a3559d..d7fed87222 100644 --- a/src/corelib/io/qfilesystemiterator_win.cpp +++ b/src/corelib/io/qfilesystemiterator_win.cpp @@ -67,7 +67,8 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi if (!nativePath.endsWith(QLatin1Char('\\'))) nativePath.append(QLatin1Char('\\')); nativePath.append(QLatin1Char('*')); -#ifdef Q_OS_WINRT + // In MSVC2015+ case we prepend //?/ for longer file-name support +#if defined(Q_OS_WINRT) && _MSC_VER < 1900 if (nativePath.startsWith(QLatin1Char('\\'))) nativePath.remove(0, 1); #endif diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index cfd50955a6..886d526fb1 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -1037,7 +1037,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, offsetHi, offsetLo, size + extra); #else LPVOID mapAddress = ::MapViewOfFileFromApp(mapHandle, access, - (ULONG64(offsetHi) << 32) + offsetLo, size); + (ULONG64(offsetHi) << 32) + offsetLo, size + extra); #endif if (mapAddress) { uchar *address = extra + static_cast(mapAddress); -- cgit v1.2.3