VirtualBox

Changeset 69720 in vbox for trunk/src/VBox/Runtime/tools


Ignore:
Timestamp:
Nov 16, 2017 4:18:19 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
119101
Message:

IPRT: More work on directory relative APIs (NT mainly) and VFS; introducing RTRmDir (test) tool.

  • Added RTVfsDirRemoveDir
  • Native NT implementation of RTDirRelRemoveDir.
  • Improved the RTFS_TYPE_DIRECTORY case of rtVfsStdDir_UnlinkEntry.
  • Added two new status code conversions to RTErrConvertFromNtStatus.
Location:
trunk/src/VBox/Runtime/tools
Files:
2 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/tools/Makefile.kmk

    r69716 r69720  
    118118 RTMkDir_SOURCES = RTMkDir.cpp
    119119
     120 # RTRmDir - our mkdir clone.
     121 PROGRAMS += RTRmDir
     122 RTRmDir_TEMPLATE = VBoxR3Tool
     123 RTRmDir_SOURCES = RTRmDir.cpp
     124
    120125 # RTShutdown - similar (but not identical) to a typical unix shutdown command.
    121126 PROGRAMS += RTShutdown
  • trunk/src/VBox/Runtime/tools/RTMkDir.cpp

    r69718 r69720  
    108108                if (RT_FAILURE(rc))
    109109                    RTVfsChainMsgError("RTVfsChainOpenDir", pszSpec, rc, offError, &ErrInfo.Core);
     110                else if (!pszFinalPath)
     111                    pszFinalPath = RTStrEnd(pszSpec, RTSTR_MAX);
    110112            }
    111113            else if (!RTPathStartsWithRoot(pszFinalPath))
  • trunk/src/VBox/Runtime/tools/RTRmDir.cpp

    r69718 r69720  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Creates directory.
     3 * IPRT - Removes directory.
    44 */
    55
     
    4444*   Structures and Typedefs                                                                                                      *
    4545*********************************************************************************************************************************/
    46 typedef struct RTCMDMKDIROPTS
     46typedef struct RTCMDRMDIROPTS
    4747{
    4848    /** -v, --verbose */
     
    5050    /** -p, --parents */
    5151    bool        fParents;
     52    /** Don't fail if directories that aren't empty. */
     53    bool        fIgnoreNotEmpty;
     54    /** Don't fail a directory doesn't exist (i.e. has already been removed). */
     55    bool        fIgnoreNonExisting;
    5256    /** Whether to always use the VFS chain API (for testing). */
    5357    bool        fAlwaysUseChainApi;
    54     /** Directory creation flags (RTDIRCREATE_FLAGS_XXX).   */
    55     uint32_t    fCreateFlags;
    56     /** The directory mode. */
    57     RTFMODE     fMode;
    58 } RTCMDMKDIROPTS;
     58} RTCMDRMDIROPTS;
    5959
    6060
     
    6666 * @param   pszDir              The path to the new directory.
    6767 */
    68 static int rtCmdMkDirOneWithParents(RTCMDMKDIROPTS const *pOpts, const char *pszDir)
    69 {
     68static int rtCmdRmDirOneWithParents(RTCMDRMDIROPTS const *pOpts, const char *pszDir)
     69{
     70    /* We need a copy we can work with here. */
     71    char *pszCopy = RTStrDup(pszDir);
     72    if (!pszCopy)
     73        return RTMsgErrorExitFailure("Out of string memory!");
     74
    7075    int rc;
    7176    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) )
    7277    {
    73         /*
    74          * Use the API for doing the entire job.  Unfortuantely, this means we
    75          * can't be very  verbose about what we're doing.
    76          */
    77         rc = RTDirCreateFullPath(pszDir, pOpts->fMode);
    78         if (RT_FAILURE(rc))
    79             RTMsgError("Failed to create directory '%s' (or a parent): %Rrc", pszDir, rc);
    80         else if (pOpts->fVerbose)
    81             RTPrintf("%s\n", pszDir);
     78        size_t cchCopy = strlen(pszCopy);
     79        do
     80        {
     81            rc = RTDirRemove(pszCopy);
     82            if (RT_SUCCESS(rc))
     83            {
     84                if (pOpts->fVerbose)
     85                    RTPrintf("%s\n", pszCopy);
     86            }
     87            else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
     88                rc = VINF_SUCCESS;
     89            else
     90            {
     91                if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
     92                    rc = VINF_SUCCESS;
     93                else
     94                    RTMsgError("Failed to remove directory '%s': %Rrc", pszCopy, rc);
     95                break;
     96            }
     97
     98            /* Strip off a component. */
     99            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
     100                cchCopy--;
     101            while (cchCopy > 0 && !RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
     102                cchCopy--;
     103            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
     104                cchCopy--;
     105            pszCopy[cchCopy] = '\0';
     106        } while (cchCopy > 0);
    82107    }
    83108    else
     
    86111         * Strip the final path element from the pszDir spec.
    87112         */
    88         char *pszCopy = RTStrDup(pszDir);
    89         if (!pszCopy)
    90             return RTMsgErrorExitFailure("Out of string memory!");
    91 
    92113        char       *pszFinalPath;
    93114        char       *pszSpec;
     
    96117        if (RT_SUCCESS(rc))
    97118        {
    98             const char * const pszFullFinalPath = pszFinalPath;
    99 
    100119            /*
    101120             * Open the root director/whatever.
    102121             */
    103122            RTERRINFOSTATIC ErrInfo;
    104             RTVFSDIR hVfsCurDir;
     123            RTVFSDIR hVfsBaseDir;
    105124            if (pszSpec)
    106125            {
    107                 rc = RTVfsChainOpenDir(pszSpec, 0 /*fOpen*/, &hVfsCurDir, &offError, RTErrInfoInitStatic(&ErrInfo));
     126                rc = RTVfsChainOpenDir(pszSpec, 0 /*fOpen*/, &hVfsBaseDir, &offError, RTErrInfoInitStatic(&ErrInfo));
    108127                if (RT_FAILURE(rc))
    109128                    RTVfsChainMsgError("RTVfsChainOpenDir", pszSpec, rc, offError, &ErrInfo.Core);
     129                else if (!pszFinalPath)
     130                    pszFinalPath = RTStrEnd(pszSpec, RTSTR_MAX);
    110131            }
    111132            else if (!RTPathStartsWithRoot(pszFinalPath))
    112133            {
    113                 rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsCurDir);
     134                rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsBaseDir);
    114135                if (RT_FAILURE(rc))
    115136                    RTMsgError("Failed to open '.' (for %s): %Rrc", rc, pszFinalPath);
     
    121142                char const chSaved = *pszFinalPath;
    122143                *pszFinalPath = '\0';
    123                 rc = RTVfsDirOpenNormal(pszRoot, 0 /*fOpen*/, &hVfsCurDir);
     144                rc = RTVfsDirOpenNormal(pszRoot, 0 /*fOpen*/, &hVfsBaseDir);
    124145                *pszFinalPath = chSaved;
    125146                if (RT_FAILURE(rc))
     
    128149
    129150            /*
    130              * Walk the path component by component.
     151             * Walk the path component by component, starting at the end.
    131152             */
    132             while (RT_SUCCESS(rc))
    133             {
    134                 /*
    135                  * Strip leading slashes.
    136                  */
    137                 while (RTPATH_IS_SLASH(*pszFinalPath))
    138                     pszFinalPath++;
    139                 if (*pszFinalPath == '\0')
     153            if (RT_SUCCESS(rc))
     154            {
     155                size_t cchFinalPath = strlen(pszFinalPath);
     156                while (RT_SUCCESS(rc) && cchFinalPath > 0)
    140157                {
    141                     RTVfsDirRelease(hVfsCurDir);
    142                     break;
    143                 }
    144 
    145                 /*
    146                  * Find the end of the next path component.
    147                  */
    148                 size_t cchComponent = 0;
    149                 char   ch;
    150                 while (   (ch = pszFinalPath[cchComponent]) != '\0'
    151                        && !RTPATH_IS_SLASH(ch))
    152                     cchComponent++;
    153 
    154                 /*
    155                  * Open or create the component.
    156                  */
    157                 pszFinalPath[cchComponent] = '\0';
    158                 RTVFSDIR hVfsNextDir = NIL_RTVFSDIR;
    159                 for (uint32_t cTries = 0; cTries < 8; cTries++)
    160                 {
    161                     /* Try open it. */
    162                     rc = RTVfsDirOpenDir(hVfsCurDir, pszFinalPath, 0 /*fFlags*/, &hVfsNextDir);
     158                    rc = RTVfsDirRemoveDir(hVfsBaseDir, pszFinalPath, 0 /*fFlags*/);
    163159                    if (RT_SUCCESS(rc))
    164                         break;
    165                     if (   rc != VERR_FILE_NOT_FOUND
    166                         && rc != VERR_PATH_NOT_FOUND)
    167160                    {
    168                         if (ch == '\0')
    169                             RTMsgError("Failed opening directory '%s': %Rrc", pszDir, rc);
     161                        if (pOpts->fVerbose)
     162                            RTPrintf("%s\n", pszCopy);
     163                    }
     164                    else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
     165                        rc = VINF_SUCCESS;
     166                    else
     167                    {
     168                        if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
     169                            rc = VINF_SUCCESS;
     170                        else if (pszSpec)
     171                            RTMsgError("Failed to remove directory '%s:%s': %Rrc", pszSpec, pszFinalPath, rc);
    170172                        else
    171                             RTMsgError("Failed opening dir '%s' (for creating '%s'): %Rrc", pszFullFinalPath, pszDir, rc);
     173                            RTMsgError("Failed to remove directory '%s': %Rrc", pszFinalPath, rc);
    172174                        break;
    173175                    }
    174176
    175                     /* Not found, so try create it. */
    176                     rc = RTVfsDirCreateDir(hVfsCurDir, pszFinalPath, pOpts->fMode, pOpts->fCreateFlags, &hVfsNextDir);
    177                     if (rc == VERR_ALREADY_EXISTS)
    178                         continue; /* We lost a creation race, try again. */
    179                     if (RT_SUCCESS(rc) && pOpts->fVerbose)
    180                     {
    181                         if (pszSpec)
    182                             RTPrintf("%s:%s\n", pszSpec, pszFullFinalPath);
    183                         else
    184                             RTPrintf("%s\n", pszFullFinalPath);
    185                     }
    186                     else if (RT_FAILURE(rc))
    187                     {
    188                         if (ch == '\0')
    189                             RTMsgError("Failed creating directory '%s': %Rrc", pszDir, rc);
    190                         else
    191                             RTMsgError("Failed creating dir '%s' (for '%s'): %Rrc", pszFullFinalPath, pszDir, rc);
    192                     }
    193                     break;
     177                    /* Strip off a component. */
     178                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
     179                        cchFinalPath--;
     180                    while (cchFinalPath > 0 && !RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
     181                        cchFinalPath--;
     182                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
     183                        cchFinalPath--;
     184                    pszFinalPath[cchFinalPath] = '\0';
    194185                }
    195                 pszFinalPath[cchComponent] = ch;
    196 
    197                 RTVfsDirRelease(hVfsCurDir);
    198                 hVfsCurDir = hVfsNextDir;
    199                 pszFinalPath += cchComponent;
     186
     187                RTVfsDirRelease(hVfsBaseDir);
    200188            }
    201189        }
    202190        else
    203191            RTVfsChainMsgError("RTVfsChainOpenParentDir", pszCopy, rc, offError, NULL);
    204         RTStrFree(pszCopy);
    205     }
     192    }
     193    RTStrFree(pszCopy);
    206194    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    207195}
     
    209197
    210198/**
    211  * Create one directory.
     199 * Removes one directory.
    212200 *
    213201 * @returns exit code
     
    215203 * @param   pszDir              The path to the new directory.
    216204 */
    217 static RTEXITCODE rtCmdMkDirOne(RTCMDMKDIROPTS const *pOpts, const char *pszDir)
     205static RTEXITCODE rtCmdRmDirOne(RTCMDRMDIROPTS const *pOpts, const char *pszDir)
    218206{
    219207    int rc;
    220208    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) )
    221         rc = RTDirCreate(pszDir, pOpts->fMode, 0);
     209        rc = RTDirRemove(pszDir);
    222210    else
    223211    {
     
    229217        if (RT_SUCCESS(rc))
    230218        {
    231             rc = RTVfsDirCreateDir(hVfsDir, pszChild, pOpts->fMode, 0 /*fFlags*/, NULL);
     219            rc = RTVfsDirRemoveDir(hVfsDir, pszChild, 0 /*fFlags*/);
    232220            RTVfsDirRelease(hVfsDir);
    233221        }
     
    241229        return RTEXITCODE_SUCCESS;
    242230    }
    243     return RTMsgErrorExitFailure("Failed to create '%s': %Rrc", pszDir, rc);
     231    if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
     232        return RTEXITCODE_SUCCESS; /** @todo be verbose about this? */
     233    if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
     234        return RTEXITCODE_SUCCESS; /** @todo be verbose about this? */
     235    return RTMsgErrorExitFailure("Failed to remove '%s': %Rrc", pszDir, rc);
    244236}
    245237
    246238
    247 static RTEXITCODE RTCmdMkDir(unsigned cArgs,  char **papszArgs)
     239static RTEXITCODE RTCmdRmDir(unsigned cArgs,  char **papszArgs)
    248240{
    249241    /*
     
    253245    {
    254246        /* operations */
    255         { "--mode",                     'm', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
    256247        { "--parents",                  'p', RTGETOPT_REQ_NOTHING },
     248        { "--ignore-fail-on-non-empty", 'F', RTGETOPT_REQ_NOTHING },
     249        { "--ignore-non-existing",      'E', RTGETOPT_REQ_NOTHING },
    257250        { "--always-use-vfs-chain-api", 'A', RTGETOPT_REQ_NOTHING },
    258         { "--allow-content-indexing",   'i', RTGETOPT_REQ_NOTHING },
    259251        { "--verbose",                  'v', RTGETOPT_REQ_NOTHING },
    260252    };
     
    266258        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);
    267259
    268     RTCMDMKDIROPTS Opts;
     260    RTCMDRMDIROPTS Opts;
    269261    Opts.fVerbose               = false;
    270262    Opts.fParents               = false;
     263    Opts.fIgnoreNotEmpty        = false;
     264    Opts.fIgnoreNonExisting     = false;
    271265    Opts.fAlwaysUseChainApi     = false;
    272     Opts.fCreateFlags           = RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET;
    273     Opts.fMode                  = 0775 | RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY;
    274266
    275267    RTGETOPTUNION ValueUnion;
     
    279271        switch (rc)
    280272        {
    281             case 'm':
    282                 /** @todo DOS+NT attributes and symbolic notation. */
    283                 Opts.fMode &= ~07777;
    284                 Opts.fMode |= ValueUnion.u32 & 07777;
    285                 break;
    286 
    287273            case 'p':
    288274                Opts.fParents = true;
     
    297283                break;
    298284
    299             case 'i':
    300                 Opts.fCreateFlags &= ~RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET;
    301                 Opts.fCreateFlags |= RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET;
     285            case 'E':
     286                Opts.fIgnoreNonExisting = true;
     287                break;
     288
     289            case 'F':
     290                Opts.fIgnoreNotEmpty = true;
    302291                break;
    303292
     
    305294                RTPrintf("Usage: %s [options] <dir> [..]\n"
    306295                         "\n"
     296                         "Removes empty directories.\n"
     297                         "\n"
    307298                         "Options:\n"
    308                          "  -m <mode>, --mode <mode>\n"
    309                          "      The creation mode. Default is 0775.\n"
    310299                         "  -p, --parent\n"
    311                          "      Create parent directories too. Ignore any existing directories.\n"
     300                         "      Remove specified parent directories too.\n"
     301                         "  -F, --ignore-fail-on-non-empty\n"
     302                         "      Do not fail if a directory is not empty, just ignore it.\n"
     303                         "      This is really handy with the -p option.\n"
     304                         "  -E, --ignore-non-existing\n"
     305                         "      Do not fail if a specified directory is not there.\n"
    312306                         "  -v, --verbose\n"
    313                          "      Tell which directories get created.\n"
     307                         "      Tell which directories get remove.\n"
    314308                         "  -A, --always-use-vfs-chain-api\n"
    315309                         "      Always use the VFS API.\n"
    316                          "  -i, --allow-content-indexing\n"
    317                          "      Don't set flags to disable context indexing on windows.\n"
    318310                         , papszArgs[0]);
    319311                return RTEXITCODE_SUCCESS;
     
    342334    {
    343335        if (Opts.fParents)
    344             rc = rtCmdMkDirOneWithParents(&Opts, ValueUnion.psz);
     336            rc = rtCmdRmDirOneWithParents(&Opts, ValueUnion.psz);
    345337        else
    346             rc = rtCmdMkDirOne(&Opts, ValueUnion.psz);
     338            rc = rtCmdRmDirOne(&Opts, ValueUnion.psz);
    347339        if (RT_FAILURE(rc))
    348340            rcExit = RTEXITCODE_FAILURE;
     
    363355    if (RT_FAILURE(rc))
    364356        return RTMsgInitFailure(rc);
    365     return RTCmdMkDir(argc, argv);
     357    return RTCmdRmDir(argc, argv);
    366358}
    367359
Note: See TracChangeset for help on using the changeset viewer.

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