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.

1737 lines
43 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. drives.c
  5. Abstract:
  6. Implements apis for managing accessible drives (Drives that are usable both on win9x
  7. side an NT side) and for managing the space on those drives.
  8. Author:
  9. Marc R. Whitten (marcw) 03-Jul-1997
  10. Revision History:
  11. marcw 16-Sep-1998 Revamped disk space usage.
  12. marcw 04-Dec-1997 Don't warn the user about obvious things (CD-Roms and
  13. Floppys not migrating..)
  14. --*/
  15. #include "pch.h"
  16. #include "sysmigp.h"
  17. #include "drives.h"
  18. //#include "..\migapp\maioctl.h"
  19. /*
  20. The following APIs are defined in this file.
  21. InitAccessibleDrives()
  22. CleanUpAccessibleDrives()
  23. GetFirstAccessibleDriveEx()
  24. GetNextAccessibleDrive()
  25. QuerySpace()
  26. UseSpace()
  27. FindSpace()
  28. OutOfSpaceMsg()
  29. */
  30. #define MAX_DRIVE_STRING MAX_PATH
  31. #define MAX_VOLUME_NAME MAX_PATH
  32. #define MAX_FILE_SYSTEM_NAME MAX_PATH
  33. #define DBG_ACCESSIBLE_DRIVES "Drives"
  34. //
  35. // Win95Upg uninstall paramters
  36. //
  37. #define S_COMPRESSIONFACTOR TEXT("CompressionFactor")
  38. #define S_BOOTCABIMAGEPADDING TEXT("BootCabImagePadding")
  39. #define S_BACKUPDISKSPACEPADDING TEXT("BackupDiskSpacePadding")
  40. typedef struct _ACCESSIBLE_DRIVES {
  41. DWORD Count;
  42. ACCESSIBLE_DRIVE_ENUM Head;
  43. ACCESSIBLE_DRIVE_ENUM Tail;
  44. } ACCESSIBLE_DRIVES, *PACCESSIBLE_DRIVES;
  45. #define MAX_NUM_DRIVES 26
  46. UINT g_DriveTypes [MAX_NUM_DRIVES];
  47. ULARGE_INTEGER g_SpaceNeededForSlowBackup = {0, 0};
  48. ULARGE_INTEGER g_SpaceNeededForFastBackup = {0, 0};
  49. ULARGE_INTEGER g_SpaceNeededForUpgrade = {0, 0};
  50. //
  51. // List of accessible drives.
  52. //
  53. ACCESSIBLE_DRIVES g_AccessibleDrives;
  54. DWORD g_ExclusionValue = 0;
  55. TCHAR g_ExclusionValueString[20];
  56. POOLHANDLE g_DrivePool;
  57. PCTSTR g_NotEnoughSpaceMessage = NULL;
  58. BOOL g_NotEnoughDiskSpace;
  59. LONGLONG g_OriginalDiskSpace = 0l;
  60. LONGLONG
  61. pRoundToNearestCluster (
  62. IN LONGLONG Space,
  63. IN UINT ClusterSize
  64. )
  65. /*++
  66. Routine Description:
  67. This routine performs the correct rounding to the nearest cluster, given an
  68. amount of space in bytes and a cluster size.
  69. Arguments:
  70. Space - Contains the number of bytes to be rounded.
  71. ClusterSize - Contains the size in bytes of a cluster on the disk.
  72. Return Value:
  73. the number of bytes rounded to the next cluster.
  74. --*/
  75. {
  76. LONGLONG rRoundedSize;
  77. if (Space % ClusterSize) {
  78. rRoundedSize = Space + (ClusterSize - (Space % ClusterSize));
  79. } else {
  80. rRoundedSize = Space;
  81. }
  82. return rRoundedSize;
  83. }
  84. BOOL
  85. IsDriveExcluded (
  86. IN PCTSTR DriveOrPath
  87. )
  88. /*++
  89. Routine Description:
  90. This routine tests whether a specified drive is excluded in memdb.
  91. Arguments:
  92. DriveOrPath - Contains the path in question (e.g. "c:\")
  93. Return Value:
  94. TRUE if the drive is found in the exclusion list in memdb, FALSE otherwise.
  95. --*/
  96. {
  97. TCHAR key[MEMDB_MAX];
  98. PSTR drive;
  99. BOOL rDriveIsExcluded = FALSE;
  100. TCHAR rootDir[] = TEXT("?:\\");
  101. rootDir[0] = DriveOrPath[0];
  102. MemDbBuildKey(
  103. key,
  104. MEMDB_CATEGORY_FILEENUM,
  105. g_ExclusionValueString,
  106. MEMDB_FIELD_FE_PATHS,
  107. rootDir
  108. );
  109. rDriveIsExcluded = MemDbGetValue (key, NULL);
  110. if (!rDriveIsExcluded) {
  111. drive = JoinPaths (rootDir, TEXT("*"));
  112. MemDbBuildKey(
  113. key,
  114. MEMDB_CATEGORY_FILEENUM,
  115. g_ExclusionValueString,
  116. MEMDB_FIELD_FE_PATHS,
  117. drive
  118. );
  119. FreePathString(drive);
  120. rDriveIsExcluded = MemDbGetValue (key, NULL);
  121. }
  122. return rDriveIsExcluded;
  123. }
  124. BOOL
  125. pBuildInitialExclusionsList (
  126. VOID
  127. )
  128. /*++
  129. Routine Description:
  130. This routine is responsible for constructing the initial exclusion list in memdb.
  131. This list will contain the contents of the exclude.inf file if it exists.
  132. As a side effect, the g_ExclusionValue and g_ExclusionValueString global variables
  133. will be initialized.
  134. Arguments:
  135. None.
  136. Return Value:
  137. TRUE if the exclusion list was successfully built, FALSE otherwise.
  138. --*/
  139. {
  140. BOOL rSuccess = TRUE;
  141. EXCLUDEINF excludeInf;
  142. TCHAR excludeInfPath[] = TEXT("?:\\exclude.inf");
  143. //
  144. // Fill in exclude inf structre.
  145. //
  146. excludeInfPath[0] = g_BootDriveLetter;
  147. excludeInf.ExclusionInfPath = excludeInfPath;
  148. excludeInf.PathSection = TEXT("Paths");
  149. excludeInf.FileSection = TEXT("Files");
  150. //
  151. // Build a enumeration ID for the exclude.inf.
  152. //
  153. g_ExclusionValue = GenerateEnumID();
  154. wsprintf(g_ExclusionValueString,TEXT("%X"),g_ExclusionValue);
  155. if (DoesFileExist (excludeInf.ExclusionInfPath)) {
  156. rSuccess = BuildExclusionsFromInf(g_ExclusionValue,&excludeInf);
  157. }
  158. ELSE_DEBUGMSG((DBG_VERBOSE,"No exclude.inf file. There are no initial exclusions."));
  159. return rSuccess;
  160. }
  161. BOOL
  162. pFindDrive (
  163. IN PCTSTR DriveString,
  164. OUT PACCESSIBLE_DRIVE_ENUM AccessibleDriveEnum
  165. )
  166. /*++
  167. Routine Description:
  168. This private routine searches the internal list of accessible drives looking for the specified
  169. drive.
  170. Arguments:
  171. DriveString - Contains the root directory of the drive in question. (e.g. "c:\").
  172. May contain a complete path. This routine will only use the first
  173. three characters while searching.
  174. AccessibleDriveEnum - Receives the ACCESSIBLE_DRIVE_ENUM structure associated with the
  175. drive if it is found.
  176. Return Value:
  177. TRUE if the drive was found in the list, FALSE otherwise.
  178. --*/
  179. {
  180. BOOL rFound = FALSE;
  181. //
  182. // Enumerate the list of drives, looking for the specified drive.
  183. //
  184. if (GetFirstAccessibleDrive(AccessibleDriveEnum)) {
  185. do {
  186. if (StringIMatchCharCount (DriveString,(*AccessibleDriveEnum)->Drive,3)) {
  187. rFound = TRUE;
  188. break;
  189. }
  190. } while(GetNextAccessibleDrive(AccessibleDriveEnum));
  191. }
  192. return rFound;
  193. }
  194. BOOL
  195. pAddAccessibleDrive (
  196. IN PTSTR Drive
  197. )
  198. /*++
  199. Routine Description:
  200. pAddAccessibleDrive is a private routine to add a drive to the list of accessible drives.
  201. It is responsible for creation and initialization of the ACCESSIBLE_DRIVE_ENUM structure
  202. for the drive and for linking that structure into the list.
  203. Arguments:
  204. Drive - Contains the root directory of the drive to add.
  205. Return Value:
  206. TRUE if the drive was successfully added to the list, FALSE otherwise.
  207. --*/
  208. {
  209. BOOL rSuccess = TRUE;
  210. ACCESSIBLE_DRIVE_ENUM newDrive = NULL;
  211. DWORD SectorsPerCluster;
  212. DWORD BytesPerSector;
  213. ULARGE_INTEGER FreeClusters = {0, 0};
  214. ULARGE_INTEGER TotalClusters = {0, 0};
  215. //
  216. // Create the list node for this drive.
  217. //
  218. newDrive = PoolMemGetMemory(g_DrivePool,sizeof(struct _ACCESSIBLE_DRIVE_ENUM));
  219. ZeroMemory(newDrive, sizeof(struct _ACCESSIBLE_DRIVE_ENUM));
  220. //
  221. // Copy the drive string for this drive.
  222. //
  223. if (rSuccess) {
  224. newDrive -> Drive = PoolMemDuplicateString(g_DrivePool,Drive);
  225. }
  226. //
  227. // Get the free space for this drive.
  228. //
  229. if (rSuccess) {
  230. if (GetDiskFreeSpaceNew (
  231. Drive,
  232. &SectorsPerCluster,
  233. &BytesPerSector,
  234. &FreeClusters,
  235. &TotalClusters
  236. )) {
  237. //
  238. // Initialize our count of the usable space for this drive.
  239. //
  240. newDrive -> UsableSpace =
  241. (LONGLONG) SectorsPerCluster * (LONGLONG) BytesPerSector * FreeClusters.QuadPart;
  242. //
  243. // Save the cluster size for this drive.
  244. //
  245. newDrive -> ClusterSize = BytesPerSector * SectorsPerCluster;
  246. //
  247. // also set the flag indicating if this is the system drive
  248. //
  249. MYASSERT (g_WinDir && g_WinDir[0]);
  250. newDrive -> SystemDrive = toupper (newDrive->Drive[0]) == toupper (g_WinDir[0]);
  251. }
  252. else {
  253. LOG((LOG_ERROR,"Could not retrieve disk space for drive %s.",Drive));
  254. rSuccess = FALSE;
  255. }
  256. }
  257. //
  258. // Finally, link this into the list and update the count of accessible drives.
  259. //
  260. newDrive -> Next = NULL;
  261. if (g_AccessibleDrives.Tail) {
  262. g_AccessibleDrives.Tail -> Next = newDrive;
  263. }
  264. else {
  265. g_AccessibleDrives.Head = newDrive;
  266. }
  267. g_AccessibleDrives.Tail = newDrive;
  268. g_AccessibleDrives.Count++;
  269. DEBUGMSG_IF((rSuccess,DBG_ACCESSIBLE_DRIVES,"Accessible Drive %s added to list.",Drive));
  270. return rSuccess;
  271. }
  272. /*++
  273. Routine Description:
  274. This private routine is responsible for excluding a drive from migration. This involves
  275. addding an incompatibility message for the drive and also adding that drive to the
  276. exclusion list in MEMDB.
  277. Arguments:
  278. Drive - Contains the root directory of the drive to exclude from migration.
  279. MsgId - Contains a Message Resource ID for the message to add to the incompatibility message.
  280. The message will be processed by ParseMessageID and will be passed Drive as an
  281. argument. If zero, no message will be displayed to the user.
  282. Return Value:
  283. None.
  284. --*/
  285. VOID
  286. pExcludeDrive (
  287. IN PTSTR Drive,
  288. IN DWORD MsgId OPTIONAL
  289. )
  290. {
  291. PCTSTR excludedDriveGroup = NULL;
  292. PCTSTR excludedDriveArgs[2];
  293. PCTSTR excludeString = NULL;
  294. if (MsgId) {
  295. //
  296. // Fill in the argument array for the excluded drive component string.
  297. //
  298. excludedDriveArgs[0] = Drive;
  299. excludedDriveArgs[1] = NULL;
  300. excludedDriveGroup = BuildMessageGroup (
  301. MSG_INSTALL_NOTES_ROOT,
  302. MsgId,
  303. Drive
  304. );
  305. if (excludedDriveGroup) {
  306. //
  307. // Report to the user that this drive will not be accessible during migration.
  308. //
  309. MsgMgr_ObjectMsg_Add(
  310. Drive,
  311. excludedDriveGroup,
  312. S_EMPTY
  313. );
  314. FreeText (excludedDriveGroup);
  315. }
  316. }
  317. //
  318. // Note it in the debug log as well.
  319. //
  320. DEBUGMSG((
  321. DBG_ACCESSIBLE_DRIVES,
  322. "The Drive %s will be excluded from migration.\n\tReason: %s",
  323. Drive,
  324. S_EMPTY
  325. ));
  326. //
  327. // Now, add the drive to the excluded paths.
  328. //
  329. excludeString = JoinPaths(Drive,TEXT("*"));
  330. ExcludePath(g_ExclusionValue,excludeString);
  331. FreePathString(excludeString);
  332. }
  333. BOOL
  334. pGetAccessibleDrives (
  335. VOID
  336. )
  337. /*++
  338. Routine Description:
  339. This routine is the private worker routine that attempts to build in the list of accessible
  340. drives. It searches through all drive strings returned through GetLogicalDriveStrings()
  341. and applies various tests to them to determine wether they are accessible or not.
  342. Accessible drives are added to the list of accessible drives while non-accessible drives
  343. are excluded from migration.
  344. Arguments:
  345. None.
  346. Return Value:
  347. TRUE if the list was successfully built, FALSE otherwise.
  348. --*/
  349. {
  350. BOOL rSuccess = TRUE;
  351. TCHAR drivesString[MAX_DRIVE_STRING];
  352. PTSTR curDrive;
  353. DWORD rc;
  354. TCHAR volumeName[MAX_VOLUME_NAME];
  355. TCHAR systemNameBuffer[MAX_FILE_SYSTEM_NAME];
  356. DWORD volumeSerialNumber;
  357. DWORD maximumComponentLength;
  358. DWORD fileSystemFlags;
  359. BOOL remoteDrive;
  360. BOOL substitutedDrive;
  361. DWORD driveType;
  362. UINT Count;
  363. UINT u;
  364. MULTISZ_ENUM e;
  365. //
  366. // Add user-supplied drives to the list
  367. //
  368. if (g_ConfigOptions.ReportOnly) {
  369. if (EnumFirstMultiSz (&e, g_ConfigOptions.ScanDrives)) {
  370. do {
  371. curDrive = (PTSTR) e.CurrentString;
  372. if (_istalpha(*curDrive) && *(curDrive + 1) == TEXT(':')) {
  373. pAddAccessibleDrive (curDrive);
  374. }
  375. } while (EnumNextMultiSz (&e));
  376. }
  377. }
  378. //
  379. // Get the list of drives on the system.
  380. //
  381. rc = GetLogicalDriveStrings(MAX_DRIVE_STRING,drivesString);
  382. if (rc == 0 || rc > MAX_DRIVE_STRING) {
  383. LOG((LOG_ERROR,"Could not build list of accessible drives. GetLogicalDriveStrings failed."));
  384. rSuccess = FALSE;
  385. }
  386. else {
  387. for (curDrive = drivesString;*curDrive;curDrive = GetEndOfString (curDrive) + 1) {
  388. if (!SafeModeActionCrashed (SAFEMODEID_DRIVE, curDrive)) {
  389. SafeModeRegisterAction(SAFEMODEID_DRIVE, curDrive);
  390. __try {
  391. //
  392. // Test cancel
  393. //
  394. if (*g_CancelFlagPtr) {
  395. __leave;
  396. }
  397. //
  398. // ensure that the drive is not excluded in the exclude.inf.
  399. //
  400. if (IsDriveExcluded (curDrive)) {
  401. pExcludeDrive(curDrive,MSG_DRIVE_EXCLUDED_SUBGROUP);
  402. __leave;
  403. }
  404. if (!GetVolumeInformation (
  405. curDrive,
  406. volumeName,
  407. MAX_VOLUME_NAME,
  408. &volumeSerialNumber,
  409. &maximumComponentLength,
  410. &fileSystemFlags,
  411. systemNameBuffer,
  412. MAX_FILE_SYSTEM_NAME
  413. )) {
  414. pExcludeDrive(curDrive,0);
  415. __leave;
  416. }
  417. //
  418. // GetVolumeInformation succeeded, now, determine if this drive will be accessible.
  419. //
  420. //
  421. // Skip drives that are compressed
  422. //
  423. if (fileSystemFlags & FS_VOL_IS_COMPRESSED)
  424. {
  425. pExcludeDrive(curDrive, MSG_DRIVE_INACCESSIBLE_SUBGROUP);
  426. __leave;
  427. }
  428. driveType = GetDriveType(curDrive);
  429. OurSetDriveType (toupper(_mbsnextc(curDrive)), driveType);
  430. //
  431. // Skip cdroms.
  432. //
  433. if (driveType == DRIVE_CDROM) {
  434. //
  435. // Is this drive the same as a local source drive?
  436. //
  437. Count = SOURCEDIRECTORYCOUNT();
  438. for (u = 0 ; u < Count ; u++) {
  439. if (_tcsnextc (SOURCEDIRECTORY(u)) == (CHARTYPE) curDrive) {
  440. break;
  441. }
  442. }
  443. if (u == Count) {
  444. pExcludeDrive(curDrive,0);
  445. }
  446. __leave;
  447. }
  448. //
  449. // Skip ramdisks.
  450. //
  451. if (driveType == DRIVE_RAMDISK)
  452. {
  453. pExcludeDrive(curDrive,MSG_DRIVE_RAM_SUBGROUP);
  454. __leave;
  455. }
  456. //
  457. // Skip any drive that does not begin "<alpha>:" (i.e. UNC drives.)
  458. //
  459. if (*curDrive == TEXT('\\') || !_istalpha(*curDrive) || *(curDrive + 1) != TEXT(':')) {
  460. pExcludeDrive(curDrive,MSG_DRIVE_INACCESSIBLE_SUBGROUP);
  461. __leave;
  462. }
  463. //
  464. // Skip floppy drives.
  465. //
  466. if (IsFloppyDrive(toupper(*curDrive) - TEXT('A') + 1)) {
  467. __leave;
  468. }
  469. //
  470. // Skip drive if it is substituted or remote.
  471. //
  472. if (!IsDriveRemoteOrSubstituted(
  473. toupper(*curDrive) - TEXT('A') + 1,
  474. &remoteDrive,
  475. &substitutedDrive
  476. )) {
  477. //
  478. // Special cases: ignore floppy drives and boot drive
  479. //
  480. if (ISPC98()) {
  481. if (IsFloppyDrive(toupper(*curDrive) - TEXT('A') + 1)) {
  482. __leave;
  483. }
  484. if (toupper (*curDrive) == g_BootDriveLetter) {
  485. __leave;
  486. }
  487. } else {
  488. if (toupper (*curDrive) == TEXT('A') ||
  489. toupper (*curDrive) == TEXT('C')
  490. ) {
  491. __leave;
  492. }
  493. }
  494. pExcludeDrive(curDrive,MSG_DRIVE_INACCESSIBLE_SUBGROUP);
  495. __leave;
  496. }
  497. if (remoteDrive) {
  498. pExcludeDrive(curDrive,MSG_DRIVE_NETWORK_SUBGROUP);
  499. __leave;
  500. }
  501. if (substitutedDrive) {
  502. pExcludeDrive(curDrive,MSG_DRIVE_SUBST_SUBGROUP);
  503. __leave;
  504. }
  505. //
  506. // If we have gotten to this point, then this drive is accessible. Add it to our list.
  507. //
  508. if (!pAddAccessibleDrive(curDrive)) {
  509. pExcludeDrive(curDrive,MSG_DRIVE_INACCESSIBLE_SUBGROUP);
  510. }
  511. }
  512. __finally {
  513. }
  514. SafeModeUnregisterAction();
  515. } else {
  516. pExcludeDrive(curDrive, MSG_DRIVE_INACCESSIBLE_SUBGROUP);
  517. }
  518. if (*g_CancelFlagPtr) {
  519. rSuccess = FALSE;
  520. DEBUGMSG((DBG_VERBOSE, "Cancel flag is set. Accessible drives not initialized."));
  521. break;
  522. }
  523. }
  524. }
  525. return rSuccess;
  526. }
  527. BOOL
  528. InitAccessibleDrives (
  529. VOID
  530. )
  531. /*++
  532. Routine Description:
  533. Init accessible drives is responsible for building the list of
  534. accessible drives and for determining the amount of free space
  535. on them.
  536. Arguments:
  537. None.
  538. Return Value:
  539. TRUE if initialization succeeded, FALSE otherwise.
  540. --*/
  541. {
  542. BOOL rSuccess = TRUE;
  543. //
  544. // Zero out the accessible drive structure.
  545. //
  546. ZeroMemory(&g_AccessibleDrives, sizeof(ACCESSIBLE_DRIVES));
  547. //
  548. // Initialize our pool memory.
  549. //
  550. g_DrivePool = PoolMemInitNamedPool ("Drive Pool");
  551. //
  552. // Disable tracking on this pool.
  553. //
  554. PoolMemDisableTracking (g_DrivePool);
  555. //
  556. //
  557. // Build the exclusion list.
  558. //
  559. if (!pBuildInitialExclusionsList()) {
  560. rSuccess = FALSE;
  561. LOG ((LOG_ERROR, (PCSTR)MSG_ERROR_UNEXPECTED_ACCESSIBLE_DRIVES));
  562. }
  563. //
  564. // Get the list of accessible drives.
  565. //
  566. else if(!pGetAccessibleDrives()) {
  567. rSuccess = FALSE;
  568. LOG ((LOG_ERROR,(PCSTR)MSG_ERROR_UNEXPECTED_ACCESSIBLE_DRIVES));
  569. } else if(g_AccessibleDrives.Count == 0) {
  570. //
  571. // If there are no accessible drives, then, we fail, except that we will allow
  572. // the NOFEAR option to disable this--in the checked build.
  573. //
  574. #ifdef DEBUG
  575. if (!g_ConfigOptions.NoFear) {
  576. #endif DEBUG
  577. rSuccess = FALSE;
  578. #ifdef DEBUG
  579. }
  580. #endif
  581. LOG ((LOG_ERROR, (PCSTR)MSG_NO_ACCESSIBLE_DRIVES_POPUP));
  582. }
  583. #ifdef DEBUG
  584. //
  585. // Dump the accessible drive list to the log if this is the debug version.
  586. //
  587. else {
  588. ACCESSIBLE_DRIVE_ENUM e;
  589. if (GetFirstAccessibleDrive(&e)) {
  590. do {
  591. DEBUGMSG((
  592. DBG_ACCESSIBLE_DRIVES,
  593. "Drive %s has %I64u free space. %s",
  594. e->Drive,
  595. e->UsableSpace,
  596. ((DWORD) (toupper(*(e->Drive)) - TEXT('A')) == *g_LocalSourceDrive) ? "This is the LS drive." : ""
  597. ));
  598. } while (GetNextAccessibleDrive(&e));
  599. }
  600. }
  601. #endif
  602. return rSuccess;
  603. }
  604. VOID
  605. CleanUpAccessibleDrives (
  606. VOID
  607. )
  608. /*++
  609. Routine Description:
  610. CleanUpAccessibleDrives is a simple clean up routine.
  611. Arguments:
  612. None.
  613. Return Value:
  614. None.
  615. --*/
  616. {
  617. //
  618. // Nothing to do except clean up our pool memory.
  619. //
  620. if (g_DrivePool) {
  621. PoolMemDestroyPool(g_DrivePool);
  622. }
  623. FreeStringResource (g_NotEnoughSpaceMessage);
  624. g_NotEnoughSpaceMessage = NULL;
  625. }
  626. /*++
  627. Routine Description:
  628. GetFirstAccessibleDriveEx and GetNextAccessibleDrive are the two enumerator routines for the
  629. list of accessible drives.
  630. Arguments:
  631. AccessibleDriveEnum - Recieves an updated ACCESSIBLE_DRIVE_ENUM structure containing the
  632. information for the current drive in the enumeration.
  633. Return Value:
  634. TRUE if the enumeration operation succeeded (i.e. there are more drives to enumerate)
  635. FALSE otherwise.
  636. --*/
  637. BOOL
  638. GetFirstAccessibleDriveEx (
  639. OUT PACCESSIBLE_DRIVE_ENUM AccessibleDriveEnum,
  640. IN BOOL SystemDriveOnly
  641. )
  642. {
  643. *AccessibleDriveEnum = g_AccessibleDrives.Head;
  644. if (!*AccessibleDriveEnum) {
  645. return FALSE;
  646. }
  647. (*AccessibleDriveEnum)->EnumSystemDriveOnly = SystemDriveOnly;
  648. if (!SystemDriveOnly || (*AccessibleDriveEnum)->SystemDrive) {
  649. return TRUE;
  650. }
  651. return GetNextAccessibleDrive (AccessibleDriveEnum);
  652. }
  653. BOOL
  654. GetNextAccessibleDrive (
  655. IN OUT PACCESSIBLE_DRIVE_ENUM AccessibleDriveEnum
  656. )
  657. {
  658. BOOL bEnumSystemDriveOnly;
  659. while (*AccessibleDriveEnum) {
  660. bEnumSystemDriveOnly = (*AccessibleDriveEnum)->EnumSystemDriveOnly;
  661. *AccessibleDriveEnum = (*AccessibleDriveEnum) -> Next;
  662. if (*AccessibleDriveEnum) {
  663. (*AccessibleDriveEnum)->EnumSystemDriveOnly = bEnumSystemDriveOnly;
  664. if (!bEnumSystemDriveOnly || (*AccessibleDriveEnum)->SystemDrive) {
  665. break;
  666. }
  667. }
  668. }
  669. return *AccessibleDriveEnum != NULL;
  670. }
  671. BOOL
  672. IsDriveAccessible (
  673. IN PCTSTR DriveString
  674. )
  675. /*++
  676. Routine Description:
  677. IsDriveAccessible tests wether the provided drive is in the accessible list. Note that
  678. only the first three characters of the DriveString will be used to determine if the
  679. drive is accessible so a complete path can be passed into this routine. (Thus determining
  680. wether that path is on an accessible drive.)
  681. Arguments:
  682. DriveString - Contains the root path of the drive in question. May contain extra information
  683. also, Only the first three characters are relevant.
  684. Return Value:
  685. TRUE if the drive is in the accessible drives list, FALSE otherwise.
  686. --*/
  687. {
  688. ACCESSIBLE_DRIVE_ENUM e;
  689. return pFindDrive(DriveString,&e);
  690. }
  691. UINT
  692. QueryClusterSize (
  693. IN PCTSTR DriveString
  694. )
  695. /*++
  696. Routine Description:
  697. QueryClusterSize returns the cluster size for a particular drive.
  698. Arguments:
  699. DriveString - Contains the root path of the drive in question. May contain extra information
  700. also, Only the first three characters are relevant.
  701. Return Value:
  702. a UINT value representing the cluster size for this drive.
  703. --*/
  704. {
  705. UINT cSize = 0;
  706. ACCESSIBLE_DRIVE_ENUM e;
  707. if (pFindDrive(DriveString,&e)) {
  708. cSize = e -> ClusterSize;
  709. }
  710. ELSE_DEBUGMSG((DBG_ACCESSIBLE_DRIVES,"QueryClusterSize: %s is not in the list of accessible drives.",DriveString));
  711. return cSize;
  712. }
  713. LONGLONG
  714. QuerySpace (
  715. IN PCTSTR DriveString
  716. )
  717. /*++
  718. Routine Description:
  719. QuerySpace returns the number of bytes available on a particular drive. Note that this
  720. number may be different than that returned by a call to GetDiskFreeSpace.
  721. The value returned by this function will include any space committed by setup but not
  722. actually used yet.
  723. Arguments:
  724. DriveString - Contains the root path of the drive in question. May contain extra information
  725. also, Only the first three characters are relevant.
  726. Return Value:
  727. a LONGLONG value representing the number of bytes available for use. It will return 0 if asked
  728. to QuerySpace for a non-accessible drive.
  729. --*/
  730. {
  731. LONGLONG rSpace = 0l;
  732. ACCESSIBLE_DRIVE_ENUM e;
  733. if (pFindDrive(DriveString,&e)) {
  734. rSpace = e -> UsableSpace;
  735. }
  736. ELSE_DEBUGMSG((DBG_ACCESSIBLE_DRIVES,"QuerySpace: %s is not in the list of accessible drives.",DriveString));
  737. return rSpace;
  738. }
  739. BOOL
  740. FreeSpace (
  741. IN PCTSTR DriveString,
  742. IN LONGLONG SpaceToUse
  743. )
  744. /*++
  745. Routine Description:
  746. The FreeSpace function allows the caller to tag some number of bytes on a drive as free even
  747. though they do not plan to free that space immediately. The number of bytes thus tagged will
  748. be added to the amount available on that drive.
  749. Arguments:
  750. DriveString - Contains the root path of the drive in question. May contain extra information
  751. also, Only the first three characters are relevant.
  752. SpaceToUse - Contains the number of bytes to tag for use.
  753. Return Value:
  754. TRUE if the space was successfully tagged, FALSE otherwise. The function will return FALSE if
  755. asked to tag space on a non-accessible drive.
  756. --*/
  757. {
  758. BOOL rSuccess = TRUE;
  759. ACCESSIBLE_DRIVE_ENUM e;
  760. if (pFindDrive(DriveString,&e)) {
  761. e -> UsableSpace += pRoundToNearestCluster (SpaceToUse, e -> ClusterSize);
  762. e->MaxUsableSpace = max (e->MaxUsableSpace, e -> UsableSpace);
  763. }
  764. else {
  765. rSuccess = FALSE;
  766. DEBUGMSG((DBG_ACCESSIBLE_DRIVES,"UseSpace: %s is not in the list of accessible drives.",DriveString));
  767. }
  768. return rSuccess;
  769. }
  770. BOOL
  771. UseSpace (
  772. IN PCTSTR DriveString,
  773. IN LONGLONG SpaceToUse
  774. )
  775. /*++
  776. Routine Description:
  777. The UseSpace function allows the caller to tag some number of bytes on a drive for use even
  778. though they do not plan to use that space immediately. The number of bytes thus tagged will
  779. be subtracted from the amount available on that drive.
  780. Arguments:
  781. DriveString - Contains the root path of the drive in question. May contain extra information
  782. also, Only the first three characters are relevant.
  783. SpaceToUse - Contains the number of bytes to tag for use.
  784. Return Value:
  785. TRUE if the space was successfully tagged, FALSE otherwise. The function will return FALSE if
  786. asked to tag space on a non-accessible drive or on an accessible drive that does not have
  787. enough space remaining.
  788. --*/
  789. {
  790. BOOL rSuccess = TRUE;
  791. ACCESSIBLE_DRIVE_ENUM e;
  792. if (pFindDrive(DriveString,&e)) {
  793. if (SpaceToUse > e -> UsableSpace) {
  794. rSuccess = FALSE;
  795. DEBUGMSG((
  796. DBG_ACCESSIBLE_DRIVES,
  797. "UseSpace: Not Enough space on drive %s to handle request. Need %u bytes, have %u bytes.",
  798. DriveString,
  799. (UINT) SpaceToUse,
  800. (UINT) e->UsableSpace
  801. ));
  802. }
  803. e -> UsableSpace -= pRoundToNearestCluster (SpaceToUse, e -> ClusterSize);
  804. }
  805. else {
  806. rSuccess = FALSE;
  807. DEBUGMSG((DBG_ACCESSIBLE_DRIVES,"UseSpace: %s is not in the list of accessible drives.",DriveString));
  808. }
  809. return rSuccess;
  810. }
  811. PCTSTR
  812. FindSpace (
  813. IN LONGLONG SpaceNeeded
  814. )
  815. /*++
  816. Routine Description:
  817. FindSpace will attempt to find a drive with enough space to hold the requested number of bytes
  818. using a 'FirstFit' algorithm -- It will search sequentially through the list of drives
  819. returning the first such drive with enough space.
  820. Arguments:
  821. SpaceNeeded - Contains the number of bytes required.
  822. Return Value:
  823. NULL if no accessible drive has enough space remaining, otherwise a buffer containing the
  824. root directory of a drive that can handle the request.
  825. --*/
  826. {
  827. PCTSTR rDrive = NULL;
  828. ACCESSIBLE_DRIVE_ENUM e;
  829. if (GetFirstAccessibleDrive(&e)) {
  830. do {
  831. if (e->UsableSpace >= SpaceNeeded) {
  832. rDrive = e->Drive;
  833. break;
  834. }
  835. } while (GetNextAccessibleDrive(&e));
  836. }
  837. return rDrive;
  838. }
  839. VOID
  840. OutOfSpaceMessage (
  841. VOID
  842. )
  843. /*++
  844. Routine Description:
  845. This routine Logs a generic OutOfSpace message. A caller should use this message only if
  846. there is no other message that would convey more information.
  847. Arguments:
  848. None.
  849. Return Value:
  850. None.
  851. --*/
  852. {
  853. LOG ((LOG_ERROR, (PCSTR)MSG_ERROR_OUT_OF_DISK_SPACE));
  854. }
  855. BOOL
  856. OurSetDriveType (
  857. IN UINT Drive,
  858. IN UINT DriveType
  859. )
  860. {
  861. INT localDrive;
  862. localDrive = Drive - 'A';
  863. if ((localDrive >= 0) && (localDrive < MAX_NUM_DRIVES)) {
  864. g_DriveTypes [localDrive] = DriveType;
  865. return TRUE;
  866. }
  867. return FALSE;
  868. }
  869. UINT
  870. OurGetDriveType (
  871. IN UINT Drive
  872. )
  873. {
  874. INT localDrive;
  875. localDrive = Drive - 'A';
  876. if ((localDrive >= 0) && (localDrive < MAX_NUM_DRIVES)) {
  877. return g_DriveTypes [localDrive];
  878. }
  879. return 0;
  880. }
  881. VOID
  882. pGenerateLackOfSpaceMessage (
  883. IN BOOL AddToReport
  884. )
  885. {
  886. TCHAR mbString[20];
  887. TCHAR lsSpaceString[20];
  888. TCHAR altMbString[20];
  889. TCHAR backupMbString[20];
  890. TCHAR drive[20];
  891. BOOL lsOnWinDirDrive;
  892. UINT driveCount = 0;
  893. ACCESSIBLE_DRIVE_ENUM drives;
  894. UINT msgId;
  895. PCTSTR args[5];
  896. PCTSTR group;
  897. PCTSTR message;
  898. //
  899. // The user does not have enough space to continue. Let him know about it.
  900. //
  901. wsprintf (mbString, TEXT("%d"), (g_OriginalDiskSpace + (QuerySpace (g_WinDir) * -1)) / (1024*1024));
  902. wsprintf (lsSpaceString, TEXT("%d"), *g_LocalSourceSpace / (1024*1024));
  903. wsprintf (altMbString, TEXT("%d"), ((QuerySpace (g_WinDir) * -1) - *g_LocalSourceSpace + g_OriginalDiskSpace) / (1024*1024));
  904. wsprintf (backupMbString, TEXT("%d"), g_SpaceNeededForSlowBackup.LowPart / (1024*1024));
  905. g_NotEnoughDiskSpace = TRUE;
  906. drive[0] = (TCHAR) _totupper ((CHARTYPE) g_WinDir[0]);
  907. drive[1] = TEXT(':');
  908. drive[2] = TEXT('\\');
  909. drive[3] = 0;
  910. args[0] = drive;
  911. args[1] = mbString;
  912. args[2] = lsSpaceString;
  913. args[3] = altMbString;
  914. args[4] = backupMbString;
  915. lsOnWinDirDrive = ((DWORD)(toupper(*g_WinDir) - TEXT('A'))) == *g_LocalSourceDrive;
  916. if (GetFirstAccessibleDrive (&drives)) {
  917. do {
  918. driveCount++;
  919. } while (GetNextAccessibleDrive (&drives));
  920. }
  921. //
  922. // If the local source is still stuck on the windir drive, that means we couldn't find a
  923. // drive where it would fit. If the user has more than one drive, and it would make a difference,
  924. // let them know that they can copy
  925. //
  926. if (lsOnWinDirDrive && driveCount > 1) {
  927. if ((QuerySpace (g_WinDir) * -1) < *g_LocalSourceSpace) {
  928. if (g_ConfigOptions.EnableBackup != TRISTATE_NO && (UNATTENDED() || REPORTONLY()) &&
  929. g_ConfigOptions.PathForBackup && g_ConfigOptions.PathForBackup[0]) {
  930. msgId = MSG_NOT_ENOUGH_DISK_SPACE_WITH_LOCALSOURCE_AND_BACKUP;
  931. } else {
  932. msgId = MSG_NOT_ENOUGH_DISK_SPACE_WITH_LOCALSOURCE;
  933. }
  934. } else {
  935. if (g_ConfigOptions.EnableBackup != TRISTATE_NO && (UNATTENDED() || REPORTONLY()) &&
  936. g_ConfigOptions.PathForBackup && g_ConfigOptions.PathForBackup[0]) {
  937. msgId = MSG_NOT_ENOUGH_DISK_SPACE_WITH_LOCALSOURCE_AND_WINDIR_AND_BACKUP;
  938. } else {
  939. msgId = MSG_NOT_ENOUGH_DISK_SPACE_WITH_LOCALSOURCE_AND_WINDIR;
  940. }
  941. }
  942. } else {
  943. if (g_ConfigOptions.EnableBackup != TRISTATE_NO && (UNATTENDED() || REPORTONLY()) &&
  944. g_ConfigOptions.PathForBackup && g_ConfigOptions.PathForBackup[0]) {
  945. msgId = MSG_NOT_ENOUGH_DISK_SPACE_WITH_BACKUP;
  946. } else {
  947. msgId = MSG_NOT_ENOUGH_DISK_SPACE;
  948. }
  949. }
  950. //
  951. // Add to upgrade report.
  952. //
  953. FreeStringResource (g_NotEnoughSpaceMessage);
  954. g_NotEnoughSpaceMessage = ParseMessageID (msgId, args);
  955. if (AddToReport) {
  956. group = BuildMessageGroup (MSG_BLOCKING_ITEMS_ROOT, MSG_NOT_ENOUGH_DISKSPACE_SUBGROUP, NULL);
  957. if (group && g_NotEnoughSpaceMessage) {
  958. MsgMgr_ObjectMsg_Add (TEXT("*DiskSpace"), group, g_NotEnoughSpaceMessage);
  959. }
  960. FreeText (group);
  961. }
  962. return;
  963. }
  964. VOID
  965. pDetermineSpaceUsagePreReport (
  966. VOID
  967. )
  968. {
  969. LONGLONG bytes;
  970. ALL_FILEOPS_ENUM e;
  971. HANDLE h;
  972. PTSTR p;
  973. BOOL enoughSpace = TRUE;
  974. TCHAR drive[20];
  975. LONG totalSpaceSaved = 0;
  976. WIN32_FIND_DATA fd;
  977. ACCESSIBLE_DRIVE_ENUM drives;
  978. DWORD SectorsPerCluster;
  979. DWORD BytesPerSector;
  980. ULARGE_INTEGER FreeClusters = {0, 0};
  981. ULARGE_INTEGER TotalClusters = {0, 0};
  982. UINT driveCount = 0;
  983. BOOL lsOnWinDirDrive = FALSE;
  984. DWORD count = 0;
  985. PCTSTR fileString;
  986. ACCESSIBLE_DRIVE_ENUM driveAccessibleEnum;
  987. UINT backupImageSpace = 0;
  988. PCTSTR backupImagePath = NULL;
  989. PCTSTR args[3];
  990. PCTSTR group;
  991. PCTSTR message;
  992. g_NotEnoughDiskSpace = FALSE;
  993. //
  994. // First, take out the amount of space that the ~ls directory will use.
  995. //
  996. drive[0] = ((CHAR) *g_LocalSourceDrive) + TEXT('A');
  997. drive[1] = TEXT(':');
  998. drive[2] = TEXT('\\');
  999. drive[3] = 0;
  1000. DEBUGMSG ((DBG_VERBOSE, "Using space for ~ls"));
  1001. UseSpace (drive, *g_LocalSourceSpace);
  1002. TickProgressBar ();
  1003. //
  1004. // Compute size of files to be deleted that aren't being moved.
  1005. //
  1006. if (EnumFirstFileOp (&e, OPERATION_FILE_DELETE, NULL)) {
  1007. do {
  1008. h = FindFirstFile (e.Path, &fd);
  1009. if (h == INVALID_HANDLE_VALUE) {
  1010. DEBUGMSG((DBG_WARNING, "DetermineSpaceUsage: Could not open %s. (%u)", e.Path, GetLastError()));
  1011. continue;
  1012. }
  1013. bytes = ((LONGLONG) fd.nFileSizeHigh << 32) | (LONGLONG) fd.nFileSizeLow;
  1014. FindClose (h);
  1015. totalSpaceSaved += (LONG) bytes;
  1016. FreeSpace (e.Path, bytes);
  1017. count++;
  1018. if (!(count % 128)) {
  1019. TickProgressBar ();
  1020. }
  1021. } while (EnumNextFileOp (&e));
  1022. }
  1023. ELSE_DEBUGMSG ((DBG_WARNING, "No files marked for deletion!"));
  1024. //
  1025. // Add in the space that the windir will grow by.
  1026. // (This information was gathered earlier by winnt32.)
  1027. //
  1028. DEBUGMSG ((DBG_VERBOSE, "Using space for windir"));
  1029. UseSpace (g_WinDir, *g_WinDirSpace);
  1030. StringCopy (drive, g_WinDir);
  1031. p = _tcschr (drive, TEXT('\\'));
  1032. if (p) {
  1033. p = _tcsinc(p);
  1034. *p = 0;
  1035. }
  1036. //
  1037. // Add in the backup image size
  1038. //
  1039. if(UNATTENDED() || REPORTONLY()){
  1040. if (g_ConfigOptions.EnableBackup != TRISTATE_NO &&
  1041. g_ConfigOptions.PathForBackup && g_ConfigOptions.PathForBackup[0]) {
  1042. backupImagePath = g_ConfigOptions.PathForBackup;
  1043. backupImageSpace = g_SpaceNeededForSlowBackup.LowPart;
  1044. MYASSERT (backupImageSpace);
  1045. DEBUGMSG ((DBG_VERBOSE, "Using space for backup"));
  1046. UseSpace (backupImagePath, backupImageSpace);
  1047. }
  1048. }
  1049. lsOnWinDirDrive = ((DWORD)(toupper(*g_WinDir) - TEXT('A'))) == *g_LocalSourceDrive;
  1050. //
  1051. // Check to see if we can move the ~ls if there isn't enough space.
  1052. //
  1053. enoughSpace = QuerySpace (g_WinDir) > 0;
  1054. if (!enoughSpace && lsOnWinDirDrive) {
  1055. DEBUGMSG ((DBG_VERBOSE, "Trying to find new home for ~ls"));
  1056. if (GetFirstAccessibleDrive (&drives)) {
  1057. do {
  1058. driveCount++;
  1059. //
  1060. // If it isn't the windir drive, and it has enough space, use it!
  1061. //
  1062. if (QuerySpace (drives->Drive) > *g_LocalSourceSpace) {
  1063. *g_LocalSourceDrive = (DWORD) (toupper(*drives->Drive) - TEXT('A'));
  1064. FreeSpace (g_WinDir, *g_LocalSourceSpace);
  1065. UseSpace (drives->Drive, *g_LocalSourceSpace);
  1066. enoughSpace = QuerySpace (g_WinDir) > 0;
  1067. DEBUGMSG ((DBG_WARNING, "Moving the local source drive from %c to %c.", *g_WinDir, *drives->Drive));
  1068. break;
  1069. }
  1070. } while (GetNextAccessibleDrive (&drives));
  1071. }
  1072. }
  1073. //
  1074. // Undo the space reserved for the backup image. The upcoming
  1075. // wizard pages will update space use.
  1076. //
  1077. if (backupImagePath) {
  1078. DEBUGMSG ((DBG_VERBOSE, "Removing backup space"));
  1079. FreeSpace (backupImagePath, backupImageSpace);
  1080. enoughSpace = QuerySpace (g_WinDir) > 0;
  1081. }
  1082. //
  1083. // Get the amount of diskspace currently used (real use) on the drive.
  1084. // we'll need this to figure out how much the user has cleaned up.
  1085. //
  1086. if (GetDiskFreeSpaceNew (
  1087. drive,
  1088. &SectorsPerCluster,
  1089. &BytesPerSector,
  1090. &FreeClusters,
  1091. &TotalClusters
  1092. )) {
  1093. //
  1094. // Initialize our count of the usable space for this drive.
  1095. //
  1096. g_OriginalDiskSpace =
  1097. (LONGLONG) SectorsPerCluster * (LONGLONG) BytesPerSector * FreeClusters.QuadPart;
  1098. }
  1099. //
  1100. // We should have a fairly accurate description of the space needed by NT at this time.
  1101. //
  1102. if (!enoughSpace) {
  1103. pGenerateLackOfSpaceMessage (TRUE);
  1104. }
  1105. if (pFindDrive(g_WinDir, &driveAccessibleEnum)) {
  1106. g_SpaceNeededForUpgrade.QuadPart = driveAccessibleEnum->MaxUsableSpace - driveAccessibleEnum->UsableSpace;
  1107. }
  1108. //
  1109. // This is a good place to add the "not enough ram" message if necessary.
  1110. //
  1111. if (*g_RamNeeded && *g_RamAvailable) {
  1112. TCHAR mbAvail[20];
  1113. TCHAR mbNeeded[20];
  1114. TCHAR mbMore[20];
  1115. wsprintf (mbAvail, TEXT("%d"), *g_RamAvailable);
  1116. wsprintf (mbNeeded, TEXT("%d"), *g_RamNeeded);
  1117. wsprintf (mbMore, TEXT("%d"), *g_RamNeeded - *g_RamAvailable);
  1118. args[0] = mbNeeded;
  1119. args[1] = mbAvail;
  1120. args[2] = mbMore;
  1121. group = BuildMessageGroup (MSG_BLOCKING_ITEMS_ROOT, MSG_NOT_ENOUGH_RAM_SUBGROUP, NULL);
  1122. message = ParseMessageID (MSG_NOT_ENOUGH_RAM, args);
  1123. if (message && group) {
  1124. MsgMgr_ObjectMsg_Add (TEXT("*Ram"), group, message);
  1125. }
  1126. FreeText (group);
  1127. FreeStringResource (message);
  1128. }
  1129. return;
  1130. }
  1131. VOID
  1132. DetermineSpaceUsagePostReport (
  1133. VOID
  1134. )
  1135. {
  1136. DWORD SectorsPerCluster;
  1137. DWORD BytesPerSector;
  1138. ULARGE_INTEGER FreeClusters = {0, 0};
  1139. ULARGE_INTEGER TotalClusters = {0, 0};
  1140. LONGLONG curSpace;
  1141. TCHAR drive[20];
  1142. PTSTR p;
  1143. StringCopy (drive, g_WinDir);
  1144. p = _tcschr (drive, TEXT('\\'));
  1145. if (p) {
  1146. p = _tcsinc(p);
  1147. *p = 0;
  1148. }
  1149. //
  1150. // Get the amount of diskspace currently used (real use) on the drive.
  1151. // we'll need this to figure out how much the user has cleaned up.
  1152. //
  1153. if (g_NotEnoughDiskSpace &&
  1154. GetDiskFreeSpaceNew (
  1155. drive,
  1156. &SectorsPerCluster,
  1157. &BytesPerSector,
  1158. &FreeClusters,
  1159. &TotalClusters
  1160. )) {
  1161. curSpace = (LONGLONG) SectorsPerCluster * (LONGLONG) BytesPerSector * FreeClusters.QuadPart;
  1162. //
  1163. // Mark the amount freed up as freed.
  1164. //
  1165. FreeSpace (g_WinDir, curSpace - g_OriginalDiskSpace);
  1166. g_OriginalDiskSpace = curSpace;
  1167. }
  1168. if (QuerySpace (g_WinDir) > 0) {
  1169. //
  1170. // User freed up enough disk space.
  1171. //
  1172. g_NotEnoughDiskSpace = FALSE;
  1173. } else {
  1174. pGenerateLackOfSpaceMessage (FALSE);
  1175. }
  1176. }
  1177. PCTSTR
  1178. GetNotEnoughSpaceMessage (
  1179. VOID
  1180. )
  1181. {
  1182. return g_NotEnoughSpaceMessage;
  1183. }
  1184. BOOL
  1185. GetUninstallMetrics (
  1186. OUT PINT OutCompressionFactor, OPTIONAL
  1187. OUT PINT OutBootCabImagePadding, OPTIONAL
  1188. OUT PINT OutBackupDiskPadding OPTIONAL
  1189. )
  1190. {
  1191. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  1192. PCTSTR parametersName[] = {
  1193. S_COMPRESSIONFACTOR,
  1194. S_BOOTCABIMAGEPADDING,
  1195. S_BACKUPDISKSPACEPADDING
  1196. };
  1197. PINT parametersValue[] = {OutCompressionFactor, OutBootCabImagePadding, OutBackupDiskPadding};
  1198. BOOL result = FALSE;
  1199. PCTSTR data;
  1200. INT i;
  1201. MYASSERT (g_Win95UpgInf != INVALID_HANDLE_VALUE);
  1202. //
  1203. // Read all of the disk space metrics from win95upg.inf
  1204. //
  1205. for (i = 0 ; i < ARRAYSIZE(parametersName) ; i++) {
  1206. if(!parametersValue[i]){
  1207. continue;
  1208. }
  1209. *(parametersValue[i]) = 0;
  1210. if (InfFindFirstLine (g_Win95UpgInf, S_UNINSTALL_DISKSPACEESTIMATION, parametersName[i], &is)) {
  1211. data = InfGetStringField (&is, 1);
  1212. if (data) {
  1213. *(parametersValue[i]) = _ttoi(data);
  1214. result = TRUE;
  1215. }
  1216. }
  1217. }
  1218. InfCleanUpInfStruct (&is);
  1219. return result;
  1220. }
  1221. DWORD
  1222. ComputeBackupLayout (
  1223. IN DWORD Request
  1224. )
  1225. {
  1226. PCTSTR fileString;
  1227. INT compressionFactor; // % of compression * 100
  1228. INT bootCabImagePadding;
  1229. ULARGE_INTEGER spaceNeededForFastBackupClusterAligned;
  1230. if (Request == REQUEST_QUERYTICKS) {
  1231. if (g_ConfigOptions.EnableBackup == TRISTATE_NO) {
  1232. return 0;
  1233. }
  1234. return TICKS_BACKUP_LAYOUT_OUTPUT;
  1235. }
  1236. if (g_ConfigOptions.EnableBackup == TRISTATE_NO) {
  1237. return ERROR_SUCCESS;
  1238. }
  1239. //
  1240. // Create the backup file lists. The output will provide disk
  1241. // space info for use by DetermineSpaceUse.
  1242. //
  1243. fileString = JoinPaths (g_TempDir, TEXT("uninstall"));
  1244. CreateDirectory (fileString, NULL);
  1245. GetUninstallMetrics (&compressionFactor, &bootCabImagePadding, NULL);
  1246. spaceNeededForFastBackupClusterAligned.QuadPart = 0;
  1247. WriteBackupFilesA (
  1248. TRUE,
  1249. g_TempDir,
  1250. &g_SpaceNeededForSlowBackup,
  1251. &g_SpaceNeededForFastBackup,
  1252. compressionFactor,
  1253. bootCabImagePadding,
  1254. NULL,
  1255. &spaceNeededForFastBackupClusterAligned
  1256. );
  1257. spaceNeededForFastBackupClusterAligned.QuadPart >>= 20;
  1258. spaceNeededForFastBackupClusterAligned.LowPart += 1;
  1259. MemDbSetValueEx (
  1260. MEMDB_CATEGORY_STATE,
  1261. MEMDB_ITEM_ROLLBACK_SPACE,
  1262. NULL,
  1263. NULL,
  1264. spaceNeededForFastBackupClusterAligned.LowPart,
  1265. NULL
  1266. );
  1267. DEBUGMSG ((DBG_VERBOSE, "Space aligned by cluster needed for fast backup: %u MB", spaceNeededForFastBackupClusterAligned.LowPart));
  1268. LOG ((LOG_INFORMATION, "Win95UpgDiskSpace: Space needed for upgrade without backup: %uMB", g_SpaceNeededForUpgrade.QuadPart>>20));
  1269. LOG ((LOG_INFORMATION, "Win95UpgDiskSpace: Space needed for backup with compression: %uMB", g_SpaceNeededForSlowBackup.QuadPart>>20));
  1270. LOG ((LOG_INFORMATION, "Win95UpgDiskSpace: Space needed for backup without compression: %uMB", g_SpaceNeededForFastBackup.QuadPart>>20));
  1271. FreePathString (fileString);
  1272. return ERROR_SUCCESS;
  1273. }
  1274. DWORD
  1275. DetermineSpaceUsage (
  1276. IN DWORD Request
  1277. )
  1278. {
  1279. if (Request == REQUEST_QUERYTICKS) {
  1280. return TICKS_SPACECHECK;
  1281. }
  1282. pDetermineSpaceUsagePreReport();
  1283. return ERROR_SUCCESS;
  1284. }