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.

878 lines
24 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 <sptlib.h>
  18. #include "burn.h"
  19. #include <winioctl.h>
  20. #define MIN_WRITE_SECTORS (0x10)
  21. #if DBG
  22. #define OUTPUT stdout
  23. #define FPRINTF(x) fprintf x
  24. #define PRINTBUFFER(x) PrintBuffer x
  25. #else
  26. #define OUTPUT stdout
  27. #define FPRINTF(x)
  28. #define PRINTBUFFER(x)
  29. #endif
  30. typedef struct _SENSE_STUFF {
  31. UCHAR Sense;
  32. UCHAR Asc;
  33. UCHAR Ascq;
  34. UCHAR Reserved;
  35. } SENSE_STUFF, *PSENSE_STUFF;
  36. SENSE_STUFF AllowedBurnSense[] = {
  37. {SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS, 0},
  38. {SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_OPERATION_IN_PROGRESS, 0}
  39. };
  40. #define AllowedBurnSenseEntries (sizeof(AllowedBurnSense)/sizeof(SENSE_STUFF))
  41. SENSE_STUFF AllowedReadDiscInfo[] = {
  42. { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_OPERATION_IN_PROGRESS, 0 },
  43. { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS, 0 },
  44. { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_FORMAT_IN_PROGRESS, 0 },
  45. { SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_ILLEGAL_MODE_FOR_THIS_TRACK, 0, 0 },
  46. { SCSI_SENSE_UNIT_ATTENTION, SCSI_ADSENSE_INSUFFICIENT_TIME_FOR_OPERATION, 0, 0 }
  47. };
  48. #define AllowedReadDiscInfoEntries (sizeof(AllowedReadDiscInfo)/sizeof(SENSE_STUFF))
  49. BOOLEAN
  50. IsSenseDataInTable(
  51. IN PSENSE_STUFF Table,
  52. IN LONG Entries, // in table
  53. IN PSENSE_DATA SenseData
  54. )
  55. {
  56. LONG i;
  57. UCHAR sense = SenseData->SenseKey & 0xf;
  58. UCHAR asc = SenseData->AdditionalSenseCode;
  59. UCHAR ascq = SenseData->AdditionalSenseCodeQualifier;
  60. for (i = 0; i < Entries; i++ ) {
  61. if ((Table[i].Sense = sense) &&
  62. (Table[i].Ascq = ascq ) &&
  63. (Table[i].Asc = asc )
  64. ) {
  65. return TRUE;
  66. }
  67. }
  68. return FALSE;
  69. }
  70. int __cdecl main(int argc, char *argv[])
  71. {
  72. int i = 0;
  73. HANDLE cdromHandle;
  74. HANDLE isoImageHandle;
  75. char buffer[32];
  76. DWORD Foo;
  77. BOOLEAN Erase = FALSE;
  78. if(argc < 3) {
  79. printf("Usage: burn <drive> <image> [/Erase]\n");
  80. return -1;
  81. }
  82. if (argc == 4) {
  83. if (!strncmp( "/E", argv[3], 2)) {
  84. Erase = TRUE;
  85. }
  86. else {
  87. printf("Unrecognized switch\n");
  88. return -1;
  89. }
  90. }
  91. sprintf(buffer, "\\\\.\\%s", argv[1]);
  92. cdromHandle = CreateFile(buffer,
  93. GENERIC_READ | GENERIC_WRITE,
  94. FILE_SHARE_READ | FILE_SHARE_WRITE,
  95. NULL,
  96. OPEN_EXISTING,
  97. FILE_ATTRIBUTE_NORMAL,
  98. NULL);
  99. if(cdromHandle == INVALID_HANDLE_VALUE) {
  100. printf("Error %d opening device %s\n", GetLastError(), buffer);
  101. return -2;
  102. }
  103. if (!DeviceIoControl( cdromHandle,
  104. FSCTL_LOCK_VOLUME,
  105. NULL, 0,
  106. NULL, 0,
  107. &Foo,
  108. NULL)) {
  109. printf("Error %d locking volume\n", GetLastError());
  110. }
  111. else {
  112. printf("Locked volume for burn\n");
  113. }
  114. isoImageHandle = CreateFile(argv[2],
  115. GENERIC_READ,
  116. FILE_SHARE_READ,
  117. NULL,
  118. OPEN_EXISTING,
  119. FILE_FLAG_SEQUENTIAL_SCAN,
  120. NULL);
  121. if (isoImageHandle == INVALID_HANDLE_VALUE) {
  122. printf("Error %d opening image file %s\n",
  123. GetLastError(), argv[2]);
  124. CloseHandle(cdromHandle);
  125. return -2;
  126. }
  127. BurnCommand(cdromHandle, isoImageHandle, Erase);
  128. CloseHandle(isoImageHandle);
  129. CloseHandle(cdromHandle);
  130. return 0;
  131. }
  132. /*++
  133. Routine Description:
  134. burns an ISO image to cdrom
  135. Arguments:
  136. CdromHandle - a file handle to send the ioctl to
  137. argc - the number of additional arguments (2)
  138. Return Value:
  139. ERROR_SUCCESS if successful
  140. The value of GetLastError() from the point of failure
  141. --*/
  142. DWORD
  143. BurnCommand(
  144. HANDLE CdromHandle,
  145. HANDLE IsoImageHandle,
  146. BOOLEAN Erase
  147. )
  148. {
  149. DWORD numberOfBlocks;
  150. DWORD availableBlocks;
  151. DWORD nwa;
  152. LONG i;
  153. ////////////////////////////////////////////////////////////////////////////////
  154. // verify the iso image file looks correct
  155. ////////////////////////////////////////////////////////////////////////////////
  156. if (!VerifyIsoImage(IsoImageHandle, &numberOfBlocks)) {
  157. printf("Error verifying ISO image\n");
  158. return GetLastError();
  159. }
  160. ////////////////////////////////////////////////////////////////////////////////
  161. // verify (as best as possible) that it's blank media
  162. ////////////////////////////////////////////////////////////////////////////////
  163. if (Erase && !EraseMedia(CdromHandle)) {
  164. printf("Error erasing media\n");
  165. return GetLastError();
  166. }
  167. if (!VerifyBlankMedia(CdromHandle)) {
  168. printf("Error verifying blank media\n");
  169. return GetLastError();
  170. }
  171. ////////////////////////////////////////////////////////////////////////////////
  172. // verify media capacity
  173. ////////////////////////////////////////////////////////////////////////////////
  174. if (!VerifyMediaCapacity(CdromHandle, numberOfBlocks)) {
  175. printf("Error verifying media capacity\n");
  176. return GetLastError();
  177. }
  178. ////////////////////////////////////////////////////////////////////////////////
  179. // DVD-R does not require mode page changes, -RW does, try anyway.
  180. ////////////////////////////////////////////////////////////////////////////////
  181. if (!SetWriteModePageDao(CdromHandle)) {
  182. printf("Error setting DAO (Required for -RW only) - ignoring.\n");
  183. }
  184. ////////////////////////////////////////////////////////////////////////////////
  185. // send the time stamp
  186. ////////////////////////////////////////////////////////////////////////////////
  187. if (!SendTimeStamp(CdromHandle, "20010614000000")) { // YYYYMMDDHHMMSS format
  188. printf("Error setting timestamp - ignoring\n");
  189. }
  190. ////////////////////////////////////////////////////////////////////////////////
  191. // optionally, send the User Specific Data
  192. ////////////////////////////////////////////////////////////////////////////////
  193. ////////////////////////////////////////////////////////////////////////////////
  194. // Reserve the RZone for this burn
  195. ////////////////////////////////////////////////////////////////////////////////
  196. if (!ReserveRZone(CdromHandle, numberOfBlocks)) {
  197. printf("Error reserving zone for burn\n");
  198. return GetLastError();
  199. }
  200. ////////////////////////////////////////////////////////////////////////////////
  201. // get NWA via Read RZone Informationcommand, specifying RZone 1 for blank disk
  202. ////////////////////////////////////////////////////////////////////////////////
  203. // Special case -- blank disc is always zero
  204. nwa = 0;
  205. ////////////////////////////////////////////////////////////////////////////////
  206. // start writing
  207. ////////////////////////////////////////////////////////////////////////////////
  208. if (!BurnThisSession(CdromHandle, IsoImageHandle, numberOfBlocks, nwa)) {
  209. printf("Error burning ISO image\n");
  210. return GetLastError();
  211. }
  212. ////////////////////////////////////////////////////////////////////////////////
  213. // wait for it to finish
  214. ////////////////////////////////////////////////////////////////////////////////
  215. if (!WaitForBurnToComplete(CdromHandle)) {
  216. printf("Error waiting for burn to complete\n");
  217. return GetLastError();
  218. }
  219. ////////////////////////////////////////////////////////////////////////////////
  220. // eject the newly burned dvd!
  221. ////////////////////////////////////////////////////////////////////////////////
  222. if (!SendStartStopUnit(CdromHandle, FALSE, TRUE) ||
  223. !SendStartStopUnit(CdromHandle, TRUE, TRUE)) {
  224. printf("Error ejecting/reinserting disc\n");
  225. return GetLastError();
  226. }
  227. printf("burn successful!\n");
  228. return 0;
  229. }
  230. BOOLEAN
  231. BurnThisSession(
  232. IN HANDLE CdromHandle,
  233. IN HANDLE IsoImageHandle,
  234. IN DWORD NumberOfBlocks,
  235. IN DWORD FirstLba
  236. )
  237. {
  238. DWORD bufferSize = 0x800 * MIN_WRITE_SECTORS; // sixteen blocks per...
  239. PUCHAR buffer = NULL;
  240. DWORD i;
  241. FPRINTF((OUTPUT, "Starting write: "));
  242. buffer = LocalAlloc(LPTR, bufferSize);
  243. if (buffer == NULL) {
  244. FPRINTF((OUTPUT, "unable to allocate write buffer\n"));
  245. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  246. return FALSE;
  247. }
  248. FPRINTF((OUTPUT, "............."));
  249. for (i = 0; i < NumberOfBlocks; i += MIN_WRITE_SECTORS) {
  250. CDB cdb;
  251. DWORD currentSize;
  252. DWORD readBytes;
  253. DWORD j;
  254. SENSE_DATA senseData;
  255. {
  256. static CHAR progress[4] = { '|', '/', '-', '\\' };
  257. DWORD percent;
  258. percent = (i*1000) / NumberOfBlocks;
  259. // # # # . # % _ d o n e _ *
  260. printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
  261. printf("%c %3d.%d%% done",
  262. progress[(i%0x40)/0x10],
  263. percent / 10, percent % 10
  264. );
  265. fflush(stdout);
  266. }
  267. RtlZeroMemory(buffer, bufferSize);
  268. if (NumberOfBlocks - i >= MIN_WRITE_SECTORS) {
  269. currentSize = 0x800 * 0x10;
  270. } else if (NumberOfBlocks - i > 0) {
  271. // end of file case -- zero memory first!
  272. RtlZeroMemory(buffer, bufferSize);
  273. currentSize = (NumberOfBlocks - i) * 0x800;
  274. } else {
  275. FPRINTF((OUTPUT, "INTERNAL ERROR line %d\n", __LINE__));
  276. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  277. LocalFree(buffer);
  278. return FALSE;
  279. }
  280. if (!ReadFile(IsoImageHandle, buffer, currentSize, &readBytes, NULL)) {
  281. FPRINTF((OUTPUT, "error reading from file %d\n", GetLastError()));
  282. LocalFree(buffer);
  283. return FALSE;
  284. }
  285. if (readBytes != currentSize) {
  286. FPRINTF((OUTPUT, "error only read %d of %d bytes\n",
  287. readBytes, currentSize));
  288. LocalFree(buffer);
  289. return FALSE;
  290. }
  291. //
  292. // must write the full buffer each time for DVD-R,
  293. // since it's a RESTRICTED_OVERWRITE medium and seems
  294. // to choke otherwise
  295. //
  296. j = 0;
  297. retryThisWrite:
  298. RtlZeroMemory(&senseData, sizeof(SENSE_DATA));
  299. RtlZeroMemory(&cdb, sizeof(CDB));
  300. cdb.CDB10.OperationCode = SCSIOP_WRITE;
  301. cdb.CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&i)->Byte3;
  302. cdb.CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&i)->Byte2;
  303. cdb.CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&i)->Byte1;
  304. cdb.CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&i)->Byte0;
  305. cdb.CDB10.TransferBlocksLsb = MIN_WRITE_SECTORS;
  306. //
  307. // NOTE: we always send full buffer size to ensure 32k alignment
  308. //
  309. if (!SptSendCdbToDeviceEx(CdromHandle,
  310. &cdb,
  311. 10,
  312. buffer,
  313. &bufferSize,
  314. &senseData,
  315. sizeof(SENSE_DATA),
  316. FALSE,
  317. 10)) {
  318. Sleep(100); // 100ms == .1 seconds
  319. if (IsSenseDataInTable(AllowedBurnSense,
  320. AllowedBurnSenseEntries,
  321. &senseData)
  322. ) {
  323. // just sleep a bit...
  324. goto retryThisWrite;
  325. } else if (j<4) {
  326. j++;
  327. FPRINTF((OUTPUT, "Retrying write to LBA 0x%x\n", i));
  328. goto retryThisWrite;
  329. }
  330. FPRINTF((OUTPUT, "\nError %d in writing LBA 0x%x (%x times)\n",
  331. GetLastError(), i, j));
  332. LocalFree(buffer);
  333. return FALSE;
  334. }
  335. }
  336. printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
  337. printf("Finished Writing\n");
  338. fflush(stdout);
  339. LocalFree(buffer);
  340. return TRUE;
  341. }
  342. VOID
  343. PrintBuffer(
  344. IN PVOID Buffer,
  345. IN DWORD Size
  346. )
  347. {
  348. DWORD offset = 0;
  349. PUCHAR buf = Buffer;
  350. while (Size > 0x10) {
  351. printf("%08x:"
  352. " %02x %02x %02x %02x %02x %02x %02x %02x"
  353. " %02x %02x %02x %02x %02x %02x %02x %02x"
  354. "\n",
  355. offset,
  356. *(buf + 0), *(buf + 1), *(buf + 2), *(buf + 3),
  357. *(buf + 4), *(buf + 5), *(buf + 6), *(buf + 7),
  358. *(buf + 8), *(buf + 9), *(buf + 10), *(buf + 11),
  359. *(buf + 12), *(buf + 13), *(buf + 14), *(buf + 15)
  360. );
  361. Size -= 0x10;
  362. offset += 0x10;
  363. buf += 0x10;
  364. }
  365. if (Size != 0) {
  366. DWORD spaceIt;
  367. printf("%08x:", offset);
  368. for (spaceIt = 0; Size != 0; Size--) {
  369. if ((spaceIt%8)==0) {
  370. printf(" "); // extra space every eight chars
  371. }
  372. printf(" %02x", *buf);
  373. spaceIt++;
  374. buf++;
  375. }
  376. printf("\n");
  377. }
  378. return;
  379. }
  380. BOOLEAN
  381. EraseMedia(
  382. IN HANDLE CdromHandle
  383. )
  384. {
  385. CDB cdb;
  386. DWORD bufferSize;
  387. printf( "Attempting to blank media...\n");
  388. RtlZeroMemory(&cdb, sizeof(CDB));
  389. cdb.AsByte[0] = 0xa1;
  390. cdb.AsByte[1] = 0x01; // minimal blank
  391. bufferSize = 0;
  392. if (!SptSendCdbToDevice(CdromHandle, &cdb, 12,
  393. NULL, &bufferSize, TRUE)) {
  394. FPRINTF((OUTPUT, "\nError %d blanking media\n",
  395. GetLastError()));
  396. return FALSE;
  397. }
  398. return TRUE;
  399. }
  400. BOOLEAN
  401. SetWriteModePageDao(
  402. IN HANDLE CdromHandle
  403. )
  404. {
  405. PCDVD_WRITE_PARAMETERS_PAGE params = NULL;
  406. MODE_PARAMETER_HEADER10 header;
  407. PMODE_PARAMETER_HEADER10 buffer;
  408. UCHAR mediumTypeCode;
  409. CDB cdb;
  410. DWORD bufferSize;
  411. DWORD maxSize;
  412. FPRINTF((OUTPUT, "Setting DAO mode in WriteParameters mode page... "));
  413. bufferSize = sizeof(MODE_PARAMETER_HEADER10);
  414. RtlZeroMemory(&header, sizeof(MODE_PARAMETER_HEADER10));
  415. RtlZeroMemory(&cdb, sizeof(CDB));
  416. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  417. cdb.MODE_SENSE10.PageCode = 0x5;
  418. cdb.MODE_SENSE10.Dbd = 1;
  419. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
  420. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
  421. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  422. (PUCHAR)&header, &bufferSize, TRUE)) {
  423. FPRINTF((OUTPUT, "\nError %d getting mode page 0x05 from device(1)\n",
  424. GetLastError()));
  425. return FALSE;
  426. }
  427. bufferSize =
  428. (header.ModeDataLength[0] << 8) +
  429. (header.ModeDataLength[1] & 0xff);
  430. bufferSize += 2; // sizeof area that tells the remaining size
  431. maxSize = bufferSize;
  432. buffer = LocalAlloc(LPTR, bufferSize);
  433. if (!buffer) {
  434. FPRINTF((OUTPUT, "\nError -- unable to alloc %d bytes for mode parameters page\n",
  435. bufferSize));
  436. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  437. return FALSE;
  438. }
  439. RtlZeroMemory(&cdb, sizeof(CDB));
  440. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  441. cdb.MODE_SENSE10.PageCode = 0x5;
  442. cdb.MODE_SENSE10.Dbd = 1;
  443. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
  444. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
  445. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  446. (PUCHAR)buffer, &bufferSize, TRUE)) {
  447. FPRINTF((OUTPUT, "\nError %d getting mode page 0x05 from device(2)\n",
  448. GetLastError()));
  449. LocalFree(buffer);
  450. return FALSE;
  451. }
  452. mediumTypeCode = buffer->MediumType;
  453. //
  454. // bufferSize now holds the amount of data returned
  455. // this should be enough...
  456. //
  457. {
  458. DWORD t =
  459. (buffer->BlockDescriptorLength[0] >> 8) +
  460. (buffer->BlockDescriptorLength[1] & 0xff);
  461. if (t != 0) {
  462. fprintf(stderr, "BlockDescriptor non-zero! (%x)\n", t);
  463. SetLastError(1);
  464. return FALSE;
  465. }
  466. }
  467. //
  468. // pointer arithmetic here. (buffer+1) points just past the
  469. // end of the mode_parameter_header10.
  470. //
  471. params = (PCDVD_WRITE_PARAMETERS_PAGE)(buffer + 1);
  472. FPRINTF((OUTPUT, "buffer = %p params = %p\n", buffer, params));
  473. //
  474. // zero the header, but don't modify any settings that don't
  475. // need to be modified!
  476. //
  477. RtlZeroMemory(buffer, FIELD_OFFSET(MODE_PARAMETER_HEADER10,
  478. BlockDescriptorLength[0]));
  479. buffer->ModeDataLength[0] = (UCHAR)((bufferSize-2) >> 8);
  480. buffer->ModeDataLength[1] = (UCHAR)((bufferSize-2) & 0xff);
  481. buffer->MediumType = mediumTypeCode;
  482. params->WriteType = 2; // DAO
  483. params->TestWrite = 0x00;
  484. params->Copy = 0x00; // original disc
  485. params->MultiSession = 0;
  486. params->BufferUnderrunFree = 1;
  487. RtlZeroMemory(&cdb, sizeof(CDB));
  488. cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  489. cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR)(bufferSize >> 8);
  490. cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR)(bufferSize & 0xff);
  491. cdb.MODE_SELECT10.PFBit = 1;
  492. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  493. (PUCHAR)buffer, &bufferSize, FALSE)) {
  494. FPRINTF((OUTPUT, "\nError %d sending mode page 0x05 to device - ignoring\n",
  495. GetLastError()));
  496. LocalFree(buffer);
  497. return TRUE;
  498. }
  499. LocalFree(buffer);
  500. FPRINTF((OUTPUT, "pass.\n"));
  501. return TRUE;
  502. }
  503. BOOLEAN
  504. ReserveRZone(
  505. IN HANDLE CdromHandle,
  506. IN DWORD numberOfBlocks
  507. )
  508. {
  509. CDB cdb;
  510. DWORD size = 0;
  511. FPRINTF((OUTPUT, "Reserving RZone... "));
  512. if (numberOfBlocks % MIN_WRITE_SECTORS) {
  513. FPRINTF((OUTPUT, "increasing size by 0x%x blocks... ",
  514. MIN_WRITE_SECTORS - (numberOfBlocks % MIN_WRITE_SECTORS)));
  515. numberOfBlocks /= MIN_WRITE_SECTORS;
  516. numberOfBlocks *= MIN_WRITE_SECTORS;
  517. numberOfBlocks += MIN_WRITE_SECTORS;
  518. }
  519. RtlZeroMemory(&cdb, sizeof(CDB));
  520. cdb.RESERVE_TRACK_RZONE.OperationCode = SCSIOP_RESERVE_TRACK_RZONE;
  521. cdb.RESERVE_TRACK_RZONE.ReservationSize[0] = (UCHAR)(numberOfBlocks >> 24);
  522. cdb.RESERVE_TRACK_RZONE.ReservationSize[1] = (UCHAR)(numberOfBlocks >> 16);
  523. cdb.RESERVE_TRACK_RZONE.ReservationSize[2] = (UCHAR)(numberOfBlocks >> 8);
  524. cdb.RESERVE_TRACK_RZONE.ReservationSize[3] = (UCHAR)(numberOfBlocks >> 0);
  525. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  526. NULL, &size, TRUE)) {
  527. FPRINTF((OUTPUT, "Error reserving RZone\n"));
  528. return FALSE;
  529. }
  530. FPRINTF((OUTPUT, "pass.\n"));
  531. return TRUE;
  532. }
  533. BOOLEAN
  534. SendStartStopUnit(
  535. IN HANDLE CdromHandle,
  536. IN BOOLEAN Start,
  537. IN BOOLEAN Eject
  538. )
  539. {
  540. CDB cdb;
  541. DWORD size = 0;
  542. RtlZeroMemory(&cdb, sizeof(CDB));
  543. cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  544. cdb.START_STOP.LoadEject = Eject;
  545. cdb.START_STOP.Start = Start;
  546. if (!SptSendCdbToDevice(CdromHandle, &cdb, 6,
  547. NULL, &size, TRUE)) {
  548. FPRINTF((OUTPUT, "Error sending Start/Stop unit\n"));
  549. return FALSE;
  550. }
  551. return TRUE;
  552. }
  553. BOOLEAN
  554. SendTimeStamp(
  555. IN HANDLE CdromHandle,
  556. IN PUCHAR DateString
  557. )
  558. {
  559. CDB cdb;
  560. SEND_DVD_STRUCTURE_TIMESTAMP timeStamp;
  561. DWORD size;
  562. size = sizeof(SEND_DVD_STRUCTURE_TIMESTAMP);
  563. FPRINTF((OUTPUT, "Sending Timestamp... "));
  564. RtlZeroMemory(&cdb, sizeof(CDB));
  565. cdb.AsByte[0] = 0xbf;
  566. cdb.AsByte[7] = 0x0f; // format == time stamp
  567. cdb.AsByte[8] = (UCHAR)(size >> 8);
  568. cdb.AsByte[9] = (UCHAR)(size & 0xff);
  569. RtlZeroMemory(&timeStamp, sizeof(SEND_DVD_STRUCTURE_TIMESTAMP));
  570. if (strlen(DateString) != 14) {
  571. FPRINTF((OUTPUT, "Incorrect string length for date\n"));
  572. SetLastError(ERROR_INVALID_DATA);
  573. return FALSE;
  574. }
  575. RtlCopyMemory(timeStamp.Year, DateString+0x00, 4);
  576. RtlCopyMemory(timeStamp.Month, DateString+0x04, 2);
  577. RtlCopyMemory(timeStamp.Day, DateString+0x06, 2);
  578. RtlCopyMemory(timeStamp.Hour, DateString+0x08, 2);
  579. RtlCopyMemory(timeStamp.Minute, DateString+0x0a, 2);
  580. RtlCopyMemory(timeStamp.Second, DateString+0x0c, 2);
  581. if (!SptSendCdbToDevice(CdromHandle, &cdb, 12,
  582. (PUCHAR)&timeStamp, &size, TRUE)) {
  583. FPRINTF((OUTPUT, "Error sending dvd timestamp\n"));
  584. return FALSE;
  585. }
  586. FPRINTF((OUTPUT, "pass.\n"));
  587. return TRUE;
  588. }
  589. BOOLEAN
  590. VerifyBlankMedia(
  591. IN HANDLE CdromHandle
  592. )
  593. {
  594. CDB cdb;
  595. PDISK_INFORMATION diskInfo;
  596. DWORD maxSize = sizeof(DISK_INFORMATION);
  597. DWORD size;
  598. FPRINTF((OUTPUT, "Verifying blank disc... "));
  599. diskInfo = LocalAlloc(LPTR, maxSize);
  600. if (diskInfo == NULL) {
  601. FPRINTF((OUTPUT, "\nError allocating diskinfo\n"));
  602. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  603. return FALSE;
  604. }
  605. RtlZeroMemory(diskInfo, sizeof(DISK_INFORMATION));
  606. RtlZeroMemory(&cdb, sizeof(CDB));
  607. cdb.READ_DISK_INFORMATION.OperationCode = SCSIOP_READ_DISK_INFORMATION;
  608. cdb.READ_DISK_INFORMATION.AllocationLength[0] = (UCHAR)(maxSize >> 8);
  609. cdb.READ_DISK_INFORMATION.AllocationLength[1] = (UCHAR)(maxSize & 0xff);
  610. size = maxSize;
  611. if (!SptSendCdbToDevice(CdromHandle, &cdb, 10,
  612. (PUCHAR)diskInfo, &size, TRUE)) {
  613. FPRINTF((OUTPUT, "\nError %d getting disk info\n",
  614. GetLastError()));
  615. LocalFree(diskInfo);
  616. return FALSE;
  617. }
  618. if (diskInfo->LastSessionStatus != 0x00) {
  619. FPRINTF((OUTPUT, "disc is not blank!\n"));
  620. SetLastError(ERROR_MEDIA_INCOMPATIBLE);
  621. LocalFree(diskInfo);
  622. return FALSE;
  623. }
  624. FPRINTF((OUTPUT, "pass.\n"));
  625. LocalFree(diskInfo);
  626. return TRUE;
  627. }
  628. BOOLEAN
  629. VerifyIsoImage(
  630. IN HANDLE IsoImageHandle,
  631. OUT PDWORD NumberOfBlocks
  632. )
  633. {
  634. BY_HANDLE_FILE_INFORMATION isoImageInfo;
  635. LONGLONG size;
  636. if (!GetFileInformationByHandle(IsoImageHandle, &isoImageInfo)) {
  637. FPRINTF((OUTPUT, "Error %d getting file info for iso image\n",
  638. GetLastError()));
  639. return FALSE;
  640. }
  641. size = ((LONGLONG)isoImageInfo.nFileSizeHigh) << 32;
  642. size |= (LONGLONG)isoImageInfo.nFileSizeLow;
  643. if ((isoImageInfo.nFileSizeLow % 2048) != 0) {
  644. FPRINTF((OUTPUT, "Error: The file size is not a multiple of 2048 (%I64d)\n",
  645. size));
  646. SetLastError(ERROR_INVALID_DATA);
  647. return FALSE;
  648. }
  649. FPRINTF((OUTPUT, "File size is %I64d bytes (%d blocks)\n",
  650. size, size / 2048));
  651. if ((LONGLONG)((size / 2048) >> 32) != 0) {
  652. FPRINTF((OUTPUT, "Error: The file is too large (%I64d)\n",
  653. size));
  654. SetLastError(ERROR_INVALID_DATA);
  655. return FALSE;
  656. }
  657. *NumberOfBlocks = (DWORD)(size / 2048);
  658. return TRUE;
  659. }
  660. BOOLEAN
  661. VerifyMediaCapacity(
  662. IN HANDLE CdromHandle,
  663. IN DWORD RequiredBlocks
  664. )
  665. {
  666. printf("NOT VERIFYING MEDIA CAPACITY!\n");
  667. return TRUE;
  668. }
  669. BOOLEAN
  670. WaitForBurnToComplete(
  671. IN HANDLE CdromHandle
  672. )
  673. {
  674. CDB cdb;
  675. DWORD size;
  676. DWORD i = 0;
  677. FPRINTF((OUTPUT, "Waiting for write to finish (long)... "));
  678. //
  679. // send flush_cache to synchronize the media and the drive's cache
  680. //
  681. RtlZeroMemory(&cdb, sizeof(cdb));
  682. cdb.SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
  683. size = 0;
  684. //
  685. // wait up to ten minutes (600 seconds) for burn to complete
  686. //
  687. if (!SptSendCdbToDeviceEx(CdromHandle,
  688. &cdb,
  689. 10,
  690. NULL,
  691. &size,
  692. NULL,
  693. 0,
  694. TRUE,
  695. 600)) {
  696. FPRINTF((OUTPUT, "Error %d sending SYNCHRONIZE_CACHE\n",
  697. GetLastError()));
  698. return FALSE;
  699. }
  700. FPRINTF((OUTPUT, "success\n"));
  701. return TRUE;
  702. }