mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-07-26 02:29:51 +02:00
772 lines
29 KiB
C
772 lines
29 KiB
C
/* FAKETAPE.C (C) Copyright Roger Bowler, 1999-2012 */
|
|
/* Hercules Tape Device Handler for FAKETAPE */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
/* Original Author: "Fish" (David B. Trout) */
|
|
/* Prime Maintainer: "Fish" (David B. Trout) */
|
|
/* Secondary Maintainer: Ivan Warren */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* This module contains the FAKETAPE emulated tape format support. */
|
|
/* The subroutines in this module are called by the general tape */
|
|
/* device handler (tapedev.c) when the tape format is FAKETAPE. */
|
|
/* Reference information: FSIMS100 Faketape manual */
|
|
/*-------------------------------------------------------------------*/
|
|
/*-------------------------------------------------------------------*/
|
|
/* Messages issued by this module are prefixed HHCTA5nn */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#include "hstdinc.h"
|
|
#include "hercules.h" /* need Hercules control blocks */
|
|
#include "tapedev.h" /* Main tape handler header file */
|
|
#include "ftlib.h" /* Main faketape header file */
|
|
|
|
//#define ENABLE_TRACING_STMTS 1 // (Fish: DEBUGGING)
|
|
//#include "dbgtrace.h" // (Fish: DEBUGGING)
|
|
|
|
/*********************************************************************/
|
|
/* START OF ORIGINAL AWS FUNCTIONS (ISW Additions) */
|
|
/*********************************************************************/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Close a FAKETAPE format file */
|
|
/* New Function added by ISW for consistency with other medias */
|
|
/*-------------------------------------------------------------------*/
|
|
void close_faketape (DEVBLK *dev)
|
|
{
|
|
if( dev->fd >= 0 )
|
|
{
|
|
WRMSG (HHC00201, "I", LCSS_DEVNUM, dev->filename, "fake");
|
|
close(dev->fd);
|
|
}
|
|
STRLCPY( dev->filename, TAPE_UNLOADED );
|
|
dev->fd=-1;
|
|
dev->blockid = 0;
|
|
dev->fenced = 0;
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Rewinds a FAKETAPE format file */
|
|
/* New Function added by ISW for consistency with other medias */
|
|
/*-------------------------------------------------------------------*/
|
|
int rewind_faketape (DEVBLK *dev,BYTE *unitstat,BYTE code)
|
|
{
|
|
off_t rcoff;
|
|
rcoff=lseek(dev->fd,0,SEEK_SET);
|
|
if(rcoff<0)
|
|
{
|
|
build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
dev->nxtblkpos=0;
|
|
dev->prvblkpos=-1;
|
|
dev->curfilen=1;
|
|
dev->blockid=0;
|
|
dev->fenced = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Determines if a FAKETAPE has passed a virtual EOT marker */
|
|
/* New Function added by ISW for consistency with other medias */
|
|
/*-------------------------------------------------------------------*/
|
|
int passedeot_faketape (DEVBLK *dev)
|
|
{
|
|
if(dev->nxtblkpos==0)
|
|
{
|
|
dev->eotwarning = 0;
|
|
return 0;
|
|
}
|
|
if(dev->tdparms.maxsize==0)
|
|
{
|
|
dev->eotwarning = 0;
|
|
return 0;
|
|
}
|
|
if(dev->nxtblkpos + dev->eotmargin > dev->tdparms.maxsize)
|
|
{
|
|
dev->eotwarning = 1;
|
|
return 1;
|
|
}
|
|
dev->eotwarning = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* START OF ORIGINAL RB AWS FUNCTIONS */
|
|
/*********************************************************************/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Open a FAKETAPE format file */
|
|
/* */
|
|
/* If successful, the file descriptor is stored in the device block */
|
|
/* and the return value is zero. Otherwise the return value is -1. */
|
|
/*-------------------------------------------------------------------*/
|
|
int open_faketape( DEVBLK* dev, BYTE* unitstat, BYTE code )
|
|
{
|
|
int rc = -1; /* Return code */
|
|
char pathname[MAX_PATH]; /* file path in host format */
|
|
|
|
/* Check for no tape in drive */
|
|
|
|
if (strcmp( dev->filename, TAPE_UNLOADED ) == 0)
|
|
{
|
|
build_senseX( TAPE_BSENSE_TAPEUNLOADED, dev, unitstat, code );
|
|
return -1;
|
|
}
|
|
|
|
/* Open the FAKETAPE file */
|
|
|
|
hostpath( pathname, dev->filename, sizeof( pathname ));
|
|
|
|
if (!dev->tdparms.logical_readonly)
|
|
{
|
|
rc = HOPEN( pathname, O_RDWR | O_BINARY,
|
|
S_IRUSR | S_IWUSR | S_IRGRP );
|
|
|
|
if (rc < 0 && sysblk.auto_tape_create)
|
|
{
|
|
/* Automatically create the missing tape file */
|
|
rc = HOPEN( pathname, O_RDWR | O_BINARY | O_CREAT,
|
|
S_IRUSR | S_IWUSR | S_IRGRP );
|
|
|
|
if (rc >= 0)
|
|
{
|
|
int tmp_fd = dev->fd;
|
|
int ret_code = 0;
|
|
dev->fd = rc;
|
|
|
|
// "%1d:%04X Tape file %s, type %s: tape created"
|
|
WRMSG( HHC00235, "I", LCSS_DEVNUM,
|
|
dev->filename, "fake" );
|
|
|
|
/* Write two tapemarks */
|
|
ret_code = write_fakemark( dev, unitstat, code );
|
|
|
|
if (ret_code >= 0)
|
|
ret_code = write_fakemark( dev, unitstat, code );
|
|
|
|
if (ret_code < 0)
|
|
{
|
|
dev->fd = tmp_fd;
|
|
rc = ret_code;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* If file is read-only open it again with read-only access */
|
|
if (0
|
|
|| dev->tdparms.logical_readonly
|
|
|| (rc < 0 && (EROFS == errno || EACCES == errno))
|
|
)
|
|
{
|
|
dev->readonly = 1;
|
|
rc = HOPEN( pathname, O_RDONLY | O_BINARY, S_IRUSR | S_IRGRP );
|
|
}
|
|
|
|
/* Check for open failure */
|
|
|
|
if (rc < 0)
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: error in function %s: %s"
|
|
WRMSG (HHC00205, "E", LCSS_DEVNUM, dev->filename, "fake", "open()", strerror(errno));
|
|
|
|
STRLCPY( dev->filename, TAPE_UNLOADED );
|
|
build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Open success. Save file descriptor and rewind to load-point */
|
|
|
|
dev->fd = rc;
|
|
rc = rewind_faketape( dev, unitstat, code );
|
|
return rc;
|
|
|
|
} /* end function open_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a FAKETAPE block header */
|
|
/* */
|
|
/* If successful, return value is zero, and prvblkl and curblkl are */
|
|
/* set to the previous and current block lengths respectively. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/* and prvblkl and curblkl are undefined. Either or both of prvblkl */
|
|
/* and/or curblkl may be NULL. */
|
|
/*-------------------------------------------------------------------*/
|
|
int readhdr_faketape (DEVBLK *dev, off_t blkpos,
|
|
U16* pprvblkl, U16* pcurblkl,
|
|
BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t rcoff; /* Return code from lseek() */
|
|
FAKETAPE_BLKHDR fakehdr; /* FakeTape block header */
|
|
char sblklen[5]; /* work for converting hdr */
|
|
int prvblkl; /* Previous block length */
|
|
int curblkl; /* Current block length */
|
|
int xorblkl; /* XOR check of block lens */
|
|
|
|
/* Reposition file to the requested block header */
|
|
rcoff = lseek (dev->fd, blkpos, SEEK_SET);
|
|
if (rcoff < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "lseek()", blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Read the 12-ASCII-hex-character block header */
|
|
rc = read (dev->fd, &fakehdr, sizeof(FAKETAPE_BLKHDR));
|
|
|
|
/* Handle read error condition */
|
|
if (rc < 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "read()", blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Handle end of file (uninitialized tape) condition */
|
|
if (rc == 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "readhdr_faketape()", blkpos, "end of file (uninitialized tape)");
|
|
|
|
/* Set unit exception with tape indicate (end of tape) */
|
|
build_senseX(TAPE_BSENSE_EMPTYTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Handle end of file within block header */
|
|
if (rc < (int)sizeof(FAKETAPE_BLKHDR))
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "readhdr_faketape()", blkpos, "unexpected end of file");
|
|
|
|
build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Convert the ASCII-hex-character block lengths to binary */
|
|
strncpy( sblklen, fakehdr.sprvblkl, 4 ); sblklen[4] = 0; sscanf( sblklen, "%x", &prvblkl );
|
|
strncpy( sblklen, fakehdr.scurblkl, 4 ); sblklen[4] = 0; sscanf( sblklen, "%x", &curblkl );
|
|
strncpy( sblklen, fakehdr.sxorblkl, 4 ); sblklen[4] = 0; sscanf( sblklen, "%x", &xorblkl );
|
|
|
|
/* Verify header integrity using the XOR header field */
|
|
if ( (prvblkl ^ curblkl) != xorblkl )
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "readhdr_faketape()", blkpos, "block header damage");
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Return the converted value(s) to the caller */
|
|
if (pprvblkl) *pprvblkl = prvblkl;
|
|
if (pcurblkl) *pcurblkl = curblkl;
|
|
|
|
/* Successful return */
|
|
return 0;
|
|
|
|
} /* end function readhdr_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a block from a FAKETAPE format file */
|
|
/* */
|
|
/* If successful, return value is block length read. */
|
|
/* If a tapemark was read, the return value is zero, and the */
|
|
/* current file number in the device block is incremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int read_faketape (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t blkpos; /* Offset of block header */
|
|
U16 curblkl; /* Current block length */
|
|
|
|
/* Initialize current block position */
|
|
blkpos = dev->nxtblkpos;
|
|
|
|
/* Read the block header to obtain the current block length */
|
|
rc = readhdr_faketape (dev, blkpos, NULL, &curblkl, unitstat,code);
|
|
if (rc < 0) return -1; /* (error message already issued) */
|
|
|
|
/* Calculate the offset of the next block header */
|
|
blkpos += sizeof(FAKETAPE_BLKHDR) + curblkl;
|
|
|
|
/* If not a tapemark, read the data block */
|
|
if (curblkl > 0)
|
|
{
|
|
rc = read (dev->fd, buf, curblkl);
|
|
|
|
/* Handle read error condition */
|
|
if (rc < 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "read()", blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Handle end of file within data block */
|
|
if (rc < curblkl)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "read_faketape()", blkpos, "end of file within data block");
|
|
|
|
/* Set unit check with data check and partial record */
|
|
build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Calculate the offsets of the next and previous blocks */
|
|
dev->prvblkpos = dev->nxtblkpos;
|
|
dev->nxtblkpos = blkpos;
|
|
|
|
/* Increment the block number */
|
|
dev->blockid++;
|
|
|
|
/* Increment file number and return zero if tapemark was read */
|
|
if (curblkl == 0)
|
|
{
|
|
dev->curfilen++;
|
|
return 0; /* UX will be set by caller */
|
|
}
|
|
|
|
/* Return block length */
|
|
return curblkl;
|
|
|
|
} /* end function read_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Write a FAKETAPE block header */
|
|
/* */
|
|
/* If successful, return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC. */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
int writehdr_faketape (DEVBLK *dev, off_t blkpos,
|
|
U16 prvblkl, U16 curblkl,
|
|
BYTE *unitstat, BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t rcoff; /* Return code from lseek() */
|
|
FAKETAPE_BLKHDR fakehdr; /* FAKETAPE block header */
|
|
char sblklen[5]; /* work buffer */
|
|
|
|
/* Position file to where block header is to go */
|
|
rcoff = lseek (dev->fd, blkpos, SEEK_SET);
|
|
if (rcoff < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "lseek()", blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Build the 12-ASCII-hex-character block header */
|
|
/* Note : strings are not NULL terminated in the faketape header */
|
|
/* hence the use of an intermediate buffer */
|
|
MSGBUF( sblklen, "%4.4X", prvblkl );
|
|
memcpy( fakehdr.sprvblkl, sblklen, sizeof(fakehdr.sprvblkl) );
|
|
MSGBUF( sblklen, "%4.4X", curblkl );
|
|
memcpy( fakehdr.scurblkl, sblklen, sizeof(fakehdr.scurblkl) );
|
|
MSGBUF( sblklen, "%4.4X", prvblkl ^ curblkl );
|
|
memcpy( fakehdr.sxorblkl, sblklen, sizeof(fakehdr.sxorblkl) );
|
|
|
|
/* Write the block header */
|
|
rc = write (dev->fd, &fakehdr, sizeof(FAKETAPE_BLKHDR));
|
|
if (rc < (int)sizeof(FAKETAPE_BLKHDR))
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "write()", blkpos, strerror(errno));
|
|
if(errno==ENOSPC)
|
|
{
|
|
/* Disk FULL */
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
} /* end function writehdr_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Write a block to a FAKETAPE format file */
|
|
/* */
|
|
/* If successful, return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int write_faketape (DEVBLK *dev, const BYTE *buf, U32 blklen,
|
|
BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t rcoff; /* Return code from lseek() */
|
|
off_t blkpos; /* Offset of block header */
|
|
U16 prvblkl; /* Length of previous block */
|
|
|
|
/* Initialize current block position and previous block length */
|
|
blkpos = dev->nxtblkpos;
|
|
prvblkl = 0;
|
|
|
|
/* Determine previous block length if not at start of tape */
|
|
if (dev->nxtblkpos > 0)
|
|
{
|
|
/* Retrieve the previous block length */
|
|
rc = readhdr_faketape (dev, dev->prvblkpos, NULL, &prvblkl, unitstat,code);
|
|
if (rc < 0) return -1;
|
|
|
|
/* Recalculate the offset of the next block */
|
|
blkpos = dev->prvblkpos + sizeof(FAKETAPE_BLKHDR) + prvblkl;
|
|
}
|
|
|
|
/* Reposition file to the new block header */
|
|
rcoff = lseek (dev->fd, blkpos, SEEK_SET);
|
|
if (rcoff < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "lseek()", blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
/* ISW: Determine if we are passed maxsize */
|
|
if(dev->tdparms.maxsize>0)
|
|
{
|
|
if((off_t)(dev->nxtblkpos+blklen+sizeof(FAKETAPE_BLKHDR)) > dev->tdparms.maxsize)
|
|
{
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
}
|
|
/* ISW: End of virtual physical EOT determination */
|
|
|
|
/* Write the block header */
|
|
rc = writehdr_faketape (dev, rcoff, prvblkl, blklen, unitstat, code);
|
|
if (rc < 0) return -1; /* (error message already issued) */
|
|
|
|
/* Calculate the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = blkpos + sizeof(FAKETAPE_BLKHDR) + blklen;
|
|
dev->prvblkpos = blkpos;
|
|
|
|
/* Write the data block */
|
|
rc = write (dev->fd, buf, blklen);
|
|
if (rc < (int)blklen)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "write()", blkpos, strerror(errno));
|
|
if(errno==ENOSPC)
|
|
{
|
|
/* Disk FULL */
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Increment the block number */
|
|
dev->blockid++;
|
|
|
|
/* Set new physical EOF */
|
|
do rc = ftruncate( dev->fd, dev->nxtblkpos );
|
|
while (EINTR == rc);
|
|
|
|
if (rc != 0)
|
|
{
|
|
/* Handle write error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "ftruncate()", blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function write_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Write a tapemark to a FAKETAPE format file */
|
|
/* */
|
|
/* If successful, return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int write_fakemark (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t rcoff; /* Return code from lseek() */
|
|
off_t blkpos; /* Offset of block header */
|
|
U16 prvblkl; /* Length of previous block */
|
|
|
|
/* Initialize current block position and previous block length */
|
|
blkpos = dev->nxtblkpos;
|
|
prvblkl = 0;
|
|
|
|
/* Determine previous block length if not at start of tape */
|
|
if (dev->nxtblkpos > 0)
|
|
{
|
|
/* Retrieve the previous block length */
|
|
rc = readhdr_faketape (dev, dev->prvblkpos, NULL, &prvblkl, unitstat,code);
|
|
if (rc < 0) return -1;
|
|
|
|
/* Recalculate the offset of the next block */
|
|
blkpos = dev->prvblkpos + sizeof(FAKETAPE_BLKHDR) + prvblkl;
|
|
}
|
|
|
|
/* Reposition file to the new block header */
|
|
rcoff = lseek (dev->fd, blkpos, SEEK_SET);
|
|
if (rcoff < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "lseek()", blkpos, strerror(errno));
|
|
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
/* ISW: Determine if we are passed maxsize */
|
|
if(dev->tdparms.maxsize>0)
|
|
{
|
|
if((off_t)(dev->nxtblkpos+sizeof(FAKETAPE_BLKHDR)) > dev->tdparms.maxsize)
|
|
{
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
}
|
|
/* ISW: End of virtual physical EOT determination */
|
|
|
|
/* Write the block header */
|
|
rc = writehdr_faketape (dev, rcoff, prvblkl, 0, unitstat, code);
|
|
if (rc < 0) return -1; /* (error message already issued) */
|
|
|
|
/* Increment the block number */
|
|
dev->blockid++;
|
|
|
|
/* Calculate the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = blkpos + sizeof(FAKETAPE_BLKHDR);
|
|
dev->prvblkpos = blkpos;
|
|
|
|
/* Set new physical EOF */
|
|
do rc = ftruncate( dev->fd, dev->nxtblkpos );
|
|
while (EINTR == rc);
|
|
|
|
if (rc != 0)
|
|
{
|
|
/* Handle write error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, dev->filename, "fake", "ftruncate()", blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function write_fakemark */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Synchronize a FAKETAPE format file (i.e. flush buffers to disk) */
|
|
/* */
|
|
/* If successful, return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int sync_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
/* Unit check if tape is write-protected */
|
|
if (dev->readonly)
|
|
{
|
|
build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Perform sync. Return error on failure. */
|
|
if (fdatasync( dev->fd ) < 0)
|
|
{
|
|
/* Log the error */
|
|
WRMSG (HHC00205, "E", LCSS_DEVNUM, dev->filename, "fake", "fdatasync()", strerror(errno));
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function sync_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space over next block of a FAKETAPE format file */
|
|
/* */
|
|
/* If successful, return value is the length of the block skipped. */
|
|
/* If the block skipped was a tapemark, the return value is zero, */
|
|
/* and the current file number in the device block is incremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsb_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t blkpos; /* Offset of block header */
|
|
U16 blklen; /* Block length */
|
|
|
|
/* Initialize current block position */
|
|
blkpos = dev->nxtblkpos;
|
|
|
|
/* Read the block header to obtain the current block length */
|
|
rc = readhdr_faketape (dev, blkpos, NULL, &blklen, unitstat,code);
|
|
if (rc < 0) return -1; /* (error message already issued) */
|
|
|
|
/* Calculate the offset of the next block */
|
|
blkpos += sizeof(FAKETAPE_BLKHDR) + blklen;
|
|
|
|
/* Calculate the offsets of the next and previous blocks */
|
|
dev->prvblkpos = dev->nxtblkpos;
|
|
dev->nxtblkpos = blkpos;
|
|
|
|
/* Increment current file number if tapemark was skipped */
|
|
if (blklen == 0)
|
|
dev->curfilen++;
|
|
|
|
/* Increment the block number */
|
|
dev->blockid++;
|
|
|
|
/* Return block length or zero if tapemark */
|
|
return blklen;
|
|
|
|
} /* end function fsb_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Backspace to previous block of a FAKETAPE format file */
|
|
/* */
|
|
/* If successful, return value is the length of the block. */
|
|
/* If the block is a tapemark, the return value is zero, */
|
|
/* and the current file number in the device block is decremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int bsb_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
U16 curblkl; /* Length of current block */
|
|
U16 prvblkl; /* Length of previous block */
|
|
off_t blkpos; /* Offset of block header */
|
|
|
|
/* Unit check if already at start of tape */
|
|
if (dev->nxtblkpos == 0)
|
|
{
|
|
build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Backspace to previous block position */
|
|
blkpos = dev->prvblkpos;
|
|
|
|
/* Read the block header to obtain the block lengths */
|
|
rc = readhdr_faketape (dev, blkpos, &prvblkl, &curblkl, unitstat,code);
|
|
if (rc < 0) return -1; /* (error message already issued) */
|
|
|
|
/* Calculate the offset of the previous block */
|
|
dev->prvblkpos = blkpos - sizeof(FAKETAPE_BLKHDR) - prvblkl;
|
|
dev->nxtblkpos = blkpos;
|
|
|
|
/* Decrement current file number if backspaced over tapemark */
|
|
if (curblkl == 0)
|
|
dev->curfilen--;
|
|
|
|
/* Decrement the block number */
|
|
dev->blockid--;
|
|
|
|
/* Return block length or zero if tapemark */
|
|
return curblkl;
|
|
|
|
} /* end function bsb_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space to next logical file of a FAKETAPE format file */
|
|
/* */
|
|
/* For FAKETAPE files, the forward space file operation is achieved */
|
|
/* by forward spacing blocks until positioned just after a tapemark. */
|
|
/* */
|
|
/* If successful, return value is zero, and the current file number */
|
|
/* in the device block is incremented by fsb_faketape. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsf_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
while (1)
|
|
{
|
|
/* Forward space over next block */
|
|
rc = fsb_faketape (dev, unitstat,code);
|
|
if (rc < 0) return -1; /* (error message already issued) */
|
|
|
|
/* Exit loop if spaced over a tapemark */
|
|
if (rc == 0) break;
|
|
|
|
} /* end while */
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function fsf_faketape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Backspace to previous logical file of a FAKETAPE format file */
|
|
/* */
|
|
/* For FAKETAPE files, the backspace file operation is achieved */
|
|
/* by backspacing blocks until positioned just before a tapemark */
|
|
/* or until positioned at start of tape. */
|
|
/* */
|
|
/* If successful, return value is zero, and the current file number */
|
|
/* in the device block is decremented by bsb_faketape. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int bsf_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
while (1)
|
|
{
|
|
/* Exit if now at start of tape */
|
|
if (dev->nxtblkpos == 0)
|
|
{
|
|
build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Backspace to previous block position */
|
|
rc = bsb_faketape (dev, unitstat,code);
|
|
if (rc < 0) return -1; /* (error message already issued) */
|
|
|
|
/* Exit loop if backspaced over a tapemark */
|
|
if (rc == 0) break;
|
|
|
|
} /* end while */
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function bsf_faketape */
|
|
|
|
/*********************************************************************/
|
|
/* END OF ORIGINAL RB AWS FUNCTIONS */
|
|
/*********************************************************************/
|