QDir::removeRecursively() fails even on empty folder
-
Greetings,
I am on Qt 5.4 built with MSVC 2012 (11.0)
Our app creates temp directories with files in it.
I am writing the cleanup function.
qDir->removeRecursively() fails all the time.
I tried running app as administrator on Windows 7.
I tried erasing all files in the directory and closing all explorers accessing the folder : still returns false.
What is wrong with removeRecursively() ?
Is there a GetLastError() thing to get more info?
BTW the temp dirs were created inside the temp folder obtained with QDir::tempPath();, for example: C:/Users/Frank/AppData/Local/Temp/GreatAppName_sectionXYZ/checksum_a4fe13430f4a23679eca887664f9d565/
In this code it would try to clean the folder "checksum_a4fe13430f4a23679eca887664f9d565"QDir filenameQDir(dirName); QFileInfoList multipleVersionsList = filenameQDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time); // The first two ones are the most recent, keep them if (multipleVersionsList.size() > 2) { for(int i=2; i<multipleVersionsList.size(); i++) { qDebug() << " " << multipleVersionsList.at(i).absoluteFilePath() << multipleVersionsList.at(i).lastModified(); QDir cleanupDir(multipleVersionsList.at(i).absoluteFilePath()); if (cleanupDir.removeRecursively()) { qDebug() << "Cleaned up old app folder:" << multipleVersionsList.at(i).absoluteFilePath(); } else { qDebug() << "ERROR: Failed to cleanup old app folder:" << multipleVersionsList.at(i).absoluteFilePath(); } } }
-
Hi and welcome
I tried on win 10, Qt 5.6
it did delete it all.
it was not temp folder, though. -
I found out what the problem was !
Files and folders had "read-only" attribute.
I had to remove attribute on both files and folder before being able to programmatically erase the directory recursively. I first wrote a RemoveDirRecursive() that is more powerful than the Qt's version since it removes read-only attributes. Then I simplified by just writing a RemoveReadOnlyAttributeRecursive() function. Calling this before QDir::removeRecursively() is what I will use as solution. I am attaching the function I wrote as reference. I am going to try on OSX to see if similar behavior is needed:/* Usage : QString directoryToRemove = "c:/my/super/awesome/directory"; RemoveReadOnlyAttributeRecursive(directoryToRemove) QDir qDir(directoryToRemove); qDir.removeRecursively(); */ static bool RemoveReadOnlyAttributeRecursive(const QString& directory) { int failures = 0; QDirIterator it(directory, QDirIterator::NoIteratorFlags); while (it.hasNext()) { QString fileName = it.next(); if (fileName.endsWith("/.") || fileName.endsWith("/..")) continue; QFileInfo fileInfo(fileName); if (fileInfo.isDir()) { if (!RemoveReadOnlyAttributeRecursive(fileName)) { qDebug() << "ERROR: Failed to RemoveReadOnlyAttributeRecursive() " << fileName; failures++; } } else { #ifdef Q_OS_WIN wchar_t* fileNamePtr = (wchar_t*)fileName.utf16(); if (!SetFileAttributes(fileNamePtr, GetFileAttributes(fileNamePtr) & ~FILE_ATTRIBUTE_READONLY)) { failures++; } #endif } } #ifdef Q_OS_WIN wchar_t* directoryPtr = (wchar_t*)directory.utf16(); if (!SetFileAttributes(directoryPtr, GetFileAttributes(directoryPtr) & ~FILE_ATTRIBUTE_READONLY)) { failures++; } #endif return failures == 0 ? true : false; }
.
And the one I wrote first but will end up not using:static bool RemoveDirRecursive(const QString& directory) { int failures = 0; QDirIterator it(directory, QDirIterator::NoIteratorFlags); while (it.hasNext()) { QString fileName = it.next(); if (fileName.endsWith("/.") || fileName.endsWith("/..")) continue; QFileInfo fileInfo(fileName); if (fileInfo.isDir()) { if (!RemoveDirRecursive(fileName)) { qDebug() << "ERROR: Failed to RemoveDirRecursive() " << fileName; failures++; } } else { if (!QFile::remove(fileName)) { qDebug() << "ERROR: Failed to QFile::remove() " << fileName; #ifdef Q_OS_WIN wchar_t* fileNamePtr = (wchar_t*)fileName.utf16(); SetFileAttributes(fileNamePtr, GetFileAttributes(fileNamePtr) & ~FILE_ATTRIBUTE_READONLY); if (!::DeleteFile(fileNamePtr)) { DWORD lastError = ::GetLastError(); qDebug() << "ERROR: GetLastError: " << lastError; failures++; } else { qDebug() << "Success on second try with windows API " << fileName; } #else failures++; #endif } } } QDir qDir; if(!qDir.remove(directory)) { qDebug() << "ERROR: Failed to qDir.remove() " << directory; #ifdef Q_OS_WIN wchar_t* directoryPtr = (wchar_t*)directory.utf16(); SetFileAttributes(directoryPtr, GetFileAttributes(directoryPtr) & ~FILE_ATTRIBUTE_READONLY); if (!::RemoveDirectory(directoryPtr)) { DWORD lastError = ::GetLastError(); qDebug() << "ERROR: GetLastError: " << lastError; failures++; } else { qDebug() << "Success on second try delete folder with windows API " << directory; } #else failures++; #endif } else { qDebug() << "Success qDir.remove " << directory; } return failures == 0 ? true : false; }