Changeset 94284 in vbox
- Timestamp:
- Mar 17, 2022 11:12:27 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp
r93391 r94284 82 82 /** List entry. */ 83 83 RTLISTNODE ListEntry; 84 /** Stub package index (zero-based) this record belongs to. */ 85 unsigned idxPkg; 84 86 /** True if file, false if directory. */ 85 87 bool fFile; 88 union 89 { 90 /** File handle (if \a fFile is \c true). */ 91 RTFILE hFile; 92 /** Directory handle (if \a fFile is \c false). */ 93 RTDIR hDir; 94 }; 86 95 /** The path to the file or directory to clean up. */ 87 96 char szPath[1]; … … 89 98 /** Pointer to a cleanup record. */ 90 99 typedef STUBCLEANUPREC *PSTUBCLEANUPREC; 100 101 /********************************************************************************************************************************* 102 * Prototypes * 103 *********************************************************************************************************************************/ 104 static bool AddCleanupRec(const char *pszPath, bool fFile, const void *phObj); 91 105 92 106 … … 292 306 const char *pszTempFile) 293 307 { 294 #if 0 /* Another example of how unnecessarily complicated things get with295 do-break-while-false and you end up with buggy code using uninitialized296 variables. */297 int rc;298 RTFILE fh;299 BOOL bCreatedFile = FALSE;300 301 do302 {303 AssertMsgBreak(pszResourceName, ("Resource pointer invalid!\n")); /* rc is not initialized here, we'll return garbage. */304 AssertMsgBreak(pszTempFile, ("Temp file pointer invalid!")); /* Ditto. */305 306 /* Read the data of the built-in resource. */307 PVOID pvData = NULL;308 DWORD dwDataSize = 0;309 rc = FindData(pszResourceName, &pvData, &dwDataSize);310 AssertMsgRCBreak(rc, ("Could not read resource data!\n"));311 312 /* Create new (and replace an old) file. */313 rc = RTFileOpen(&fh, pszTempFile,314 RTFILE_O_CREATE_REPLACE315 | RTFILE_O_WRITE316 | RTFILE_O_DENY_NOT_DELETE317 | RTFILE_O_DENY_WRITE);318 AssertMsgRCBreak(rc, ("Could not open file for writing!\n"));319 bCreatedFile = TRUE;320 321 /* Write contents to new file. */322 size_t cbWritten = 0;323 rc = RTFileWrite(fh, pvData, dwDataSize, &cbWritten);324 AssertMsgRCBreak(rc, ("Could not open file for writing!\n"));325 AssertMsgBreak(dwDataSize == cbWritten, ("File was not extracted completely! Disk full?\n"));326 327 } while (0);328 329 if (RTFileIsValid(fh)) /* fh is unused uninitalized (MSC agrees) */330 RTFileClose(fh);331 332 if (RT_FAILURE(rc))333 {334 if (bCreatedFile)335 RTFileDelete(pszTempFile);336 }337 338 #else /* This is exactly the same as above, except no bug and better assertion339 message. Note only the return-success statment is indented, indicating340 that the whole do-break-while-false approach was totally unnecessary. */341 342 308 AssertPtrReturn(pszResourceName, VERR_INVALID_POINTER); 343 309 AssertPtrReturn(pszTempFile, VERR_INVALID_POINTER); … … 354 320 RTFILE_O_CREATE_REPLACE 355 321 | RTFILE_O_WRITE 356 | RTFILE_O_DENY_NOT_DELETE357 322 | RTFILE_O_DENY_WRITE); 323 358 324 AssertMsgRCReturn(rc, ("Could not open '%s' for writing: %Rrc\n", pszTempFile, rc), rc); 325 326 /* Add a cleanup record, so that we can properly clean up (partially run) stuff. */ 327 bool fRc = AddCleanupRec(pszTempFile, true /*fFile*/, &hFile); 328 AssertMsgReturn(fRc, ("Could not add cleanup record '%s': %Rrc\n", pszTempFile, rc), rc); 359 329 360 330 /* Write contents to new file. */ … … 363 333 AssertMsgStmt(cbWritten == dwDataSize || RT_FAILURE_NP(rc), ("%#zx vs %#x\n", cbWritten, dwDataSize), rc = VERR_WRITE_ERROR); 364 334 365 int rc2 = RTFileClose(hFile); 366 AssertRC(rc2); 335 /* See @bugref{10201} comment 8. */ 336 337 rc = RTFileClose(hFile); 338 AssertMsgRCReturn(rc, ("Closing file failed: %Rrc\n", rc), rc); 339 340 rc = RTFileOpen(&hFile, pszTempFile, 341 RTFILE_O_OPEN 342 | RTFILE_O_READ 343 | RTFILE_O_DENY_WRITE); 344 AssertMsgRCReturn(rc, ("Could not open '%s' for reading: %Rrc\n", pszTempFile, rc), rc); 345 346 /* 347 * Note: We keep the file open so that nobody else can write to it until we're done. 348 * See @bugref{10201} 349 */ 367 350 368 351 if (RT_SUCCESS(rc)) 369 352 return VINF_SUCCESS; 370 353 371 RTFileDelete(pszTempFile);372 373 #endif374 354 return rc; 375 355 } … … 434 414 * @param pszPath The path to the file or directory to clean up. 435 415 * @param fFile @c true if file, @c false if directory. 436 */ 437 static bool AddCleanupRec(const char *pszPath, bool fFile) 438 { 416 * @param phObj File / directory handle, depending on \a fFile. 417 */ 418 static bool AddCleanupRec(const char *pszPath, bool fFile, const void *phObj) 419 { 420 AssertPtrReturn(phObj, false); 439 421 size_t cchPath = strlen(pszPath); Assert(cchPath > 0); 440 PSTUBCLEANUPREC pRec = (PSTUBCLEANUPREC)RTMemAlloc (RT_UOFFSETOF_DYN(STUBCLEANUPREC, szPath[cchPath + 1]));422 PSTUBCLEANUPREC pRec = (PSTUBCLEANUPREC)RTMemAllocZ(RT_UOFFSETOF_DYN(STUBCLEANUPREC, szPath[cchPath + 1])); 441 423 if (!pRec) 442 424 { … … 445 427 } 446 428 pRec->fFile = fFile; 429 if (pRec->fFile) 430 memcpy(&pRec->hFile, phObj, sizeof(RTFILE)); 431 else 432 memcpy(&pRec->hDir, phObj, sizeof(RTDIR)); 447 433 memcpy(pRec->szPath, pszPath, cchPath + 1); 448 434 … … 463 449 for (int i = 0; i < 5; i++) 464 450 { 465 int rc ;451 int rc = VINF_SUCCESS; 466 452 bool fFinalTry = i == 4; 467 453 … … 470 456 { 471 457 if (pCur->fFile) 472 rc = RTFileDelete(pCur->szPath); 473 else 474 { 475 rc = RTDirRemoveRecursive(pCur->szPath, RTDIRRMREC_F_CONTENT_AND_DIR); 476 if (rc == VERR_DIR_NOT_EMPTY && fFinalTry) 477 rc = VINF_SUCCESS; 458 { 459 if (RTFileIsValid(pCur->hFile)) 460 { 461 rc = RTFileClose(pCur->hFile); 462 if (RT_SUCCESS(rc)) 463 pCur->hFile = NIL_RTFILE; 464 } 465 466 if (RT_SUCCESS(rc)) 467 rc = RTFileDelete(pCur->szPath); 468 } 469 else /* Directory */ 470 { 471 if (RTDirIsValid(pCur->hDir)) 472 { 473 rc = RTDirClose(pCur->hDir); 474 if (RT_SUCCESS(rc)) 475 pCur->hDir = NIL_RTDIR; 476 } 477 478 if (RT_SUCCESS(rc)) 479 { 480 /* Note: Not removing the directory recursively, as we should have separate cleanup records for that. */ 481 rc = RTDirRemove(pCur->szPath); 482 if (rc == VERR_DIR_NOT_EMPTY && fFinalTry) 483 rc = VINF_SUCCESS; 484 } 478 485 } 479 486 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) … … 682 689 */ 683 690 char szPkgFile[RTPATH_MAX]; 684 int rc = RTPathJoin(szPkgFile, sizeof(szPkgFile), pszPkgDir, pPackage->szFileName); 691 692 /* 693 * Use the cleanup record to built-up the final name to process, as the cleanup record's file name might be different 694 * than the original package's name. 695 * 696 * We can't write to the package's attributes, as those point to a write-protected area within the stub loader. 697 * So I didn't feel to re-writing nearly everything here and went for this approach instead. 698 * 699 ** @todo The structure / stub API needs a major overhaul.* 700 */ 701 PSTUBCLEANUPREC pRec = NULL; 702 PSTUBCLEANUPREC pCur; 703 RTListForEach(&g_TmpFiles, pCur, STUBCLEANUPREC, ListEntry) 704 { 705 if (pCur->idxPkg == iPackage) 706 { 707 pRec = pCur; 708 break; 709 } 710 } 711 AssertMsgReturn(pRec != NULL, ("Package #%x not found in cleanup records\n", iPackage), RTEXITCODE_FAILURE); 712 713 const char *pszFileName = RTPathFilename(pRec->szPath); 714 AssertMsgReturn(pszFileName != NULL, ("Cleanup record does not have a valid file name\n"), RTEXITCODE_FAILURE); 715 int rc = RTPathJoin(szPkgFile, sizeof(szPkgFile), pszPkgDir, pszFileName); 685 716 if (RT_FAILURE(rc)) 686 717 return ShowError("Internal error: RTPathJoin failed: %Rrc", rc); 718 687 719 RTPathChangeToDosSlashes(szPkgFile, true /* Force conversion. */); /* paranoia */ 688 720 … … 786 818 if (!pszDstSubDir) 787 819 return ShowError("Out of memory!"); 788 bool fRc = AddCleanupRec(pszDstSubDir, false /*fFile*/); 820 821 /* 822 * Note: We keep the directory open so that nobody else can delete / replace it while we're working on it. 823 * See @bugref{10201} 824 */ 825 RTDIR hDstSubDir; 826 rc = RTDirOpen(&hDstSubDir, pszDstSubDir); 827 if (RT_FAILURE(rc)) 828 return ShowError("Unable to open the destination .custom directory: %Rrc", rc); 829 830 /* Add a cleanup record. */ 831 bool fRc = AddCleanupRec(pszDstSubDir, false /*fFile*/, &hDstSubDir); 832 AssertMsgReturn(fRc, ("Could not add cleanup record '%s': %Rrc\n", pszDstSubDir, rc), RTEXITCODE_FAILURE); 833 789 834 RTStrFree(pszDstSubDir); 790 835 if (!fRc) … … 809 854 if (RT_FAILURE(rc)) 810 855 return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc); 856 811 857 *pfCreatedExtractDir = true; 812 858 } 813 859 860 RTDIR hDir; 861 rc = RTDirOpen(&hDir, pszDstDir); 862 if (RT_FAILURE(rc)) 863 return ShowError("Failed to open extraction path '%s': %Rrc", pszDstDir, rc); 864 865 /* Add a cleanup record. */ 866 bool fRc = AddCleanupRec(pszDstDir, false /*fFile*/, &hDir); 867 AssertMsgReturn(fRc, ("Could not add cleanup record '%s': %Rrc\n", pszDstDir, rc), RTEXITCODE_FAILURE); 868 814 869 /* 815 870 * Extract files. … … 817 872 for (unsigned k = 0; k < cPackages; k++) 818 873 { 819 PVBOXSTUBPKG pPackage = FindPackageHeader(k);874 PVBOXSTUBPKG const pPackage = FindPackageHeader(k); 820 875 if (!pPackage) 821 876 return RTEXITCODE_FAILURE; /* Done complaining already. */ … … 824 879 { 825 880 char szDstFile[RTPATH_MAX]; 826 rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, pPackage->szFileName); 881 if (fExtractOnly) /* If we only extract, use the original file name. */ 882 { 883 rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, pPackage->szFileName); 884 } 885 else /* When temporarily extracting and running, use a random file name. See @bugref{10201} */ 886 { 887 rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, "XXXXXXXXXXXX"); 888 if (RT_SUCCESS(rc)) 889 { 890 const char *pszDotExt = RTPathSuffix(pPackage->szFileName); 891 if (pszDotExt) 892 rc = RTStrCat(szDstFile, sizeof(szDstFile), pszDotExt); 893 if (RT_SUCCESS(rc)) 894 rc = RTFileCreateTemp(szDstFile, 0700); 895 } 896 } 827 897 if (RT_FAILURE(rc)) 828 return ShowError("Internal error: RTPathJoinfailed: %Rrc", rc);898 return ShowError("Internal error: Build extraction file name failed: %Rrc", rc); 829 899 830 900 rc = Extract(pPackage, szDstFile); 831 901 if (RT_FAILURE(rc)) 832 902 return ShowError("Error extracting package #%u: %Rrc", k, rc); 833 834 if (!fExtractOnly && !AddCleanupRec(szDstFile, true /*fFile*/))835 {836 RTFileDelete(szDstFile);837 return RTEXITCODE_FAILURE;838 }839 903 } 840 904 } 905 906 /* Note: Closing the directory will be done when processing the cleanup record. */ 841 907 842 908 return RTEXITCODE_SUCCESS; … … 1069 1135 } 1070 1136 1071 /* Set the default extraction path if not given the the user. */ 1137 /* 1138 * Set a default extraction path if not explicitly given by the user. 1139 * 1140 * By default we're constructing a non-deterministic path. 1141 * See @bugref{10201} 1142 */ 1072 1143 if (szExtractPath[0] == '\0') 1073 1144 { 1074 1145 vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath)); 1075 1146 if (RT_SUCCESS(vrc)) 1076 vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox"); 1147 { 1148 if (!fExtractOnly) /* Only use a random sub-dir if we extract + run (and not just extract). */ 1149 { 1150 vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "XXXXXXXXXXXXXXXX"); 1151 if (RT_SUCCESS(vrc)) 1152 vrc = RTDirCreateTemp(szExtractPath, 0700); /** @todo Use RTDirCreateTempSecure() once it's implemented. */ 1153 } 1154 } 1155 1077 1156 if (RT_FAILURE(vrc)) 1078 return ShowError("Failed to c onstructextraction path: %Rrc", vrc);1157 return ShowError("Failed to create extraction path: %Rrc", vrc); 1079 1158 } 1080 1159 RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */ … … 1118 1197 if (g_iVerbosity) 1119 1198 { 1199 RTPrintf("Extraction path : %s\n", szExtractPath); 1120 1200 RTPrintf("Silent installation : %RTbool\n", g_fSilent); 1121 1201 RTPrintf("Logging enabled : %RTbool\n", fEnableLogging);
Note:
See TracChangeset
for help on using the changeset viewer.