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.

999 lines
29 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. burn.c
  5. Abstract:
  6. A user mode app that allows simple commands to be sent to a
  7. selected scsi device.
  8. Environment:
  9. User mode only
  10. Revision History:
  11. 03-26-96 : Created
  12. --*/
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <assert.h>
  17. #include "burn.h"
  18. #include "sptlib.h"
  19. #define MAX_CD_IMAGE_SIZE (700 * 1024 * 1024)
  20. #define MAX_DVD_IMAGE_SIZE (4700 * 1000 * 1000)
  21. #define POST_GAP_SIZE 150
  22. #define IS_TEST_BURN FALSE
  23. typedef struct _SENSE_STUFF {
  24. UCHAR Sense;
  25. UCHAR Asc;
  26. UCHAR Ascq;
  27. UCHAR Reserved;
  28. } SENSE_STUFF, *PSENSE_STUFF;
  29. SENSE_STUFF AllowedBurnSense[] = {
  30. {SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS, 0},
  31. {SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_OPERATION_IN_PROGRESS, 0}
  32. };
  33. #define AllowedBurnSenseEntries (sizeof(AllowedBurnSense)/sizeof(SENSE_STUFF))
  34. SENSE_STUFF AllowedReadDiscInfo[] = {
  35. { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_OPERATION_IN_PROGRESS, 0 },
  36. { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS, 0 },
  37. { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_FORMAT_IN_PROGRESS, 0 },
  38. { SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_ILLEGAL_MODE_FOR_THIS_TRACK, 0, 0 },
  39. { SCSI_SENSE_UNIT_ATTENTION, SCSI_ADSENSE_INSUFFICIENT_TIME_FOR_OPERATION, 0, 0 }
  40. };
  41. #define AllowedReadDiscInfoEntries (sizeof(AllowedReadDiscInfo)/sizeof(SENSE_STUFF))
  42. BOOLEAN
  43. IsSenseDataInTable(
  44. IN PSENSE_STUFF Table,
  45. IN LONG Entries, // in table
  46. IN PSENSE_DATA SenseData
  47. )
  48. {
  49. LONG i;
  50. UCHAR sense = SenseData->SenseKey & 0xf;
  51. UCHAR asc = SenseData->AdditionalSenseCode;
  52. UCHAR ascq = SenseData->AdditionalSenseCodeQualifier;
  53. for (i = 0; i < Entries; i++ ) {
  54. if ((Table[i].Sense = sense) &&
  55. (Table[i].Ascq = ascq ) &&
  56. (Table[i].Asc = asc )
  57. ) {
  58. return TRUE;
  59. }
  60. }
  61. return FALSE;
  62. }
  63. __inline
  64. DWORD
  65. MakeCdSpeed(
  66. IN DWORD Speed
  67. )
  68. {
  69. Speed *= (75 * 2352); // this makes it the proper speed
  70. Speed += 500; // rounding...
  71. Speed /= 1000; // yes, this is by 1000, not 1024!
  72. return Speed;
  73. }
  74. #if DBG
  75. #define OUTPUT stderr
  76. #define FPRINTF(x) fprintf x
  77. #else
  78. #define OUTPUT stdout
  79. #define FPRINTF(x)
  80. #endif
  81. int __cdecl main(int argc, char *argv[])
  82. {
  83. int i = 0;
  84. HANDLE cdromHandle;
  85. HANDLE isoImageHandle;
  86. HACK_FLAGS hackFlags;
  87. char buffer[32];
  88. if(argc < 3) {
  89. printf("Usage: burn <drive> <image>\n");
  90. return -1;
  91. }
  92. sprintf(buffer, "\\\\.\\%s", argv[1]);
  93. cdromHandle = CreateFile(buffer,
  94. GENERIC_READ | GENERIC_WRITE,
  95. FILE_SHARE_READ | FILE_SHARE_WRITE,
  96. NULL,
  97. OPEN_EXISTING,
  98. FILE_ATTRIBUTE_NORMAL,
  99. NULL);
  100. if(cdromHandle == INVALID_HANDLE_VALUE) {
  101. printf("Error %d opening device %s\n", GetLastError(), buffer);
  102. return -2;
  103. }
  104. isoImageHandle = CreateFile(argv[2],
  105. GENERIC_READ,
  106. FILE_SHARE_READ,
  107. NULL,
  108. OPEN_EXISTING,
  109. FILE_FLAG_SEQUENTIAL_SCAN,
  110. NULL);
  111. if (isoImageHandle == INVALID_HANDLE_VALUE) {
  112. printf("Error %d opening image file %s\n",
  113. GetLastError(), argv[2]);
  114. CloseHandle(cdromHandle);
  115. return -2;
  116. }
  117. RtlZeroMemory(&hackFlags, sizeof(HACK_FLAGS));
  118. hackFlags.TestBurn = 0;
  119. hackFlags.IgnoreModePageErrors = 1;
  120. BurnCommand(cdromHandle, isoImageHandle, hackFlags);
  121. CloseHandle(isoImageHandle);
  122. CloseHandle(cdromHandle);
  123. return 0;
  124. }
  125. VOID
  126. PrintBuffer(
  127. IN PVOID Buffer,
  128. IN DWORD Size
  129. )
  130. {
  131. DWORD offset = 0;
  132. PUCHAR buf = Buffer;
  133. while (Size > 0x10) {
  134. printf("%08x:"
  135. " %02x %02x %02x %02x %02x %02x %02x %02x"
  136. " %02x %02x %02x %02x %02x %02x %02x %02x"
  137. "\n",
  138. offset,
  139. *(buf + 0), *(buf + 1), *(buf + 2), *(buf + 3),
  140. *(buf + 4), *(buf + 5), *(buf + 6), *(buf + 7),
  141. *(buf + 8), *(buf + 9), *(buf + 10), *(buf + 11),
  142. *(buf + 12), *(buf + 13), *(buf + 14), *(buf + 15)
  143. );
  144. Size -= 0x10;
  145. offset += 0x10;
  146. buf += 0x10;
  147. }
  148. if (Size != 0) {
  149. DWORD spaceIt;
  150. printf("%08x:", offset);
  151. for (spaceIt = 0; Size != 0; Size--) {
  152. if ((spaceIt%8)==0) {
  153. printf(" "); // extra space every eight chars
  154. }
  155. printf(" %02x", *buf);
  156. spaceIt++;
  157. buf++;
  158. }
  159. printf("\n");
  160. }
  161. return;
  162. }
  163. BOOLEAN
  164. VerifyIsoImage(
  165. IN HANDLE IsoImageHandle,
  166. OUT PLONG NumberOfBlocks
  167. )
  168. {
  169. BY_HANDLE_FILE_INFORMATION isoImageInfo;
  170. if (!GetFileInformationByHandle(IsoImageHandle, &isoImageInfo)) {
  171. FPRINTF((OUTPUT, "Error %d getting file info for iso image\n",
  172. GetLastError()));
  173. return FALSE;
  174. }
  175. if (isoImageInfo.nFileSizeHigh != 0) {
  176. FPRINTF((OUTPUT, "Error: File too large\n"));
  177. SetLastError(ERROR_INVALID_DATA);
  178. return FALSE;
  179. }
  180. if ((isoImageInfo.nFileSizeLow % 2048) != 0) {
  181. FPRINTF((OUTPUT, "Error: The file size is not a multiple of 2048 (%I64d)\n",
  182. isoImageInfo.nFileSizeLow));
  183. SetLastError(ERROR_INVALID_DATA);
  184. return FALSE;
  185. }
  186. FPRINTF((OUTPUT, "File size is %d bytes (%d blocks)\n",
  187. isoImageInfo.nFileSizeLow,
  188. isoImageInfo.nFileSizeLow / 2048
  189. ));
  190. *NumberOfBlocks = isoImageInfo.nFileSizeLow / 2048;
  191. return TRUE;
  192. }
  193. BOOLEAN
  194. VerifyBlankMedia(
  195. IN HANDLE CdromHandle
  196. )
  197. {
  198. CDB cdb;
  199. PDISK_INFORMATION diskInfo;
  200. DWORD maxSize = sizeof(DISK_INFORMATION);
  201. DWORD size;
  202. FPRINTF((OUTPUT, "Verifying blank disc... "));
  203. diskInfo = LocalAlloc(LPTR, maxSize);
  204. if (diskInfo == NULL) {
  205. FPRINTF((OUTPUT, "\nError allocating diskinfo\n"));
  206. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  207. return FALSE;
  208. }
  209. RtlZeroMemory(diskInfo, sizeof(DISK_INFORMATION));
  210. RtlZeroMemory(&cdb, sizeof(CDB));
  211. cdb.READ_DISK_INFORMATION.OperationCode = SCSIOP_READ_DISK_INFORMATION;
  212. cdb.READ_DISK_INFORMATION.AllocationLength[0] = (UCHAR)(maxSize >> 8);
  213. cdb.READ_DISK_INFORMATION.AllocationLength[1] = (UCHAR)(maxSize & 0xff);
  214. size = maxSize;
  215. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  216. (PUCHAR)diskInfo, &size, TRUE)) {
  217. FPRINTF((OUTPUT, "\nError %d getting disk info\n",
  218. GetLastError()));
  219. LocalFree(diskInfo);
  220. return FALSE;
  221. }
  222. if (diskInfo->LastSessionStatus != 0x00) {
  223. FPRINTF((OUTPUT, "disc is not blank!\n"));
  224. SetLastError(ERROR_MEDIA_INCOMPATIBLE);
  225. LocalFree(diskInfo);
  226. return FALSE;
  227. }
  228. FPRINTF((OUTPUT, "pass.\n"));
  229. LocalFree(diskInfo);
  230. return TRUE;
  231. }
  232. BOOLEAN
  233. SetWriteModePage(
  234. IN HANDLE CdromHandle,
  235. IN BOOLEAN TestBurn,
  236. IN UCHAR WriteType,
  237. IN UCHAR MultiSession,
  238. IN UCHAR DataBlockType,
  239. IN UCHAR SessionFormat
  240. )
  241. {
  242. PCDVD_WRITE_PARAMETERS_PAGE params = NULL;
  243. MODE_PARAMETER_HEADER10 header;
  244. PMODE_PARAMETER_HEADER10 buffer;
  245. UCHAR mediumTypeCode;
  246. CDB cdb;
  247. DWORD bufferSize;
  248. DWORD maxSize;
  249. FPRINTF((OUTPUT, "Setting WriteParameters mode page... "));
  250. bufferSize = sizeof(MODE_PARAMETER_HEADER10);
  251. RtlZeroMemory(&header, sizeof(MODE_PARAMETER_HEADER10));
  252. RtlZeroMemory(&cdb, sizeof(CDB));
  253. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  254. cdb.MODE_SENSE10.PageCode = 0x5;
  255. cdb.MODE_SENSE10.Dbd = 1;
  256. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
  257. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
  258. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  259. (PUCHAR)&header, &bufferSize, TRUE)) {
  260. FPRINTF((OUTPUT, "\nError %d getting mode page 0x05 from device(1)\n",
  261. GetLastError()));
  262. return FALSE;
  263. }
  264. bufferSize =
  265. (header.ModeDataLength[0] << 8) +
  266. (header.ModeDataLength[1] & 0xff);
  267. bufferSize += 2; // sizeof area that tells the remaining size
  268. maxSize = bufferSize;
  269. buffer = LocalAlloc(LPTR, bufferSize);
  270. if (!buffer) {
  271. FPRINTF((OUTPUT, "\nError -- unable to alloc %d bytes for mode parameters page\n",
  272. bufferSize));
  273. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  274. return FALSE;
  275. }
  276. RtlZeroMemory(&cdb, sizeof(CDB));
  277. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  278. cdb.MODE_SENSE10.PageCode = 0x5;
  279. cdb.MODE_SENSE10.Dbd = 1;
  280. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
  281. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
  282. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  283. (PUCHAR)buffer, &bufferSize, TRUE)) {
  284. FPRINTF((OUTPUT, "\nError %d getting mode page 0x05 from device(2)\n",
  285. GetLastError()));
  286. LocalFree(buffer);
  287. return FALSE;
  288. }
  289. mediumTypeCode = buffer->MediumType;
  290. //
  291. // bufferSize now holds the amount of data returned
  292. // this should be enough...
  293. //
  294. {
  295. DWORD t =
  296. (buffer->BlockDescriptorLength[0] >> 8) +
  297. (buffer->BlockDescriptorLength[1] & 0xff);
  298. if (t != 0) {
  299. fprintf(stderr, "BlockDescriptor non-zero! (%x)\n", t);
  300. SetLastError(1);
  301. return FALSE;
  302. }
  303. }
  304. //
  305. // pointer arithmetic here. (buffer+1) points just past the
  306. // end of the mode_parameter_header10.
  307. //
  308. params = (PCDVD_WRITE_PARAMETERS_PAGE)(buffer + 1);
  309. FPRINTF((OUTPUT, "buffer = %p params = %p\n", buffer, params));
  310. //
  311. // zero the header, but don't modify any settings that don't
  312. // need to be modified!
  313. //
  314. RtlZeroMemory(buffer, FIELD_OFFSET(MODE_PARAMETER_HEADER10,
  315. BlockDescriptorLength[0]));
  316. buffer->ModeDataLength[0] = (UCHAR)((bufferSize-2) >> 8);
  317. buffer->ModeDataLength[1] = (UCHAR)((bufferSize-2) & 0xff);
  318. buffer->MediumType = mediumTypeCode;
  319. params->WriteType = WriteType;
  320. params->TestWrite = (TestBurn ? 0x01 : 0x00);
  321. params->Copy = 0x00; // original disc
  322. //params->TrackMode = 0x04; // control nibble in Q subchannel
  323. params->MultiSession = MultiSession;
  324. params->DataBlockType = DataBlockType;
  325. params->SessionFormat = SessionFormat;
  326. params->MediaCatalogNumberValid = 0x00;
  327. params->ISRCValid = 0x00;
  328. RtlZeroMemory(&cdb, sizeof(CDB));
  329. cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  330. cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR)(bufferSize >> 8);
  331. cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR)(bufferSize & 0xff);
  332. cdb.MODE_SELECT10.PFBit = 1;
  333. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  334. (PUCHAR)buffer, &bufferSize, FALSE)) {
  335. FPRINTF((OUTPUT, "\nError %d sending mode page 0x05 to device\n",
  336. GetLastError()));
  337. LocalFree(buffer);
  338. return FALSE;
  339. }
  340. LocalFree(buffer);
  341. FPRINTF((OUTPUT, "pass.\n"));
  342. return TRUE;
  343. }
  344. BOOLEAN
  345. GetNextWritableAddress(
  346. IN HANDLE CdromHandle,
  347. IN UCHAR Track,
  348. OUT PLONG NextWritableAddress,
  349. OUT PLONG AvailableBlocks
  350. )
  351. {
  352. CDB cdb;
  353. TRACK_INFORMATION trackInfo;
  354. DWORD size = sizeof(TRACK_INFORMATION);
  355. LONG nwa, available;
  356. *NextWritableAddress = (LONG)-1;
  357. *AvailableBlocks = (LONG)0;
  358. FPRINTF((OUTPUT, "Verifying track info... "));
  359. RtlZeroMemory(&cdb, sizeof(CDB));
  360. RtlZeroMemory(&trackInfo, sizeof(TRACK_INFORMATION));
  361. cdb.READ_TRACK_INFORMATION.OperationCode = SCSIOP_READ_TRACK_INFORMATION;
  362. cdb.READ_TRACK_INFORMATION.Track = 0x01;
  363. cdb.READ_TRACK_INFORMATION.BlockAddress[3] = Track;
  364. cdb.READ_TRACK_INFORMATION.AllocationLength[0] = (UCHAR)(size >> 8);
  365. cdb.READ_TRACK_INFORMATION.AllocationLength[1] = (UCHAR)(size & 0xff);
  366. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  367. (PUCHAR)&trackInfo, &size, TRUE)) {
  368. FPRINTF((OUTPUT, "\nError %d getting track info\n",
  369. GetLastError()));
  370. return FALSE;
  371. }
  372. if (!trackInfo.NWA_V) {
  373. FPRINTF((OUTPUT, "invalid NextWritableAddress -- may be invalid media?\n"));
  374. SetLastError(ERROR_MEDIA_INCOMPATIBLE);
  375. return FALSE;
  376. }
  377. nwa = (trackInfo.NextWritableAddress[0] << 24) |
  378. (trackInfo.NextWritableAddress[1] << 16) |
  379. (trackInfo.NextWritableAddress[2] << 8) |
  380. (trackInfo.NextWritableAddress[3] << 0);
  381. available = (trackInfo.FreeBlocks[0] << 24) |
  382. (trackInfo.FreeBlocks[1] << 16) |
  383. (trackInfo.FreeBlocks[2] << 8) |
  384. (trackInfo.FreeBlocks[3] << 0);
  385. FPRINTF((OUTPUT, "pass.\n"));
  386. *NextWritableAddress = nwa;
  387. *AvailableBlocks = available;
  388. return TRUE;
  389. }
  390. BOOLEAN
  391. SendOptimumPowerCalibration(
  392. IN HANDLE CdromHandle
  393. )
  394. {
  395. CDB cdb;
  396. DWORD size;
  397. FPRINTF((OUTPUT, "Setting OPC_INFORMATION..."));
  398. RtlZeroMemory(&cdb, sizeof(CDB));
  399. cdb.SEND_OPC_INFORMATION.OperationCode = SCSIOP_SEND_OPC_INFORMATION;
  400. cdb.SEND_OPC_INFORMATION.DoOpc = 1;
  401. size = 0;
  402. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  403. NULL, &size, TRUE)) {
  404. FPRINTF((OUTPUT, "\nFailed to send SET_OPC_INFORMATION (%d)\n",
  405. GetLastError()));
  406. return FALSE;
  407. }
  408. FPRINTF((OUTPUT, "pass.\n"));
  409. return TRUE;
  410. }
  411. BOOLEAN
  412. SetRecordingSpeed(
  413. IN HANDLE CdromHandle,
  414. IN DWORD Speed
  415. )
  416. {
  417. CDB cdb;
  418. DWORD size;
  419. DWORD kbSpeed;
  420. FPRINTF((OUTPUT, "Setting CD Speed..."));
  421. kbSpeed = MakeCdSpeed(Speed);
  422. RtlZeroMemory(&cdb, sizeof(CDB));
  423. cdb.SET_CD_SPEED.OperationCode = SCSIOP_SET_CD_SPEED;
  424. cdb.SET_CD_SPEED.ReadSpeed[0] = 0xff;
  425. cdb.SET_CD_SPEED.ReadSpeed[1] = 0xff;
  426. cdb.SET_CD_SPEED.WriteSpeed[0] = (UCHAR)(kbSpeed >> 8);
  427. cdb.SET_CD_SPEED.WriteSpeed[1] = (UCHAR)(kbSpeed & 0xff);
  428. size = 0;
  429. if (!SptSendCdbToDevice(CdromHandle, &cdb, 12,
  430. NULL, &size, TRUE)) {
  431. FPRINTF((OUTPUT, "\nFailed to send SET_CD_SPEED (%d)\n",
  432. GetLastError()));
  433. return FALSE;
  434. }
  435. FPRINTF((OUTPUT, "pass.\n"));
  436. return TRUE;
  437. }
  438. VOID
  439. WaitForReadDiscInfoToWork(
  440. IN HANDLE CdromHandle
  441. )
  442. {
  443. CDB cdb;
  444. DWORD size;
  445. DISK_INFORMATION diskInfo;
  446. DWORD i;
  447. //
  448. // loop using SCSIOP_READ_DISK_INFORMATION (0x51) since
  449. // that seems to fail for *ALL* drives until the drive is ready
  450. //
  451. for (i=0; ; i++) {
  452. size = sizeof(DISK_INFORMATION);
  453. RtlZeroMemory(&diskInfo, sizeof(DISK_INFORMATION));
  454. RtlZeroMemory(&cdb, sizeof(CDB));
  455. cdb.READ_DISK_INFORMATION.OperationCode = SCSIOP_READ_DISK_INFORMATION;
  456. cdb.READ_DISK_INFORMATION.AllocationLength[0] = (UCHAR)(size >> 8);
  457. cdb.READ_DISK_INFORMATION.AllocationLength[1] = (UCHAR)(size & 0xff);
  458. if (SptSendCdbToDevice(CdromHandle, &cdb, 10,
  459. (PUCHAR)&diskInfo, &size, TRUE)) {
  460. FPRINTF((OUTPUT, "ReadDiscInfo Succeeded! (%d seconds)\n", i));
  461. return;
  462. }
  463. // should verify the errors are valid errors (AllowedReadDiscInfo[])?
  464. // need to sleep here so we don't overload the unit!
  465. Sleep(1000); // one second
  466. }
  467. return;
  468. }
  469. BOOLEAN
  470. BurnThisSession(
  471. IN HANDLE CdromHandle,
  472. IN HANDLE IsoImageHandle,
  473. IN LONG NumberOfBlocks,
  474. IN LONG FirstLba
  475. )
  476. {
  477. DWORD bufferSize = 0x800 * 0x10;
  478. PUCHAR buffer = NULL;
  479. LONG currentBlock;
  480. FPRINTF((OUTPUT, "Starting write: "));
  481. buffer = LocalAlloc(LPTR, bufferSize);
  482. if (buffer == NULL) {
  483. FPRINTF((OUTPUT, "unable to allocate write buffer\n"));
  484. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  485. return FALSE;
  486. }
  487. FPRINTF((OUTPUT, "............."));
  488. for (currentBlock = 0; currentBlock < NumberOfBlocks + POST_GAP_SIZE; ) {
  489. CDB cdb;
  490. DWORD readSize;
  491. DWORD readBytes;
  492. {
  493. static CHAR progress[4] = { '|', '/', '-', '\\' };
  494. DWORD percent;
  495. percent = (currentBlock*1000) / (NumberOfBlocks+POST_GAP_SIZE);
  496. // # # # . # % _ d o n e _ *
  497. printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
  498. printf("%c %3d.%d%% done",
  499. progress[(currentBlock%0x40)/0x10],
  500. percent / 10, percent % 10
  501. );
  502. fflush(stdout);
  503. }
  504. if (NumberOfBlocks - currentBlock >= 0x10) {
  505. readSize = 0x800 * 0x10;
  506. } else if (NumberOfBlocks - currentBlock > 0) {
  507. readSize = (NumberOfBlocks - currentBlock) * 0x800;
  508. RtlZeroMemory(buffer, bufferSize);
  509. } else {
  510. readSize = 0;
  511. readBytes = 0;
  512. RtlZeroMemory(buffer, bufferSize);
  513. }
  514. if (readSize &&
  515. !ReadFile(IsoImageHandle, buffer, readSize, &readBytes, NULL)
  516. ) {
  517. FPRINTF((OUTPUT, "error reading from file %d\n", GetLastError()));
  518. LocalFree(buffer);
  519. return FALSE;
  520. }
  521. if (readBytes != readSize) {
  522. FPRINTF((OUTPUT, "error only read %d of %d bytes from file\n",
  523. readBytes, readSize));
  524. LocalFree(buffer);
  525. return FALSE;
  526. }
  527. {
  528. BOOL writeCompleted = FALSE;
  529. while (!writeCompleted) {
  530. BOOLEAN ignoreError;
  531. SENSE_DATA senseData;
  532. RtlZeroMemory(&senseData, sizeof(senseData));
  533. RtlZeroMemory(&cdb, sizeof(CDB));
  534. cdb.CDB10.OperationCode = SCSIOP_WRITE;
  535. cdb.CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&currentBlock)->Byte3;
  536. cdb.CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&currentBlock)->Byte2;
  537. cdb.CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&currentBlock)->Byte1;
  538. cdb.CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&currentBlock)->Byte0;
  539. if ((currentBlock + 0x10) <= (NumberOfBlocks + POST_GAP_SIZE)) {
  540. cdb.CDB10.TransferBlocksLsb = 0x10;
  541. } else {
  542. cdb.CDB10.TransferBlocksLsb =
  543. (UCHAR)(NumberOfBlocks + POST_GAP_SIZE - currentBlock);
  544. }
  545. writeCompleted = SptSendCdbToDeviceEx(CdromHandle,
  546. &cdb,
  547. 10,
  548. buffer,
  549. &bufferSize,
  550. &senseData,
  551. sizeof(SENSE_DATA),
  552. FALSE,
  553. 50 // timeout seconds
  554. );
  555. ignoreError = IsSenseDataInTable(AllowedBurnSense,
  556. AllowedBurnSenseEntries,
  557. &senseData);
  558. if ((!writeCompleted) && ignoreError) {
  559. printf("Continuing on %x/%x/%x\n",
  560. senseData.SenseKey & 0xf,
  561. senseData.AdditionalSenseCode,
  562. senseData.AdditionalSenseCodeQualifier
  563. );
  564. Sleep(100); // 100ms == .1 seconds
  565. }
  566. if (!writeCompleted && !ignoreError) {
  567. FPRINTF((OUTPUT, "\nError %d in writing LBA 0x%x\n",
  568. GetLastError(), currentBlock));
  569. LocalFree(buffer);
  570. return FALSE;
  571. }
  572. } // while(!writeCompleted) loop
  573. } // random block to have local variable writeCompleted
  574. // write completed success, so continue.
  575. currentBlock += 0x10;
  576. }
  577. printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
  578. LocalFree(buffer);
  579. printf("Finished Writing\nSynchronizing Cache: ");
  580. fflush(stdout);
  581. //
  582. // do the FLUSH_CACHE immediate
  583. //
  584. {
  585. DWORD size;
  586. CDB cdb;
  587. RtlZeroMemory(&cdb, sizeof(CDB));
  588. cdb.SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
  589. cdb.SYNCHRONIZE_CACHE10.Immediate = 1;
  590. size = 0;
  591. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  592. NULL, &size, TRUE)) {
  593. FPRINTF((OUTPUT, "\nError %d Synchronizing Cache\n",
  594. GetLastError()));
  595. return FALSE;
  596. }
  597. }
  598. WaitForReadDiscInfoToWork(CdromHandle);
  599. return TRUE;
  600. }
  601. BOOLEAN
  602. CloseTrack(
  603. IN HANDLE CdromHandle,
  604. IN LONG Track
  605. )
  606. {
  607. CDB cdb;
  608. DWORD size;
  609. FPRINTF((OUTPUT, "Closing the track..."));
  610. if (Track > 0xffff) {
  611. SetLastError(ERROR_INVALID_PARAMETER);
  612. return FALSE;
  613. }
  614. RtlZeroMemory(&cdb, sizeof(CDB));
  615. cdb.CLOSE_TRACK.OperationCode = SCSIOP_CLOSE_TRACK_SESSION;
  616. cdb.CLOSE_TRACK.Immediate = 0;
  617. cdb.CLOSE_TRACK.Track = 1;
  618. cdb.CLOSE_TRACK.Session = 0;
  619. cdb.CLOSE_TRACK.TrackNumber[0] = (UCHAR)(Track >> 8);
  620. cdb.CLOSE_TRACK.TrackNumber[1] = (UCHAR)(Track & 0xff);
  621. size = 0;
  622. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  623. NULL, &size, TRUE)) {
  624. FPRINTF((OUTPUT, "\nError %d Closing Track\n",
  625. GetLastError()));
  626. return FALSE;
  627. }
  628. WaitForReadDiscInfoToWork(CdromHandle);
  629. FPRINTF((OUTPUT, "pass.\n"));
  630. return TRUE;
  631. }
  632. BOOLEAN
  633. CloseSession(
  634. IN HANDLE CdromHandle
  635. )
  636. {
  637. CDB cdb;
  638. DWORD size;
  639. FPRINTF((OUTPUT, "Closing the disc..."));
  640. RtlZeroMemory(&cdb, sizeof(CDB));
  641. cdb.CLOSE_TRACK.OperationCode = SCSIOP_CLOSE_TRACK_SESSION;
  642. cdb.CLOSE_TRACK.Immediate = 1;
  643. cdb.CLOSE_TRACK.Track = 0;
  644. cdb.CLOSE_TRACK.Session = 1;
  645. size = 0;
  646. if (!SptSendCdbToDeviceEx(CdromHandle,
  647. &cdb,
  648. 10,
  649. NULL,
  650. &size,
  651. NULL,
  652. 0,
  653. TRUE,
  654. 240)) { // four minutes to close session
  655. FPRINTF((OUTPUT, "\nError %d Synchronizing Cache\n",
  656. GetLastError()));
  657. return FALSE;
  658. }
  659. WaitForReadDiscInfoToWork(CdromHandle);
  660. FPRINTF((OUTPUT, "pass.\n"));
  661. return TRUE;
  662. }
  663. BOOLEAN
  664. SendStartStopUnit(
  665. IN HANDLE CdromHandle,
  666. IN BOOLEAN Start,
  667. IN BOOLEAN Eject
  668. )
  669. {
  670. CDB cdb;
  671. DWORD size;
  672. RtlZeroMemory(&cdb, sizeof(CDB));
  673. cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  674. cdb.START_STOP.LoadEject = Eject;
  675. cdb.START_STOP.Start = Start;
  676. size = 0;
  677. if (!SptSendCdbToDevice(CdromHandle, &cdb, 6,
  678. NULL, &size, TRUE)) {
  679. return FALSE;
  680. }
  681. return TRUE;
  682. }
  683. /*
  684. ERROR_BAD_COMMAND
  685. ERROR_INVALID_DATA
  686. ERROR_INVALID_PARAMETER
  687. ERROR_MEDIA_INCOMPATIBLE
  688. ERROR_NOT_ENOUGH_MEMORY
  689. ERROR_OUTOFMEMORY
  690. */
  691. /*++
  692. Routine Description:
  693. burns an ISO image to cdrom
  694. Arguments:
  695. CdromHandle - a file handle to send the ioctl to
  696. argc - the number of additional arguments (2)
  697. Return Value:
  698. ERROR_SUCCESS if successful
  699. The value of GetLastError() from the point of failure
  700. --*/
  701. DWORD
  702. BurnCommand(
  703. HANDLE CdromHandle,
  704. HANDLE IsoImageHandle,
  705. HACK_FLAGS HackFlags
  706. )
  707. {
  708. LONG numberOfBlocks;
  709. LONG availableBlocks;
  710. LONG firstLba;
  711. LONG i;
  712. ////////////////////////////////////////////////////////////////////////////////
  713. // verify the iso image file looks correct
  714. ////////////////////////////////////////////////////////////////////////////////
  715. if (!VerifyIsoImage(IsoImageHandle, &numberOfBlocks)) {
  716. printf("Error verifying ISO image\n");
  717. return GetLastError();
  718. }
  719. ////////////////////////////////////////////////////////////////////////////////
  720. // verify (as best as possible) that it's blank media
  721. ////////////////////////////////////////////////////////////////////////////////
  722. if (!VerifyBlankMedia(CdromHandle)) {
  723. printf("Error verifying blank media\n");
  724. return GetLastError();
  725. }
  726. ////////////////////////////////////////////////////////////////////////////////
  727. // Setup the write mode page
  728. ////////////////////////////////////////////////////////////////////////////////
  729. if (!SetWriteModePage(CdromHandle,
  730. (BOOLEAN)HackFlags.TestBurn,
  731. 0x01, // track-at-once
  732. 0x03, // we close the session/disc ourselves
  733. 0x08, // 0x08 == Mode 1 (ISO/IEC 10149 == 2048 bytes)
  734. // 0x0a == Mode 2 (CDROM XA, Form 1, 2048 bytes)
  735. 0x00 // 0x00 == CD-DA, CD-ROM, or other data disc
  736. // 0x20 == CDROM XA
  737. )) {
  738. printf("Error setting write mode page\n");
  739. if (!HackFlags.IgnoreModePageErrors) {
  740. return GetLastError();
  741. } else {
  742. printf("Ignoring error and attempting to continue...\n");
  743. }
  744. }
  745. ////////////////////////////////////////////////////////////////////////////////
  746. // get next writable address
  747. ////////////////////////////////////////////////////////////////////////////////
  748. if (!GetNextWritableAddress(CdromHandle, 0x01, &firstLba, &availableBlocks)) {
  749. printf("Error verifying next writable address\n");
  750. return GetLastError();
  751. }
  752. if (availableBlocks < numberOfBlocks) {
  753. printf("Error verifying free blocks on media (%d needed, %d available)\n",
  754. numberOfBlocks, availableBlocks);
  755. SetLastError(ERROR_MEDIA_INCOMPATIBLE);
  756. return GetLastError();
  757. }
  758. if (firstLba != 0) {
  759. printf("Error verifying next writable address is zero\n");
  760. SetLastError(ERROR_MEDIA_INCOMPATIBLE);
  761. return GetLastError();
  762. }
  763. ////////////////////////////////////////////////////////////////////////////////
  764. // set the cd speed to four for now, can later make a cmd-line switch
  765. ////////////////////////////////////////////////////////////////////////////////
  766. if (!SetRecordingSpeed(CdromHandle, 4)) {
  767. printf("Error setting the cd speed to %d\n", 4);
  768. return GetLastError();
  769. }
  770. ////////////////////////////////////////////////////////////////////////////////
  771. // calibrate the drive's power -- this is optional, so let it fail!
  772. ////////////////////////////////////////////////////////////////////////////////
  773. if (!SendOptimumPowerCalibration(CdromHandle)) {
  774. printf("WARNING: setting optimum power calibration failed\n");
  775. //return GetLastError();
  776. }
  777. ////////////////////////////////////////////////////////////////////////////////
  778. // start writing
  779. ////////////////////////////////////////////////////////////////////////////////
  780. if (!BurnThisSession(CdromHandle, IsoImageHandle, numberOfBlocks, firstLba)) {
  781. printf("Error burning ISO image\n");
  782. return GetLastError();
  783. }
  784. ////////////////////////////////////////////////////////////////////////////////
  785. // close the track -- ignore failures
  786. ////////////////////////////////////////////////////////////////////////////////
  787. if (!CloseTrack(CdromHandle, 0)) {
  788. printf("WARNING: error closing the track -- may be ignored?\n");
  789. //return GetLastError();
  790. }
  791. ////////////////////////////////////////////////////////////////////////////////
  792. // close the session
  793. ////////////////////////////////////////////////////////////////////////////////
  794. if (!CloseSession(CdromHandle)) {
  795. printf("Error closing session\n");
  796. return GetLastError();
  797. }
  798. ////////////////////////////////////////////////////////////////////////////////
  799. // eject the newly burned cd!
  800. ////////////////////////////////////////////////////////////////////////////////
  801. if (!SendStartStopUnit(CdromHandle, FALSE, TRUE) ||
  802. !SendStartStopUnit(CdromHandle, TRUE, TRUE)) {
  803. printf("Error ejecting/reinserting disc\n");
  804. return GetLastError();
  805. }
  806. printf("burn successful!\n");
  807. return 0;
  808. }