VirtualBox

Ignore:
Timestamp:
Jun 10, 2020 3:13:58 PM (5 years ago)
Author:
vboxsync
Message:

IPRT/tarcmd: Added initial support for creating TAR files from directories.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/zip/tarcmd.cpp

    r84760 r84761  
    6464#define RTZIPTARCMD_OPT_READ_AHEAD          1010
    6565#define RTZIPTARCMD_OPT_USE_PUSH_FILE       1011
     66#define RTZIPTARCMD_OPT_NO_RECURSION        1012
    6667
    6768/** File format. */
     
    111112    /** Use RTVfsFsStrmPushFile instead of RTVfsFsStrmAdd for files. */
    112113    bool            fUsePushFile;
     114    /** Whether to handle directories recursively or not. Defaults to \c true. */
     115    bool            fRecursive;
    113116    /** The compressor/decompressor method to employ (0, z or j). */
    114117    char            chZipper;
     
    153156typedef RTZIPTARCMDOPS *PRTZIPTARCMDOPS;
    154157
     158/** The size of the directory entry buffer we're using. */
     159#define RTZIPTARCMD_DIRENTRY_BUF_SIZE (sizeof(RTDIRENTRYEX) + RTPATH_MAX)
     160
    155161/**
    156162 * Callback used by rtZipTarDoWithMembers
     
    184190        }
    185191    return false;
     192}
     193
     194
     195/**
     196 * Queries information about a VFS object.
     197 *
     198 * @returns VBox status code.
     199 * @param   pszSpec             VFS object spec to use.
     200 * @param   paObjInfo           Where to store the queried object information.
     201 *                              Must at least provide 3 structs, namely for UNIX, UNIX_OWNER and UNIX_GROUP attributes.
     202 * @param   cObjInfo            Number of objection information structs handed in.
     203 */
     204static int rtZipTarCmdQueryObjInfo(const char *pszSpec, PRTFSOBJINFO paObjInfo, unsigned cObjInfo)
     205{
     206    AssertPtrReturn(paObjInfo, VERR_INVALID_POINTER);
     207    AssertReturn(cObjInfo >= 3, VERR_INVALID_PARAMETER);
     208
     209    RTERRINFOSTATIC ErrInfo;
     210    uint32_t        offError;
     211    int rc = RTVfsChainQueryInfo(pszSpec, &paObjInfo[0], RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK,
     212                                 &offError, RTErrInfoInitStatic(&ErrInfo));
     213    if (RT_SUCCESS(rc))
     214    {
     215        rc = RTVfsChainQueryInfo(pszSpec, &paObjInfo[1], RTFSOBJATTRADD_UNIX_OWNER, RTPATH_F_ON_LINK,
     216                                 &offError, RTErrInfoInitStatic(&ErrInfo));
     217        if (RT_SUCCESS(rc))
     218        {
     219            rc = RTVfsChainQueryInfo(pszSpec, &paObjInfo[2], RTFSOBJATTRADD_UNIX_GROUP, RTPATH_F_ON_LINK,
     220                                     &offError, RTErrInfoInitStatic(&ErrInfo));
     221            if (RT_FAILURE(rc))
     222                RT_BZERO(&paObjInfo[2], sizeof(RTFSOBJINFO));
     223        }
     224        else
     225        {
     226            RT_BZERO(&paObjInfo[1], sizeof(RTFSOBJINFO));
     227            RT_BZERO(&paObjInfo[2], sizeof(RTFSOBJINFO));
     228        }
     229
     230        rc = VINF_SUCCESS; /* aObjInfo[1] + aObjInfo[2] are optional. */
     231    }
     232    else
     233        RTVfsChainMsgError("RTVfsChainQueryInfo", pszSpec, rc, offError, &ErrInfo.Core);
     234
     235    return rc;
    186236}
    187237
     
    254304
    255305/**
    256  * Archives a directory recursively .
     306 * Sub-directory helper for creating archives.
     307 *
     308 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + printed message.
     309 * @param   pOpts           The options.
     310 * @param   hVfsFss         The TAR filesystem stream handle.
     311 * @param   pszSrc          The directory path or VFS spec.  We append to the
     312 *                          buffer as we decend.
     313 * @param   cchSrc          The length of the input.
     314 * @param   paObjInfo[3]    Array of three FS object info structures.  The first
     315 *                          one is always filled with RTFSOBJATTRADD_UNIX info.
     316 *                          The next two may contain owner and group names if
     317 *                          available.  The three buffers can be reused.
     318 * @param   pszDst          The name to archive it the under.  We append to the
     319 *                          buffer as we decend.
     320 * @param   cchDst          The length of the input.
     321 * @param   pDirEntry       Directory entry to use for the directory to handle.
     322 * @param   pErrInfo        Error info buffer (saves stack space).
     323 */
     324static RTEXITCODE rtZipTarCmdArchiveDirSub(PRTZIPTARCMDOPS pOpts, RTVFSFSSTREAM hVfsFss,
     325                                           char *pszSrc, size_t cchSrc, RTFSOBJINFO paObjInfo[3],
     326                                           char pszDst[RTPATH_MAX], size_t cchDst, PRTDIRENTRYEX pDirEntry,
     327                                           PRTERRINFOSTATIC pErrInfo)
     328{
     329    if (pOpts->fVerbose)
     330        RTPrintf("%s\n", pszDst);
     331
     332    uint32_t offError;
     333    RTVFSDIR hVfsIoDir;
     334    int rc = RTVfsChainOpenDir(pszSrc, 0 /*fFlags*/,
     335                               &hVfsIoDir, &offError, RTErrInfoInitStatic(pErrInfo));
     336    if (RT_FAILURE(rc))
     337        return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenDir", pszSrc, rc, offError, &pErrInfo->Core);
     338
     339    /* Make sure we've got some room in the path, to save us extra work further down. */
     340    if (cchSrc + 3 >= RTPATH_MAX)
     341        return RTMsgErrorExitFailure("Source path too long: '%s'\n", pszSrc);
     342
     343    /* Ensure we've got a trailing slash (there is space for it see above). */
     344    if (!RTPATH_IS_SEP(pszSrc[cchSrc - 1]))
     345    {
     346        pszSrc[cchSrc++] = RTPATH_SLASH;
     347        pszSrc[cchSrc]   = '\0';
     348    }
     349
     350    /* Ditto for destination. */
     351    if (cchDst + 3 >= RTPATH_MAX)
     352        return RTMsgErrorExitFailure("Destination path too long: '%s'\n", pszDst);
     353
     354    if (!RTPATH_IS_SEP(pszDst[cchDst - 1]))
     355    {
     356        pszDst[cchDst++] = RTPATH_SLASH;
     357        pszDst[cchDst]   = '\0';
     358    }
     359
     360    /*
     361     * Process the files and subdirs.
     362     */
     363    for (;;)
     364    {
     365        size_t cbDirEntry = RTZIPTARCMD_DIRENTRY_BUF_SIZE;
     366        rc = RTVfsDirReadEx(hVfsIoDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_UNIX);
     367        if (RT_FAILURE(rc))
     368            break;
     369
     370        /* Check length. */
     371        if (pDirEntry->cbName + cchSrc + 3 >= RTPATH_MAX)
     372        {
     373            rc = VERR_BUFFER_OVERFLOW;
     374            break;
     375        }
     376
     377        switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
     378        {
     379            case RTFS_TYPE_DIRECTORY:
     380            {
     381                if (RTDirEntryExIsStdDotLink(pDirEntry))
     382                    continue;
     383
     384                if (!pOpts->fRecursive)
     385                    continue;
     386
     387                memcpy(&pszSrc[cchSrc], pDirEntry->szName, pDirEntry->cbName + 1);
     388                if (RT_SUCCESS(rc))
     389                {
     390                    memcpy(&pszDst[cchDst], pDirEntry->szName, pDirEntry->cbName + 1);
     391                    rc = rtZipTarCmdArchiveDirSub(pOpts, hVfsFss, pszSrc, cchSrc + pDirEntry->cbName, paObjInfo,
     392                                                  pszDst, cchDst + pDirEntry->cbName, pDirEntry, pErrInfo);
     393                }
     394
     395                break;
     396            }
     397
     398            case RTFS_TYPE_FILE:
     399            {
     400                memcpy(&pszSrc[cchSrc], pDirEntry->szName, pDirEntry->cbName + 1);
     401                rc = rtZipTarCmdQueryObjInfo(pszSrc, paObjInfo, 3 /* cObjInfo */);
     402                if (RT_SUCCESS(rc))
     403                {
     404                    memcpy(&pszDst[cchDst], pDirEntry->szName, pDirEntry->cbName + 1);
     405                    rc = rtZipTarCmdArchiveFile(pOpts, hVfsFss, pszSrc, paObjInfo, pszDst, pErrInfo);
     406                }
     407                break;
     408            }
     409
     410            default:
     411            {
     412                if (pOpts->fVerbose)
     413                    RTPrintf("Warning: File system type %#x for '%s' not implemented yet, sorry! Skipping ...\n",
     414                             pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK, pDirEntry->szName);
     415                break;
     416            }
     417        }
     418    }
     419
     420    RTVfsDirRelease(hVfsIoDir);
     421
     422    if (rc != VERR_NO_MORE_FILES)
     423        return RTMsgErrorExitFailure("RTVfsDirReadEx failed unexpectedly!");
     424
     425    return RTEXITCODE_SUCCESS;
     426}
     427
     428
     429/**
     430 * Archives a directory recursively.
    257431 *
    258432 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + printed message.
     
    275449                                        PRTERRINFOSTATIC pErrInfo)
    276450{
    277     RT_NOREF(pOpts, hVfsFss, pszSrc, cchSrc, paObjInfo, pszDst, cchDst, pErrInfo);
    278     return RTMsgErrorExitFailure("Adding directories has not yet been implemented! Sorry.");
     451    RT_NOREF(cchSrc);
     452
     453    char szSrcAbs[RTPATH_MAX];
     454    int rc = RTPathAbs(pszSrc, szSrcAbs, sizeof(szSrcAbs));
     455    if (RT_FAILURE(rc))
     456        return RTMsgErrorExitFailure("RTPathAbs failed on '%s': %Rrc\n", pszSrc, rc);
     457
     458    union
     459    {
     460        uint8_t         abPadding[RTZIPTARCMD_DIRENTRY_BUF_SIZE];
     461        RTDIRENTRYEX    DirEntry;
     462    } uBuf;
     463
     464    return rtZipTarCmdArchiveDirSub(pOpts, hVfsFss, szSrcAbs, strlen(szSrcAbs), paObjInfo, pszDst, cchDst, &uBuf.DirEntry, pErrInfo);
    279465}
    280 
    281466
    282467
     
    491676                     * What kind of object is this and what affiliations does it have?
    492677                     */
    493                     RTERRINFOSTATIC ErrInfo;
    494                     uint32_t        offError;
    495                     RTFSOBJINFO     aObjInfo[3];
    496                     rc = RTVfsChainQueryInfo(szSrc, &aObjInfo[0], RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK,
    497                                              &offError, RTErrInfoInitStatic(&ErrInfo));
     678                    RTFSOBJINFO aObjInfo[3];
     679                    rc = rtZipTarCmdQueryObjInfo(szSrc, aObjInfo, RT_ELEMENTS(aObjInfo));
    498680                    if (RT_SUCCESS(rc))
    499681                    {
    500 
    501                         rc = RTVfsChainQueryInfo(szSrc, &aObjInfo[1], RTFSOBJATTRADD_UNIX_OWNER, RTPATH_F_ON_LINK,
    502                                                  &offError, RTErrInfoInitStatic(&ErrInfo));
    503                         if (RT_SUCCESS(rc))
    504                         {
    505                             rc = RTVfsChainQueryInfo(szSrc, &aObjInfo[2], RTFSOBJATTRADD_UNIX_GROUP, RTPATH_F_ON_LINK,
    506                                                      &offError, RTErrInfoInitStatic(&ErrInfo));
    507                             if (RT_FAILURE(rc))
    508                                 RT_ZERO(aObjInfo[2]);
    509                         }
    510                         else
    511                         {
    512                             RT_ZERO(aObjInfo[1]);
    513                             RT_ZERO(aObjInfo[2]);
    514                         }
     682                        RTERRINFOSTATIC ErrInfo;
    515683
    516684                        /*
     
    539707                    }
    540708                    else
    541                         rcExit = RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", pszFile, rc, offError, &ErrInfo.Core);
     709                        rcExit = RTMsgErrorExitFailure("querying object information for '%s' failed (%s)", szSrc, pszFile);
    542710                }
    543711                else
     
    15061674        { "--sparse",               'S',                                RTGETOPT_REQ_NOTHING },
    15071675        { "--format",               RTZIPTARCMD_OPT_FORMAT,             RTGETOPT_REQ_STRING },
     1676        { "--no-recursion",         RTZIPTARCMD_OPT_NO_RECURSION,       RTGETOPT_REQ_NOTHING },
    15081677
    15091678        /* IPRT extensions */
     
    15401709#endif
    15411710    Opts.enmTarFormat = RTZIPTARFORMAT_DEFAULT;
     1711    Opts.fRecursive   = true; /* Recursion is implicit unless otherwise specified. */
    15421712
    15431713    RTGETOPTUNION   ValueUnion;
     
    16281798            case RTZIPTARCMD_OPT_UTC:
    16291799                Opts.fDisplayUtc = true;
     1800                break;
     1801
     1802            case RTZIPTARCMD_OPT_NO_RECURSION:
     1803                Opts.fRecursive = false;
    16301804                break;
    16311805
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