mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-19 10:15:56 +02:00
The OMA/2 specification defines several optional fields for the "@TDF" entry: DEN1600, DEN6250, SIZE and a type of comment introduced by a ";" character. (Ref: http://support.funsoft.com/flexman/fsims100-faketape10-fsi-007-000-010-003.html)
1205 lines
44 KiB
C
1205 lines
44 KiB
C
/* OMATAPE.C (C) Copyright Roger Bowler, 1999-2012 */
|
|
/* Hercules Tape Device Handler for OMATAPE */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
/* Original Author: Roger Bowler */
|
|
/* Prime Maintainer: Ivan Warren */
|
|
/* Secondary Maintainer: "Fish" (David B. Trout) */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* This module contains the OMATAPE emulated tape format support. */
|
|
/* The subroutines in this module are called by the general tape */
|
|
/* device handler (tapedev.c) when the tape format is OMATAPE. */
|
|
/*-------------------------------------------------------------------*/
|
|
/*-------------------------------------------------------------------*/
|
|
/* Reference information: */
|
|
/* SC53-1200 S/370 and S/390 Optical Media Attach/2 User's Guide */
|
|
/* SC53-1201 S/370 and S/390 Optical Media Attach/2 Technical Ref */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#include "hstdinc.h"
|
|
#include "hercules.h" /* need Hercules control blocks */
|
|
#include "tapedev.h" /* Main tape handler header file */
|
|
|
|
//#define ENABLE_TRACING_STMTS 1 // (Fish: DEBUGGING)
|
|
//#include "dbgtrace.h" // (Fish: DEBUGGING)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read and parse the OMA TDF tape descriptor file */
|
|
/*-------------------------------------------------------------------*/
|
|
int read_omadesc( DEVBLK* dev )
|
|
{
|
|
FILE* oma; /* OMA tape descriptor file */
|
|
OMATAPE_DESC* tdftab; /* -> Tape descriptor array */
|
|
int i; /* Array subscript */
|
|
int stmt; /* TDF file statement number */
|
|
int argc; /* Parsed TDF record argc */
|
|
char* argv[ 4 ]; /* Parsed TDF record argv */
|
|
char* tdffilenm; /* -> Filename in TDF record */
|
|
char* tdfformat; /* -> Format in TDF record */
|
|
char* tdfreckwd; /* -> Keyword in TDF record */
|
|
char* tdfblklen; /* -> Length in TDF record */
|
|
char str[512]; /* Stmt. read from OMA file */
|
|
char pathname[ MAX_PATH + 1];/* file path in host format */
|
|
char buf[ MAX_PATH + 32 ]; /* Work for MSGBUF use */
|
|
size_t pathlen; /* Length of TDF path name */
|
|
U16 filecount; /* Number of files */
|
|
U32 blklen; /* Fixed block length */
|
|
BYTE c; /* Work area for sscanf */
|
|
|
|
/* Normalize path separators to be all '/' forward slashes */
|
|
hostpath( pathname, dev->filename, sizeof( pathname ));
|
|
|
|
/* Isolate the base path name of the TDF file */
|
|
for (pathlen = strlen( pathname ); pathlen > 0; )
|
|
{
|
|
pathlen--;
|
|
if (pathname[ pathlen - 1 ] == '/') break;
|
|
}
|
|
|
|
/* Open the TDF tape descriptor file */
|
|
if (!(oma = fopen( pathname, "r" )))
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: error in function %s: %s"
|
|
WRMSG( HHC00205, "E", LCSS_DEVNUM, dev->filename, "OMA", "fopen()", strerror( errno ));
|
|
return -1;
|
|
}
|
|
|
|
/* Check that the first record is a @TDF header
|
|
and count the number of records in the file. */
|
|
for (filecount = 0; fgets( str, sizeof( str ), oma ); filecount++)
|
|
{
|
|
if (filecount != 0) /* If not first record */
|
|
continue; /* then just count it */
|
|
|
|
/* Check that the first record is a @TDF header...
|
|
Note: The OMA/2 specification defines several optional fields
|
|
for the "@TDF" entry: "DEN1600", "DEN6250", "SIZE" and a type
|
|
of comment introduced by a ";" character. Hercules allows for,
|
|
but does not support, any of these.
|
|
*/
|
|
if (0
|
|
|| memcmp( str, "@TDF", 4 ) != 0
|
|
// || (1
|
|
// && str[4] != '\r'
|
|
// && str[4] != '\n'
|
|
// )
|
|
)
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: not a valid @TDF file: %s"
|
|
WRMSG( HHC00206, "E", LCSS_DEVNUM, dev->filename, "OMA",
|
|
"Missing or invalid @TDF header." );
|
|
fclose( oma );
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Check for EOF or I/O error */
|
|
if (ferror( oma ))
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: error in function %s: %s"
|
|
WRMSG( HHC00205, "E", LCSS_DEVNUM, dev->filename, "OMA", "fgets()", strerror( errno ));
|
|
fclose( oma );
|
|
return -1;
|
|
}
|
|
|
|
/* Check for empty file or file with only @TDF statement */
|
|
if (filecount < 2)
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: not a valid @TDF file: %s"
|
|
WRMSG( HHC00206, "E", LCSS_DEVNUM, dev->filename, "OMA",
|
|
"Descriptor contains zero control records." );
|
|
fclose( oma );
|
|
return -1;
|
|
}
|
|
|
|
/* Obtain storage for the tape descriptor array */
|
|
if (!(tdftab = (OMATAPE_DESC*) malloc( filecount * sizeof( OMATAPE_DESC ))))
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: error in function %s: %s"
|
|
WRMSG( HHC00205, "E", LCSS_DEVNUM, dev->filename, "OMA", "malloc()", strerror( errno ));
|
|
return -1;
|
|
}
|
|
|
|
/* Rewind OMA file back to the beginning */
|
|
rewind( oma );
|
|
|
|
/* Now read and actually process each statement in the file... */
|
|
for (filecount = 0, stmt = 1; fgets( str, sizeof( str ), oma ); stmt++)
|
|
{
|
|
/* (skip @TDF statement) */
|
|
if (stmt == 1)
|
|
continue;
|
|
|
|
/* (remove trailing whitespace) */
|
|
RTRIM( str );
|
|
|
|
/* Clear the tape descriptor array entry */
|
|
memset( &(tdftab[ filecount ]), 0, sizeof( OMATAPE_DESC ));
|
|
|
|
/* Exit if EOT record encountered */
|
|
if (str_caseless_eq( str, "EOT" ))
|
|
break;
|
|
|
|
/* TM tapemark record? */
|
|
if (str_caseless_eq( str, "TM" ))
|
|
{
|
|
tdftab[ filecount++ ].format = 'X';
|
|
continue;
|
|
}
|
|
|
|
/* Parse the TDF record */
|
|
parse_args( str, 4, argv, &argc );
|
|
|
|
tdffilenm = argv[0]; /* -> Filename in TDF record */
|
|
tdfformat = argv[1]; /* -> Format in TDF record */
|
|
tdfreckwd = argv[2]; /* -> Keyword in TDF record */
|
|
tdfblklen = argv[3]; /* -> Length in TDF record */
|
|
|
|
/* Check for missing fields */
|
|
if (0
|
|
|| !tdffilenm
|
|
|| !tdfformat
|
|
)
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: line %d: %s"
|
|
WRMSG( HHC00207, "E", LCSS_DEVNUM, dev->filename, "OMA", stmt, "filename or format missing" );
|
|
goto omadesc_error;
|
|
}
|
|
|
|
/* Check that the file name is not too long */
|
|
if (pathlen + 1 + strlen( tdffilenm ) + 1 >= sizeof( tdftab[ filecount ].filename ))
|
|
{
|
|
if (!strchr( tdffilenm, SPACE ))
|
|
MSGBUF( buf, "filename %s too long", tdffilenm );
|
|
else
|
|
MSGBUF( buf, "filename '%s' too long", tdffilenm );
|
|
|
|
// "%1d:%04X Tape file %s, type %s: line %d: %s"
|
|
WRMSG( HHC00207, "E", LCSS_DEVNUM, dev->filename, "OMA", stmt, buf );
|
|
goto omadesc_error;
|
|
}
|
|
|
|
/* Convert the file name to Unix format */
|
|
for (i=0; i < (int) strlen( tdffilenm ); i++)
|
|
{
|
|
if (tdffilenm[i] == '\\')
|
|
tdffilenm[i] = '/';
|
|
}
|
|
|
|
/* Prefix the file name with the base path name
|
|
ONLY if the filename is NOT an absolute path.
|
|
*/
|
|
#if defined(_MSVC_)
|
|
if (tdffilenm[1] != ':') // (not Windows absolute path)
|
|
#else
|
|
if (tdffilenm[0] != '/') // (not Unix absolute path)
|
|
#endif
|
|
{
|
|
/* (use memcpy since "pathlen" has already been checked above) */
|
|
memcpy( tdftab[ filecount ].filename, dev->filename, pathlen );
|
|
tdftab[ filecount ].filename[ pathlen ] = 0;
|
|
|
|
/* Append path separator only if needed */
|
|
if (tdftab[ filecount ].filename[ pathlen - 1 ] != '/')
|
|
STRLCAT( tdftab[ filecount ].filename, "/" );
|
|
}
|
|
|
|
/* Save the file name in the tape descriptor array */
|
|
STRLCAT( tdftab[ filecount ].filename, tdffilenm );
|
|
|
|
/* Check for valid file format code */
|
|
if (str_caseless_eq( tdfformat, "HEADERS" ))
|
|
{
|
|
tdftab[ filecount++ ].format = 'H';
|
|
continue;
|
|
}
|
|
|
|
if (str_caseless_eq( tdfformat, "TEXT" ))
|
|
{
|
|
tdftab[ filecount++ ].format = 'T';
|
|
continue;
|
|
}
|
|
|
|
if /* (treat UNDEFINED same as FIXED) */
|
|
(0
|
|
|| str_caseless_eq( tdfformat, "FIXED" )
|
|
|| str_caseless_eq( tdfformat, "UNDEFINED" )
|
|
)
|
|
{
|
|
/* Check for RECSIZE keyword */
|
|
if (0
|
|
|| !tdfreckwd
|
|
|| str_caseless_ne( tdfreckwd, "RECSIZE" )
|
|
)
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: line %d: %s"
|
|
WRMSG( HHC00207, "E", LCSS_DEVNUM, dev->filename, "OMA", stmt, "keyword RECSIZE missing" );
|
|
goto omadesc_error;
|
|
}
|
|
|
|
/* Check for valid fixed block length */
|
|
if (0
|
|
|| !tdfblklen
|
|
|| sscanf( tdfblklen, "%u%c", &blklen, &c ) != 1
|
|
|| blklen < 1
|
|
|| blklen > USHRT_MAX // (max U16)
|
|
)
|
|
{
|
|
MSGBUF( buf, "invalid record size %s", tdfblklen );
|
|
|
|
// "%1d:%04X Tape file %s, type %s: line %d: %s"
|
|
WRMSG( HHC00207, "E", LCSS_DEVNUM, dev->filename, "OMA", stmt, buf );
|
|
goto omadesc_error;
|
|
}
|
|
|
|
/* Set format and block length in descriptor array */
|
|
tdftab[ filecount ].format = 'F';
|
|
tdftab[ filecount ].blklen = (U16) blklen;
|
|
filecount++;
|
|
continue;
|
|
}
|
|
|
|
/* Not a TDF format that we recognize/support */
|
|
MSGBUF( buf, "invalid record format '%s'", tdfformat );
|
|
|
|
// "%1d:%04X Tape file %s, type %s: line %d: %s"
|
|
WRMSG( HHC00207, "E", LCSS_DEVNUM, dev->filename, "OMA", stmt, buf );
|
|
goto omadesc_error;
|
|
}
|
|
/* end for( fgets( str, oma ) ) */
|
|
|
|
/* Check for EOF or I/O error */
|
|
if (ferror( oma ))
|
|
{
|
|
// "%1d:%04X Tape file %s, type %s: error in function %s: %s"
|
|
WRMSG( HHC00205, "E", LCSS_DEVNUM, dev->filename, "OMA", "fgets()", strerror( errno ));
|
|
goto omadesc_error;
|
|
}
|
|
|
|
/* Close the OMA file */
|
|
fclose( oma );
|
|
|
|
/* Force an EOT as last entry */
|
|
tdftab[ filecount++ ].format = 'E';
|
|
|
|
/* Save the file count and TDF array pointer in the device block */
|
|
dev->omafiles = filecount;
|
|
dev->omadesc = tdftab;
|
|
|
|
return 0;
|
|
|
|
omadesc_error:
|
|
|
|
free( tdftab );
|
|
fclose( oma );
|
|
return -1;
|
|
|
|
} /* end function read_omadesc */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Open the OMATAPE file defined by the current file number */
|
|
/* */
|
|
/* The OMA tape descriptor file is read if necessary. */
|
|
/* 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_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int fd; /* File descriptor integer */
|
|
int rc; /* Return code */
|
|
OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */
|
|
char pathname[MAX_PATH]; /* file path in host format */
|
|
|
|
/* Check for no tape in drive */
|
|
if (!strcmp (dev->filename, TAPE_UNLOADED))
|
|
{
|
|
build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Read the OMA descriptor file if necessary */
|
|
if (dev->omadesc == NULL)
|
|
{
|
|
rc = read_omadesc (dev);
|
|
if (rc < 0)
|
|
{
|
|
build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
dev->blockid = 0;
|
|
}
|
|
|
|
dev->fenced = 0;
|
|
|
|
/* Unit exception if beyond end of tape */
|
|
/* ISW: CHANGED PROCESSING - RETURN UNDEFINITE Tape Marks */
|
|
/* NOTE: The last entry in the TDF table is ALWAYS */
|
|
/* an EOT Condition */
|
|
/* This is ensured by the TDF reading routine */
|
|
if(dev->curfilen>dev->omafiles)
|
|
{
|
|
dev->curfilen=dev->omafiles;
|
|
return(0);
|
|
}
|
|
|
|
/* Point to the current file entry in the OMA descriptor table */
|
|
omadesc = (OMATAPE_DESC*)(dev->omadesc);
|
|
omadesc += (dev->curfilen-1);
|
|
if(omadesc->format=='X')
|
|
{
|
|
return 0;
|
|
}
|
|
if(omadesc->format=='E')
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Open the OMATAPE file */
|
|
hostpath(pathname, omadesc->filename, sizeof(pathname));
|
|
fd = HOPEN (pathname, O_RDONLY | O_BINARY);
|
|
|
|
/* Check for successful open */
|
|
if (fd < 0 || lseek (fd, 0, SEEK_END) > LONG_MAX)
|
|
{
|
|
if (fd >= 0) /* (if open was successful, then it) */
|
|
errno = EOVERFLOW; /* (must have been a lseek overflow) */
|
|
|
|
// "%1d:%04X Tape file %s, type %s: error in function %s: %s"
|
|
WRMSG (HHC00205, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "open()", strerror(errno));
|
|
|
|
if (fd >= 0)
|
|
close(fd); /* (close the file if it was opened) */
|
|
|
|
build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* OMA tapes are always read-only */
|
|
dev->readonly = 1;
|
|
|
|
/* Store the file descriptor in the device block */
|
|
dev->fd = fd;
|
|
return 0;
|
|
|
|
} /* end function open_omatape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a block header from an OMA tape file in OMA headers format */
|
|
/* */
|
|
/* If successful, return value is zero, and the current block */
|
|
/* length and previous and next header offsets are returned. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int readhdr_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc,
|
|
long blkpos, S32 *pcurblkl, S32 *pprvhdro,
|
|
S32 *pnxthdro, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t rcoff; /* Return code from lseek() */
|
|
int padding; /* Number of padding bytes */
|
|
OMATAPE_BLKHDR omahdr; /* OMATAPE block header */
|
|
S32 curblkl; /* Length of current block */
|
|
S32 prvhdro; /* Offset of previous header */
|
|
S32 nxthdro; /* Offset of next header */
|
|
|
|
/* Seek to start of block header */
|
|
rcoff = lseek (dev->fd, blkpos, SEEK_SET);
|
|
if (rcoff < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "lseek()", (off_t)blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Read the 16-byte block header */
|
|
rc = read (dev->fd, &omahdr, sizeof(omahdr));
|
|
|
|
/* Handle read error condition */
|
|
if (rc < 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "read()", (off_t)blkpos,
|
|
strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Handle end of file within block header */
|
|
if (rc < (int)sizeof(omahdr))
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "readhdr_omaheaders()", (off_t)blkpos, "unexpected end of file");
|
|
|
|
/* Set unit check with data check and partial record */
|
|
build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Extract the current block length and previous header offset */
|
|
curblkl = (S32)(((U32)(omahdr.curblkl[3]) << 24)
|
|
| ((U32)(omahdr.curblkl[2]) << 16)
|
|
| ((U32)(omahdr.curblkl[1]) << 8)
|
|
| omahdr.curblkl[0]);
|
|
prvhdro = (S32)((U32)(omahdr.prvhdro[3]) << 24)
|
|
| ((U32)(omahdr.prvhdro[2]) << 16)
|
|
| ((U32)(omahdr.prvhdro[1]) << 8)
|
|
| omahdr.prvhdro[0];
|
|
|
|
/* Check for valid block header */
|
|
if (curblkl < -1 || curblkl == 0 || curblkl > MAX_TAPE_BLKSIZE
|
|
|| memcmp(omahdr.omaid, "@HDF", 4) != 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "readhdr_omaheaders()", (off_t)blkpos, "invalid block header");
|
|
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Calculate the number of padding bytes which follow the data */
|
|
padding = (16 - (curblkl & 15)) & 15;
|
|
|
|
/* Calculate the offset of the next block header */
|
|
nxthdro = blkpos + sizeof(OMATAPE_BLKHDR) + curblkl + padding;
|
|
|
|
/* Return current block length and previous/next header offsets */
|
|
*pcurblkl = curblkl;
|
|
*pprvhdro = prvhdro;
|
|
*pnxthdro = nxthdro;
|
|
return 0;
|
|
|
|
} /* end function readhdr_omaheaders */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a block from an OMA tape file in OMA headers format */
|
|
/* */
|
|
/* If successful, return value is block length read. */
|
|
/* If a tapemark was read, the file is closed, the current file */
|
|
/* number in the device block is incremented so that the next file */
|
|
/* will be opened by the next CCW, and the return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int read_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc,
|
|
BYTE *buf, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
long blkpos; /* Offset to block header */
|
|
S32 curblkl; /* Length of current block */
|
|
S32 prvhdro; /* Offset of previous header */
|
|
S32 nxthdro; /* Offset of next header */
|
|
|
|
/* Read the 16-byte block header */
|
|
blkpos = dev->nxtblkpos;
|
|
rc = readhdr_omaheaders (dev, omadesc, blkpos, &curblkl,
|
|
&prvhdro, &nxthdro, unitstat,code);
|
|
if (rc < 0) return -1;
|
|
|
|
/* Update the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = nxthdro;
|
|
dev->prvblkpos = blkpos;
|
|
|
|
/* Increment file number and return zero if tapemark */
|
|
if (curblkl == -1)
|
|
{
|
|
close (dev->fd);
|
|
dev->fd = -1;
|
|
dev->curfilen++;
|
|
dev->nxtblkpos = 0;
|
|
dev->prvblkpos = -1;
|
|
return 0;
|
|
}
|
|
|
|
/* Read data block from tape file */
|
|
rc = read (dev->fd, buf, curblkl);
|
|
|
|
/* Handle read error condition */
|
|
if (rc < 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "read()", (off_t)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, omadesc->filename, "OMA", "read_omaheaders()", (off_t)blkpos, "unexpected end of file");
|
|
|
|
/* Set unit check with data check and partial record */
|
|
build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Return block length */
|
|
return curblkl;
|
|
|
|
} /* end function read_omaheaders */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a block from an OMA tape file in fixed block format */
|
|
/* */
|
|
/* If successful, return value is block length read. */
|
|
/* If a tapemark was read, the file is closed, the current file */
|
|
/* number in the device block is incremented so that the next file */
|
|
/* will be opened by the next CCW, and the return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int read_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc,
|
|
BYTE *buf, BYTE *unitstat,BYTE code)
|
|
{
|
|
off_t rcoff; /* Return code from lseek() */
|
|
int blklen; /* Block length */
|
|
long blkpos; /* Offset of block in file */
|
|
|
|
/* Initialize current block position */
|
|
blkpos = dev->nxtblkpos;
|
|
|
|
/* Seek to new current block position */
|
|
rcoff = lseek (dev->fd, blkpos, SEEK_SET);
|
|
if (rcoff < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "lseek()", (off_t)blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Read fixed length block or short final block */
|
|
blklen = read (dev->fd, buf, omadesc->blklen);
|
|
|
|
/* Handle read error condition */
|
|
if (blklen < 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "read()", (off_t)blkpos,
|
|
strerror(errno));
|
|
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* At end of file return zero to indicate tapemark */
|
|
if (blklen == 0)
|
|
{
|
|
close (dev->fd);
|
|
dev->fd = -1;
|
|
dev->curfilen++;
|
|
dev->nxtblkpos = 0;
|
|
dev->prvblkpos = -1;
|
|
return 0;
|
|
}
|
|
|
|
/* Calculate the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = blkpos + blklen;
|
|
dev->prvblkpos = blkpos;
|
|
|
|
/* Return block length, or zero to indicate tapemark */
|
|
return blklen;
|
|
|
|
} /* end function read_omafixed */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a block from an OMA tape file in ASCII text format */
|
|
/* */
|
|
/* If successful, return value is block length read. */
|
|
/* If a tapemark was read, the file is closed, the current file */
|
|
/* number in the device block is incremented so that the next file */
|
|
/* will be opened by the next CCW, and the return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/* */
|
|
/* The buf parameter points to the I/O buffer during a read */
|
|
/* operation, or is NULL for a forward space block operation. */
|
|
/*-------------------------------------------------------------------*/
|
|
int read_omatext (DEVBLK *dev, OMATAPE_DESC *omadesc,
|
|
BYTE *buf, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t rcoff; /* Return code from lseek() */
|
|
int num; /* Number of characters read */
|
|
int pos; /* Position in I/O buffer */
|
|
long blkpos; /* Offset of block in file */
|
|
BYTE c; /* Character work area */
|
|
|
|
/* Initialize current block position */
|
|
blkpos = dev->nxtblkpos;
|
|
|
|
/* Seek to new current block position */
|
|
rcoff = lseek (dev->fd, blkpos, SEEK_SET);
|
|
if (rcoff < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "lseek()", (off_t)blkpos, strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Read data from tape file until end of line */
|
|
for (num = 0, pos = 0; ; )
|
|
{
|
|
rc = read (dev->fd, &c, 1);
|
|
if (rc < 1) break;
|
|
|
|
/* Treat X'1A' as end of file */
|
|
if (c == '\x1A')
|
|
{
|
|
rc = 0;
|
|
break;
|
|
}
|
|
|
|
/* Count characters read */
|
|
num++;
|
|
|
|
/* Ignore carriage return character */
|
|
if (c == '\r') continue;
|
|
|
|
/* Exit if newline character */
|
|
if (c == '\n') break;
|
|
|
|
/* Ignore characters in excess of I/O buffer length */
|
|
if (pos >= MAX_TAPE_BLKSIZE) continue;
|
|
|
|
/* Translate character to EBCDIC and copy to I/O buffer */
|
|
if (buf != NULL)
|
|
buf[pos] = host_to_guest(c);
|
|
|
|
/* Count characters copied or skipped */
|
|
pos++;
|
|
|
|
} /* end for(num) */
|
|
|
|
/* At end of file return zero to indicate tapemark */
|
|
if (rc == 0 && num == 0)
|
|
{
|
|
close (dev->fd);
|
|
dev->fd = -1;
|
|
dev->curfilen++;
|
|
dev->nxtblkpos = 0;
|
|
dev->prvblkpos = -1;
|
|
return 0;
|
|
}
|
|
|
|
/* Handle read error condition */
|
|
if (rc < 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "read()", (off_t)blkpos,
|
|
strerror(errno));
|
|
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Check for block not terminated by newline */
|
|
if (rc < 1)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "read_omatext()", (off_t)blkpos, "unexpected end of file");
|
|
|
|
/* Set unit check with data check and partial record */
|
|
build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Check for invalid zero length block */
|
|
if (pos == 0)
|
|
{
|
|
WRMSG (HHC00204, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "read_omatext()", (off_t)blkpos, "invalid block header");
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Calculate the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = blkpos + num;
|
|
dev->prvblkpos = blkpos;
|
|
|
|
/* Return block length */
|
|
return pos;
|
|
|
|
} /* end function read_omatext */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a block from an OMA - Selection of format done here */
|
|
/* */
|
|
/* If successful, return value is block length read. */
|
|
/* If a tapemark was read, the file is closed, the current file */
|
|
/* number in the device block is incremented so that the next file */
|
|
/* will be opened by the next CCW, and the return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/* */
|
|
/* The buf parameter points to the I/O buffer during a read */
|
|
/* operation, or is NULL for a forward space block operation. */
|
|
/*-------------------------------------------------------------------*/
|
|
int read_omatape (DEVBLK *dev,
|
|
BYTE *buf, BYTE *unitstat,BYTE code)
|
|
{
|
|
int len;
|
|
OMATAPE_DESC *omadesc;
|
|
omadesc = (OMATAPE_DESC*)(dev->omadesc);
|
|
omadesc += (dev->curfilen-1);
|
|
|
|
switch (omadesc->format)
|
|
{
|
|
default:
|
|
case 'H':
|
|
len = read_omaheaders (dev, omadesc, buf, unitstat,code);
|
|
break;
|
|
case 'F':
|
|
len = read_omafixed (dev, omadesc, buf, unitstat,code);
|
|
break;
|
|
case 'T':
|
|
len = read_omatext (dev, omadesc, buf, unitstat,code);
|
|
break;
|
|
case 'X':
|
|
len=0;
|
|
dev->curfilen++;
|
|
break;
|
|
case 'E':
|
|
len=0;
|
|
break;
|
|
} /* end switch(omadesc->format) */
|
|
|
|
if (len >= 0)
|
|
dev->blockid++;
|
|
|
|
return len;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space to next file of OMA tape device */
|
|
/* */
|
|
/* For OMA tape devices, the forward space file operation is */
|
|
/* achieved by closing the current file, and incrementing the */
|
|
/* current file number in the device block, which causes the */
|
|
/* next file will be opened when the next CCW is processed. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsf_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
UNREFERENCED(unitstat);
|
|
UNREFERENCED(code);
|
|
|
|
/* Close the current OMA file */
|
|
if (dev->fd >= 0)
|
|
close (dev->fd);
|
|
dev->fd = -1;
|
|
dev->nxtblkpos = 0;
|
|
dev->prvblkpos = -1;
|
|
|
|
/* Increment the current file number */
|
|
dev->curfilen++;
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function fsf_omatape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space over next block of OMA file in OMA headers format */
|
|
/* */
|
|
/* If successful, return value is the length of the block skipped. */
|
|
/* If the block skipped was a tapemark, the return value is zero, */
|
|
/* the file is closed, and the current file number in the device */
|
|
/* block is incremented so that the next file belonging to the OMA */
|
|
/* tape will be opened when the next CCW is executed. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsb_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc,
|
|
BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
long blkpos; /* Offset of block header */
|
|
S32 curblkl; /* Length of current block */
|
|
S32 prvhdro; /* Offset of previous header */
|
|
S32 nxthdro; /* Offset of next header */
|
|
|
|
/* Initialize current block position */
|
|
blkpos = dev->nxtblkpos;
|
|
|
|
/* Read the 16-byte block header */
|
|
rc = readhdr_omaheaders (dev, omadesc, blkpos, &curblkl,
|
|
&prvhdro, &nxthdro, unitstat,code);
|
|
if (rc < 0) return -1;
|
|
|
|
/* Check if tapemark was skipped */
|
|
if (curblkl == -1)
|
|
{
|
|
/* Close the current OMA file */
|
|
if (dev->fd >= 0)
|
|
close (dev->fd);
|
|
dev->fd = -1;
|
|
dev->nxtblkpos = 0;
|
|
dev->prvblkpos = -1;
|
|
|
|
/* Increment the file number */
|
|
dev->curfilen++;
|
|
|
|
/* Return zero to indicate tapemark */
|
|
return 0;
|
|
}
|
|
|
|
/* Update the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = nxthdro;
|
|
dev->prvblkpos = blkpos;
|
|
|
|
/* Return block length */
|
|
return curblkl;
|
|
|
|
} /* end function fsb_omaheaders */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space over next block of OMA file in fixed block format */
|
|
/* */
|
|
/* If successful, return value is the length of the block skipped. */
|
|
/* If already at end of file, the return value is zero, */
|
|
/* the file is closed, and the current file number in the device */
|
|
/* block is incremented so that the next file belonging to the OMA */
|
|
/* tape will be opened when the next CCW is executed. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsb_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc,
|
|
BYTE *unitstat,BYTE code)
|
|
{
|
|
off_t eofpos; /* Offset of end of file */
|
|
off_t blkpos; /* Offset of current block */
|
|
int curblkl; /* Length of current block */
|
|
|
|
/* Initialize current block position */
|
|
blkpos = dev->nxtblkpos;
|
|
|
|
/* Seek to end of file to determine file size */
|
|
eofpos = lseek (dev->fd, 0, SEEK_END);
|
|
if (eofpos < 0 || eofpos >= LONG_MAX)
|
|
{
|
|
/* Handle seek error condition */
|
|
if ( eofpos >= LONG_MAX) errno = EOVERFLOW;
|
|
WRMSG (HHC00205, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "lseek()", strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Check if already at end of file */
|
|
if (blkpos >= eofpos)
|
|
{
|
|
/* Close the current OMA file */
|
|
if (dev->fd >= 0)
|
|
close (dev->fd);
|
|
dev->fd = -1;
|
|
dev->nxtblkpos = 0;
|
|
dev->prvblkpos = -1;
|
|
|
|
/* Increment the file number */
|
|
dev->curfilen++;
|
|
|
|
/* Return zero to indicate tapemark */
|
|
return 0;
|
|
}
|
|
|
|
/* Calculate current block length */
|
|
curblkl = (int)(eofpos - blkpos);
|
|
if (curblkl > omadesc->blklen)
|
|
curblkl = omadesc->blklen;
|
|
|
|
/* Update the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = (long)(blkpos + curblkl);
|
|
dev->prvblkpos = (long)(blkpos);
|
|
|
|
/* Return block length */
|
|
return curblkl;
|
|
|
|
} /* end function fsb_omafixed */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space to next block of OMA file */
|
|
/* */
|
|
/* If successful, return value is the length of the block skipped. */
|
|
/* If forward spaced over end of file, return value is 0. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsb_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */
|
|
|
|
/* Point to the current file entry in the OMA descriptor table */
|
|
omadesc = (OMATAPE_DESC*)(dev->omadesc);
|
|
omadesc += (dev->curfilen-1);
|
|
|
|
/* Forward space block depending on OMA file type */
|
|
switch (omadesc->format)
|
|
{
|
|
default:
|
|
case 'H':
|
|
rc = fsb_omaheaders (dev, omadesc, unitstat,code);
|
|
break;
|
|
case 'F':
|
|
rc = fsb_omafixed (dev, omadesc, unitstat,code);
|
|
break;
|
|
case 'T':
|
|
rc = read_omatext (dev, omadesc, NULL, unitstat,code);
|
|
break;
|
|
} /* end switch(omadesc->format) */
|
|
|
|
if (rc >= 0) dev->blockid++;
|
|
|
|
return rc;
|
|
|
|
} /* end function fsb_omatape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Backspace to previous file of OMA tape device */
|
|
/* */
|
|
/* If the current file number is 1, then backspace file simply */
|
|
/* closes the file, setting the current position to start of tape. */
|
|
/* Otherwise, the current file is closed, the current file number */
|
|
/* is decremented, the new file is opened, and the new file is */
|
|
/* repositioned to just before the tape mark at the end of the file. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int bsf_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t pos; /* File position */
|
|
OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */
|
|
S32 curblkl; /* Length of current block */
|
|
S32 prvhdro; /* Offset of previous header */
|
|
S32 nxthdro; /* Offset of next header */
|
|
|
|
/* Close the current OMA file */
|
|
if (dev->fd >= 0)
|
|
close (dev->fd);
|
|
dev->fd = -1;
|
|
dev->nxtblkpos = 0;
|
|
dev->prvblkpos = -1;
|
|
|
|
/* Exit with tape at load point if currently on first file */
|
|
if (dev->curfilen <= 1)
|
|
{
|
|
build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Decrement current file number */
|
|
dev->curfilen--;
|
|
|
|
/* Point to the current file entry in the OMA descriptor table */
|
|
omadesc = (OMATAPE_DESC*)(dev->omadesc);
|
|
omadesc += (dev->curfilen-1);
|
|
|
|
/* Open the new current file */
|
|
rc = open_omatape (dev, unitstat,code);
|
|
if (rc < 0) return rc;
|
|
|
|
/* Reposition before tapemark header at end of file, or
|
|
to end of file for fixed block or ASCII text files */
|
|
pos = 0;
|
|
if ( 'H' == omadesc->format )
|
|
pos -= sizeof(OMATAPE_BLKHDR);
|
|
|
|
pos = lseek (dev->fd, pos, SEEK_END);
|
|
if (pos < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
WRMSG (HHC00205, "E", LCSS_DEVNUM, omadesc->filename, "OMA", "lseek()", strerror(errno));
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
dev->sense[0] = SENSE_EC;
|
|
*unitstat = CSW_CE | CSW_DE | CSW_UC;
|
|
return -1;
|
|
}
|
|
dev->nxtblkpos = pos;
|
|
dev->prvblkpos = -1;
|
|
|
|
/* Determine the offset of the previous block */
|
|
switch (omadesc->format)
|
|
{
|
|
case 'H':
|
|
/* For OMA headers files, read the tapemark header
|
|
and extract the previous block offset */
|
|
rc = readhdr_omaheaders (dev, omadesc, pos, &curblkl,
|
|
&prvhdro, &nxthdro, unitstat,code);
|
|
if (rc < 0) return -1;
|
|
dev->prvblkpos = prvhdro;
|
|
break;
|
|
case 'F':
|
|
/* For OMA fixed block files, calculate the previous block
|
|
offset allowing for a possible short final block */
|
|
pos = (pos + omadesc->blklen - 1) / omadesc->blklen;
|
|
dev->prvblkpos = (pos > 0 ? (pos - 1) * omadesc->blklen : -1);
|
|
break;
|
|
case 'T':
|
|
/* For OMA ASCII text files, the previous block is unknown */
|
|
dev->prvblkpos = -1;
|
|
break;
|
|
} /* end switch(omadesc->format) */
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function bsf_omatape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Backspace to previous block of OMA file */
|
|
/* */
|
|
/* If successful, return value is +1. */
|
|
/* If current position is at start of a file, then a backspace file */
|
|
/* operation is performed to reset the position to the end of the */
|
|
/* previous file, and the return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/* */
|
|
/* Note that for ASCII text files, the previous block position is */
|
|
/* known only if the previous CCW was a read or a write, so any */
|
|
/* attempt to issue more than one consecutive backspace block on */
|
|
/* an ASCII text file will fail with unit check status. */
|
|
/*-------------------------------------------------------------------*/
|
|
int bsb_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */
|
|
long blkpos; /* Offset of block header */
|
|
S32 curblkl; /* Length of current block */
|
|
S32 prvhdro = 0; /* Offset of previous header */
|
|
S32 nxthdro; /* Offset of next header */
|
|
|
|
/* Point to the current file entry in the OMA descriptor table */
|
|
omadesc = (OMATAPE_DESC*)(dev->omadesc);
|
|
omadesc += (dev->curfilen-1);
|
|
|
|
/* Backspace file if current position is at start of file */
|
|
if (dev->nxtblkpos == 0)
|
|
{
|
|
/* Unit check if already at start of tape */
|
|
if (dev->curfilen <= 1)
|
|
{
|
|
build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Perform backspace file operation */
|
|
rc = bsf_omatape (dev, unitstat,code);
|
|
if (rc < 0) return -1;
|
|
|
|
dev->blockid--;
|
|
|
|
/* Return zero to indicate tapemark detected */
|
|
return 0;
|
|
}
|
|
|
|
/* Unit check if previous block position is unknown */
|
|
if (dev->prvblkpos < 0)
|
|
{
|
|
build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Backspace to previous block position */
|
|
blkpos = dev->prvblkpos;
|
|
|
|
/* Determine new previous block position */
|
|
switch (omadesc->format)
|
|
{
|
|
case 'H':
|
|
/* For OMA headers files, read the previous block header to
|
|
extract the block length and new previous block offset */
|
|
rc = readhdr_omaheaders (dev, omadesc, blkpos, &curblkl,
|
|
&prvhdro, &nxthdro, unitstat,code);
|
|
if (rc < 0) return -1;
|
|
break;
|
|
case 'F':
|
|
/* For OMA fixed block files, calculate the new previous
|
|
block offset by subtracting the fixed block length */
|
|
if (blkpos >= omadesc->blklen)
|
|
prvhdro = blkpos - omadesc->blklen;
|
|
else
|
|
prvhdro = -1;
|
|
break;
|
|
case 'T':
|
|
/* For OMA ASCII text files, new previous block is unknown */
|
|
prvhdro = -1;
|
|
break;
|
|
} /* end switch(omadesc->format) */
|
|
|
|
/* Update the offsets of the next and previous blocks */
|
|
dev->nxtblkpos = blkpos;
|
|
dev->prvblkpos = prvhdro;
|
|
|
|
dev->blockid--;
|
|
|
|
/* Return +1 to indicate backspace successful */
|
|
return +1;
|
|
|
|
} /* end function bsb_omatape */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Close an OMA tape file set */
|
|
/* */
|
|
/* All errors are ignored */
|
|
/*-------------------------------------------------------------------*/
|
|
void close_omatape2(DEVBLK *dev)
|
|
{
|
|
if (dev->fd >= 0)
|
|
{
|
|
WRMSG (HHC00201, "I", LCSS_DEVNUM, dev->filename, "OMA");
|
|
close (dev->fd);
|
|
}
|
|
dev->fd=-1;
|
|
if (dev->omadesc != NULL)
|
|
{
|
|
free (dev->omadesc);
|
|
dev->omadesc = NULL;
|
|
}
|
|
|
|
/* Reset the device dependent fields */
|
|
dev->nxtblkpos=0;
|
|
dev->prvblkpos=-1;
|
|
dev->curfilen=1;
|
|
dev->blockid=0;
|
|
dev->fenced = 0;
|
|
dev->omafiles = 0;
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Close an OMA tape file set */
|
|
/* */
|
|
/* All errors are ignored */
|
|
/* Change the filename to '*' - unloaded */
|
|
/* TAPE REALLY UNLOADED */
|
|
/*-------------------------------------------------------------------*/
|
|
void close_omatape(DEVBLK *dev)
|
|
{
|
|
close_omatape2(dev);
|
|
STRLCPY( dev->filename, TAPE_UNLOADED );
|
|
dev->blockid = 0;
|
|
dev->fenced = 0;
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Rewind an OMA tape file set */
|
|
/* */
|
|
/* All errors are ignored */
|
|
/*-------------------------------------------------------------------*/
|
|
int rewind_omatape(DEVBLK *dev,BYTE *unitstat,BYTE code)
|
|
{
|
|
UNREFERENCED(unitstat);
|
|
UNREFERENCED(code);
|
|
close_omatape2(dev);
|
|
dev->fenced = 0;
|
|
return 0;
|
|
}
|