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.

1741 lines
50 KiB

  1. #include <mytypes.h>
  2. #include <diskio.h>
  3. #include <partio.h>
  4. #include <misclib.h>
  5. #include <makepart.h>
  6. #include <partimag.h>
  7. #include <msgfile.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <memory.h>
  11. #include <dos.h>
  12. #include <share.h>
  13. #include <string.h>
  14. #include "makemast.h"
  15. #define xERROR 0
  16. #define xPROCEED 1
  17. #define xBAIL 2
  18. FPVOID IoBuffer,UnalignedBuffer;
  19. CMD_LINE_ARGS CmdLineArgs;
  20. ULONG CheckSum;
  21. ULONG ImageCheckSum;
  22. ULONG BytesCRC;
  23. ULONG FreeSpaceStart;
  24. ULONG FreeSpaceEnd;
  25. //
  26. // Extra space needed for worst case disk expansion.
  27. //
  28. // 16MB - 64K is the largest FAT that Win98 scandisk can handle, thus
  29. // we only support a FAT table up to that size.
  30. //
  31. // So at worst we'll need to reserve twice that amount of space (32MB) in front to prevent
  32. // the cluster restores from trashing our bitmap and MPK startup partitions.
  33. //
  34. // Fat32ResizeMaxOffset will be set to 0 if the partition isn't FAT32
  35. #define FAT32_SPACE_TO_LEAVE 65535
  36. ULONG Fat32ResizeMaxOffset;
  37. //
  38. // Text for the program
  39. //
  40. char *textNoDisks;
  41. char *textSelectDiskPrompt;
  42. char *textCantOpenDisk;
  43. char *textOOM;
  44. char *textDiskReadError;
  45. char *textDiskWriteError;
  46. char *textSureWipeMaster;
  47. char *textSureWipeDisk;
  48. char *textMbrIoFailed;
  49. char *textRebootPrompt;
  50. char *textDone;
  51. char *textDisk;
  52. char *textPaddedMbCount;
  53. char *textInvalidSelection;
  54. char *textMaster;
  55. char *textYesNo;
  56. char *textMasterDiskCorrupt;
  57. char *textUsage;
  58. char *textMasterDiskFull;
  59. char *textRoomForNImages;
  60. char *textEnterImageFilename;
  61. char *textInvalidImageFile;
  62. char *textImageFileTooBig;
  63. char *textCantAccessImageFile;
  64. char *textTransferringFile;
  65. char *textCantOpenFile;
  66. char *textReadingListFromFile;
  67. char *textGeometryMismatch;
  68. char *textTooFragmented;
  69. char *textChecksum;
  70. char *textChecksumFail;
  71. char *textBytesProcessed;
  72. char *textChecksumOK;
  73. char *textTooManyPartitions;
  74. char *textFoundExistingPartitions;
  75. char *textExpandedImageFileTooBig;
  76. char *textFreeSpaceNeedsToBeHere;
  77. MESSAGE_STRING TextMessages[] = { { &textNoDisks, 1 },
  78. { &textSelectDiskPrompt, 2 },
  79. { &textCantOpenDisk, 3 },
  80. { &textOOM, 4 },
  81. { &textDiskReadError, 5 },
  82. { &textDiskWriteError, 6 },
  83. { &textSureWipeMaster, 7 },
  84. { &textSureWipeDisk, 8 },
  85. { &textMbrIoFailed, 9 },
  86. { &textRebootPrompt, 10 },
  87. { &textDone, 11 },
  88. { &textDisk, 12 },
  89. { &textPaddedMbCount, 13 },
  90. { &textInvalidSelection, 14 },
  91. { &textMaster, 15 },
  92. { &textYesNo, 16 },
  93. { &textMasterDiskCorrupt, 17 },
  94. { &textUsage, 18 },
  95. { &textMasterDiskFull, 19 },
  96. { &textRoomForNImages, 20 },
  97. { &textEnterImageFilename, 21 },
  98. { &textInvalidImageFile, 22 },
  99. { &textImageFileTooBig, 23 },
  100. { &textCantAccessImageFile, 24 },
  101. { &textTransferringFile, 25 },
  102. { &textCantOpenFile, 26 },
  103. { &textReadingListFromFile, 27 },
  104. { &textGeometryMismatch, 28 },
  105. { &textTooFragmented, 29 },
  106. { &textChecksum, 30 },
  107. { &textChecksumFail, 31 },
  108. { &textBytesProcessed, 32 },
  109. { &textChecksumOK, 33 },
  110. { &textTooManyPartitions, 34 },
  111. { &textFoundExistingPartitions, 35 },
  112. { &textExpandedImageFileTooBig,36 },
  113. { &textFreeSpaceNeedsToBeHere,37 }
  114. };
  115. BOOL
  116. DoIt(
  117. IN UINT DiskId
  118. );
  119. BOOL
  120. SetUpMasterDisk(
  121. IN HDISK DiskHandle,
  122. IN USHORT SectorCount,
  123. IN BOOL Init
  124. );
  125. BOOL
  126. TransferImages(
  127. IN HDISK DiskHandle
  128. );
  129. BOOL
  130. DetermineRelocations(
  131. IN UINT FileHandle,
  132. IN HDISK DiskHandle,
  133. IN ULONG ImageStartSector,
  134. IN ULONG ImageSectorCount,
  135. IN FPMASTER_DISK MasterDisk
  136. );
  137. BOOL
  138. NeedToRelocClusterBitmap(
  139. IN FPMASTER_DISK MasterDisk,
  140. IN OUT FPPARTITION_IMAGE PartitionImage,
  141. IN ULONG ImageStart,
  142. IN UINT FileHandle,
  143. IN OUT FPBYTE ClusterBuffer
  144. );
  145. BOOL
  146. NeedToRelocBootPart(
  147. IN FPMASTER_DISK MasterDisk,
  148. IN OUT FPPARTITION_IMAGE PartitionImage,
  149. IN UINT FileHandle,
  150. IN OUT FPBYTE ClusterBuffer
  151. );
  152. BOOL
  153. IsClusterRunFree(
  154. IN UINT FileHandle,
  155. IN FPPARTITION_IMAGE PartitionImage,
  156. IN ULONG StartCluster,
  157. IN ULONG ClusterCount,
  158. IN OUT FPBYTE ClusterBuffer,
  159. OUT BOOL *Free
  160. );
  161. BOOL
  162. IsRunGoodForRelocations(
  163. IN ULONG ImageStart,
  164. IN ULONG ImageLength,
  165. IN FPMASTER_DISK MasterDisk,
  166. IN OUT ULONG *RunStart,
  167. IN ULONG RunLength,
  168. IN ULONG SectorsNeeded
  169. );
  170. BOOL
  171. DetermineIfEisaPartitionExists(
  172. IN HDISK DiskHandle,
  173. IN VOID* IoBuffer,
  174. IN FPPARTITION_TABLE_ENTRY pPartitionTable
  175. );
  176. ULONG
  177. DetermineHighestSectOccupied(
  178. IN FPPARTITION_TABLE_ENTRY pPartitionTable,
  179. IN BYTE SectorsPerTrack,
  180. IN USHORT Heads
  181. );
  182. BOOL
  183. RestorePartitionTable(
  184. IN HDISK DiskHandle,
  185. IN VOID* IoBuffer,
  186. IN FPPARTITION_TABLE_ENTRY pPartitionTable
  187. );
  188. BYTE
  189. FindFirstUnusedEntry(
  190. IN FPPARTITION_TABLE_ENTRY pPartitionTable
  191. );
  192. BOOL
  193. IsUnknownPartition(
  194. BYTE SysId
  195. );
  196. int
  197. main(
  198. IN int argc,
  199. IN char *argv[]
  200. )
  201. {
  202. UINT DiskCount;
  203. UINT Selection;
  204. BOOL b;
  205. UINT u;
  206. BYTE Int13Unit;
  207. ULONG dontcare;
  208. if(!GetTextForProgram(argv[0],TextMessages,sizeof(TextMessages)/sizeof(TextMessages[0]))) {
  209. fprintf(stderr,"Unable to find messages for program\n");
  210. return(FAILURE);
  211. }
  212. if(!ParseArgs(argc,argv,TRUE,"DFIMQRXY",&CmdLineArgs)) {
  213. fprintf(stderr,textUsage);
  214. fprintf(stderr,"\n");
  215. return(FAILURE);
  216. }
  217. //
  218. // Initialize.
  219. //
  220. DiskCount = InitializeDiskList();
  221. if(!DiskCount) {
  222. fprintf(stderr,"%s\n",textNoDisks);
  223. return(FAILURE);
  224. }
  225. _Log("%u disks\n",DiskCount);
  226. //
  227. // We don't check return code because zero partitions
  228. // is a perfectly valid case.
  229. //
  230. InitializePartitionList();
  231. //
  232. // Allocate a maximally-sized i/o buffer
  233. //
  234. if(!AllocTrackBuffer(63,&IoBuffer,&UnalignedBuffer)) {
  235. fprintf(stderr,"%s\n",textOOM);
  236. return(FAILURE);
  237. }
  238. //
  239. // Select disk.
  240. //
  241. Selection = (UINT)(-1);
  242. if(CmdLineArgs.MasterDiskInt13Unit) {
  243. for(u=0; u<DiskCount; u++) {
  244. GetDiskInfoById(
  245. u,
  246. 0,
  247. &Int13Unit,
  248. (FPBYTE)&dontcare,
  249. (FPUSHORT)&dontcare,
  250. (FPUSHORT)&dontcare,
  251. &dontcare
  252. );
  253. if(Int13Unit == CmdLineArgs.MasterDiskInt13Unit) {
  254. Selection = u;
  255. break;
  256. }
  257. }
  258. }
  259. if(Selection == (UINT)(-1)) {
  260. Selection = SelectDisk(
  261. DiskCount,
  262. textSelectDiskPrompt,
  263. NULL,
  264. NULL,
  265. textDisk,
  266. textPaddedMbCount,
  267. textInvalidSelection,
  268. textMaster
  269. );
  270. }
  271. //
  272. // Do our thing.
  273. //
  274. printf("\n");
  275. if(b = DoIt(Selection)) {
  276. printf("\n%s\n",textDone);
  277. }
  278. return(b ? SUCCESS : FAILURE);
  279. }
  280. BOOL
  281. DoIt(
  282. IN UINT DiskId
  283. )
  284. {
  285. HDISK DiskHandle;
  286. BOOL Init;
  287. BOOL b;
  288. //
  289. // Determine whether this disk is already a master disk, and if so,
  290. // what to do about it.
  291. //
  292. // If selected disk is not a master disk, offer to make it one.
  293. // If selected disk is a master disk, offer to reinitialize it.
  294. //
  295. if(IsMasterDisk(DiskId,IoBuffer)) {
  296. _Log("Selected disk is already a master disk\n");
  297. if(CmdLineArgs.Quiet) {
  298. Init = CmdLineArgs.Reinit;
  299. } else {
  300. Init = ConfirmOperation(textSureWipeMaster,textYesNo[0],textYesNo[1]);
  301. }
  302. } else {
  303. _Log("Selected disk is not already a master disk\n");
  304. if(!CmdLineArgs.Quiet && !ConfirmOperation(textSureWipeDisk,textYesNo[0],textYesNo[1])) {
  305. return(TRUE);
  306. }
  307. Init = TRUE;
  308. }
  309. //
  310. // Open the disk.
  311. //
  312. DiskHandle = OpenDisk(DiskId);
  313. if(!DiskHandle) {
  314. fprintf(stderr,"%s\n",textCantOpenDisk);
  315. return(FALSE);
  316. }
  317. if(!SetUpMasterDisk(DiskHandle,BOOT_IMAGE_SIZE,Init)) {
  318. CloseDisk(DiskHandle);
  319. return(FALSE);
  320. }
  321. //
  322. // Now transfer images to the master disk.
  323. //
  324. b = TransferImages(DiskHandle);
  325. CloseDisk(DiskHandle);
  326. return(b);
  327. }
  328. BOOL
  329. SetUpMasterDisk(
  330. IN HDISK DiskHandle,
  331. IN USHORT SectorCount,
  332. IN BOOL Init
  333. )
  334. {
  335. PMASTER_DISK p;
  336. UINT PartId;
  337. UINT DiskId;
  338. BYTE SystemId;
  339. BYTE Unit;
  340. BYTE SectorsPerTrack;
  341. USHORT Heads;
  342. USHORT Cylinders;
  343. ULONG ExtendedSectorCount;
  344. ULONG StartSector;
  345. ULONG Count;
  346. // ULONG DontCare;
  347. BOOL bPreserveEisaPartition;
  348. PARTITION_TABLE_ENTRY PartitionTable[NUM_PARTITION_TABLE_ENTRIES];
  349. // there are a maxiumum of 4 entries in
  350. // the partition table.
  351. p = (FPMASTER_DISK)IoBuffer;
  352. //
  353. // First get some hardware values.
  354. //
  355. GetDiskInfoByHandle(
  356. DiskHandle,
  357. &Unit,
  358. &SectorsPerTrack,
  359. &Heads,
  360. (FPUSHORT)&Cylinders,
  361. &ExtendedSectorCount,
  362. &DiskId
  363. );
  364. //
  365. // We need to figure out if an eisa/hiber partition exists, and we need to
  366. // know the lowest possible cylinder we can write images to.
  367. //
  368. memset(PartitionTable, 0, sizeof(PARTITION_TABLE_ENTRY)*4);
  369. // note: DetermineIfEisaPartitionExists trashes the first 512 bytes of IoBuffer
  370. bPreserveEisaPartition = DetermineIfEisaPartitionExists(DiskHandle,IoBuffer,PartitionTable);
  371. if(bPreserveEisaPartition) {
  372. //
  373. // Save away the range of free cylinders.
  374. //
  375. FreeSpaceStart = DetermineHighestSectOccupied(PartitionTable,SectorsPerTrack,Heads);
  376. _Log("Existing unknown partitions found.\n");
  377. printf("%s\n",textFoundExistingPartitions);
  378. if( FindFirstUnusedEntry(PartitionTable) == -1 ) {
  379. printf("%s\n",textTooManyPartitions);
  380. return(FALSE);
  381. }
  382. } else {
  383. //
  384. // FreeSpaceStart is ignored if it is zero.
  385. //
  386. FreeSpaceStart = 0;
  387. }
  388. //
  389. // The assumption for now is that we don't support preserving partitions at the end of
  390. // the disk.
  391. //
  392. FreeSpaceEnd = ExtendedSectorCount;
  393. _Log("Free space starts sector %ld\n", FreeSpaceStart);
  394. _Log("Free space ends sector %ld\n", FreeSpaceEnd);
  395. if( FreeSpaceStart > FreeSpaceEnd ) {
  396. //
  397. // The logic that determines FreeSpaceStart assumes that all the existing partitions
  398. // on the disk are at the beginning of the disk and the free space is contiguous after
  399. // the last pre-existing unknown partition.
  400. //
  401. fprintf(stderr,textFreeSpaceNeedsToBeHere);
  402. fprintf(stderr,"\n");
  403. _Log(textFreeSpaceNeedsToBeHere);
  404. _Log("\n");
  405. return(FALSE);
  406. }
  407. //
  408. // Clear out the partition table and then create a new partition
  409. // of the requested size at the end of the disk.
  410. // We also slam in our boot code.
  411. //
  412. // Once we've done that, slam in our special data structure
  413. // on sector 1.
  414. //
  415. if(Init) {
  416. _Log("Initializing the disk... \n");
  417. if(ReinitializePartitionTable(DiskHandle,IoBuffer) == -1) {
  418. fprintf(stderr,"%s\n",textMbrIoFailed);
  419. return(FALSE);
  420. }
  421. PartId = MakePartitionAtEndOfEmptyDisk(DiskHandle,IoBuffer,SectorCount,TRUE);
  422. if(PartId != (UINT)(-1)) {
  423. GetPartitionInfoById(
  424. PartId,
  425. 0,
  426. &DiskId,
  427. &SystemId,
  428. &StartSector,
  429. &Count
  430. );
  431. } else {
  432. fprintf(stderr,"%s\n",textMbrIoFailed);
  433. return(FALSE);
  434. }
  435. if( bPreserveEisaPartition ) {
  436. //
  437. // We put the partitions we want to save back into the partition table.
  438. //
  439. if(!RestorePartitionTable(DiskHandle,IoBuffer,PartitionTable)) {
  440. return FALSE;
  441. }
  442. }
  443. memset(p,0,512);
  444. p->StartupPartitionStartSector = StartSector;
  445. p->StartupPartitionSectorCount = Count;
  446. p->Signature = MASTER_DISK_SIGNATURE;
  447. p->Size = sizeof(MASTER_DISK);
  448. p->FreeSpaceStart = FreeSpaceStart;
  449. p->FreeSpaceEnd = FreeSpaceEnd;
  450. } else {
  451. //
  452. // Reinitialize only selected fields
  453. //
  454. if(!ReadDisk(DiskHandle,1,1,p)) {
  455. fprintf(stderr,textDiskReadError,1L);
  456. fprintf(stderr,"\n");
  457. return(FALSE);
  458. }
  459. p->State = MDS_NONE;
  460. p->SelectedLanguage = 0;
  461. p->SelectionOrdinal = 0;
  462. p->ClusterBitmapStart = 0;
  463. p->NonClusterSectorsDone = 0;
  464. p->ForwardXferSectorCount = 0;
  465. p->ReverseXferSectorCount = 0;
  466. }
  467. //
  468. // Store away or validate the disk geometry.
  469. //
  470. if(!Init) {
  471. _Log("Checking disk geometry...\n");
  472. //
  473. // Validate that this matches the original geometry values
  474. //
  475. if((SectorsPerTrack != p->OriginalSectorsPerTrack)
  476. || (Heads != p->OriginalHeads)) {
  477. fprintf(stderr,"\n%s\n",textGeometryMismatch);
  478. }
  479. _Log("%d sectors per track, %d heads.\n", SectorsPerTrack, Heads);
  480. _Log("Master disk geometry matches values recorded in master disk.\n");
  481. } else {
  482. _Log("Setting disk geometry...\n");
  483. p->OriginalSectorsPerTrack = SectorsPerTrack;
  484. p->OriginalHeads = Heads;
  485. _Log("%d sectors per track, %d heads.\n", SectorsPerTrack, Heads);
  486. }
  487. //
  488. // Save it out to disk.
  489. //
  490. if(!WriteDisk(DiskHandle,1,1,p)) {
  491. fprintf(stderr,textDiskWriteError,1L);
  492. fprintf(stderr,"\n");
  493. return(FALSE);
  494. }
  495. //
  496. // Apply the boot image if specified.
  497. //
  498. if(CmdLineArgs.ImageFile) {
  499. if(!ApplyImage(DiskHandle,p->StartupPartitionStartSector,p->StartupPartitionSectorCount,SectorsPerTrack,Heads)) {
  500. return(FALSE);
  501. }
  502. printf("\n\n");
  503. }
  504. return(TRUE);
  505. }
  506. BOOL
  507. TransferImages(
  508. IN HDISK DiskHandle
  509. )
  510. {
  511. PPARTITION_IMAGE Images;
  512. FPMASTER_DISK MasterDisk;
  513. ULONG NextImageEnd;
  514. UINT u,Limit;
  515. UINT FileHandle;
  516. UINT Read;
  517. ULONG FileSize;
  518. ULONG Sector;
  519. UINT NewImages;
  520. FPCHAR Filenames;
  521. FPCHAR p;
  522. ULONG OriginalSize;
  523. FPBYTE New;
  524. FILE *FileList;
  525. BOOL b;
  526. //
  527. // Retrieve the master disk structure. Leave it in the last sector
  528. // of the i/o buffer.
  529. //
  530. if(!ReadDisk(DiskHandle,1,1,(FPBYTE)IoBuffer+(62*512))) {
  531. fprintf(stderr,textDiskReadError,1L);
  532. fprintf(stderr,"\n");
  533. return(FALSE);
  534. }
  535. MasterDisk = (FPVOID)((FPBYTE)IoBuffer+(62*512));
  536. //
  537. // Allocate a buffer for the image headers.
  538. //
  539. Images = malloc(MasterDisk->ImageCount * sizeof(PARTITION_IMAGE));
  540. if(!Images) {
  541. fprintf(stderr,"%s\n",textOOM);
  542. }
  543. //
  544. // Read each existing image's header.
  545. //
  546. NextImageEnd = MasterDisk->StartupPartitionStartSector;
  547. for(u=0; u<MasterDisk->ImageCount; u++) {
  548. if(!ReadDisk(DiskHandle,MasterDisk->ImageStartSector[u],1,IoBuffer)) {
  549. fprintf(stderr,textDiskReadError,MasterDisk->ImageStartSector[u]);
  550. fprintf(stderr,"\n");
  551. return(FALSE);
  552. }
  553. memmove(&Images[u],IoBuffer,sizeof(PARTITION_IMAGE));
  554. //
  555. // Sanity check
  556. //
  557. if((Images[u].Signature != PARTITION_IMAGE_SIGNATURE)
  558. || (Images[u].Size != sizeof(PARTITION_IMAGE))) {
  559. fprintf(stderr,textMasterDiskCorrupt,MasterDisk->ImageStartSector[u]);
  560. fprintf(stderr,"\n");
  561. return(FALSE);
  562. }
  563. NextImageEnd = MasterDisk->ImageStartSector[u];
  564. }
  565. //
  566. // Make sure there's room for new images.
  567. //
  568. if(MasterDisk->ImageCount >= MAX_PARTITION_IMAGES) {
  569. fprintf(stderr,textMasterDiskFull,MasterDisk->ImageCount);
  570. fprintf(stderr,"\n");
  571. return(FALSE);
  572. } else {
  573. //
  574. // Prompt the user for partition image filenames.
  575. //
  576. // Open and validate each file, and make sure there's room on the disk
  577. // for the image. We don't leave the files open since under DOS
  578. // we might run out of file handles, and we don't want to transfer
  579. // the data now (it could take a long time and we want to let the user
  580. // go get a cup of coffee or something). Actual data transfer
  581. // takes place in a separate loop.
  582. //
  583. // We leave 1 track + 128 sectors free at the start of the disk.
  584. // The track is for the MBR and the other is used for transfers where
  585. // the max transfer size is for one 64K cluster (we ensure that
  586. // no transfer's write range overlaps its read). Because we're not
  587. // totally confident that the geometry we've got now is the one that
  588. // will be in effect on the end-user's machine, we maximize
  589. // the track size.
  590. //
  591. Filenames = malloc(0);
  592. if(!Filenames) {
  593. fprintf(stderr,"%s\n",textOOM);
  594. return(FALSE);
  595. }
  596. p = Filenames;
  597. Limit = MAX_PARTITION_IMAGES - MasterDisk->ImageCount;
  598. NewImages = 0;
  599. printf(textRoomForNImages,Limit);
  600. printf("\n");
  601. if(CmdLineArgs.FileListFile) {
  602. FileList = fopen(CmdLineArgs.FileListFile,"rt");
  603. if(!FileList) {
  604. fprintf(stderr,textCantOpenFile,CmdLineArgs.FileListFile);
  605. fprintf(stderr,"\n");
  606. return(FALSE);
  607. }
  608. printf(textReadingListFromFile,CmdLineArgs.FileListFile);
  609. printf("\n");
  610. }
  611. for(u=0; u<Limit; u++) {
  612. prompt:
  613. if(CmdLineArgs.FileListFile) {
  614. if(fgets((FPBYTE)IoBuffer+512,256,FileList)) {
  615. //
  616. // Strip trailing spaces and newline
  617. //
  618. Read = strlen((FPBYTE)IoBuffer+512);
  619. while(Read
  620. && ( (((FPBYTE)IoBuffer+512)[Read-1] == '\n')
  621. || (((FPBYTE)IoBuffer+512)[Read-1] == ' ')
  622. || (((FPBYTE)IoBuffer+512)[Read-1] == '\t'))) {
  623. ((FPBYTE)IoBuffer+512)[--Read] = 0;
  624. }
  625. if(*((FPBYTE)IoBuffer+512)) {
  626. printf(" %s\n",(FPBYTE)IoBuffer+512);
  627. }
  628. } else {
  629. //
  630. // Force us to bust out of the filename read loop
  631. //
  632. *((FPBYTE)IoBuffer+512) = 0;
  633. }
  634. } else {
  635. printf(textEnterImageFilename,u+1);
  636. printf(" ");
  637. gets((FPBYTE)IoBuffer+512);
  638. }
  639. if(*((FPBYTE)IoBuffer+512)) {
  640. if(_dos_open((FPBYTE)IoBuffer+512,SH_DENYWR,&FileHandle)) {
  641. printf("%s\n",textInvalidImageFile);
  642. goto prompt;
  643. }
  644. if(_dos_read(FileHandle,IoBuffer,512,&Read)
  645. || (Read != 512)
  646. || ((FileSize = DosSeek(FileHandle,0,DOSSEEK_END)) == (ULONG)(-1))
  647. || (FileSize % 512)
  648. || (((FPPARTITION_IMAGE)IoBuffer)->Signature != PARTITION_IMAGE_SIGNATURE)
  649. || (((FPPARTITION_IMAGE)IoBuffer)->Size != sizeof(PARTITION_IMAGE))) {
  650. _dos_close(FileHandle);
  651. printf("%s\n",textInvalidImageFile);
  652. goto prompt;
  653. }
  654. FileSize /= 512;
  655. //
  656. // BUGBUG we should reserve at least 32MB worth of sectors to prevent
  657. // overlapping with the expanded FAT table in the Fat32 case.
  658. //
  659. // As well, we need to have the capability to preserve a hiber partition.
  660. // FreeSpaceStart describes how many sectors we need to leave at the
  661. // beginning of the disk to avoid stomping on such a partition.
  662. //
  663. // FreeSpaceStart was determined in SetupMasterDisk()
  664. //
  665. #define RESERVE (63+128+FAT32_SPACE_TO_LEAVE)
  666. if((NextImageEnd - RESERVE - FreeSpaceStart) < FileSize) {
  667. _dos_close(FileHandle);
  668. fprintf(stderr,textImageFileTooBig,FileSize,NextImageEnd-RESERVE);
  669. fprintf(stderr,"\n");
  670. goto prompt;
  671. }
  672. //
  673. // Now check that the disk is at least big enough to contain the real size
  674. // of the image.
  675. //
  676. if( FreeSpaceEnd - FreeSpaceStart < ((FPPARTITION_IMAGE)IoBuffer)->TotalSectorCount ) {
  677. _dos_close(FileHandle);
  678. fprintf(stderr,textExpandedImageFileTooBig,
  679. ((FPPARTITION_IMAGE)IoBuffer)->TotalSectorCount,
  680. FreeSpaceEnd - FreeSpaceStart);
  681. fprintf(stderr,"\n");
  682. _Log(textExpandedImageFileTooBig,
  683. ((FPPARTITION_IMAGE)IoBuffer)->TotalSectorCount,
  684. FreeSpaceEnd - FreeSpaceStart);
  685. _Log("\n");
  686. goto prompt;
  687. }
  688. //
  689. // It's OK. Remember the filename.
  690. //
  691. New = realloc(Filenames,(p - Filenames) + strlen((FPBYTE)IoBuffer+512) + 1);
  692. if(!New) {
  693. fprintf(stderr,"%s\n",textOOM);
  694. return(FALSE);
  695. }
  696. p += New - Filenames;
  697. Filenames = New;
  698. strcpy(p,(FPBYTE)IoBuffer+512);
  699. p += strlen(p)+1;
  700. MasterDisk->ImageStartSector[MasterDisk->ImageCount+u] = NextImageEnd - FileSize;
  701. NextImageEnd -= FileSize;
  702. NewImages++;
  703. } else {
  704. break;
  705. }
  706. }
  707. }
  708. //
  709. // Now transfer the data for new images.
  710. //
  711. printf("\n");
  712. for(p=Filenames,u=0; u<NewImages; u++,p+=strlen(p)+1) {
  713. printf(textTransferringFile,p,0);
  714. printf("\r");
  715. _Log("\nProcessing image %s...\n",p);
  716. if(_dos_open(p,SH_DENYWR,&FileHandle)) {
  717. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  718. return(FALSE);
  719. }
  720. CheckSum = CRC32_INITIAL_VALUE;
  721. BytesCRC = 0;
  722. if((FileSize = DosSeek(FileHandle,0,DOSSEEK_END)) == (ULONG)(-1)) {
  723. _dos_close(FileHandle);
  724. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  725. return(FALSE);
  726. }
  727. FileSize /= 512;
  728. OriginalSize = FileSize;
  729. Sector = MasterDisk->ImageStartSector[MasterDisk->ImageCount+u];
  730. b = DetermineRelocations(
  731. FileHandle,
  732. DiskHandle,
  733. Sector,
  734. FileSize,
  735. MasterDisk
  736. );
  737. if(!b) {
  738. _dos_close(FileHandle);
  739. return(FALSE);
  740. }
  741. FileSize--;
  742. Sector++;
  743. while(FileSize) {
  744. Limit = (FileSize > 62L) ? 62 : (UINT)FileSize;
  745. if(_dos_read(FileHandle,IoBuffer,Limit*512,&Read) || (Read != (Limit*512))) {
  746. _dos_close(FileHandle);
  747. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  748. return(FALSE);
  749. }
  750. CheckSum = CRC32Compute( IoBuffer, Limit*512, CheckSum);
  751. BytesCRC += Limit*512;
  752. if(!WriteDisk(DiskHandle,Sector,(BYTE)Limit,IoBuffer)) {
  753. _dos_close(FileHandle);
  754. fprintf(stderr,"\n");
  755. fprintf(stderr,textDiskWriteError,Sector);
  756. fprintf(stderr,"\n");
  757. return(FALSE);
  758. }
  759. FileSize -= Limit;
  760. Sector += Limit;
  761. printf(textTransferringFile,p,100*(OriginalSize-FileSize)/OriginalSize);
  762. printf("\r");
  763. }
  764. _dos_close(FileHandle);
  765. printf(textChecksum, p, CheckSum );
  766. _Log(textChecksum, p, CheckSum );
  767. _Log("\n");
  768. printf("\n");
  769. printf( textBytesProcessed,BytesCRC );
  770. _Log( textBytesProcessed,BytesCRC );
  771. _Log("\n");
  772. printf("\n");
  773. if( CheckSum != ImageCheckSum ) {
  774. printf(textChecksumFail,ImageCheckSum);
  775. _Log(textChecksumFail,ImageCheckSum);
  776. } else {
  777. printf(textChecksumOK);
  778. _Log(textChecksumOK);
  779. }
  780. printf("\n");
  781. _Log("\n");
  782. }
  783. MasterDisk->ImageCount += NewImages;
  784. if(!WriteDisk(DiskHandle,1,1,(FPBYTE)IoBuffer+(62*512))) {
  785. fprintf(stderr,textDiskWriteError,1L);
  786. fprintf(stderr,"\n");
  787. return(FALSE);
  788. }
  789. free(Filenames);
  790. free(Images);
  791. return(TRUE);
  792. }
  793. BYTE BitValue[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
  794. BOOL
  795. DetermineRelocations(
  796. IN UINT FileHandle,
  797. IN HDISK DiskHandle,
  798. IN ULONG ImageStartSector,
  799. IN ULONG ImageSectorCount,
  800. IN FPMASTER_DISK MasterDisk
  801. )
  802. /*++
  803. Routine Description:
  804. This routine determines where there is unused space in the volume
  805. being imaged that will allow relocation of the cluster bitmap
  806. and the mpk boot partition somewhere on the disk.
  807. Arguments:
  808. Return Value:
  809. --*/
  810. {
  811. UINT Read;
  812. FPPARTITION_IMAGE p;
  813. FPBYTE ClusterBuffer;
  814. ULONG SectorsNeeded;
  815. ULONG Count;
  816. ULONG Cluster;
  817. ULONG Base;
  818. BOOL On;
  819. BOOL InRun;
  820. ULONG Start;
  821. BOOL b;
  822. //
  823. // Set up pointers.
  824. //
  825. p = IoBuffer;
  826. ClusterBuffer = (FPBYTE)IoBuffer + 512;
  827. //
  828. // Read the partition image header from the file.
  829. //
  830. if(DosSeek(FileHandle,0,DOSSEEK_START)) {
  831. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  832. return(FALSE);
  833. }
  834. if(_dos_read(FileHandle,p,512,&Read) || (Read != 512)) {
  835. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  836. return(FALSE);
  837. }
  838. //
  839. // Calculate the checksum of the header.
  840. //
  841. ImageCheckSum = ((PPARTITION_IMAGE)p)->CRC;
  842. ((PPARTITION_IMAGE)p)->CRC = 0;
  843. CheckSum = CRC32Compute( (FPBYTE)p, 512, CheckSum);
  844. BytesCRC += 512;
  845. ((PPARTITION_IMAGE)p)->CRC = ImageCheckSum;
  846. //
  847. // determine whether this is a FAT32 image
  848. //
  849. if(DosSeek(FileHandle,512,DOSSEEK_START) == (ULONG)(-1)) {
  850. _dos_close(FileHandle);
  851. printf("%s\n",textInvalidImageFile);
  852. return FALSE;
  853. }
  854. if( _dos_read(FileHandle,ClusterBuffer,512,&Read)
  855. || (Read != 512) )
  856. {
  857. _dos_close(FileHandle);
  858. printf("%s\n",textInvalidImageFile);
  859. return FALSE;
  860. }
  861. if( IsFat32(ClusterBuffer) ) {
  862. Fat32ResizeMaxOffset = FAT32_SPACE_TO_LEAVE;
  863. _Log("The image is a FAT32 volume, setting up resizing...\n\n");
  864. } else {
  865. // we don't support resizing
  866. Fat32ResizeMaxOffset = 0;
  867. _Log("The image is not a FAT32 volume, resizing disabled...\n\n");
  868. }
  869. //
  870. // Determine whether the cluster bitmap will need to be relocated
  871. // and whether the boot partition will need to be relocated.
  872. // Track how many contiguous sectors are needed to relocate
  873. // the stuff we need to relocate. If we don't need to relocate
  874. // anything, we're done.
  875. //
  876. p->Flags &= ~(PARTIMAGE_RELOCATE_BITMAP | PARTIMAGE_RELOCATE_BOOT);
  877. p->BitmapRelocationStart = 0;
  878. p->BootRelocationStart = 0;
  879. SectorsNeeded = 0;
  880. if(!NeedToRelocClusterBitmap(MasterDisk,p,ImageStartSector,FileHandle,ClusterBuffer)) {
  881. return(FALSE);
  882. }
  883. if(p->Flags & PARTIMAGE_RELOCATE_BITMAP) {
  884. SectorsNeeded += (p->LastUsedCluster/(8*512)) + 1;
  885. _Log("Need to relocate bitmap\n");
  886. }
  887. if(!NeedToRelocBootPart(MasterDisk,p,FileHandle,ClusterBuffer)) {
  888. return(FALSE);
  889. }
  890. if(p->Flags & PARTIMAGE_RELOCATE_BOOT) {
  891. SectorsNeeded += MasterDisk->StartupPartitionSectorCount;
  892. _Log("Need to relocate boot\n");
  893. }
  894. if( p->Flags & PARTIMAGE_RELOCATE_BOOT || p->Flags & PARTIMAGE_RELOCATE_BITMAP ) {
  895. SectorsNeeded += Fat32ResizeMaxOffset;
  896. _Log("Need to add maximum possible %ld sectors to compensate for FAT32 fat growth.\n", Fat32ResizeMaxOffset);
  897. }
  898. if(SectorsNeeded) {
  899. _Log("0x%lx sectors needed for relocation\n",SectorsNeeded);
  900. b = FALSE;
  901. //
  902. // Seek the input file to the beginning of the cluster bitmap.
  903. //
  904. Start = (1 + p->NonClusterSectors + (p->SectorsPerCluster * p->UsedClusterCount)) * 512;
  905. if(DosSeek(FileHandle,Start,DOSSEEK_START) != Start) {
  906. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  907. return(FALSE);
  908. }
  909. Count = 0;
  910. for(Cluster=0; Cluster <= p->LastUsedCluster; Cluster++,Base++) {
  911. //
  912. // Reload the cluster buffer if necessary.
  913. //
  914. if(!(Cluster % (512*8))) {
  915. if(_dos_read(FileHandle,ClusterBuffer,512,&Read) || (Read != 512)) {
  916. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  917. return(FALSE);
  918. }
  919. Base = 0;
  920. }
  921. On = (ClusterBuffer[Base/8] & BitValue[Base%8]) ? TRUE : FALSE;
  922. //
  923. // Do something special before we examine the first cluster's bit,
  924. // to force a state transition.
  925. //
  926. if(!Cluster) {
  927. InRun = !On;
  928. }
  929. if(On == InRun) {
  930. //
  931. // Used/unused state didn't change. If we're not in a used run,
  932. // keep track of the size.
  933. //
  934. if(!On) {
  935. Count += p->SectorsPerCluster;
  936. }
  937. } else {
  938. if(On) {
  939. //
  940. // First 1 bit in a used run. The current free run is now
  941. // exhausted, so examine it.
  942. //
  943. if(Count) {
  944. b = IsRunGoodForRelocations(
  945. ImageStartSector,
  946. ImageSectorCount,
  947. MasterDisk,
  948. &Start,
  949. Count,
  950. SectorsNeeded
  951. );
  952. if(b) {
  953. //
  954. // for FAT32 Fat32ResizeMaxOffset will be != 0
  955. // this lets us offset the relocation to account
  956. // for possible FAT expansion.
  957. //
  958. // If there is an EISA/hiber partition, we need to
  959. // offset the start of the relocation by FreeSpaceStart,
  960. // otherwise we might get stomped when we're restoring
  961. // the partition image.
  962. //
  963. Start = Start + Fat32ResizeMaxOffset + FreeSpaceStart;
  964. if(p->Flags & PARTIMAGE_RELOCATE_BOOT) {
  965. _Log("Boot will be relocated to 0x%lx\n",Start);
  966. p->BootRelocationStart = Start;
  967. Start += MasterDisk->StartupPartitionSectorCount;
  968. }
  969. if(p->Flags & PARTIMAGE_RELOCATE_BITMAP) {
  970. _Log("Bitmap will be relocated to 0x%lx\n",Start);
  971. p->BitmapRelocationStart = Start;
  972. }
  973. break;
  974. }
  975. }
  976. } else {
  977. //
  978. // First 0 bit in an unused run.
  979. //
  980. Count = p->SectorsPerCluster;
  981. Start = (ULONG)(MasterDisk->OriginalSectorsPerTrack) + p->NonClusterSectors
  982. + (Cluster * p->SectorsPerCluster);
  983. }
  984. InRun = On;
  985. }
  986. }
  987. } else {
  988. b = TRUE;
  989. }
  990. if(b) {
  991. //
  992. // Restore the file pointer to just after the partition image
  993. // header sector.
  994. //
  995. if(DosSeek(FileHandle,512,DOSSEEK_START) != 512) {
  996. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  997. return(FALSE);
  998. }
  999. //
  1000. // Write out the partition image header.
  1001. //
  1002. if(!WriteDisk(DiskHandle,ImageStartSector,1,p)) {
  1003. fprintf(stderr,"\n");
  1004. fprintf(stderr,textDiskWriteError,ImageStartSector);
  1005. fprintf(stderr,"\n");
  1006. return(FALSE);
  1007. }
  1008. } else {
  1009. fprintf(stderr,"\n%s\n",textTooFragmented);
  1010. }
  1011. return(b);
  1012. }
  1013. BOOL
  1014. NeedToRelocClusterBitmap(
  1015. IN FPMASTER_DISK MasterDisk,
  1016. IN OUT FPPARTITION_IMAGE PartitionImage,
  1017. IN ULONG ImageStart,
  1018. IN UINT FileHandle,
  1019. IN OUT FPBYTE ClusterBuffer
  1020. )
  1021. {
  1022. ULONG ClusterBitmapStart;
  1023. ULONG ClusterBitmapSize;
  1024. ULONG Cluster0Sector;
  1025. ULONG FirstUnused;
  1026. ULONG FirstCluster;
  1027. ULONG LastCluster;
  1028. ULONG NeededClusters;
  1029. BOOL b;
  1030. //
  1031. // Figure out where the cluster bitmap starts on-disk and
  1032. // how many sectors it occupies. We offset the start by
  1033. // Fat32ResizeMaxOffset sectors at the front of the allocation
  1034. // in order to anticipate FAT expansion.
  1035. //
  1036. // Fat32ResizeMaxOffset will be zero for a non-FAT32 image and
  1037. // will have no effect in that case.
  1038. //
  1039. ClusterBitmapStart = ImageStart
  1040. + 1
  1041. + PartitionImage->NonClusterSectors
  1042. + (PartitionImage->UsedClusterCount * PartitionImage->SectorsPerCluster)
  1043. - Fat32ResizeMaxOffset;
  1044. ClusterBitmapSize = (PartitionImage->LastUsedCluster/(8*512)) + 1 + Fat32ResizeMaxOffset;
  1045. _Log("On-disk cluster bitmap start/size = 0x%lx/0x%lx\n",ClusterBitmapStart,ClusterBitmapSize);
  1046. //
  1047. // Calculate the first physical sector corresponding to cluster 0
  1048. // in the restored volume, and the first sector past the last
  1049. // used cluster in the restored volume.
  1050. //
  1051. Cluster0Sector = MasterDisk->OriginalSectorsPerTrack + PartitionImage->NonClusterSectors + FreeSpaceStart;
  1052. FirstUnused = Cluster0Sector + ((PartitionImage->LastUsedCluster+1) * PartitionImage->SectorsPerCluster);
  1053. _Log("Volume cluster 0 sector = 0x%lx\n",Cluster0Sector);
  1054. _Log("Volume first unused sector = 0x%lx\n",FirstUnused);
  1055. //
  1056. // If the cluster bitmap overlaps or could potentially overlap
  1057. // with the area on the disk where the non-cluster data will get
  1058. // restored, then it must be relocated.
  1059. //
  1060. if(ClusterBitmapStart < Cluster0Sector ) {
  1061. _Log("Cluster bitmap is in volume non-cluster data\n");
  1062. PartitionImage->Flags |= PARTIMAGE_RELOCATE_BITMAP;
  1063. return(TRUE);
  1064. }
  1065. //
  1066. // If the cluster bitmap is in space we know for sure is free, then
  1067. // it does not need to be relocated.
  1068. //
  1069. // If we are preserving an EISA/hiber partition, we need to adjust
  1070. // by FreeSpaceStart sectors.
  1071. //
  1072. if(ClusterBitmapStart >= FirstUnused) {
  1073. _Log("Cluster bitmap is past end of used space in volume\n");
  1074. return(TRUE);
  1075. }
  1076. //
  1077. // Figure out which clusters in the restored volume are occupied by the
  1078. // on-disk cluster bitmap.
  1079. //
  1080. FirstCluster = (ClusterBitmapStart - Cluster0Sector)
  1081. / PartitionImage->SectorsPerCluster;
  1082. LastCluster = (((ClusterBitmapStart + ClusterBitmapSize) - 1) - Cluster0Sector)
  1083. / PartitionImage->SectorsPerCluster;
  1084. _Log("First/last clusters used by cluster bitmap: 0x%lx/0x%lx\n",FirstCluster,LastCluster);
  1085. if(LastCluster > PartitionImage->LastUsedCluster) {
  1086. LastCluster = PartitionImage->LastUsedCluster;
  1087. _Log("(last cluster adjusted to 0x%lx)\n",LastCluster);
  1088. }
  1089. NeededClusters = (LastCluster - FirstCluster) + 1;
  1090. _Log("Need 0x%lx clusters free in volume to encompass cluster bitmap\n",NeededClusters);
  1091. //
  1092. // Determine whether these clusters are free in the volume
  1093. //
  1094. if(!IsClusterRunFree(FileHandle,PartitionImage,FirstCluster,NeededClusters,ClusterBuffer,&b)) {
  1095. return(FALSE);
  1096. }
  1097. if(b) {
  1098. _Log("Needed clusters for bitmap are free\n");
  1099. } else {
  1100. _Log("Needed clusters for bitmap are not free\n");
  1101. PartitionImage->Flags |= PARTIMAGE_RELOCATE_BITMAP;
  1102. }
  1103. return(TRUE);
  1104. }
  1105. BOOL
  1106. NeedToRelocBootPart(
  1107. IN FPMASTER_DISK MasterDisk,
  1108. IN OUT FPPARTITION_IMAGE PartitionImage,
  1109. IN UINT FileHandle,
  1110. IN OUT FPBYTE ClusterBuffer
  1111. )
  1112. {
  1113. ULONG Cluster0Sector;
  1114. ULONG FirstUnused;
  1115. ULONG FirstCluster;
  1116. ULONG LastCluster;
  1117. ULONG NeededClusters;
  1118. ULONG StartupPartitionStartSector;
  1119. ULONG StartupPartitionSectorCount;
  1120. BOOL b;
  1121. //
  1122. // Calculate the first physical sector corresponding to cluster 0
  1123. // in the restored volume, and the first physical sector past the last
  1124. // used cluster in the restored volume.
  1125. //
  1126. Cluster0Sector = MasterDisk->OriginalSectorsPerTrack + PartitionImage->NonClusterSectors + FreeSpaceStart;
  1127. FirstUnused = Cluster0Sector + ((PartitionImage->LastUsedCluster+1) * PartitionImage->SectorsPerCluster);
  1128. _Log("Volume cluster 0 sector = 0x%lx\n",Cluster0Sector);
  1129. _Log("Volume first unused sector = 0x%lx\n",FirstUnused);
  1130. //
  1131. // If the boot partition is in space we know for sure is free, then
  1132. // it does not need to be relocated.
  1133. //
  1134. // We offset the start of the MPK boot partition by Fat32ResizeMaxOffset
  1135. // sectors at the front of the allocation in order to anticipate FAT expansion.
  1136. //
  1137. // Fat32ResizeMaxOffset will be zero for a non-FAT32 image and
  1138. // will have no effect in that case.
  1139. //
  1140. StartupPartitionStartSector = MasterDisk->StartupPartitionStartSector - Fat32ResizeMaxOffset;
  1141. StartupPartitionSectorCount = MasterDisk->StartupPartitionSectorCount + Fat32ResizeMaxOffset;
  1142. if(StartupPartitionStartSector >= FirstUnused) {
  1143. _Log("Boot partition is past end of used space in volume\n");
  1144. return(TRUE);
  1145. }
  1146. //
  1147. // Figure out which clusters in the restored volume are occupied by the
  1148. // boot partition.
  1149. //
  1150. FirstCluster = (StartupPartitionStartSector - Cluster0Sector)
  1151. / PartitionImage->SectorsPerCluster;
  1152. LastCluster = (((StartupPartitionStartSector + StartupPartitionSectorCount) - 1) - Cluster0Sector)
  1153. / PartitionImage->SectorsPerCluster;
  1154. _Log("First/last clusters used by boot partition: 0x%lx/0x%lx\n",FirstCluster,LastCluster);
  1155. if(LastCluster > PartitionImage->LastUsedCluster) {
  1156. LastCluster = PartitionImage->LastUsedCluster;
  1157. _Log("(last cluster adjusted to 0x%lx)\n",LastCluster);
  1158. }
  1159. NeededClusters = (LastCluster - FirstCluster) + 1;
  1160. _Log("Need 0x%lx clusters free in volume to encompass boot partition.\n",NeededClusters);
  1161. //
  1162. // Determine whether these clusters are free in the volume
  1163. //
  1164. if(!IsClusterRunFree(FileHandle,PartitionImage,FirstCluster,NeededClusters,ClusterBuffer,&b)) {
  1165. return(FALSE);
  1166. }
  1167. if(b) {
  1168. _Log("Needed clusters for boot partition are free\n");
  1169. } else {
  1170. _Log("Needed clusters for boot partition are not free\n");
  1171. PartitionImage->Flags |= PARTIMAGE_RELOCATE_BOOT;
  1172. }
  1173. return(TRUE);
  1174. }
  1175. BOOL
  1176. IsClusterRunFree(
  1177. IN UINT FileHandle,
  1178. IN FPPARTITION_IMAGE PartitionImage,
  1179. IN ULONG StartCluster,
  1180. IN ULONG ClusterCount,
  1181. IN OUT FPBYTE ClusterBuffer,
  1182. OUT BOOL *Free
  1183. )
  1184. {
  1185. ULONG Count;
  1186. UINT Bit;
  1187. ULONG Offset;
  1188. UINT Read;
  1189. *Free = FALSE;
  1190. _Log(" Checking if cluster run is free: start 0x%lx, length 0x%lx\n",StartCluster,ClusterCount);
  1191. //
  1192. // Calculate the offset in the file to the sector of the
  1193. // cluster bitmap continaing the entry for the start cluster.
  1194. //
  1195. Offset = 1 + PartitionImage->NonClusterSectors
  1196. + (PartitionImage->UsedClusterCount * PartitionImage->SectorsPerCluster);
  1197. Offset += StartCluster / (8*512);
  1198. _Log(" Offset in image file to cluster bitmap = 0x%lx sectors\n",Offset);
  1199. Offset *= 512;
  1200. if(DosSeek(FileHandle,Offset,DOSSEEK_START) != Offset) {
  1201. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  1202. return(FALSE);
  1203. }
  1204. if(_dos_read(FileHandle,ClusterBuffer,512,&Read) || (Read != 512)) {
  1205. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  1206. return(FALSE);
  1207. }
  1208. Offset = (StartCluster % (8*512)) / 8;
  1209. Bit = (UINT)(StartCluster % 8);
  1210. Count = 0;
  1211. _Log(" Start byte/bit in cluster buffer: %u/%u\n",Offset,Bit);
  1212. while((StartCluster < PartitionImage->LastUsedCluster) && !(ClusterBuffer[Offset] & BitValue[Bit])) {
  1213. if(++Count == ClusterCount) {
  1214. _Log(" Range is free\n");
  1215. *Free = TRUE;
  1216. return(TRUE);
  1217. }
  1218. StartCluster++;
  1219. Bit++;
  1220. if(Bit == 8) {
  1221. Bit = 0;
  1222. Offset++;
  1223. if((Offset == 512) && (StartCluster < PartitionImage->LastUsedCluster)) {
  1224. if(_dos_read(FileHandle,ClusterBuffer,512,&Read) || (Read != 512)) {
  1225. fprintf(stderr,"\n%s\n",textCantAccessImageFile);
  1226. return(FALSE);
  1227. }
  1228. Offset = 0;
  1229. }
  1230. }
  1231. }
  1232. _Log(" Range is not free\n");
  1233. return(TRUE);
  1234. }
  1235. BOOL
  1236. IsRunGoodForRelocations(
  1237. IN ULONG ImageStart,
  1238. IN ULONG ImageLength,
  1239. IN FPMASTER_DISK MasterDisk,
  1240. IN OUT ULONG *RunStart,
  1241. IN ULONG RunLength,
  1242. IN ULONG SectorsNeeded
  1243. )
  1244. {
  1245. ULONG RunEnd;
  1246. ULONG ImageEnd;
  1247. _Log(" Check if run is ok for reloc, run start = 0x%lx, len = 0x%lx\n",*RunStart,RunLength);
  1248. //
  1249. // Firstly, the run has to be large enough.
  1250. //
  1251. if(RunLength < SectorsNeeded) {
  1252. _Log(" Run is too small\n");
  1253. return(FALSE);
  1254. }
  1255. _Log(" Image start = 0x%lx, length = 0x%lx\n",ImageStart,ImageLength);
  1256. _Log(" Boot start = 0x%lx, length = 0x%lx\n",MasterDisk->StartupPartitionStartSector,MasterDisk->StartupPartitionSectorCount);
  1257. //
  1258. // Secondly, the run must not overlap the on-disk image.
  1259. //
  1260. if((*RunStart + SectorsNeeded) > ImageStart) {
  1261. //
  1262. // There's not enough space at the start of the run.
  1263. // We need to see whether there's enough space at the end.
  1264. //
  1265. _Log(" Not enough space at head of run\n");
  1266. RunEnd = *RunStart + RunLength;
  1267. ImageEnd = ImageStart + ImageLength;
  1268. if((RunEnd - SectorsNeeded) < ImageEnd) {
  1269. //
  1270. // Not enough space at the end either.
  1271. //
  1272. _Log(" Not enough space at end either\n");
  1273. return(FALSE);
  1274. }
  1275. //
  1276. // There could be enough space at the end of the run.
  1277. // Adjust the run parameters in preparation for checking for
  1278. // overlap with the boot partition.
  1279. //
  1280. if(*RunStart < ImageEnd) {
  1281. _Log(" Run starts inside image, adjusting run start\n");
  1282. *RunStart = ImageEnd;
  1283. } else {
  1284. _Log(" Run is entirely past end of image\n");
  1285. }
  1286. //
  1287. // Note: we don't check for the case where the run is somehow
  1288. // further out on the disk than the bootup partition. We assume
  1289. // the start of the boot partition is a magic boundary.
  1290. //
  1291. if((*RunStart + SectorsNeeded) <= MasterDisk->StartupPartitionStartSector) {
  1292. _Log(" Run is acceptable\n");
  1293. return(TRUE);
  1294. } else {
  1295. _Log(" Run overlaps boot partition\n");
  1296. return(FALSE);
  1297. }
  1298. } else {
  1299. //
  1300. // There's enough space at the start of the run.
  1301. // We assume that the image is nearer to the start of the disk
  1302. // than than the boot partition is, so in this case we don't
  1303. // need to check anything else, we're done.
  1304. //
  1305. _Log(" There's enough space at head of run\n");
  1306. return(TRUE);
  1307. }
  1308. }
  1309. BOOL
  1310. DetermineIfEisaPartitionExists(
  1311. IN HDISK DiskHandle,
  1312. IN VOID* IoBuffer,
  1313. IN FPPARTITION_TABLE_ENTRY pPartitionTable
  1314. )
  1315. {
  1316. UCHAR i;
  1317. BOOL found;
  1318. //
  1319. // Suck in the MBR
  1320. //
  1321. if(!ReadDisk(DiskHandle,0,1,IoBuffer)) {
  1322. fprintf(stderr,textDiskReadError,0);
  1323. fprintf(stderr,"\n");
  1324. return(FALSE);
  1325. }
  1326. //
  1327. // Validate that it is a good MBR.
  1328. //
  1329. if( ((FPMBR)IoBuffer)->AA55Signature != BOOT_RECORD_SIGNATURE ) {
  1330. fprintf(stderr,textDiskReadError,0);
  1331. _Log(" WARNING: The MBR was invalid!");
  1332. return FALSE;
  1333. }
  1334. //
  1335. // Save away the partition table into the buffer we were passed.
  1336. //
  1337. memcpy(pPartitionTable,
  1338. ((FPMBR)IoBuffer)->PartitionTable,
  1339. sizeof(PARTITION_TABLE_ENTRY) * NUM_PARTITION_TABLE_ENTRIES);
  1340. //
  1341. // Now walk the entries, looking for non-recognized partition types.
  1342. // We assume these are EISA or hiber partitions.
  1343. //
  1344. found = FALSE;
  1345. for( i=0; i<NUM_PARTITION_TABLE_ENTRIES;i++ ) {
  1346. if( IsUnknownPartition(pPartitionTable[i].SysId) ) {
  1347. //
  1348. // Non-recognized, keep it.
  1349. //
  1350. found = TRUE;
  1351. } else {
  1352. //
  1353. // nuke the partition
  1354. //
  1355. memset( &(pPartitionTable[i]), 0, sizeof(PARTITION_TABLE_ENTRY) );
  1356. }
  1357. }
  1358. //
  1359. // If these exist, return true. Otherwise return false.
  1360. //
  1361. return found;
  1362. }
  1363. ULONG
  1364. DetermineHighestSectOccupied(
  1365. IN FPPARTITION_TABLE_ENTRY pPartitionTable,
  1366. IN BYTE SectorsPerTrack,
  1367. IN USHORT Heads
  1368. )
  1369. {
  1370. UINT i;
  1371. ULONG OccupiedSect;
  1372. ULONG tempSect;
  1373. //
  1374. // Walk the partition table, look for the highest used cylinder.
  1375. // Since this is called to preserve EISA or hiber partitions, we
  1376. // can assume they reside at the beginning of the disk.
  1377. //
  1378. OccupiedSect = 0;
  1379. _Log("Determining highest occupied sector...\n");
  1380. for( i=0; i<NUM_PARTITION_TABLE_ENTRIES;i++ ) {
  1381. if( IsUnknownPartition( pPartitionTable[i].SysId )) {
  1382. //
  1383. // Non-recognized!
  1384. //
  1385. _Log("A non-recognized partition exists!\n");
  1386. tempSect = (pPartitionTable[i].Start + pPartitionTable[i].Count);
  1387. if( OccupiedSect < tempSect ) {
  1388. //
  1389. // track align the highest used sector -- anything below this is off limits
  1390. //
  1391. OccupiedSect = tempSect;
  1392. _Log("New highest occupied sector is %ld\n",OccupiedSect);
  1393. if(OccupiedSect % SectorsPerTrack) {
  1394. OccupiedSect = OccupiedSect + (SectorsPerTrack - (OccupiedSect % SectorsPerTrack));
  1395. }
  1396. }
  1397. }
  1398. }
  1399. _Log("Highest occupied sector (track-aligned) is %ld\n",OccupiedSect);
  1400. return OccupiedSect;
  1401. }
  1402. BOOL
  1403. RestorePartitionTable(
  1404. IN HDISK DiskHandle,
  1405. IN VOID* IoBuffer,
  1406. IN FPPARTITION_TABLE_ENTRY pPartitionTable
  1407. )
  1408. {
  1409. int i,j;
  1410. FPMBR theMBR = ((FPMBR)IoBuffer);
  1411. //
  1412. // Load the MBR back in, drop our old partition info back in.
  1413. //
  1414. if(!ReadDisk(DiskHandle,0,1,IoBuffer) ) {
  1415. fprintf(stderr,textDiskReadError,0);
  1416. fprintf(stderr,"\n");
  1417. return(FALSE);
  1418. }
  1419. //
  1420. // Validate that it is a good MBR.
  1421. //
  1422. if( theMBR->AA55Signature != BOOT_RECORD_SIGNATURE ) {
  1423. fprintf(stderr,textDiskReadError,0);
  1424. _Log(" WARNING: The MBR was invalid!");
  1425. return FALSE;
  1426. }
  1427. //
  1428. // Restore the original partitions.
  1429. //
  1430. for(i=0;i<NUM_PARTITION_TABLE_ENTRIES;i++){
  1431. if(IsUnknownPartition(pPartitionTable[i].SysId)
  1432. && (pPartitionTable[i].SysId != 0)) {
  1433. j = FindFirstUnusedEntry(theMBR->PartitionTable);
  1434. if( j != -1 ) {
  1435. memcpy(&(theMBR->PartitionTable[j]),
  1436. &(pPartitionTable[i]),
  1437. sizeof(PARTITION_TABLE_ENTRY));
  1438. } else {
  1439. fprintf(stderr,textTooManyPartitions);
  1440. fprintf(stderr,"\n");
  1441. return(FALSE);
  1442. }
  1443. }
  1444. }
  1445. if(!WriteDisk(DiskHandle,0,1,IoBuffer)) {
  1446. fprintf(stderr,textDiskWriteError,0);
  1447. fprintf(stderr,"\n");
  1448. return(FALSE);
  1449. }
  1450. return TRUE;
  1451. }
  1452. BOOL
  1453. IsUnknownPartition(
  1454. IN BYTE SysId
  1455. )
  1456. {
  1457. if( SysId != 0x00 && // not unused
  1458. SysId != 0x01 &&
  1459. SysId != 0x04 &&
  1460. SysId != 0x06 &&
  1461. SysId != 0x07 &&
  1462. SysId != 0x0b &&
  1463. SysId != 0x0c &&
  1464. SysId != 0x0e ) {
  1465. return TRUE;
  1466. }
  1467. return FALSE;
  1468. }
  1469. BYTE
  1470. FindFirstUnusedEntry(
  1471. IN FPPARTITION_TABLE_ENTRY pPartitionTable
  1472. )
  1473. {
  1474. BYTE i;
  1475. for(i=0;i<NUM_PARTITION_TABLE_ENTRIES;i++){
  1476. if(pPartitionTable[i].SysId == 0) {
  1477. return i;
  1478. }
  1479. }
  1480. return -1;
  1481. }