Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

797 lines
22 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. validate.c
  5. Abstract:
  6. Code to validate an uninstall image
  7. Author:
  8. Jim Schmidt (jimschm) 19-Jan-2001
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. #include "undop.h"
  14. #include "file.h"
  15. #include "persist.h"
  16. #include "uninstall.h"
  17. //
  18. // Contants
  19. //
  20. #define MAX_BACKUP_FILES 3
  21. #define _SECOND ((__int64) 10000000)
  22. #define _MINUTE (60 * _SECOND)
  23. #define _HOUR (60 * _MINUTE)
  24. #define _DAY (24 * _HOUR)
  25. PERSISTENCE_IMPLEMENTATION(DRIVE_LAYOUT_INFORMATION_EX_PERSISTENCE);
  26. PERSISTENCE_IMPLEMENTATION(DISKINFO_PERSISTENCE);
  27. PERSISTENCE_IMPLEMENTATION(DRIVEINFO_PERSISTENCE);
  28. PERSISTENCE_IMPLEMENTATION(FILEINTEGRITYINFO_PERSISTENCE);
  29. PERSISTENCE_IMPLEMENTATION(BACKUPIMAGEINFO_PERSISTENCE);
  30. //
  31. // Code
  32. //
  33. PCTSTR
  34. GetUndoDirPath (
  35. VOID
  36. )
  37. /*++
  38. Routine Description:
  39. GetUndoDirPath queries the registry and obtains the stored backup path.
  40. Arguments:
  41. None.
  42. Return Value:
  43. The backup path, which must be freed with MemFree, or NULL if the backup
  44. path is not stored in the registry.
  45. --*/
  46. {
  47. PCTSTR backUpPath = NULL;
  48. HKEY key;
  49. key = OpenRegKeyStr (S_REGKEY_WIN_SETUP);
  50. if (key) {
  51. backUpPath = GetRegValueString (key, S_REG_KEY_UNDO_PATH);
  52. CloseRegKey (key);
  53. }
  54. return backUpPath;
  55. }
  56. BOOL
  57. pIsUserAdmin (
  58. VOID
  59. )
  60. /*++
  61. Routine Description:
  62. This routine returns TRUE if the caller's process is a
  63. member of the Administrators local group.
  64. Caller is NOT expected to be impersonating anyone and IS
  65. expected to be able to open their own process and process
  66. token.
  67. Arguments:
  68. None.
  69. Return Value:
  70. TRUE - Caller has Administrators local group.
  71. FALSE - Caller does not have Administrators local group.
  72. --*/
  73. {
  74. HANDLE Token;
  75. UINT BytesRequired;
  76. PTOKEN_GROUPS Groups;
  77. BOOL b;
  78. UINT i;
  79. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  80. PSID AdministratorsGroup;
  81. //
  82. // On non-NT platforms the user is administrator.
  83. //
  84. if(!ISNT()) {
  85. return(TRUE);
  86. }
  87. //
  88. // Open the process token.
  89. //
  90. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  91. return(FALSE);
  92. }
  93. b = FALSE;
  94. Groups = NULL;
  95. //
  96. // Get group information.
  97. //
  98. if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
  99. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  100. && (Groups = (PTOKEN_GROUPS)LocalAlloc(LPTR,BytesRequired))
  101. && GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
  102. b = AllocateAndInitializeSid(
  103. &NtAuthority,
  104. 2,
  105. SECURITY_BUILTIN_DOMAIN_RID,
  106. DOMAIN_ALIAS_RID_ADMINS,
  107. 0, 0, 0, 0, 0, 0,
  108. &AdministratorsGroup
  109. );
  110. if(b) {
  111. //
  112. // See if the user has the administrator group.
  113. //
  114. b = FALSE;
  115. for(i=0; i<Groups->GroupCount; i++) {
  116. if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
  117. b = TRUE;
  118. break;
  119. }
  120. }
  121. FreeSid(AdministratorsGroup);
  122. }
  123. }
  124. //
  125. // Clean up and return.
  126. //
  127. if(Groups) {
  128. LocalFree((HLOCAL)Groups);
  129. }
  130. CloseHandle(Token);
  131. return(b);
  132. }
  133. PBACKUPIMAGEINFO
  134. pReadUndoFileIntegrityInfo(
  135. VOID
  136. )
  137. /*++
  138. Routine Description:
  139. pReadUndoFileIntegrityInfo reads the uninstall registry info that was
  140. written by setup. This info tells undo what files are in the backup image
  141. and details about those files.
  142. Arguments:
  143. None.
  144. Return Value:
  145. A pointer to a BACKUPIMAGEINFO which must be freed with MemFree structure
  146. if successful, NULL otherwise.
  147. --*/
  148. {
  149. static BACKUPIMAGEINFO backupInfo;
  150. BYTE * filesIntegrityPtr = NULL;
  151. UINT sizeOfBuffer = 0;
  152. UINT typeOfRegKey;
  153. HKEY key;
  154. LONG rc;
  155. BOOL bResult = FALSE;
  156. key = OpenRegKeyStr (S_REGKEY_WIN_SETUP);
  157. if (key) {
  158. rc = RegQueryValueEx (
  159. key,
  160. S_REG_KEY_UNDO_INTEGRITY,
  161. NULL,
  162. &typeOfRegKey,
  163. NULL,
  164. &sizeOfBuffer
  165. );
  166. if(rc == ERROR_SUCCESS && sizeOfBuffer){
  167. filesIntegrityPtr = MemAlloc(g_hHeap, 0, sizeOfBuffer);
  168. if(filesIntegrityPtr){
  169. rc = RegQueryValueEx (
  170. key,
  171. S_REG_KEY_UNDO_INTEGRITY,
  172. NULL,
  173. &typeOfRegKey,
  174. (PBYTE)filesIntegrityPtr,
  175. &sizeOfBuffer
  176. );
  177. if (rc != ERROR_SUCCESS) {
  178. MemFree(g_hHeap, 0, filesIntegrityPtr);
  179. filesIntegrityPtr = NULL;
  180. DEBUGMSG ((DBG_ERROR, "File integrity info struct is not the expected size"));
  181. }
  182. }
  183. }
  184. CloseRegKey (key);
  185. }
  186. if(filesIntegrityPtr){
  187. if(Persist_Success == PERSIST_LOAD(filesIntegrityPtr,
  188. sizeOfBuffer,
  189. BACKUPIMAGEINFO,
  190. BACKUPIMAGEINFO_VERSION,
  191. &backupInfo)){
  192. bResult = TRUE;
  193. }
  194. MemFree(g_hHeap, 0, filesIntegrityPtr);
  195. }
  196. return bResult? &backupInfo: NULL;
  197. }
  198. VOID
  199. pReleaseMemOfUndoFileIntegrityInfo(
  200. BACKUPIMAGEINFO * pBackupImageInfo
  201. )
  202. /*++
  203. Routine Description:
  204. pReleaseMemOfUndoFileIntegrityInfo releases memory of BACKUPIMAGEINFO structure,
  205. that was allocated previously by pReadUndoFileIntegrityInfo function
  206. Arguments:
  207. None.
  208. Return Value:
  209. None.
  210. --*/
  211. {
  212. if(!pBackupImageInfo){
  213. return;
  214. }
  215. PERSIST_RELEASE_STRUCT_MEMORY(BACKUPIMAGEINFO, BACKUPIMAGEINFO_VERSION, pBackupImageInfo);
  216. }
  217. BOOL
  218. pIsEnoughDiskSpace(
  219. IN TCHAR Drive,
  220. IN PULARGE_INTEGER NeedDiskSpacePtr
  221. )
  222. {
  223. ULARGE_INTEGER TotalNumberOfFreeBytes;
  224. TCHAR drive[] = TEXT("?:\\");
  225. if(!NeedDiskSpacePtr){
  226. MYASSERT(FALSE);
  227. return FALSE;
  228. }
  229. drive[0] = Drive;
  230. if(!GetDiskFreeSpaceEx(drive, NULL, NULL, &TotalNumberOfFreeBytes)){
  231. LOG ((LOG_ERROR, "Unable to get %c drive free space information", Drive));
  232. return FALSE;
  233. }
  234. if(TotalNumberOfFreeBytes.QuadPart < NeedDiskSpacePtr->QuadPart){
  235. LOG ((
  236. LOG_ERROR,
  237. "No enough space on windir drive %c:\\. Free: %d MB Need: %d MB",
  238. Drive,
  239. (UINT)TotalNumberOfFreeBytes.QuadPart>>20,
  240. (UINT)NeedDiskSpacePtr->QuadPart>>20)
  241. );
  242. return FALSE;
  243. }
  244. return TRUE;
  245. }
  246. UNINSTALLSTATUS pDiskInfoComparationStatusToUninstallStatus(
  247. IN DISKINFO_COMPARATION_STATUS diskInfoCmpStatus
  248. )
  249. {
  250. switch(diskInfoCmpStatus)
  251. {
  252. case DiskInfoCmp_DifferentLetter:
  253. case DiskInfoCmp_DriveMountPointHasChanged:
  254. return Uninstall_DifferentDriveLetter;
  255. case DiskInfoCmp_FileSystemHasChanged:
  256. return Uninstall_DifferentDriveFileSystem;
  257. case DiskInfoCmp_GeometryHasChanged:
  258. return Uninstall_DifferentDriveGeometry;
  259. case DiskInfoCmp_PartitionPlaceHasChanged:
  260. case DiskInfoCmp_PartitionLengthHasChanged:
  261. case DiskInfoCmp_PartitionTypeHasChanged:
  262. case DiskInfoCmp_PartitionStyleHasChanged:
  263. case DiskInfoCmp_PartitionCountHasChanged:
  264. case DiskInfoCmp_PartitionNumberHasChanged:
  265. case DiskInfoCmp_RewritePartitionHasChanged:
  266. case DiskInfoCmp_PartitionAttributesHasChanged:
  267. return Uninstall_DifferentDrivePartitionInfo;
  268. ;
  269. };
  270. return Uninstall_WrongDrive;
  271. }
  272. UNINSTALLSTATUS
  273. SanityCheck (
  274. IN SANITYFLAGS Flags,
  275. IN PCWSTR VolumeRestriction, OPTIONAL
  276. OUT PULONGLONG DiskSpace OPTIONAL
  277. )
  278. {
  279. PCTSTR path = NULL;
  280. UINT attribs;
  281. UINT version;
  282. UINT i;
  283. UINT j;
  284. WIN32_FILE_ATTRIBUTE_DATA fileDetails;
  285. PCTSTR backUpPath = NULL;
  286. PBACKUPIMAGEINFO imageInfo = NULL;
  287. UNINSTALLSTATUS result;
  288. OSVERSIONINFOEX osVersion;
  289. ULONGLONG condition;
  290. SYSTEMTIME st;
  291. FILETIME ft;
  292. ULARGE_INTEGER backupFileTime;
  293. ULARGE_INTEGER timeDifference;
  294. PCWSTR unicodePath;
  295. BOOL restricted;
  296. WCHAR winDir[MAX_PATH];
  297. ULARGE_INTEGER TotalNumberOfFreeBytes;
  298. ULARGE_INTEGER FileSize;
  299. UINT drivesNumber;
  300. DRIVEINFO drivesInfo[MAX_DRIVE_NUMBER];
  301. UINT disksNumber;
  302. DISKINFO * disksInfo = NULL;
  303. WCHAR * FileSystemName = NULL;
  304. WCHAR * VolumeNTPath = NULL;
  305. BOOL oldImage = FALSE;
  306. DISKINFO_COMPARATION_STATUS DiskCmpStatus;
  307. __try {
  308. if (DiskSpace) {
  309. *DiskSpace = 0;
  310. }
  311. //
  312. // Check OS version. Use the Windows 2000 VerifyVersionInfo API so we
  313. // always get good results, even in the future. We support NT 5.1 and
  314. // above.
  315. //
  316. condition = VerSetConditionMask (0, VER_MAJORVERSION, VER_GREATER_EQUAL);
  317. condition = VerSetConditionMask (condition, VER_MINORVERSION, VER_GREATER_EQUAL);
  318. condition = VerSetConditionMask (condition, VER_PLATFORMID, VER_EQUAL);
  319. ZeroMemory (&osVersion, sizeof (osVersion));
  320. osVersion.dwOSVersionInfoSize = sizeof (osVersion);
  321. osVersion.dwMajorVersion = 5;
  322. osVersion.dwMinorVersion = 1;
  323. osVersion.dwPlatformId = VER_PLATFORM_WIN32_NT;
  324. if (!VerifyVersionInfo (
  325. &osVersion,
  326. VER_MAJORVERSION|VER_MINORVERSION|VER_PLATFORMID,
  327. condition
  328. )) {
  329. DEBUGMSG ((DBG_ERROR, "VerifyVersionInfo says this is not the OS we support"));
  330. result = Uninstall_InvalidOsVersion;
  331. __leave;
  332. }
  333. //
  334. // Validate security
  335. //
  336. if (!pIsUserAdmin()) {
  337. result = Uninstall_NotEnoughPrivileges;
  338. DEBUGMSG ((DBG_WARNING, "User is not an administrator"));
  339. __leave;
  340. }
  341. //
  342. // Get info setup wrote to the registry
  343. //
  344. DEBUGMSG ((DBG_NAUSEA, "Getting registry info"));
  345. backUpPath = GetUndoDirPath();
  346. imageInfo = pReadUndoFileIntegrityInfo();
  347. if(!backUpPath || !imageInfo) {
  348. result = Uninstall_DidNotFindRegistryEntries;
  349. LOG ((LOG_WARNING, "Uninstall: Failed to retrieve registry entries"));
  350. __leave;
  351. }
  352. //
  353. // Verify backup subdirectory exists
  354. //
  355. DEBUGMSG ((DBG_NAUSEA, "Validating undo subdirectory"));
  356. attribs = GetFileAttributes (backUpPath);
  357. if (attribs == INVALID_ATTRIBUTES || !(attribs & FILE_ATTRIBUTE_DIRECTORY)) {
  358. DEBUGMSG ((DBG_VERBOSE, "%s not found", backUpPath));
  359. result = Uninstall_DidNotFindDirOrFiles;
  360. __leave;
  361. }
  362. //
  363. // Compute disk space used by image
  364. //
  365. if (DiskSpace) {
  366. for (i = 0; i < imageInfo->NumberOfFiles; i++) {
  367. path = JoinPaths (backUpPath, imageInfo->FilesInfo[i].FileName);
  368. DEBUGMSG ((DBG_NAUSEA, "Getting disk space for %s", path));
  369. if (VolumeRestriction) {
  370. DEBUGMSG ((DBG_NAUSEA, "Validating volume restriction for %s", path));
  371. unicodePath = CreateUnicode (path);
  372. restricted = !StringIPrefixW (unicodePath, VolumeRestriction);
  373. if (restricted) {
  374. DEBUGMSGW ((
  375. DBG_VERBOSE,
  376. "%s is being skipped because it is not on volume %s",
  377. unicodePath,
  378. VolumeRestriction
  379. ));
  380. }
  381. DestroyUnicode (unicodePath);
  382. if (restricted) {
  383. FreePathString (path);
  384. path = NULL;
  385. continue;
  386. }
  387. }
  388. if (GetFileAttributesEx (path, GetFileExInfoStandard, &fileDetails) &&
  389. fileDetails.dwFileAttributes != INVALID_ATTRIBUTES &&
  390. !(fileDetails.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  391. ) {
  392. DEBUGMSG ((
  393. DBG_NAUSEA,
  394. "Adding %I64u bytes for %s",
  395. (ULONGLONG) fileDetails.nFileSizeLow +
  396. ((ULONGLONG) fileDetails.nFileSizeHigh << (ULONGLONG) 32),
  397. path
  398. ));
  399. *DiskSpace += (ULONGLONG) fileDetails.nFileSizeLow +
  400. ((ULONGLONG) fileDetails.nFileSizeHigh << (ULONGLONG) 32);
  401. }
  402. FreePathString (path);
  403. path = NULL;
  404. }
  405. }
  406. //
  407. // Validate each file in the backup subdirectory
  408. //
  409. for (i = 0; i < imageInfo->NumberOfFiles; i++) {
  410. path = JoinPaths (backUpPath, imageInfo->FilesInfo[i].FileName);
  411. DEBUGMSG ((DBG_NAUSEA, "Validating %s", path));
  412. if (VolumeRestriction) {
  413. DEBUGMSG ((DBG_NAUSEA, "Validating volume restriction for %s", path));
  414. unicodePath = CreateUnicode (path);
  415. restricted = !StringIPrefixW (unicodePath, VolumeRestriction);
  416. if (restricted) {
  417. DEBUGMSGW ((
  418. DBG_VERBOSE,
  419. "%s is being skipped because it is not on volume %s",
  420. unicodePath,
  421. VolumeRestriction
  422. ));
  423. }
  424. DestroyUnicode (unicodePath);
  425. if (restricted) {
  426. FreePathString (path);
  427. path = NULL;
  428. continue;
  429. }
  430. }
  431. if (!GetFileAttributesEx (path, GetFileExInfoStandard, &fileDetails) ||
  432. fileDetails.dwFileAttributes == INVALID_ATTRIBUTES ||
  433. (fileDetails.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  434. ) {
  435. DEBUGMSG ((DBG_VERBOSE, "%s not found", path));
  436. result = Uninstall_DidNotFindDirOrFiles;
  437. __leave;
  438. }
  439. DEBUGMSG ((DBG_NAUSEA, "Validating time for %s", path));
  440. //
  441. // Get the current FILETIME and transfer file time into a ULONGLONG
  442. //
  443. backupFileTime.LowPart = fileDetails.ftLastWriteTime.dwLowDateTime;
  444. backupFileTime.HighPart = fileDetails.ftLastWriteTime.dwHighDateTime;
  445. GetSystemTime (&st);
  446. SystemTimeToFileTime (&st, &ft);
  447. timeDifference.LowPart = ft.dwLowDateTime;
  448. timeDifference.HighPart = ft.dwHighDateTime;
  449. //
  450. // If time is messed up, then fail
  451. //
  452. if (timeDifference.QuadPart < backupFileTime.QuadPart) {
  453. DEBUGMSG ((DBG_VERBOSE, "File time of %s is in the future according to current clock", path));
  454. result = Uninstall_NewImage;
  455. __leave;
  456. }
  457. //
  458. // Subtract the original write time from the current time. If
  459. // the result is less than 7 days, then stop.
  460. //
  461. timeDifference.QuadPart -= backupFileTime.QuadPart;
  462. if (Flags & FAIL_IF_NOT_OLD) {
  463. if (timeDifference.QuadPart < 7 * _DAY) {
  464. DEBUGMSG ((DBG_VERBOSE, "Image is less than 7 days old", path));
  465. result = Uninstall_NewImage;
  466. __leave;
  467. }
  468. }
  469. //
  470. // Check if the image is more than 30 days old. If so, stop.
  471. //
  472. if (timeDifference.QuadPart >= (31 * _DAY)) {
  473. DEBUGMSG ((DBG_VERBOSE, "Image is more than 30 days old", path));
  474. oldImage = TRUE;
  475. }
  476. //
  477. // Check file size
  478. //
  479. FileSize.LowPart = fileDetails.nFileSizeLow;
  480. FileSize.HighPart = fileDetails.nFileSizeHigh;
  481. if(FileSize.QuadPart != imageInfo->FilesInfo[i].FileSize.QuadPart){
  482. DEBUGMSG ((DBG_VERBOSE, "%s was changed", path));
  483. result = Uninstall_FileWasModified;
  484. __leave;
  485. }
  486. if (Flags & VERIFY_CAB) {
  487. if (imageInfo->FilesInfo[i].IsCab) {
  488. if (!CheckCabForAllFilesAvailability (path)){
  489. result = Uninstall_FileWasModified;
  490. __leave;
  491. }
  492. }
  493. }
  494. FreePathString (path);
  495. path = NULL;
  496. }
  497. DEBUGMSG ((DBG_VERBOSE, "Undo image is valid"));
  498. //
  499. // Validate disk geometry and partition info
  500. //
  501. path = JoinPaths (backUpPath, TEXT("boot.cab"));
  502. if(!GetBootDrive(backUpPath, path)){
  503. LOG ((LOG_WARNING, "Uninstall Validate: Unable to open %s", path));
  504. result = Uninstall_FileWasModified;
  505. __leave;
  506. }
  507. if(!GetWindowsDirectoryW(winDir, ARRAYSIZE(winDir))){
  508. LOG ((LOG_WARNING, "Uninstall Validate: Unable to get Windows dir"));
  509. result = Uninstall_CantRetrieveSystemInfo;
  510. __leave;
  511. }
  512. //
  513. // compare disk information
  514. //
  515. FileSystemName = MemAlloc(g_hHeap, 0, MAX_DRIVE_NUMBER * MAX_PATH);
  516. if(!FileSystemName){
  517. LOG ((LOG_WARNING, "Uninstall Validate: Unable to allocate memory for FileSystemName"));
  518. result = Uninstall_NotEnoughMemory;
  519. __leave;
  520. }
  521. VolumeNTPath = MemAlloc(g_hHeap, 0, MAX_DRIVE_NUMBER * MAX_PATH);
  522. if(!VolumeNTPath){
  523. LOG ((LOG_WARNING, "Uninstall Validate: Unable to allocate memory for VolumeNTPath"));
  524. result = Uninstall_NotEnoughMemory;
  525. __leave;
  526. }
  527. memset(drivesInfo, 0, sizeof(drivesInfo));
  528. for(j = 0; j < ARRAYSIZE(drivesInfo); j++){
  529. drivesInfo[j].FileSystemName = &FileSystemName[j * MAX_PATH];
  530. drivesInfo[j].VolumeNTPath = &VolumeNTPath[j * MAX_PATH];
  531. }
  532. if(!GetUndoDrivesInfo(drivesInfo, &drivesNumber, g_BootDrv, winDir[0], backUpPath[0])){
  533. LOG ((LOG_WARNING, "Uninstall Validate: Unable to get disk drives information"));
  534. result = Uninstall_CantRetrieveSystemInfo;
  535. __leave;
  536. }
  537. if(drivesNumber != imageInfo->NumberOfDrives){
  538. LOG ((LOG_WARNING, "Uninstall Validate: Different number of drive %d, was %d", drivesNumber, imageInfo->NumberOfDrives));
  539. result = Uninstall_DifferentNumberOfDrives;
  540. __leave;
  541. }
  542. if(!CompareDrivesInfo(drivesInfo,
  543. imageInfo->DrivesInfo,
  544. drivesNumber,
  545. &DiskCmpStatus,
  546. NULL)){
  547. LOG ((LOG_WARNING, "Uninstall Validate: Different drives layout"));
  548. result = pDiskInfoComparationStatusToUninstallStatus(DiskCmpStatus);
  549. __leave;
  550. }
  551. if(!GetDisksInfo(&disksInfo, &disksNumber)){
  552. LOG ((LOG_WARNING, "Uninstall Validate: Unable to get physical disk information"));
  553. result = Uninstall_CantRetrieveSystemInfo;
  554. __leave;
  555. }
  556. if(disksNumber != imageInfo->NumberOfDisks){
  557. LOG ((LOG_WARNING, "Uninstall Validate: Different number of disks %d, was %d", disksNumber, imageInfo->NumberOfDisks));
  558. result = Uninstall_DifferentNumberOfDrives;
  559. __leave;
  560. }
  561. if(!CompareDisksInfo(disksInfo,
  562. imageInfo->DisksInfo,
  563. disksNumber,
  564. &DiskCmpStatus,
  565. NULL)){
  566. LOG ((LOG_WARNING, "Uninstall Validate: Different disks layout"));
  567. result = pDiskInfoComparationStatusToUninstallStatus(DiskCmpStatus);
  568. __leave;
  569. }
  570. //
  571. // validate free disk space
  572. //
  573. if(towlower(backUpPath[0]) == towlower(winDir[0]) ||
  574. towlower(backUpPath[0]) == towlower(g_BootDrv)){
  575. if(towlower(backUpPath[0]) == towlower(winDir[0])){
  576. imageInfo->BackupFilesDiskSpace.QuadPart += imageInfo->UndoFilesDiskSpace.QuadPart;
  577. }
  578. else{
  579. imageInfo->BootFilesDiskSpace.QuadPart += imageInfo->UndoFilesDiskSpace.QuadPart;
  580. }
  581. }
  582. else{
  583. if(!pIsEnoughDiskSpace(backUpPath[0], &imageInfo->UndoFilesDiskSpace)){
  584. result = Uninstall_NotEnoughSpace;
  585. __leave;
  586. }
  587. }
  588. if(towlower(g_BootDrv) == towlower(winDir[0])){
  589. imageInfo->BackupFilesDiskSpace.QuadPart += imageInfo->BootFilesDiskSpace.QuadPart;
  590. }
  591. else
  592. {
  593. if(!pIsEnoughDiskSpace(g_BootDrv, &imageInfo->BootFilesDiskSpace)){
  594. result = Uninstall_NotEnoughSpace;
  595. __leave;
  596. }
  597. }
  598. if(!pIsEnoughDiskSpace(winDir[0], &imageInfo->BackupFilesDiskSpace)){
  599. result = Uninstall_NotEnoughSpace;
  600. __leave;
  601. }
  602. //
  603. // Uninstall backup is valid & uninstall is possible. Now process warnings.
  604. //
  605. if (oldImage) {
  606. result = Uninstall_OldImage;
  607. } else {
  608. result = Uninstall_Valid;
  609. }
  610. }
  611. __finally {
  612. if (path) {
  613. FreePathString (path);
  614. }
  615. if(backUpPath){
  616. MemFree(g_hHeap, 0, backUpPath);
  617. }
  618. if(imageInfo){
  619. pReleaseMemOfUndoFileIntegrityInfo(imageInfo);
  620. }
  621. if(disksInfo){
  622. FreeDisksInfo(disksInfo, disksNumber);
  623. }
  624. if(VolumeNTPath){
  625. MemFree(g_hHeap, 0, VolumeNTPath);
  626. }
  627. if(FileSystemName){
  628. MemFree(g_hHeap, 0, FileSystemName);
  629. }
  630. }
  631. return result;
  632. }