Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

702 lines
17 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
cdp.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 <windows.h>
#include <devioctl.h>
#include <ntddscsi.h>
#define _NTSRB_ // to keep srb.h from being included
#include <scsi.h>
#ifdef DBG
#define dbg(x) x
#else
#define dbg(x) /* x */
#endif
#define ARGUMENT_USED(x) (x == NULL)
typedef struct {
char *Name;
char *Description;
DWORD (*Function)(HANDLE device, int argc, char *argv[]);
} COMMAND;
typedef struct {
SCSI_PASS_THROUGH Spt;
char SenseInfoBuffer[18];
char DataBuffer[0]; // Allocate buffer space
// after this
} SPT_WITH_BUFFERS, *PSPT_WITH_BUFFERS;
typedef struct {
UCHAR Reserved1;
UCHAR ADR : 4;
UCHAR Control : 4;
UCHAR TrackNumber;
UCHAR Reserved2;
union {
UCHAR Swap[4];
ULONG Block;
struct {
UCHAR Reserved;
UCHAR M;
UCHAR S;
UCHAR F;
} MSF;
} Address;
} TRACK, *PTRACK;
#define MAKE_SPT(p, size, cdbsize, datain, datasize) \
size = sizeof(SPT_WITH_BUFFERS) + datasize; \
p = (PSPT_WITH_BUFFERS) malloc(size); \
memset(p, 0, size); \
p->Spt.Length = sizeof(p->Spt); \
p->Spt.CdbLength = cdbsize; \
p->Spt.SenseInfoLength = 12; \
p->Spt.DataIn = datain; \
p->Spt.DataTransferLength = datasize; \
p->Spt.TimeOutValue = 20; \
p->Spt.SenseInfoOffset = \
((DWORD) &(p->SenseInfoBuffer[0]) - (DWORD) (p)); \
p->Spt.DataBufferOffset = \
((DWORD) &(p->DataBuffer[0]) - (DWORD) (p))
DWORD StartStopCommand(HANDLE device, int argc, char *argv[]);
DWORD TestCommand(HANDLE device, int argc, char *argv[]);
DWORD ReadTOCCommand(HANDLE device, int argc, char *argv[]);
DWORD PlayCommand(HANDLE device, int argc, char *argv[]);
DWORD PauseResumeCommand(HANDLE device, int argc, char *argv[]);
DWORD SendCommand(HANDLE device, int argc, char *argv[]);
DWORD ListCommand(HANDLE device, int argc, char *argv[]);
//
// List of commands
// all command names are case sensitive
// arguments are passed into command routines
// list must be terminated with NULL command
// command will not be listed in help if description == NULL
//
COMMAND CommandArray[] = {
{"eject", "spins down and ejects the specified drive", StartStopCommand},
{"help", "help for all commands", ListCommand},
{"load", "loads the specified drive", StartStopCommand},
{"pause", "pauses audio playback", PauseResumeCommand},
{"play", "[start track [end track]] plays audio tracks [", PlayCommand},
{"resume", "resumes paused audio playback", PauseResumeCommand},
{"send", NULL, SendCommand},
{"start", "spins up the drive", StartStopCommand},
{"stop", "spinds down the drive", StartStopCommand},
{"test", NULL, TestCommand},
{"toc", "prints the table of contents", ReadTOCCommand},
{NULL, NULL, NULL}
};
#define STATUS_SUCCESS 0
int __cdecl main(int argc, char *argv[])
{
int i = 0;
HANDLE h;
char buffer[32];
if(argc < 3) {
printf("Usage: cdp <drive> <command> [parameters]\n");
printf("possible commands: \n");
ListCommand(NULL, argc, argv);
printf("\n");
return -1;
}
sprintf(buffer, "\\\\.\\%s", argv[1]);
dbg(printf("Sending command %s to drive %s\n", argv[2], buffer));
h = CreateFile(buffer,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(h == INVALID_HANDLE_VALUE) {
printf("Error %d opening device %s\n", GetLastError(), buffer);
return -2;
}
//
// Iterate through the command array and find the correct function to
// call.
//
while(CommandArray[i].Name != NULL) {
if(strcmp(argv[2], CommandArray[i].Name) == 0) {
(CommandArray[i].Function)(h, (argc - 2), &(argv[2]));
break;
}
i++;
}
if(CommandArray[i].Name == NULL) {
printf("Unknown command %s\n", argv[2]);
}
CloseHandle(h);
return 0;
}
DWORD StartStopCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
Sends down a startstop command.
Arguments:
device - a file handle to send the ioctl to
argc - the number of additional arguments. should be zero
argv[0] - "eject", "load", "start" or "stop"
Return Value:
STATUS_SUCCESS if successful
The value of GetLastError() from the point of failure
--*/
{
PSPT_WITH_BUFFERS spt;
PCDB cdb;
DWORD returned;
DWORD errorValue = STATUS_SUCCESS;
DWORD packetSize;
UCHAR loadEject = 0;
UCHAR start = 0;
if(strcmp("eject", argv[0]) == 0) {
loadEject = 1;
start = 0;
} else if(strcmp("load", argv[0]) == 0) {
loadEject = 1;
start = 1;
} else if(strcmp("start", argv[0]) == 0) {
loadEject = 0;
start = 1;
} else if(strcmp("stop", argv[0]) == 0) {
loadEject = 0;
start = 0;
} else {
assert(0);
}
MAKE_SPT(spt, packetSize, 6, 0, 0);
cdb = (PCDB) &(spt->Spt.Cdb[0]);
cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
cdb->START_STOP.Immediate = 0;
cdb->START_STOP.Start = start;
cdb->START_STOP.LoadEject = loadEject;
if(!DeviceIoControl(device,
IOCTL_SCSI_PASS_THROUGH,
spt,
sizeof(SPT_WITH_BUFFERS),
spt,
sizeof(SPT_WITH_BUFFERS),
&returned,
FALSE)) {
errorValue = GetLastError();
printf("Eject - error sending IOCTL (%d)\n", errorValue);
}
free(spt);
return errorValue;
}
DWORD LoadCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
Creates an START_STOP pass through ioctl and sends it to the passed in
file handle
Arguments:
device - a file handle to send the ioctl to
argc - the number of additional arguments. should be zero
argv - the additional arguments
Return Value:
STATUS_SUCCESS if successful
The value of GetLastError() from the point of failure
--*/
{
PSPT_WITH_BUFFERS spt;
PCDB cdb;
DWORD returned;
DWORD errorValue = STATUS_SUCCESS;
DWORD packetSize;
printf("Loading cd\n");
MAKE_SPT(spt, packetSize, 6, 0, 0);
cdb = (PCDB) &(spt->Spt.Cdb[0]);
cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
cdb->START_STOP.Immediate = 0;
cdb->START_STOP.Start = 1;
cdb->START_STOP.LoadEject = 1;
if(!DeviceIoControl(device,
IOCTL_SCSI_PASS_THROUGH,
spt,
packetSize,
spt,
packetSize,
&returned,
FALSE)) {
errorValue = GetLastError();
printf("Load - error sending IOCTL (%d)\n", errorValue);
}
free(spt);
return STATUS_SUCCESS;
}
DWORD ReadTOCCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
Reads and prints out the cdrom's table of contents
Arguments:
device - a file handle to send the ioctl to
argc - the number of additional arguments. should be zero
argv - the additional arguments
Return Value:
STATUS_SUCCESS if successful
The value of GetLastError() from the point of failure
--*/
{
PSPT_WITH_BUFFERS spt;
DWORD errorValue = STATUS_SUCCESS;
DWORD packetSize, returned = 0;
PCDB cdb;
int numTracks, i;
PTRACK track;
// DWORD addr;
printf("Reading Table of Contents\n");
//
// Allocate an SPT packet big enough to hold the 4 byte TOC header
//
MAKE_SPT(spt, packetSize, 10, 1, 0x04);
cdb = (PCDB) &(spt->Spt.Cdb[0]);
cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
cdb->READ_TOC.Msf = 0;
cdb->READ_TOC.StartingTrack = 0;
cdb->READ_TOC.AllocationLength[1] = 0x04;
if(!DeviceIoControl(device,
IOCTL_SCSI_PASS_THROUGH,
spt,
packetSize,
spt,
packetSize,
&returned,
FALSE)) {
errorValue = GetLastError();
printf("Error %d sending READ_TOC pass through\n", errorValue);
goto EndReadTOC;
} else {
dbg(printf("READ_TOC pass through returned %d bytes\n", returned));
}
printf("TOC Data Length: %d\n", (WORD) *(spt->DataBuffer));
printf("First Track Number: %d\n", spt->DataBuffer[2]);
printf("Last Track Number: %d\n", spt->DataBuffer[3]);
numTracks = spt->DataBuffer[3] - spt->DataBuffer[2] + 1;
free(spt);
MAKE_SPT(spt, packetSize, 10, 1, (4 + (numTracks * 8)));
cdb = (PCDB) &(spt->Spt.Cdb[0]);
cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
cdb->READ_TOC.Msf = 0;
cdb->READ_TOC.StartingTrack = 1;
cdb->READ_TOC.AllocationLength[1] = 0x04 + (numTracks * 8);
if(!DeviceIoControl(device,
IOCTL_SCSI_PASS_THROUGH,
spt,
packetSize,
spt,
packetSize,
&returned,
FALSE)) {
errorValue = GetLastError();
printf("Error %d sending READ_TOC pass through\n", errorValue);
goto EndReadTOC;
} else {
dbg(printf("READ_TOC pass through returned %d bytes\n", returned));
}
track = (PTRACK) &(spt->DataBuffer[4]);
printf("Number ADR Control Address (MSF)\n");
printf("------ --- ------- -------------\n");
for(i = 0; i < numTracks; i++) {
printf("%6d %3d %7d %3d:%3d:%3d\n", track->TrackNumber,
track->ADR,
track->Control,
track->Address.MSF.M,
track->Address.MSF.S,
track->Address.MSF.F);
track++;
}
EndReadTOC:
free(spt);
return errorValue;
}
DWORD PlayCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
Plays an audio track
Arguments:
device - a file handle to send the ioctl to
argc - the number of additional arguments.
argv[1] - the starting track. Starts at zero if this is not here
argv[2] - the ending track. Let track if not specified
Return Value:
STATUS_SUCCESS if successful
The value of GetLastError() from the point of failure
--*/
{
PSPT_WITH_BUFFERS spt;
DWORD errorValue = STATUS_SUCCESS;
DWORD packetSize, returned = 0;
PCDB cdb;
char startingTrack = 1, endingTrack = -1;
if(argc > 2) endingTrack = atoi(argv[2]);
if(argc > 1) startingTrack = atoi(argv[1]);
printf("Playing from track %d to ", startingTrack);
if(endingTrack == -1) {
printf("end of disk\n");
} else {
printf("track %d\n", endingTrack);
}
//
// Allocate an SPT packet big enough to hold the 4 byte TOC header
//
MAKE_SPT(spt, packetSize, 10, 1, 0);
//
// Unfortunately no one defined the PLAY_INDEX command for us so
// cheat and use MSF
//
cdb = (PCDB) &(spt->Spt.Cdb[0]);
cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_TRACK_INDEX;
cdb->PLAY_AUDIO_MSF.StartingS = startingTrack;
cdb->PLAY_AUDIO_MSF.StartingF = 0;
cdb->PLAY_AUDIO_MSF.EndingS = endingTrack;
cdb->PLAY_AUDIO_MSF.EndingF = 0;
if(!DeviceIoControl(device,
IOCTL_SCSI_PASS_THROUGH,
spt,
packetSize,
spt,
packetSize,
&returned,
FALSE)) {
errorValue = GetLastError();
printf("Error %d sending PLAY_AUDIO_INDEX pass through\n", errorValue);
} else {
dbg(printf("PLAY_AUDIO_INDEX pass through returned %d bytes\n", returned));
}
free(spt);
return errorValue;
}
DWORD PauseResumeCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
pauses or resumes audio playback
Arguments:
device - a file handle to send the ioctl to
argc - the number of additional arguments.
argv[0] - "pause" or "resume"
Return Value:
STATUS_SUCCESS if successful
The value of GetLastError() from the point of failure
--*/
{
PSPT_WITH_BUFFERS spt;
DWORD errorValue = STATUS_SUCCESS;
DWORD packetSize, returned = 0;
PCDB cdb;
char pauseResume;
if(strcmp("pause", argv[0]) == 0) pauseResume = 0;
else pauseResume = 1;
printf("%s cdrom playback\n", (pauseResume ? "Pausing" : "Resuming"));
//
// Allocate an SPT packet big enough to hold the 4 byte TOC header
//
MAKE_SPT(spt, packetSize, 10, 1, 0);
//
// Unfortunately no one defined the PLAY_INDEX command for us so
// cheat and use MSF
//
cdb = (PCDB) &(spt->Spt.Cdb[0]);
cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
cdb->PAUSE_RESUME.Action = pauseResume;
if(!DeviceIoControl(device,
IOCTL_SCSI_PASS_THROUGH,
spt,
packetSize,
spt,
packetSize,
&returned,
FALSE)) {
errorValue = GetLastError();
printf("Error %d sending PAUSE_RESUME pass through\n", errorValue);
} else {
dbg(printf("PAUSE_RESUME pass through returned %d bytes\n", returned));
}
free(spt);
return errorValue;
}
DWORD SendCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
Parses a hex byte string and creates a cdb to send down.
Arguments:
device - a file handle to send the ioctl to
argc - the number of additional arguments. should be zero
argv[1] - The CDB to send in a quoted hex byte string
"47 00 00 00 01 00 00 ff 00 00"
argv[2] - for data in commands: the number of bytes (decimal) to
expect from the target
for data out commands: a quoted byte string containing the
data to be sent
Return Value:
STATUS_SUCCESS if successful
The value of GetLastError() from the point of failure
--*/
{
PSPT_WITH_BUFFERS spt;
PCDB cdb;
DWORD returned;
DWORD errorValue = STATUS_SUCCESS;
DWORD packetSize;
int i;
UCHAR cdbLength = 0;
DWORD dataLength = 0;
MAKE_SPT(spt, packetSize, 6, 0, 0);
cdb = (PCDB) &(spt->Spt.Cdb[0]);
//
// Determine the length of the CDB first
//
for(i = 0; i < 12; i++) {
spt->Spt.Cdb[i];
}
if(!DeviceIoControl(device,
IOCTL_SCSI_PASS_THROUGH,
spt,
sizeof(SPT_WITH_BUFFERS),
spt,
sizeof(SPT_WITH_BUFFERS),
&returned,
FALSE)) {
errorValue = GetLastError();
printf("Eject - error sending IOCTL (%d)\n", errorValue);
}
free(spt);
return errorValue;
}
DWORD TestCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
Tests the command "parsing"
Arguments:
device - a file handle to send the ioctl to
argc - the number of additional arguments. should be zero
argv - the additional arguments
Return Value:
STATUS_SUCCESS if successful
The value of GetLastError() from the point of failure
--*/
{
int i;
printf("Test - %d additional arguments\n", argc);
for(i = 0; i < argc; i++) {
printf("arg %d: %s\n", i, argv[i]);
}
return STATUS_SUCCESS;
}
DWORD ListCommand(HANDLE device, int argc, char *argv[])
/*++
Routine Description:
Prints out the command list
Arguments:
device - unused
argc - unused
argv - unused
Return Value:
STATUS_SUCCESS
--*/
{
int i = 0;
while(CommandArray[i].Name != NULL) {
if(CommandArray[i].Description != NULL) {
printf("\t%s - %s\n",
CommandArray[i].Name,
CommandArray[i].Description);
}
i++;
}
return STATUS_SUCCESS;
}