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>
This commit is contained in:
parent
9d504e1150
commit
ed48391c59
@ -1123,67 +1123,62 @@ static bool isDirPath(const QString &dirPath, bool *existed)
|
|||||||
return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
|
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
|
//static
|
||||||
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
|
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
|
||||||
{
|
{
|
||||||
QString dirName = entry.filePath();
|
QString dirName = entry.filePath();
|
||||||
Q_CHECK_FILE_NAME(dirName, false);
|
Q_CHECK_FILE_NAME(dirName, false);
|
||||||
|
|
||||||
if (createParents) {
|
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
|
||||||
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
|
|
||||||
// We spefically search for / so \ would break it..
|
// try to mkdir this directory
|
||||||
int oldslash = -1;
|
DWORD lastError;
|
||||||
if (dirName.startsWith(QLatin1String("\\\\"))) {
|
if (mkDir(dirName, &lastError))
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
// mkpath should return true, if the directory already exists, mkdir false.
|
||||||
return mkDir(entry.filePath());
|
if (!createParents)
|
||||||
|
return false;
|
||||||
|
if (lastError == ERROR_ALREADY_EXISTS)
|
||||||
|
return isDirPath(dirName, nullptr);
|
||||||
|
|
||||||
|
return createDirectoryWithParents(dirName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
|
Loading…
Reference in New Issue
Block a user