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();
    		}
    	}
    }
    

  • Qt Champions 2016

    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;
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.