Return to BSD News archive
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!agate!howland.reston.ans.net!noc.near.net!ceylon!genesis!steve2 From: steve2@genesis.nred.ma.us Newsgroups: comp.os.386bsd.development Subject: ft dist0.2 part 03/03 Message-ID: <CCtK7G.3E5@genesis.nred.ma.us> Date: 4 Sep 93 07:45:10 GMT Organization: Genesis Public Access Unix +1 508 664 0149 Lines: 1589 # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # qtar # qtar/Makefile # qtar/action.c # qtar/fileset.c # qtar/ftecc.c # qtar/func.c # qtar/header.c # qtar/qtar.c # qtar/qtar.h # qtar/volume.c # tools # tools/getseg.c # tools/postest.c # echo c - qtar mkdir qtar > /dev/null 2>&1 echo x - qtar/Makefile sed 's/^X//' >qtar/Makefile << 'END-of-qtar/Makefile' X# X# Copyright (c) 1993 Steve Gerakines X# X# This is freely redistributable software. You may do anything you X# wish with it, so long as the above notice stays intact. X# X# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X# POSSIBILITY OF SUCH DAMAGE. X# X# Makefile - QIC tape archiver makefile X# 07/22/93 v0.1 X# Initial revision. X# X XCC = cc XCFLAGS = -O X XOBJ = qtar.o ftecc.o header.o action.o func.o fileset.o volume.o X Xqtar: $(OBJ) X $(CC) -o qtar $(OBJ) X Xclean: X rm -f qtar $(OBJ) core core.* X X$(OBJ): qtar.h END-of-qtar/Makefile echo x - qtar/action.c sed 's/^X//' >qtar/action.c << 'END-of-qtar/action.c' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * action.c - QIC tape archiver actions X * 07/22/93 v0.1 X * Initial revision. X */ X#include <stdio.h> X#include <stdlib.h> X#include <errno.h> X#include <sys/ftape.h> X#include "qtar.h" X#include <ctype.h> X Xint tfd; /* file descriptor for tape */ X X X/* List volume names on tape (volume list) */ Xvoid getvols() X{ X if (!check_stat(tfd,0)) { X ioctl(tfd, QIOREWIND); X if (!get_header(tfd)) vol_list(); X } X} X X/* Retrieve files from tape (extract or list) */ Xvoid getfiles() X{ X QIC_VTbl *v; X X if (check_stat(tfd,0)) return; X ioctl(tfd, QIOREWIND); X if (get_header(tfd)) return; X if ((v = vol_select(label)) == NULL) { X fprintf(stderr, "No volumes selected\n"); X return; X } X X /* Retrieve the file set directory from tape. */ X fs_retrieve(v); X X /* Traverse the file set data and list/extract files. */ X fs_perform(); X} X X X/* Put files to tape */ Xputfiles() X{ X} X X X/* X * Either get files or put files X */ Xdoaction() X{ X /* Open the tape device */ X tfd = open(ftdev, 2); X if (tfd < 2) { X perror(ftdev); X exit(0); X } X X switch(action) { X case ACT_LISTVOL: X getvols(); X break; X X case ACT_LIST: X case ACT_EXTRACT: X getfiles(); X break; X X case ACT_APPEND: X case ACT_CREATE: X putfiles(); X break; X X default: X fprintf(stderr, "qtar: invalid action code\n"); X break; X } X X close(tfd); X} END-of-qtar/action.c echo x - qtar/fileset.c sed 's/^X//' >qtar/fileset.c << 'END-of-qtar/fileset.c' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * fileset.c - QIC tape archiver fileset functions X * 08/14/93 v0.1 X * Initial revision. X */ X#include <stdio.h> X#include <stdlib.h> X#include <errno.h> X#include <time.h> X#include <sys/stat.h> X#include <pwd.h> X#include <grp.h> X#include <string.h> X#include <sys/ftape.h> X#include "qtar.h" X#include <ctype.h> X XULONG sg_cpos; /* Absolute byte position on tape */ XULONG sg_bpos; /* Byte offset within data block */ XULONG sg_avail; /* Total bytes available in current segment */ XULONG sg_foffset; /* First block offset found */ XULONG sg_boffset; /* Byte offset from segment structure */ XULONG sg_bcount; /* Byte count from segment structure */ Xint sg_iscpr; /* TRUE if this block of data is compressed */ Xint sg_first; /* TRUE if first segment read */ X XFSNode fsroot; /* file set root directory */ Xchar rootname[2]; /* root directory string "" or "/" */ Xint curuid, curgid; /* uid and gid of current user */ X X/* Initialize for I/O processing on a fileset. */ Xfs_init(QIC_VTbl *v) X{ X sg_cpos = (ULONG)v->vt_first * QCV_SEGSIZE; X curuid = getuid(); X curgid = getgid(); X} X X X/* Read single characters, buffer by segment */ Xint fs_getc() X{ X static int curseg = -1; X static int curtrk = -1; X int bpos, sno, tno, cno, r; X QIC_Segment s; X X tno = sg_cpos / (QCV_SEGSIZE * geo.g_segtrk); X sno = (sg_cpos / QCV_SEGSIZE) % geo.g_segtrk; X cno = sg_cpos % QCV_SEGSIZE; X X if (sg_first) { X sg_first = 0; X goto nextseg; X } X X /* If current character exceeds amount available, next segment. */ X if (cno >= sg_avail) { Xcompute_next: X sg_cpos &= ~0x7fff; X sg_cpos += QCV_SEGSIZE; X tno = sg_cpos / (QCV_SEGSIZE * geo.g_segtrk); X sno = (sg_cpos / QCV_SEGSIZE) % geo.g_segtrk; X cno = sg_cpos % QCV_SEGSIZE; X goto nextseg; X } X X /* If byte position exceeds amount in this block, process next block. */ X if (vf_strat && sg_bpos == sg_bcount) { X if ((sg_avail - cno) <= 12) goto compute_next; X sg_bcount = US_VAL(buff,cno); X if (!sg_bcount) goto compute_next; X sg_bpos = 0; X cno += 2; X sg_cpos += 2; X } X X if (tno != curtrk || sno != curseg) { Xnextseg: X curseg = sno; X curtrk = tno; X s.sg_trk = tno; X s.sg_seg = sno; X s.sg_badmap = BADMAP(tno,sno); X s.sg_data = buff; X if (ioctl(tfd, QIOREAD, &s) < 0) perror("read"); X r = check_parity(s.sg_data, s.sg_badmap, s.sg_crcmap); X sg_avail = sect_bytes(s.sg_badmap) - QCV_ECCSIZE; X switch (vf_strat) { X case 0: /* No compression used */ X bpos = 0; X sg_cpos = tno * QCV_SEGSIZE * geo.g_segtrk + sno * QCV_SEGSIZE; X sg_boffset = sg_cpos; X sg_bcount = sg_avail; X sg_iscpr = 0; X cno = 0; X/*printf("trk %d segment %d sg_boffset=%d\n", tno, sno, sg_boffset);*/ X break; X case 1: /* Compression, no segment spanning */ X sg_foffset = 0; X break; X case 2: X sg_foffset = US_VAL(s.sg_data,0); X cno += 2; X sg_cpos += 2; X break; X } X } X X if (vf_strat && cno == sg_foffset) { X sg_boffset = UL_VAL(buff,cno); X sg_bcount = US_VAL(buff,cno+4) & 0x7fff; X sg_iscpr = (US_VAL(buff,cno+4) & 0x8000) == 0; X cno += 6; X sg_cpos += 6; X } X X r = buff[cno++]; X sg_cpos++; X X return(r); X} X X X/* Retrieve file set directory from tape for a given volume. */ Xint fs_retrieve(QIC_VTbl *v) X{ X char *name; X X /* Initialize for processing a volume */ X vol_init(v); X sg_first = 1; X X /* Initialize the root node */ X rootname[0] = (isabsolute) ? '/' : '\0'; X rootname[1] = '\0'; X fsroot.name = rootname; X bzero(fsroot.fixed, 10); X bzero(fsroot.sys, 32); X fsroot.hsize = fsroot.dsize = 0; X fsroot.nxosi = 0; X fsroot.xosi = NULL; X fsroot.next = fsroot.prev = fsroot.parent = NULL; X fsroot.dirh = fsroot.dirt = NULL; X X /* Recurse and gather file info if root not empty. */ X if (UL_VAL(v->vt_dtasize,0)) return(fs_gather(&fsroot, rootname)); X return(0); X} X X X/* Gather file info recursively. */ Xfs_gather(FSNode *n, char *dname) X{ X FSNode *dh, *dt; X int i, siz, psiz; X FSNode *nn; X char curdir[80]; X char tmpstr[128]; X X dh = dt = NULL; X X psiz = strlen(dname); X if (psiz && dname[psiz-1] == '/') psiz--; X if (dname[0] == '/') psiz--; X X /* First, read all entries for the current directory. */ X for (;;) { X /* Allocate a new node */ X if ((nn = (FSNode *)malloc(sizeof(FSNode))) == NULL) { X fprintf(stderr, "qtar: Out of memory!\n"); X exit(1); X } X for (i = 0; i < 10; i++) nn->fixed[i] = fs_getc(); X siz = nn->fixed[0] - 9; X for (i = 0; siz > 0; siz--, i++) nn->sys[i] = fs_getc(); X siz = fs_getc(); X if ((nn->name = malloc(siz+1)) == NULL) { X fprintf (stderr, "qtar: Out of memory!\n"); X exit(1); X } X if (islowering) { X for (i = 0; siz > 0; siz--, i++) X nn->name[i] = tolower(fs_getc()); X } else { X for (i = 0; siz > 0; siz--, i++) X nn->name[i] = fs_getc(); X } X nn->name[i] = '\0'; X nn->hsize = nn->dsize = 0; X if (UL_VAL(nn->fixed,6)) { X nn->hsize = nn->fixed[0] + i + psiz + 7; X nn->dsize = UL_VAL(nn->fixed,6) - nn->hsize; X } X X nn->nxosi = 0; X nn->xosi = NULL; X nn->next = nn->prev = NULL; X nn->parent = n; X nn->dirh = nn->dirt = NULL; X if (dh != NULL) { X nn->prev = dt; X dt->next = nn; X dt = nn; X } else X dh = dt = nn; X if (nn->fixed[1] & 0xc0) break; X } X X /* Save the list head and tail for the given parent. */ X n->dirh = dh; X n->dirt = dt; X X /* Next scan the list and recurse on non-empty sub directories. */ X for (; dh != NULL; dh = dh->next) { X if ((dh->fixed[1] & 0x20) == 0) continue; X sprintf(curdir, "%s%s/", dname, dh->name); X if (UL_VAL(dh->fixed,6)) continue; X fs_gather(dh, curdir); X } X return(0); X} X X/* Kick off tree traversal. */ Xfs_perform() X{ X fs_traverse(&fsroot, rootname, nfiles ? 1 : 0); X} X X/* Locate files in the tree recursively. */ Xfs_traverse(FSNode *n, char *path, int docmp) X{ X FSNode *dh; X int i; X char item[256]; X X dh = n->dirh; X for (; dh != NULL; dh = dh->next) { X if (dh->dirh != NULL) continue; X strcpy(item, path); X strcat(item, dh->name); X if (docmp) { X for (i = 0; i < nfiles; i++) X if (!strcmp(item, filelist[i])) break; X if (i == nfiles) continue; X } X if (action == ACT_EXTRACT) X fs_extract(dh, item); X else X fs_list(dh, item); X } X X dh = n->dirh; X for (; dh != NULL; dh = dh->next) { X if (dh->dirh == NULL) continue; X strcpy(item, path); X strcat(item, dh->name); X/*printf("docmp=%d nfiles=%d item=%s\n", docmp, nfiles, item);*/ X if (docmp) { X for (i = 0; i < nfiles; i++) X if (!strcmp(item, filelist[i])) break; X if (i == nfiles) { X strcat(item, "/"); X fs_traverse(dh, item, 1); X continue; X } X } X if (action == ACT_EXTRACT) X fs_extract(dh, item); X else X fs_list(dh, item); X strcat(item, "/"); X fs_traverse(dh, item, 0); X } X} X X/* Extract an item from tape */ Xfs_extract(FSNode *n, char *item) X{ X} X X/* List an item stored on tape */ Xfs_list(FSNode *n, char *item) X{ X int uid, gid, perm, size; X int i, uextend; X char str[32], str2[16], pbits[11], owner[32], *cp; X const char xwr[] = "xwr"; X static struct passwd *p; X static struct group *g; X struct tm *mtime; X static int omax = 3; X static int smax = 5; X static int lastuid = -1; /* cache last uid and gid entries */ X static int lastgid = -1; X X if (!isverbose) { X printf("%s%s\n", item, (n->fixed[1] & 0x20) ? "/" : ""); X return(0); X } X X /* Decide if the unix extension area exists */ X uextend = (n->fixed[0] > 9 && n->sys[0] == 1) ? 1 : 0; X X /* Figure out permissions and file type */ X perm = (n->fixed[1] & 0x7) << 6; X if (uextend) { X perm |= n->sys[1] & 0x3f; X perm |= (n->sys[2] & 0x01) ? S_ISUID : 0; X perm |= (n->sys[2] & 0x02) ? S_ISGID : 0; X perm |= (n->sys[2] & 0x04) ? S_ISTXT : 0; X perm |= (n->sys[2] & 0x10) ? S_IFCHR : 0; X perm |= (n->sys[2] & 0x20) ? S_IFBLK : 0; X perm |= (n->sys[2] & 0x40) ? S_IFREG : 0; X perm |= (n->sys[2] & 0x80) ? S_IFIFO : 0; X } X X size = 0; X if ((n->fixed[1] & 0x20) == 0) { X if (!uextend) perm |= S_IFREG; X size = n->dsize; X } else X perm |= S_IFDIR; X X /* Get file uid and gid, if any */ X uid = (uextend) ? UL_VAL(n->sys,15) : curuid; X gid = (uextend) ? UL_VAL(n->sys,19) : curgid; X X /* Modification time */ X mtime = qtime(&n->fixed[2]); X X /* Now display what we've got. */ X strcpy(pbits, "----------"); X if ((perm & S_IFBLK) == S_IFBLK) X pbits[0] = 'b'; X else if ((perm & S_IFDIR) == S_IFDIR) X pbits[0] = 'd'; X else if ((perm & S_IFCHR) == S_IFCHR) X pbits[0] = 'c'; X else if ((perm & S_IFIFO) == S_IFIFO) X pbits[0] = 'p'; X for (i = 0; i < 9; i++) X if (perm & (1 << i)) pbits[9 - i] = xwr[i % 3]; X X if (uid != lastuid) { X if ((p = getpwuid(uid)) == NULL) { X uid = curuid; X p = getpwuid(curuid); X } X lastuid = uid; X } X if (gid != lastgid) { X if ((g = getgrgid(gid)) == NULL) { X gid = curgid; X g = getgrgid(curgid); X } X lastgid = gid; X } X strcpy(owner, (p == NULL) ? "nobody" : p->pw_name); X strcat(owner, "/"); X strcat(owner, (p == NULL) ? "nobody" : g->gr_name); X if (omax < (i=strlen(owner))) omax = i; X sprintf(str, "%d", size); X if (smax < (i=strlen(str))) smax = i; X strcpy(str, asctime(mtime)); X if ((cp = strchr(str, '\n')) != NULL) *cp = '\0'; X X if (pbits[0] == 'b' || pbits[0] == 'c') { X sprintf(str2, "%d, %d", n->sys[23], n->sys[24]); X printf("%s %-*.*s %*.*s %s %s%s\n", X pbits, omax,omax,owner, smax,smax,str2, X str, item, (n->fixed[1]&0x20) ? "/":""); X } else X printf("%s %-*.*s %*d %s %s%s\n", X pbits, omax,omax,owner, smax,size, X str, item, (n->fixed[1]&0x20) ? "/":""); X} END-of-qtar/fileset.c echo x - qtar/ftecc.c sed 's/^X//' >qtar/ftecc.c << 'END-of-qtar/ftecc.c' X/* X * ftecc.c 07/22/93 X * Handle error correction for floppy tape drives. X * X * File contents are copyrighted by David L. Brown and falls under the X * terms of the GNU Public License. See his original release for the X * specific terms. X * X * Steve Gerakines X * steve2@genesis.nred.ma.us X * Modified slightly to fit with my tape driver. I'm not at all happy X * with this module and will have it replaced with a more functional one X * in the next release. I am close, but progress will continue to be X * slow until I can find a book on the subject where the translator X * understands both the to and from languages. :-( For now it will X * suffice. X */ X#include <sys/ftape.h> X#include "qtar.h" X X/* X * In order to speed up the correction and adjustment, we can compute X * a matrix of coefficients for the multiplication. X */ Xstruct inv_mat { X UCHAR log_denom; /* The log z of the denominator. */ X UCHAR zs[3][3]; /* The coefficients for the adjustment matrix. */ X}; X X/* This array is a table of powers of x, from 0 to 254. */ Xstatic UCHAR alpha_power[] = { X 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, X 0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4, X 0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb, X 0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd, X 0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31, X 0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67, X 0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc, X 0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b, X 0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4, X 0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26, X 0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21, X 0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba, X 0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30, X 0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, X 0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3, X 0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a, X 0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9, X 0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44, X 0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef, X 0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85, X 0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6, X 0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf, X 0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff, X 0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58, X 0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a, X 0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24, X 0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8, X 0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64, X 0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2, X 0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda, X 0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77, X 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3 X}; X X/* X * This is the reverse lookup table. There is no log of 0, so the X * first element is not valid. X */ Xstatic UCHAR alpha_log[] = { X 0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a, X 0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a, X 0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1, X 0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3, X 0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83, X 0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4, X 0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35, X 0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38, X 0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70, X 0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48, X 0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24, X 0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15, X 0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f, X 0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10, X 0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7, X 0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b, X 0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08, X 0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a, X 0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91, X 0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb, X 0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2, X 0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf, X 0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52, X 0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86, X 0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc, X 0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc, X 0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8, X 0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44, X 0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1, X 0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97, X 0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5, X 0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7 X}; X X/* Multiply two numbers in the field. */ Xstatic UCHAR multiply(UCHAR a, UCHAR b) X{ X int tmp; X X if (a == 0 || b == 0) return(0); X tmp = (alpha_log[a] + alpha_log[b]); X if (tmp > 254) tmp -= 255; X return (alpha_power[tmp]); X} X Xstatic UCHAR divide(UCHAR a, UCHAR b) X{ X int tmp; X X if (a == 0 || b == 0) return(0); X tmp = (alpha_log[a] - alpha_log[b]); X if (tmp < 0) tmp += 255; X return (alpha_power[tmp]); X} X X/* X * This is just like divide, except we have already looked up the log X * of the second number. X */ Xstatic UCHAR divide_out(UCHAR a, UCHAR b) X{ X int tmp; X X if (a == 0) return 0; X tmp = alpha_log[a] - b; X if (tmp < 0) tmp += 255; X return (alpha_power[tmp]); X} X X/* This returns the value z^{a-b}. */ Xstatic UCHAR z_of_ab(UCHAR a, UCHAR b) X{ X int tmp = (int)a - (int)b; X X if (tmp < 0) X tmp += 255; X else if (tmp >= 255) X tmp -= 255; X return(alpha_power[tmp]); X} X X/* Calculate the inverse matrix. Returns 1 if the matrix is valid, or X * zero if there is no inverse. The i's are the indices of the bytes X * to be corrected. X */ Xstatic int calculate_inverse (UCHAR *pblk, struct inv_mat *inv) X{ X /* First some variables to remember some of the results. */ X UCHAR z20, z10, z21, z12, z01, z02; X UCHAR i0, i1, i2; X X i0 = pblk[0]; i1 = pblk[1]; i2 = pblk[2]; X X z20 = z_of_ab (i2, i0); z10 = z_of_ab (i1, i0); X z21 = z_of_ab (i2, i1); z12 = z_of_ab (i1, i2); X z01 = z_of_ab (i0, i1); z02 = z_of_ab (i0, i2); X inv->log_denom = (z20 ^ z10 ^ z21 ^ z12 ^ z01 ^ z02); X if (inv->log_denom == 0) return 0; X inv->log_denom = alpha_log[inv->log_denom]; X X /* Calculate all of the coefficients on the top. */ X inv->zs[0][0] = alpha_power[i1] ^ alpha_power[i2]; X inv->zs[0][1] = z21 ^ z12; X inv->zs[0][2] = alpha_power[255-i1] ^ alpha_power[255-i2]; X X inv->zs[1][0] = alpha_power[i0] ^ alpha_power[i2]; X inv->zs[1][1] = z20 ^ z02; X inv->zs[1][2] = alpha_power[255-i0] ^ alpha_power[255-i2]; X X inv->zs[2][0] = alpha_power[i0] ^ alpha_power[i1]; X inv->zs[2][1] = z10 ^ z01; X inv->zs[2][2] = alpha_power[255-i0] ^ alpha_power[255-i1]; X return(1); X} X X/* X * Determine the error values for a given inverse matrix and syndromes. X */ Xstatic void determine3(struct inv_mat *inv, UCHAR *es, UCHAR *ss) X{ X UCHAR tmp; X int i, j; X X for (i = 0; i < 3; i++) { X tmp = 0; X for (j = 0; j < 3; j++) tmp ^= multiply (ss[j], inv->zs[i][j]); X es[i] = divide_out(tmp, inv->log_denom); X } X} X X X/* X * Compute the 3 syndrome values. The data pointer should point to X * the offset within the first block of the column to calculate. The X * count of blocks is in blocks. The three bytes will be placed in X * ss[0], ss[1], and ss[2]. X */ Xstatic void compute_syndromes(UCHAR *data, int nblks, int col, UCHAR *ss) X{ X int i; X UCHAR v; X X ss[0] = 0; ss[1] = 0; ss[2] = 0; X for (i = (nblks-1)*QCV_BLKSIZE; i >= 0; i -= QCV_BLKSIZE) { X v = data[i+col]; X if (ss[0] & 0x01) { ss[0] >>= 1; ss[0] ^= 0xc3; } else ss[0] >>= 1; X ss[0] ^= v; X ss[1] ^= v; X if (ss[2] & 0x80) { ss[2] <<= 1; ss[2] ^= 0x87; } else ss[2] <<= 1; X ss[2] ^= v; X } X} X X/* X * Calculate the parity bytes for a segment. Returns 0 on success. X */ Xint set_parity (UCHAR *data, ULONG badmap) X{ X int col; X struct inv_mat inv; X UCHAR ss[3], es[3], pblk[3]; X int nblks; X X nblks = sect_count(badmap); X pblk[0] = nblks-3; pblk[1] = nblks-2; pblk[2] = nblks-1; X if (!calculate_inverse(pblk, &inv)) return(1); X pblk[0] *= QCV_BLKSIZE; pblk[1] *= QCV_BLKSIZE; pblk[2] *= QCV_BLKSIZE; X for (col = 0; col < QCV_BLKSIZE; col++) { X compute_syndromes (data, nblks, col, ss); X determine3(&inv, es, ss); X data[pblk[0]+col] = es[0]; X data[pblk[1]+col] = es[1]; X data[pblk[2]+col] = es[2]; X } X return(0); X} X X X/* X * Check and correct errors in a block. Returns 0 on success, X * 1 if failed. X */ Xint check_parity(UCHAR *data, ULONG badmap, ULONG crcmap) X{ X int i, j, col, crcerrs, r, tries, nblks; X struct inv_mat inv; X UCHAR i1, i2, ss[3], es[3], eblk[3]; X X nblks = sect_count(badmap); X crcerrs = 0; X for (i = 0; crcerrs < 3 && i < nblks; i++) X if (crcmap & (1 << i)) eblk[crcerrs++] = i; X X for (i = 1, j = crcerrs; j < 3 && i < nblks; i++) X if ((crcmap & (1 << i)) == 0) eblk[j++] = i; X X if (!calculate_inverse (eblk, &inv)) return(1); X X eblk[0] *= QCV_BLKSIZE; eblk[1] *= QCV_BLKSIZE; eblk[2] *= QCV_BLKSIZE; X r = 0; X for (col = 0; col < QCV_BLKSIZE; col++) { X compute_syndromes (data, nblks, col, ss); X X if (!ss[0] && !ss[1] && !ss[2]) continue; X if (crcerrs) { X determine3 (&inv, es, ss); X for (j = 0; j < crcerrs; j++) X data[eblk[j] + col] ^= es[j]; X compute_syndromes (data, nblks, col, ss); X if (!ss[0] && !ss[1] && !ss[2]) { X r = 1; X continue; X } X } X determine3 (&inv, es, ss); X i1 = alpha_log[divide(ss[2], ss[1])]; X i2 = alpha_log[divide(ss[1], ss[0])]; X if (i1 != i2 || ((QCV_BLKSIZE * i1) + col) > QCV_SEGSIZE) X r = 1; X else X data[QCV_BLKSIZE * i1 + col] ^= ss[1]; X } X X return(r); X} END-of-qtar/ftecc.c echo x - qtar/func.c sed 's/^X//' >qtar/func.c << 'END-of-qtar/func.c' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * func.c - QIC tape archiver misc support functions X * 07/22/93 v0.1 X * Initial revision. X */ X#include <stdio.h> X#include <errno.h> X#include <time.h> X#include <sys/ftape.h> X#include "qtar.h" X X X/* Check status of tape drive */ Xint check_stat(int fd, int wr) X{ X int r, s; X X r = ioctl(fd, QIOSTATUS, &s); X if (r < 0) { X fprintf(stderr, "Couldn't get drive status\n"); X return(1); X } X X if ((s & QS_FMTOK) == 0) { X fprintf(stderr, "Tape is not formatted\n"); X return(2); X } X X if (wr && (s & QS_RDONLY) != 0) { X fprintf(stderr, "Tape is write protected\n"); X return(3); X } X X return(0); X} X X/* Return number of sectors available in a segment. */ Xint sect_count(ULONG badmap) X{ X int i, amt; X X for (amt = QCV_BLKSEG, i = 0; i < QCV_BLKSEG; i++) X if (badmap & (1 << i)) amt--; X return(amt); X} X X/* Return number of bytes available in a segment. */ Xint sect_bytes(ULONG badmap) X{ X int i, amt; X X for (amt = QCV_SEGSIZE, i = 0; i < QCV_BLKSEG; i++) X if (badmap & (1 << i)) amt -= QCV_BLKSIZE; X return(amt); X} X X/* Return tm struct from QIC date format. */ Xstruct tm *qtime(UCHAR *qt) X{ X ULONG *vp = (ULONG *)qt; X static struct tm t; X ULONG v; X X v = *vp; X t.tm_year = ((v >> 24) & 0xff)+47; v &= 0xffffff; X t.tm_sec = v % 60; v /= 60; X t.tm_min = v % 60; v /= 60; X t.tm_hour = v % 24; v /= 24; X t.tm_mday = (v % 31)+1; v /= 31; X t.tm_mon = v % 12; v /= 12; X t.tm_wday = 0; X t.tm_yday = 0; X t.tm_isdst = 0; X t.tm_gmtoff = 0; X t.tm_zone = NULL; X return(&t); X} X END-of-qtar/func.c echo x - qtar/header.c sed 's/^X//' >qtar/header.c << 'END-of-qtar/header.c' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * header.c - QIC tape archiver header processing X * 07/22/93 v0.1 X * Initial revision. X */ X#include <stdio.h> X#include <errno.h> X#include <time.h> X#include <sys/ftape.h> X#include "qtar.h" X Xint gothdr = 0; /* TRUE if valid header found */ Xint shdr = -1; /* Header Segment */ Xint sdhdr = -1; /* Duplicate header Segment */ Xint sdcms = -1; /* Compression map Segment */ Xint svtbl = -1; /* Volume table Segment */ X XUCHAR buff[QCV_SEGSIZE]; /* Scratch buffer */ X Xstatic UCHAR hbuff[QCV_SEGSIZE]; /* Header buffer */ Xstatic UCHAR vbuff[QCV_SEGSIZE]; /* VTBL buffer (packed) */ Xstatic UCHAR cbuff[QCV_SEGSIZE]; /* Compression map (packed) */ XQIC_Header *hptr = (QIC_Header *)hbuff; /* Pointer to header */ XQIC_VTbl *vptr = (QIC_VTbl *)vbuff; /* Pointer to vtbl */ XQIC_DCMap *cptr = (QIC_DCMap *)cbuff; /* Pointer to dcms */ Xint vbytes = 0; /* VTBL size in bytes */ Xint cbytes = 0; /* Compression map size */ XQIC_Geom geo; /* Tape geometry */ X X X/* Read header from tape */ Xget_header(int fd) X{ X int r, sn, bytes; X QIC_Segment s; X X if (ioctl(fd, QIOGEOM, &geo) < 0) { X fprintf(stderr, "Couldn't determine tape geometry\n"); X return(1); X } X X /* First get the header and duplicate */ X for (sn = 0; sn < 16; sn++) { X s.sg_trk = 0; X s.sg_seg = sn; X s.sg_badmap = 0; X s.sg_data = buff; X ioctl(fd, QIOREAD, &s); X r = check_parity(s.sg_data, 0, s.sg_crcmap); X X if (s.sg_data[0] == 0x55 && s.sg_data[1] == 0xaa && X s.sg_data[2] == 0x55 && s.sg_data[3] == 0xaa) { X if (shdr >= 0) { X sdhdr = sn; X if (!r && !gothdr) { X fprintf(stderr, "Using secondary header\n"); X bcopy(s.sg_data, hbuff, QCV_SEGSIZE); X gothdr = 1; X } X break; X } X shdr = sn; X if (!r) { X bcopy(s.sg_data, hbuff, QCV_SEGSIZE); X gothdr = 1; X } else { X fprintf(stderr, "Too many errors in primary header\n"); X } X } X } X X if (!gothdr) { X fprintf(stderr, "Couldn't read header segment\n"); X ioctl(fd, QIOREWIND); X return(1); X } X X for (sn = sdhdr+1; sn < 32; sn++) { X s.sg_trk = 0; X s.sg_seg = sn; X s.sg_badmap = BADMAP(0,sn); X s.sg_data = buff; X ioctl(fd, QIOREAD, &s); X r = check_parity(s.sg_data, s.sg_badmap, s.sg_crcmap); X bytes = sect_bytes(s.sg_badmap); X X if (s.sg_data[0] == 'D' && s.sg_data[1] == 'C' && X s.sg_data[2] == 'M' && s.sg_data[3] == 'S') { X if (r) fprintf(stderr, "Compression map failed CRC check\n"); X sdcms = sn; X cbytes = bytes; X bcopy(s.sg_data, cbuff, cbytes); X break; X } X if (svtbl >= 0) break; /* if no compression map, stop */ X X if (s.sg_data[0] == 'V' && s.sg_data[1] == 'T' && X s.sg_data[2] == 'B' && s.sg_data[3] == 'L') { X if (r) fprintf(stderr, "Volume table failed CRC check\n"); X svtbl = sn; X vbytes = bytes; X bcopy(s.sg_data, vbuff, vbytes); X continue; X } X } X return(0); X} END-of-qtar/header.c echo x - qtar/qtar.c sed 's/^X//' >qtar/qtar.c << 'END-of-qtar/qtar.c' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * qtar.c - QIC tape archiver X * 07/22/93 v0.1 X * Initial groundwork for a QIC format tape archiver. X */ X#include <stdio.h> X#include <errno.h> X#include <sys/ftape.h> X#include "qtar.h" X Xint action = ACT_NONE; /* action to perform */ Xint isverbose = 0; /* list verbosely */ Xchar *ftdev = "/dev/ft0a"; /* device to use */ Xint ismultivol = 0; /* multi-volume archive */ Xint ispreserve = 0; /* preserve permissions */ Xint isabsolute = 0; /* absolute filenames */ Xint islowering = 0; /* convert to lowercase filenames */ Xint isstdout = 0; /* extract to stdout */ Xchar *label = NULL; /* volume label to use (default = first) */ Xchar **filelist; Xint nfiles = 0; X X/* Display usage */ Xusage() X{ X printf("usage: qtar [-clrtx][LMOPpv] [-f dev] [-V vol] [file ...]\n"); X printf("One of the following actions:\n"); X printf(" -c create new archive\n"); X printf(" -l list tape volumes only\n"); X printf(" -r append files to archive\n"); X printf(" -t list files in archive\n"); X printf(" -x extract files from archive\n"); X printf("Options:\n"); X printf(" -L lowercase filenames\n"); X printf(" -M multi-volume archive\n"); X printf(" -O extract to stdout\n"); X printf(" -P don't remove leading '/'\n"); X printf(" -p preserve permissions on extract\n"); X printf(" -v verbose listing of files\n"); X printf(" -f device use device instead of %s\n", ftdev); X printf(" -V volume specify volume name\n"); X exit(0); X} X X X/* Main entry point */ Xmain(int argc, char *argv[]) X{ X int i, j; X char *cp; X X if (argc < 2) usage(); X for (i = 1; i < argc; i++) { X cp = argv[i]; X if (i > 1 && *cp != '-') break; X if (*cp == '-') cp++; X X while (*cp != '\0') { X switch(*cp) { X case 'c': X if (action != ACT_NONE) usage(); X action = ACT_CREATE; X break; X case 'l': X if (action != ACT_NONE) usage(); X action = ACT_LISTVOL; X break; X case 'r': X if (action != ACT_NONE) usage(); X action = ACT_APPEND; X break; X case 't': X if (action != ACT_NONE) usage(); X action = ACT_LIST; X break; X case 'x': X if (action != ACT_NONE) usage(); X action = ACT_EXTRACT; X break; X case 'L': X islowering++; X break; X case 'M': X ismultivol++; X break; X case 'O': X isstdout++; X break; X case 'P': X isabsolute++; X break; X case 'p': X ispreserve++; X break; X case 'v': X isverbose++; X break; X case 'f': X if (i == (argc - 1) || argv[i+1][0] == '-') usage(); X cp[1] = '\0'; X ftdev = argv[++i]; X break; X case 'V': X if (i == (argc - 1) || argv[i+1][0] == '-') usage(); X cp[1] = '\0'; X label = argv[++i]; X break; X default: X usage(); X /* NOTREACHED */ X } X cp++; X } X } X if (action == ACT_NONE) usage(); X nfiles = argc - i; X filelist = &argv[i]; X if ((action == ACT_APPEND || action == ACT_CREATE) && !nfiles) usage(); X if (action == ACT_LISTVOL && nfiles) usage(); X X doaction(); X X exit(0); X} END-of-qtar/qtar.c echo x - qtar/qtar.h sed 's/^X//' >qtar/qtar.h << 'END-of-qtar/qtar.h' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * qtar.h - QIC tape archiver header file X * 07/22/93 v0.1 X * Initial revision. X */ X X/* Action requested */ Xenum { X ACT_NONE, /* No action */ X ACT_LIST, /* List files in volume */ X ACT_LISTVOL, /* List tape volumes */ X ACT_EXTRACT, /* Extract from volume */ X ACT_APPEND, /* Append new volume */ X ACT_CREATE /* Create new volume, erasing old */ X}; X X/* Fileset structure */ Xtypedef struct fsnode { /* file set tree */ X char *name; /* file/directory name */ X UCHAR fixed[10]; /* fixed info */ X UCHAR sys[32]; /* system specific info */ X int hsize; /* Total header size */ X int dsize; /* Total data size */ X int nxosi; /* number of applicable xosi records */ X UCHAR **xosi; /* the actual XOSI records */ X struct fsnode *next; /* next directory entry */ X struct fsnode *prev; /* previous directory entry */ X struct fsnode *parent; /* pointer to parent directory entry */ X struct fsnode *dirh; /* head of sub-directory */ X struct fsnode *dirt; /* tail of sub-directory */ X} FSNode; X Xextern int action; /* action to perform */ Xextern int isverbose; /* list verbosely */ Xextern char *ftdev; /* device to use */ Xextern int ismultivol; /* multi-volume archive */ Xextern int ispreserve; /* preserve permissions */ Xextern int isabsolute; /* absolute filenames */ Xextern int islowering; /* convert to lowercase filenames */ Xextern int isstdout; /* extract to stdout */ Xextern char *label; /* volume label to use */ Xextern char **filelist; /* list of files to process */ Xextern int nfiles; /* number of files to process */ Xextern int tfd; /* file descriptor for tape */ Xextern QIC_VTbl *vptr; /* VTBL pointer */ Xextern QIC_Header *hptr; /* Header pointer */ Xextern QIC_DCMap *cptr; /* DCMS pointer */ Xextern UCHAR buff[QCV_SEGSIZE]; /* Scratch buffer */ Xextern QIC_Geom geo; /* Current tape's geometry */ Xextern int vf_strat; /* Compression strategy */ X Xextern int vbytes; /* VTBL size in bytes */ Xextern int cbytes; /* DCMS size in bytes */ Xextern int gothdr; /* TRUE if header found */ Xextern int shdr; /* Header segment number */ Xextern int sdhdr; /* Duplicate header segment number */ Xextern int svtbl; /* Volume table segment number */ Xextern int sdcms; /* Compresion map segment number */ X X/* header.c */ Xextern int get_header(); X X/* func.c */ Xextern int check_stat(); Xextern struct tm *qtime(); Xextern int sect_count(); Xextern int sect_bytes(); X X/* ftecc.c */ Xextern int set_parity(); Xextern int check_parity(); X X/* volume.c */ Xextern int vol_init(); Xextern int vol_list(); Xextern QIC_VTbl *vol_select(); X X/* fileset.c */ Xextern int fs_init(); Xextern int fs_retrieve(); Xextern int fs_gather(); Xextern int fs_traverse(); Xextern int fs_getc(); X X/* Lookup the badmap for a given track and segment. */ X#define BADMAP(t,s) hptr->qh_badmap[(t)*geo.g_segtrk+(s)] X X/* Retrieve values from a character array. */ X#define UL_VAL(s,p) (*((ULONG *)&(s)[p])) X#define US_VAL(s,p) (*((USHORT *)&(s)[p])) END-of-qtar/qtar.h echo x - qtar/volume.c sed 's/^X//' >qtar/volume.c << 'END-of-qtar/volume.c' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * volume.c - QIC tape archiver volume support functions X * 08/14/93 v0.1 X * Initial revision. X */ X#include <stdio.h> X#include <stdlib.h> X#include <errno.h> X#include <time.h> X#include <sys/ftape.h> X#include "qtar.h" X#include <ctype.h> X X/* Volume flags */ Xint vf_compress; /* TRUE if compression used */ Xint vf_cptype; /* Compression method */ Xint vf_segspan; /* TRUE if segment spanning used */ Xint vf_strat; /* Volume I/O strategy */ X X/* Retrieve the name of a volume, use default if none given. */ Xchar *vol_name(QIC_VTbl *v) X{ X static char str[45]; X X /* Grab this volume's name; use default name if none */ X strncpy(str, v->vt_vname, 44); X str[44] = '\0'; X if (str[0] == '\0' || str[0] == ' ') X sprintf(str, "Volume_%d\n", (int)(v - vptr) / sizeof(QIC_VTbl)); X return(str); X} X X X/* List volumes in vtbl */ Xvol_list() X{ X char str[80]; X int i; X int maxent = vbytes / sizeof(QIC_VTbl); X struct tm *t; X QIC_VTbl *v; X X if (isverbose) { X printf( X"Volume Seq OS Saved Label\n"); X printf( X"============================================ === ==== ======== ================\n"); X } X X for (i = 0; i < maxent; i++) { X v = &vptr[i]; X if (v->vt_sig[0] != 'V' || v->vt_sig[1] != 'T' || X v->vt_sig[2] != 'B' || v->vt_sig[3] != 'L') break; X if (!isverbose) { X printf("%s\n", vol_name(v)); X continue; X } X printf("%-44.44s ", vol_name(v)); X printf("%3d ", v->vt_multi); X switch (v->vt_ostype) { X case 1: X printf("DOS "); X break; X case 2: X printf("Unix "); X break; X case 4: X printf("OS/2 "); X break; X case 8: X printf("Mac "); X break; X case 16: X printf("NetW "); X break; X case 32: X printf("LanM "); X break; X default: X printf("Unk "); X break; X } X X t = qtime(v->vt_savdate); X printf("%02d/%02d/%02d ", t->tm_mon+1, t->tm_mday, t->tm_year % 100); X X strncpy(str, v->vt_label, 16); X str[16] = '\0'; X printf("%s\n",str); X } X if (!i && isverbose) printf("(no volumes)\n"); X} X X X/* Locate the requested volume label by name. */ XQIC_VTbl *vol_select(char *which) X{ X QIC_VTbl *v; X int maxent = vbytes / sizeof(QIC_VTbl); X char str[45]; X int i; X X /* If no volume segment found, return error. */ X if (svtbl < 0) return(NULL); X X for (i = 0; i < maxent; i++) { X v = &vptr[i]; X if (v->vt_sig[0] != 'V' || v->vt_sig[1] != 'T' || X v->vt_sig[2] != 'B' || v->vt_sig[3] != 'L') break; X if (which == NULL) return(v); X if (!strncmp(vol_name(v), which, 44)) return(v); X } X return(NULL); X} X X X/* Initialize for I/O on a given volume. */ Xvol_init(QIC_VTbl *v) X{ X X /* Initialize flags for this volume */ X vf_compress = v->vt_cprtype & 0x80; X vf_cptype = v->vt_cprtype & 0x3f; X vf_segspan = v->vt_flags & 0x10; X vf_strat = 0; X if (vf_compress) { X vf_strat = 1; X if (vf_segspan) vf_strat = 2; X } X fs_init(v); X} END-of-qtar/volume.c echo c - tools mkdir tools > /dev/null 2>&1 echo x - tools/getseg.c sed 's/^X//' >tools/getseg.c << 'END-of-tools/getseg.c' X#include <stdio.h> X#include <sys/ftape.h> X#include <errno.h> X XQIC_Segment s; XUCHAR buff[QCV_SEGSIZE]; X Xmain(int argc, char *argv[]) X{ X int i, j, r, fd; X int seg, trk; X QIC_Geom g; X X if (argc != 3) { X fprintf(stderr, "usage: getseg track# seg#\n"); X exit(1); X } X X if ((fd = open("/dev/ft0a",0)) < 0) { X perror("/dev/ft0a"); X exit(1); X } X trk = atoi(argv[1]); X seg = atoi(argv[2]); X X r = ioctl(fd, QIOGEOM, &g); X if (r < 0) { X perror("QIOGEOM"); X exit(1); X } X fprintf(stderr, "Current tape format is: %s/%s\n", g.g_fmtdesc,g.g_lendesc); X X if (trk < 0 || trk >= g.g_trktape || X seg < 0 || seg >= g.g_segtrk) { X fprintf(stderr, "bad parameters for tape; tracks %d segments %d\n", X g.g_trktape, g.g_segtrk); X exit(1); X } X X s.sg_trk = trk; X s.sg_seg = seg; X s.sg_data = buff; X fprintf(stderr, "reading %d %d ... ", trk, seg); X r = ioctl(fd, QIOREAD, &s); X if (r < 0) perror("QIOREAD"); X fprintf(stderr, "badmap is %08lx\n", s.sg_crcmap); X close(fd); X fwrite(buff, 1, QCV_SEGSIZE, stdout); X exit(0); X} END-of-tools/getseg.c echo x - tools/postest.c sed 's/^X//' >tools/postest.c << 'END-of-tools/postest.c' X#include <stdio.h> X#include <sys/ftape.h> X#include <errno.h> X XQIC_Segment s; XUCHAR buff[QCV_SEGSIZE]; X Xmain() X{ X int i, j, r, fd; X int seg, trk; X X srand(time(NULL)); X X if ((fd = open("/dev/ft0a",0)) < 0) { X perror("/dev/ft0a"); X exit(1); X } X X for (i = 0; i < 20; i++) { X j = rand() % 10; X seg = rand() % 150; X trk = rand() % 28; X while (j--) { X s.sg_trk = trk; X s.sg_seg = seg; X s.sg_data = buff; X printf("==> reading %d %d\n", trk, seg); X r = ioctl(fd, QIOREAD, &s); X if (r < 0) perror("QIOREAD"); X seg = (seg + 1) % 150; X if (!seg) trk++; X } X } X X printf("all done."); X close(fd); X exit(0); X} END-of-tools/postest.c exit