ansi tape read utility in C
notes at isucs1.UUCP
notes at isucs1.UUCP
Wed Oct 3 08:00:39 AEST 1984
Here is a simple quick and dirty program to read and write ansi labeled tapes.
It doesn't have a lot of flexibility, such as user control over record and
block sizes and so forth, but it does allow files to be transferred.
I hope it is of some help to you. And if someone else has already responded
with something better I could probably use it too.
Quent Johnson
-------------------------->>>>CUT HERE <<<-------------------------------------
/* <ansitar.c>
******************************************************************************
* March 26,1984 *
* *
* *
* AUTHORS: Steve Christiansen -- ISU Computation Center *
* Quentin Johnson -- ISU Computer Science Department *
******************************************************************************
A simple archiver for `ansi standard' tapes.
New tapes can be created or files appended to existing volumes.
Files can be extracted or the names of files on the tape can be listed.
Fixed and variable record length files can be read; both the 'A` and
'M` carriage control formats are interpreted when read.
For now only multi-file, single-volume tapes with record and block
size determined by program constants can be written. Since this program
is meant to be only a quick and dirty method of file transfer between the
various mainframes it does not allow users control of format. A space is
written in the carriage control format field. The record format is `F'
for fixed length.
The record and block length are set for 12 80 character records per
block since the major use will be for transferring text files to be
edited on an 80 column screen.
The VAX/VMS manual: "Magnetic Tape Users Guide" was used as a reference
for the tape format used by this program.
*/
#include <stdio.h>
#include <sys/types.h> /* needed by mtio.h */
#include <sys/ioctl.h>
#include <sys/mtio.h> /* magnetic tape io control */
#define TAPE "/dev/rmt8" /* 1600 bpi raw tape device */
#define VOLNAME "CSUNIX" /* volume name for tapes written */
#define TRUE 1
#define FALSE 0
#define RD 0 /* modes for low level i/o */
#define RW 2
#define LABBUFSIZ 128 /* max. tape label record size when reading */
#define DATBUFSIZ 8192 /* read data buffer size */
#define TBLKSIZ 960 /* tape data write block size */
/* set up for typical text files
with 80 col. lines; 12/block */
#define RECSIZ 80 /* default record size for writing */
/* indices for label name list */
#define VOL1 0
#define HDR1 1
#define HDR2 2
#define HDR3 3
#define EOF1 4
#define EOF2 5
#define EOF3 6
#define EOV1 7
#define EOV2 8
#define EOV3 9
#define NLABIDS 10
/* standard tape label names */
char *labelids[NLABIDS] =
{ "VOL1", /* contains volume name */
"HDR1", /* contains file name,#blocks, creation date, etc. */
"HDR2", /* contains record size, block size, record format */
"HDR3", /* optional */
"EOF1",
"EOF2", /* optional */
"EOF3", /* optional */
"EOV1",
"EOV2", /* optional */
"EOV3" }; /* optional */
int file, /* sequence number of file in volume */
recsz, /* record size */
blksz, /* blocksize */
nblks, /* number of blocks in tape file */
creatn, /* creation, expiration dates */
expir,
section, /* file section within volume */
gen, /* file generation & version */
ver;
char recfm, /* tape file record format (fixed,variable) */
form, /* carriage control format (A or M ) */
name[18], /* current tape-file-name */
volume[7], /* tape volume name */
set[7], /* tape volume set name */
genstr[5], /* file generation & version */
verstr[3];
int hdr1, hdr2, hdr3, eov, vol1; /* flags: if !=0 this label was read */
int tapefd, /* for tape i/o */
diskfd; /* for copying disk files to tape */
FILE *output; /* disk output file for extracting tape files */
int noproc, /* if == 1, don't process carriage control */
verbose; /* if == 1, echo file names when encountered */
char function; /* x,t,a,or c - what to do with tape */
char labelbuf[LABBUFSIZ], /* tape label record buffer */
databuf[DATBUFSIZ], /* buffer for reading */
tapebuf[TBLKSIZ]; /* buffer for writing to tape */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
quit(msg, parm) /* Fatal error handler */
char *msg;
int parm;
{
printf("In file %s: ", (hdr1? name : "??????"));
printf(msg, parm);
printf("\n");
exit(1);
}
readlabel()
{
register len;
if ((len = read(tapefd, labelbuf, LABBUFSIZ)) < 0)
quit("Label read error.");
if (len == 0) return(FALSE); /* hit tape mark */
if (len != 80)
quit("Wrong length label record.");
return(TRUE);
}
readheader()
{
register id;
register char *p;
hdr1 = hdr2 = hdr3 = FALSE;
if (readlabel() == FALSE) return(FALSE);
do {
for (id = 0 ; id < NLABIDS ; id++)
if (strncmp(labelids[id], labelbuf, 4) == 0) break;
switch (id) {
case HDR1:
hdr1 = TRUE;
if (sscanf(labelbuf, "%*4c%17c%6c%4d%4d%4c%2c%6d%6d%*1c%6d",
name, set, §ion, &file, genstr, verstr, &creatn, &expir, &nblks) != 9)
quit("Bad format in HDR1 label.");
for (p = &name[16] ; p > name ; p--) if (*p != ' ') {
*++p = 0;
break;
}
if (sscanf(genstr, "%d", &gen) != 1) gen = 0;
if (sscanf(verstr, "%d", &ver) != 1) ver = 0;
break;
case HDR2:
hdr2 = TRUE;
if (sscanf(labelbuf, "%*4c%1c%5d%5d%*21c%1c",
&recfm, &blksz, &recsz, &form) != 4)
quit("Bad format in HDR2 label.");
break;
case HDR3:
hdr3 = TRUE;
break;
case VOL1:
vol1 = TRUE;
if (sscanf(labelbuf, "%*4c%6c", volume) != 1)
quit("Bad format in VOL1 label.");
break;
case EOF1:
case EOF2:
case EOF3:
case EOV1:
case EOV2:
case EOV3:
quit("Unexpected label (%s) in file header.", labelids[id]);
}
} while (readlabel());
if (hdr1 == FALSE)
quit("Missing HDR1 label in file header.");
if (hdr2 == FALSE) recfm = blksz = recsz = 0;
return(TRUE);
}
readtrailer()
{
register id, eof;
eov = eof = FALSE;
if (readlabel() == FALSE) return(FALSE);
do {
for (id = 0 ; id < NLABIDS ; id++)
if (strncmp(labelids[id], labelbuf, 4) == 0) break;
switch (id) {
case EOV1:
eov = TRUE;
case EOF1:
eof = TRUE;
if (sscanf(&labelbuf[55], "%6d", &nblks) != 1) {
printf("In file %s: bad format in EOF1 label.\n", name);
nblks = 0;
}
break;
case VOL1:
case HDR1:
case HDR2:
case HDR3:
quit("Unexpected label (%s) in file trailer.", labelids[id]);
}
} while (readlabel());
if (eof == FALSE) {
printf("In file %s: missing EOF1 or EOV1 label in file trailer.\n", name);
nblks = 0;
}
return(TRUE);
}
printheading(volname) /* for 't' function */
char *volname;
{
printf("Volume: %s\n\n", (vol1? volname : "(missing volume label.)"));
printf(" set file recfm recsz blksz nblks creat expir gen ver name\n");
}
printdata() /* for 't' function */
{
printf("%6s %4d ", set, file);
printf(" %1c %1c ", recfm, form);
printf("%5d %5d%6d %5d %5d", recsz, blksz, nblks, creatn, expir);
printf("%4d %3d %s", gen, ver, name);
if (eov || section != 1) printf(" (section %d)", section);
printf("\n");
}
processblock(blklen) /* 'x' function */
int blklen;
{
int bytcnt;
register nextrec, allpad, i;
register char *recptr;
nextrec = 0;
while (nextrec < blklen) {
recptr = &databuf[nextrec];
if (recfm == 'D') {
if (sscanf(recptr, "%4d", &bytcnt) != 1) return;
nextrec += bytcnt;
if (form != 'M' && noproc == 0) {
bytcnt -= 4;
recptr += 4;
}
}
else {
allpad = 1;
bytcnt = 0;
for (i = 1 ; i <= recsz ; i++) {
if (*recptr != ' ') bytcnt = i;
if (*recptr++ != '^') allpad = 0;
}
if (allpad) return;
recptr = &databuf[nextrec];
nextrec += recsz;
if (form == 'M' || noproc) bytcnt = recsz;
}
if (form == 'A') {
bytcnt--;
switch (*recptr++) {
case '1':
putc('\n', output);
putc('\f', output);
break;
case '+':
putc('\r', output);
break;
case '-':
putc('\n', output);
case '0':
putc('\n', output);
default:
putc('\n', output);
}
}
while (--bytcnt >= 0) putc(*recptr++, output);
if (form != 'A' && form != 'M' && noproc == 0)
putc('\n', output);
}
}
/* connect disk file name with tape file name */
openfile(filelist, nfiles, function)
char **filelist;
int nfiles;
char function;
{
char filename[18],
*afterslash,
*rindex();
register int i;
register char ch, *cp, *p1, *p2;
if (function == 'x') {
p1 = name; /* tape file name */
p2 = filename; /* disk file name */
do {
ch = *p1++;
if (ch >= 'A' && ch <= 'Z') ch += ('a' - 'A');
} while (*p2++ = ch); /* filename = lcase(name) */
if (nfiles > 0)
/* && if current tape file was an argument */
while (strcmp(filelist[--nfiles], filename) != 0)
if (nfiles == 0) return(FALSE);
output = fopen(filename,"w");
if (output != NULL) return(TRUE);
printf("Can't open file %s.\n", filename);
return(FALSE);
}
else { /* function is 'c' or 'a' */
if ((afterslash = rindex(*filelist,'/')) == 0)
afterslash = *filelist;
else afterslash++; /* forget dir path name */
strncpy(name,afterslash,17); /* create tape file name */
name[17] = 0;
for (i=0; i<17; i++) /* blank fill on right replacing nulls */
if (name[i] == 0) name[i] = ' ';
cp = name;
while (*cp) { /* convert to upper case */
if ((*cp >= 'a') && (*cp <= 'z'))
*cp = *cp - 'a' + 'A';
cp++;
}
diskfd = open(*filelist,RD);
if (diskfd > 0) return(TRUE);
printf("Can't open %s for reading.\n",*filelist);
return(FALSE);
}
}
mt(command,count)
/* execute mag tape command */
/* tapefd is assumed opened previously */
short command;
int count;
{
struct mtop mag_op;
mag_op.mt_op = command;
mag_op.mt_count = count;
return((ioctl(tapefd,MTIOCTOP,&mag_op) < 0) ? FALSE : TRUE);
}
tapemark()
{
if (mt(MTWEOF,1) == FALSE)
quit("Can't write tape mark on tape device %s.",TAPE);
}
mklabels(lab1,lab2) /* write header or trailer labels to tape */
char *lab1,*lab2;
{
char label[81];
/* write HDR1 or EOF1 label */
sprintf(label,"%s%s%s0001%04d000100 00000 00000 %06dDECDECFILE11A%-7s",
lab1,name,set,file,nblks," ");
if (write(tapefd,label,80) != 80)
return(FALSE);
/* write HDR2 or EOF2 label */
sprintf(label,"%sF%05d%05d%-35s00%-28s",lab2,blksz,recsz," "," ");
if (write(tapefd,label,80) != 80)
return(FALSE);
tapemark(); /* mark end of header or trailer */
return(TRUE);
}
tapewrite() /* copy disk file to tape */
/* i/o channels are already opened for tape & disk */
{
register char *t,*d;
register int buflen,count;
t = tapebuf;
count = nblks = 0;
while ((buflen = read(diskfd,databuf,DATBUFSIZ)) != 0) {
if (buflen < 0)
quit("Error reading disk file.");
d = databuf;
while (buflen --) {
*t++ = *d++;
if (++count == blksz) {
if (write(tapefd,tapebuf,blksz) <= 0)
quit("Error writing to tape device %s.",TAPE);
count = 0; nblks++;
t = tapebuf;
}
}
}
if (count > 0) {
while (count++ < blksz)
*t++ = '^';
if (write(tapefd,tapebuf,blksz) <= 0)
quit("Error writing to tape device %s.",TAPE);
nblks++;
}
tapemark(); /* mark end of file section */
}
volend() /* position to end of tape volume for append function */
{
int oldfile = 0;
vol1 = FALSE;
if (readheader() == FALSE) {
printf("Unexpected tape mark while reading header label.\n");
exit(1);
}
do {
if (verbose) printf("Found: %s\n",name);
if (mt(MTFSF,1) == FALSE)
quit("Error while skipping file on tape device %s.",TAPE);
if (readtrailer() == FALSE)
quit("Missing file trailer.");
oldfile = file; /* file sequence number */
} while (readheader());
file = oldfile + 1 /* number of first file to be appended */;
/* now back up one tape mark since last `readheader' put tape
after end of volume */
if (mt(MTBSF,1) == FALSE)
quit("Can't position to end of volume on tape device %s.",TAPE);
}
mkvol() /* write VOL1 label */
{
char label[81];
sprintf(label,"VOL1%s%40s1%28s3",volume," "," ");
if (write(tapefd,label,80) != 80)
return(FALSE);
return(TRUE);
}
main(argc, argv)
int argc;
char **argv;
{
int len, /* # bytes read into buffer */
blkcnt, /* # blocks read from tape */
curfile, /* current file argument */
dofile; /* whether to process current tape file */
if (argc < 2) {
printf("Usage: ansitar {txac[vn]} [files...]\n");
exit(1);
}
if (*argv[1] == '-') argv[1]++; /* ignore optional '-' in flags */
while (*argv[1]) {
switch (*argv[1]) {
case 't': /* table of contents */
case 'x': /* extract files from tape */
case 'c': /* create tape & possibly append files */
case 'a': /* append files to tape */
if (function != 0) {
printf("No multiple functions allowed.\n");
exit(1);
}
function = *argv[1];
break;
case 'v':
verbose++;
break;
case 'n': /* don't process carriage control */
noproc++;
break;
default:
printf("%c -- unknown flag.\n", *argv[1]);
exit(1);
}
argv[1]++;
}
if (function == 0) {
printf("Usage: ansitar {txac[vn]} [files...]\n");
exit(1);
}
switch (function) {
case 'x':
case 't':
if ((tapefd = open(TAPE, RD)) < 0) {
printf("Can't open tape device %s for reading.\n", TAPE);
exit(1);
}
vol1 = FALSE;
if (readheader() == FALSE) {
printf("Unexpected tape mark while reading header label.\n");
exit(1);
}
if (function == 't') printheading(volume);
do {
if (blksz > DATBUFSIZ)
quit("%d byte block size is too big.", blksz);
if (function == 'x')
dofile = openfile(&argv[2], argc-2, function);
blkcnt = 0;
while ((len = read(tapefd, databuf, DATBUFSIZ)) != 0) {
if (len < 0) quit("Tape data read error.");
if (hdr2 == FALSE && blksz == 0) blksz = recsz = len;
blkcnt++;
if (dofile) processblock(len);
}
if (dofile) fclose(output);
if (readtrailer() == FALSE)
quit("Missing file trailer.");
if (function == 't') printdata();
else if (verbose) {
printf("%s", (dofile ? "extracted: " : "found: "));
printf("%s\n", name);
}
if (blkcnt != nblks)
printf("In file %s: block count mismatch - %d read.\n",name,blkcnt);
} while (readheader());
break;
case 'c':
case 'a':
if ((tapefd = open(TAPE,RW)) < 0) {
printf("Can't open tape device %s for read/write.\n",TAPE);
exit(1);
}
if (function == 'c') {
strcpy(volume,VOLNAME);
strcpy(set,VOLNAME);
file = 1; /* file sequence in tape volume */
/* create new tape */
if (mkvol() == FALSE) {
printf("Can't write VOL1 label on tape device %s.\n", TAPE);
exit(1);
}
if (verbose)
printf("Volume: %s created.\n",volume);
function = 'a';
}
else volend(); /* position to end of volume */
curfile = 2; /* current file-name argument */
recsz = RECSIZ;
blksz = TBLKSIZ;
do { /* each file named by an argument */
nblks = 0;
if (openfile(&argv[curfile],1,function) == TRUE) {
if (mklabels(labelids[HDR1],labelids[HDR2]) == FALSE)
quit("Can't write tape file header for %s.\n", argv[curfile]);
/* copy disk file to tape file */
tapewrite();
if (mklabels(labelids[EOF1],labelids[EOF2]) == FALSE)
quit("Can't write tape file trailer for %s.\n", argv[curfile]);
if (verbose)
printf("%s written to tape as %s \n",argv[curfile],name);
file++;
close(diskfd);
}
else if (verbose)
printf("%s not written to tape.\n",argv[curfile]);
} while (++curfile < argc);
tapemark(); /* mark end of tape */
break;
default: ; /* nothing for now.... */
} /* end case */
exit(0);
} /* end main */
More information about the Comp.unix.wizards
mailing list