VirtualBox

Changeset 94313 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 20, 2022 12:25:08 AM (3 years ago)
Author:
vboxsync
Message:

installer/win: More fixes for VBoxStub. bugref:10201

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp

    r94285 r94313  
    8686    /** True if file, false if directory. */
    8787    bool        fFile;
     88    /** Set if we should not delete the file/directory.
     89     * This is used for user supplied extraction directories. */
     90    bool        fDontDelete;
    8891    union
    8992    {
     
    103106*   Prototypes                                                                                                                   *
    104107*********************************************************************************************************************************/
    105 static bool AddCleanupRec(const char *pszPath, bool fFile, const void *phObj);
     108static PSTUBCLEANUPREC AddCleanupRec(const char *pszPath, bool fIsFile);
    106109
    107110
     
    206209
    207210
     211/** Logs error details to stderr. */
     212static void LogError(const char *pszFmt, ...)
     213{
     214    va_list va;
     215    va_start(va, pszFmt);
     216    RTStrmPrintf(g_pStdErr, "error: %N\n", pszFmt, &va);
     217    va_end(va);
     218}
     219
     220
     221/** Logs error details to stderr, returning @a rc. */
     222static int LogErrorRc(int rc, const char *pszFmt, ...)
     223{
     224    va_list va;
     225    va_start(va, pszFmt);
     226    RTStrmPrintf(g_pStdErr, "error: %N\n", pszFmt, &va);
     227    va_end(va);
     228    return rc;
     229}
     230
     231
     232/** Logs error details to stderr, RTEXITCODE_FAILURE. */
     233static RTEXITCODE LogErrorExitFailure(const char *pszFmt, ...)
     234{
     235    va_list va;
     236    va_start(va, pszFmt);
     237    RTStrmPrintf(g_pStdErr, "error: %N\n", pszFmt, &va);
     238    va_end(va);
     239    return RTEXITCODE_FAILURE;
     240}
     241
     242
    208243/**
    209244 * Finds the specified in the resource section of the executable.
     
    211246 * @returns IPRT status code.
    212247 *
    213  * @param   pszDataName         Name of resource to read.
    214  * @param   ppvResource         Where to return the pointer to the data.
    215  * @param   pdwSize             Where to return the size of the data (if found).
    216  *                              Optional.
    217  */
    218 static int FindData(const char *pszDataName, PVOID *ppvResource, DWORD *pdwSize)
     248 * @param   pszDataName     Name of resource to read.
     249 * @param   ppbResource     Where to return the pointer to the data.
     250 * @param   pcbResource     Where to return the size of the data (if found).
     251 *                          Optional.
     252 */
     253static int FindData(const char *pszDataName, uint8_t const **ppbResource, DWORD *pcbResource)
    219254{
    220255    AssertReturn(pszDataName, VERR_INVALID_PARAMETER);
     
    235270    DWORD cb = SizeofResource(hInst, hRsrc);
    236271    AssertReturn(cb > 0, VERR_NO_DATA);
    237     if (pdwSize)
    238         *pdwSize = cb;
     272    if (pcbResource)
     273        *pcbResource = cb;
    239274
    240275    /* Get pointer to resource. */
     
    243278
    244279    /* Lock resource. */
    245     *ppvResource = LockResource(hData);
    246     AssertReturn(*ppvResource, VERR_IO_GEN_FAILURE);
     280    *ppbResource = (uint8_t const *)LockResource(hData);
     281    AssertReturn(*ppbResource, VERR_IO_GEN_FAILURE);
    247282    return VINF_SUCCESS;
    248283}
     
    256291 * @param   iPackage            The package number.
    257292 */
    258 static PVBOXSTUBPKG FindPackageHeader(unsigned iPackage)
     293static const VBOXSTUBPKG *FindPackageHeader(unsigned iPackage)
    259294{
    260295    char szHeaderName[32];
    261296    RTStrPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", iPackage);
    262297
    263     PVBOXSTUBPKG pPackage;
    264     int rc = FindData(szHeaderName, (PVOID *)&pPackage, NULL);
     298    VBOXSTUBPKG const *pPackage;
     299    int rc = FindData(szHeaderName, (uint8_t const **)&pPackage, NULL);
    265300    if (RT_FAILURE(rc))
    266301    {
     
    302337 * @param   pszResourceName     The resource name to extract.
    303338 * @param   pszTempFile         The full file path + name to extract the resource to.
    304  *
    305  */
    306 static int ExtractFile(const char *pszResourceName,
    307                        const char *pszTempFile)
     339 * @param   hFile               Handle to pszTempFile if RTFileCreateUnique was
     340 *                              used to generate the name, otherwise NIL_RTFILE.
     341 * @param   idxPackage          The package index for annotating the cleanup
     342 *                              record with (HACK ALERT).
     343 */
     344static int ExtractFile(const char *pszResourceName, const char *pszTempFile, RTFILE hFile, unsigned idxPackage)
    308345{
    309346    AssertPtrReturn(pszResourceName, VERR_INVALID_POINTER);
    310347    AssertPtrReturn(pszTempFile, VERR_INVALID_POINTER);
    311348
    312     /* Read the data of the built-in resource. */
    313     PVOID pvData = NULL;
    314     DWORD dwDataSize = 0;
    315     int rc = FindData(pszResourceName, &pvData, &dwDataSize);
    316     AssertMsgRCReturn(rc, ("Could not read resource data: %Rrc\n", rc), rc);
    317 
    318     /* Create new (and replace an old) file. */
    319     RTFILE hFile;
    320     rc = RTFileOpen(&hFile, pszTempFile,
    321                       RTFILE_O_CREATE_REPLACE
    322                     | RTFILE_O_WRITE
    323                     | RTFILE_O_DENY_WRITE);
    324 
    325     AssertMsgRCReturn(rc, ("Could not open '%s' for writing: %Rrc\n", pszTempFile, rc), rc);
     349    /* Create new (and replace any old) file. */
     350    if (hFile == NIL_RTFILE)
     351    {
     352        int rc = RTFileOpen(&hFile, pszTempFile,
     353                            RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE
     354                            | (0700 << RTFILE_O_CREATE_MODE_SHIFT));
     355        AssertRCReturn(rc, LogErrorRc(rc, "#%u: Failed to create/replace '%s' for writing: %Rrc", idxPackage, pszTempFile, rc));
     356    }
    326357
    327358    /* Add a cleanup record, so that we can properly clean up (partially run) stuff. */
    328     bool fRc = AddCleanupRec(pszTempFile, true /*fFile*/, &hFile);
    329     AssertMsgReturn(fRc, ("Could not add cleanup record '%s': %Rrc\n", pszTempFile, rc), rc);
    330 
    331     /* Write contents to new file. */
    332     size_t cbWritten = 0;
    333     rc = RTFileWrite(hFile, pvData, dwDataSize, &cbWritten);
    334     AssertMsgStmt(cbWritten == dwDataSize || RT_FAILURE_NP(rc), ("%#zx vs %#x\n", cbWritten, dwDataSize), rc = VERR_WRITE_ERROR);
    335 
    336     /* See @bugref{10201} comment 8. */
     359    int rc = VERR_NO_MEMORY;
     360    PSTUBCLEANUPREC pCleanupRec = AddCleanupRec(pszTempFile, true /*fIsFile*/);
     361    AssertReturn(pCleanupRec, VERR_NO_MEMORY);
     362
     363    pCleanupRec->idxPkg = idxPackage;
     364    pCleanupRec->hFile  = hFile;
     365
     366    /* Find the data of the built-in resource. */
     367    uint8_t const *pbData = NULL;
     368    DWORD          cbData = 0;
     369    rc = FindData(pszResourceName, &pbData, &cbData);
     370    AssertRCReturn(rc, LogErrorRc(rc, "#%u: Failed to locate resource '%s': %Rrc", idxPackage, pszResourceName, rc));
     371
     372    /* Write the contents to the file. */
     373    rc = RTFileWrite(hFile, pbData, cbData, NULL);
     374    AssertRCReturn(rc, LogErrorRc(rc, "#%u: RTFileWrite('%s',, %#x,) failed: %Rrc", idxPackage, pszTempFile, cbData, rc));
     375
     376    /*
     377     * We now wish to keep the file open, however since we've got it open in write
     378     * mode with deny-write sharing (effectively exclusive write mode) this will
     379     * prevent the MSI API from opening it in deny-write mode for reading purposes.
     380     *
     381     * So we have to do the best we can to transition this to a read-only handle
     382     * that denies write (and deletion/renaming).  First we open it again in
     383     * read-only mode only denying deletion, not writing.  Then close the original
     384     * handle.  Finally open a read-only handle that denies both reading and
     385     * deletion/renaming, and verify that the file content is still the same.
     386     *
     387     * Note! DuplicateHandle to read-only and closing the original does not work,
     388     *       as the kernel doesn't update the sharing access info for the handles.
     389     */
     390    RTFSOBJINFO ObjInfo1;
     391    rc = RTFileQueryInfo(hFile, &ObjInfo1, RTFSOBJATTRADD_UNIX);
     392    AssertRCReturn(rc, LogErrorRc(rc, "#%u: RTFileQueryInfo failed on '%s': %Rrc", idxPackage, pszTempFile, rc));
     393
     394    RTFILE hFile2 = NIL_RTFILE;
     395    rc = RTFileOpen(&hFile2, pszTempFile,
     396                    RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE | (0700 << RTFILE_O_CREATE_MODE_SHIFT));
     397    AssertRCReturn(rc, LogErrorRc(rc, "#%u: First re-opening of '%s' failed: %Rrc", idxPackage, pszTempFile, rc));
    337398
    338399    rc = RTFileClose(hFile);
    339     AssertMsgRCReturn(rc, ("Closing file failed: %Rrc\n", rc), rc);
    340 
    341     rc = RTFileOpen(&hFile, pszTempFile,
    342                       RTFILE_O_OPEN
    343                     | RTFILE_O_READ
    344                     | RTFILE_O_DENY_WRITE);
    345     AssertMsgRCReturn(rc, ("Could not open '%s' for reading: %Rrc\n", pszTempFile, rc), rc);
    346 
    347     /*
    348      * Note: We keep the file open so that nobody else can write to it until we're done.
    349      * See @bugref{10201}
    350      */
    351 
    352     if (RT_SUCCESS(rc))
    353         return VINF_SUCCESS;
    354 
    355     return rc;
     400    AssertRCReturnStmt(rc, RTFileClose(hFile2),
     401                       LogErrorRc(rc, "#%u: RTFileClose('%s') failed: %Rrc", idxPackage, pszTempFile, rc));
     402    pCleanupRec->hFile = hFile2;
     403
     404    rc = RTFileOpen(&hFile, pszTempFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
     405    AssertRCReturn(rc, LogErrorRc(rc, "#%u: Second re-opening of '%s' failed: %Rrc", idxPackage, pszTempFile, rc));
     406    pCleanupRec->hFile = hFile;
     407
     408    rc = RTFileClose(hFile2);
     409    AssertRCStmt(rc, LogError("#%u: Failed to close 2nd handle to '%s': %Rrc", idxPackage, pszTempFile, rc));
     410
     411    /* check the size and inode number. */
     412    RTFSOBJINFO ObjInfo2;
     413    rc = RTFileQueryInfo(hFile, &ObjInfo2, RTFSOBJATTRADD_UNIX);
     414    AssertRCReturn(rc, LogErrorRc(rc, "#%u: RTFileQueryInfo failed on '%s': %Rrc", idxPackage, pszTempFile, rc));
     415
     416    AssertReturn(ObjInfo2.cbObject == cbData,
     417                 LogErrorRc(VERR_STATE_CHANGED, "#%u: File size of '%s' changed: %'RU64, expected %'RU32",
     418                            idxPackage, pszTempFile, ObjInfo2.cbObject, pbData));
     419
     420    AssertReturn(ObjInfo2.Attr.u.Unix.INodeId == ObjInfo1.Attr.u.Unix.INodeId,
     421                 LogErrorRc(VERR_STATE_CHANGED, "#%u: File ID of '%s' changed: %#RX64, expected %#RX64",
     422                            idxPackage, pszTempFile, ObjInfo2.Attr.u.Unix.INodeId, ObjInfo1.Attr.u.Unix.INodeId));
     423
     424
     425    /* Check the content. */
     426    uint32_t off = 0;
     427    while (off < cbData)
     428    {
     429        uint8_t abBuf[_64K];
     430        size_t  cbToRead = RT_MIN(cbData - off, sizeof(abBuf));
     431        rc = RTFileRead(hFile, abBuf, cbToRead, NULL);
     432        AssertRCReturn(rc, LogErrorRc(rc, "#%u: RTFileRead failed on '%s' at offset %#RX32: %Rrc",
     433                                      idxPackage, pszTempFile, off, rc));
     434        AssertReturn(memcmp(abBuf, &pbData[off], cbToRead) == 0,
     435                     LogErrorRc(VERR_STATE_CHANGED, "#%u: File '%s' has change (mismatch in %#zx byte block at %#RX32)",
     436                                idxPackage, pszTempFile, cbToRead, off));
     437        off += cbToRead;
     438    }
     439
     440    return VINF_SUCCESS;
    356441}
    357442
     
    364449 * @param   pPackage            Pointer to a VBOXSTUBPKG struct that contains the resource.
    365450 * @param   pszTempFile         The full file path + name to extract the resource to.
    366  */
    367 static int Extract(const PVBOXSTUBPKG  pPackage,
    368                    const char         *pszTempFile)
    369 {
    370     return ExtractFile(pPackage->szResourceName, pszTempFile);
     451 * @param   hFile               Handle to pszTempFile if RTFileCreateUnique was
     452 *                              used to generate the name, otherwise NIL_RTFILE.
     453 * @param   idxPackage          The package index for annotating the cleanup
     454 *                              record with (HACK ALERT).
     455 */
     456static int Extract(VBOXSTUBPKG const *pPackage, const char *pszTempFile, RTFILE hFile, unsigned idxPackage)
     457{
     458    return ExtractFile(pPackage->szResourceName, pszTempFile, hFile, idxPackage);
    371459}
    372460
     
    400488 * @param   pPackage            Pointer to a VBOXSTUBPKG struct that contains the resource.
    401489 */
    402 static bool PackageIsNeeded(PVBOXSTUBPKG pPackage)
     490static bool PackageIsNeeded(VBOXSTUBPKG const *pPackage)
    403491{
    404492    if (pPackage->byArch == VBOXSTUBPKGARCH_ALL)
     
    412500 * Adds a cleanup record.
    413501 *
    414  * @returns Fully complained boolean success indicator.
     502 * The caller must set the hFile or hDir if so desired.
     503 *
     504 * @returns Pointer to the cleanup record on success, fully complained NULL on
     505 *          failure.
    415506 * @param   pszPath             The path to the file or directory to clean up.
    416  * @param   fFile               @c true if file, @c false if directory.
    417  * @param   phObj               File / directory handle, depending on \a fFile.
    418  */
    419 static bool AddCleanupRec(const char *pszPath, bool fFile, const void *phObj)
    420 {
    421     AssertPtrReturn(phObj, false);
     507 * @param   fIsFile             @c true if file, @c false if directory.
     508 */
     509static PSTUBCLEANUPREC AddCleanupRec(const char *pszPath, bool fIsFile)
     510{
    422511    size_t cchPath = strlen(pszPath); Assert(cchPath > 0);
    423512    PSTUBCLEANUPREC pRec = (PSTUBCLEANUPREC)RTMemAllocZ(RT_UOFFSETOF_DYN(STUBCLEANUPREC, szPath[cchPath + 1]));
    424     if (!pRec)
    425     {
     513    if (pRec)
     514    {
     515        pRec->idxPkg    = ~0U;
     516        pRec->fFile     = fIsFile;
     517        if (fIsFile)
     518            pRec->hFile = NIL_RTFILE;
     519        else
     520            pRec->hDir  = NIL_RTDIR;
     521        memcpy(pRec->szPath, pszPath, cchPath + 1);
     522
     523        RTListPrepend(&g_TmpFiles, &pRec->ListEntry);
     524    }
     525    else
    426526        ShowError("Out of memory!");
    427         return false;
    428     }
    429     pRec->fFile = fFile;
    430     if (pRec->fFile)
    431         memcpy(&pRec->hFile, phObj, sizeof(RTFILE));
    432     else
    433         memcpy(&pRec->hDir, phObj, sizeof(RTDIR));
    434     memcpy(pRec->szPath, pszPath, cchPath + 1);
    435 
    436     RTListPrepend(&g_TmpFiles, &pRec->ListEntry);
    437     return true;
     527    return pRec;
    438528}
    439529
     
    450540    for (int i = 0; i < 5; i++)
    451541    {
    452         int rc = VINF_SUCCESS;
    453         bool fFinalTry = i == 4;
     542        bool const fFinalTry = i == 4;
    454543
    455544        PSTUBCLEANUPREC pCur, pNext;
    456545        RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry)
    457546        {
     547            int rc = VINF_SUCCESS;
    458548            if (pCur->fFile)
    459549            {
    460                 if (RTFileIsValid(pCur->hFile))
     550                if (pCur->hFile != NIL_RTFILE)
    461551                {
    462                     rc = RTFileClose(pCur->hFile);
    463                     if (RT_SUCCESS(rc))
    464                         pCur->hFile = NIL_RTFILE;
     552                    if (RTFileIsValid(pCur->hFile))
     553                    {
     554                        int rcCloseFile = RTFileClose(pCur->hFile);
     555                        AssertRCStmt(rcCloseFile, LogError("Cleanup file '%s' for #%u: RTFileClose(%p) failed: %Rrc",
     556                                                           pCur->szPath, pCur->idxPkg, pCur->hFile, rcCloseFile));
     557                    }
     558                    pCur->hFile = NIL_RTFILE;
    465559                }
    466 
    467                 if (RT_SUCCESS(rc))
     560                if (!pCur->fDontDelete)
    468561                    rc = RTFileDelete(pCur->szPath);
    469562            }
    470563            else /* Directory */
    471564            {
    472                 if (RTDirIsValid(pCur->hDir))
     565                if (pCur->hDir != NIL_RTDIR)
    473566                {
    474                     rc = RTDirClose(pCur->hDir);
    475                     if (RT_SUCCESS(rc))
    476                         pCur->hDir = NIL_RTDIR;
     567                    if (RTDirIsValid(pCur->hDir))
     568                    {
     569                        int rcCloseDir = RTDirClose(pCur->hDir);
     570                        AssertRCStmt(rcCloseDir, LogError("Cleanup dir '%s' for #%u: RTDirClose(%p) failed: %Rrc",
     571                                                          pCur->szPath, pCur->idxPkg, pCur->hDir, rcCloseDir));
     572                    }
     573                    pCur->hDir = NIL_RTDIR;
    477574                }
    478575
    479                 if (RT_SUCCESS(rc))
     576                /* Note: Not removing the directory recursively, as we should have separate cleanup records for that. */
     577                if (!pCur->fDontDelete)
    480578                {
    481                     /* Note: Not removing the directory recursively, as we should have separate cleanup records for that. */
    482579                    rc = RTDirRemove(pCur->szPath);
    483580                    if (rc == VERR_DIR_NOT_EMPTY && fFinalTry)
     
    505602            if (!pszPkgDir)
    506603                return;
    507             rc = RTDirRemove(pszPkgDir);
     604            int rc = RTDirRemove(pszPkgDir);
    508605            if (RT_SUCCESS(rc) || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND || fFinalTry)
    509606                return;
     
    670767 * @returns Fully complained exit code.
    671768 * @param   iPackage            The package number.
    672  * @param   pszPkgDir           The package directory (aka extraction dir).
    673769 * @param   pszMsiArgs          Any additional installer (MSI) argument
    674770 * @param   fLogging            Whether to enable installer logging.
    675771 */
    676 static RTEXITCODE ProcessPackage(unsigned iPackage, const char *pszPkgDir, const char *pszMsiArgs, bool fLogging)
     772static RTEXITCODE ProcessPackage(unsigned iPackage, const char *pszMsiArgs, bool fLogging)
    677773{
    678774    /*
    679775     * Get the package header and check if it's needed.
    680776     */
    681     PVBOXSTUBPKG pPackage = FindPackageHeader(iPackage);
     777    VBOXSTUBPKG const * const pPackage = FindPackageHeader(iPackage);
    682778    if (pPackage == NULL)
    683779        return RTEXITCODE_FAILURE;
     
    687783
    688784    /*
    689      * Deal with the file based on it's extension.
    690      */
    691     char szPkgFile[RTPATH_MAX];
    692 
    693     /*
    694      * Use the cleanup record to built-up the final name to process, as the cleanup record's file name might be different
    695      * than the original package's name.
    696      *
    697      * We can't write to the package's attributes, as those point to a write-protected area within the stub loader.
    698      * So I didn't feel to re-writing nearly everything here and went for this approach instead.
    699      *
    700      ** @todo The structure / stub API needs a major overhaul.*
     785     * Get the cleanup record for the package so we can get the extracted
     786     * filename (pPackage is read-only and thus cannot assist here).
    701787     */
    702788    PSTUBCLEANUPREC pRec = NULL;
     
    710796        }
    711797    }
    712     AssertMsgReturn(pRec != NULL, ("Package #%x not found in cleanup records\n", iPackage), RTEXITCODE_FAILURE);
    713 
    714     const char *pszFileName = RTPathFilename(pRec->szPath);
    715     AssertMsgReturn(pszFileName != NULL, ("Cleanup record does not have a valid file name\n"), RTEXITCODE_FAILURE);
    716     int rc = RTPathJoin(szPkgFile, sizeof(szPkgFile), pszPkgDir, pszFileName);
    717     if (RT_FAILURE(rc))
    718         return ShowError("Internal error: RTPathJoin failed: %Rrc", rc);
    719 
    720     RTPathChangeToDosSlashes(szPkgFile, true /* Force conversion. */); /* paranoia */
     798    AssertReturn(pRec != NULL, LogErrorExitFailure("Package #%u not found in cleanup records", iPackage));
     799
     800    /*
     801     * Deal with the file based on it's extension.
     802     */
     803    RTPathChangeToDosSlashes(pRec->szPath, true /* Force conversion. */); /* paranoia */
    721804
    722805    RTEXITCODE rcExit;
    723     const char *pszSuff = RTPathSuffix(szPkgFile);
    724     if (RTStrICmp(pszSuff, ".msi") == 0)
    725         rcExit = ProcessMsiPackage(szPkgFile, pszMsiArgs, fLogging);
    726     else if (RTStrICmp(pszSuff, ".cab") == 0)
     806    const char *pszSuff = RTPathSuffix(pRec->szPath);
     807    if (RTStrICmpAscii(pszSuff, ".msi") == 0)
     808        rcExit = ProcessMsiPackage(pRec->szPath, pszMsiArgs, fLogging);
     809    else if (RTStrICmpAscii(pszSuff, ".cab") == 0)
    727810        rcExit = RTEXITCODE_SUCCESS; /* Ignore .cab files, they're generally referenced by other files. */
    728811    else
    729         rcExit = ShowError("Internal error: Do not know how to handle file '%s'.", pPackage->szFileName);
    730 
     812        rcExit = ShowError("Internal error: Do not know how to handle file '%s' (%s).", pPackage->szFileName, pRec->szPath);
    731813    return rcExit;
    732814}
     
    820902            return ShowError("Out of memory!");
    821903
     904        PSTUBCLEANUPREC pCleanupRec = AddCleanupRec(pszDstSubDir, false /*fIsFile*/);
     905        AssertReturn(pCleanupRec, RTEXITCODE_FAILURE);
     906
    822907        /*
    823          * Note: We keep the directory open so that nobody else can delete / replace it while we're working on it.
    824          * See @bugref{10201}
     908         * Open the directory to make it difficult to replace or delete (see @bugref{10201}).
    825909         */
     910        /** @todo this is still race prone, given that SHFileOperationW is the one
     911         *        creating it and we're really a bit late opening it here.  Anyway,
     912         *        it's harmless as this code isn't used at present. */
    826913        RTDIR hDstSubDir;
    827914        rc = RTDirOpen(&hDstSubDir, pszDstSubDir);
    828915        if (RT_FAILURE(rc))
    829916            return ShowError("Unable to open the destination .custom directory: %Rrc", rc);
    830 
    831         /* Add a cleanup record. */
    832         bool fRc = AddCleanupRec(pszDstSubDir, false /*fFile*/, &hDstSubDir);
    833         AssertMsgReturn(fRc, ("Could not add cleanup record '%s': %Rrc\n", pszDstSubDir, rc), RTEXITCODE_FAILURE);
     917        pCleanupRec->hDir = hDstSubDir;
    834918
    835919        RTStrFree(pszDstSubDir);
    836         if (!fRc)
    837             return RTEXITCODE_FAILURE;
    838920    }
    839921
     
    842924
    843925
    844 static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly, bool *pfCreatedExtractDir)
     926/**
     927 * Extracts the files for all needed packages to @a pszDstDir.
     928 *
     929 * @returns
     930 * @param   cPackages       Number of packages to consinder.
     931 * @param   pszDstDir       Where to extract the files.
     932 * @param   fExtractOnly    Set if only extracting and not doing any installing.
     933 * @param   ppExtractDirRec Where we keep the cleanup record for @a pszDstDir.
     934 *                          This may have been created by the caller already.
     935 */
     936static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly, PSTUBCLEANUPREC *ppExtractDirRec)
    845937{
    846938    int rc;
    847939
    848940    /*
    849      * Make sure the directory exists.
    850      */
    851     *pfCreatedExtractDir = false;
     941     * Make sure the directory exists (normally WinMain created it for us).
     942     */
     943    PSTUBCLEANUPREC pCleanupRec = *ppExtractDirRec;
    852944    if (!RTDirExists(pszDstDir))
    853945    {
     946        AssertReturn(!pCleanupRec, ShowError("RTDirExists failed on '%s' which we just created!", pszDstDir));
     947
    854948        rc = RTDirCreate(pszDstDir, 0700, 0);
    855949        if (RT_FAILURE(rc))
    856950            return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc);
    857951
    858         *pfCreatedExtractDir = true;
    859     }
    860 
    861     RTDIR hDir;
    862     rc = RTDirOpen(&hDir, pszDstDir);
     952        *ppExtractDirRec = pCleanupRec = AddCleanupRec(pszDstDir, false /*fFile*/);
     953        AssertReturn(pCleanupRec, LogErrorExitFailure("Failed to add cleanup record for dir '%s'", pszDstDir));
     954    }
     955    /*
     956     * If we need to create the cleanup record, the caller did not create the
     957     * directory so we should not delete it when done.
     958     */
     959    else if (!pCleanupRec)
     960    {
     961        *ppExtractDirRec = pCleanupRec = AddCleanupRec(pszDstDir, false /*fFile*/);
     962        AssertReturn(pCleanupRec, LogErrorExitFailure("Failed to add cleanup record for existing dir '%s'", pszDstDir));
     963        pCleanupRec->fDontDelete = true;
     964    }
     965
     966    /*
     967     * Open up the directory to make it difficult to delete / replace.
     968     */
     969    rc = RTDirOpen(&pCleanupRec->hDir, pszDstDir);
    863970    if (RT_FAILURE(rc))
    864971        return ShowError("Failed to open extraction path '%s': %Rrc", pszDstDir, rc);
    865972
    866     /* Add a cleanup record. */
    867     bool fRc = AddCleanupRec(pszDstDir, false /*fFile*/, &hDir);
    868     AssertMsgReturn(fRc, ("Could not add cleanup record '%s': %Rrc\n", pszDstDir, rc), RTEXITCODE_FAILURE);
     973    /*
     974     * Change current directory to the extraction directory for the same reason
     975     * as we open it above.
     976     */
     977    RTPathSetCurrent(pszDstDir);
    869978
    870979    /*
     
    873982    for (unsigned k = 0; k < cPackages; k++)
    874983    {
    875         PVBOXSTUBPKG const pPackage = FindPackageHeader(k);
     984        VBOXSTUBPKG const * const pPackage = FindPackageHeader(k);
    876985        if (!pPackage)
    877986            return RTEXITCODE_FAILURE; /* Done complaining already. */
     
    879988        if (fExtractOnly || PackageIsNeeded(pPackage))
    880989        {
    881             char szDstFile[RTPATH_MAX];
    882             if (fExtractOnly) /* If we only extract, use the original file name. */
     990            /* If we only extract or if it's a common file, use the original file name,
     991               otherwise generate a random name with the same file extension (@bugref{10201}). */
     992            RTFILE hFile = NIL_RTFILE;
     993            char   szDstFile[RTPATH_MAX];
     994            if (fExtractOnly || pPackage->byArch == VBOXSTUBPKGARCH_ALL)
     995                rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, pPackage->szFileName);
     996            else
    883997            {
    884                 rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, pPackage->szFileName);
    885             }
    886             else /* When temporarily extracting and running, use a random file name. See @bugref{10201} */
    887             {
    888                 rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, "XXXXXXXXXXXX");
     998                rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, "XXXXXXXXXXXXXXXXXXXXXXXX");
    889999                if (RT_SUCCESS(rc))
    8901000                {
    891                     const char *pszDotExt = RTPathSuffix(pPackage->szFileName);
    892                     if (pszDotExt)
    893                         rc = RTStrCat(szDstFile, sizeof(szDstFile), pszDotExt);
     1001                    const char *pszSuffix = RTPathSuffix(pPackage->szFileName);
     1002                    if (pszSuffix)
     1003                        rc = RTStrCat(szDstFile, sizeof(szDstFile), pszSuffix);
    8941004                    if (RT_SUCCESS(rc))
    895                         rc = RTFileCreateTemp(szDstFile, 0700);
     1005                    {
     1006                        rc = RTFileCreateUnique(&hFile, szDstFile,
     1007                                                RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE
     1008                                                | (0700 << RTFILE_O_CREATE_MODE_SHIFT));
     1009                        if (RT_FAILURE(rc))
     1010                            return ShowError("Failed to create unique filename for '%s' in '%s': %Rrc",
     1011                                             pPackage->szFileName, pszDstDir, rc);
     1012                    }
    8961013                }
    8971014            }
     
    8991016                return ShowError("Internal error: Build extraction file name failed: %Rrc", rc);
    9001017
    901             rc = Extract(pPackage, szDstFile);
     1018            rc = Extract(pPackage, szDstFile, hFile, k);
    9021019            if (RT_FAILURE(rc))
    903                 return ShowError("Error extracting package #%u: %Rrc", k, rc);
     1020                return ShowError("Error extracting package #%u (%s): %Rrc", k, pPackage->szFileName, rc);
    9041021        }
    9051022    }
    906 
    907     /* Note: Closing the directory will be done when processing the cleanup record. */
    9081023
    9091024    return RTEXITCODE_SUCCESS;
     
    10201135
    10211136            case 'p':
    1022                 vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz);
    1023                 if (RT_FAILURE(vrc))
    1024                     return ShowSyntaxError("Extraction path is too long.");
     1137                if (*ValueUnion.psz == '\0')
     1138                    szExtractPath[0] = '\0';
     1139                else
     1140                {
     1141                    vrc = RTPathAbs(ValueUnion.psz, szExtractPath, sizeof(szExtractPath));
     1142                    if (RT_FAILURE(vrc))
     1143                        return ShowSyntaxError("Extraction path is too long (%Rrc)", vrc);
     1144                }
    10251145                break;
    10261146
     
    11371257
    11381258    /*
    1139      * Set a default extraction path if not explicitly given by the user.
    1140      *
    1141      * By default we're constructing a non-deterministic path.
    1142      * See @bugref{10201}
    1143      */
    1144     if (szExtractPath[0] == '\0')
    1145     {
    1146         vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
    1147         if (RT_SUCCESS(vrc))
    1148         {
    1149             if (!fExtractOnly) /* Only use a random sub-dir if we extract + run (and not just extract). */
    1150             {
    1151                 vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "XXXXXXXXXXXXXXXX");
    1152                 if (RT_SUCCESS(vrc))
    1153                     vrc = RTDirCreateTemp(szExtractPath, 0700); /** @todo Use RTDirCreateTempSecure() once it's implemented. */
    1154             }
    1155         }
    1156 
    1157         if (RT_FAILURE(vrc))
    1158             return ShowError("Failed to create extraction path: %Rrc", vrc);
    1159     }
    1160     RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */
    1161 
    1162     /*
    11631259     * Check if we're already running and jump out if so (this is mainly to
    11641260     * protect the TEMP directory usage, right?).
     
    11791275 *   */
    11801276    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     1277    RTListInit(&g_TmpFiles);
     1278
     1279    /*
     1280     * Create a random extraction directory in the temporary directory if none
     1281     * was given by the user (see @bugref{10201}).
     1282     */
     1283    PSTUBCLEANUPREC pExtractDirRec = NULL; /* This also indicates that */
     1284    if (szExtractPath[0] == '\0')
     1285    {
     1286        vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
     1287        if (RT_FAILURE(vrc))
     1288        {
     1289            CloseHandle(hMutexAppRunning); /* close it so we don't keep it open while showing the error message. */
     1290            return ShowError("Failed to find temporary directory: %Rrc", vrc);
     1291        }
     1292        if (!fExtractOnly) /* Only use a random sub-dir if we extract + run (and not just extract). */
     1293        {
     1294            vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "XXXXXXXXXXXXXXXXXXXXXXXX");
     1295            if (RT_SUCCESS(vrc))
     1296                /** @todo Need something that return a handle as well as a path. */
     1297                vrc = RTDirCreateTemp(szExtractPath, 0700);
     1298            if (RT_FAILURE(vrc))
     1299            {
     1300                CloseHandle(hMutexAppRunning); /* close it so we don't keep it open while showing the error message. */
     1301                return ShowError("Failed to create extraction path: %Rrc", vrc);
     1302            }
     1303            pExtractDirRec = AddCleanupRec(szExtractPath, false /*fIsFile*/);
     1304        }
     1305    }
     1306    RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */
    11811307
    11821308    /*
     
    12191345         * Read our manifest.
    12201346         */
    1221         PVBOXSTUBPKGHEADER pHeader = NULL;
    1222         vrc = FindData("MANIFEST", (PVOID *)&pHeader, NULL);
     1347        VBOXSTUBPKGHEADER const *pHeader = NULL;
     1348        vrc = FindData("MANIFEST", (uint8_t const **)&pHeader, NULL);
    12231349        if (RT_SUCCESS(vrc))
    12241350        {
     
    12261352             *        commonly defined, nor the version number... */
    12271353
    1228             RTListInit(&g_TmpFiles);
    1229 
    12301354            /*
    12311355             * Up to this point, we haven't done anything that requires any cleanup.
    12321356             * From here on, we do everything in functions so we can counter clean up.
    12331357             */
    1234             bool fCreatedExtractDir = false;
    1235             rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly, &fCreatedExtractDir);
     1358            rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly, &pExtractDirRec);
    12361359            if (rcExit == RTEXITCODE_SUCCESS)
    12371360            {
     
    12491372                           && (rcExit == RTEXITCODE_SUCCESS || rcExit == (RTEXITCODE)ERROR_SUCCESS_REBOOT_REQUIRED))
    12501373                    {
    1251                         RTEXITCODE rcExit2 = ProcessPackage(iPackage, szExtractPath, szMSIArgs, fEnableLogging);
     1374                        RTEXITCODE rcExit2 = ProcessPackage(iPackage, szMSIArgs, fEnableLogging);
    12521375                        if (rcExit2 != RTEXITCODE_SUCCESS)
    12531376                            rcExit = rcExit2;
     
    12611384             */
    12621385            if (!fExtractOnly)
    1263                 CleanUp(!fEnableLogging && fCreatedExtractDir ? szExtractPath : NULL);
     1386            {
     1387                RTPathSetCurrent("..");
     1388                CleanUp(!fEnableLogging && pExtractDirRec && !pExtractDirRec->fDontDelete ? szExtractPath : NULL);
     1389            }
    12641390
    12651391            /* Free any left behind cleanup records (not strictly needed). */
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