Leaked source code of windows server 2003
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.

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