scsitape.c
来自「通用SCSI设备备份/读写程序」· C语言 代码 · 共 852 行 · 第 1/2 页
C
852 行
return 1; } return 0;}#ifdef MTSRSZstatic int Solaris_setblk(int fh,int count) { /* we get here only if we have a MTSRSZ, which means Solaris. */ struct mtop mt_com; /* the struct used for the MTIOCTOP ioctl */ int result; /* okay, we have fh and count.... */ /* Now to try the ioctl: */ mt_com.mt_op=MTSRSZ; mt_com.mt_count=count; /* surround the actual ioctl to enable threading, since fsf/etc. can be * big time consumers and we want other threads to be able to run too. */ result=ioctl(fh, MTIOCTOP, (char *)&mt_com); if (result < 0) { return errno; } /* okay, we did okay. Return a value of None... */ return 0;}#endif /* okay, this is a write: we need to set the block size to something: */static int S_setblk(void) { RequestSense_T sense; CDB_T CDB; unsigned char buffer[12]; unsigned int count = (unsigned int) arg1; CDB[0]=0x15; /* MODE SELECT */ CDB[1]=0x10; /* scsi2 */ CDB[2]=0; CDB[3]=0; CDB[4]=12; /* length of data */ CDB[5]=0; slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T)); slow_bzero(buffer,12); /* Now to set the mode page header: */ buffer[0]=0; buffer[1]=0; buffer[2]=0x10; /* we are in buffered mode now, people! */ buffer[3]=8; /* block descriptor length. */ buffer[4]=0; /* reset to default density, sigh. */ /* 0 */ buffer[5]=0; /* 1 */ buffer[6]=0; /* 2 */ buffer[7]=0; /* 3 */ buffer[8]=0; /* 4 */ buffer[9]=(count >> 16) & 0xff; /* 5 */ buffer[10]=(count >> 8) & 0xff; /* 6 */ buffer[11]= count & 0xff; /* 7 */ if (SCSI_ExecuteCommand(MediumChangerFD,Output,&CDB,6,buffer,12,&sense)!=0){ PrintRequestSense(&sense); return 1; }#ifdef MTSRSZ /* Solaris_setblk(MediumChangerFD,count); */#endif return 0;}/*************************************************************************//* SCSI read/write calls. These are mostly pulled out of BRU 16.1, * modified to work within the mtxl.h framework rather than the * scsi_lowlevel.h framework. *************************************************************************/ #define MAX_READ_SIZE 128*1024 /* max size of a variable-block read */#define READ_OK 0#define READ_FILEMARK 1#define READ_EOD 2#define READ_EOP 3#define READ_SHORT 5#define READ_ERROR 255#define WRITE_OK 0#define WRITE_ERROR 1#define WRITE_EOM 2#define WRITE_EOV 3/* These are copied out of BRU 16.1, with all the boolean masks changed * to our bitmasks.*/#define S_NO_SENSE(s) ((s).SenseKey == 0x0)#define S_RECOVERED_ERROR(s) ((s).SenseKey == 0x1)#define S_NOT_READY(s) ((s).SenseKey == 0x2)#define S_MEDIUM_ERROR(s) ((s).SenseKey == 0x3)#define S_HARDWARE_ERROR(s) ((s).SenseKey == 0x4)#define S_UNIT_ATTENTION(s) ((s).SenseKey == 0x6)#define S_BLANK_CHECK(s) ((s).SenseKey == 0x8)#define S_VOLUME_OVERFLOW(s) ((s).SenseKey == 0xd)#define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */#define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s).Filemark && (s).Valid)/* Sigh, the T-10 SSC spec says all of the following is needed to * detect a short read while in variable block mode. We'll see. */#define SHORT_READ(s) (S_NO_SENSE((s)) && (s).ILI && (s).Valid && (s).AdditionalSenseCode==0 && (s).AdditionalSenseCodeQualifier==0) #define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s).Valid)#define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s).EOM && (s).Valid)#define HIT_EOM(s) ((s).EOM && (s).Valid)#define BECOMING_READY(s) (S_UNIT_ATTENTION((s)) && (s).AdditionalSenseCode == 0x28 && (s).AdditionalSenseCodeQualifier == 0)/* Reading is a problem. We can hit a filemark, hit an EOD, or hit an * EOP. Our caller may do something about that. Note that we assume that * our caller has already put us into fixed block mode. If he has not, then * we are in trouble anyhow. */int SCSI_readt(DEVICE_TYPE fd, char * buf, unsigned int bufsize, unsigned int *len, unsigned int timeout) { int rtnval; CDB_T cmd; int blockCount; int info; RequestSense_T RequestSense; if (bufsize==0) { /* we are in variable block mode */ blockCount=MAX_READ_SIZE; /* variable block size. */ } else { blockCount= *len / bufsize ; if ((*len % bufsize) != 0) { fprintf(stderr,"Error: Data (%d bytes) not even multiple of block size (%d bytes).\n",*len,bufsize); exit(1); /* we're finished, sigh. */ } } if (timeout == 0) { timeout = 1 * 60; /* 1 minutes */ } memset(&cmd, 0, sizeof(CDB_T)); cmd[0] = 0x08; /* READ */ cmd[1] = (bufsize) ? 1 : 0; /* fixed length or var length blocks */ cmd[2] = (blockCount >> 16) & 0xff; /* MSB */ cmd[3] = (blockCount >> 8) & 0xff; cmd[4] = blockCount & 0xff; /* LSB */ /* okay, let's read, look @ the result code: */ rtnval=READ_OK; if (SCSI_ExecuteCommand(fd,Input,&cmd,6,buf,(bufsize) ? *len : MAX_READ_SIZE,&RequestSense)) { rtnval=READ_ERROR; if (HIT_EOP(RequestSense)) { cmd[0]=0x08; rtnval=READ_EOP; } if (HIT_FILEMARK(RequestSense)) { rtnval=READ_FILEMARK; } if (HIT_EOD(RequestSense)) { rtnval=READ_EOD; } if ( (bufsize==0) && SHORT_READ(RequestSense)) { rtnval=READ_SHORT; /* we only do short reads for variable block mode */ } if (rtnval != READ_ERROR) { /* info contains number of blocks or bytes *not* read. May be negative if the block we were trying to read was too big. So we will have to account for that and set it to zero if so, so that we return the proper # of blocks read. */ info=((RequestSense.Information[0]<<24) + (RequestSense.Information[1]<<16) + (RequestSense.Information[2]<<8) + RequestSense.Information[3]); /* on 64-bit platforms, we may need to turn 'info' into a negative # */ if (info > 0x7fffffff) info = 0; if (info < 0) info=0; /* make sure we don't return too big len read. */ /* Now set *len to # of bytes read. */ *len= bufsize ? (blockCount-info) * bufsize : MAX_READ_SIZE-info ; } else { PrintRequestSense(&RequestSense); exit(1); /* foo. */ } } return(rtnval);}/* Low level SCSI write. Modified from BRU 16.1, with much BRU smarts * taken out and with the various types changed to mtx types rather than * BRU types. */ int SCSI_writet(DEVICE_TYPE fd, char * buf, unsigned int blocksize, unsigned int *len, unsigned int timeout) { CDB_T cmd; int blockCount; int rtnval=0; RequestSense_T RequestSense; if (blocksize==0) { /* we are in variable block mode */ blockCount=*len; /* variable block size. */ } else { blockCount= *len / blocksize ; if ((*len % blocksize) != 0) { fprintf(stderr,"Error: Data (%d bytes) not even multiple of block size (%d bytes).\n",*len,blocksize); exit(1); /* we're finished, sigh. */ } } fprintf(stderr,"Writing %d blocks\n",blockCount); memset(&cmd, 0, sizeof(CDB_T)); cmd[0] = 0x0a; /* WRITE */ cmd[1] = (blocksize) ? 1 : 0; /* fixed length or var length blocks */ cmd[2] = (blockCount >> 16) & 0xff; /* MSB */ cmd[3] = (blockCount >> 8) & 0xff; cmd[4] = blockCount & 0xff; /* LSB */ if (SCSI_ExecuteCommand(fd,Output,&cmd,6,buf, *len, &RequestSense)) { if (HIT_EOM(RequestSense)) { /* we hit end of media. Return -1. */ if (S_VOLUME_OVERFLOW(RequestSense)) { exit(WRITE_EOV); } exit(WRITE_EOM); /* end of media! */ } else { /* it was plain old write error: */ PrintRequestSense(&RequestSense); exit(WRITE_ERROR); } } else { rtnval = *len; /* worked! */ } return(rtnval);}/* S_write is not implemented yet! */static int S_write(void) { unsigned char *buffer; /* the buffer we're gonna read/write out of. */ int buffersize; int len; /* the length of the data in the buffer */ int blocksize=arg[0]; int numblocks=arg[1]; int varsize=0; /* variable size block flag */ int result; int eof_input; int infile=fileno(stdin); /* sigh */ if (blocksize==0) { varsize=1; buffersize=MAX_READ_SIZE; len=MAX_READ_SIZE; } else { varsize=0; /* fixed block mode */ buffersize=blocksize; len=blocksize; } /* sigh, make it oversized just to have some */ buffer=malloc(buffersize+8); eof_input=0; while (!eof_input) { /* size_t could be 64 bit on a 32 bit platform, so do casts. */ len=0; /* If it is a pipe, we could read 4096 bytes rather than the full * 128K bytes or whatever, so we must gather multiple reads into * the buffer. */ while (len < buffersize) { result=(int)read(infile,buffer+len,(size_t)(buffersize-len)); if (!result) { eof_input=1; if (!len) { /* if we have no deata in our buffer, exit */ return 0; /* we're at end of file! */ } break; /* otherwise, break and write the data */ } len+=result; /* add the result input to our length. */ } result=SCSI_writet(MediumChangerFD,buffer,blocksize,&len,DEFAULT_TIMEOUT); if (!result) { return 1; /* at end of tape! */ } /* Now see if we have numbytes or numblocks. If so, we may wish to exit this loop. */ if (arg[1]) { if (varsize) { /***BUG***/ return 0; /* we will only write one block in variable size mode :-( */ } else { if (numblocks) { numblocks--; } else { return 0; /* we're done. */ } } } } /* and done! */ return 0;}/* Okay, the read thingy: *//* We have a device opened (we hope!) by the parser. * we will have arg[0] and arg[1] being the blocksize and # of blocks * (respectively). */ static int S_read(void) { unsigned char *buffer; /* the buffer we're going to be reading out of */ int buffersize; int len; /* the length of the data in the buffer */ int blocksize=arg[0]; int numblocks=arg[1]; int varsize=0; /* variable size block flag. */ int result; int outfile=fileno(stdout); /* sigh. */ if (blocksize==0) { varsize=1; buffersize=MAX_READ_SIZE; len=MAX_READ_SIZE; } else { varsize=0; /* fixed block mode */ buffersize=blocksize; len=blocksize; } /* sigh, make it oversized just to have some */ buffer=malloc(buffersize+8); while (1) { if (varsize) { /* it could have gotten reset by prior short read... */ len=MAX_READ_SIZE; } result=SCSI_readt(MediumChangerFD,buffer,blocksize, &len, DEFAULT_TIMEOUT); if (result==READ_FILEMARK || result==READ_EOD || result==READ_EOP) { /* okay, normal end of file? */ if (len > 0) { write(outfile,buffer,len); }#ifdef NEED_TO_GO_PAST_FILEMARK /* Now, let's try to go past the filemark if that's what we hit: */ if (result==READ_FILEMARK) { arg1=1; /* arg for S_fsf. */ S_fsf(); /* and go forward 1 filemark, we hope! */ }#endif return 0; /* hit normal end of file. */ } else if (result==READ_SHORT) { /* short reads are only valid in variable block mode. */ if (varsize) { if (len > 0) { write(outfile,buffer,len); } } else { fprintf(stderr,"scsitape:Short Read encountered on input. Aborting.\n"); fflush(stderr); exit(1); /* error exit! */ } } else if (result==READ_OK) { write(outfile,buffer,len); } else { fprintf(stderr,"scsitape:Read Error\n"); fflush(stderr); exit(1); } /* Now see if we have numbytes or numblocks: if so, we may wish to * exit this loop. */ if (arg[1]) { if (varsize) { /****BUG****/ return 0; /* we're only reading one block in var size mode! */ } else { if (numblocks) { numblocks--; } else { return 0; /* we're done. */ } } } }} /* got the goddam cancer of the curly braces. You can tell I used to * do Lisp. *//* See parse_args for the scoop. parse_args does all. */int main(int argc, char **argv) { argv0=argv[0]; parse_args(argc,argv); if (device) SCSI_CloseDevice(device,MediumChangerFD); exit(0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?