📄 aspi.c
字号:
#ident "$Id: aspi.c,v 1.1 1992/01/15 01:14:12 chris Exp $"
#include <stdio.h>
#include <fcntl.h>
#include <dos.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include <errno.h>
/*
* $Log: aspi.c,v $
* Revision 1.1 1992/01/15 01:14:12 chris
* Initial revision
*
*
*
* chris@alderan.sdata.de
*/
#define DWORD unsigned long
#ifndef TAPE_ID
#define TAPE_ID "0:4:0"
#endif
#include "aspi.h"
#include "scsi.h"
#include "scsierr.h"
#ifndef CTCTRL
#include "tar.h"
#endif
static char *aspi_c_id = "$Id: aspi.c,v 1.1 1992/01/15 01:14:12 chris Exp $";
void aspiinit();
extern int errno;
/*
* The complete scsi address of our tape device
*/
int adapter_id, scsi_tape_id, lun_id;
/*
* Because all the scsi functions start with:
* SCSIfunc(adapter_id, scsi_tape_id, lun, .......)
* .. we define a macro "TARGET", so that we can write SCSIfunc(TARGET, ...);
*/
#define TARGET adapter_id, scsi_tape_id, lun_id
#ifndef CTCTRL
/* Flags to for use with the streamer (detected at aspiopen()) */
static int aspifile, no_rewind;
/* This holds the max., and min. recordsize, the streamer can deal with */
static blocklimit lim;
static long recsize; /* the record size to use */
static int logrec; /* log2(recordsize) */
static long apos; /* this holds the current archive file pointer */
static int write_file_mark_on_close;
static int end_of_medium;
static unsigned char rsense[14]; /* array for scsi-sense-data */
/*
* The next two functions are called when you open a file.
* They check if the filename specifies the scsi-tape.
* The filenames used for that are "/dev/ct" - "rewind cartridge tape"
* and "/dev/nrct" - "no rewind cartridge tape" (no rewind on close)
* I just choose those names "/dev/ct" and "/dev/nrct" because the
* filenames are unusual to exist on a MSDOS filesystem and also because
* I'm used to them from my ix386. Anyway, there are no other dependencies
* on those names in the whole program. So, if you prefer to change the
* names to "/dev/rmt0" or whatever, just change them !
* As you can see in aspicreate() and aspiopen(), I still open a
* MSDOS-output-dummy-file. "nul:" is kind of /dev/null for MSDOS
* and I had to do this because the MSDOS code from tar still
* does some operations on this file like setmode(stream) etc. and
* I was too lazy to change the code in tar. So, with this they
* may do setmode()'s on the null-device as long as they want :-)
*/
/*
* Create an archive file
*/
aspicreat(path, mode)
char *path;
int mode;
{
end_of_medium = 0;
if ( !strcmp(path, "/dev/ct") ) {
apos = 0l;
no_rewind = 0;
aspiinit();
write_file_mark_on_close = 1;
return (aspifile=creat("NUL", mode));
} else if ( !strcmp(path,"/dev/nrct") ) {
apos = 0l;
no_rewind = 1;
aspiinit();
write_file_mark_on_close = 1;
return (aspifile=creat("NUL", mode));
}
aspifile = -1;
return creat(path, mode);
}
/*
* Open an archive file
*/
aspiopen(path, oflag, mode)
char *path;
int oflag;
int mode;
{
end_of_medium = 0;
if ( !strcmp(path, "/dev/ct") ) {
apos = 0l;
no_rewind = 0;
aspiinit();
if ( (oflag & O_WRONLY) || (oflag & O_RDWR) )
write_file_mark_on_close = 1;
else write_file_mark_on_close = 0;
return (aspifile=open("NUL", oflag, mode));
} else if ( !strcmp(path,"/dev/nrct") ) {
apos = 0l;
no_rewind = 1;
aspiinit();
if ( (oflag & O_WRONLY) || (oflag & O_RDWR) )
write_file_mark_on_close = 1;
else write_file_mark_on_close = 0;
return (aspifile=open("NUL", oflag, mode));
}
aspifile = -1;
return open(path, oflag, mode);
}
/*
* So, all the other functions now just check if (fileds == aspifile)
* and do redirect the opereation to the tape. Otherwise they just
* hand the request to the original function (e.g aspiread()->read() etc.).
*/
/*
* Read data from an archive file
*/
aspiread(fileds, buf, nbyte)
int fileds;
char *buf;
int nbyte;
{
int i;
unsigned int *u;
if ( fileds == aspifile ) {
u = ( unsigned int * ) &nbyte; /* Hack, I know */
if ( nbyte % ( int ) recsize ) {
( void ) fprintf(stderr,
"aspiread: Illegal blocklen for tape: %u\n", nbyte);
( void ) aspiclose(fileds);
exit(EX_SYSTEM);
}
i = SCSIRead(TARGET, buf, ( long ) *u, logrec, 0, 1, rsense);
if ( i ) { /* If any error ... */
unsigned bytes_read;
if ( i == E$BlankCheck ) { /* EEOM (early end of medium) */
errno = ENOSPC;
if ( (rsense[2] & 0x40) && (rsense[0] &0x80) ) {
/* compute the number of bytes read */
bytes_read = *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
apos += ( long ) bytes_read;
return ( int ) bytes_read;
} else return 0;
} else if ( (i==E$Medium) && (rsense[2] & 0x40) && (rsense[0] & 0x80) ) {
errno = ENOSPC;
bytes_read = *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
apos += ( long ) bytes_read;
return ( int ) bytes_read;
} else {
( void ) fprintf(stderr,"aspiread: errno: %d\n", i);
( void ) aspiclose(fileds);
exit(EX_SYSTEM);
}
}
apos += ( long ) *u;
return nbyte;
}
return read(fileds, buf, nbyte);
}
/*
* Write data to an archive file
*/
aspiwrite(fileds, buf, nbyte)
int fileds;
char *buf;
int nbyte;
{
int i;
unsigned int *u;
if ( fileds == aspifile ) {
if ( end_of_medium ) {
/*
* This only happens when an end_of_medium condition was detected
* at the previous aspiwrite() call but all bytes were written to
* the tape anyway. In this case we don't make anymore attempts to
* write to the tape but return an ENOSPC error and set the size
* of transfered bytes to 0
*/
errno = ENOSPC;
return 0;
}
u = ( unsigned int * ) &nbyte; /* Hack , i know */
if ( nbyte % ( int ) recsize ) {
( void ) fprintf(stderr,
"aspiwrite: Illegal blocklen for tape: %u\n", nbyte);
( void ) aspiclose(fileds);
exit(EX_SYSTEM);
}
i = SCSIWrite(TARGET, buf, ( long ) *u, logrec, 1, rsense);
if ( i == E$EndOfMedium ) {
unsigned int bytes_read;
end_of_medium = 1;
if ( (rsense[0] & 0x80) && (rsense[6] || rsense[5]) ) {
/* return the real number of bytes that were written to the tape */
errno = ENOSPC;
bytes_read = *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
apos += ( long ) bytes_read;
return ( int ) bytes_read;
} else i = 0; /* do not return an error if all bytes were written */
}
if ( i ) { /* any other error we can't recover */
( void ) fprintf(stderr,"aspiwrite: errno: %d\n", i);
( void ) aspiclose(fileds);
exit(EX_SYSTEM);
}
apos += ( long ) *u;
return nbyte;
}
return write(fileds, buf, nbyte);
}
/*
* close an archive file
*/
aspiclose(fileds)
int fileds;
{
int i;
if ( fileds == aspifile ) {
/* first, write a filemark ! */
if ( write_file_mark_on_close && (!end_of_medium) )
if ( (i=SCSIWriteFilemarks(TARGET, 1l, 0, 0, 0)) )
( void ) fprintf(stderr,"aspiclose: Error writing filemark\n");
/* then rewind the tape if we have to */
if ( ! no_rewind ) {
if ( (i=SCSIRewind(TARGET, 0, 0)) )
( void ) fprintf(stderr,"aspiclose: Error rewinding the tape\n");
} else if ( ! write_file_mark_on_close ) {
/*
* This means we've been reading an archive on a "/dev/nrct" tape.
* In this case we have seek over the filemark at the end of the
* archive.
*/
if ( (i=SCSISpace(TARGET, 1, 1l, 0)) )
( void ) fprintf(stderr,"aspiclose: Error seeking filemark\n");
}
apos = 0l;
}
return close(fileds);
}
/*
* Seek on the archive file
*/
long aspilseek(fileds, offset, whence)
int fileds;
long offset;
int whence;
{
int i;
long newpos;
if ( fileds == aspifile ) {
/*
* NOTE: seeking backwards is not supported by every streamer.
* The Archive Viper 2150S does, but I don't know about others.
*/
switch ( whence ) {
case SEEK_SET:
newpos = offset;
break;
case SEEK_CUR:
newpos = apos + offset;
break;
default:
( void ) fprintf(stderr, "aspilseek: mode %d not supported\n", whence);
( void ) aspiclose(fileds);
exit(EX_SYSTEM);
break;
}
if ( newpos % recsize ) {
( void ) fprintf(stderr,
"aspilseek: can't seek to a non-block-boundary position (%ld)\n",
newpos);
( void ) aspiclose(fileds);
exit(EX_SYSTEM);
}
if ( (i=SCSISpace(TARGET, 0, (newpos-apos)>>logrec, 0)) ) {
( void ) fprintf(stderr, "aspilseek: SCSISpace retuned errno %d\n", i);
( void ) aspiclose(fileds);
exit(EX_SYSTEM);
}
apos = newpos;
return newpos;
}
return lseek(fileds, offset, whence);
}
#endif /* CTCTRL */
/*
* Here we start with all that aspi stuff !!!
* --------------------------------------------
* the way we get the entrypoint of the aspi - module is quite strange,
* but anyway ..
*/
/*
* This will be the function for all aspi requests, it gets
* initialized at aspiinit() and called from aspirequest()
*/
void (far *aspi)(void far *) = (void far *) 0;
/*
* Initialize aspi and the tape device
*/
void aspiinit()
{
int h,i;
long l;
union REGS inregs;
union REGS outregs;
char *getenv(), *tapeid;
if ( (h=open("SCSIMGR$",0)) == -1 ) {
perror("Opening ASPI Manager");
exit(1);
}
/*
* This is an ioctl(READ) to the "SCSIMGR$".
* It returns the entrypoint of the aspi-module (far pointer)
* in the 4 bytes, pointed to by the dx register.
*/
inregs.x.ax = 0x4402;
inregs.x.dx = ( int ) &aspi;
inregs.x.cx = 4;
inregs.x.bx = h;
intdos(&inregs, &outregs);
/*
* Now find out on which device we have to operate
*/
tapeid = getenv("TAPEID");
if ( !tapeid ) tapeid = TAPE_ID;
if ( (tapeid[1] != ':') || (tapeid[3] != ':') ||
(!isdigit(tapeid[0])) || (!isdigit(tapeid[2])) || (!isdigit(tapeid[4])) ) {
( void ) fprintf(stderr,"aspiinit: Illegal TAPEID: \"%s\"\n", tapeid);
exit(1);
} else {
adapter_id = tapeid[0] - '0';
scsi_tape_id = tapeid[2] - '0';
lun_id = tapeid[4] - '0';
}
#ifndef CTCTRL
/*
* Now, check the device ...
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -