Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1059 lines
25 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <windows.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <ntddvol.h>
  8. #include <ntdddisk.h>
  9. #include <align.h>
  10. #include <bootmbr.h>
  11. #include "identify.h"
  12. #define SECTOR_SIZE 512
  13. #define SECTOR_MASK (SECTOR_SIZE - 1)
  14. #define BOOTSECT_SECTORS 16
  15. #define BOOTSECT_SIZE (BOOTSECT_SECTORS * SECTOR_SIZE)
  16. #define MAX_NUM_CHS_ADDRESSABLE_SECTORS 16514064
  17. #define NTLDR_FIND L"NTLDR"
  18. #define NTLDR_REPLACE L"$LDR$"
  19. #define NTLDR_LEN (sizeof(NTLDR_FIND)-sizeof(WCHAR))
  20. //
  21. // Perform the copy using 8 outstanding I/Os of 128k each
  22. //
  23. #define COPYBUF_SIZE (128 * 1024)
  24. #define COPYBUF_COUNT 8
  25. //
  26. // A failed assert will abort the process
  27. //
  28. #define assert(x) if (!(x)) { printf("Assert failed: %s\n", #x); exit(-1); }
  29. typedef struct _COPYBUF {
  30. OVERLAPPED Overlapped;
  31. ULONG State;
  32. ULONG Bytes;
  33. PVOID Buffer;
  34. } COPYBUF, *PCOPYBUF;
  35. //
  36. // Three possible states for a copybuf
  37. //
  38. #define CB_FREE 0x0
  39. #define CB_READ 0x1
  40. #define CB_WRITE 0x2
  41. //
  42. // CUSTOM_IDENTIFY_DATA consists of an IDENTIFY_DATA structure,
  43. // along with three fields in which to pass along the "BIOS" disk
  44. // geometry to the SIMICS simulator.
  45. //
  46. #pragma pack(push,1)
  47. typedef union _CUSTOM_IDENTIFY_DATA {
  48. IDENTIFY_DATA IdentifyData;
  49. struct {
  50. USHORT Reserved[128];
  51. ULONG Cylinders;
  52. USHORT Heads;
  53. USHORT SectorsPerTrack;
  54. } BiosData;
  55. } CUSTOM_IDENTIFY_DATA, *PCUSTOM_IDENTIFY_DATA;
  56. #pragma pack(pop)
  57. BOOLEAN
  58. DisplayDiskGeometry(
  59. IN HANDLE handle
  60. );
  61. VOID
  62. DoWrite (
  63. IN PVOID Buffer,
  64. IN ULONG Length,
  65. IN ULONG64 Offset,
  66. IN PCOPYBUF CopyBuf
  67. );
  68. VOID
  69. GetBootSectors (
  70. IN LARGE_INTEGER Offset
  71. );
  72. BOOLEAN
  73. GetIdentifyData(
  74. IN HANDLE Handle,
  75. OUT PIDENTIFY_DATA IdentifyData
  76. );
  77. BOOLEAN
  78. GetVolumeInfo (
  79. IN PCHAR DrivePath,
  80. OUT PULONG DriveNumber,
  81. OUT PULONG PartitionNumber,
  82. OUT PULONG64 StartingOffset,
  83. OUT PULONG64 ExtentLength
  84. );
  85. VOID
  86. InitializeCopyBuffers (
  87. VOID
  88. );
  89. VOID
  90. MassageIdentifyData(
  91. VOID
  92. );
  93. VOID
  94. ProcessCompletedCopy (
  95. PCOPYBUF CopyBuf
  96. );
  97. BOOL
  98. ScanCopyBuffers (
  99. VOID
  100. );
  101. VOID
  102. StartRead (
  103. IN OUT PCOPYBUF CopyBuf
  104. );
  105. VOID
  106. StartWrite (
  107. IN OUT PCOPYBUF CopyBuf
  108. );
  109. VOID
  110. WriteMBRCode(
  111. IN PUCHAR FilePath
  112. );
  113. //
  114. // Global data declarations follow
  115. //
  116. COPYBUF CopyBufArray[COPYBUF_COUNT];
  117. //
  118. // Identifies the PhysicalDrive.
  119. //
  120. INT gDeviceNumber;
  121. //
  122. // Identifies the position of the drive on the controller
  123. // ie. master == 0, slave == 1.
  124. //
  125. UCHAR gDriveNumber = 1;
  126. HANDLE DriveHandle;
  127. HANDLE FileHandle;
  128. //
  129. // CopyOffset is the byte offset between data on the source disk image and
  130. // corresponding data in the output file. This is used to account for the
  131. // sector-sized prefix in the output file.
  132. //
  133. ULONG CopyOffset;
  134. ULONG64 CurrentOffset;
  135. ULONG64 DriveSize;
  136. ULONG64 MaxSize;
  137. UCHAR PercentComplete;
  138. ULONG OutstandingIo;
  139. IDENTIFY_DATA IdentifyData;
  140. DISK_GEOMETRY DiskGeometry;
  141. //
  142. // Array of event handles, one per copy buffer
  143. //
  144. HANDLE IoEvents[COPYBUF_COUNT];
  145. int
  146. _cdecl main (
  147. int argc,
  148. char *argv[]
  149. )
  150. {
  151. char deviceBuffer[20];
  152. PCHAR outputFileName;
  153. PCHAR drive;
  154. PCHAR options;
  155. BOOLEAN result;
  156. BOOLEAN writeBootSect;
  157. ULONG64 volumeOffset;
  158. ULONG64 volumeSize;
  159. ULONG partitionNumber;
  160. DWORD waitResult;
  161. PCOPYBUF copyBuf;
  162. ULONG i;
  163. ULONG openAttributes;
  164. writeBootSect = FALSE;
  165. //
  166. // Must be invoked with two arguments
  167. //
  168. if (argc != 3 && argc != 4) {
  169. fprintf(stderr,
  170. "Usage: %s <drive:> <OutputFile> [/b]\n",
  171. argv[0]);
  172. exit(1);
  173. }
  174. InitializeCopyBuffers();
  175. //
  176. // Extract arguments
  177. //
  178. drive = argv[1];
  179. outputFileName = argv[2];
  180. result = GetVolumeInfo(drive,
  181. &gDeviceNumber,
  182. &partitionNumber,
  183. &volumeOffset,
  184. &volumeSize);
  185. if (result == FALSE) {
  186. exit(1);
  187. }
  188. if (argc == 4) {
  189. options = argv[3];
  190. if (_stricmp(options, "/b") != 0) {
  191. fprintf(stderr, "Invalid option %s specified\n",options);
  192. exit(1);
  193. }
  194. writeBootSect = TRUE;
  195. }
  196. //
  197. // Calculate how many sectors need to be in the image
  198. //
  199. MaxSize = (volumeOffset + volumeSize + SECTOR_MASK) / SECTOR_SIZE;
  200. sprintf(deviceBuffer,"\\\\.\\PhysicalDrive%d",
  201. gDeviceNumber);
  202. openAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING;
  203. if (writeBootSect == FALSE) {
  204. openAttributes |= FILE_FLAG_OVERLAPPED;
  205. }
  206. //
  207. // Open the physical source drive.
  208. //
  209. DriveHandle = CreateFile(deviceBuffer,
  210. GENERIC_READ | GENERIC_WRITE,
  211. FILE_SHARE_READ | FILE_SHARE_WRITE,
  212. NULL,
  213. OPEN_EXISTING,
  214. openAttributes,
  215. NULL);
  216. if (INVALID_HANDLE_VALUE == DriveHandle){
  217. printf("Couldn't open: %s. Drive may not exist. ",
  218. deviceBuffer);
  219. return -1;
  220. }
  221. //
  222. // Retrieve and display the BIOS disk geometry
  223. //
  224. result = DisplayDiskGeometry( DriveHandle );
  225. if (result == FALSE) {
  226. printf("Could not retrieve disk geometry\n");
  227. exit(1);
  228. }
  229. //
  230. // Reteive the identify data, if possible. If the data could not be
  231. // retrieved, MassageIdentifyData() will attempt to fabricate the relevant
  232. // portions based on the BIOS disk geometry retrieved previously.
  233. //
  234. GetIdentifyData( DriveHandle,
  235. &IdentifyData );
  236. MassageIdentifyData();
  237. DriveSize = IdentifyData.UserAddressableSectors * (ULONGLONG)512;
  238. if (MaxSize == 0) {
  239. MaxSize = DriveSize;
  240. } else {
  241. MaxSize *= 512;
  242. }
  243. printf("Drive size %dMB\n",(ULONG)(DriveSize / (1024 * 1024)));
  244. printf("Image size %dMB\n",(ULONG)(MaxSize / (1024 * 1024)));
  245. //
  246. // Open the output file
  247. //
  248. FileHandle = CreateFile(outputFileName,
  249. GENERIC_READ | GENERIC_WRITE,
  250. 0,
  251. NULL,
  252. CREATE_ALWAYS,
  253. openAttributes,
  254. NULL);
  255. if (FileHandle == INVALID_HANDLE_VALUE) {
  256. printf("Could not create %s\n", outputFileName);
  257. return -1;
  258. }
  259. if (writeBootSect != FALSE) {
  260. //
  261. // We're just creating bootsect.dat.
  262. //
  263. LARGE_INTEGER offset;
  264. offset.QuadPart = volumeOffset;
  265. GetBootSectors(offset);
  266. goto closeHandles;
  267. }
  268. //
  269. // Write the identify data
  270. //
  271. CopyOffset = 0;
  272. CurrentOffset = 0;
  273. DoWrite(&IdentifyData,
  274. sizeof(IDENTIFY_DATA),
  275. 0,
  276. &CopyBufArray[0]);
  277. //
  278. // Kick off reads on all of the remaining copy buffers
  279. //
  280. CopyOffset = sizeof(IDENTIFY_DATA);
  281. for (i = 1; i < COPYBUF_COUNT; i++) {
  282. StartRead(&CopyBufArray[i]);
  283. }
  284. //
  285. // Loop, processing completed I/O as appropriate. When all
  286. // outstanding io has completed, the copy is complete.
  287. //
  288. do {
  289. waitResult = WaitForMultipleObjects( COPYBUF_COUNT,
  290. IoEvents,
  291. FALSE,
  292. INFINITE );
  293. waitResult -= WAIT_OBJECT_0;
  294. assert(waitResult < COPYBUF_COUNT);
  295. copyBuf = &CopyBufArray[waitResult];
  296. ProcessCompletedCopy(copyBuf);
  297. } while (OutstandingIo > 0);
  298. closeHandles:
  299. //
  300. // The copy is finished.
  301. //
  302. printf("%s created\n", outputFileName);
  303. CloseHandle(DriveHandle);
  304. CloseHandle(FileHandle);
  305. #if 0
  306. if (writeBootSect == FALSE) {
  307. //
  308. // Write the MBR code into the output image
  309. //
  310. WriteMBRCode(outputFileName);
  311. }
  312. #endif
  313. return 0;
  314. }
  315. VOID
  316. InitializeCopyBuffers (
  317. VOID
  318. )
  319. {
  320. ULONG bytes;
  321. PCOPYBUF copyBuf;
  322. PCOPYBUF copyBufEnd;
  323. ULONG i;
  324. HANDLE event;
  325. PCHAR copyBuffer;
  326. //
  327. // Make a single, sector-aligned allocation to contain all of the copy
  328. // buffers
  329. //
  330. bytes = COPYBUF_SIZE * COPYBUF_COUNT + SECTOR_MASK;
  331. copyBuffer = malloc(bytes);
  332. if (copyBuffer == NULL) {
  333. printf("Out of memory\n");
  334. exit(-1);
  335. }
  336. copyBuffer =
  337. (PCHAR)(((ULONG_PTR)copyBuffer + SECTOR_MASK) & ~SECTOR_MASK);
  338. //
  339. // Walk the copyBuf array, initializing each to point to it's portion of
  340. // the copy buffer
  341. //
  342. copyBuf = CopyBufArray;
  343. for (i = 0; i < COPYBUF_COUNT; i++) {
  344. copyBuf->State = CB_FREE;
  345. copyBuf->Buffer = copyBuffer;
  346. event = CreateEvent( NULL,
  347. FALSE,
  348. FALSE,
  349. NULL );
  350. assert(event != NULL);
  351. copyBuf->Overlapped.hEvent = event;
  352. IoEvents[i] = event;
  353. copyBuffer += COPYBUF_SIZE;
  354. copyBuf++;
  355. }
  356. }
  357. BOOLEAN
  358. GetVolumeInfo (
  359. IN PCHAR DrivePath,
  360. OUT PULONG DriveNumber,
  361. OUT PULONG PartitionNumber,
  362. OUT PULONG64 StartingOffset,
  363. OUT PULONG64 ExtentLength
  364. )
  365. {
  366. char deviceBuffer[20];
  367. HANDLE volumeHandle;
  368. BOOL result;
  369. STORAGE_DEVICE_NUMBER deviceNumber;
  370. PARTITION_INFORMATION partitionInformation;
  371. ULONG bytesReturned;
  372. //
  373. // Determine which physical drive contains the specified partition by
  374. //
  375. // - Opening the volume
  376. //
  377. // - Sending IOCTL_STORAGE_GET_DEVICE_NUMBER to retrieve the device and
  378. // partition number
  379. //
  380. // - Sending IOCTL_DISK_GET_PARTITION_INFO to retrieve the starting
  381. // offset and length of the volume
  382. //
  383. // - Closing the volume
  384. //
  385. sprintf(deviceBuffer, "\\\\.\\%s", DrivePath);
  386. volumeHandle = CreateFile(deviceBuffer,
  387. GENERIC_READ,
  388. FILE_SHARE_READ | FILE_SHARE_WRITE,
  389. NULL,
  390. OPEN_EXISTING,
  391. FILE_ATTRIBUTE_NORMAL |
  392. FILE_FLAG_NO_BUFFERING |
  393. FILE_FLAG_OVERLAPPED,
  394. NULL);
  395. if (volumeHandle == INVALID_HANDLE_VALUE) {
  396. printf("Error %d opening %s\n", GetLastError(), deviceBuffer);
  397. return FALSE;
  398. }
  399. result = DeviceIoControl(volumeHandle,
  400. IOCTL_STORAGE_GET_DEVICE_NUMBER,
  401. NULL,
  402. 0,
  403. &deviceNumber,
  404. sizeof(deviceNumber),
  405. &bytesReturned,
  406. NULL);
  407. if (result == FALSE) {
  408. printf("Could not get device number for %s\n", deviceBuffer);
  409. CloseHandle(volumeHandle);
  410. return FALSE;
  411. }
  412. if (deviceNumber.DeviceType != FILE_DEVICE_DISK) {
  413. printf("%s is not a disk\n",deviceBuffer);
  414. CloseHandle(volumeHandle);
  415. return FALSE;
  416. }
  417. bytesReturned = 0;
  418. result = DeviceIoControl(volumeHandle,
  419. IOCTL_DISK_GET_PARTITION_INFO,
  420. NULL,
  421. 0,
  422. &partitionInformation,
  423. sizeof(partitionInformation),
  424. &bytesReturned,
  425. NULL);
  426. CloseHandle(volumeHandle);
  427. if (result == FALSE) {
  428. printf("Error %d retrieving partition information for %s\n",
  429. GetLastError(),
  430. deviceBuffer);
  431. return FALSE;
  432. }
  433. //
  434. // All of the information was successfully retrieved. Fill in the
  435. // output parameters and return.
  436. //
  437. *DriveNumber = deviceNumber.DeviceNumber;
  438. *PartitionNumber = deviceNumber.PartitionNumber;
  439. *StartingOffset = partitionInformation.StartingOffset.QuadPart;
  440. *ExtentLength = partitionInformation.PartitionLength.QuadPart;
  441. return TRUE;
  442. }
  443. BOOLEAN
  444. GetIdentifyData(
  445. IN HANDLE Handle,
  446. OUT PIDENTIFY_DATA IdentifyData
  447. )
  448. {
  449. SENDCMDINPARAMS inputParams;
  450. PSENDCMDOUTPARAMS outputParams;
  451. PIDENTIFY_DATA identifyData;
  452. ULONG bytesReturned;
  453. ULONG bufSize;
  454. ZeroMemory(&inputParams, sizeof(SENDCMDINPARAMS));
  455. bufSize = sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE;
  456. bufSize *= 2;
  457. outputParams = (PSENDCMDOUTPARAMS) malloc(bufSize);
  458. if (!outputParams) {
  459. printf("Out of memory\n");
  460. return FALSE;
  461. }
  462. ZeroMemory(outputParams, bufSize);
  463. //
  464. // Build register structure to send SMART command.
  465. //
  466. inputParams.irDriveRegs.bFeaturesReg = 0;
  467. inputParams.irDriveRegs.bSectorCountReg = 1;
  468. inputParams.irDriveRegs.bSectorNumberReg = 1;
  469. inputParams.irDriveRegs.bCylLowReg = 0;
  470. inputParams.irDriveRegs.bCylHighReg = 0;
  471. inputParams.irDriveRegs.bDriveHeadReg = 0xA0 | ((gDriveNumber & 1) << 4);
  472. inputParams.irDriveRegs.bCommandReg = ID_CMD;
  473. bytesReturned = 0;
  474. if (!DeviceIoControl (Handle,
  475. SMART_RCV_DRIVE_DATA,
  476. &inputParams,
  477. sizeof(SENDCMDINPARAMS) - 1,
  478. outputParams,
  479. bufSize,
  480. &bytesReturned,
  481. NULL)) {
  482. printf("IDE_IDENTIFY failed with 0x%x, %d bytes returned\n",
  483. GetLastError(),
  484. bytesReturned);
  485. printf("WARNING: This image file will work with the SIMICS simulator\n"
  486. " but not simnow.\n");
  487. memset(IdentifyData, 0, sizeof(IDENTIFY_DATA));
  488. free(outputParams);
  489. return FALSE;
  490. }
  491. identifyData = (PIDENTIFY_DATA)outputParams->bBuffer;
  492. *IdentifyData = *identifyData;
  493. free(outputParams);
  494. return TRUE;
  495. }
  496. VOID
  497. MassageIdentifyData(
  498. VOID
  499. )
  500. /*++
  501. Routine Description:
  502. This routine sets the bios CHS geometry in the IdentifyData structure
  503. in a place previously agreed upon with Simics.
  504. Arguments:
  505. None.
  506. Return Value:
  507. None.
  508. --*/
  509. {
  510. PCUSTOM_IDENTIFY_DATA custom;
  511. ULONG sectorCount;
  512. USHORT ideCylinders;
  513. USHORT ideHeads;
  514. USHORT ideSectorsPerTrack;
  515. C_ASSERT(FIELD_OFFSET(IDENTIFY_DATA,NumCylinders)/2 == 1);
  516. C_ASSERT(FIELD_OFFSET(IDENTIFY_DATA,NumHeads)/2 == 3);
  517. C_ASSERT(FIELD_OFFSET(IDENTIFY_DATA,NumSectorsPerTrack)/2 == 6);
  518. C_ASSERT(FIELD_OFFSET(IDENTIFY_DATA,CurrentSectorCapacity)/2 == 57);
  519. //
  520. // Set the BIOS disk geometry in the new fields that are passed
  521. // along to the SIMICS simulator.
  522. //
  523. custom = (PCUSTOM_IDENTIFY_DATA)&IdentifyData;
  524. custom->BiosData.Cylinders = DiskGeometry.Cylinders.LowPart;
  525. custom->BiosData.Heads = (USHORT)DiskGeometry.TracksPerCylinder;
  526. custom->BiosData.SectorsPerTrack = (USHORT)DiskGeometry.SectorsPerTrack;
  527. if (IdentifyData.NumCylinders == 0) {
  528. //
  529. // The IDENTIFY_DATA ioctl failed (SMART isn't supported), so parts
  530. // of the IDE geometry must be fabricated, including:
  531. //
  532. // - NumCylinders
  533. // - NumHeads
  534. // - NumSectorsPerTrack
  535. // - CurrentSectorCapacity
  536. // - UserAddressableSectors
  537. //
  538. sectorCount = DiskGeometry.Cylinders.LowPart *
  539. DiskGeometry.TracksPerCylinder *
  540. DiskGeometry.SectorsPerTrack;
  541. if (sectorCount > MAX_NUM_CHS_ADDRESSABLE_SECTORS) {
  542. IdentifyData.NumCylinders = 16383;
  543. IdentifyData.NumHeads = 16;
  544. IdentifyData.NumSectorsPerTrack = 63;
  545. } else {
  546. IdentifyData.NumSectorsPerTrack =
  547. (USHORT)DiskGeometry.SectorsPerTrack;
  548. IdentifyData.NumHeads = 16;
  549. IdentifyData.NumCylinders = (USHORT)
  550. (sectorCount / (IdentifyData.NumSectorsPerTrack *
  551. IdentifyData.NumHeads));
  552. }
  553. IdentifyData.CurrentSectorCapacity = sectorCount;
  554. IdentifyData.UserAddressableSectors = sectorCount;
  555. }
  556. printf("IDE disk geometry:\n"
  557. " Cyls %d\n"
  558. " Heads %d\n"
  559. " Sct/Trk %d\n\n"
  560. "BIOS disk geometry:\n"
  561. " Cyls %d\n"
  562. " Heads %d\n"
  563. " Sct/Trk %d\n",
  564. IdentifyData.NumCylinders,
  565. IdentifyData.NumHeads,
  566. IdentifyData.NumSectorsPerTrack,
  567. custom->BiosData.Cylinders,
  568. custom->BiosData.Heads,
  569. custom->BiosData.SectorsPerTrack);
  570. }
  571. VOID
  572. DoWrite (
  573. IN PVOID Buffer,
  574. IN ULONG Length,
  575. IN ULONG64 Offset,
  576. IN PCOPYBUF CopyBuf
  577. )
  578. {
  579. LARGE_INTEGER offset;
  580. BOOL result;
  581. offset.QuadPart = Offset;
  582. CopyBuf->Overlapped.Offset = offset.HighPart;
  583. CopyBuf->Overlapped.OffsetHigh = offset.LowPart;
  584. CopyBuf->State = CB_READ;
  585. memcpy(CopyBuf->Buffer,Buffer,Length);
  586. CopyBuf->Bytes = Length;
  587. StartWrite(CopyBuf);
  588. }
  589. VOID
  590. StartWrite (
  591. IN OUT PCOPYBUF CopyBuf
  592. )
  593. {
  594. LARGE_INTEGER offset;
  595. BOOL result;
  596. ULONG error;
  597. CopyBuf->State = CB_WRITE;
  598. //
  599. // Adjust the offset
  600. //
  601. offset.LowPart = CopyBuf->Overlapped.Offset;
  602. offset.HighPart = CopyBuf->Overlapped.OffsetHigh;
  603. offset.QuadPart += CopyOffset;
  604. CopyBuf->Overlapped.Offset = offset.LowPart;
  605. CopyBuf->Overlapped.OffsetHigh = offset.HighPart;
  606. result = WriteFile( FileHandle,
  607. CopyBuf->Buffer,
  608. CopyBuf->Bytes,
  609. NULL,
  610. &CopyBuf->Overlapped );
  611. if (result == FALSE) {
  612. error = GetLastError();
  613. if (error != ERROR_IO_PENDING &&
  614. error != ERROR_IO_INCOMPLETE) {
  615. printf("Error %d returned from write\n",error);
  616. exit(-1);
  617. }
  618. }
  619. OutstandingIo += 1;
  620. }
  621. VOID
  622. StartRead (
  623. IN OUT PCOPYBUF CopyBuf
  624. )
  625. {
  626. LARGE_INTEGER offset;
  627. BOOL result;
  628. ULONG64 length;
  629. ULONG error;
  630. if (CurrentOffset == MaxSize) {
  631. return;
  632. }
  633. length = MaxSize - CurrentOffset;
  634. if (length > COPYBUF_SIZE) {
  635. length = COPYBUF_SIZE;
  636. }
  637. CopyBuf->State = CB_READ;
  638. offset.QuadPart = CurrentOffset;
  639. CurrentOffset += length;
  640. CopyBuf->Overlapped.Offset = offset.LowPart;
  641. CopyBuf->Overlapped.OffsetHigh = offset.HighPart;
  642. result = ReadFile( DriveHandle,
  643. CopyBuf->Buffer,
  644. (ULONG)length,
  645. NULL,
  646. &CopyBuf->Overlapped );
  647. if (result == FALSE) {
  648. error = GetLastError();
  649. if (error != ERROR_IO_PENDING &&
  650. error != ERROR_IO_INCOMPLETE) {
  651. printf("Error %d returned from read\n",error);
  652. exit(-1);
  653. }
  654. }
  655. OutstandingIo += 1;
  656. }
  657. BOOLEAN
  658. DisplayDiskGeometry(
  659. IN HANDLE handle
  660. )
  661. {
  662. BOOL result;
  663. ULONG bytesReturned;
  664. result = DeviceIoControl(handle,
  665. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  666. NULL,
  667. 0,
  668. &DiskGeometry,
  669. sizeof(DiskGeometry),
  670. &bytesReturned,
  671. NULL);
  672. if (result == FALSE) {
  673. return FALSE;
  674. }
  675. printf("%I64d Cylinders %d Heads %d Sectors/Track\n",
  676. DiskGeometry.Cylinders.QuadPart,
  677. DiskGeometry.TracksPerCylinder,
  678. DiskGeometry.SectorsPerTrack);
  679. return TRUE;
  680. }
  681. VOID
  682. ProcessCompletedCopy (
  683. PCOPYBUF CopyBuf
  684. )
  685. {
  686. UCHAR percent;
  687. HANDLE handle;
  688. BOOL result;
  689. //
  690. // Decrement the outstanding Io count. Successfully starting another
  691. // read or write will increment it again.
  692. //
  693. OutstandingIo -= 1;
  694. //
  695. // We have found a buffer with either a read or a write in progress.
  696. // Retrieve the number of bytes transferred.
  697. //
  698. if (CopyBuf->State == CB_READ) {
  699. handle = DriveHandle;
  700. } else {
  701. handle = FileHandle;
  702. }
  703. result = GetOverlappedResult( handle,
  704. &CopyBuf->Overlapped,
  705. &CopyBuf->Bytes,
  706. FALSE );
  707. assert(result != FALSE);
  708. if (CopyBuf->State == CB_READ) {
  709. //
  710. // This buffer contains data read from the drive, kick off a write
  711. // to the output file.
  712. //
  713. StartWrite(CopyBuf);
  714. } else {
  715. //
  716. // This buffer represents data that has been written to the drive.
  717. // Use it to start another read.
  718. //
  719. percent = (UCHAR)((CurrentOffset * 100) / MaxSize);
  720. if (percent != PercentComplete) {
  721. printf("%d%%\r",percent);
  722. PercentComplete = percent;
  723. }
  724. StartRead(CopyBuf);
  725. }
  726. }
  727. VOID
  728. GetBootSectors (
  729. IN LARGE_INTEGER VolumeOffset
  730. )
  731. /*++
  732. Routine Description:
  733. Reads the first BOOT_SECT sectors from the cmd-line-supplied volume,
  734. searches for NTLDR and replaces with $LDR$, and writes the sectors
  735. to the output file.
  736. Arguments:
  737. VolumeOffset - Physical disk offset of the start of the boot sectors
  738. Return Value:
  739. None. Program is aborted on failure.
  740. --*/
  741. {
  742. UCHAR buffer[ BOOTSECT_SIZE + SECTOR_SIZE - 1 ];
  743. OVERLAPPED overlapped;
  744. PUCHAR sectorData;
  745. ULONG bytesTransferred;
  746. PCHAR search;
  747. BOOL result;
  748. //
  749. // Read the boot sectors into sectorData
  750. //
  751. sectorData = ROUND_UP_POINTER(buffer,SECTOR_SIZE);
  752. RtlZeroMemory(&overlapped,sizeof(overlapped));
  753. overlapped.Offset = VolumeOffset.LowPart;
  754. overlapped.OffsetHigh = VolumeOffset.HighPart;
  755. result = ReadFile(DriveHandle,
  756. sectorData,
  757. BOOTSECT_SIZE,
  758. &bytesTransferred,
  759. &overlapped);
  760. if (result == FALSE || bytesTransferred != BOOTSECT_SIZE) {
  761. fprintf(stderr,
  762. "Error %d reading boot sectors\n",
  763. GetLastError());
  764. exit(1);
  765. }
  766. //
  767. // Find "NTLDR" and replace it with "$LDR$". The magic numbers here
  768. // came directly from code in setup... start the search at offset 1024
  769. // and work backwards, giving up if not found by offset 62.
  770. //
  771. search = sectorData + 1024 - NTLDR_LEN;
  772. while (TRUE) {
  773. if (memcmp(search,NTLDR_FIND,NTLDR_LEN) == 0) {
  774. //
  775. // Found it. Copy $LDR$ in instead.
  776. //
  777. memcpy(search,NTLDR_REPLACE,NTLDR_LEN);
  778. break;
  779. }
  780. search -= sizeof(WCHAR);
  781. if (search == (sectorData + 62)) {
  782. //
  783. // Couldn't find the string, give up
  784. //
  785. fprintf(stderr,"Couldn't find NTLDR string\n");
  786. exit(1);
  787. }
  788. }
  789. RtlZeroMemory(&overlapped,sizeof(overlapped));
  790. overlapped.Offset = 0;
  791. result = WriteFile(FileHandle,
  792. sectorData,
  793. BOOTSECT_SECTORS * SECTOR_SIZE,
  794. &bytesTransferred,
  795. &overlapped);
  796. if (result == FALSE) {
  797. fprintf(stderr,
  798. "Error %d reading boot sectors\n",
  799. GetLastError());
  800. exit(1);
  801. }
  802. }
  803. VOID
  804. WriteMBRCode(
  805. IN PUCHAR FilePath
  806. )
  807. {
  808. HANDLE handle;
  809. BOOL result;
  810. DWORD bytesWritten;
  811. handle = CreateFile(FilePath,
  812. GENERIC_READ | GENERIC_WRITE,
  813. 0,
  814. NULL,
  815. OPEN_EXISTING,
  816. FILE_ATTRIBUTE_NORMAL,
  817. NULL);
  818. if (handle == INVALID_HANDLE_VALUE) {
  819. fprintf(stderr,"Error %d opening %s\n", GetLastError(),FilePath);
  820. exit(1);
  821. }
  822. result = WriteFile(handle,
  823. x86BootCode,
  824. 440,
  825. &bytesWritten,
  826. NULL);
  827. if (result == FALSE) {
  828. fprintf(stderr,"Error %d writing MBR code\n", GetLastError());
  829. exit(1);
  830. }
  831. CloseHandle(handle);
  832. }