VirtualBox

Changeset 34391 in vbox


Ignore:
Timestamp:
Nov 26, 2010 11:12:17 AM (14 years ago)
Author:
vboxsync
Message:

More extension pack code.

Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/manifest.h

    r34381 r34391  
    212212 *                              the expected results.)
    213213 * @param   pszEntry            The entry name.
    214  * @param   fAttrs              The attributes to create for this stream.
     214 * @param   fAttrs              The attributes to create for this stream.  See
     215 *                              RTMANIFEST_ATTR_XXX.
    215216 */
    216217RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs);
  • trunk/include/iprt/vfs.h

    r34031 r34391  
    711711
    712712
     713/** @defgroup grp_vfs_file          VFS Miscellaneous
     714 * @{
     715 */
     716
     717/**
     718 * Memorizes the I/O stream as a file backed by memory.
     719 *
     720 * @returns VBox status code.
     721 *
     722 * @param   hVfsIos         The VFS I/O stream to memorize.  This will be read
     723 *                          to the end on success, on failure its position is
     724 *                          undefined.
     725 * @param   fFlags          A combination of RTFILE_O_READ and RTFILE_O_WRITE.
     726 * @param   phVfsFile       Where to return the handle to the memory file on
     727 *                          success.
     728 */
     729RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile);
     730
     731/** @}  */
     732
     733
    713734/** @defgroup grp_rt_vfs_chain  VFS Chains
    714735 *
  • trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp

    r34381 r34391  
    234234}
    235235
     236
     237/**
     238 * Validates a name in an extension pack.
     239 *
     240 * We restrict the charset to try make sure the extension pack can be unpacked
     241 * on all file systems.
     242 *
     243 * @returns Program exit code, failure with message.
     244 * @param   pszName             The name to validate.
     245 */
     246static RTEXITCODE ValidateNameInExtPack(const char *pszName)
     247{
     248    if (RTPathStartsWithRoot(pszName))
     249        return RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s': starts with root spec", pszName);
     250
     251    const char *pszErr = NULL;
     252    const char *psz = pszName;
     253    int ch;
     254    while ((ch = *psz) != '\0')
     255    {
     256        /* Character set restrictions. */
     257        if (ch < 0 || ch >= 128)
     258        {
     259            pszErr = "Only 7-bit ASCII allowed";
     260            break;
     261        }
     262        if (ch <= 31 || ch == 127)
     263        {
     264            pszErr = "No control characters are not allowed";
     265            break;
     266        }
     267        if (ch == '\\')
     268        {
     269            pszErr = "Only backward slashes are not allowed";
     270            break;
     271        }
     272        if (strchr("'\":;*?|[]<>(){}", ch))
     273        {
     274            pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed";
     275            break;
     276        }
     277
     278        /* Take the simple way out and ban all ".." sequences. */
     279        if (   ch     == '.'
     280            && psz[1] == '.')
     281        {
     282            pszErr = "Double dot sequence are not allowed";
     283            break;
     284        }
     285    }
     286
     287    if (pszErr)
     288        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr);
     289    return RTEXITCODE_SUCCESS;
     290}
     291
     292
     293/**
     294 * Validates a file in an extension pack.
     295 *
     296 * @returns Program exit code, failure with message.
     297 * @param   pszName             The name of the file.
     298 * @param   hVfsObj             The VFS object.
     299 */
     300static RTEXITCODE ValidateFileInExtPack(const char *pszName, RTVFSOBJ hVfsObj)
     301{
     302    RTEXITCODE rcExit = ValidateNameInExtPack(pszName);
     303    if (rcExit == RTEXITCODE_SUCCESS)
     304    {
     305        RTFSOBJINFO ObjInfo;
     306        int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
     307        if (RT_SUCCESS(rc))
     308        {
     309            if (ObjInfo.cbObject >= 9*_1G64)
     310                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s': too large (%'RU64 bytes)",
     311                                        pszName, (uint64_t)ObjInfo.cbObject);
     312            if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
     313                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
     314                                        "The alleged file '%s' has a mode mask saying differently (%RTfmode)",
     315                                        pszName, ObjInfo.Attr.fMode);
     316        }
     317        else
     318            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
     319    }
     320    return rcExit;
     321}
     322
     323
     324/**
     325 * Validates a directory in an extension pack.
     326 *
     327 * @returns Program exit code, failure with message.
     328 * @param   pszName             The name of the directory.
     329 * @param   hVfsObj             The VFS object.
     330 */
     331static RTEXITCODE ValidateDirInExtPack(const char *pszName, RTVFSOBJ hVfsObj)
     332{
     333    RTEXITCODE rcExit = ValidateNameInExtPack(pszName);
     334    if (rcExit == RTEXITCODE_SUCCESS)
     335    {
     336        RTFSOBJINFO ObjInfo;
     337        int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
     338        if (RT_SUCCESS(rc))
     339        {
     340            if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
     341                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
     342                                        "The alleged directory '%s' has a mode mask saying differently (%RTfmode)",
     343                                        pszName, ObjInfo.Attr.fMode);
     344        }
     345        else
     346            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
     347    }
     348    return rcExit;
     349}
     350
     351/**
     352 * Validates a member of an extension pack.
     353 *
     354 * @returns Program exit code, failure with message.
     355 * @param   pszName             The name of the directory.
     356 * @param   enmType             The object type.
     357 * @param   hVfsObj             The VFS object.
     358 */
     359static RTEXITCODE ValidateMemberOfExtPack(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj)
     360{
     361    RTEXITCODE rcExit;
     362    if (   enmType == RTVFSOBJTYPE_FILE
     363        || enmType == RTVFSOBJTYPE_IO_STREAM)
     364        rcExit = ValidateFileInExtPack(pszName, hVfsObj);
     365    else if (   enmType == RTVFSOBJTYPE_DIR
     366             || enmType == RTVFSOBJTYPE_BASE)
     367        rcExit = ValidateDirInExtPack(pszName, hVfsObj);
     368    else
     369        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s' is not a file or directory (enmType=%d)", pszName, enmType);
     370    return rcExit;
     371}
     372
     373
    236374/**
    237375 * Validates the extension pack tarball prior to unpacking.
     
    304442    RTMANIFEST hManifest;
    305443    int rc = RTManifestCreate(0 /*fFlags*/, &hManifest);
    306 
    307     /** @todo continue coding here! */
    308     AssertRC(rc);
    309 
    310     return RTEXITCODE_FAILURE;
     444    if (RT_SUCCESS(rc))
     445    {
     446        /*
     447         * Process the tarball.
     448         */
     449        RTVFSFILE hXmlFile      = NIL_RTVFSFILE;
     450        RTVFSFILE hManifestFile = NIL_RTVFSFILE;
     451        RTVFSFILE hSignFile     = NIL_RTVFSFILE;
     452        for (;;)
     453        {
     454            /*
     455             * Get the next stream object.
     456             */
     457            char           *pszName;
     458            RTVFSOBJ        hVfsObj;
     459            RTVFSOBJTYPE    enmType;
     460            rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj);
     461            if (RT_FAILURE(rc))
     462            {
     463                if (rc != VERR_EOF)
     464                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext failed: %Rrc", rc);
     465                break;
     466            }
     467
     468            /*
     469             * Check the type & name validity.
     470             */
     471            rcExit = ValidateMemberOfExtPack(pszName, enmType, hVfsObj);
     472            if (rcExit == RTEXITCODE_SUCCESS)
     473            {
     474                /*
     475                 * Check if this is one of the standard files.
     476                 */
     477                const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName;
     478                PRTVFSFILE  phVfsFile;
     479                if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME))
     480                    phVfsFile = &hXmlFile;
     481                else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME))
     482                    phVfsFile = &hManifestFile;
     483                else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME))
     484                    phVfsFile = &hSignFile;
     485                else
     486                    phVfsFile = NULL;
     487                if (phVfsFile)
     488                {
     489                    /*
     490                     * Make sure it's a file and that it isn't too large.
     491                     */
     492                    if (*phVfsFile != NIL_RTVFSFILE)
     493                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "There can only be one '%s'", pszAdjName);
     494                    else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE)
     495                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Standard member '%s' is not a file", pszAdjName);
     496                    else
     497                    {
     498                        RTFSOBJINFO ObjInfo;
     499                        rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
     500                        if (RT_SUCCESS(rc))
     501                        {
     502                            if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
     503                                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Standard member '%s' is not a file", pszAdjName);
     504                            else if (ObjInfo.cbObject >= _1M)
     505                                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
     506                                                        "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)",
     507                                                        pszAdjName, (uint64_t)ObjInfo.cbObject);
     508                            else
     509                            {
     510                                /*
     511                                 * Make an in memory copy of the stream.
     512                                 */
     513                                RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
     514                                rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, phVfsFile);
     515                                if (RT_SUCCESS(rc))
     516                                {
     517                                    /*
     518                                     * To simplify the code below, replace
     519                                     * hVfsObj with the memorized file.
     520                                     */
     521                                    RTVfsObjRelease(hVfsObj);
     522                                    hVfsObj = RTVfsObjFromFile(*phVfsFile);
     523                                }
     524                                else
     525                                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
     526                                                            "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszName, rc);
     527                                RTVfsIoStrmRelease(hVfsIos);
     528                            }
     529                        }
     530                        else
     531                            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
     532                    }
     533                }
     534            }
     535
     536            /*
     537             * Add any I/O stream to the manifest
     538             */
     539            if (   rcExit == RTEXITCODE_SUCCESS
     540                && (   enmType == RTVFSOBJTYPE_FILE
     541                    || enmType == RTVFSOBJTYPE_IO_STREAM))
     542            {
     543                RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
     544                rc = RTManifestEntryAddIoStream(hManifest, hVfsIos, pszName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256);
     545                if (RT_FAILURE(rc))
     546                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszName, rc);
     547                RTVfsIoStrmRelease(hVfsIos);
     548            }
     549
     550            /*
     551             * Clean up and break out on failure.
     552             */
     553            RTVfsObjRelease(hVfsObj);
     554            RTStrFree(pszName);
     555            if (rcExit != RTEXITCODE_SUCCESS)
     556                break;
     557        }
     558
     559        /*
     560         * If we've successfully processed the tarball, verify that the
     561         * mandatory files are present.
     562         */
     563        if (rcExit == RTEXITCODE_SUCCESS)
     564        {
     565            if (hXmlFile == NIL_RTVFSFILE)
     566                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME);
     567            if (hManifestFile == NIL_RTVFSFILE)
     568                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME);
     569            if (hSignFile == NIL_RTVFSFILE)
     570                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME);
     571        }
     572
     573
     574
     575        RTManifestRelease(hManifest);   /** @todo return this and use it during unpacking */
     576    }
     577    RTVfsFsStrmRelease(hTarFss);
     578
     579    return rcExit;
    311580}
    312581
  • trunk/src/VBox/Main/include/ExtPackUtil.h

    r34307 r34391  
    2626 * The name of the description file in an extension pack.  */
    2727#define VBOX_EXTPACK_DESCRIPTION_NAME   "ExtPack.xml"
     28/** @name VBOX_EXTPACK_DESCRIPTION_NAME
     29 * The name of the manifest file in an extension pack.  */
     30#define VBOX_EXTPACK_MANIFEST_NAME      "ExtPack.manifest"
     31/** @name VBOX_EXTPACK_SIGNATURE_NAME
     32 * The name of the signature file in an extension pack.  */
     33#define VBOX_EXTPACK_SIGNATURE_NAME     "ExtPack.signature"
    2834/** @name VBOX_EXTPACK_SUFFIX
    2935 * The suffix of a extension pack tarball. */
  • trunk/src/VBox/Runtime/Makefile.kmk

    r34381 r34391  
    372372        common/vfs/vfsbase.cpp \
    373373        common/vfs/vfschain.cpp \
     374        common/vfs/vfsmemory.cpp \
    374375        common/vfs/vfsmisc.cpp \
    375376        common/vfs/vfsstdfile.cpp \
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