⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aspi.c

📁 unix 下tar 执行程序的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#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 + -