VirtualBox

Ignore:
Timestamp:
Apr 4, 2013 9:43:25 AM (12 years ago)
Author:
vboxsync
Message:

VBoxStub.cpp: Don't delete the extraction directory recursively since the user can point this to C:\Windows or worse places via --path. Converted everything to use unicode APIs (won't allow non-koreans to use hangul paths for the actual installation since cabinet.dll doesn't speak unicode).

File:
1 edited

Legend:

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

    r45320 r45332  
    1919*   Header Files                                                               *
    2020*******************************************************************************/
    21 #include <windows.h>
     21#include <Windows.h>
    2222#include <commctrl.h>
    2323#include <lmerr.h>
    2424#include <msiquery.h>
    2525#include <objbase.h>
     26
    2627#include <shlobj.h>
    2728#include <stdlib.h>
     
    3536#include <iprt/dir.h>
    3637#include <iprt/file.h>
     38#include <iprt/getopt.h>
    3739#include <iprt/initterm.h>
    38 #include <iprt/getopt.h>
     40#include <iprt/list.h>
    3941#include <iprt/mem.h>
    4042#include <iprt/message.h>
     43#include <iprt/param.h>
    4144#include <iprt/path.h>
    42 #include <iprt/param.h>
    4345#include <iprt/stream.h>
    4446#include <iprt/string.h>
     
    5456#endif
    5557
    56 #ifndef  _UNICODE /* Isn't this a little late? */
    57 #define  _UNICODE
    58 #endif
     58
     59/*******************************************************************************
     60*   Defined Constants And Macros                                               *
     61*******************************************************************************/
     62#define MY_UNICODE_SUB(str) L ##str
     63#define MY_UNICODE(str)     MY_UNICODE_SUB(str)
     64
     65
     66/*******************************************************************************
     67*   Structures and Typedefs                                                    *
     68*******************************************************************************/
     69/**
     70 * Cleanup record.
     71 */
     72typedef struct STUBCLEANUPREC
     73{
     74    /** List entry. */
     75    RTLISTNODE  ListEntry;
     76    /** True if file, false if directory. */
     77    bool        fFile;
     78    /** The path to the file or directory to clean up. */
     79    char        szPath[1];
     80} STUBCLEANUPREC;
     81/** Pointer to a cleanup record. */
     82typedef STUBCLEANUPREC *PSTUBCLEANUPREC;
    5983
    6084
     
    6286*   Global Variables                                                           *
    6387*******************************************************************************/
    64 static bool g_fSilent = false;
     88/** Whether it's a silent or interactive GUI driven install. */
     89static bool             g_fSilent = false;
     90/** List of temporary files. */
     91static RTLISTANCHOR     g_TmpFiles;
     92
    6593
    6694
     
    83111            RTMsgError("%s", pszMsg);
    84112        else
    85             MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR);
     113        {
     114            PRTUTF16 pwszMsg;
     115            int rc = RTStrToUtf16(pszMsg, &pwszMsg);
     116            if (RT_SUCCESS(rc))
     117            {
     118                MessageBoxW(GetDesktopWindow(), pwszMsg, MY_UNICODE(VBOX_STUB_TITLE), MB_ICONERROR);
     119                RTUtf16Free(pwszMsg);
     120            }
     121            else
     122                MessageBoxA(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR);
     123        }
    86124        RTStrFree(pszMsg);
    87125    }
     
    112150            RTPrintf("%s\n", pszMsg);
    113151        else
    114             MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION);
     152        {
     153            PRTUTF16 pwszMsg;
     154            int rc = RTStrToUtf16(pszMsg, &pwszMsg);
     155            if (RT_SUCCESS(rc))
     156            {
     157                MessageBoxW(GetDesktopWindow(), pwszMsg, MY_UNICODE(VBOX_STUB_TITLE), MB_ICONINFORMATION);
     158                RTUtf16Free(pwszMsg);
     159            }
     160            else
     161                MessageBoxA(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION);
     162        }
    115163    }
    116164    else /* Should never happen! */
     
    129177 * @param   pdwSize             Where to return the size of the data (if found).
    130178 *                              Optional.
    131  *
    132  */
    133 static int FindData(const char *pszDataName,
    134                     PVOID      *ppvResource,
    135                     DWORD      *pdwSize)
     179 */
     180static int FindData(const char *pszDataName, PVOID *ppvResource, DWORD *pdwSize)
    136181{
    137182    AssertReturn(pszDataName, VERR_INVALID_PARAMETER);
    138     HINSTANCE hInst = NULL;
     183    HINSTANCE hInst = NULL;             /* indicates the executable image */
    139184
    140185    /* Find our resource. */
    141     HRSRC hRsrc = FindResourceEx(hInst, RT_RCDATA, pszDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
     186    PRTUTF16 pwszDataName;
     187    int rc = RTStrToUtf16(pszDataName, &pwszDataName);
     188    AssertRCReturn(rc, rc);
     189    HRSRC hRsrc = FindResourceExW(hInst,
     190                                  (LPWSTR)RT_RCDATA,
     191                                  pwszDataName,
     192                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
     193    RTUtf16Free(pwszDataName);
    142194    AssertReturn(hRsrc, VERR_IO_GEN_FAILURE);
    143195
     
    303355 * Decides whether we need a specified package to handle or not.
    304356 *
    305  * @returns TRUE if we need to handle the specified package, FALSE if not.
     357 * @returns @c true if we need to handle the specified package, @c false if not.
    306358 *
    307359 * @param   pPackage            Pointer to a VBOXSTUBPKG struct that contains the resource.
    308360 *
    309361 */
    310 static BOOL PackageIsNeeded(PVBOXSTUBPKG pPackage)
    311 {
    312     BOOL bIsWow64 = IsWow64();
    313     if ((bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_AMD64)) /* 64bit Windows. */
    314     {
    315         return TRUE;
    316     }
    317     else if ((!bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_X86)) /* 32bit. */
    318     {
    319         return TRUE;
    320     }
    321     else if (pPackage->byArch == VBOXSTUBPKGARCH_ALL)
    322     {
    323         return TRUE;
    324     }
    325     return FALSE;
     362static bool PackageIsNeeded(PVBOXSTUBPKG pPackage)
     363{
     364    if (pPackage->byArch == VBOXSTUBPKGARCH_ALL)
     365        return true;
     366    VBOXSTUBPKGARCH enmArch = IsWow64() ? VBOXSTUBPKGARCH_AMD64 : VBOXSTUBPKGARCH_X86;
     367    return pPackage->byArch == enmArch;
     368}
     369
     370
     371/**
     372 * Adds a cleanup record.
     373 *
     374 * @returns Fully complained boolean success indicator.
     375 * @param   pszPath             The path to the file or directory to clean up.
     376 * @param   fFile               @c true if file, @c false if directory.
     377 */
     378static bool AddCleanupRec(const char *pszPath, bool fFile)
     379{
     380    size_t cchPath = strlen(pszPath); Assert(cchPath > 0);
     381    PSTUBCLEANUPREC pRec = (PSTUBCLEANUPREC)RTMemAlloc(RT_OFFSETOF(STUBCLEANUPREC, szPath[cchPath + 1]));
     382    if (!pRec)
     383    {
     384        ShowError("Out of memory!");
     385        return false;
     386    }
     387    pRec->fFile = fFile;
     388    memcpy(pRec->szPath, pszPath, cchPath + 1);
     389
     390    RTListPrepend(&g_TmpFiles, &pRec->ListEntry);
     391    return true;
     392}
     393
     394
     395/**
     396 * Cleans up all the extracted files and optionally removes the package
     397 * directory.
     398 *
     399 * @param   cPackages           The number of packages.
     400 * @param   pszPkgDir           The package directory, NULL if it shouldn't be
     401 *                              removed.
     402 */
     403static void CleanUp(unsigned cPackages, const char *pszPkgDir)
     404{
     405    for (int i = 0; i < 5; i++)
     406    {
     407        int rc;
     408        bool fFinalTry = i == 4;
     409
     410        PSTUBCLEANUPREC pCur, pNext;
     411        RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry)
     412        {
     413            if (pCur->fFile)
     414                rc = RTFileDelete(pCur->szPath);
     415            else
     416            {
     417                rc = RTDirRemoveRecursive(pCur->szPath, RTDIRRMREC_F_CONTENT_AND_DIR);
     418                if (rc == VERR_DIR_NOT_EMPTY && fFinalTry)
     419                    rc = VINF_SUCCESS;
     420            }
     421            if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
     422                rc = VINF_SUCCESS;
     423            if (RT_SUCCESS(rc))
     424            {
     425                RTListNodeRemove(&pCur->ListEntry);
     426                RTMemFree(pCur);
     427            }
     428            else if (fFinalTry)
     429            {
     430                if (pCur->fFile)
     431                    ShowError("Failed to delete temporary file '%s': %Rrc", pCur->szPath, rc);
     432                else
     433                    ShowError("Failed to delete temporary directory '%s': %Rrc", pCur->szPath, rc);
     434            }
     435        }
     436
     437        if (RTListIsEmpty(&g_TmpFiles) || fFinalTry)
     438        {
     439            if (!pszPkgDir)
     440                return;
     441            rc = RTDirRemove(pszPkgDir);
     442            if (RT_SUCCESS(rc) || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND || fFinalTry)
     443                return;
     444        }
     445
     446        /* Delay a little and try again. */
     447        RTThreadSleep(i == 0 ? 100 : 3000);
     448    }
    326449}
    327450
     
    331454 *
    332455 * @returns Fully complained exit code.
    333  * @param   iPackage            The package number.
    334456 * @param   pszMsi              The path to the MSI to process.
    335457 * @param   pszMsiArgs          Any additional installer (MSI) argument
    336458 * @param   fLogging            Whether to enable installer logging.
    337459 */
    338 static RTEXITCODE ProcessMsiPackage(unsigned iPackage, const char *pszMsi, const char *pszMsiArgs, bool fLogging)
     460static RTEXITCODE ProcessMsiPackage(const char *pszMsi, const char *pszMsiArgs, bool fLogging)
    339461{
    340462    int rc;
     
    370492        UINT uLogLevel = MsiEnableLogW(INSTALLLOGMODE_VERBOSE,
    371493                                       pwszLogFile,
    372                                        INSTALLLOGATTRIBUTES_FLUSHEACHLINE | (iPackage > 0 ? INSTALLLOGATTRIBUTES_APPEND : 0));
     494                                       INSTALLLOGATTRIBUTES_FLUSHEACHLINE);
    373495        RTUtf16Free(pwszLogFile);
    374496        if (uLogLevel != ERROR_SUCCESS)
     
    441563            if (uStatus >= NERR_BASE && uStatus <= MAX_NERR)
    442564            {
    443                 hModule = LoadLibraryEx(TEXT("netmsg.dll"),
    444                                         NULL,
    445                                         LOAD_LIBRARY_AS_DATAFILE);
     565                hModule = LoadLibraryExW(L"netmsg.dll",
     566                                         NULL,
     567                                         LOAD_LIBRARY_AS_DATAFILE);
    446568                if (hModule != NULL)
    447569                    dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
    448570            }
    449571
    450             /** @todo this is totally WRONG wrt to string code pages. We expect UTF-8
    451              *        while the ANSI code page might be one of the special Chinese ones,
    452              *        IPRT is going to be so angry with us (and so will the users). */
    453             DWORD dwBufferLength;
    454             LPSTR szMessageBuffer;
    455             if (dwBufferLength = FormatMessageA(dwFormatFlags,
    456                                                 hModule, /* If NULL, load system stuff. */
    457                                                 uStatus,
    458                                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    459                                                 (LPSTR)&szMessageBuffer,
    460                                                 0,
    461                                                 NULL))
     572            PWSTR pwszMsg;
     573            if (FormatMessageW(dwFormatFlags,
     574                               hModule, /* If NULL, load system stuff. */
     575                               uStatus,
     576                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     577                               (PWSTR)&pwszMsg,
     578                               0,
     579                               NULL) > 0)
    462580            {
    463                 ShowError("Installation failed! Error: %s", szMessageBuffer);
    464                 LocalFree(szMessageBuffer);
     581                ShowError("Installation failed! Error: %ls", pwszMsg);
     582                LocalFree(pwszMsg);
    465583            }
    466584            else /* If text lookup failed, show at least the error number. */
     
    501619     * Deal with the file based on it's extension.
    502620     */
    503     char *pszPkgFile = RTPathJoinA(pszPkgDir, pPackage->szFileName);
    504     if (!pszPkgFile)
    505         return ShowError("Out of memory on line #%u!", __LINE__);
    506     RTPathChangeToDosSlashes(pszPkgFile, true /* Force conversion. */); /* paranoia */
     621    char szPkgFile[RTPATH_MAX];
     622    int rc = RTPathJoin(szPkgFile, sizeof(szPkgFile), pszPkgDir, pPackage->szFileName);
     623    if (RT_FAILURE(rc))
     624        return ShowError("Internal error: RTPathJoin failed: %Rrc", rc);
     625    RTPathChangeToDosSlashes(szPkgFile, true /* Force conversion. */); /* paranoia */
    507626
    508627    RTEXITCODE rcExit;
    509     const char *pszExt = RTPathExt(pszPkgFile);
     628    const char *pszExt = RTPathExt(szPkgFile);
    510629    if (RTStrICmp(pszExt, ".msi") == 0)
    511         rcExit = ProcessMsiPackage(iPackage, pszPkgFile, pszMsiArgs, fLogging);
     630        rcExit = ProcessMsiPackage(szPkgFile, pszMsiArgs, fLogging);
     631    else if (RTStrICmp(pszExt, ".cab") == 0)
     632        rcExit = RTEXITCODE_SUCCESS; /* Ignore .cab files, they're generally referenced by other files. */
    512633    else
    513634        rcExit = ShowError("Internal error: Do not know how to handle file '%s'.", pPackage->szFileName);
    514635
    515     RTStrFree(pszPkgFile);
    516636    return rcExit;
    517637}
     
    548668{
    549669    char szSrcDir[RTPATH_MAX];
    550     int rc = RTPathExecDir(szSrcDir, sizeof(szSrcDir) - 1);
     670    int rc = RTPathExecDir(szSrcDir, sizeof(szSrcDir));
    551671    if (RT_SUCCESS(rc))
    552         rc = RTPathAppend(szSrcDir, sizeof(szSrcDir) - 1, ".custom");
     672        rc = RTPathAppend(szSrcDir, sizeof(szSrcDir), ".custom");
    553673    if (RT_FAILURE(rc))
    554674        return ShowError("Failed to construct '.custom' dir path: %Rrc", rc);
     
    558678        /*
    559679         * Use SHFileOperation w/ FO_COPY to do the job.  This API requires an
    560          * extra zero at the end of both source and destination paths.  Thus
    561          * the -1 above and below.
     680         * extra zero at the end of both source and destination paths.
    562681         */
    563682        size_t   cwc;
    564         RTUTF16  wszSrcDir[RTPATH_MAX + 2];
     683        RTUTF16  wszSrcDir[RTPATH_MAX + 1];
    565684        PRTUTF16 pwszSrcDir = wszSrcDir;
    566685        rc = RTStrToUtf16Ex(szSrcDir, RTSTR_MAX, &pwszSrcDir, RTPATH_MAX, &cwc);
     
    569688        wszSrcDir[cwc] = '\0';
    570689
    571         RTUTF16  wszDstDir[RTPATH_MAX + 2];
     690        RTUTF16  wszDstDir[RTPATH_MAX + 1];
    572691        PRTUTF16 pwszDstDir = wszSrcDir;
    573692        rc = RTStrToUtf16Ex(pszDstDir, RTSTR_MAX, &pwszDstDir, RTPATH_MAX, &cwc);
     
    593712        if (rc != 0)    /* Not a Win32 status code! */
    594713            return ShowError("Copying the '.custom' dir failed: %#x", rc);
     714
     715        /*
     716         * Add a cleanup record for recursively deleting the destination
     717         * .custom directory.  We should actually add this prior to calling
     718         * SHFileOperationW since it may partially succeed...
     719         */
     720        char *pszDstSubDir = RTPathJoinA(pszDstDir, ".custom");
     721        if (!pszDstSubDir)
     722            return ShowError("Out of memory!");
     723        bool fRc = AddCleanupRec(pszDstSubDir, false /*fFile*/);
     724        RTStrFree(pszDstSubDir);
     725        if (!fRc)
     726            return RTEXITCODE_FAILURE;
    595727    }
    596728
     
    599731
    600732
    601 static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly)
     733static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly, bool *pfCreatedExtractDir)
    602734{
    603735    int rc;
     
    606738     * Make sure the directory exists.
    607739     */
     740    *pfCreatedExtractDir = false;
    608741    if (!RTDirExists(pszDstDir))
    609742    {
     
    611744        if (RT_FAILURE(rc))
    612745            return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc);
     746        *pfCreatedExtractDir = true;
    613747    }
    614748
     
    624758        if (fExtractOnly || PackageIsNeeded(pPackage))
    625759        {
    626             char *pszDstFile = RTPathJoinA(pszDstDir, pPackage->szFileName);
    627             if (!pszDstFile)
    628                 return ShowError("Out of memory on line %u!", __LINE__);
    629 
    630             rc = Extract(pPackage, pszDstFile);
    631             RTStrFree(pszDstFile);
     760            char szDstFile[RTPATH_MAX];
     761            rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, pPackage->szFileName);
     762            if (RT_FAILURE(rc))
     763                return ShowError("Internal error: RTPathJoin failed: %Rrc", rc);
     764
     765            rc = Extract(pPackage, szDstFile);
    632766            if (RT_FAILURE(rc))
    633767                return ShowError("Error extracting package #%u: %Rrc", k, rc);
     768
     769            if (!fExtractOnly && !AddCleanupRec(szDstFile, true /*fFile*/))
     770            {
     771                RTFileDelete(szDstFile);
     772                return RTEXITCODE_FAILURE;
     773            }
    634774        }
    635775    }
     
    758898            case 'h':
    759899                ShowInfo("-- %s v%d.%d.%d.%d --\n"
     900                         "\n"
    760901                         "Command Line Parameters:\n\n"
    761902                         "--extract                - Extract file contents to temporary directory\n"
     
    803944
    804945    }
     946    else
     947    {
     948        /** @todo should check if there is a .custom subdirectory there or not. */
     949    }
    805950    RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */
    806951
     
    813958     *        commonly defined, nor the version number... */
    814959
     960    RTListInit(&g_TmpFiles);
     961
    815962    /*
    816963     * Up to this point, we haven't done anything that requires any cleanup.
    817964     * From here on, we do everything in function so we can counter clean up.
    818965     */
    819     RTEXITCODE rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly);
     966    bool fCreatedExtractDir;
     967    RTEXITCODE rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly, &fCreatedExtractDir);
    820968    if (rcExit == RTEXITCODE_SUCCESS)
    821969    {
    822970        if (fExtractOnly)
    823         {
    824             if (!g_fSilent)
    825                 ShowInfo("Files were extracted to: %s", szExtractPath);
    826         }
     971            ShowInfo("Files were extracted to: %s", szExtractPath);
    827972        else
    828973        {
     
    830975#ifdef VBOX_WITH_CODE_SIGNING
    831976            if (rcExit == RTEXITCODE_SUCCESS && fEnableSilentCert && g_fSilent)
    832                 InstallCertificate();
     977                rcExit = InstallCertificate();
    833978#endif
    834979            unsigned iPackage = 0;
     
    838983                iPackage++;
    839984            }
     985
     986            /* Don't fail if cleanup fail. At least for now. */
     987            CleanUp(pHeader->byCntPkgs, !fEnableLogging && fCreatedExtractDir ? szExtractPath : NULL);
    840988        }
    841989    }
    842990
    843 
    844 
    845     do /* break loop */
    846     {
    847 
    848         /* Clean up (only on success - prevent deleting the log). */
    849         if (   !fExtractOnly
    850             && RT_SUCCESS(vrc))
    851         {
    852             for (int i = 0; i < 5; i++)
    853             {
    854                 vrc = RTDirRemoveRecursive(szExtractPath, 0 /*fFlags*/);
    855                 if (RT_SUCCESS(vrc))
    856                     break;
    857                 RTThreadSleep(3000 /* Wait 3 seconds.*/);
    858             }
    859         }
    860 
    861     } while (0);
    862 
    863     /* Release instance mutex. */
     991    /* Free any left behind cleanup records (not strictly needed). */
     992    PSTUBCLEANUPREC pCur, pNext;
     993    RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry)
     994    {
     995        RTListNodeRemove(&pCur->ListEntry);
     996        RTMemFree(pCur);
     997    }
     998
     999    /*
     1000     * Release instance mutex.
     1001     */
    8641002    if (hMutexAppRunning != NULL)
    8651003    {
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