QFileSystemEngine: add rmpath()
removeDirectory() acts in two mode, rmdir (one entry) and rmpath (the entry and all empty parent directories). This is irregular behavior, and API with a very specific use-case (in unittests, where you create a dir tree and want to cleanup after the test finishes). So, split the code into rmdir() and rmpath(), which matches QDir::rmdir() and QDir::rmpath(). On Unix, a further optimization pointed out by Thiago in review, remove the stat() call, ::rmdir() will fail with ENOTDIR if we try to remove anything that isn't a dir. Change-Id: I1bbb6e6c1ce49ba6d73d3c510b449223498612fb Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
46737c0bc0
commit
ead72a1155
@ -1552,7 +1552,7 @@ bool QDir::rmdir(const QString &dirName) const
|
|||||||
|
|
||||||
QString fn = filePath(dirName);
|
QString fn = filePath(dirName);
|
||||||
if (!d->fileEngine)
|
if (!d->fileEngine)
|
||||||
return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), false);
|
return QFileSystemEngine::rmdir(QFileSystemEntry(fn));
|
||||||
|
|
||||||
return d->fileEngine->rmdir(fn, false);
|
return d->fileEngine->rmdir(fn, false);
|
||||||
}
|
}
|
||||||
@ -1606,7 +1606,7 @@ bool QDir::rmpath(const QString &dirPath) const
|
|||||||
|
|
||||||
QString fn = filePath(dirPath);
|
QString fn = filePath(dirPath);
|
||||||
if (!d->fileEngine)
|
if (!d->fileEngine)
|
||||||
return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), true);
|
return QFileSystemEngine::rmpath(QFileSystemEntry(fn));
|
||||||
return d->fileEngine->rmdir(fn, true);
|
return d->fileEngine->rmdir(fn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,15 @@ public:
|
|||||||
|
|
||||||
static bool createDirectory(const QFileSystemEntry &entry, bool createParents,
|
static bool createDirectory(const QFileSystemEntry &entry, bool createParents,
|
||||||
std::optional<QFile::Permissions> permissions = std::nullopt);
|
std::optional<QFile::Permissions> permissions = std::nullopt);
|
||||||
static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents);
|
static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
|
||||||
|
{
|
||||||
|
if (removeEmptyParents)
|
||||||
|
return rmpath(entry);
|
||||||
|
return rmdir(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rmdir(const QFileSystemEntry &entry);
|
||||||
|
static bool rmpath(const QFileSystemEntry &entry);
|
||||||
|
|
||||||
static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
|
static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
|
||||||
|
|
||||||
|
@ -1189,30 +1189,28 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
|
|||||||
return createDirectoryWithParents(dirName, mode, false);
|
return createDirectoryWithParents(dirName, mode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
bool QFileSystemEngine::rmdir(const QFileSystemEntry &entry)
|
||||||
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
|
|
||||||
{
|
{
|
||||||
Q_CHECK_FILE_NAME(entry, false);
|
const QByteArray path = entry.nativeFilePath();
|
||||||
|
Q_CHECK_FILE_NAME(path, false);
|
||||||
|
return ::rmdir(path.constData()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (removeEmptyParents) {
|
bool QFileSystemEngine::rmpath(const QFileSystemEntry &entry)
|
||||||
QString dirName = QDir::cleanPath(entry.filePath());
|
{
|
||||||
for (qsizetype oldslash = 0, slash=dirName.size(); slash > 0; oldslash = slash) {
|
const QString path = QDir::cleanPath(entry.filePath());
|
||||||
const QByteArray chunk = QFile::encodeName(dirName.left(slash));
|
Q_CHECK_FILE_NAME(path, false);
|
||||||
QT_STATBUF st;
|
|
||||||
if (QT_STAT(chunk.constData(), &st) != -1) {
|
for (qsizetype oldslash = 0, slash = path.size(); slash > 0; oldslash = slash) {
|
||||||
if ((st.st_mode & S_IFMT) != S_IFDIR)
|
const QByteArray chunk = QFile::encodeName(path.left(slash));
|
||||||
return false;
|
|
||||||
if (::rmdir(chunk.constData()) != 0)
|
if (::rmdir(chunk.constData()) != 0)
|
||||||
return oldslash != 0;
|
return oldslash != 0;
|
||||||
} else {
|
|
||||||
return false;
|
slash = path.lastIndexOf(QDir::separator(), oldslash - 1);
|
||||||
}
|
|
||||||
slash = dirName.lastIndexOf(QDir::separator(), oldslash-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return rmdir(QFile::encodeName(entry.filePath()).constData()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
||||||
|
@ -1554,31 +1554,36 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
|
|||||||
return createDirectoryWithParents(dirName, securityAttributes, false);
|
return createDirectoryWithParents(dirName, securityAttributes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
bool QFileSystemEngine::rmdir(const QFileSystemEntry &entry)
|
||||||
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
|
|
||||||
{
|
{
|
||||||
QString dirName = entry.filePath();
|
QString dirName = entry.filePath();
|
||||||
Q_CHECK_FILE_NAME(dirName, false);
|
Q_CHECK_FILE_NAME(dirName, false);
|
||||||
|
|
||||||
if (removeEmptyParents) {
|
return rmDir(dirName);
|
||||||
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
|
}
|
||||||
for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
|
|
||||||
|
bool QFileSystemEngine::rmpath(const QFileSystemEntry &entry)
|
||||||
|
{
|
||||||
|
const QString dirName = QDir::toNativeSeparators(QDir::cleanPath(entry.filePath()));
|
||||||
|
Q_CHECK_FILE_NAME(dirName, false);
|
||||||
|
|
||||||
|
for (int oldslash = 0, slash = dirName.size(); slash > 0; oldslash = slash) {
|
||||||
const auto chunkRef = QStringView{dirName}.left(slash);
|
const auto chunkRef = QStringView{dirName}.left(slash);
|
||||||
if (chunkRef.length() == 2 && chunkRef.at(0).isLetter()
|
if (chunkRef.length() == 2 && chunkRef.at(0).isLetter()
|
||||||
&& chunkRef.at(1) == u':') {
|
&& chunkRef.at(1) == u':') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const QString chunk = chunkRef.toString();
|
const QString chunk = chunkRef.toString();
|
||||||
|
// TODO: get isDirPath() and rmDir() to accept QStringView
|
||||||
if (!isDirPath(chunk, nullptr))
|
if (!isDirPath(chunk, nullptr))
|
||||||
return false;
|
return false;
|
||||||
if (!rmDir(chunk))
|
if (!rmDir(chunk))
|
||||||
return oldslash != 0;
|
return oldslash != 0;
|
||||||
slash = dirName.lastIndexOf(QDir::separator(), oldslash - 1);
|
slash = dirName.lastIndexOf(QDir::separator(), oldslash - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return rmDir(entry.filePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
//static
|
//static
|
||||||
QString QFileSystemEngine::rootPath()
|
QString QFileSystemEngine::rootPath()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user