示例#1
0
/**
 * Opens the output file.
 *
 * @returns Command exit, error messages written using RTMsg*.
 *
 * @param   pszFile             The input filename.
 * @param   pOpts               The options, szOutput will be filled in by this
 *                              function on success.
 * @param   phVfsIos            Where to return the output stream handle.
 *
 * @remarks This is actually not quite the way we need to do things.
 *
 *          First of all, we need a GZIP file system stream for a real GZIP
 *          implementation, since there may be more than one file in the gzipped
 *          file.
 *
 *          Second, we need to open the output files as we encounter files in the input
 *          file system stream. The gzip format contains timestamp and usually a
 *          filename, the default is to use this name (see the --no-name
 *          option).
 */
static RTEXITCODE gzipOpenOutput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos)
{
    int rc;
    if (!strcmp(pszFile, "-") || pOpts->fStdOut)
    {
        strcpy(pOpts->szOutput, "-");

        if (   !pOpts->fForce
            && !pOpts->fDecompress
            && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT))
            return RTMsgErrorExit(RTEXITCODE_SYNTAX,
                                  "Yeah, right. I'm not writing any compressed data to the terminal without --force.\n");

        rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT,
                                      RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
                                      true /*fLeaveOpen*/,
                                      phVfsIos);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard output: %Rrc", rc);
    }
    else
    {
        Assert(!RTVfsChainIsSpec(pszFile));

        /* Construct an output filename. */
        rc = RTStrCopy(pOpts->szOutput, sizeof(pOpts->szOutput), pszFile);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc);
        if (pOpts->fDecompress)
        {
            /** @todo take filename from archive? */
            size_t cchSuff = strlen(pOpts->pszSuff); Assert(cchSuff > 0);
            size_t cch = strlen(pOpts->szOutput);
            if (   cch <= cchSuff
                || strcmp(&pOpts->szOutput[cch - cchSuff], pOpts->pszSuff))
                return RTMsgErrorExit(RTEXITCODE_FAILURE, "Input file does not end with: '%s'", pOpts->pszSuff);
            pOpts->szOutput[cch - cchSuff] = '\0';
            if (!RTPathFilename(pOpts->szOutput))
                return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: Input file name is all suffix.");
        }
        else
        {
            rc = RTStrCat(pOpts->szOutput, sizeof(pOpts->szOutput), pOpts->pszSuff);
            if (RT_FAILURE(rc))
                return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc);
        }

        /* Open the output file. */
        uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;
        if (pOpts->fForce)
            fOpen |= RTFILE_O_CREATE_REPLACE;
        else
            fOpen |= RTFILE_O_CREATE;
        rc = RTVfsIoStrmOpenNormal(pOpts->szOutput, fOpen, phVfsIos);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening output file '%s': %Rrc", pOpts->szOutput, rc);
    }

    return RTEXITCODE_SUCCESS;
}
/**
 * Recursively changes the file mode.
 *
 * @returns exit code
 * @param   pOpts               The mkdir option.
 * @param   pszPath             The path to start changing the mode of.
 */
static int rtCmdChModRecursive(RTCMDCHMODOPTS const *pOpts, const char *pszPath)
{
    /*
     * Check if it's a directory first.  If not, join the non-recursive code.
     */
    int             rc;
    uint32_t        offError;
    RTFSOBJINFO     ObjInfo;
    RTERRINFOSTATIC ErrInfo;
    bool const      fUseChainApi = pOpts->fAlwaysUseChainApi || RTVfsChainIsSpec(pszPath);
    if (!fUseChainApi)
    {
        rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
        if (RT_FAILURE(rc))
            return RTMsgErrorExitFailure("RTPathQueryInfoEx failed on '%s': %Rrc", pszPath, rc);
    }
    else
    {
        rc = RTVfsChainQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK,
                                 &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_FAILURE(rc))
            return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
    }

    if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
    {
        /*
         * Don't bother redoing the above work if its not necessary.
         */
        RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
        if (fNewMode != ObjInfo.Attr.fMode)
            return rtCmdChModOne(pOpts, pszPath);
        if (pOpts->enmNoiseLevel >= kRTCmdChModNoise_Verbose)
            RTPrintf("%s\n", pszPath);
        return RTEXITCODE_SUCCESS;
    }

    /*
     * For recursion we always use the VFS layer.
     */
    RTVFSDIR hVfsDir;
    if (!fUseChainApi)
    {
        rc = RTVfsDirOpenNormal(pszPath, 0 /** @todo write attrib flag*/, &hVfsDir);
        if (RT_FAILURE(rc))
            return RTMsgErrorExitFailure("RTVfsDirOpenNormal failed on '%s': %Rrc", pszPath, rc);
    }
    else
    {
        rc = RTVfsChainOpenDir(pszPath, 0 /** @todo write attrib flag*/, &hVfsDir, &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_FAILURE(rc))
            return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
    }

    RTMsgError("Recursion is not yet implemented\n");
    RTVfsDirRelease(hVfsDir);
    rc = VERR_NOT_IMPLEMENTED;

    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
/**
 * Changes the file mode of one file system object.
 *
 * @returns exit code
 * @param   pOpts               The chmod options.
 * @param   pszPath             The path to the file system object to change the
 *                              file mode of.
 */
static RTEXITCODE rtCmdChModOne(RTCMDCHMODOPTS const *pOpts, const char *pszPath)
{
    int         rc;
    RTFSOBJINFO ObjInfo;
    bool        fChanges = false;
    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszPath) )
    {
        rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
        if (RT_SUCCESS(rc))
        {
            RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
            fChanges = fNewMode != ObjInfo.Attr.fMode;
            if (fChanges)
            {
                rc = RTPathSetMode(pszPath, fNewMode);
                if (RT_FAILURE(rc))
                    RTMsgError("RTPathSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
            }
        }
        else
            RTMsgError("RTPathQueryInfoEx failed on '%s': %Rrc", pszPath, rc);
    }
    else
    {
        RTVFSOBJ        hVfsObj;
        uint32_t        offError;
        RTERRINFOSTATIC ErrInfo;
        rc = RTVfsChainOpenObj(pszPath, RTFILE_O_ACCESS_ATTR_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
                               RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_FOLLOW_LINK,
                               &hVfsObj, &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_SUCCESS(rc))
        {
            rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
            if (RT_SUCCESS(rc))
            {
                RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
                fChanges = fNewMode != ObjInfo.Attr.fMode;
                if (fChanges)
                {
                    rc = RTVfsObjSetMode(hVfsObj, fNewMode, RTCHMOD_SET_ALL_MASK);
                    if (RT_FAILURE(rc))
                        RTMsgError("RTVfsObjSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
                }
            }
            else
                RTVfsChainMsgError("RTVfsObjQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
            RTVfsObjRelease(hVfsObj);
        }
        else
            RTVfsChainMsgError("RTVfsChainOpenObject", pszPath, rc, offError, &ErrInfo.Core);
    }

    if (RT_SUCCESS(rc))
    {
        if (pOpts->enmNoiseLevel >= (fChanges ? kRTCmdChModNoise_Changes : kRTCmdChModNoise_Verbose))
            RTPrintf("%s\n", pszPath);
        return RTEXITCODE_SUCCESS;
    }
    return RTEXITCODE_FAILURE;
}
/**
 * Removes one directory.
 *
 * @returns exit code
 * @param   pOpts               The mkdir option.
 * @param   pszDir              The path to the new directory.
 */
static RTEXITCODE rtCmdRmDirOne(RTCMDRMDIROPTS const *pOpts, const char *pszDir)
{
    int rc;
    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) )
        rc = RTDirRemove(pszDir);
    else
    {
        RTVFSDIR        hVfsDir;
        const char     *pszChild;
        uint32_t        offError;
        RTERRINFOSTATIC ErrInfo;
        rc = RTVfsChainOpenParentDir(pszDir, 0 /*fOpen*/, &hVfsDir, &pszChild, &offError, RTErrInfoInitStatic(&ErrInfo));
        if (RT_SUCCESS(rc))
        {
            rc = RTVfsDirRemoveDir(hVfsDir, pszChild, 0 /*fFlags*/);
            RTVfsDirRelease(hVfsDir);
        }
        else
            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenParentDir", pszDir, rc, offError, &ErrInfo.Core);
    }
    if (RT_SUCCESS(rc))
    {
        if (pOpts->fVerbose)
            RTPrintf("%s\n", pszDir);
        return RTEXITCODE_SUCCESS;
    }
    if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
        return RTEXITCODE_SUCCESS; /** @todo be verbose about this? */
    if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
        return RTEXITCODE_SUCCESS; /** @todo be verbose about this? */
    return RTMsgErrorExitFailure("Failed to remove '%s': %Rrc", pszDir, rc);
}
示例#5
0
/**
 * A mini GZIP program.
 *
 * @returns Program exit code.
 *
 * @param   cArgs               The number of arguments.
 * @param   papszArgs           The argument vector.  (Note that this may be
 *                              reordered, so the memory must be writable.)
 */
RTEXITCODE RTZipGzipCmd(unsigned cArgs, char **papszArgs)
{

    /*
     * Parse the command line.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        { "--ascii",        'a', RTGETOPT_REQ_NOTHING },
        { "--stdout",       'c', RTGETOPT_REQ_NOTHING },
        { "--to-stdout",    'c', RTGETOPT_REQ_NOTHING },
        { "--decompress",   'd', RTGETOPT_REQ_NOTHING },
        { "--uncompress",   'd', RTGETOPT_REQ_NOTHING },
        { "--force",        'f', RTGETOPT_REQ_NOTHING },
        { "--keep",         'k', RTGETOPT_REQ_NOTHING },
        { "--list",         'l', RTGETOPT_REQ_NOTHING },
        { "--no-name",      'n', RTGETOPT_REQ_NOTHING },
        { "--name",         'N', RTGETOPT_REQ_NOTHING },
        { "--quiet",        'q', RTGETOPT_REQ_NOTHING },
        { "--recursive",    'r', RTGETOPT_REQ_NOTHING },
        { "--suffix",       'S', RTGETOPT_REQ_STRING  },
        { "--test",         't', RTGETOPT_REQ_NOTHING },
        { "--verbose",      'v', RTGETOPT_REQ_NOTHING },
        { "--fast",         '1', RTGETOPT_REQ_NOTHING },
        { "-1",             '1', RTGETOPT_REQ_NOTHING },
        { "-2",             '2', RTGETOPT_REQ_NOTHING },
        { "-3",             '3', RTGETOPT_REQ_NOTHING },
        { "-4",             '4', RTGETOPT_REQ_NOTHING },
        { "-5",             '5', RTGETOPT_REQ_NOTHING },
        { "-6",             '6', RTGETOPT_REQ_NOTHING },
        { "-7",             '7', RTGETOPT_REQ_NOTHING },
        { "-8",             '8', RTGETOPT_REQ_NOTHING },
        { "-9",             '9', RTGETOPT_REQ_NOTHING },
        { "--best",         '9', RTGETOPT_REQ_NOTHING }
    };

    RTGZIPCMDOPTS Opts;
    Opts.fAscii      = false;
    Opts.fStdOut     = false;
    Opts.fDecompress = false;
    Opts.fForce      = false;
    Opts.fKeep       = false;
    Opts.fList       = false;
    Opts.fName       = true;
    Opts.fQuiet      = false;
    Opts.fRecursive  = false;
    Opts.pszSuff     = ".gz";
    Opts.fTest       = false;
    Opts.uLevel      = 6;

    RTEXITCODE  rcExit      = RTEXITCODE_SUCCESS;
    unsigned    cProcessed  = 0;
    //RTVFSIOSTREAM hVfsStdOut= NIL_RTVFSIOSTREAM;

    RTGETOPTSTATE GetState;
    int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
                          RTGETOPTINIT_FLAGS_OPTS_FIRST);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);

    for (;;)
    {
        RTGETOPTUNION ValueUnion;
        int chOpt = RTGetOpt(&GetState, &ValueUnion);
        switch (chOpt)
        {
            case 0:
                /*
                 * If we've processed any files we're done.  Otherwise take
                 * input from stdin and write the output to stdout.
                 */
                if (cProcessed > 0)
                    return rcExit;
                ValueUnion.psz = "-";
                Opts.fStdOut = true;
                /* Fall thru. */
            case VINF_GETOPT_NOT_OPTION:
            {
                if (!*Opts.pszSuff && !Opts.fStdOut)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --suffix option specified an empty string");
                if (!Opts.fStdOut && RTVfsChainIsSpec(ValueUnion.psz))
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Must use standard out with VFS chain specifications");
                if (Opts.fName)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --name option has not yet been implemented. Use --no-name.");
                if (Opts.fAscii)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --ascii option has not yet been implemented.");
                if (Opts.fRecursive)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --recursive option has not yet been implemented.");

                /* Open the input file. */
                RTVFSIOSTREAM hVfsSrc;
                RTEXITCODE rcExit2 = gzipOpenInput(ValueUnion.psz, &Opts, &hVfsSrc);
                if (rcExit2 == RTEXITCODE_SUCCESS)
                {
                    if (Opts.fList)
                        rcExit2 = gzipListFile(&hVfsSrc, &Opts);
                    else if (Opts.fTest)
                        rcExit2 = gzipTestFile(&hVfsSrc, &Opts);
                    else
                    {
                        RTVFSIOSTREAM hVfsDst;
                        rcExit2 = gzipOpenOutput(ValueUnion.psz, &Opts, &hVfsDst);
                        if (rcExit2 == RTEXITCODE_SUCCESS)
                        {
                            if (Opts.fDecompress)
                                rcExit2 = gzipDecompressFile(&hVfsSrc, &Opts, &hVfsDst);
                            else
                                rcExit2 = gzipCompressFile(&hVfsSrc, &Opts, &hVfsDst);
                            RTVfsIoStrmRelease(hVfsDst);
                        }
                    }
                    RTVfsIoStrmRelease(hVfsSrc);
                }
                if (rcExit2 != RTEXITCODE_SUCCESS)
                    rcExit = rcExit2;

                cProcessed++;
                break;
            }

            case 'a':   Opts.fAscii      = true;  break;
            case 'c':
                Opts.fStdOut = true;
                Opts.fKeep   = true;
                break;
            case 'd':   Opts.fDecompress = true;  break;
            case 'f':   Opts.fForce      = true;  break;
            case 'k':   Opts.fKeep       = true;  break;
            case 'l':   Opts.fList       = true;  break;
            case 'n':   Opts.fName       = false; break;
            case 'N':   Opts.fName       = true;  break;
            case 'q':   Opts.fQuiet      = true;  break;
            case 'r':   Opts.fRecursive  = true;  break;
            case 'S':   Opts.pszSuff     = ValueUnion.psz; break;
            case 't':   Opts.fTest       = true;  break;
            case 'v':   Opts.fQuiet      = false; break;
            case '1':   Opts.uLevel      = 1;     break;
            case '2':   Opts.uLevel      = 2;     break;
            case '3':   Opts.uLevel      = 3;     break;
            case '4':   Opts.uLevel      = 4;     break;
            case '5':   Opts.uLevel      = 5;     break;
            case '6':   Opts.uLevel      = 6;     break;
            case '7':   Opts.uLevel      = 7;     break;
            case '8':   Opts.uLevel      = 8;     break;
            case '9':   Opts.uLevel      = 9;     break;

            case 'h':
                RTPrintf("Usage: to be written\nOption dump:\n");
                for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
                    RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
                return RTEXITCODE_SUCCESS;

            case 'V':
                RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
                return RTEXITCODE_SUCCESS;

            default:
                return RTGetOptPrintError(chOpt, &ValueUnion);
        }
    }
}
/**
 * Create one directory and any missing parent directories.
 *
 * @returns exit code
 * @param   pOpts               The mkdir option.
 * @param   pszDir              The path to the new directory.
 */
static int rtCmdRmDirOneWithParents(RTCMDRMDIROPTS const *pOpts, const char *pszDir)
{
    /* We need a copy we can work with here. */
    char *pszCopy = RTStrDup(pszDir);
    if (!pszCopy)
        return RTMsgErrorExitFailure("Out of string memory!");

    int rc;
    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) )
    {
        size_t cchCopy = strlen(pszCopy);
        do
        {
            rc = RTDirRemove(pszCopy);
            if (RT_SUCCESS(rc))
            {
                if (pOpts->fVerbose)
                    RTPrintf("%s\n", pszCopy);
            }
            else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
                rc = VINF_SUCCESS;
            else
            {
                if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
                    rc = VINF_SUCCESS;
                else
                    RTMsgError("Failed to remove directory '%s': %Rrc", pszCopy, rc);
                break;
            }

            /* Strip off a component. */
            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            while (cchCopy > 0 && !RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            pszCopy[cchCopy] = '\0';
        } while (cchCopy > 0);
    }
    else
    {
        /*
         * Strip the final path element from the pszDir spec.
         */
        char       *pszFinalPath;
        char       *pszSpec;
        uint32_t    offError;
        rc = RTVfsChainSplitOffFinalPath(pszCopy, &pszSpec, &pszFinalPath, &offError);
        if (RT_SUCCESS(rc))
        {
            /*
             * Open the root director/whatever.
             */
            RTERRINFOSTATIC ErrInfo;
            RTVFSDIR hVfsBaseDir;
            if (pszSpec)
            {
                rc = RTVfsChainOpenDir(pszSpec, 0 /*fOpen*/, &hVfsBaseDir, &offError, RTErrInfoInitStatic(&ErrInfo));
                if (RT_FAILURE(rc))
                    RTVfsChainMsgError("RTVfsChainOpenDir", pszSpec, rc, offError, &ErrInfo.Core);
                else if (!pszFinalPath)
                    pszFinalPath = RTStrEnd(pszSpec, RTSTR_MAX);
            }
            else if (!RTPathStartsWithRoot(pszFinalPath))
            {
                rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsBaseDir);
                if (RT_FAILURE(rc))
                    RTMsgError("Failed to open '.' (for %s): %Rrc", rc, pszFinalPath);
            }
            else
            {
                char *pszRoot = pszFinalPath;
                pszFinalPath = RTPathSkipRootSpec(pszFinalPath);
                char const chSaved = *pszFinalPath;
                *pszFinalPath = '\0';
                rc = RTVfsDirOpenNormal(pszRoot, 0 /*fOpen*/, &hVfsBaseDir);
                *pszFinalPath = chSaved;
                if (RT_FAILURE(rc))
                    RTMsgError("Failed to open root dir for '%s': %Rrc", rc, pszRoot);
            }

            /*
             * Walk the path component by component, starting at the end.
             */
            if (RT_SUCCESS(rc))
            {
                size_t cchFinalPath = strlen(pszFinalPath);
                while (RT_SUCCESS(rc) && cchFinalPath > 0)
                {
                    rc = RTVfsDirRemoveDir(hVfsBaseDir, pszFinalPath, 0 /*fFlags*/);
                    if (RT_SUCCESS(rc))
                    {
                        if (pOpts->fVerbose)
                            RTPrintf("%s\n", pszCopy);
                    }
                    else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
                        rc = VINF_SUCCESS;
                    else
                    {
                        if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
                            rc = VINF_SUCCESS;
                        else if (pszSpec)
                            RTMsgError("Failed to remove directory '%s:%s': %Rrc", pszSpec, pszFinalPath, rc);
                        else
                            RTMsgError("Failed to remove directory '%s': %Rrc", pszFinalPath, rc);
                        break;
                    }

                    /* Strip off a component. */
                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    while (cchFinalPath > 0 && !RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    pszFinalPath[cchFinalPath] = '\0';
                }

                RTVfsDirRelease(hVfsBaseDir);
            }
        }
        else
            RTVfsChainMsgError("RTVfsChainOpenParentDir", pszCopy, rc, offError, NULL);
    }
    RTStrFree(pszCopy);
    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
示例#7
0
int main(int argc, char **argv)
{
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    /*
     * Parse the command line.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        { "--ascii",        'a', RTGETOPT_REQ_NOTHING },
        { "--stdout",       'c', RTGETOPT_REQ_NOTHING },
        { "--to-stdout",    'c', RTGETOPT_REQ_NOTHING },
        { "--decompress",   'd', RTGETOPT_REQ_NOTHING },
        { "--uncompress",   'd', RTGETOPT_REQ_NOTHING },
        { "--force",        'f', RTGETOPT_REQ_NOTHING },
        { "--list",         'l', RTGETOPT_REQ_NOTHING },
        { "--no-name",      'n', RTGETOPT_REQ_NOTHING },
        { "--name",         'N', RTGETOPT_REQ_NOTHING },
        { "--quiet",        'q', RTGETOPT_REQ_NOTHING },
        { "--recursive",    'r', RTGETOPT_REQ_NOTHING },
        { "--suffix",       'S', RTGETOPT_REQ_STRING  },
        { "--test",         't', RTGETOPT_REQ_NOTHING },
        { "--verbose",      'v', RTGETOPT_REQ_NOTHING },
        { "--fast",         '1', RTGETOPT_REQ_NOTHING },
        { "-1",             '1', RTGETOPT_REQ_NOTHING },
        { "-2",             '2', RTGETOPT_REQ_NOTHING },
        { "-3",             '3', RTGETOPT_REQ_NOTHING },
        { "-4",             '4', RTGETOPT_REQ_NOTHING },
        { "-5",             '5', RTGETOPT_REQ_NOTHING },
        { "-6",             '6', RTGETOPT_REQ_NOTHING },
        { "-7",             '7', RTGETOPT_REQ_NOTHING },
        { "-8",             '8', RTGETOPT_REQ_NOTHING },
        { "-9",             '9', RTGETOPT_REQ_NOTHING },
        { "--best",         '9', RTGETOPT_REQ_NOTHING }
    };

    bool        fAscii      = false;
    bool        fStdOut     = false;
    bool        fDecompress = false;
    bool        fForce      = false;
    bool        fList       = false;
    bool        fName       = true;
    bool        fQuiet      = false;
    bool        fRecursive  = false;
    const char *pszSuff     = ".gz";
    bool        fTest       = false;
    unsigned    uLevel      = 6;

    RTEXITCODE  rcExit      = RTEXITCODE_SUCCESS;
    unsigned    cProcessed  = 0;
    RTVFSIOSTREAM hVfsStdOut= NIL_RTVFSIOSTREAM;

    RTGETOPTSTATE GetState;
    rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
                      RTGETOPTINIT_FLAGS_OPTS_FIRST);
    for (;;)
    {
        RTGETOPTUNION ValueUnion;
        rc = RTGetOpt(&GetState, &ValueUnion);
        switch (rc)
        {
        case 0:
        {
            /*
             * If we've processed any files we're done.  Otherwise take
             * input from stdin and write the output to stdout.
             */
            if (cProcessed > 0)
                return rcExit;
#if 0
            rc = RTVfsFileFromRTFile(1,
                                     RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
                                     true /*fLeaveOpen*/,
                                     &hVfsOut);


            if (!fForce && isStdHandleATty(fDecompress ? 0 : 1))
                return RTMsgErrorExit(RTEXITCODE_SYNTAX,
                                      "Yeah, right. I'm not %s any compressed data %s the terminal without --force.\n",
                                      fDecompress ? "reading" : "writing",
                                      fDecompress ? "from"    : "to");
#else
            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "reading from standard input has not yet been implemented");
#endif
            return rcExit;
        }

        case VINF_GETOPT_NOT_OPTION:
        {
            if (!*pszSuff && !fStdOut)
                return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --suffix option specified an empty string");
            if (!fStdOut && RTVfsChainIsSpec(ValueUnion.psz))
                return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Must use standard out with VFS chain specifications");

            RTEXITCODE rcExit2;
            if (fList)
                rcExit2 = gzipListFile(ValueUnion.psz, fForce);
            else if (fTest)
                rcExit2 = gzipTestFile(ValueUnion.psz, fForce);
            else if (fDecompress)
                rcExit2 = gzipDecompressFile(ValueUnion.psz, fStdOut, fForce, &hVfsStdOut);
            else
                rcExit2 = gzipCompressFile(ValueUnion.psz, fStdOut, fForce, &hVfsStdOut);
            if (rcExit2 != RTEXITCODE_SUCCESS)
                rcExit = rcExit2;

            cProcessed++;
            break;
        }

        case 'a':
            fAscii      = true;
            break;
        case 'c':
            fStdOut     = true;
            break;
        case 'd':
            fDecompress = true;
            break;
        case 'f':
            fForce      = true;
            break;
        case 'l':
            fList       = true;
            break;
        case 'n':
            fName       = false;
            break;
        case 'N':
            fName       = true;
            break;
        case 'q':
            fQuiet      = true;
            break;
        case 'r':
            fRecursive  = true;
            break;
        case 'S':
            pszSuff     = ValueUnion.psz;
            break;
        case 't':
            fTest       = true;
            break;
        case 'v':
            fQuiet      = false;
            break;
        case '1':
            uLevel      = 1;
            break;
        case '2':
            uLevel      = 2;
            break;
        case '3':
            uLevel      = 3;
            break;
        case '4':
            uLevel      = 4;
            break;
        case '5':
            uLevel      = 5;
            break;
        case '6':
            uLevel      = 6;
            break;
        case '7':
            uLevel      = 7;
            break;
        case '8':
            uLevel      = 8;
            break;
        case '9':
            uLevel      = 9;
            break;

        case 'h':
            RTPrintf("Usage: to be written\nOption dump:\n");
            for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
                RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
            return RTEXITCODE_SUCCESS;

        case 'V':
            RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
            return RTEXITCODE_SUCCESS;

        default:
            return RTGetOptPrintError(rc, &ValueUnion);
        }
    }
}