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.

1504 lines
42 KiB

  1. #include "enduser.h"
  2. //
  3. // Partition image structure for the partition being restored.
  4. //
  5. PARTITION_IMAGE PartitionImage;
  6. //
  7. // Number of sectors to zap to wipe out an image
  8. // 0.98 MB of 512-byte sectors
  9. //
  10. #define ZAP_MAX 2000
  11. //
  12. // Maximum size of FAT32 fats
  13. #define MAX_FAT32_TABLE_SIZE (16*1024*1024-65536)
  14. #define MAX_FAT32_ENTRIES ((16*1024*1024-65536)/4)
  15. VOID
  16. RelocateClusterBitmap(
  17. IN HDISK DiskHandle,
  18. IN ULONG ImageStart
  19. );
  20. VOID
  21. RelocateBootPartition(
  22. IN HDISK DiskHandle,
  23. IN USHORT Cylinders,
  24. IN ULONG ExtendedCount
  25. );
  26. VOID
  27. FixUpBpb(
  28. IN HDISK DiskHandle,
  29. IN BYTE SectorsPerTrack,
  30. IN USHORT Heads,
  31. IN ULONG StartSector
  32. );
  33. VOID
  34. RemoveNonSelectedOsData(
  35. IN HDISK DiskHandle
  36. );
  37. VOID
  38. CreatePartitionTableEntry(
  39. IN HDISK DiskHandle,
  40. IN USHORT Cylinders,
  41. IN ULONG DiskSectorCount,
  42. IN ULONG StartSector,
  43. OUT ULONG *LastSector,
  44. IN BOOL Relocating
  45. );
  46. VOID
  47. TellUserToWait(
  48. VOID
  49. );
  50. VOID
  51. StartGauge(
  52. VOID
  53. );
  54. BOOL
  55. TestImage(
  56. IN HDISK DiskHandle,
  57. IN ULONG StartSector
  58. );
  59. BOOL
  60. MungeParametersForFat32Extend(
  61. IN HDISK DiskHandle,
  62. IN USHORT Cylinders,
  63. IN BYTE SectorsPerTrack,
  64. IN ULONG SourceStart,
  65. IN ULONG *TargetStart,
  66. IN FPMASTER_DISK pMasterDisk,
  67. IN FPPARTITION_IMAGE pPartitionImage,
  68. IN VOID *TemporaryBuffer
  69. );
  70. VOID
  71. AdjustTargetStart(
  72. IN HDISK DiskHandle,
  73. IN BYTE SectorsPerTrack,
  74. IN ULONG *TargetStart,
  75. IN VOID *TemporaryBuffer
  76. );
  77. ULONG
  78. ComputeClusters(
  79. IN ULONG ClusterSize,
  80. IN ULONG Sectors,
  81. IN ULONG SectorSize,
  82. IN ULONG ReservedSectors,
  83. IN ULONG Fats
  84. );
  85. BOOL
  86. IsUnknownPartition(
  87. IN BYTE SysId
  88. );
  89. VOID
  90. RestoreUsersDisk(
  91. IN HDISK DiskHandle
  92. )
  93. /*++
  94. Routine Description:
  95. This is the top-level routine concerned with restoring the user's
  96. disk so it seems as if only a single os was ever preinstalled on it.
  97. Arguments:
  98. DiskHandle - supplies open disk handle to master/target hard disk.
  99. Return Value:
  100. None. Does not return if error.
  101. --*/
  102. {
  103. ULONG SourceStart;
  104. ULONG TargetStart;
  105. BYTE Int13Unit;
  106. BYTE SectorsPerTrack;
  107. USHORT Heads;
  108. USHORT Cylinders;
  109. ULONG ExtendedCount;
  110. UINT DiskId;
  111. ULONG LastSector;
  112. FPFAT32_BOOT_SECTOR pFat32BootSect;
  113. FPPARTITION_IMAGE pFat32ImgHdr;
  114. TellUserToWait();
  115. GetDiskInfoByHandle(
  116. DiskHandle,
  117. &Int13Unit,
  118. &SectorsPerTrack,
  119. &Heads,
  120. &Cylinders,
  121. &ExtendedCount,
  122. &DiskId
  123. );
  124. SourceStart = MasterDiskInfo.ImageStartSector[MasterDiskInfo.SelectionOrdinal];
  125. TargetStart = SectorsPerTrack;
  126. _Log("Starting restore: SourceStart = 0x%lx, TargetStart = 0x%lx\n",SourceStart,TargetStart);
  127. //
  128. // Read the partition image information structure off the disk
  129. // to determine how large the image is. Cache it away somewhere safe.
  130. //
  131. if(MasterDiskInfo.State >= MDS_CACHED_IMAGE_HEADER) {
  132. _Log("Have cached partition image header, fetching from disk\n");
  133. if(!ReadDisk(DiskHandle,2,1,(FPBYTE)IoBuffer+512)) {
  134. FatalError(textReadFailedAtSector,1,2L);
  135. }
  136. } else {
  137. //
  138. // Ok, figure out where we can start laying down the partition.
  139. //
  140. _Log("TargetStart is %d, adjusting...\n",TargetStart);
  141. AdjustTargetStart( DiskHandle,
  142. SectorsPerTrack,
  143. &TargetStart,
  144. (BYTE*)IoBuffer+4096);
  145. _Log("New TargetStart is %d.\n",TargetStart);
  146. //
  147. // pull the first two sectors of the image in
  148. //
  149. if(!ReadDisk(DiskHandle,SourceStart,2,(FPBYTE)IoBuffer+512)) {
  150. FatalError(textReadFailedAtSector,2,SourceStart);
  151. }
  152. //
  153. // the first will be the image header, the second could be a fat32 boot sector
  154. //
  155. pFat32BootSect = (FPFAT32_BOOT_SECTOR)((BYTE*)IoBuffer+1024);
  156. //
  157. // We need to adjust the target start to compensate for a preserved
  158. // eisa/hiber partition
  159. //
  160. if( IsFat32(pFat32BootSect) ) {
  161. //
  162. // if it is a fat32 boot sector, then we store away some useful things we will
  163. // use when we call MungeParametersForFat32Extend.
  164. //
  165. pFat32ImgHdr = (FPPARTITION_IMAGE)((BYTE*)IoBuffer+512);
  166. pFat32ImgHdr->Fat32ReservedSectors = pFat32BootSect->PackedBpb.ReservedSectors;
  167. #if 0
  168. //
  169. // this is not necessarily 0x20
  170. //
  171. if(pFat32ImgHdr->Fat32ReservedSectors != 0x20) {
  172. FatalError(textReadFailedAtSector,2,SourceStart);
  173. }
  174. #endif
  175. //
  176. // since this is a Fat32 image, we determine how big we can expand it,
  177. // where we can start the expansion, and how big the new FATs need to be.
  178. //
  179. // We use IoBuffer+4096 as a convenient temporary work bufer.
  180. //
  181. // This will fill in the Fat32 fields of the partition image (pFat32ImageHdr)
  182. // header which we will store away safely in the next step.
  183. //
  184. MungeParametersForFat32Extend(DiskHandle,
  185. Cylinders,
  186. SectorsPerTrack,
  187. SourceStart,
  188. &TargetStart,
  189. &MasterDiskInfo,
  190. (FPPARTITION_IMAGE)pFat32ImgHdr,
  191. (BYTE*)IoBuffer+4096);
  192. }
  193. //
  194. // Save it.
  195. //
  196. if(!CmdLineArgs.Test) {
  197. if(!WriteDisk(DiskHandle,2,1,(FPBYTE)IoBuffer+512)) {
  198. FatalError(textWriteFailedAtSector,1,2L);
  199. }
  200. }
  201. _Log("Successfully cached partition image header\n");
  202. //
  203. // Clobbers first sector of IoBuffer
  204. //
  205. if(!CmdLineArgs.Test) {
  206. UpdateMasterDiskState(DiskHandle,MDS_CACHED_IMAGE_HEADER);
  207. _Log("Master disk state updated to indicate cached partition image header\n");
  208. }
  209. }
  210. SourceStart++;
  211. memmove(&PartitionImage,(FPBYTE)IoBuffer+512,sizeof(PARTITION_IMAGE));
  212. _Log("Image header for image to be restored --\n");
  213. _Log(" Signature: 0x%lx\n",PartitionImage.Signature);
  214. _Log(" Size: %u\n",PartitionImage.Size);
  215. _Log(" NonClusterSectors: 0x%lx\n",PartitionImage.NonClusterSectors);
  216. _Log(" ClusterCount: 0x%lx\n",PartitionImage.ClusterCount);
  217. _Log(" TotalSectorCount: 0x%lx\n",PartitionImage.TotalSectorCount);
  218. _Log(" LastUsedCluster: 0x%lx\n",PartitionImage.LastUsedCluster);
  219. _Log(" UsedClusterCount: 0x%lx\n",PartitionImage.UsedClusterCount);
  220. _Log(" SectorsPerCluster: %u\n",PartitionImage.SectorsPerCluster);
  221. _Log(" SystemId: %u\n",PartitionImage.SystemId);
  222. _Log("\n");
  223. if(CmdLineArgs.Test) {
  224. // validate the disk image first.
  225. TestImage(DiskHandle,SourceStart-1);
  226. TellUserToWait();
  227. }
  228. StartGauge();
  229. //
  230. // Fix up things so that no one can get back the data for the OSes
  231. // they didn't install.
  232. //
  233. RemoveNonSelectedOsData(DiskHandle);
  234. XmsInit();
  235. //
  236. // Relocate the cluster bitmap if necessary
  237. //
  238. RelocateClusterBitmap(DiskHandle,SourceStart);
  239. //
  240. // Relocate the boot partition if necessary.
  241. //
  242. RelocateBootPartition(DiskHandle,Cylinders,ExtendedCount);
  243. //
  244. // Transfer the partition data from the image to the start of
  245. // the hard drive.
  246. //
  247. ExpandImage(DiskHandle,SectorsPerTrack,SourceStart,TargetStart);
  248. XmsTerminate();
  249. TellUserToWait();
  250. //
  251. // Next, fix up the BPB's geometry-related fields.
  252. //
  253. FixUpBpb(DiskHandle,SectorsPerTrack,Heads,TargetStart);
  254. //
  255. // The next step is to create the partition table entry that describes
  256. // the partition we are restoring and remove the one for the bootable
  257. // partition.
  258. //
  259. CreatePartitionTableEntry(
  260. DiskHandle,
  261. Cylinders,
  262. ExtendedCount,
  263. TargetStart,
  264. &LastSector,
  265. FALSE
  266. );
  267. //
  268. // Now we're done. As a single final step, we recreate the
  269. // mirror boot sector for NTFS. Note that there is a window for failure
  270. // in this operation, but there's no good way around this. If we write
  271. // this sector before now we risk wiping out the bootstrap program.
  272. //
  273. if(PartitionImage.SystemId == 7) {
  274. if(ReadDisk(DiskHandle,TargetStart,1,IoBuffer)) {
  275. if(!CmdLineArgs.Test) {
  276. if(!WriteDisk(DiskHandle,LastSector,1,IoBuffer)) {
  277. FatalError(textWriteFailedAtSector,1,LastSector);
  278. }
  279. }
  280. } else {
  281. FatalError(textReadFailedAtSector,1,TargetStart);
  282. }
  283. }
  284. }
  285. VOID
  286. RemoveNonSelectedOsData(
  287. IN HDISK DiskHandle
  288. )
  289. {
  290. UINT i;
  291. ULONG SectorCount;
  292. ULONG OriginalCount;
  293. ULONG CurrentSector;
  294. PPARTITION_IMAGE p;
  295. //
  296. // See if we've already done this step.
  297. //
  298. if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_REMOVED_OTHERS)) {
  299. _Log("Already removed non-selected OS data\n");
  300. GaugeDelta(ZAP_MAX * (MasterDiskInfo.ImageCount-1));
  301. return;
  302. }
  303. //
  304. // Scribble over the first 1 MB or so of each image. This takes out
  305. // some significant file system data structures and some data.
  306. // We also take out the partition image header itself, but we do that
  307. // last so if we restart we'll be able to complete operating on the
  308. // image we were working on.
  309. //
  310. p = IoBuffer;
  311. for(i=0; i<MasterDiskInfo.ImageCount; i++) {
  312. if(i == MasterDiskInfo.SelectionOrdinal) {
  313. continue;
  314. }
  315. CurrentSector = MasterDiskInfo.ImageStartSector[i];
  316. if(!ReadDisk(DiskHandle,CurrentSector++,1,IoBuffer)) {
  317. FatalError(textReadFailedAtSector,1,CurrentSector-1);
  318. }
  319. //
  320. // If the sector is not a valid partition image header,
  321. // then we assume we've already taken it out in a previous pass
  322. // and we don't worry about it.
  323. //
  324. if(p->Signature == PARTITION_IMAGE_SIGNATURE) {
  325. _Log("Removing non-selected OS data for image %u\n",i);
  326. SectorCount = p->NonClusterSectors + (p->UsedClusterCount * p->SectorsPerCluster);
  327. if(SectorCount > ZAP_MAX) {
  328. SectorCount = ZAP_MAX;
  329. }
  330. OriginalCount = SectorCount;
  331. memset(IoBuffer,0,63*512);
  332. while(SectorCount >= 63) {
  333. if(!CmdLineArgs.Test) {
  334. if(!WriteDisk(DiskHandle,CurrentSector,63,IoBuffer)) {
  335. FatalError(textWriteFailedAtSector,63,CurrentSector);
  336. }
  337. }
  338. CurrentSector += 63;
  339. SectorCount -= 63;
  340. GaugeDelta(63);
  341. }
  342. if(SectorCount) {
  343. if(!CmdLineArgs.Test) {
  344. if(!WriteDisk(DiskHandle,CurrentSector,(BYTE)SectorCount,IoBuffer)) {
  345. FatalError(textWriteFailedAtSector,(unsigned)SectorCount,CurrentSector);
  346. }
  347. }
  348. GaugeDelta(SectorCount);
  349. }
  350. //
  351. // Now take out the image header.
  352. //
  353. if(!CmdLineArgs.Test) {
  354. if(!WriteDisk(DiskHandle,MasterDiskInfo.ImageStartSector[i],1,IoBuffer)) {
  355. FatalError(textWriteFailedAtSector,1,MasterDiskInfo.ImageStartSector[i]);
  356. }
  357. }
  358. //
  359. // We allowed for ZAP_MAX sectors in the gauge but there might
  360. // have been less than that in the image (strange case, but possible).
  361. //
  362. if(OriginalCount < (ULONG)ZAP_MAX) {
  363. GaugeDelta((ULONG)ZAP_MAX - OriginalCount);
  364. }
  365. } else {
  366. _Log("Non-selected OS data for image %u previously removed\n",i);
  367. GaugeDelta(ZAP_MAX);
  368. }
  369. }
  370. //
  371. // Update state to indicate that we've done this step.
  372. //
  373. if(!CmdLineArgs.Test) {
  374. _Log("Updating master disk state to indicate non-selected os data removed...\n");
  375. UpdateMasterDiskState(DiskHandle,MDS_REMOVED_OTHERS);
  376. _Log("Master disk state updated to indicate non-selected os data removed\n");
  377. }
  378. }
  379. VOID
  380. RelocateClusterBitmap(
  381. IN HDISK DiskHandle,
  382. IN ULONG ImageStart
  383. )
  384. {
  385. ULONG BitmapSize;
  386. ULONG Read;
  387. ULONG Target;
  388. BOOL Xms;
  389. //
  390. // Figure out how large the cluster bitmap is in sectors.
  391. //
  392. BitmapSize = (PartitionImage.LastUsedCluster/CLUSTER_BITS_PER_SECTOR) + 1;
  393. _Log("Cluster bitmap is 0x%lx sectors\n",BitmapSize);
  394. //
  395. // If we've already done this step, nothing to do.
  396. //
  397. if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_RELOCATED_BITMAP)) {
  398. _Log("Already relocated cluster bitmap\n");
  399. GaugeDelta(2*BitmapSize);
  400. return;
  401. }
  402. ImageStart += PartitionImage.NonClusterSectors
  403. + (PartitionImage.SectorsPerCluster * PartitionImage.UsedClusterCount);
  404. if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BITMAP) {
  405. //
  406. // Figure out where the bitmap will be relocated to.
  407. //
  408. Target = PartitionImage.BitmapRelocationStart;
  409. MasterDiskInfo.ClusterBitmapStart = CmdLineArgs.Test ? ImageStart : Target;
  410. _Log("Cluster bitmap to be relocated from sector 0x%lx to sector 0x%lx\n",ImageStart,Target);
  411. //
  412. // Note that there's no overlap problem so we just flat out
  413. // transfer the bitmap from beginning to end.
  414. //
  415. while(BitmapSize) {
  416. XmsIoDiskRead(DiskHandle,ImageStart,BitmapSize,&Read,&Xms);
  417. XmsIoDiskWrite(DiskHandle,Target,0,Read,Xms);
  418. BitmapSize -= Read;
  419. ImageStart += Read;
  420. Target += Read;
  421. }
  422. } else {
  423. _Log("No need to relocate cluster bitmap\n");
  424. MasterDiskInfo.ClusterBitmapStart = ImageStart;
  425. }
  426. //
  427. // Note that we update state to indicate that this is done even if we
  428. // don't actually relocate the cluster bitmap, for completeness and
  429. // tracking of what's going on.
  430. //
  431. if(!CmdLineArgs.Test) {
  432. _Log("Updating master disk state to indicate cluster bitmap relocated...\n");
  433. UpdateMasterDiskState(DiskHandle,MDS_RELOCATED_BITMAP);
  434. _Log("Master disk state updated to indicate cluster bitmap relocated\n");
  435. }
  436. }
  437. VOID
  438. RelocateBootPartition(
  439. IN HDISK DiskHandle,
  440. IN USHORT Cylinders,
  441. IN ULONG ExtendedCount
  442. )
  443. {
  444. ULONG Read;
  445. ULONG Target;
  446. ULONG ImageStart;
  447. ULONG Count;
  448. BOOL Xms;
  449. if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BOOT) {
  450. //
  451. // If we've already done this step, nothing to do.
  452. //
  453. if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_RELOCATED_BOOT)) {
  454. _Log("Already relocated boot partition\n");
  455. GaugeDelta(2*MasterDiskInfo.StartupPartitionSectorCount);
  456. } else {
  457. //
  458. // Figure out where the boot partition will be relocated to.
  459. //
  460. Target = PartitionImage.BootRelocationStart;
  461. ImageStart = MasterDiskInfo.StartupPartitionStartSector;
  462. Count = MasterDiskInfo.StartupPartitionSectorCount;
  463. if(!CmdLineArgs.Test) {
  464. MasterDiskInfo.StartupPartitionStartSector = Target;
  465. }
  466. _Log(
  467. "Cluster bitmap to be relocated from sector 0x%lx to sector 0x%lx\n",
  468. ImageStart,
  469. Target
  470. );
  471. //
  472. // Note that there's no overlap problem so we just flat out
  473. // transfer the boot partition from end to end.
  474. //
  475. while(Count) {
  476. XmsIoDiskRead(DiskHandle,ImageStart,Count,&Read,&Xms);
  477. XmsIoDiskWrite(DiskHandle,Target,0,Read,Xms);
  478. Count -= Read;
  479. ImageStart += Read;
  480. Target += Read;
  481. }
  482. if(!CmdLineArgs.Test) {
  483. _Log("Updating master disk state to indicate boot part relocated...\n");
  484. UpdateMasterDiskState(DiskHandle,MDS_RELOCATED_BOOT);
  485. _Log("Master disk state updated to indicate boot part relocated\n");
  486. }
  487. }
  488. //
  489. // Ok, it's been transferred. Fix up the mbr to point at it.
  490. // Note that CreatePartitionTableEntry updates master disk state but is protected by
  491. // checking aginst CmdLineArgs.Test.
  492. //
  493. if(CmdLineArgs.Test || (MasterDiskInfo.State < MDS_RELOCATED_BOOT_MBR)) {
  494. CreatePartitionTableEntry(
  495. DiskHandle,
  496. Cylinders,
  497. ExtendedCount,
  498. MasterDiskInfo.StartupPartitionStartSector,
  499. &Target,
  500. TRUE
  501. );
  502. }
  503. } else {
  504. _Log("No need to relocate boot partition\n");
  505. }
  506. }
  507. VOID
  508. FixUpBpb(
  509. IN HDISK DiskHandle,
  510. IN BYTE SectorsPerTrack,
  511. IN USHORT Heads,
  512. IN ULONG StartSector
  513. )
  514. {
  515. USHORT BackupBootSectorOfs;
  516. //
  517. // See if we've already done this step.
  518. //
  519. if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_UPDATED_BPB)) {
  520. _Log("Already fixed up BPB\n");
  521. return;
  522. }
  523. if(!ReadDisk(DiskHandle,StartSector,1,IoBuffer)) {
  524. FatalError(textReadFailedAtSector,1,StartSector);
  525. }
  526. if(PartitionImage.Fat32ReservedSectors) {
  527. //
  528. // this is a FAT32 partition, we munge some extra stuff in the BPB
  529. // when we do the partition expansion
  530. //
  531. FPFAT32_BOOT_SECTOR pBootSect = IoBuffer;
  532. ULONG FatSectorCount;
  533. pBootSect->PackedBpb.LargeSectors = PartitionImage.Fat32AdjustedSectorCount;
  534. FatSectorCount = PartitionImage.Fat32AdjustedFatTableEntryCount / (512/4);
  535. FatSectorCount = (PartitionImage.Fat32AdjustedFatTableEntryCount % (512/4)) ?
  536. FatSectorCount++ : FatSectorCount;
  537. pBootSect->PackedBpb.LargeSectorsPerFat = FatSectorCount;
  538. BackupBootSectorOfs = pBootSect->PackedBpb.BackupBootSector;
  539. }
  540. //
  541. // Slam the relevent fields.
  542. //
  543. *(FPUSHORT)&((FPBYTE)IoBuffer)[24] = SectorsPerTrack;
  544. *(FPUSHORT)&((FPBYTE)IoBuffer)[26] = Heads;
  545. *(FPULONG)&((FPBYTE)IoBuffer)[28] = StartSector;
  546. //
  547. // Want to do this but for fat32 it's in a different place
  548. // so it's dangerous
  549. //
  550. //*(FPBYTE)&((FPBYTE)IoBuffer)[36] = Int13Unit;
  551. if(!CmdLineArgs.Test) {
  552. if(!WriteDisk(DiskHandle,StartSector,1,IoBuffer)) {
  553. FatalError(textWriteFailedAtSector,1,StartSector);
  554. }
  555. if( PartitionImage.Fat32ReservedSectors ) {
  556. //
  557. // Fat32 has a backup boot sector
  558. //
  559. if(!WriteDisk(DiskHandle,StartSector+BackupBootSectorOfs,1,IoBuffer)) {
  560. FatalError(textWriteFailedAtSector,1,StartSector+BackupBootSectorOfs);
  561. }
  562. _Log("Successfully fixed up FAT32 mirror BPB\n");
  563. }
  564. }
  565. _Log("Successfully fixed up BPB\n");
  566. if(PartitionImage.Fat32ReservedSectors) {
  567. //
  568. // FAT32 case.
  569. //
  570. ULONG NewFreeClusterCount;
  571. ULONG OldFreeClusterCount;
  572. USHORT FsInfoSectorOfs;
  573. FPFSINFO_SECTOR pFsInfoSector;
  574. //
  575. // need to fixup the FsInfoSector to reflect the new free space count.
  576. //
  577. OldFreeClusterCount = PartitionImage.ClusterCount - PartitionImage.UsedClusterCount;
  578. NewFreeClusterCount = PartitionImage.Fat32AdjustedFatTableEntryCount - PartitionImage.UsedClusterCount;
  579. FsInfoSectorOfs = ((FPFAT32_BOOT_SECTOR)IoBuffer)->PackedBpb.FsInfoSector;
  580. //
  581. // ok, get FSINFO in.
  582. //
  583. if(!ReadDisk(DiskHandle,StartSector+FsInfoSectorOfs,1,IoBuffer)) {
  584. FatalError(textReadFailedAtSector,1,StartSector+FsInfoSectorOfs);
  585. }
  586. //
  587. // now verify it is, in fact, an FSINFO sector.
  588. //
  589. pFsInfoSector = (FPFSINFO_SECTOR)IoBuffer;
  590. if(pFsInfoSector->FsInfoSignature != FSINFO_SIGNATURE ||
  591. pFsInfoSector->SectorBeginSignature != FSINFO_SECTOR_BEGIN_SIGNATURE ||
  592. pFsInfoSector->SectorEndSignature != FSINFO_SECTOR_END_SIGNATURE
  593. ) {
  594. FatalError(textReadFailedAtSector,1,StartSector+FsInfoSectorOfs);
  595. }
  596. //
  597. // validate our old free cluster count
  598. //
  599. if( OldFreeClusterCount != pFsInfoSector->FreeClusterCount ) {
  600. FatalError(textReadFailedAtSector,1,StartSector+FsInfoSectorOfs);
  601. }
  602. //
  603. // now drop in our new freespace count.
  604. //
  605. pFsInfoSector->FreeClusterCount = NewFreeClusterCount;
  606. //
  607. // Write FSINFO sect back out. Twice. (the two copies are identical.)
  608. //
  609. if(!CmdLineArgs.Test) {
  610. if(!WriteDisk(DiskHandle,StartSector+FsInfoSectorOfs,1,IoBuffer)) {
  611. FatalError(textWriteFailedAtSector,1,StartSector+FsInfoSectorOfs);
  612. }
  613. if(!WriteDisk(DiskHandle,StartSector+BackupBootSectorOfs+FsInfoSectorOfs,1,IoBuffer)) {
  614. FatalError(textWriteFailedAtSector,1,StartSector+BackupBootSectorOfs+FsInfoSectorOfs);
  615. }
  616. }
  617. _Log("Successfully fixed up FsInfoSector(s)\n");
  618. }
  619. if(!CmdLineArgs.Test) {
  620. _Log("Updating master disk state to indicate BPB fixed up...\n");
  621. UpdateMasterDiskState(DiskHandle,MDS_UPDATED_BPB);
  622. _Log("Master disk state updated to indicate BPB fixed up\n");
  623. }
  624. }
  625. VOID
  626. CreatePartitionTableEntry(
  627. IN HDISK DiskHandle,
  628. IN USHORT Cylinders,
  629. IN ULONG DiskSectorCount,
  630. IN ULONG StartSector,
  631. OUT ULONG *LastSector,
  632. IN BOOL Relocating
  633. )
  634. {
  635. unsigned i;
  636. USHORT SectorsPerCylinder;
  637. USHORT r;
  638. ULONG EndSector;
  639. BOOL Overflow;
  640. ULONG C;
  641. BYTE H;
  642. BYTE S;
  643. struct {
  644. BYTE Active;
  645. BYTE StartH;
  646. BYTE StartS;
  647. BYTE StartC;
  648. BYTE SysId;
  649. BYTE EndH;
  650. BYTE EndS;
  651. BYTE EndC;
  652. ULONG Start;
  653. ULONG Count;
  654. } *PartTabEnt,*TheEntry;
  655. if(!DiskSectorCount) {
  656. DiskSectorCount = (ULONG)MasterDiskInfo.OriginalSectorsPerTrack
  657. * (ULONG)MasterDiskInfo.OriginalHeads
  658. * (ULONG)Cylinders;
  659. }
  660. SectorsPerCylinder = MasterDiskInfo.OriginalHeads * MasterDiskInfo.OriginalSectorsPerTrack;
  661. //
  662. // Read the MBR
  663. //
  664. if(!ReadDisk(DiskHandle,0,1,IoBuffer)) {
  665. FatalError(textReadFailedAtSector,1,0L);
  666. }
  667. //
  668. // Traverse the MBR, trying to find the MPK boot partition.
  669. // Also make sure all entries are inactive.
  670. //
  671. TheEntry = NULL;
  672. for(i=0; i<4; i++) {
  673. PartTabEnt = (FPVOID)((FPBYTE)IoBuffer + 0x1be + (i*16));
  674. if(PartTabEnt->SysId
  675. && (PartTabEnt->Start == MasterDiskInfo.StartupPartitionStartSector)
  676. && !TheEntry) {
  677. TheEntry = PartTabEnt;
  678. }
  679. PartTabEnt->Active = 0;
  680. }
  681. if(!TheEntry) {
  682. //
  683. // Couldn't find it, something is seriously corrupt.
  684. //
  685. FatalError(textCantFindMPKBoot);
  686. }
  687. if(Relocating) {
  688. EndSector = StartSector + MasterDiskInfo.StartupPartitionSectorCount;
  689. } else {
  690. if( PartitionImage.Fat32ReservedSectors ) {
  691. //
  692. // FAT32 resize case
  693. //
  694. EndSector = PartitionImage.Fat32AdjustedSectorCount + StartSector;
  695. } else {
  696. EndSector = PartitionImage.TotalSectorCount + StartSector;
  697. }
  698. //
  699. // Refigure the end sector so it's aligned to a cylinder boundary.
  700. //
  701. if(r = (USHORT)(EndSector % SectorsPerCylinder)) {
  702. EndSector += SectorsPerCylinder - r;
  703. }
  704. //
  705. // In some cases NT reports the disk is 1 or 2 cylinders
  706. // larger than int13 reports. Thus we may have a volume that
  707. // spans beyond the end of the disk as reported by int13.
  708. // If we cap the end of the partition to the size reported
  709. // by int13 in this case, we will end up with a partition
  710. // whose size in the partition table is smaller than the
  711. // size recorded in the BPB. NTFS is particular will then
  712. // refuse to mount the drive and you get inaccassible boot device.
  713. // BIOSes will typically allow I/O to these "extra" cylinders
  714. // even though they're not reported via int13 function 8, so this
  715. // shouldn't be a problem.
  716. //
  717. //if(EndSector > DiskSectorCount) {
  718. // EndSector = DiskSectorCount;
  719. //}
  720. }
  721. TheEntry->Active = 0x80;
  722. TheEntry->Start = StartSector;
  723. TheEntry->Count = EndSector - StartSector;
  724. //
  725. // Calculate start CHS values.
  726. //
  727. C = StartSector / SectorsPerCylinder;
  728. if(C >= (ULONG)Cylinders) {
  729. C = Cylinders - 1;
  730. H = (BYTE)(MasterDiskInfo.OriginalHeads - 1);
  731. S = (BYTE)(MasterDiskInfo.OriginalSectorsPerTrack - 1);
  732. } else {
  733. H = (BYTE)((StartSector % SectorsPerCylinder) / MasterDiskInfo.OriginalSectorsPerTrack);
  734. S = (BYTE)((StartSector % SectorsPerCylinder) % MasterDiskInfo.OriginalSectorsPerTrack);
  735. }
  736. TheEntry->StartC = (BYTE)C;
  737. TheEntry->StartH = H;
  738. TheEntry->StartS = (BYTE)((S + 1) | (((USHORT)C & 0x300) >> 2));
  739. //
  740. // Similarly for the end.
  741. //
  742. EndSector--;
  743. *LastSector = EndSector;
  744. C = EndSector / SectorsPerCylinder;
  745. if(C >= (ULONG)Cylinders) {
  746. C = Cylinders - 1;
  747. H = (BYTE)(MasterDiskInfo.OriginalHeads - 1);
  748. S = (BYTE)(MasterDiskInfo.OriginalSectorsPerTrack - 1);
  749. Overflow = TRUE;
  750. } else {
  751. H = (BYTE)((EndSector % SectorsPerCylinder) / MasterDiskInfo.OriginalSectorsPerTrack);
  752. S = (BYTE)((EndSector % SectorsPerCylinder) % MasterDiskInfo.OriginalSectorsPerTrack);
  753. Overflow = FALSE;
  754. }
  755. TheEntry->EndC = (BYTE)C;
  756. TheEntry->EndH = H;
  757. TheEntry->EndS = (BYTE)((S + 1) | (((USHORT)C & 0x300) >> 2));
  758. if(!Relocating) {
  759. TheEntry->SysId = PartitionImage.SystemId;
  760. }
  761. if(Overflow) {
  762. switch(TheEntry->SysId) {
  763. case 1:
  764. case 4:
  765. case 6:
  766. //
  767. // Regular FAT12/FAT12/BIGFAT --> XINT13 FAT
  768. //
  769. TheEntry->SysId = 0xe;
  770. break;
  771. case 0xb:
  772. //
  773. // FAT32 --> XINT13 FAT32
  774. //
  775. TheEntry->SysId = 0xc;
  776. break;
  777. }
  778. } else {
  779. switch(TheEntry->SysId) {
  780. case 0xc:
  781. //
  782. // XINT13 FAT32 --> FAT32
  783. //
  784. TheEntry->SysId = 0xb;
  785. break;
  786. case 0xe:
  787. //
  788. // XINT13 FAT --> regular FAT
  789. //
  790. if(Relocating) {
  791. if(MasterDiskInfo.StartupPartitionSectorCount >= 65536L) {
  792. TheEntry->SysId = 6;
  793. } else {
  794. if(MasterDiskInfo.StartupPartitionSectorCount >= 32680L) {
  795. TheEntry->SysId = 4;
  796. } else {
  797. TheEntry->SysId = 1;
  798. }
  799. }
  800. } else {
  801. if(PartitionImage.TotalSectorCount >= 65536L) {
  802. TheEntry->SysId = 6;
  803. } else {
  804. if(PartitionImage.TotalSectorCount >= 32680L) {
  805. TheEntry->SysId = 4;
  806. } else {
  807. TheEntry->SysId = 1;
  808. }
  809. }
  810. }
  811. break;
  812. }
  813. }
  814. //
  815. // Write the MBR.
  816. //
  817. // Note that after the MBR has been updated, the system will no longer
  818. // boot into this program. Thus the master disk state is now irrelevent.
  819. // But just for completeness, we track that we completed this operation.
  820. //
  821. if(!CmdLineArgs.Test) {
  822. if(!WriteDisk(DiskHandle,0,1,IoBuffer)) {
  823. FatalError(textWriteFailedAtSector,1,0L);
  824. }
  825. }
  826. if(!CmdLineArgs.Test) {
  827. UpdateMasterDiskState(DiskHandle,Relocating ? MDS_RELOCATED_BOOT_MBR : MDS_UPDATED_MBR);
  828. }
  829. }
  830. VOID
  831. TellUserToWait(
  832. VOID
  833. )
  834. {
  835. FPCHAR p,q;
  836. char c;
  837. UINT line;
  838. INT maxlen;
  839. DispClearClientArea(NULL);
  840. //
  841. // This could be more than one line. We want the message centered
  842. // and left-aligned. Determine the longest line length and center
  843. // the entire message based on that length.
  844. //
  845. maxlen = 0;
  846. p = textPleaseWaitRestoring;
  847. do {
  848. //
  849. // Locate the next newline or terminator
  850. //
  851. for(q=p; (*q != '\n') && *q; q++);
  852. //
  853. // See if this line is maximum length seen so far.
  854. //
  855. if((q-p) > maxlen) {
  856. maxlen = q-p;
  857. }
  858. p = q+1;
  859. } while(*q);
  860. //
  861. // Second pass actually prints it out.
  862. //
  863. p = textPleaseWaitRestoring;
  864. line = 1;
  865. do {
  866. for(q=p; (*q != '\n') && *q; q++);
  867. //
  868. // Nul-terminate the line in preparation for printing it out.
  869. //
  870. c = *q;
  871. *q = 0;
  872. DispPositionCursor((BYTE)((80-maxlen)/2),(BYTE)(TEXT_TOP_LINE+line));
  873. DispWriteString(p);
  874. line++;
  875. *q = c;
  876. p = q+1;
  877. } while(*q);
  878. }
  879. VOID
  880. StartGauge(
  881. VOID
  882. )
  883. {
  884. ULONG SectorCount;
  885. //
  886. // Figure out how many sectors we will transfer in total.
  887. // This includes
  888. //
  889. // a) relocating the cluster bitmap
  890. // b) relocating the boot partition
  891. // c) transferring the actual data
  892. // d) zapping unselected OS images
  893. //
  894. SectorCount = 0;
  895. if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BITMAP) {
  896. SectorCount += (PartitionImage.LastUsedCluster/CLUSTER_BITS_PER_SECTOR) + 1;
  897. }
  898. if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BOOT) {
  899. SectorCount += MasterDiskInfo.StartupPartitionSectorCount;
  900. }
  901. SectorCount += PartitionImage.NonClusterSectors;
  902. SectorCount += PartitionImage.SectorsPerCluster * PartitionImage.UsedClusterCount;
  903. SectorCount *= 2;
  904. SectorCount += ZAP_MAX * (MasterDiskInfo.ImageCount-1);
  905. GaugeInit(SectorCount);
  906. }
  907. BOOL
  908. TestImage(
  909. IN HDISK DiskHandle,
  910. IN ULONG StartSector
  911. )
  912. {
  913. FPVOID Buffer,OriginalBuffer;
  914. ULONG CurrentSector;
  915. ULONG ImageCRC;
  916. ULONG CalcCRC;
  917. ULONG BytesCRC;
  918. ULONG SectorsRemaining;
  919. ULONG TotalSectors;
  920. ULONG BitmapSize;
  921. BYTE Count;
  922. DispClearClientArea(NULL);
  923. DispPositionCursor(TEXT_LEFT_MARGIN,TEXT_TOP_LINE);
  924. DispWriteString(textValidatingImage);
  925. _Log("Validating image...\n");
  926. DispWriteString("\n\n");
  927. // need to allocate aligned buffer
  928. if(!AllocTrackBuffer(63,&Buffer,&OriginalBuffer)) {
  929. FatalError(textOOM);
  930. return FALSE;
  931. }
  932. CalcCRC = CRC32_INITIAL_VALUE;
  933. BytesCRC = 0;
  934. // read inital sector to get info
  935. CurrentSector = StartSector;
  936. if( ReadDisk( DiskHandle, CurrentSector, 1, Buffer ) ) {
  937. ImageCRC = ((PPARTITION_IMAGE)Buffer)->CRC;
  938. BitmapSize = ((PPARTITION_IMAGE)Buffer)->LastUsedCluster;
  939. BitmapSize = (BitmapSize % (8*512)) ? BitmapSize/(8*512)+1 : BitmapSize/(8*512);
  940. SectorsRemaining = ((PPARTITION_IMAGE)Buffer)->NonClusterSectors // fs structs
  941. + ((PPARTITION_IMAGE)Buffer)->SectorsPerCluster
  942. * ((PPARTITION_IMAGE)Buffer)->UsedClusterCount // data area
  943. + BitmapSize; // image cluster bitmap
  944. ((PPARTITION_IMAGE)Buffer)->CRC = 0;
  945. ((PPARTITION_IMAGE)Buffer)->BitmapRelocationStart = 0;
  946. ((PPARTITION_IMAGE)Buffer)->BootRelocationStart = 0;
  947. ((PPARTITION_IMAGE)Buffer)->Flags = 0;
  948. TotalSectors = SectorsRemaining;
  949. } else {
  950. FatalError(textReadFailedAtSector,1,CurrentSector);
  951. return FALSE;
  952. }
  953. CurrentSector++;
  954. // update the computed CRC
  955. CalcCRC = CRC32Compute( Buffer, 512, CalcCRC);
  956. BytesCRC += 512;
  957. GaugeInit(SectorsRemaining);
  958. // loop reading the entire file, updating the CRC
  959. while (SectorsRemaining) {
  960. Count = (BYTE) ((SectorsRemaining > 63L) ? 63L : SectorsRemaining);
  961. if( ReadDisk( DiskHandle, CurrentSector, Count , Buffer ) ) {
  962. CalcCRC = CRC32Compute( Buffer, Count*512, CalcCRC);
  963. BytesCRC += Count*512;
  964. } else {
  965. FatalError(textReadFailedAtSector,Count,CurrentSector);
  966. return FALSE;
  967. }
  968. SectorsRemaining -= Count;
  969. CurrentSector += Count;
  970. // print progress
  971. GaugeDelta(Count);
  972. }
  973. // compare with stored CRC
  974. DispClearClientArea(NULL);
  975. DispPositionCursor(TEXT_LEFT_MARGIN,TEXT_TOP_LINE);
  976. _Log("Image file checksum = 0x%08lx\n",CalcCRC);
  977. if( CalcCRC != ImageCRC ) {
  978. FatalError(textChecksumFail);
  979. _Log("** WARNING ** checksum does not match original checksum 0x%08lx\n",ImageCRC);
  980. return FALSE;
  981. } else {
  982. DispWriteString(textChecksumOk);
  983. }
  984. _Log("Image checksum ok.\n");
  985. free(OriginalBuffer);
  986. return TRUE;
  987. }
  988. BOOL
  989. MungeParametersForFat32Extend(
  990. IN HDISK DiskHandle,
  991. IN USHORT Cylinders,
  992. IN BYTE SectorsPerTrack,
  993. IN ULONG SourceStart,
  994. IN ULONG *TargetStart,
  995. IN FPMASTER_DISK pMasterDisk,
  996. IN FPPARTITION_IMAGE pPartitionImage,
  997. IN VOID *TemporaryBuffer
  998. )
  999. {
  1000. ULONG SectorsPerCylinder;
  1001. USHORT ReservedSectorCount;
  1002. ULONG NewSectorCount;
  1003. ULONG NewFatSize;
  1004. ULONG ClusterSize;
  1005. //
  1006. // check for FAT32
  1007. //
  1008. if( pPartitionImage->SystemId == 0x0b || pPartitionImage->SystemId == 0x0c ) {
  1009. SectorsPerCylinder = pMasterDisk->OriginalHeads * pMasterDisk->OriginalSectorsPerTrack;
  1010. //
  1011. // get the reserved sector count and the cluster size from the header
  1012. //
  1013. ReservedSectorCount = pPartitionImage->Fat32ReservedSectors;
  1014. ClusterSize = pPartitionImage->SectorsPerCluster;
  1015. //
  1016. // Read the boot sector of the image
  1017. //
  1018. if(!ReadDisk(DiskHandle,SourceStart+1,1,TemporaryBuffer)) {
  1019. FatalError(textReadFailedAtSector,1,0L);
  1020. }
  1021. //
  1022. // Need to save away the original FAT32 fat size.
  1023. //
  1024. if( IsFat32( TemporaryBuffer ) ) {
  1025. pPartitionImage->Fat32OriginalFatTableSectCount =
  1026. ((FPFAT32_BOOT_SECTOR)TemporaryBuffer)->PackedBpb.LargeSectorsPerFat;
  1027. } else {
  1028. //
  1029. // If we're here, and this isn't FAT32, we're in trouble.
  1030. //
  1031. FatalError(textCantFindMasterDisk);
  1032. }
  1033. //
  1034. // calculate the max size of the new partition
  1035. // = (total cylinder count - the new start) * (sectors/cyl)
  1036. //
  1037. // we assume the new partition will extend to the end of the disk.
  1038. //
  1039. NewSectorCount = Cylinders * SectorsPerCylinder - *TargetStart;
  1040. //
  1041. // given this number of sectors, calculate how many clusters we can make
  1042. // and how many FAT entries we need to track them
  1043. //
  1044. NewFatSize = ComputeClusters(
  1045. ClusterSize*512, // # of bytes in a cluster
  1046. NewSectorCount, // # of sectors in partition
  1047. 512, // sector size in bytes
  1048. ReservedSectorCount, // reserved sector count
  1049. 2 // # of Fats
  1050. );
  1051. if( NewFatSize < MAX_FAT32_ENTRIES ) {
  1052. //
  1053. // if this will fit in a 16MB-64K FAT, then leave it alone.
  1054. //
  1055. } else {
  1056. //
  1057. // otherwise we clip the partition size to the max allowed.
  1058. //
  1059. NewFatSize = MAX_FAT32_ENTRIES;
  1060. NewSectorCount = ReservedSectorCount + MAX_FAT32_ENTRIES/256 + MAX_FAT32_ENTRIES * ClusterSize;
  1061. }
  1062. pPartitionImage->Fat32AdjustedFatTableEntryCount = NewFatSize;
  1063. pPartitionImage->Fat32AdjustedSectorCount = NewSectorCount;
  1064. }
  1065. return TRUE;
  1066. }
  1067. VOID
  1068. AdjustTargetStart(
  1069. IN HDISK DiskHandle,
  1070. IN BYTE SectorsPerTrack,
  1071. IN ULONG *TargetStart,
  1072. IN VOID *TemporaryBuffer
  1073. )
  1074. {
  1075. unsigned i;
  1076. BOOL foundUnknown;
  1077. FPPARTITION_TABLE_ENTRY pPartitionTab;
  1078. //
  1079. // Read the MBR
  1080. //
  1081. if(!ReadDisk(DiskHandle,0,1,TemporaryBuffer)) {
  1082. FatalError(textReadFailedAtSector,1,0L);
  1083. }
  1084. //
  1085. // Validate that it is a good MBR.
  1086. //
  1087. if( ((FPMBR)TemporaryBuffer)->AA55Signature != BOOT_RECORD_SIGNATURE ) {
  1088. FatalError(textReadFailedAtSector,1,0L);
  1089. _Log(" WARNING: The MBR was invalid!");
  1090. }
  1091. //
  1092. // now inspect the MBR, and check for an unrecognized partition.
  1093. //
  1094. pPartitionTab = ((FPMBR)TemporaryBuffer)->PartitionTable;
  1095. foundUnknown = FALSE;
  1096. for(i=0; i<4; i++) {
  1097. if( IsUnknownPartition(pPartitionTab[i].SysId) ) {
  1098. //
  1099. // we assume the EISA config/hiber partition is at the start of the disk
  1100. // adjust the start of the image restore to the cylinder past the end of it
  1101. //
  1102. foundUnknown = TRUE;
  1103. }
  1104. }
  1105. _Log(" The master disk claims %ld sectors were reserved for EISA and hiber partitions.\n",
  1106. MasterDiskInfo.FreeSpaceStart);
  1107. if(foundUnknown == FALSE && MasterDiskInfo.FreeSpaceStart ) {
  1108. //
  1109. // eh? How did FreeSpaceStart get set without having a partition there?
  1110. //
  1111. _Log(" WARNING: The master disk claims disk space was reserved for \n");
  1112. _Log(" EISA/hiber partition when one does not appear to exist!\n");
  1113. FatalError(textCantOpenMasterDisk);
  1114. }
  1115. if(MasterDiskInfo.FreeSpaceStart) {
  1116. //
  1117. // MasterDiskInfo.FreeSpaceStart will be non-zero if we discovered a non-recognized
  1118. // partition when we built the master disk. The target start sector should be adjusted
  1119. // to this number.
  1120. //
  1121. *TargetStart = MasterDiskInfo.FreeSpaceStart;
  1122. }
  1123. //
  1124. // otherwise we should just leave the target start sector alone.
  1125. //
  1126. return;
  1127. }
  1128. //
  1129. // modified from \nt\private\utils\ufat\src\rfatsa.cxx
  1130. //
  1131. ULONG
  1132. ComputeClusters(
  1133. IN ULONG ClusterSize,
  1134. IN ULONG Sectors,
  1135. IN ULONG SectorSize,
  1136. IN ULONG ReservedSectors,
  1137. IN ULONG Fats
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. This routine computes the number of clusters on a volume given
  1142. the cluster size, volume size and the fat type.
  1143. Arguments:
  1144. ClusterSize - Supplies the size of a cluster in number of bytes.
  1145. Sectors - Supplies the total number of sectors in the volume.
  1146. SectorSize - Supplies the size of a sector in number of bytes.
  1147. ReservedSectors - Supplies the number of reserved sectors.
  1148. Fats - Supplies the number of copies of fat for this volume.
  1149. Return Value:
  1150. ULONG - The total number of clusters for the given configuration.
  1151. ++*/
  1152. {
  1153. ULONG entries_per_sec; // Number of FAT entries per sector.
  1154. ULONG fat_entry_size; // Size of each FAT entry in number of BITS.
  1155. ULONG sectors_left; // Number of sectors left for consideration.
  1156. ULONG sec_per_clus; // Sectors per cluster.
  1157. ULONG increment = 1; // Increment step size in number of FAT sectors.
  1158. ULONG clusters = 0; // Number of clusters in total.
  1159. ULONG temp; // Temporary place-holder for optimizing certain
  1160. // computations.
  1161. sectors_left = Sectors - ReservedSectors;
  1162. sec_per_clus = ClusterSize / SectorSize;
  1163. //
  1164. // The Fat entry size is 32 bits, since we only support FAT32
  1165. //
  1166. fat_entry_size = 32;
  1167. //
  1168. // Compute the number of FAT entries a sector can hold.
  1169. // NOTE that fat_entry_size is the size in BITS,
  1170. // this is the reason for the "* 8" (bits per byte).
  1171. //
  1172. entries_per_sec = (SectorSize * 8) / fat_entry_size;
  1173. //
  1174. // Compute a sensible increment step size to begin with.
  1175. //
  1176. while (Sectors / (increment * entries_per_sec * sec_per_clus) > 1) {
  1177. increment *= 2;
  1178. }
  1179. //
  1180. // We have to handle the first sector of FAT entries
  1181. // separately because the first two entries are reserved.
  1182. // Kind of yucky, isn't it?
  1183. //
  1184. temp = Fats + ((entries_per_sec - 2) * sec_per_clus);
  1185. if (sectors_left < temp) {
  1186. return (sectors_left - Fats) / sec_per_clus;
  1187. } else {
  1188. sectors_left -= temp;
  1189. clusters += entries_per_sec - 2;
  1190. while (increment && sectors_left) {
  1191. temp = (Fats + entries_per_sec * sec_per_clus) * increment;
  1192. if (sectors_left < temp) {
  1193. //
  1194. // If the increment step is only one, try to utilize the remaining sectors
  1195. // as much as possible.
  1196. //
  1197. if (increment == 1) {
  1198. //
  1199. // Additional clusters may be possible after allocating
  1200. // one more sector of fat.
  1201. //
  1202. if ( sectors_left > Fats) {
  1203. temp = (sectors_left - Fats) / sec_per_clus;
  1204. if (temp > 0) {
  1205. clusters += temp;
  1206. }
  1207. }
  1208. }
  1209. //
  1210. // Cut the increment step by half if it is too big.
  1211. //
  1212. increment /= 2;
  1213. } else {
  1214. sectors_left -= temp;
  1215. clusters += increment * entries_per_sec;
  1216. }
  1217. }
  1218. return clusters;
  1219. }
  1220. FatalError("This line should never be executed.");
  1221. return 0;
  1222. }
  1223. BOOL
  1224. IsUnknownPartition(
  1225. IN BYTE SysId
  1226. )
  1227. {
  1228. if( SysId != 0x00 && // not unused
  1229. SysId != 0x01 &&
  1230. SysId != 0x04 &&
  1231. SysId != 0x06 &&
  1232. SysId != 0x07 &&
  1233. SysId != 0x0b &&
  1234. SysId != 0x0c &&
  1235. SysId != 0x0e ) {
  1236. return TRUE;
  1237. }
  1238. return FALSE;
  1239. }