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