Changeset 94313 in vbox for trunk/src/VBox
- Timestamp:
- Mar 20, 2022 12:25:08 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp
r94285 r94313 86 86 /** True if file, false if directory. */ 87 87 bool fFile; 88 /** Set if we should not delete the file/directory. 89 * This is used for user supplied extraction directories. */ 90 bool fDontDelete; 88 91 union 89 92 { … … 103 106 * Prototypes * 104 107 *********************************************************************************************************************************/ 105 static bool AddCleanupRec(const char *pszPath, bool fFile, const void *phObj);108 static PSTUBCLEANUPREC AddCleanupRec(const char *pszPath, bool fIsFile); 106 109 107 110 … … 206 209 207 210 211 /** Logs error details to stderr. */ 212 static 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. */ 222 static 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. */ 233 static 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 208 243 /** 209 244 * Finds the specified in the resource section of the executable. … … 211 246 * @returns IPRT status code. 212 247 * 213 * @param pszDataName 214 * @param pp vResourceWhere to return the pointer to the data.215 * @param p dwSizeWhere to return the size of the data (if found).216 * 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 */ 253 static int FindData(const char *pszDataName, uint8_t const **ppbResource, DWORD *pcbResource) 219 254 { 220 255 AssertReturn(pszDataName, VERR_INVALID_PARAMETER); … … 235 270 DWORD cb = SizeofResource(hInst, hRsrc); 236 271 AssertReturn(cb > 0, VERR_NO_DATA); 237 if (p dwSize)238 *p dwSize = cb;272 if (pcbResource) 273 *pcbResource = cb; 239 274 240 275 /* Get pointer to resource. */ … … 243 278 244 279 /* Lock resource. */ 245 *pp vResource =LockResource(hData);246 AssertReturn(*pp vResource, VERR_IO_GEN_FAILURE);280 *ppbResource = (uint8_t const *)LockResource(hData); 281 AssertReturn(*ppbResource, VERR_IO_GEN_FAILURE); 247 282 return VINF_SUCCESS; 248 283 } … … 256 291 * @param iPackage The package number. 257 292 */ 258 static PVBOXSTUBPKGFindPackageHeader(unsigned iPackage)293 static const VBOXSTUBPKG *FindPackageHeader(unsigned iPackage) 259 294 { 260 295 char szHeaderName[32]; 261 296 RTStrPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", iPackage); 262 297 263 PVBOXSTUBPKGpPackage;264 int rc = FindData(szHeaderName, ( PVOID*)&pPackage, NULL);298 VBOXSTUBPKG const *pPackage; 299 int rc = FindData(szHeaderName, (uint8_t const **)&pPackage, NULL); 265 300 if (RT_FAILURE(rc)) 266 301 { … … 302 337 * @param pszResourceName The resource name to extract. 303 338 * @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 */ 344 static int ExtractFile(const char *pszResourceName, const char *pszTempFile, RTFILE hFile, unsigned idxPackage) 308 345 { 309 346 AssertPtrReturn(pszResourceName, VERR_INVALID_POINTER); 310 347 AssertPtrReturn(pszTempFile, VERR_INVALID_POINTER); 311 348 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 } 326 357 327 358 /* 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)); 337 398 338 399 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; 356 441 } 357 442 … … 364 449 * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource. 365 450 * @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 */ 456 static int Extract(VBOXSTUBPKG const *pPackage, const char *pszTempFile, RTFILE hFile, unsigned idxPackage) 457 { 458 return ExtractFile(pPackage->szResourceName, pszTempFile, hFile, idxPackage); 371 459 } 372 460 … … 400 488 * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource. 401 489 */ 402 static bool PackageIsNeeded( PVBOXSTUBPKGpPackage)490 static bool PackageIsNeeded(VBOXSTUBPKG const *pPackage) 403 491 { 404 492 if (pPackage->byArch == VBOXSTUBPKGARCH_ALL) … … 412 500 * Adds a cleanup record. 413 501 * 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. 415 506 * @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 */ 509 static PSTUBCLEANUPREC AddCleanupRec(const char *pszPath, bool fIsFile) 510 { 422 511 size_t cchPath = strlen(pszPath); Assert(cchPath > 0); 423 512 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 426 526 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; 438 528 } 439 529 … … 450 540 for (int i = 0; i < 5; i++) 451 541 { 452 int rc = VINF_SUCCESS; 453 bool fFinalTry = i == 4; 542 bool const fFinalTry = i == 4; 454 543 455 544 PSTUBCLEANUPREC pCur, pNext; 456 545 RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry) 457 546 { 547 int rc = VINF_SUCCESS; 458 548 if (pCur->fFile) 459 549 { 460 if ( RTFileIsValid(pCur->hFile))550 if (pCur->hFile != NIL_RTFILE) 461 551 { 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; 465 559 } 466 467 if (RT_SUCCESS(rc)) 560 if (!pCur->fDontDelete) 468 561 rc = RTFileDelete(pCur->szPath); 469 562 } 470 563 else /* Directory */ 471 564 { 472 if ( RTDirIsValid(pCur->hDir))565 if (pCur->hDir != NIL_RTDIR) 473 566 { 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; 477 574 } 478 575 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) 480 578 { 481 /* Note: Not removing the directory recursively, as we should have separate cleanup records for that. */482 579 rc = RTDirRemove(pCur->szPath); 483 580 if (rc == VERR_DIR_NOT_EMPTY && fFinalTry) … … 505 602 if (!pszPkgDir) 506 603 return; 507 rc = RTDirRemove(pszPkgDir);604 int rc = RTDirRemove(pszPkgDir); 508 605 if (RT_SUCCESS(rc) || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND || fFinalTry) 509 606 return; … … 670 767 * @returns Fully complained exit code. 671 768 * @param iPackage The package number. 672 * @param pszPkgDir The package directory (aka extraction dir).673 769 * @param pszMsiArgs Any additional installer (MSI) argument 674 770 * @param fLogging Whether to enable installer logging. 675 771 */ 676 static RTEXITCODE ProcessPackage(unsigned iPackage, const char *psz PkgDir, const char *pszMsiArgs, bool fLogging)772 static RTEXITCODE ProcessPackage(unsigned iPackage, const char *pszMsiArgs, bool fLogging) 677 773 { 678 774 /* 679 775 * Get the package header and check if it's needed. 680 776 */ 681 PVBOXSTUBPKGpPackage = FindPackageHeader(iPackage);777 VBOXSTUBPKG const * const pPackage = FindPackageHeader(iPackage); 682 778 if (pPackage == NULL) 683 779 return RTEXITCODE_FAILURE; … … 687 783 688 784 /* 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). 701 787 */ 702 788 PSTUBCLEANUPREC pRec = NULL; … … 710 796 } 711 797 } 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 */ 721 804 722 805 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) 727 810 rcExit = RTEXITCODE_SUCCESS; /* Ignore .cab files, they're generally referenced by other files. */ 728 811 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); 731 813 return rcExit; 732 814 } … … 820 902 return ShowError("Out of memory!"); 821 903 904 PSTUBCLEANUPREC pCleanupRec = AddCleanupRec(pszDstSubDir, false /*fIsFile*/); 905 AssertReturn(pCleanupRec, RTEXITCODE_FAILURE); 906 822 907 /* 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}). 825 909 */ 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. */ 826 913 RTDIR hDstSubDir; 827 914 rc = RTDirOpen(&hDstSubDir, pszDstSubDir); 828 915 if (RT_FAILURE(rc)) 829 916 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; 834 918 835 919 RTStrFree(pszDstSubDir); 836 if (!fRc)837 return RTEXITCODE_FAILURE;838 920 } 839 921 … … 842 924 843 925 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 */ 936 static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly, PSTUBCLEANUPREC *ppExtractDirRec) 845 937 { 846 938 int rc; 847 939 848 940 /* 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; 852 944 if (!RTDirExists(pszDstDir)) 853 945 { 946 AssertReturn(!pCleanupRec, ShowError("RTDirExists failed on '%s' which we just created!", pszDstDir)); 947 854 948 rc = RTDirCreate(pszDstDir, 0700, 0); 855 949 if (RT_FAILURE(rc)) 856 950 return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc); 857 951 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); 863 970 if (RT_FAILURE(rc)) 864 971 return ShowError("Failed to open extraction path '%s': %Rrc", pszDstDir, rc); 865 972 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); 869 978 870 979 /* … … 873 982 for (unsigned k = 0; k < cPackages; k++) 874 983 { 875 PVBOXSTUBPKGconst pPackage = FindPackageHeader(k);984 VBOXSTUBPKG const * const pPackage = FindPackageHeader(k); 876 985 if (!pPackage) 877 986 return RTEXITCODE_FAILURE; /* Done complaining already. */ … … 879 988 if (fExtractOnly || PackageIsNeeded(pPackage)) 880 989 { 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 883 997 { 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"); 889 999 if (RT_SUCCESS(rc)) 890 1000 { 891 const char *psz DotExt= RTPathSuffix(pPackage->szFileName);892 if (psz DotExt)893 rc = RTStrCat(szDstFile, sizeof(szDstFile), psz DotExt);1001 const char *pszSuffix = RTPathSuffix(pPackage->szFileName); 1002 if (pszSuffix) 1003 rc = RTStrCat(szDstFile, sizeof(szDstFile), pszSuffix); 894 1004 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 } 896 1013 } 897 1014 } … … 899 1016 return ShowError("Internal error: Build extraction file name failed: %Rrc", rc); 900 1017 901 rc = Extract(pPackage, szDstFile );1018 rc = Extract(pPackage, szDstFile, hFile, k); 902 1019 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); 904 1021 } 905 1022 } 906 907 /* Note: Closing the directory will be done when processing the cleanup record. */908 1023 909 1024 return RTEXITCODE_SUCCESS; … … 1020 1135 1021 1136 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 } 1025 1145 break; 1026 1146 … … 1137 1257 1138 1258 /* 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 /*1163 1259 * Check if we're already running and jump out if so (this is mainly to 1164 1260 * protect the TEMP directory usage, right?). … … 1179 1275 * */ 1180 1276 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. */ 1181 1307 1182 1308 /* … … 1219 1345 * Read our manifest. 1220 1346 */ 1221 PVBOXSTUBPKGHEADERpHeader = NULL;1222 vrc = FindData("MANIFEST", ( PVOID*)&pHeader, NULL);1347 VBOXSTUBPKGHEADER const *pHeader = NULL; 1348 vrc = FindData("MANIFEST", (uint8_t const **)&pHeader, NULL); 1223 1349 if (RT_SUCCESS(vrc)) 1224 1350 { … … 1226 1352 * commonly defined, nor the version number... */ 1227 1353 1228 RTListInit(&g_TmpFiles);1229 1230 1354 /* 1231 1355 * Up to this point, we haven't done anything that requires any cleanup. 1232 1356 * From here on, we do everything in functions so we can counter clean up. 1233 1357 */ 1234 bool fCreatedExtractDir = false; 1235 rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly, &fCreatedExtractDir); 1358 rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly, &pExtractDirRec); 1236 1359 if (rcExit == RTEXITCODE_SUCCESS) 1237 1360 { … … 1249 1372 && (rcExit == RTEXITCODE_SUCCESS || rcExit == (RTEXITCODE)ERROR_SUCCESS_REBOOT_REQUIRED)) 1250 1373 { 1251 RTEXITCODE rcExit2 = ProcessPackage(iPackage, sz ExtractPath, szMSIArgs, fEnableLogging);1374 RTEXITCODE rcExit2 = ProcessPackage(iPackage, szMSIArgs, fEnableLogging); 1252 1375 if (rcExit2 != RTEXITCODE_SUCCESS) 1253 1376 rcExit = rcExit2; … … 1261 1384 */ 1262 1385 if (!fExtractOnly) 1263 CleanUp(!fEnableLogging && fCreatedExtractDir ? szExtractPath : NULL); 1386 { 1387 RTPathSetCurrent(".."); 1388 CleanUp(!fEnableLogging && pExtractDirRec && !pExtractDirRec->fDontDelete ? szExtractPath : NULL); 1389 } 1264 1390 1265 1391 /* Free any left behind cleanup records (not strictly needed). */
Note:
See TracChangeset
for help on using the changeset viewer.