|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
burn.c
Abstract:
A user mode app that allows simple commands to be sent to a selected scsi device.
Environment:
User mode only
Revision History:
03-26-96 : Created
--*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "burn.h"
#include "sptlib.h"
#define MAX_CD_IMAGE_SIZE (700 * 1024 * 1024)
#define MAX_DVD_IMAGE_SIZE (4700 * 1000 * 1000)
#define POST_GAP_SIZE 150
#define IS_TEST_BURN FALSE
typedef struct _SENSE_STUFF { UCHAR Sense; UCHAR Asc; UCHAR Ascq; UCHAR Reserved; } SENSE_STUFF, *PSENSE_STUFF;
SENSE_STUFF AllowedBurnSense[] = { {SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS, 0}, {SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_OPERATION_IN_PROGRESS, 0} }; #define AllowedBurnSenseEntries (sizeof(AllowedBurnSense)/sizeof(SENSE_STUFF))
SENSE_STUFF AllowedReadDiscInfo[] = { { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_OPERATION_IN_PROGRESS, 0 }, { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS, 0 }, { SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_FORMAT_IN_PROGRESS, 0 }, { SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_ILLEGAL_MODE_FOR_THIS_TRACK, 0, 0 }, { SCSI_SENSE_UNIT_ATTENTION, SCSI_ADSENSE_INSUFFICIENT_TIME_FOR_OPERATION, 0, 0 } }; #define AllowedReadDiscInfoEntries (sizeof(AllowedReadDiscInfo)/sizeof(SENSE_STUFF))
BOOLEAN IsSenseDataInTable( IN PSENSE_STUFF Table, IN LONG Entries, // in table
IN PSENSE_DATA SenseData ) { LONG i; UCHAR sense = SenseData->SenseKey & 0xf; UCHAR asc = SenseData->AdditionalSenseCode; UCHAR ascq = SenseData->AdditionalSenseCodeQualifier;
for (i = 0; i < Entries; i++ ) { if ((Table[i].Sense = sense) && (Table[i].Ascq = ascq ) && (Table[i].Asc = asc ) ) { return TRUE; } } return FALSE; }
__inline DWORD MakeCdSpeed( IN DWORD Speed ) { Speed *= (75 * 2352); // this makes it the proper speed
Speed += 500; // rounding...
Speed /= 1000; // yes, this is by 1000, not 1024!
return Speed; }
#if DBG
#define OUTPUT stderr
#define FPRINTF(x) fprintf x
#else
#define OUTPUT stdout
#define FPRINTF(x)
#endif
int __cdecl main(int argc, char *argv[]) { int i = 0; HANDLE cdromHandle; HANDLE isoImageHandle; HACK_FLAGS hackFlags; char buffer[32];
if(argc < 3) { printf("Usage: burn <drive> <image>\n"); return -1; }
sprintf(buffer, "\\\\.\\%s", argv[1]);
cdromHandle = CreateFile(buffer, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(cdromHandle == INVALID_HANDLE_VALUE) { printf("Error %d opening device %s\n", GetLastError(), buffer); return -2; }
isoImageHandle = CreateFile(argv[2], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (isoImageHandle == INVALID_HANDLE_VALUE) { printf("Error %d opening image file %s\n", GetLastError(), argv[2]); CloseHandle(cdromHandle); return -2; } RtlZeroMemory(&hackFlags, sizeof(HACK_FLAGS)); hackFlags.TestBurn = 0; hackFlags.IgnoreModePageErrors = 1;
BurnCommand(cdromHandle, isoImageHandle, hackFlags); CloseHandle(isoImageHandle); CloseHandle(cdromHandle);
return 0; }
VOID PrintBuffer( IN PVOID Buffer, IN DWORD Size ) { DWORD offset = 0; PUCHAR buf = Buffer;
while (Size > 0x10) { printf("%08x:" " %02x %02x %02x %02x %02x %02x %02x %02x" " %02x %02x %02x %02x %02x %02x %02x %02x" "\n", offset, *(buf + 0), *(buf + 1), *(buf + 2), *(buf + 3), *(buf + 4), *(buf + 5), *(buf + 6), *(buf + 7), *(buf + 8), *(buf + 9), *(buf + 10), *(buf + 11), *(buf + 12), *(buf + 13), *(buf + 14), *(buf + 15) ); Size -= 0x10; offset += 0x10; buf += 0x10; }
if (Size != 0) {
DWORD spaceIt;
printf("%08x:", offset); for (spaceIt = 0; Size != 0; Size--) {
if ((spaceIt%8)==0) { printf(" "); // extra space every eight chars
} printf(" %02x", *buf); spaceIt++; buf++; } printf("\n");
} return;
}
BOOLEAN VerifyIsoImage( IN HANDLE IsoImageHandle, OUT PLONG NumberOfBlocks ) { BY_HANDLE_FILE_INFORMATION isoImageInfo; if (!GetFileInformationByHandle(IsoImageHandle, &isoImageInfo)) { FPRINTF((OUTPUT, "Error %d getting file info for iso image\n", GetLastError())); return FALSE; } if (isoImageInfo.nFileSizeHigh != 0) { FPRINTF((OUTPUT, "Error: File too large\n")); SetLastError(ERROR_INVALID_DATA); return FALSE; } if ((isoImageInfo.nFileSizeLow % 2048) != 0) { FPRINTF((OUTPUT, "Error: The file size is not a multiple of 2048 (%I64d)\n", isoImageInfo.nFileSizeLow)); SetLastError(ERROR_INVALID_DATA); return FALSE; } FPRINTF((OUTPUT, "File size is %d bytes (%d blocks)\n", isoImageInfo.nFileSizeLow, isoImageInfo.nFileSizeLow / 2048 )); *NumberOfBlocks = isoImageInfo.nFileSizeLow / 2048; return TRUE;
}
BOOLEAN VerifyBlankMedia( IN HANDLE CdromHandle ) { CDB cdb; PDISK_INFORMATION diskInfo; DWORD maxSize = sizeof(DISK_INFORMATION); DWORD size;
FPRINTF((OUTPUT, "Verifying blank disc... "));
diskInfo = LocalAlloc(LPTR, maxSize); if (diskInfo == NULL) { FPRINTF((OUTPUT, "\nError allocating diskinfo\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } RtlZeroMemory(diskInfo, sizeof(DISK_INFORMATION)); RtlZeroMemory(&cdb, sizeof(CDB)); cdb.READ_DISK_INFORMATION.OperationCode = SCSIOP_READ_DISK_INFORMATION; cdb.READ_DISK_INFORMATION.AllocationLength[0] = (UCHAR)(maxSize >> 8); cdb.READ_DISK_INFORMATION.AllocationLength[1] = (UCHAR)(maxSize & 0xff);
size = maxSize; if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, (PUCHAR)diskInfo, &size, TRUE)) { FPRINTF((OUTPUT, "\nError %d getting disk info\n", GetLastError())); LocalFree(diskInfo); return FALSE; }
if (diskInfo->LastSessionStatus != 0x00) { FPRINTF((OUTPUT, "disc is not blank!\n")); SetLastError(ERROR_MEDIA_INCOMPATIBLE); LocalFree(diskInfo); return FALSE; } FPRINTF((OUTPUT, "pass.\n")); LocalFree(diskInfo); return TRUE; }
BOOLEAN SetWriteModePage( IN HANDLE CdromHandle, IN BOOLEAN TestBurn, IN UCHAR WriteType, IN UCHAR MultiSession, IN UCHAR DataBlockType, IN UCHAR SessionFormat ) { PCDVD_WRITE_PARAMETERS_PAGE params = NULL; MODE_PARAMETER_HEADER10 header; PMODE_PARAMETER_HEADER10 buffer;
UCHAR mediumTypeCode;
CDB cdb; DWORD bufferSize; DWORD maxSize;
FPRINTF((OUTPUT, "Setting WriteParameters mode page... ")); bufferSize = sizeof(MODE_PARAMETER_HEADER10);
RtlZeroMemory(&header, sizeof(MODE_PARAMETER_HEADER10)); RtlZeroMemory(&cdb, sizeof(CDB)); cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; cdb.MODE_SENSE10.PageCode = 0x5; cdb.MODE_SENSE10.Dbd = 1; cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferSize >> 8); cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferSize & 0xff); if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, (PUCHAR)&header, &bufferSize, TRUE)) { FPRINTF((OUTPUT, "\nError %d getting mode page 0x05 from device(1)\n", GetLastError())); return FALSE; } bufferSize = (header.ModeDataLength[0] << 8) + (header.ModeDataLength[1] & 0xff); bufferSize += 2; // sizeof area that tells the remaining size
maxSize = bufferSize; buffer = LocalAlloc(LPTR, bufferSize); if (!buffer) { FPRINTF((OUTPUT, "\nError -- unable to alloc %d bytes for mode parameters page\n", bufferSize)); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } RtlZeroMemory(&cdb, sizeof(CDB)); cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; cdb.MODE_SENSE10.PageCode = 0x5; cdb.MODE_SENSE10.Dbd = 1; cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferSize >> 8); cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferSize & 0xff); if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, (PUCHAR)buffer, &bufferSize, TRUE)) { FPRINTF((OUTPUT, "\nError %d getting mode page 0x05 from device(2)\n", GetLastError())); LocalFree(buffer); return FALSE; }
mediumTypeCode = buffer->MediumType; //
// bufferSize now holds the amount of data returned
// this should be enough...
//
{ DWORD t = (buffer->BlockDescriptorLength[0] >> 8) + (buffer->BlockDescriptorLength[1] & 0xff);
if (t != 0) { fprintf(stderr, "BlockDescriptor non-zero! (%x)\n", t); SetLastError(1); return FALSE; } } //
// pointer arithmetic here. (buffer+1) points just past the
// end of the mode_parameter_header10.
//
params = (PCDVD_WRITE_PARAMETERS_PAGE)(buffer + 1); FPRINTF((OUTPUT, "buffer = %p params = %p\n", buffer, params));
//
// zero the header, but don't modify any settings that don't
// need to be modified!
//
RtlZeroMemory(buffer, FIELD_OFFSET(MODE_PARAMETER_HEADER10, BlockDescriptorLength[0])); buffer->ModeDataLength[0] = (UCHAR)((bufferSize-2) >> 8); buffer->ModeDataLength[1] = (UCHAR)((bufferSize-2) & 0xff); buffer->MediumType = mediumTypeCode; params->WriteType = WriteType; params->TestWrite = (TestBurn ? 0x01 : 0x00); params->Copy = 0x00; // original disc
//params->TrackMode = 0x04; // control nibble in Q subchannel
params->MultiSession = MultiSession; params->DataBlockType = DataBlockType; params->SessionFormat = SessionFormat; params->MediaCatalogNumberValid = 0x00; params->ISRCValid = 0x00;
RtlZeroMemory(&cdb, sizeof(CDB)); cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10; cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR)(bufferSize >> 8); cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR)(bufferSize & 0xff); cdb.MODE_SELECT10.PFBit = 1; if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, (PUCHAR)buffer, &bufferSize, FALSE)) { FPRINTF((OUTPUT, "\nError %d sending mode page 0x05 to device\n", GetLastError())); LocalFree(buffer); return FALSE; } LocalFree(buffer); FPRINTF((OUTPUT, "pass.\n")); return TRUE; }
BOOLEAN GetNextWritableAddress( IN HANDLE CdromHandle, IN UCHAR Track, OUT PLONG NextWritableAddress, OUT PLONG AvailableBlocks ) { CDB cdb; TRACK_INFORMATION trackInfo; DWORD size = sizeof(TRACK_INFORMATION); LONG nwa, available;
*NextWritableAddress = (LONG)-1; *AvailableBlocks = (LONG)0;
FPRINTF((OUTPUT, "Verifying track info... "));
RtlZeroMemory(&cdb, sizeof(CDB)); RtlZeroMemory(&trackInfo, sizeof(TRACK_INFORMATION));
cdb.READ_TRACK_INFORMATION.OperationCode = SCSIOP_READ_TRACK_INFORMATION; cdb.READ_TRACK_INFORMATION.Track = 0x01; cdb.READ_TRACK_INFORMATION.BlockAddress[3] = Track; cdb.READ_TRACK_INFORMATION.AllocationLength[0] = (UCHAR)(size >> 8); cdb.READ_TRACK_INFORMATION.AllocationLength[1] = (UCHAR)(size & 0xff);
if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, (PUCHAR)&trackInfo, &size, TRUE)) { FPRINTF((OUTPUT, "\nError %d getting track info\n", GetLastError())); return FALSE; }
if (!trackInfo.NWA_V) { FPRINTF((OUTPUT, "invalid NextWritableAddress -- may be invalid media?\n")); SetLastError(ERROR_MEDIA_INCOMPATIBLE); return FALSE; } nwa = (trackInfo.NextWritableAddress[0] << 24) | (trackInfo.NextWritableAddress[1] << 16) | (trackInfo.NextWritableAddress[2] << 8) | (trackInfo.NextWritableAddress[3] << 0);
available = (trackInfo.FreeBlocks[0] << 24) | (trackInfo.FreeBlocks[1] << 16) | (trackInfo.FreeBlocks[2] << 8) | (trackInfo.FreeBlocks[3] << 0); FPRINTF((OUTPUT, "pass.\n"));
*NextWritableAddress = nwa; *AvailableBlocks = available; return TRUE; }
BOOLEAN SendOptimumPowerCalibration( IN HANDLE CdromHandle ) { CDB cdb; DWORD size; FPRINTF((OUTPUT, "Setting OPC_INFORMATION..."));
RtlZeroMemory(&cdb, sizeof(CDB));
cdb.SEND_OPC_INFORMATION.OperationCode = SCSIOP_SEND_OPC_INFORMATION; cdb.SEND_OPC_INFORMATION.DoOpc = 1; size = 0; if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, NULL, &size, TRUE)) { FPRINTF((OUTPUT, "\nFailed to send SET_OPC_INFORMATION (%d)\n", GetLastError())); return FALSE; } FPRINTF((OUTPUT, "pass.\n")); return TRUE; }
BOOLEAN SetRecordingSpeed( IN HANDLE CdromHandle, IN DWORD Speed ) { CDB cdb; DWORD size; DWORD kbSpeed; FPRINTF((OUTPUT, "Setting CD Speed...")); kbSpeed = MakeCdSpeed(Speed);
RtlZeroMemory(&cdb, sizeof(CDB)); cdb.SET_CD_SPEED.OperationCode = SCSIOP_SET_CD_SPEED; cdb.SET_CD_SPEED.ReadSpeed[0] = 0xff; cdb.SET_CD_SPEED.ReadSpeed[1] = 0xff; cdb.SET_CD_SPEED.WriteSpeed[0] = (UCHAR)(kbSpeed >> 8); cdb.SET_CD_SPEED.WriteSpeed[1] = (UCHAR)(kbSpeed & 0xff); size = 0; if (!SptSendCdbToDevice(CdromHandle, &cdb, 12, NULL, &size, TRUE)) { FPRINTF((OUTPUT, "\nFailed to send SET_CD_SPEED (%d)\n", GetLastError())); return FALSE; } FPRINTF((OUTPUT, "pass.\n")); return TRUE; }
VOID WaitForReadDiscInfoToWork( IN HANDLE CdromHandle ) { CDB cdb; DWORD size; DISK_INFORMATION diskInfo; DWORD i;
//
// loop using SCSIOP_READ_DISK_INFORMATION (0x51) since
// that seems to fail for *ALL* drives until the drive is ready
//
for (i=0; ; i++) { size = sizeof(DISK_INFORMATION); RtlZeroMemory(&diskInfo, sizeof(DISK_INFORMATION)); RtlZeroMemory(&cdb, sizeof(CDB)); cdb.READ_DISK_INFORMATION.OperationCode = SCSIOP_READ_DISK_INFORMATION; cdb.READ_DISK_INFORMATION.AllocationLength[0] = (UCHAR)(size >> 8); cdb.READ_DISK_INFORMATION.AllocationLength[1] = (UCHAR)(size & 0xff); if (SptSendCdbToDevice(CdromHandle, &cdb, 10, (PUCHAR)&diskInfo, &size, TRUE)) { FPRINTF((OUTPUT, "ReadDiscInfo Succeeded! (%d seconds)\n", i)); return; } // should verify the errors are valid errors (AllowedReadDiscInfo[])?
// need to sleep here so we don't overload the unit!
Sleep(1000); // one second
} return; }
BOOLEAN BurnThisSession( IN HANDLE CdromHandle, IN HANDLE IsoImageHandle, IN LONG NumberOfBlocks, IN LONG FirstLba ) { DWORD bufferSize = 0x800 * 0x10; PUCHAR buffer = NULL; LONG currentBlock;
FPRINTF((OUTPUT, "Starting write: "));
buffer = LocalAlloc(LPTR, bufferSize); if (buffer == NULL) { FPRINTF((OUTPUT, "unable to allocate write buffer\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; }
FPRINTF((OUTPUT, "............."));
for (currentBlock = 0; currentBlock < NumberOfBlocks + POST_GAP_SIZE; ) {
CDB cdb; DWORD readSize; DWORD readBytes;
{ static CHAR progress[4] = { '|', '/', '-', '\\' }; DWORD percent; percent = (currentBlock*1000) / (NumberOfBlocks+POST_GAP_SIZE); // # # # . # % _ d o n e _ *
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); printf("%c %3d.%d%% done", progress[(currentBlock%0x40)/0x10], percent / 10, percent % 10 ); fflush(stdout); }
if (NumberOfBlocks - currentBlock >= 0x10) { readSize = 0x800 * 0x10; } else if (NumberOfBlocks - currentBlock > 0) { readSize = (NumberOfBlocks - currentBlock) * 0x800; RtlZeroMemory(buffer, bufferSize); } else { readSize = 0; readBytes = 0; RtlZeroMemory(buffer, bufferSize); }
if (readSize && !ReadFile(IsoImageHandle, buffer, readSize, &readBytes, NULL) ) { FPRINTF((OUTPUT, "error reading from file %d\n", GetLastError())); LocalFree(buffer); return FALSE; }
if (readBytes != readSize) { FPRINTF((OUTPUT, "error only read %d of %d bytes from file\n", readBytes, readSize)); LocalFree(buffer); return FALSE; }
{ BOOL writeCompleted = FALSE; while (!writeCompleted) { BOOLEAN ignoreError; SENSE_DATA senseData; RtlZeroMemory(&senseData, sizeof(senseData)); RtlZeroMemory(&cdb, sizeof(CDB));
cdb.CDB10.OperationCode = SCSIOP_WRITE; cdb.CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)¤tBlock)->Byte3; cdb.CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)¤tBlock)->Byte2; cdb.CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)¤tBlock)->Byte1; cdb.CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)¤tBlock)->Byte0; if ((currentBlock + 0x10) <= (NumberOfBlocks + POST_GAP_SIZE)) { cdb.CDB10.TransferBlocksLsb = 0x10; } else { cdb.CDB10.TransferBlocksLsb = (UCHAR)(NumberOfBlocks + POST_GAP_SIZE - currentBlock); }
writeCompleted = SptSendCdbToDeviceEx(CdromHandle, &cdb, 10, buffer, &bufferSize, &senseData, sizeof(SENSE_DATA), FALSE, 50 // timeout seconds
); ignoreError = IsSenseDataInTable(AllowedBurnSense, AllowedBurnSenseEntries, &senseData); if ((!writeCompleted) && ignoreError) { printf("Continuing on %x/%x/%x\n", senseData.SenseKey & 0xf, senseData.AdditionalSenseCode, senseData.AdditionalSenseCodeQualifier ); Sleep(100); // 100ms == .1 seconds
}
if (!writeCompleted && !ignoreError) { FPRINTF((OUTPUT, "\nError %d in writing LBA 0x%x\n", GetLastError(), currentBlock)); LocalFree(buffer); return FALSE; }
} // while(!writeCompleted) loop
} // random block to have local variable writeCompleted
// write completed success, so continue.
currentBlock += 0x10;
}
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); LocalFree(buffer);
printf("Finished Writing\nSynchronizing Cache: "); fflush(stdout); //
// do the FLUSH_CACHE immediate
//
{ DWORD size; CDB cdb; RtlZeroMemory(&cdb, sizeof(CDB)); cdb.SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; cdb.SYNCHRONIZE_CACHE10.Immediate = 1; size = 0;
if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, NULL, &size, TRUE)) { FPRINTF((OUTPUT, "\nError %d Synchronizing Cache\n", GetLastError())); return FALSE; } }
WaitForReadDiscInfoToWork(CdromHandle); return TRUE; }
BOOLEAN CloseTrack( IN HANDLE CdromHandle, IN LONG Track ) { CDB cdb; DWORD size; FPRINTF((OUTPUT, "Closing the track..."));
if (Track > 0xffff) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } RtlZeroMemory(&cdb, sizeof(CDB)); cdb.CLOSE_TRACK.OperationCode = SCSIOP_CLOSE_TRACK_SESSION; cdb.CLOSE_TRACK.Immediate = 0; cdb.CLOSE_TRACK.Track = 1; cdb.CLOSE_TRACK.Session = 0; cdb.CLOSE_TRACK.TrackNumber[0] = (UCHAR)(Track >> 8); cdb.CLOSE_TRACK.TrackNumber[1] = (UCHAR)(Track & 0xff); size = 0;
if (!SptSendCdbToDevice(CdromHandle, &cdb, 10, NULL, &size, TRUE)) { FPRINTF((OUTPUT, "\nError %d Closing Track\n", GetLastError())); return FALSE; } WaitForReadDiscInfoToWork(CdromHandle);
FPRINTF((OUTPUT, "pass.\n")); return TRUE;
}
BOOLEAN CloseSession( IN HANDLE CdromHandle ) { CDB cdb; DWORD size; FPRINTF((OUTPUT, "Closing the disc..."));
RtlZeroMemory(&cdb, sizeof(CDB)); cdb.CLOSE_TRACK.OperationCode = SCSIOP_CLOSE_TRACK_SESSION; cdb.CLOSE_TRACK.Immediate = 1; cdb.CLOSE_TRACK.Track = 0; cdb.CLOSE_TRACK.Session = 1; size = 0;
if (!SptSendCdbToDeviceEx(CdromHandle, &cdb, 10, NULL, &size, NULL, 0, TRUE, 240)) { // four minutes to close session
FPRINTF((OUTPUT, "\nError %d Synchronizing Cache\n", GetLastError())); return FALSE; } WaitForReadDiscInfoToWork(CdromHandle);
FPRINTF((OUTPUT, "pass.\n")); return TRUE; }
BOOLEAN SendStartStopUnit( IN HANDLE CdromHandle, IN BOOLEAN Start, IN BOOLEAN Eject ) { CDB cdb; DWORD size;
RtlZeroMemory(&cdb, sizeof(CDB)); cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; cdb.START_STOP.LoadEject = Eject; cdb.START_STOP.Start = Start;
size = 0; if (!SptSendCdbToDevice(CdromHandle, &cdb, 6, NULL, &size, TRUE)) { return FALSE; }
return TRUE; }
/*
ERROR_BAD_COMMAND ERROR_INVALID_DATA ERROR_INVALID_PARAMETER ERROR_MEDIA_INCOMPATIBLE ERROR_NOT_ENOUGH_MEMORY
ERROR_OUTOFMEMORY
*/
/*++
Routine Description:
burns an ISO image to cdrom
Arguments: CdromHandle - a file handle to send the ioctl to
argc - the number of additional arguments (2)
Return Value:
ERROR_SUCCESS if successful The value of GetLastError() from the point of failure
--*/ DWORD BurnCommand( HANDLE CdromHandle, HANDLE IsoImageHandle, HACK_FLAGS HackFlags ) { LONG numberOfBlocks; LONG availableBlocks; LONG firstLba; LONG i;
////////////////////////////////////////////////////////////////////////////////
// verify the iso image file looks correct
////////////////////////////////////////////////////////////////////////////////
if (!VerifyIsoImage(IsoImageHandle, &numberOfBlocks)) { printf("Error verifying ISO image\n"); return GetLastError(); } ////////////////////////////////////////////////////////////////////////////////
// verify (as best as possible) that it's blank media
////////////////////////////////////////////////////////////////////////////////
if (!VerifyBlankMedia(CdromHandle)) { printf("Error verifying blank media\n"); return GetLastError(); }
////////////////////////////////////////////////////////////////////////////////
// Setup the write mode page
////////////////////////////////////////////////////////////////////////////////
if (!SetWriteModePage(CdromHandle, (BOOLEAN)HackFlags.TestBurn, 0x01, // track-at-once
0x03, // we close the session/disc ourselves
0x08, // 0x08 == Mode 1 (ISO/IEC 10149 == 2048 bytes)
// 0x0a == Mode 2 (CDROM XA, Form 1, 2048 bytes)
0x00 // 0x00 == CD-DA, CD-ROM, or other data disc
// 0x20 == CDROM XA
)) { printf("Error setting write mode page\n"); if (!HackFlags.IgnoreModePageErrors) { return GetLastError(); } else { printf("Ignoring error and attempting to continue...\n"); }
}
////////////////////////////////////////////////////////////////////////////////
// get next writable address
////////////////////////////////////////////////////////////////////////////////
if (!GetNextWritableAddress(CdromHandle, 0x01, &firstLba, &availableBlocks)) { printf("Error verifying next writable address\n"); return GetLastError(); } if (availableBlocks < numberOfBlocks) { printf("Error verifying free blocks on media (%d needed, %d available)\n", numberOfBlocks, availableBlocks); SetLastError(ERROR_MEDIA_INCOMPATIBLE); return GetLastError(); } if (firstLba != 0) { printf("Error verifying next writable address is zero\n"); SetLastError(ERROR_MEDIA_INCOMPATIBLE); return GetLastError(); }
////////////////////////////////////////////////////////////////////////////////
// set the cd speed to four for now, can later make a cmd-line switch
////////////////////////////////////////////////////////////////////////////////
if (!SetRecordingSpeed(CdromHandle, 4)) { printf("Error setting the cd speed to %d\n", 4); return GetLastError(); }
////////////////////////////////////////////////////////////////////////////////
// calibrate the drive's power -- this is optional, so let it fail!
////////////////////////////////////////////////////////////////////////////////
if (!SendOptimumPowerCalibration(CdromHandle)) { printf("WARNING: setting optimum power calibration failed\n"); //return GetLastError();
}
////////////////////////////////////////////////////////////////////////////////
// start writing
////////////////////////////////////////////////////////////////////////////////
if (!BurnThisSession(CdromHandle, IsoImageHandle, numberOfBlocks, firstLba)) { printf("Error burning ISO image\n"); return GetLastError(); }
////////////////////////////////////////////////////////////////////////////////
// close the track -- ignore failures
////////////////////////////////////////////////////////////////////////////////
if (!CloseTrack(CdromHandle, 0)) { printf("WARNING: error closing the track -- may be ignored?\n"); //return GetLastError();
}
////////////////////////////////////////////////////////////////////////////////
// close the session
////////////////////////////////////////////////////////////////////////////////
if (!CloseSession(CdromHandle)) { printf("Error closing session\n"); return GetLastError(); }
////////////////////////////////////////////////////////////////////////////////
// eject the newly burned cd!
////////////////////////////////////////////////////////////////////////////////
if (!SendStartStopUnit(CdromHandle, FALSE, TRUE) || !SendStartStopUnit(CdromHandle, TRUE, TRUE)) { printf("Error ejecting/reinserting disc\n"); return GetLastError(); }
printf("burn successful!\n"); return 0; }
|