summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorChristoph Schleifenbaum <christoph.schleifenbaum@kdab.com>2019-09-25 12:52:07 +0200
committerChristoph Schleifenbaum <christoph.schleifenbaum@kdab.com>2019-10-25 23:11:52 +0200
commited48391c592e8ba68c723e3017ac384f0c7a7c23 (patch)
treedf5988f40578e5282aa87b1276728d5a4cfea488 /src/corelib/io
parent9d504e1150e4bd49d34aba5cee938d1fd9f7e80c (diff)
QFileSystemEngine: Rework createDirectory on Windows
Try starting to create the directory at the end, not at the front. This is the same way as the Unix implementation is doing. This avoids problems like us trying to enter directories we are not allowed to read, which might be due to access rights or due to sandboxing. Change-Id: I67c1ed4bdc20a15b1af9b33aa48d59fea359da22 Reviewed-by: Christoph Schleifenbaum <christoph.schleifenbaum@kdab.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp103
1 files changed, 49 insertions, 54 deletions
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index ae29190848..0579872f8d 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -1123,67 +1123,62 @@ static bool isDirPath(const QString &dirPath, bool *existed)
return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
}
+// NOTE: if \a shouldMkdirFirst is false, we assume the caller did try to mkdir
+// before calling this function.
+static bool createDirectoryWithParents(const QString &nativeName, bool shouldMkdirFirst = true)
+{
+ const auto isUNCRoot = [](const QString &nativeName) {
+ return nativeName.startsWith(QLatin1String("\\\\")) && nativeName.count(QDir::separator()) <= 3;
+ };
+ const auto isDriveName = [](const QString &nativeName) {
+ return nativeName.size() == 2 && nativeName.at(1) == QLatin1Char(':');
+ };
+ const auto isDir = [](const QString &nativeName) {
+ bool exists = false;
+ return isDirPath(nativeName, &exists) && exists;
+ };
+ // Do not try to mkdir a UNC root path or a drive letter.
+ if (isUNCRoot(nativeName) || isDriveName(nativeName))
+ return false;
+
+ if (shouldMkdirFirst) {
+ if (mkDir(nativeName))
+ return true;
+ }
+
+ const int backSlash = nativeName.lastIndexOf(QDir::separator());
+ if (backSlash < 1)
+ return false;
+
+ const QString parentNativeName = nativeName.left(backSlash);
+ if (!createDirectoryWithParents(parentNativeName))
+ return false;
+
+ // try again
+ if (mkDir(nativeName))
+ return true;
+ return isDir(nativeName);
+}
+
//static
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
{
QString dirName = entry.filePath();
Q_CHECK_FILE_NAME(dirName, false);
- if (createParents) {
- dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
- // We spefically search for / so \ would break it..
- int oldslash = -1;
- if (dirName.startsWith(QLatin1String("\\\\"))) {
- // Don't try to create the root path of a UNC path;
- // CreateDirectory() will just return ERROR_INVALID_NAME.
- for (int i = 0; i < dirName.size(); ++i) {
- if (dirName.at(i) != QDir::separator()) {
- oldslash = i;
- break;
- }
- }
- if (oldslash != -1)
- oldslash = dirName.indexOf(QDir::separator(), oldslash);
- } else if (dirName.size() > 2
- && dirName.at(1) == QLatin1Char(':')) {
- // Don't try to call mkdir with just a drive letter
- oldslash = 2;
- }
- for (int slash=0; slash != -1; oldslash = slash) {
- slash = dirName.indexOf(QDir::separator(), oldslash+1);
- if (slash == -1) {
- if (oldslash == dirName.length())
- break;
- slash = dirName.length();
- }
- if (slash) {
- DWORD lastError;
- QString chunk = dirName.left(slash);
- if (!mkDir(chunk, &lastError)) {
- if (lastError == ERROR_ALREADY_EXISTS || lastError == ERROR_ACCESS_DENIED) {
- bool existed = false;
- if (isDirPath(chunk, &existed) && existed)
- continue;
-#ifdef Q_OS_WINRT
- static QThreadStorage<QString> dataLocation;
- if (!dataLocation.hasLocalData())
- dataLocation.setLocalData(QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DataLocation)));
- static QThreadStorage<QString> tempLocation;
- if (!tempLocation.hasLocalData())
- tempLocation.setLocalData(QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::TempLocation)));
- // We try to create something outside the sandbox, which is forbidden
- // However we could still try to pass into the sandbox
- if (dataLocation.localData().startsWith(chunk) || tempLocation.localData().startsWith(chunk))
- continue;
-#endif
- }
- return false;
- }
- }
- }
+ dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
+
+ // try to mkdir this directory
+ DWORD lastError;
+ if (mkDir(dirName, &lastError))
return true;
- }
- return mkDir(entry.filePath());
+ // mkpath should return true, if the directory already exists, mkdir false.
+ if (!createParents)
+ return false;
+ if (lastError == ERROR_ALREADY_EXISTS)
+ return isDirPath(dirName, nullptr);
+
+ return createDirectoryWithParents(dirName, false);
}
//static