diff --git a/src/base/utils/fs.cpp b/src/base/utils/fs.cpp index 04ccb12ef..77404c25d 100644 --- a/src/base/utils/fs.cpp +++ b/src/base/utils/fs.cpp @@ -99,9 +99,13 @@ QString Utils::Fs::folderName(const QString &filePath) } /** - * This function will first remove system cache files, e.g. `Thumbs.db`, - * `.DS_Store`. Then will try to remove the whole tree if the tree consist - * only of folders + * This function will first check if there are only system cache files, e.g. `Thumbs.db`, + * `.DS_Store` and/or only temp files that end with '~', e.g. `filename~`. + * If they are the only files it will try to remove them and delete the folder. + * This action will be performed for each subfolder starting from the deepest folder. + * There is an inherent race condition here. A file might appear after it is checked + * that only the above mentioned "useless" files exist but before the whole folder is removed. + * In this case, the folder will not be removed but the "useless" files will be deleted. */ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path) { @@ -110,12 +114,12 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path) const QStringList deleteFilesList = { // Windows - "Thumbs.db", - "desktop.ini", + QLatin1String("Thumbs.db"), + QLatin1String("desktop.ini"), // Linux - ".directory", + QLatin1String(".directory"), // Mac OS - ".DS_Store" + QLatin1String(".DS_Store") }; // travel from the deepest folder and remove anything unwanted on the way out. @@ -128,18 +132,25 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path) , [](const QString &l, const QString &r) { return l.count('/') > r.count('/'); }); for (const QString &p : asConst(dirList)) { - // remove unwanted files - for (const QString &f : deleteFilesList) { - forceRemove(p + f); - } - - // remove temp files on linux (file ends with '~'), e.g. `filename~` const QDir dir(p); + // A deeper folder may have not been removed in the previous iteration + // so don't remove anything from this folder either. + if (!dir.isEmpty(QDir::Dirs | QDir::NoDotAndDotDot)) + continue; + const QStringList tmpFileList = dir.entryList(QDir::Files); - for (const QString &f : tmpFileList) { - if (f.endsWith('~')) - forceRemove(p + f); - } + + // deleteFilesList contains unwanted files, usually created by the OS + // temp files on linux usually end with '~', e.g. `filename~` + const bool hasOtherFiles = std::any_of(tmpFileList.cbegin(), tmpFileList.cend(), [&deleteFilesList](const QString &f) + { + return (!f.endsWith('~') && !deleteFilesList.contains(f, Qt::CaseInsensitive)); + }); + if (hasOtherFiles) + continue; + + for (const QString &f : tmpFileList) + forceRemove(p + f); // remove directory if empty dir.rmdir(p);