VirtualBox

Changeset 44299 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Jan 15, 2013 2:58:38 PM (12 years ago)
Author:
vboxsync
Message:

RTTar: Implemented simple extraction (-x).

Location:
trunk/src/VBox/Runtime/common
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/getopt.cpp

    r42129 r44299  
    792792        RTMsgError("Unknown option: '%s'", pValueUnion->psz);
    793793    else if (ch == VERR_GETOPT_INVALID_ARGUMENT_FORMAT)
    794         /** @todo r=klaus not really ideal, as the option isn't available */
    795         RTMsgError("Invalid argument format: '%s'", pValueUnion->psz);
     794        /** @todo r=klaus not really ideal, as the value isn't available */
     795        RTMsgError("The value given '%s' has an invalid format.", pValueUnion->pDef->pszLong);
    796796    else if (pValueUnion->pDef)
    797797        RTMsgError("%s: %Rrs\n", pValueUnion->pDef->pszLong, ch);
  • trunk/src/VBox/Runtime/common/zip/tarcmd.cpp

    r44278 r44299  
    11/* $Id$ */
    22/** @file
    3  * IPRT - TAR Command.
     3 * IPRT - A mini TAR Command.
    44 */
    55
     
    3434#include <iprt/buildconfig.h>
    3535#include <iprt/ctype.h>
     36#include <iprt/dir.h>
    3637#include <iprt/file.h>
    3738#include <iprt/getopt.h>
     
    4041#include <iprt/message.h>
    4142#include <iprt/param.h>
     43#include <iprt/path.h>
    4244#include <iprt/stream.h>
    4345#include <iprt/string.h>
     46#include <iprt/symlink.h>
    4447#include <iprt/vfs.h>
    4548
     
    4851*   Defined Constants And Macros                                               *
    4952*******************************************************************************/
    50 #define RTZIPTARCMD_OPT_DELETE      1000
    51 #define RTZIPTARCMD_OPT_OWNER       1001
    52 #define RTZIPTARCMD_OPT_GROUP       1002
    53 #define RTZIPTARCMD_OPT_UTC         1003
    54 #define RTZIPTARCMD_OPT_PREFIX      1004
     53#define RTZIPTARCMD_OPT_DELETE              1000
     54#define RTZIPTARCMD_OPT_OWNER               1001
     55#define RTZIPTARCMD_OPT_GROUP               1002
     56#define RTZIPTARCMD_OPT_UTC                 1003
     57#define RTZIPTARCMD_OPT_PREFIX              1004
     58#define RTZIPTARCMD_OPT_FILE_MODE_AND_MASK  1005
     59#define RTZIPTARCMD_OPT_FILE_MODE_OR_MASK   1006
     60#define RTZIPTARCMD_OPT_DIR_MODE_AND_MASK   1007
     61#define RTZIPTARCMD_OPT_DIR_MODE_OR_MASK    1008
    5562
    5663
     
    7481    /** Whether we're verbose or quiet. */
    7582    bool            fVerbose;
    76     /** Whether to preserve permissions when restoring. */
    77     bool            fPreservePermissions;
     83    /** Whether to preserve the original file owner when restoring. */
     84    bool            fPreserveOwner;
     85    /** Whether to preserve the original file group when restoring. */
     86    bool            fPreserveGroup;
     87    /** Whether to skip restoring the modification time (only time stored by the
     88     * traditional TAR format). */
     89    bool            fNoModTime;
    7890    /** The compressor/decompressor method to employ (0, z or j). */
    7991    char            chZipper;
    8092
    81     /** The owner to set. */
     93    /** The owner to set. NULL if not applicable.
     94     * Always resolved into uidOwner for extraction. */
    8295    const char     *pszOwner;
    83     /** The owner ID to set when unpacking if pszOwner is not NULL. */
     96    /** The owner ID to set. NIL_RTUID if not applicable. */
    8497    RTUID           uidOwner;
    85     /** The group to set. */
     98    /** The group to set. NULL if not applicable.
     99     * Always resolved into gidGroup for extraction. */
    86100    const char     *pszGroup;
    87     /** The group ID to set when unpacking if pszGroup is not NULL. */
     101    /** The group ID to set. NIL_RTGUID if not applicable. */
    88102    RTGID           gidGroup;
    89103    /** Display the modification times in UTC instead of local time. */
    90104    bool            fDisplayUtc;
     105    /** File mode AND mask. */
     106    RTFMODE         fFileModeAndMask;
     107    /** File mode OR mask. */
     108    RTFMODE         fFileModeOrMask;
     109    /** Directory mode AND mask. */
     110    RTFMODE         fDirModeAndMask;
     111    /** Directory mode OR mask. */
     112    RTFMODE         fDirModeOrMask;
    91113
    92114    /** What to prefix all names with when creating, adding, whatever. */
     
    101123/** Pointer to the IPRT tar options. */
    102124typedef RTZIPTARCMDOPS *PRTZIPTARCMDOPS;
     125
     126/**
     127 * Callback used by rtZipTarDoWithMembers
     128 *
     129 * @returns rcExit or RTEXITCODE_FAILURE.
     130 * @param   pOpts               The tar options.
     131 * @param   hVfsObj             The tar object to display
     132 * @param   pszName             The name.
     133 * @param   rcExit              The current exit code.
     134 */
     135typedef RTEXITCODE (*PFNDOWITHMEMBER)(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, const char *pszName, RTEXITCODE rcExit);
    103136
    104137
     
    226259
    227260/**
    228  * Display a tar entry in the verbose form.
     261 * Worker for the --list and --extract commands.
     262 *
     263 * @returns The appropriate exit code.
     264 * @param   pOpts               The tar options.
     265 * @param   pfnCallback         The command specific callback.
     266 */
     267static RTEXITCODE rtZipTarDoWithMembers(PRTZIPTARCMDOPS pOpts, PFNDOWITHMEMBER pfnCallback)
     268{
     269    /*
     270     * Allocate a bitmap to go with the file list.  This will be used to
     271     * indicate which files we've processed and which not.
     272     */
     273    uint32_t *pbmFound = NULL;
     274    if (pOpts->cFiles)
     275    {
     276        pbmFound = (uint32_t *)RTMemAllocZ(((pOpts->cFiles + 31) / 32) * sizeof(uint32_t));
     277        if (!pbmFound)
     278            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate the found-file-bitmap");
     279    }
     280
     281
     282    /*
     283     * Open the input archive.
     284     */
     285    RTVFSFSSTREAM hVfsFssIn;
     286    RTEXITCODE rcExit = rtZipTarCmdOpenInputArchive(pOpts, &hVfsFssIn);
     287    if (rcExit == RTEXITCODE_SUCCESS)
     288    {
     289        /*
     290         * Process the stream.
     291         */
     292        for (;;)
     293        {
     294            /*
     295             * Retrive the next object.
     296             */
     297            char       *pszName;
     298            RTVFSOBJ    hVfsObj;
     299            int rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, NULL, &hVfsObj);
     300            if (RT_FAILURE(rc))
     301            {
     302                if (rc != VERR_EOF)
     303                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext returned %Rrc", rc);
     304                break;
     305            }
     306
     307            /*
     308             * Should we process this entry?
     309             */
     310            uint32_t    iFile = UINT32_MAX;
     311            if (   !pOpts->cFiles
     312                || rtZipTarCmdIsNameInArray(pszName, pOpts->papszFiles, &iFile) )
     313            {
     314                if (pbmFound)
     315                    ASMBitSet(pbmFound, iFile);
     316
     317                rcExit = pfnCallback(pOpts, hVfsObj, pszName, rcExit);
     318            }
     319
     320            /*
     321             * Release the current object and string.
     322             */
     323            RTVfsObjRelease(hVfsObj);
     324            RTStrFree(pszName);
     325        }
     326
     327        /*
     328         * Complain about any files we didn't find.
     329         */
     330        for (uint32_t iFile = 0; iFile < pOpts->cFiles; iFile++)
     331            if (!ASMBitTest(pbmFound, iFile))
     332            {
     333                RTMsgError("%s: Was not found in the archive", pOpts->papszFiles[iFile]);
     334                rcExit = RTEXITCODE_FAILURE;
     335            }
     336    }
     337    RTMemFree(pbmFound);
     338    return rcExit;
     339}
     340
     341
     342/**
     343 * Checks if the name contains any escape sequences.
     344 *
     345 * An escape sequence would generally be one or more '..' references.  On DOS
     346 * like system, something that would make up a drive letter reference is also
     347 * considered an escape sequence.
     348 *
     349 * @returns true / false.
     350 * @param   pszName     The name to consider.
     351 */
     352static bool rtZipTarHasEscapeSequence(const char *pszName)
     353{
     354#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     355    if (pszName[0] == ':')
     356        return true;
     357#endif
     358    while (*pszName)
     359    {
     360        while (RTPATH_IS_SEP(*pszName))
     361            pszName++;
     362        if (   pszName[0] == '.'
     363            && pszName[1] == '.'
     364            && (pszName[2] == '\0' || RTPATH_IS_SLASH(pszName[2])) )
     365            return true;
     366        while (*pszName && !RTPATH_IS_SEP(*pszName))
     367            pszName++;
     368    }
     369
     370    return false;
     371}
     372
     373
     374/**
     375 * Queries the user ID to use when extracting a member.
    229376 *
    230377 * @returns rcExit or RTEXITCODE_FAILURE.
     378 * @param   pOpts               The tar options.
     379 * @param   pUser               The user info.
     380 * @param   pszName             The file name to use when complaining.
    231381 * @param   rcExit              The current exit code.
     382 * @param   pUid                Where to return the user ID.
     383 */
     384static RTEXITCODE rtZipTarQueryExtractOwner(PRTZIPTARCMDOPS pOpts, PCRTFSOBJINFO pOwner, const char *pszName, RTEXITCODE rcExit,
     385                                            PRTUID pUid)
     386{
     387    if (pOpts->uidOwner != NIL_RTUID)
     388        *pUid = pOpts->uidOwner;
     389    else if (pOpts->fPreserveGroup)
     390    {
     391        if (!pOwner->Attr.u.UnixGroup.szName[0])
     392             *pUid = pOwner->Attr.u.UnixOwner.uid;
     393        else
     394        {
     395            *pUid = NIL_RTUID;
     396            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: User resolving is not implemented.", pszName);
     397        }
     398    }
     399    else
     400        *pUid = NIL_RTUID;
     401    return rcExit;
     402}
     403
     404
     405/**
     406 * Queries the group ID to use when extracting a member.
     407 *
     408 * @returns rcExit or RTEXITCODE_FAILURE.
     409 * @param   pOpts               The tar options.
     410 * @param   pGroup              The group info.
     411 * @param   pszName             The file name to use when complaining.
     412 * @param   rcExit              The current exit code.
     413 * @param   pGid                Where to return the group ID.
     414 */
     415static RTEXITCODE rtZipTarQueryExtractGroup(PRTZIPTARCMDOPS pOpts, PCRTFSOBJINFO pGroup, const char *pszName, RTEXITCODE rcExit,
     416                                            PRTGID pGid)
     417{
     418    if (pOpts->gidGroup != NIL_RTGID)
     419        *pGid = pOpts->gidGroup;
     420    else if (pOpts->fPreserveGroup)
     421    {
     422        if (!pGroup->Attr.u.UnixGroup.szName[0])
     423            *pGid = pGroup->Attr.u.UnixGroup.gid;
     424        else
     425        {
     426            *pGid = NIL_RTGID;
     427            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Group resolving is not implemented.", pszName);
     428        }
     429    }
     430    else
     431        *pGid = NIL_RTGID;
     432    return rcExit;
     433}
     434
     435
     436
     437/**
     438 * Extracts a file.
     439 *
     440 * Since we can restore permissions and attributes more efficiently by working
     441 * directly on the file handle, we have special code path for files.
     442 *
     443 * @returns rcExit or RTEXITCODE_FAILURE.
     444 * @param   pOpts               The tar options.
    232445 * @param   hVfsObj             The tar object to display
    233  * @param   pszName             The name.
    234  * @param   pOpts               The tar options.
    235  */
    236 static RTEXITCODE rtZipTarCmdDisplayEntryVerbose(RTEXITCODE rcExit, RTVFSOBJ hVfsObj, const char *pszName,
    237                                                  PRTZIPTARCMDOPS pOpts)
     446 * @param   rcExit              The current exit code.
     447 * @param   pUnixInfo           The unix fs object info.
     448 * @param   pOwner              The owner info.
     449 * @param   pGroup              The group info.
     450 */
     451static RTEXITCODE rtZipTarCmdExtractFile(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, RTEXITCODE rcExit,
     452                                         const char *pszDst, PCRTFSOBJINFO pUnixInfo, PCRTFSOBJINFO pOwner, PCRTFSOBJINFO pGroup)
    238453{
     454    /*
     455     * Open the destination file and create a stream object for it.
     456     */
     457    uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_ACCESS_ATTR_DEFAULT
     458                   | ((RTFS_UNIX_IWUSR | RTFS_UNIX_IRUSR) << RTFILE_O_CREATE_MODE_SHIFT);
     459    RTFILE hFile;
     460    int rc = RTFileOpen(&hFile, pszDst, fOpen);
     461    if (RT_FAILURE(rc))
     462        return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating file: %Rrc", pszDst, rc);
     463
     464    RTVFSIOSTREAM hVfsIosDst;
     465    rc = RTVfsIoStrmFromRTFile(hFile, fOpen, true /*fLeaveOpen*/, &hVfsIosDst);
     466    if (RT_SUCCESS(rc))
     467    {
     468        /*
     469         * Pump the data thru.
     470         */
     471        RTVFSIOSTREAM hVfsIosSrc = RTVfsObjToIoStream(hVfsObj);
     472        rc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, (uint32_t)RT_MIN(pUnixInfo->cbObject, _1M));
     473        if (RT_SUCCESS(rc))
     474        {
     475            /*
     476             * Correct the file mode and other attributes.
     477             */
     478            if (!pOpts->fNoModTime)
     479            {
     480                rc = RTFileSetTimes(hFile, NULL, &pUnixInfo->ModificationTime, NULL, NULL);
     481                if (RT_FAILURE(rc))
     482                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error setting times: %Rrc", pszDst, rc);
     483            }
     484
     485#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
     486            if (   pOpts->uidOwner != NIL_RTUID
     487                || pOpts->gidGroup != NIL_RTGID
     488                || pOpts->fPreserveOwner
     489                || pOpts->fPreserveGroup)
     490            {
     491                RTUID uidFile;
     492                rcExit = rtZipTarQueryExtractOwner(pOpts, pOwner, pszDst, rcExit, &uidFile);
     493
     494                RTGID gidFile;
     495                rcExit = rtZipTarQueryExtractGroup(pOpts, pGroup, pszDst, rcExit, &gidFile);
     496                if (uidFile != NIL_RTUID || gidFile != NIL_RTGID)
     497                {
     498                    rc = RTFileSetOwner(hFile, uidFile, gidFile);
     499                    if (RT_FAILURE(rc))
     500                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error owner/group: %Rrc", pszDst, rc);
     501                }
     502            }
     503#endif
     504
     505            RTFMODE fMode = (pUnixInfo->Attr.fMode & pOpts->fFileModeAndMask) | pOpts->fFileModeOrMask;
     506            rc = RTFileSetMode(hFile, fMode | RTFS_TYPE_FILE);
     507            if (RT_FAILURE(rc))
     508                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error changing mode: %Rrc", pszDst, rc);
     509        }
     510        else
     511            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error writing out file: %Rrc", pszDst, rc);
     512        RTVfsIoStrmRelease(hVfsIosSrc);
     513        RTVfsIoStrmRelease(hVfsIosDst);
     514    }
     515    else
     516        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating I/O stream for file: %Rrc", pszDst, rc);
     517    RTFileClose(hFile);
     518    return rcExit;
     519}
     520
     521
     522/**
     523 * @callback_method_impl{PFNDOWITHMEMBER, Implements --extract.}
     524 */
     525static RTEXITCODE rtZipTarCmdExtractCallback(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, const char *pszName, RTEXITCODE rcExit)
     526{
     527    if (pOpts->fVerbose)
     528        RTPrintf("%s\n", pszName);
     529
     530    /*
     531     * Query all the information.
     532     */
     533    RTFSOBJINFO UnixInfo;
     534    int rc = RTVfsObjQueryInfo(hVfsObj, &UnixInfo, RTFSOBJATTRADD_UNIX);
     535    if (RT_FAILURE(rc))
     536        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo returned %Rrc on '%s'", rc, pszName);
     537
     538    RTFSOBJINFO Owner;
     539    rc = RTVfsObjQueryInfo(hVfsObj, &Owner, RTFSOBJATTRADD_UNIX_OWNER);
     540    if (RT_FAILURE(rc))
     541        return RTMsgErrorExit(RTEXITCODE_FAILURE,
     542                              "RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
     543                              rc, pszName);
     544
     545    RTFSOBJINFO Group;
     546    rc = RTVfsObjQueryInfo(hVfsObj, &Group, RTFSOBJATTRADD_UNIX_GROUP);
     547    if (RT_FAILURE(rc))
     548        return RTMsgErrorExit(RTEXITCODE_FAILURE,
     549                              "RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
     550                              rc, pszName);
     551
     552    const char *pszLinkType = NULL;
     553    char szTarget[RTPATH_MAX];
     554    szTarget[0] = '\0';
     555    RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
     556    if (hVfsSymlink != NIL_RTVFSSYMLINK)
     557    {
     558        rc = RTVfsSymlinkRead(hVfsSymlink, szTarget, sizeof(szTarget));
     559        RTVfsSymlinkRelease(hVfsSymlink);
     560        if (RT_FAILURE(rc))
     561            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: RTVfsSymlinkRead failed: %Rrc", pszName, rc);
     562        if (!RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
     563            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Hardlinks are not supported.", pszName);
     564        if (!szTarget[0])
     565            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Link target is empty.", pszName);
     566    }
     567    else if (RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
     568        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get symlink object for '%s'", pszName);
     569
     570    if (rtZipTarHasEscapeSequence(pszName))
     571        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Name '%s' contains an escape sequence.", pszName);
     572
     573    /*
     574     * Construct the path to the extracted member.
     575     */
     576    char szDst[RTPATH_MAX];
     577    rc = RTPathJoin(szDst, sizeof(szDst), pOpts->pszDirectory ? pOpts->pszDirectory : ".", pszName);
     578    if (RT_FAILURE(rc))
     579        return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to construct destination path for: %Rrc", pszName, rc);
     580
     581    /*
     582     * Extract according to the type.
     583     */
     584    switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
     585    {
     586        case RTFS_TYPE_FILE:
     587            return rtZipTarCmdExtractFile(pOpts, hVfsObj, rcExit, szDst, &UnixInfo, &Owner, &Group);
     588
     589        case RTFS_TYPE_DIRECTORY:
     590            rc = RTDirCreateFullPath(szDst, UnixInfo.Attr.fMode & RTFS_UNIX_ALL_ACCESS_PERMS);
     591            if (RT_FAILURE(rc))
     592                return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating directory: %Rrc", szDst, rc);
     593            break;
     594
     595        case RTFS_TYPE_SYMLINK:
     596            rc = RTSymlinkCreate(szDst, szTarget, RTSYMLINKTYPE_UNKNOWN, 0);
     597            if (RT_FAILURE(rc))
     598                return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating symbolic link: %Rrc", szDst, rc);
     599            break;
     600
     601        case RTFS_TYPE_FIFO:
     602            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: FIFOs are not supported.", pszName);
     603        case RTFS_TYPE_DEV_CHAR:
     604            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: FIFOs are not supported.", pszName);
     605        case RTFS_TYPE_DEV_BLOCK:
     606            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Block devices are not supported.", pszName);
     607        case RTFS_TYPE_SOCKET:
     608            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Sockets are not supported.", pszName);
     609        case RTFS_TYPE_WHITEOUT:
     610            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Whiteouts are not support.", pszName);
     611        default:
     612            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Unknown file type.", pszName);
     613    }
     614
     615    /*
     616     * Set other attributes as requested  .
     617     *                                    .
     618     * Note! File extraction does get here.
     619     */
     620    if (!pOpts->fNoModTime)
     621    {
     622        rc = RTPathSetTimesEx(szDst, NULL, &UnixInfo.ModificationTime, NULL, NULL, RTPATH_F_ON_LINK);
     623        if (RT_FAILURE(rc) && rc != VERR_NOT_SUPPORTED && rc != VERR_NS_SYMLINK_SET_TIME)
     624            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error changing modification time: %Rrc.", pszName, rc);
     625    }
     626
     627#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
     628    if (   pOpts->uidOwner != NIL_RTUID
     629        || pOpts->gidGroup != NIL_RTGID
     630        || pOpts->fPreserveOwner
     631        || pOpts->fPreserveGroup)
     632    {
     633        RTUID uidFile;
     634        rcExit = rtZipTarQueryExtractOwner(pOpts, &Owner, szDst, rcExit, &uidFile);
     635
     636        RTGID gidFile;
     637        rcExit = rtZipTarQueryExtractGroup(pOpts, &Group, szDst, rcExit, &gidFile);
     638        if (uidFile != NIL_RTUID || gidFile != NIL_RTGID)
     639        {
     640            rc = RTPathSetOwnerEx(szDst, uidFile, gidFile, RTPATH_F_ON_LINK);
     641            if (RT_FAILURE(rc))
     642                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error owner/group: %Rrc", szDst, rc);
     643        }
     644    }
     645#endif
     646
     647    if (!RTFS_IS_SYMLINK(UnixInfo.Attr.fMode)) /* RTPathSetMode follows symbolic links atm. */
     648    {
     649        RTFMODE fMode;
     650        if (RTFS_IS_DIRECTORY(UnixInfo.Attr.fMode))
     651            fMode = (UnixInfo.Attr.fMode & (pOpts->fDirModeAndMask  | RTFS_TYPE_MASK)) | pOpts->fDirModeOrMask;
     652        else
     653            fMode = (UnixInfo.Attr.fMode & (pOpts->fFileModeAndMask | RTFS_TYPE_MASK)) | pOpts->fFileModeOrMask;
     654        rc = RTPathSetMode(szDst, fMode);
     655        if (RT_FAILURE(rc))
     656            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error changing mode: %Rrc", szDst, rc);
     657    }
     658
     659    return rcExit;
     660}
     661
     662
     663/**
     664 * @callback_method_impl{PFNDOWITHMEMBER, Implements --list.}
     665 */
     666static RTEXITCODE rtZipTarCmdListCallback(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, const char *pszName, RTEXITCODE rcExit)
     667{
     668    /*
     669     * This is very simple in non-verbose mode.
     670     */
     671    if (!pOpts->fVerbose)
     672    {
     673        RTPrintf("%s\n", pszName);
     674        return rcExit;
     675    }
     676
    239677    /*
    240678     * Query all the information.
     
    393831}
    394832
     833
    395834/**
    396  * Implements the -t/--list operation.
    397  *
    398  * @returns The appropriate exit code.
    399  * @param   pOpts               The tar options.
    400  */
    401 static RTEXITCODE rtZipTarCmdList(PRTZIPTARCMDOPS pOpts)
     835 * Display usage.
     836 *
     837 * @param   pszProgName         The program name.
     838 */
     839static void rtZipTarUsage(const char *pszProgName)
    402840{
    403841    /*
    404      * Allocate a bitmap to go with the file list.  This will be used to
    405      * indicate which files we've processed and which not.
    406      */
    407     uint32_t *pbmFound = NULL;
    408     if (pOpts->cFiles)
    409     {
    410         pbmFound = (uint32_t *)RTMemAllocZ(((pOpts->cFiles + 31) / 32) * sizeof(uint32_t));
    411         if (!pbmFound)
    412             return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate the found-file-bitmap");
    413     }
    414 
    415 
    416     /*
    417      * Open the input archive.
    418      */
    419     RTVFSFSSTREAM hVfsFssIn;
    420     RTEXITCODE rcExit = rtZipTarCmdOpenInputArchive(pOpts, &hVfsFssIn);
    421     if (rcExit == RTEXITCODE_SUCCESS)
    422     {
    423         /*
    424          * Process the stream.
    425          */
    426         for (;;)
    427         {
    428             /*
    429              * Retrive the next object.
    430              */
    431             char       *pszName;
    432             RTVFSOBJ    hVfsObj;
    433             int rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, NULL, &hVfsObj);
    434             if (RT_FAILURE(rc))
    435             {
    436                 if (rc != VERR_EOF)
    437                     rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext returned %Rrc", rc);
    438                 break;
    439             }
    440 
    441             /*
    442              * Should we display this entry?
    443              */
    444             uint32_t    iFile = UINT32_MAX;
    445             if (   !pOpts->cFiles
    446                 || rtZipTarCmdIsNameInArray(pszName, pOpts->papszFiles, &iFile) )
    447             {
    448                 if (pbmFound)
    449                     ASMBitSet(pbmFound, iFile);
    450 
    451                 if (!pOpts->fVerbose)
    452                     RTPrintf("%s\n", pszName);
    453                 else
    454                     rcExit = rtZipTarCmdDisplayEntryVerbose(rcExit, hVfsObj, pszName, pOpts);
    455             }
    456 
    457             /*
    458              * Release the current object and string.
    459              */
    460             RTVfsObjRelease(hVfsObj);
    461             RTStrFree(pszName);
    462         }
    463 
    464         /*
    465          * Complain about any files we didn't find.
    466          */
    467         for (uint32_t iFile = 0; iFile < pOpts->cFiles; iFile++)
    468             if (!ASMBitTest(pbmFound, iFile))
    469             {
    470                 RTMsgError("%s: Was not found in the archive", pOpts->papszFiles[iFile]);
    471                 rcExit = RTEXITCODE_FAILURE;
    472             }
    473     }
    474     RTMemFree(pbmFound);
    475     return rcExit;
     842     *        0         1         2         3         4         5         6         7         8
     843     *        012345678901234567890123456789012345678901234567890123456789012345678901234567890
     844     */
     845    RTPrintf("Usage: %s [options]\n"
     846             "\n",
     847             pszProgName);
     848    RTPrintf("Operations:\n"
     849             "    -A, --concatenate, --catenate\n"
     850             "        Append the content of one tar archive to another. (not impl)\n"
     851             "    -c, --create\n"
     852             "        Create a new tar archive. (not impl)\n"
     853             "    -d, --diff, --compare\n"
     854             "        Compare atar archive with the file system. (not impl)\n"
     855             "    -r, --append\n"
     856             "        Append more files to the tar archive. (not impl)\n"
     857             "    -t, --list\n"
     858             "        List the contents of the tar archive.\n"
     859             "    -u, --update\n"
     860             "        Update the archive, adding files that are newer than the\n"
     861             "        ones in the archive. (not impl)\n"
     862             "    -x, --extract, --get\n"
     863             "        Extract the files from the tar archive.\n"
     864             "    --delete\n"
     865             "        Delete files from the tar archive.\n"
     866             "\n"
     867             );
     868    RTPrintf("Basic Options:\n"
     869             "    -C <dir>, --directory <dir>           (-A, -C, -d, -r, -u, -x)\n"
     870             "        Sets the base directory for input and output file members.\n"
     871             "        This does not apply to --file, even if it preceeds it.\n"
     872             "    -f <archive>, --file <archive>        (all)\n"
     873             "        The tar file to create or process. '-' indicates stdout/stdin,\n"
     874             "        which is is the default.\n"
     875             "    -v, --verbose                         (all)\n"
     876             "        Verbose operation.\n"
     877             "    -p, --preserve-permissions            (-x)\n"
     878             "        Preserve all permissions when extracting.  Must be used\n"
     879             "        before the mode mask options as it will change some of these.\n"
     880             "    -j, --bzip2                           (all)\n"
     881             "        Compress/decompress the archive with bzip2.\n"
     882             "    -z, --gzip, --gunzip, --ungzip        (all)\n"
     883             "        Compress/decompress the archive with gzip.\n"
     884             "\n");
     885    RTPrintf("Misc Options:\n"
     886             "    --owner <uid/username>                (-A, -C, -d, -r, -u, -x)\n"
     887             "        Set the owner of extracted and archived files to the user specified.\n"
     888             "    --group <uid/username>                (-A, -C, -d, -r, -u, -x)\n"
     889             "        Set the group of extracted and archived files to the group specified.\n"
     890             "    --utc                                 (-t)\n"
     891             "        Display timestamps as UTC instead of local time.\n"
     892             "\n");
     893    RTPrintf("IPRT Options:\n"
     894             "    --prefix <dir-prefix>                 (-A, -C, -d, -r, -u)\n"
     895             "        Directory prefix to give the members added to the archive.\n"
     896             "    --file-mode-and-mask <octal-mode>     (-A, -C, -d, -r, -u, -x)\n"
     897             "        Restrict the access mode of regular and special files.\n"
     898             "    --file-mode-and-mask <octal-mode>     (-A, -C, -d, -r, -u, -x)\n"
     899             "        Include the given access mode for regular and special files.\n"
     900             "    --dir-mode-and-mask <octal-mode>      (-A, -C, -d, -r, -u, -x)\n"
     901             "        Restrict the access mode of directories.\n"
     902             "    --dir-mode-and-mask <octal-mode>      (-A, -C, -d, -r, -u, -x)\n"
     903             "        Include the given access mode for directories.\n"
     904             "\n");
     905    RTPrintf("Standard Options:\n"
     906             "    -h, -?, --help\n"
     907             "        Display this help text.\n"
     908             "    -V, --version\n"
     909             "        Display version number.\n");
    476910}
    477 
    478 
    479911
    480912RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
     
    518950
    519951        /* IPRT extensions */
    520         { "--prefix",               RTZIPTARCMD_OPT_PREFIX, RTGETOPT_REQ_STRING },
     952        { "--prefix",               RTZIPTARCMD_OPT_PREFIX,             RTGETOPT_REQ_STRING },
     953        { "--file-mode-and-mask",   RTZIPTARCMD_OPT_FILE_MODE_AND_MASK, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
     954        { "--file-mode-or-mask",    RTZIPTARCMD_OPT_FILE_MODE_OR_MASK,  RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
     955        { "--dir-mode-and-mask",    RTZIPTARCMD_OPT_DIR_MODE_AND_MASK,  RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
     956        { "--dir-mode-or-mask",     RTZIPTARCMD_OPT_DIR_MODE_OR_MASK,   RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
    521957    };
    522958
     
    528964
    529965    RTZIPTARCMDOPS Opts;
    530     RT_ZERO(Opts); /* nice defaults :-) */
     966    RT_ZERO(Opts);
     967    Opts.uidOwner = NIL_RTUID;
     968    Opts.gidGroup = NIL_RTUID;
     969    Opts.fFileModeAndMask = RTFS_UNIX_ALL_ACCESS_PERMS;
     970    Opts.fDirModeAndMask  = RTFS_UNIX_ALL_ACCESS_PERMS;
     971#if 0
     972    if (RTPermIsSuperUser())
     973    {
     974        Opts.fFileModeAndMask = RTFS_UNIX_ALL_PERMS;
     975        Opts.fDirModeAndMask  = RTFS_UNIX_ALL_PERMS;
     976        Opts.fPreserveOwner   = true;
     977        Opts.fPreserveGroup   = true;
     978    }
     979#endif
    531980
    532981    RTGETOPTUNION   ValueUnion;
     
    5701019
    5711020            case 'p':
    572                 Opts.fPreservePermissions = true;
     1021                Opts.fFileModeAndMask   = RTFS_UNIX_ALL_PERMS;
     1022                Opts.fDirModeAndMask    = RTFS_UNIX_ALL_PERMS;
     1023                Opts.fPreserveOwner     = true;
     1024                Opts.fPreserveGroup     = true;
    5731025                break;
    5741026
     
    5841036                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify --owner once");
    5851037                Opts.pszOwner = ValueUnion.psz;
     1038
     1039                rc = RTStrToUInt32Full(Opts.pszOwner, 0, &ValueUnion.u32);
     1040                if (RT_SUCCESS(rc) && rc != VINF_SUCCESS)
     1041                    return RTMsgErrorExit(RTEXITCODE_SYNTAX,
     1042                                          "Error convering --owner '%s' into a number: %Rrc", Opts.pszOwner, rc);
     1043                if (RT_SUCCESS(rc))
     1044                {
     1045                    Opts.uidOwner = ValueUnion.u32;
     1046                    Opts.pszOwner = NULL;
     1047                }
    5861048                break;
    5871049
     
    5901052                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify --group once");
    5911053                Opts.pszGroup = ValueUnion.psz;
     1054
     1055                rc = RTStrToUInt32Full(Opts.pszGroup, 0, &ValueUnion.u32);
     1056                if (RT_SUCCESS(rc) && rc != VINF_SUCCESS)
     1057                    return RTMsgErrorExit(RTEXITCODE_SYNTAX,
     1058                                          "Error convering --group '%s' into a number: %Rrc", Opts.pszGroup, rc);
     1059                if (RT_SUCCESS(rc))
     1060                {
     1061                    Opts.gidGroup = ValueUnion.u32;
     1062                    Opts.pszGroup = NULL;
     1063                }
    5921064                break;
    5931065
     
    6031075                break;
    6041076
     1077            case RTZIPTARCMD_OPT_FILE_MODE_AND_MASK:
     1078                Opts.fFileModeAndMask = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
     1079                break;
     1080
     1081            case RTZIPTARCMD_OPT_FILE_MODE_OR_MASK:
     1082                Opts.fFileModeOrMask  = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
     1083                break;
     1084
     1085            case RTZIPTARCMD_OPT_DIR_MODE_AND_MASK:
     1086                Opts.fDirModeAndMask  = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
     1087                break;
     1088
     1089            case RTZIPTARCMD_OPT_DIR_MODE_OR_MASK:
     1090                Opts.fDirModeOrMask   = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
     1091                break;
     1092
     1093
     1094            /* Standard bits. */
    6051095            case 'h':
    606                 RTPrintf("Usage: to be written\nOption dump:\n");
    607                 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
    608                     if (RT_C_IS_PRINT(s_aOptions[i].iShort))
    609                         RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
    610                     else
    611                         RTPrintf(" %s\n", s_aOptions[i].pszLong);
     1096                rtZipTarUsage(RTPathFilename(papszArgs[0]));
    6121097                return RTEXITCODE_SUCCESS;
    6131098
     
    6521137    {
    6531138        case 't':
    654             return rtZipTarCmdList(&Opts);
     1139            return rtZipTarDoWithMembers(&Opts, rtZipTarCmdListCallback);
     1140
     1141        case 'x':
     1142            return rtZipTarDoWithMembers(&Opts, rtZipTarCmdExtractCallback);
    6551143
    6561144        case 'A':
     
    6591147        case 'r':
    6601148        case 'u':
    661         case 'x':
    6621149        case RTZIPTARCMD_OPT_DELETE:
    6631150            return RTMsgErrorExit(RTEXITCODE_FAILURE, "The operation %s is not implemented yet", Opts.pszOperation);
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