VirtualBox

Changeset 27246 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Mar 10, 2010 12:51:15 PM (15 years ago)
Author:
vboxsync
Message:

RTDirRemoveRecursive: Fixed memory leak, made it deal with UNKNOWN and thus work on Linux, optimized stack usage, added flag for only removing the content of the specified directory. TXS: clean up the scratch directory.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/dir.cpp

    r21675 r27246  
    723723
    724724
    725 RTDECL(int) RTDirRemoveRecursive(const char *pszPath)
    726 {
    727     int rc;
    728 
    729     if (!RTDirExists(pszPath))
    730         return VINF_SUCCESS;
    731 
    732     char szAbsPath[RTPATH_MAX];
    733     /** @todo use RTPathReal here instead? */
    734     rc = RTPathAbs(pszPath, szAbsPath, sizeof(szAbsPath));
     725/**
     726 * Recursion worker for RTDirRemoveRecursive.
     727 *
     728 * @returns IPRT status code.
     729 * @param   pszBuf              The path buffer.  Contains the abs path to the
     730 *                              directory to recurse into.  Trailing slash.
     731 * @param   cchDir              The length of the directory we're cursing into,
     732 *                              including the trailing slash.
     733 * @param   pDirEntry           The dir entry buffer.  (Shared to save stack.)
     734 * @param   pObjInfo            The object info buffer.  (ditto)
     735 */
     736static int rtDirRemoveRecursiveSub(char *pszBuf, size_t cchDir, PRTDIRENTRY pDirEntry, PRTFSOBJINFO pObjInfo)
     737{
     738    AssertReturn(RTPATH_IS_SLASH(pszBuf[cchDir - 1]), VERR_INTERNAL_ERROR_4);
     739
     740    /*
     741     * Enumerate the directory content and dispose of it.
     742     */
     743    PRTDIR pDir;
     744    int rc = RTDirOpen(&pDir, pszBuf);
    735745    if (RT_FAILURE(rc))
    736746        return rc;
    737 
    738     PRTDIR pDir = NULL;
    739     rc = RTDirOpen(&pDir, szAbsPath);
    740     if (RT_SUCCESS(rc))
    741     {
    742         RTDIRENTRY dirEntry;
    743         size_t cbDirEntry = sizeof(dirEntry);
    744 
    745         while ((rc = RTDirRead(pDir, &dirEntry, NULL /* Passing an argument won't work here yet. */)) == VINF_SUCCESS)
     747    while (RT_SUCCESS(rc = RTDirRead(pDir, pDirEntry, NULL)))
     748    {
     749        if (   pDirEntry->szName[0] != '.'
     750            || pDirEntry->cbName > 2
     751            || (   pDirEntry->cbName == 2
     752                && pDirEntry->szName[1] != '.')
     753           )
    746754        {
    747             char* pszEntry = NULL;
    748             rc = RTStrAPrintf(&pszEntry, "%s/%s", szAbsPath, dirEntry.szName);
    749             if(    RT_SUCCESS(rc)
    750                 && strcmp(dirEntry.szName, ".")
    751                 && strcmp(dirEntry.szName, ".."))
    752             {
    753                 switch (dirEntry.enmType)
     755            /* Construct the full name of the entry. */
     756            if (cchDir + pDirEntry->cbName + 1 /* dir slash */ >= RTPATH_MAX)
     757            {
     758                rc = VERR_FILENAME_TOO_LONG;
     759                break;
     760            }
     761            memcpy(&pszBuf[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
     762
     763            /* Deal with the unknown type. */
     764            if (pDirEntry->enmType == RTDIRENTRYTYPE_UNKNOWN)
     765            {
     766                rc = RTPathQueryInfoEx(pszBuf, pObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
     767                if (RT_SUCCESS(rc) && RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
     768                    pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
     769                else if (RT_SUCCESS(rc) && RTFS_IS_FILE(pObjInfo->Attr.fMode))
     770                    pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
     771                else if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(pObjInfo->Attr.fMode))
     772                    pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
     773            }
     774
     775            /* Try the delete the fs object. */
     776            switch (pDirEntry->enmType)
     777            {
     778                case RTDIRENTRYTYPE_FILE:
     779                    rc = RTFileDelete(pszBuf);
     780                    break;
     781
     782                case RTDIRENTRYTYPE_DIRECTORY:
    754783                {
    755                     case RTDIRENTRYTYPE_FILE:
    756 
    757                         rc = RTFileDelete(pszEntry);
    758                         break;
    759 
    760                     case RTDIRENTRYTYPE_DIRECTORY:
    761 
    762                         rc = RTDirRemoveRecursive(pszEntry);
    763                         break;
    764 
    765                     default:
    766                         /** @todo not implemented yet. */
    767                         break;
     784                    size_t cchSubDir = cchDir + pDirEntry->cbName;
     785                    pszBuf[cchSubDir++] = '/';
     786                    pszBuf[cchSubDir]   = '\0';
     787                    rc = rtDirRemoveRecursiveSub(pszBuf, cchSubDir, pDirEntry, pObjInfo);
     788                    if (RT_SUCCESS(rc))
     789                    {
     790                        pszBuf[cchSubDir] = '\0';
     791                        rc = RTDirRemove(pszBuf);
     792                    }
     793                    break;
    768794                }
    769795
    770                 RTStrFree(pszEntry);
     796                //case RTDIRENTRYTYPE_SYMLINK:
     797                //    rc = RTSymlinkDelete(pszBuf);
     798                //    break;
     799
     800                default:
     801                    /** @todo not implemented yet. */
     802                    rc = VINF_SUCCESS;
     803                    break;
    771804            }
    772 
    773805            if (RT_FAILURE(rc))
    774806               break;
    775807        }
    776         if (rc == VERR_NO_MORE_FILES)
    777             rc = VINF_SUCCESS;
    778 
    779         RTDirClose(pDir);
     808    }
     809    if (rc == VERR_NO_MORE_FILES)
     810        rc = VINF_SUCCESS;
     811    RTDirClose(pDir);
     812    return rc;
     813}
     814
     815
     816RTDECL(int) RTDirRemoveRecursive(const char *pszPath, uint32_t fFlags)
     817{
     818    AssertReturn(!(fFlags & ~RTDIRRMREC_F_VALID_MASK), VERR_INVALID_PARAMETER);
     819
     820    /* Get an absolute path because this is easier to work with. */
     821    /** @todo use RTPathReal here instead? */
     822    char szAbsPath[RTPATH_MAX];
     823    int rc = RTPathAbs(pszPath, szAbsPath, sizeof(szAbsPath));
     824    if (RT_FAILURE(rc))
     825        return rc;
     826
     827    /* This API is not permitted applied to the root of anything. */
     828    if (RTPathCountComponents(szAbsPath) <= 1)
     829        return VERR_ACCESS_DENIED;
     830
     831    /* Because of the above restriction, we never have to deal with the root
     832       slash problem and can safely strip any trailing slashes and add a
     833       definite one. */
     834    RTPathStripTrailingSlash(szAbsPath);
     835    size_t cchAbsPath = strlen(szAbsPath);
     836    if (cchAbsPath + 1 >= RTPATH_MAX)
     837        return VERR_FILENAME_TOO_LONG;
     838    szAbsPath[cchAbsPath++] = '/';
     839    szAbsPath[cchAbsPath] = 0;
     840
     841    /* Check if it exists so we can return quietly if it doesn't. */
     842    RTFSOBJINFO SharedObjInfoBuf;
     843    rc = RTPathQueryInfoEx(szAbsPath, &SharedObjInfoBuf, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
     844    if (   rc == VERR_PATH_NOT_FOUND
     845        || rc == VERR_FILE_NOT_FOUND)
     846        return VINF_SUCCESS;
     847    if (RT_FAILURE(rc))
     848        return rc;
     849    if (!RTFS_IS_DIRECTORY(SharedObjInfoBuf.Attr.fMode))
     850        return VERR_NOT_A_DIRECTORY;
     851
     852    /* We're all set for the recursion now, so get going. */
     853    RTDIRENTRY  SharedDirEntryBuf;
     854    rc = rtDirRemoveRecursiveSub(szAbsPath, cchAbsPath, &SharedDirEntryBuf, &SharedObjInfoBuf);
     855
     856    /* Remove the specified directory if desired and removing the content was
     857       successful. */
     858    if (   RT_SUCCESS(rc)
     859        && !(fFlags & RTDIRRMREC_F_CONTENT_ONLY))
     860    {
     861        szAbsPath[cchAbsPath] = 0;
    780862        rc = RTDirRemove(szAbsPath);
    781863    }
    782 
    783     LogFlow(("RTDirRemoveRecursive(%p:{%s}): returns %Rrc\n", pszPath, pszPath, rc));
    784864    return rc;
    785865}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette