mackay@uw-june.UUCP (05/19/84)
# The rest of this file is a shell script which will extract: # README ansitar.1 ansitar.c echo x - README cat >README <<'StopHere' Ansitar reads from or writes to a magnetic tape in ANSI labeled tape format, which is a useful format for exchange of ASCII character files with a non-UNIX system. Eight-bit binary is also possible, using F-type blocking, but the results are likely to be unsatisfactory in most cases. This program was forwarded to me in answer to a desperate request, and has already proved very useful. It appeared on net.sources earlier with ANSI System level 1 capacities, and has now acquired System level 3 capacities (i. e. everything but spanned records). Spanned records would not be very difficult, but they do not seem to be very much in demand either. It reads and writes HDR2 labels as well as HDR1 labels, and is thus capable of deblocking tapes without explicit declaration of block or record sizes. A large number of the more interesting features are still marked off as VARIAN code because that is the way I received the program. The VARIAN code is basic to efficient operation, unlike the PIP code, which is for a rather special environment. I have not bothered to provide a makefile, since there is only one program here. ansitar.1 belongs ideally in /usr/man/man1 and the executable program anywhere in a generally used path. mackay@washington.ARPA (Computer Science, Univ of Washington) 'StopHere' echo x - ansitar.1 cat >ansitar.1 <<'StopHere' .TH ANSITAR 1 5/1/84 .SH NAME ansitar \- read or write ANSI multifile labeled tapes .SH SYNOPSIS .B ansitar subcommand [blocksize] [linesize] [vsn] file .br .B ansitar .RB "subcommand[" "RSl" "]" [blocksize] [linesize] [labelsize] [vsn] file .LP .SH DESCRIPTION .I Ansitar reads from or writes to a magnetic tape in ANSI labeled tape format, which is a useful format for exchange of ASCII character files with a non-UNIX system. Eight-bit binary is also possible, but the results are likely to be unsatisfactory in most cases. .PP A non-standard version compiled with .B #define PIP permits reading of RT11 and RSTS files as well. .PP .I subcommand is any rational concatenation of compatible characters from the following groups \- only one from each group: .IP .B [crtx], [bBDF], [RS], .B l, U, v, V, [0..9] .LP .TP .B c Create a new multifile tape. (Destroy all previous files on tape). .TP .B r Replace files on tape without destroying any previous files. .TP .B t List all files on tape. .TP .B x Extract files from tape. (See note on `*' wild-card character). .TP .B b Use next argument as a tape block size. .TP .B B Use next argument as a tape block size and following argument as line size (for blocking/unblocking of fixed length records). .TP .B D .I Reading. Not required for System level 3 tape with valid HDR2 label. For System level 1 and 2 use next argument as tape block size. .I Writing. Write HDR2/EOF2 labels and variable length records (D format, System level 3) with block size 2048 and maximum line size 255. .TP .B F .I Reading. Not required if tape has valid HDR2 label. Use .B B for ANSI System level 1 tapes. .I Writing. Same as B, but write HDR2/EOF2 label for automatic unblocking. (F format, System level 3). .TP .B R Read with RT11 label and name conventions. .TP .B S Read with RSTS conventions (same as RT11, except 80-character labels). .TP .B l Use next argument as non-standard label size. .TP .B U Do case conversion on alphabetic characters in filenames. Upper-case to lower-case from tape to UNIX. Lower-case to upper-case from UNIX to tape. .TP .B v Use .I `verbose' mode \- Lots of information about labels. .TP .B V Use next argument (up to 6 alphanumeric characters) as tape .I vsn. .TP .B 1..9 Select tape unit (default is .I /dev/rmt8 ). .PP The arguments for .B b, B, D, F, l are unsigned decimal strings. It is probably preferable to use only upper-case alphabetics in the argument to .B V. Arguments are evaluated in the order in which the associated subcommand characters appear. .PP Note: The `*' wild card character may be used to get a number of related files from tape, but in that case the filename must be quoted to prevent the shell from attempting to expand the wild card. When writing from UNIX to tape, wild cards work normally. .SH SEE ALSO .I ANSI X3.27-1978: Magnetic Tape Labels and File Structure for Information Interchange. .br .I ISO 1001-1979: Magnetic Tape Labels and File Structure for Information Interchange. .SH AUTHORS Unknown, modified by David R. Brown, further modified by Pierre A. MacKay. .SH BUGS 'StopHere' echo x - ansitar.c cat >ansitar.c <<'StopHere' /* >From zehntel!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!uiucuxc!root Sat Jul 2 04:31:32 1983 Subject: Ansitar.c - (nf) Newsgroups: net.sources #N:uiucuxc:12500005:000:19678 uiucuxc!root Jul 1 23:55:00 1983 * * 10/28/83 DRB: new option 'D': read variable length records (D format) * 10/29/83 FGH: 1. wildcard ability added to filenames. * 2. when output filename isn't valid for Unix (as it's perhaps * taken from a foreign tape), this program now just skips * that file rather than exiting the whole job. * 10/30/83 FGH: 1. some problems with varunblock's handling of end of record. * still must use 'D' option with 'b' such that b's argument * exceeds the tape's physical record size (2048 in my case) * 2. changed varunblock/doxtract to correct the byte count. * * 10/31/83 DRB: * new option P - create/read files in "pip" (FILES-11) counted format. * handle tape read error * From zehntel!tektronix!ucbcad!ucbvax!decvax!microsoft!uw-beaver!cornell!vax135!floyd!harpo!utah-cs!utah-gr!thomas Tue Aug 2 21:27:08 1983 * (=Spencer) (#ifdef PIP) # MACKAY@WASHINGTON.ARPA * 04/24/84 PAM: * 1. Upgrade to ANSI X3.27 System level 3. * Program now reads and writes HDR2 label * for deblocking info. * 2. When reading, sets blocksize only if D-type, blocksize * and linesize (aka record-length) if F-type. * Neither D nor b/B need be specified on the * command line if tape has valid HDR2 labels. * 3. Full HDR2 info provided in "verbose mode." * (Ought to check matching EOF2 and print string * for HDR3-9/EOF3-9 labels) * 4. If D is used as an option in writing, a default * blocksize of 2048 is chosen, based on the ISO * recommendation for maximum blocksize. Line length * is limited to 255 bytes, which seems a reasonable * maximum. * */ #define VARIAN #define PIP #ifdef VARIAN #define DEBUG 0 /* set to nonzero to debug new Varian code */ #define DBG if(DEBUG) fprintf(stderr, #define WILDCARD '*' #endif VARIAN #include <stdio.h> #include <ctype.h> #include <time.h> #include <pwd.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/mtio.h> /* ansitar -- archiver for ansi-format labelled tapes * * ansitar [crxtvbl] [blocksize] [labelsize] file ... * * The options are similar to tar: * c - create a tape * r - replace (update) a tape * x - extract files * t - print table of contents * v - set verbose mode: for crx, print names; for t print labels * 0-9 - select drive 0-9 * b - use next argument as a block size * B - use next argument as tape block size, and * following argument as line size (for blocking/unblocking) * l - use next arg as a label size * U - select upper(out)/lower(in) case translation of names * V - use next argument as a VSN * R - use RT11 label and name conventions (UGH!) * S - use RSTS conventions (==RT11 except 80-byte labels) * P - create/read files in "pip" (FILES-11) counted format. * D - create/read files with variable length records (D format) * * When extracting from tape to UNIX, the filename may contain * to * indicate a wild card; however, the asterisk should be enclosed * in quotes, however, to prevent the shell from interpreting it. * * Examples of usage: * ansitar tv Verbose table of contents * ansitar xvDUb 2000 file1 file2 Extract file1 and file2 from * tape with 2000 bytes/block * and variable length records * * BUGS: * * Warning: The routines skipfile and backspace use nonstandard * (4.1BSD) ioctl calls! */ #define Skiparg() argc--; argv++ #define MAXLINE 256 #define TRUE 1 #define FALSE 0 #define READ 0 #define READWRITE 2 #define ISOBLOCK 2048 /* field sizes */ #define LABID 3 #define SERIAL 6 #define OWNER 14 #define FILEID 17 #define SETID 6 #define SECNO 4 #define SEQNO 4 #define GENNO 4 #define GENVSNO 2 #define CRDATE 6 #define EXDATE 6 #define BLOCKS 6 #define SYSTEM 13 #define BLKMAX 5 #define RECMAX 5 #define BYTOFFS 2 #define DBYTES 4 /* pad fields (reserved for future use) */ #define VRES1 20 #define VRES2 6 #define VRES3 28 #define HRES1 7 #define H2RES1 35 #define H2RES2 28 /* Volume header label */ struct vol { char v_labid[LABID]; /* label identifier "VOL" */ char v_labno; /* label number */ char v_serial[SERIAL]; /* volume serial number */ char v_access; /* accessibility */ char v_res1[VRES1]; /* reserved for future use */ char v_res2[VRES2]; /* reserved for future use */ char v_owner[OWNER]; /* owner identifier */ char v_res3[VRES3]; /* reserved for future use */ char v_stdlabel; /* standard label flag */ }; /* file header/eof label */ struct hdr { char h_labid[LABID]; /* label identifier: "HDR" or "EOF" */ char h_labno; /* label number */ char h_fileid[FILEID]; /* file identifier */ char h_setid[SETID]; /* file set identifier */ char h_secno[SECNO]; /* file section number */ char h_seqno[SEQNO]; /* file sequence number */ char h_genno[GENNO]; /* generation number */ char h_genvsno[GENVSNO]; /* generation vsn number */ char h_crdate[CRDATE]; /* creation date */ char h_exdate[EXDATE]; /* expiration date */ char h_access; /* accessibility */ char h_blocks[BLOCKS]; /* block count */ char h_system[SYSTEM]; /* system code */ char h_x1[7]; /* reserved */ }; /* deblocking hdr2/eof2 label */ struct hd2 { char h2_labid[LABID]; /* label identifier: "HDR" or "EOF" */ char h2_labno; /* label number "2" */ char h2_datatype; /* type identifier "D" or "F" */ char h2_blkmax[BLKMAX]; /* maximum block size in bytes */ char h2_recmax[RECMAX]; /* maximum record size in bytes */ char h2_x1[H2RES1]; /* reserved */ char h2_bytoffs[BYTOFFS]; /* extra stuff at start of block */ char h2_x2[H2RES2]; /* reserved */ }; struct vol vol1; struct hdr hdr1, eof1; struct hd2 hdr2, eof2; char *tapefile = "/dev/rmt8"; char *buffer, *linebuffer, *malloc(), *realloc(), *index(); char **filetab; unsigned blocksize = 512; unsigned linesize = 0; int bfactor = 0; int labelsize = sizeof(struct vol); int tapeunit = 0; int tf; char *defvsn = ""; char curdate[CRDATE+1]; char *alongtime = " 99364"; #ifdef PIP int create, replace, xtract, table, verbose, confirm, pipfile; #else int create, replace, xtract, table, verbose, confirm; #endif int blocking; int RT11, Upper; #ifdef VARIAN int Varlen; #endif VARIAN int Fixlen; main(argc, argv) int argc; char **argv; { char *ap; int bufsize, openmode; if (argc < 2) usage(); Skiparg(); openmode = READ; ap = argv[0]; Skiparg(); while (*ap) { switch (*ap) { case 'c': create++; openmode = READWRITE; break; case 'r': replace++; openmode = READWRITE; break; case 'x': xtract++; break; case 't': table++; break; case 'v': verbose++; break; case 'w': confirm++; break; case 'b': case 'B': case 'F': blocking++; blocksize = atoi(argv[0]); if (blocksize <= 0) fatal("bad block size %s\n", argv[0]); Skiparg(); if ((*ap == 'B') || (*ap == 'F')) { linesize = atoi(argv[0]); if (linesize <= 0 || blocksize % linesize != 0) fatal("bad line size %s\n", argv[0]); bfactor = blocksize / linesize; Skiparg(); } if (*ap == 'F') Fixlen++; break; case 'l': labelsize = atoi(argv[0]); if (labelsize < sizeof(struct hdr)) fatal("label size must be >= %d\n", sizeof(struct hdr)); Skiparg(); break; case 'U': Upper++; break; case 'V': defvsn = argv[0]; if (strlen(defvsn) > SERIAL) defvsn[SERIAL] = '\0'; Skiparg(); break; case 'S': case 'R': RT11++; Upper++; if (*ap == 'R') labelsize = 512; break; #ifdef VARIAN case 'D': Varlen++; break; #endif VARIAN #ifdef PIP case 'P': pipfile++; break; #endif PIP default: if (isdigit(*ap)) { tapeunit = *ap; break; } fatal("bad flag: %c\n", *ap); } ap++; } filetab = argv; filetab[argc] = NULL; if (tapeunit) tapefile[strlen(tapefile)-1] = tapeunit; tf = open(tapefile, openmode); if (tf < 0) fatal("can't open %s%s\n", tapefile, (openmode != READ) ? " for writing" : ""); bufsize = max(blocksize, labelsize); buffer = malloc(bufsize + 10); if (buffer == NULL) fatal("can't allocate buffer of %d bytes\n", blocksize); if (linesize) { linebuffer = malloc(linesize + 10); if (linebuffer == NULL) fatal("can't allocate line buffer of %d bytes\n", linesize); } getansidate(curdate); if (verbose && blocking) { printf("Blocksize: %d", blocksize); if (linesize) printf(" Linesize: %d", linesize); putc('\n', stdout); } if (create || replace) doupdate(tf); else if (xtract) doxtract(tf); else if (table) dotable(tf); else usage(); exit(0); } usage() { fatal("usage: ansitar crxtvbl [blocksize] [labelsize] file ...\n"); } dotable(tf) int tf; { char fileid[FILEID+1]; int files, n; int blocks; int lbseq; long bytes; getvol(tf, &vol1); prtvol(&vol1); putc('\n', stdout); files = 0; lbseq = '1'; while (gethdr(tf, &hdr1)) { files++; if (verbose) prthdr(&hdr1); getmark(tf, &hdr2, lbseq); sncpy(fileid, hdr1.h_fileid, FILEID); blocks = 0; bytes = 0L; while ((n = getrec(tf, buffer, blocksize)) > 0) { blocks++; bytes += n; } lbseq = '1'; geteof(tf, &eof1); if (verbose) prthdr(&eof1); getmark(tf, &hdr2, lbseq); cmphdreof(&hdr1, &eof1); if (verbose) putc('\n', stdout); printf("t %s %d blocks %D bytes\n", fileid, blocks, bytes); if (linesize) printf("\t F-type: blocksize: %d linesize %d\n", blocksize, linesize); else printf("\t D-type: blocksize: %d\n", blocksize); if (verbose) putc('\n', stdout); } printf("\n%d files\n", files); } doxtract(tf) int tf; { char fileid[FILEID+1]; FILE *fp; long bytes; int blocks; int n, xall; int lbseq; #ifdef VARIAN int newn; #endif VARIAN lbseq = '1'; xall = (filetab[0] == NULL); getvol(tf, &vol1); if (verbose) prtvol(&vol1); while (gethdr(tf, &hdr1)) { getmark(tf, &hdr2, lbseq); sncpy(fileid, hdr1.h_fileid, FILEID); trimsp(fileid); if (RT11) fromRT11(fileid); /* if 1.you're doing all the files or 2. this file matches */ /* one of the the names in the arglist, then copy it, else */ /* skip this file. filetab is really 'argv' list. */ if ( (xall || lookup(filetab, fileid, Upper)) && checkw('x', fileid) ) { if (Upper) makelower(fileid); /* name to lower case*/ fp = fopen(fileid, "w"); #ifdef VARIAN if (fp == NULL) { printf("can't create %s - will skip\n", fileid); skipfile(tf); } #else if (fp == NULL) fatal("can't create %s\n", fileid); #endif VARIAN else{ /* file OK, do the copy */ blocks = 0; bytes = 0L; while ((n = getrec(tf, buffer, blocksize)) > 0) { if (linesize) lunblock(fp, buffer, n, linesize); else #ifdef VARIAN if (Varlen) { newn = varunblock(fp,buffer,n); n = newn; /* now it's # written */ } else #endif VARIAN #ifdef PIP if (pipfile) pipunblock(fp, buffer, n); else #endif PIP fwrite(buffer, n, 1, fp); blocks++; bytes += n; } fclose(fp); if (verbose) printf("x %s %d blocks %D bytes\n", fileid, blocks, bytes); } /* end 'if file open was OK' */ } /* end 'if filename OK or copying all' */ else /* if this file is not be copied */ skipfile(tf); lbseq = '1'; geteof(tf, &eof1); cmphdreof(&hdr1, &eof1); getmark(tf, &hdr2, lbseq); } } doupdate(tf) int tf; { int i, n; int blocks; long bytes; char line[MAXLINE]; char fileid[FILEID+1]; char recmax[RECMAX+1]; FILE *fp; int sequence; int lbseq; lbseq = '1'; sequence = 0; if (create) { initvol(&vol1); putvol(tf, &vol1); } else { /* replace */ getvol(tf, &vol1); while (gethdr(tf, &hdr1)) { sncpy(line, hdr1.h_seqno, SEQNO); sequence = atoi(line); getmark(tf, &hdr2, lbseq); skipfile(tf); lbseq = '1'; geteof(tf, &eof1); getmark(tf, &hdr2, lbseq); } backspace(tf); } for (i=0; filetab[i] != NULL; i++) { if (!checkw('a', filetab[i])) continue; strncpy(fileid, filetab[i], FILEID); fileid[FILEID] = '\0'; fp = fopen(fileid, "r"); if (fp == NULL) fatal("can't open %s\n", fileid); sequence++; if (RT11) toRT11(fileid); if (Upper) makeupper(fileid); inithdr(&hdr1, fileid, sequence); puthdr(tf, &hdr1); if (Varlen) { blocksize = ISOBLOCK; realloc(buffer,blocksize+10); linesize = 0; inithdr2(&hdr2, 'D', blocksize, 0); n = dblock(fp, buffer, blocksize); utoaz(n, recmax, RECMAX); blcopy(hdr2.h2_recmax, recmax, RECMAX); puthdr(tf, &hdr2); fclose(fp); fp = fopen("#tmp.tmp", "r"); if (fp == NULL) fatal("can't re-read #tmp.tmp\n"); } if (Fixlen) { inithdr2(&hdr2, 'F', blocksize, linesize); puthdr(tf, &hdr2); } tapemark(tf); blocks = 0; bytes = 0L; if (linesize) while ((n = lblock(fp, buffer, linesize, bfactor)) > 0) { if (n % 2) { buffer[n] = '\0'; n++; } n = write(tf, buffer, n); blocks++; bytes += n; } #ifdef PIP else if (pipfile) while ((n = pipblock(fp, buffer, blocksize)) > 0) { n = write(tf, buffer, n); blocks++; bytes += n; } else #else else #endif PIP while ((n = fread(buffer, sizeof(char), blocksize, fp)) > 0) { if (n % 2) { buffer[n] = '\0'; n++; } n = write(tf, buffer, n); blocks++; bytes += n; } fclose(fp); tapemark(tf); blcopy(hdr1.h_labid, "EOF", LABID); utoaz(blocks, line, BLOCKS); blcopy(hdr1.h_blocks, line, BLOCKS); puthdr(tf, &hdr1); if ((Varlen) || (Fixlen)) { blcopy(hdr2.h2_labid, "EOF", LABID); puthdr(tf, &hdr2); } tapemark(tf); if (verbose) printf("a %s %d blocks %D bytes\n", fileid, blocks, bytes); } tapemark(tf); } getvol(tf, volp) int tf; struct vol *volp; { int n; if (labelsize == sizeof(struct vol)) n = read(tf, (char *)volp, sizeof(struct vol)); else { n = read(tf, buffer, labelsize); bcopy((char *)volp, buffer, sizeof(struct vol)); } #ifdef PIP if (n<0) { perror("Tape read error"); exit(1); } #endif PIP if (n != labelsize || strncmp(volp->v_labid, "VOL", LABID) != 0 || volp->v_labno != '1') { printf("Warning: Volume label (VOL1) missing\n"); backspace(tf); return; } /* check for RT11 boot block between VOL1 and first HDR1 */ if (RT11) { /* must have labelsize = 512 */ n = read(tf, buffer, labelsize); bcopy((char *)&hdr1, buffer, sizeof(struct hdr)); if (n == labelsize && strncmp(hdr1.h_labid, "HDR", LABID) == 0) backspace(tf); else printf("Possible RT11 bootstrap block.\n"); } } int gethdr(tf, hdrp) int tf; struct hdr *hdrp; { int n; if (labelsize == sizeof(struct hdr)) n = read(tf, (char *)hdrp, sizeof(struct hdr)); else { n = read(tf, buffer, labelsize); bcopy((char *)hdrp, buffer, sizeof(struct hdr)); } if (n == 0) return(FALSE); if (n != labelsize || strncmp(hdrp->h_labid, "HDR", LABID) != 0 || hdrp->h_labno != '1') hdrerr(tf, hdrp); return(TRUE); } hdrerr(tf, hdrp) int tf; struct hdr *hdrp; { int found, n; printf("Warning: File label (HDR1) error - skipping\n"); found = FALSE; while (!found) { skipfile(tf); if (labelsize == sizeof(struct hdr)) n = read(tf, (char *)hdrp, sizeof(struct hdr)); else { n = read(tf, buffer, labelsize); bcopy((char *)hdrp, buffer, sizeof(struct hdr)); } if ((n == labelsize) && (strncmp(hdrp->h_labid, "HDR", LABID) == 0)) found = TRUE; } } geteof(tf, eofp) int tf; struct hdr *eofp; { int n; if (labelsize == sizeof(struct hdr)) n = read(tf, eofp, sizeof(struct hdr)); else { n = read(tf, buffer, labelsize); bcopy((char *)eofp, buffer, sizeof(struct hdr)); } if (n != labelsize || strncmp(eofp->h_labid, "EOF", LABID) != 0 || eofp->h_labno != '1') printf("Warning: File label (EOF1) error\n"); } int getrec(f, buf, size) int f; char *buf; int size; { int n; n = read(f, buf, size); if (n < 0) fatal("Read error (record may be larger than %db)\n", size); return(n); } getmark(tf, hdr2p, labseq) int tf; int labseq; struct hd2 *hdr2p; { char rec[sizeof(struct hdr)]; char blkmax[BLKMAX+1], recmax[RECMAX+1]; char lstring[sizeof(struct hdr) + 1]; int n; int s; s = labseq; s++; n = read(tf, rec, sizeof(rec)); if (n == 0) return; if (n == sizeof(struct hdr) && (strncmp("HDR", rec, 3)==0)) { bcopy((char *)hdr2p, rec, sizeof(struct hdr)); if (hdr2p->h2_labno == s) { sncpy(blkmax, hdr2p->h2_blkmax, BLKMAX); sncpy(recmax, hdr2p->h2_recmax, RECMAX); if ((verbose) && (table)) prthdr2(&hdr2); blocksize = max(blocksize, atoi(blkmax)); if (hdr2p->h2_datatype == 'D') { linesize = 0; Varlen = TRUE; } else { linesize = max(linesize, atoi(recmax)); Varlen = FALSE; } realloc(buffer,blocksize+10); } } else if ((verbose) && (table)) { sncpy(lstring, rec, sizeof(struct hdr)); printf("%s\n", lstring); } /* skip HDR3-9 */ while (n == sizeof(struct hdr) && (strncmp("HDR", rec, 3)==0 || strncmp("EOF", rec, 3)==0)) { n = read(tf, rec, sizeof(rec)); if (n == 0) return; else if ((verbose) && (table)) { sncpy(lstring, rec, sizeof(struct hdr)); printf("%s\n", lstring); } } printf("Warning: tape mark missing\n"); } cmphdreof(hdrp, eofp) struct hdr *hdrp, *eofp; { char line[MAXLINE]; static int len = FILEID+SETID+SECNO+SEQNO+GENNO+GENVSNO+ CRDATE+EXDATE+1; if (strncmp(hdrp->h_fileid, eofp->h_fileid, len) != 0 || strncmp(hdrp->h_system, eofp->h_system, SYSTEM) != 0) { sncpy(line, hdrp->h_fileid, FILEID); fprintf(stderr, "Warning: HDR and EOF labels for %s disagree\n", line); } } putvol(tf, volp) int tf; struct vol *volp; { int len; if (labelsize == sizeof(struct vol)) { write(tf, volp, sizeof(struct vol)); return; } bcopy(buffer, (char *)volp, sizeof(struct vol)); len = labelsize - sizeof(struct vol); blcopy(&buffer[sizeof(struct vol)], "", len); write(tf, buffer, labelsize); } puthdr(tf, hdrp) int tf; struct hdr *hdrp; { int len; if (labelsize == sizeof(struct hdr)) { write(tf, hdrp, sizeof(struct hdr)); return; } bcopy(buffer, (char *)hdrp, sizeof(struct hdr)); len = labelsize - sizeof(struct hdr); blcopy(&buffer[sizeof(struct hdr)], "", len); write(tf, buffer, labelsize); } prtvol(volp) struct vol *volp; { char labid[LABID+1], serial[SERIAL+1], owner[OWNER+1]; sncpy(labid, volp->v_labid, LABID); sncpy(serial, volp->v_serial, SERIAL); sncpy(owner, volp->v_owner, OWNER); printf("Volume label:\n"); printf("\tLabel: %s%c Serial: %s Access: %c\n", labid, volp->v_labno, serial, volp->v_access); printf("\tOwner: %s Standard: %c\n", owner, volp->v_stdlabel); } prthdr(hdrp) struct hdr *hdrp; { char labid[LABID+1], fileid[FILEID+1], setid[SETID+1]; char secno[SECNO+1], seqno[SEQNO+1]; char genno[GENNO+1], genvsno[GENVSNO+1]; char crdate[CRDATE+1], exdate[EXDATE+1]; char blocks[BLOCKS+1], system[SYSTEM+1]; sncpy(labid, hdrp->h_labid, LABID); sncpy(fileid, hdrp->h_fileid, FILEID); sncpy(setid, hdrp->h_setid, SETID); sncpy(secno, hdrp->h_secno, SECNO); sncpy(seqno, hdrp->h_seqno, SEQNO); sncpy(genno, hdrp->h_genno, GENNO); sncpy(genvsno, hdrp->h_genvsno, GENVSNO); sncpy(crdate, hdrp->h_crdate, CRDATE); sncpy(exdate, hdrp->h_exdate, EXDATE); sncpy(blocks, hdrp->h_blocks, BLOCKS); sncpy(system, hdrp->h_system, SYSTEM); printf("File Label:\n"); printf("\tLabel: %s%c File: %s\n", labid, hdrp->h_labno, fileid); printf("\tSet: %s Section: %s Sequence: %s\n", setid, secno, seqno); printf("\tGeneration: %s Generation Version: %s\n", genno, genvsno); printf("\tCreated: %s Expires: %s Access: %c\n", crdate, exdate, hdrp->h_access); printf("\tBlocks: %s System: %s\n", blocks, system); } prthdr2(hdrp) struct hd2 *hdrp; { char labid[LABID+1]; char blkmax[BLKMAX+1], recmax[RECMAX+1]; char bytoffs[BYTOFFS+1]; sncpy(labid, hdrp->h2_labid, LABID); sncpy(blkmax, hdrp->h2_blkmax, BLKMAX); sncpy(recmax, hdrp->h2_recmax, RECMAX); sncpy(bytoffs, hdrp->h2_bytoffs, BYTOFFS); printf("File Label:\n"); printf("\tLabel: %s%c Datatype: %c\n", labid, hdrp->h2_labno, hdrp->h2_datatype); printf("\tMaximum block size: %s Maximum record size: %s\n", blkmax, recmax); printf("\tByte offset at head of block: %s\n", bytoffs); } initvol(volp) struct vol *volp; { struct passwd *passwp, *getpwuid(); blcopy(volp, "", sizeof(struct vol)); blcopy(volp->v_labid, "VOL", LABID); volp->v_labno = '1'; blcopy(volp->v_serial, defvsn, SERIAL); volp->v_access = ' '; passwp = getpwuid(getuid()); blcopy(volp->v_owner, passwp->pw_name, OWNER); if ((Varlen) || (Fixlen)) volp->v_stdlabel = '3'; else volp->v_stdlabel = '1'; } inithdr(hdrp, filename, seq) struct hdr *hdrp; char *filename; int seq; { char seqno[SEQNO+1]; blcopy(hdrp, "", sizeof(struct hdr)); blcopy(hdrp->h_labid, "HDR", LABID); hdrp->h_labno = '1'; blcopy(hdrp->h_fileid, filename, FILEID); blcopy(hdrp->h_secno, "0001", SECNO); utoaz(seq, seqno, SEQNO); blcopy(hdrp->h_seqno, seqno, SEQNO); blcopy(hdrp->h_genno, "0001", GENNO); blcopy(hdrp->h_genvsno, "00", GENVSNO); blcopy(hdrp->h_crdate, curdate, CRDATE); blcopy(hdrp->h_exdate, alongtime, EXDATE); blcopy(hdrp->h_blocks, "000000", BLOCKS); blcopy(hdrp->h_system, "Unix V7", SYSTEM); } inithdr2(hdr2p, rectype, b, r) struct hd2 *hdr2p; int rectype; int b, r; { char blkmax[BLKMAX+1]; char recmax[RECMAX+1]; blcopy(hdr2p, "", sizeof(struct hdr)); blcopy(hdr2p->h2_labid, "HDR", LABID); hdr2p->h2_labno = '2'; hdr2p->h2_datatype = rectype; utoaz(b, blkmax, BLKMAX); blcopy(hdr2p->h2_blkmax, blkmax, BLKMAX); utoaz(r, recmax, RECMAX); blcopy(hdr2p->h2_recmax, recmax, RECMAX); blcopy(hdr2p->h2_bytoffs, "00", BYTOFFS); } int dblock(fp,buffer,blocksize) FILE *fp; char *buffer; int blocksize; { FILE *fs; char dbuffer[MAXLINE+5]; #if DEBUG char tbuffer[ISOBLOCK + 1]; #endif char *bb, *db; int n, nl, nlm; int brem; int nf; fs = fopen("#tmp.tmp", "w"); if (fs == NULL) fatal("can't create #tmp.tmp\n"); bb = buffer; brem = blocksize + 1; n = 1; nlm = 0; while (n) { n = drecord(fp, dbuffer); nlm = max(nlm, n); #if DEBUG printf(" %s\n in dbuffer %d brem\n", dbuffer, brem); #endif if ((n) && ((brem -= n) > 0)) { for(nl = 0; nl < n; ++nl) *bb++ = dbuffer[nl]; #if DEBUG *bb = 0; printf("first try %s\n", buffer); #endif } else { brem += n; #if DEBUG printf(" %d fill bytes needed\n", brem); #endif while (brem-- > 0) *bb++ = '^'; bb = buffer; nl = n; #if DEBUG strncpy(tbuffer, buffer, blocksize);printf("%s\n", tbuffer); #endif nf = fwrite(buffer, blocksize, 1, fs); if (n) { for(nl = 0; nl < n; ++nl) *bb++ = dbuffer[nl]; #if DEBUG strncpy(tbuffer, buffer, blocksize);printf("%s\n", tbuffer); #endif brem = blocksize - n; } } } fclose(fs); return(nlm); } int drecord(fp, lbuffer) FILE *fp; char *lbuffer; { char count[DBYTES+1]; int n; n = filldln(fp, lbuffer); utoaz(n, count, DBYTES); bcopy(lbuffer, count, DBYTES); return(n); } int filldln(fp, lbuf) FILE *fp; char *lbuf; { int i, linelim; register int c; register char *lb; lb = lbuf; linelim = MAXLINE+DBYTES; i = DBYTES; lb += DBYTES; while ((c = getc(fp)) && (c != EOF) && (c != '\n')) { *lb++ = c; if (i++ > linelim-1) break; } *lb = '\0'; if (c == '\n') return(i); if (c == EOF) return(0); printf("%d byte line too long; Broken into parts.\n", i); return(i); } int lblock(fp, buffer, lsize, bfactor) FILE *fp; char *buffer; int lsize, bfactor; { register char *lp, *linelim; register int c; int i; char *bp; bp = buffer; for (i=0; i<bfactor; i++) { lp = bp; linelim = &lp[lsize]; while (lp < linelim) { c = getc(fp); if (c == '\n' || c == EOF) break; *lp++ = c; } if (c == EOF && lp == bp) break; while (c != '\n' && c != EOF) c = getc(fp); while (lp < linelim) *lp++ = ' '; bp += lsize; } return(bp - buffer); } lunblock(fp, buffer, blen, lsize) FILE *fp; char *buffer; int blen, lsize; { register char *lastp, *bp1; char *bp, *buflim; buflim = &buffer[blen]; bp = buffer; while (bp < buflim) { lastp = &bp[lsize-1]; while (lastp >= bp && isspace(*lastp)) lastp--; for (bp1=bp; bp1<=lastp; bp1++) putc(*bp1, fp); putc('\n', fp); bp += lsize; } } blcopy(dest, src, n) char *dest, *src; int n; { int i; i=0; while (i < n && *src) { *dest++ = *src++; i++; } while (i++ < n) *dest++ = ' '; } sncpy(dest, src, n) char *dest, *src; int n; { int i; i = 0; while (*src && i<n) { *dest++ = *src++; i++; } *dest = '\0'; } utoaz(n, buf, size) int n; char *buf; int size; { char *p; p = &buf[size-1]; while (p >= buf && n != 0) { *p = '0' + (n % 10); n /= 10; p--; } while (p >= buf) { *p = '0'; p--; } } tapemark(tf) int tf; { struct mtop mtop; mtop.mt_count = 1; mtop.mt_op = MTWEOF; ioctl(tf, MTIOCTOP, &mtop); } skipfile(tf) int tf; { struct mtop mtop; mtop.mt_count = 1; mtop.mt_op = MTFSF; ioctl(tf, MTIOCTOP, &mtop); } backspace(tf) int tf; { struct mtop mtop; mtop.mt_count = 1; mtop.mt_op = MTBSR; ioctl(tf, MTIOCTOP, &mtop); } /* getansidate -- return the current date in ansi format * * Ansi dates are strings of the form " yyddd" where * yy = the year and ddd = the day in the year. There must * be an initial blank. */ getansidate(curdate) char *curdate; { time_t now, time(); struct tm *timep, *localtime(); now = time(NULL); timep = localtime(&now); curdate[0] = ' '; utoaz(timep->tm_year, &curdate[1], 2); utoaz(timep->tm_yday, &curdate[3], 3); curdate[6] = '\0'; } int lookup(tab, name, Upper) char *tab[]; char *name; int Upper; { int i; char lower[MAXLINE]; if (Upper) { strcpy(lower, name); makelower(lower); } for (i=0; tab[i] != NULL; i++) #ifdef VARIAN if (wildcmp(tab[i], name, WILDCARD) == 0 || (Upper && wildcmp(tab[i], lower, WILDCARD)==0)) #else if (strcmp(tab[i], name) == 0 || (Upper && strcmp(tab[i], lower)==0)) #endif VARIAN return(TRUE); return(FALSE); } makelower(s) char *s; { register char *p; p = s; while (*p) { if (isupper(*p)) *p = tolower(*p); p++; } } makeupper(s) char *s; { register char *p; p = s; while (*p) { if (islower(*p)) *p = toupper(*p); p++; } } int haslower(p) register char *p; { while (*p) { if (islower(*p)) return(TRUE); p++; } return(FALSE); } toRT11(name) char *name; { char buf[32], *extp; extp = index(name, '.'); if (extp != NULL) { *extp = '\0'; extp++; } blcopy(buf, name, 6); buf[6] = '.'; if (extp != NULL) blcopy(&buf[7], extp, 3); else strcpy(&buf[7], "ext"); buf[10] = '\0'; strcpy(name, buf); } fromRT11(name) char *name; { char *op, *np; op = np = name; while (*op) { if (!isspace(*op)) *np++ = *op; op++; } *np = '\0'; } trimsp(s) char *s; { register char *p; p = &s[strlen(s)-1]; while (p >= s && isspace(*p)) p--; *++p = '\0'; } bcopy(dest, src, size) char *dest, *src; int size; { while (size-- > 0) *dest++ = *src++; } int max(a, b) int a, b; { if (a > b) return(a); return(b); } int checkw(c, name) char c, *name; { if (!confirm) return(TRUE); printf("%c %s:", c, name); c = getchar(); if (c != '\n') while ((c = getchar()) != '\n') ; return(c == 'y' || c == 'Y'); } /* VARARGS */ fatal(s, a1, a2, a3, a4) char *s; { fprintf(stderr, "ansitar: "); fprintf(stderr, s, a1, a2, a3, a4); exit(1); } #ifdef VARIAN /* varunblock - unblock variable length records ("D" format) * Beginning of each record contains a 4 digit number which is the * length of the record (including the count). * There are no line terminators (CR or LF). */ varunblock(fp, buffer, blen) FILE *fp; char *buffer; int blen; { /* the function now returns the # of bytes it decided to write */ register char *lastp, *bp1; char *bp, *buflim; int count; int newblen; /* this will count the actual bytes written out */ buflim = &buffer[blen]; bp = buffer; newblen = 0; #if DEBUG DBG" varunblock called. length %d\n",blen); if(DEBUG)hexdmp(" buffer passed to varunblock",buffer,blen); DBG" "); #endif DEBUG while (bp < buflim) { #if DEBUG DBG" count being made from %2x %2x %2x %2x %2x\n", *bp,*(bp+1),*(bp+2),*(bp+3),*(bp+4)); #endif sscanf(bp,"%4d",&count); count = count - 4; /* count includes the count itself */ #if DEBUG DBG" count %3d\n ",count); #endif if (*bp == 0x5e) /* if fill encountered for length */ { /* then abandon this record */ #if DEBUG DBG" hit filler. assume eor. break\n"); #endif break; } bp = bp+4; /* point to the end of line */ lastp = bp + count; while (bp<lastp) { #if DEBUG if(DEBUG) putc(*bp, stderr); #endif putc(*bp++, fp); newblen++; } #if DEBUG if(DEBUG) putc('\n', stderr); #endif putc('\n', fp); newblen++; } return(newblen); } wildcmp(wilds,str,wc) /* compare 2 strings. 1st can have a wildcard '*' */ char *wilds; /* input string possibly containing a wildcard chr*/ char *str; /* 2nd input string. wild chrs in it aren't 'wild'*/ char wc; /* the 'wild card' character, often a '*' */ { /* function return is 0 if equal (like strcmp). < > not supported */ char *l,*s; int flag; /* will watch for multiple *'s in 'wild'*/ char wcrd; if (strlen(str) == 0) return(-1); /* don't match phantom */ wcrd = wc & 127; flag = 0; /* wildcard not encountered yet */ for (l=wilds,s=str ; *l != '\0' ; ) { if (*l == wcrd) /* if wildcard emcountered, adjust pointers*/ { if (flag) return(0); flag = 1; l++; /* skip the wildcard */ s = str + strlen(str) - (strlen(wilds) - (l - wilds) ); } else{ /* no wildcard, increment pointers normally */ if (*l != *s) return(*l - *s); l++; s++; } } if (*s != '\0') return(*l - *s); return(0); /* returning "success" indicator. they were equal */ } #endif VARIAN #ifdef PIP /***************************************************************** * TAG( pipunblock ) * * Unblock pip records. These are in a counted format with a 4 byte * count, followed by the record. (Count includes the length of the * count). Blank space at the end of a block is filled with '^' * characters. */ pipunblock(fp, buffer, n) FILE *fp; char *buffer; { register char *cp; int len, i; for (cp=buffer; cp<buffer+n; ) { for (i=0, len=0; i<4; i++) len = len*10 + *cp++ - '0'; for (len -= 4; len > 0; len--) putc(*cp++, fp); putc('\n', fp); while (*cp == '^' && cp<buffer+n) cp++; } } /***************************************************************** * TAG( pipblock ) * * Read lines from the input file and block them pip-style into the * buffer. Make logical blocks of 512 bytes and fill space at the end * of the logical blocks with '^' characters. */ pipblock(fp, buffer, blocksize) FILE *fp; char *buffer; { register char *cp; static char linebuf[512]; /* lines not allowed longer than this? */ static int nline = 0; int n; if (blocksize%512) { fprintf(stderr, "Blocksize must be a multiple of 512 for pip tapes\n"); exit(1); } for (cp=buffer; cp<(buffer+blocksize); ) { if (nline <= 0) if (fgets(linebuf, 508, fp) == NULL) nline = -1; else { linebuf[508] = '\0'; nline = strlen(linebuf); if (linebuf[nline-1] == '\n') linebuf[--nline] = '\0'; } if (nline > (508 - (cp-buffer)%512) || (nline < 0 && (cp-buffer)%512 != 0)) while ( (cp-buffer)%512 != 0 ) *cp++ = '^'; if (cp-buffer >= blocksize || nline < 0) return cp-buffer; sprintf(cp, "%04d", nline+4); cp += 4; strncpy(cp, linebuf, 508); cp += nline; nline = 0; } return cp-buffer; /* should never get here, but you never know */ } #endif PIP 'StopHere'