|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 23994 (0x5dba)
Types: TextFile
Notes: UNIX file
Names: »restor.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/dump/restor.c«
/*
* Restore.
* restor key [args]
* f [dump] Use this dump, not the default.
* v Verbose.
* t Print dates of the dump.
* x,X Extract. X asks for reel numbers and does
* a rewind between reels.
* r,R Mass restore. R asks for reel numbers and does
* a rewind between reels.
*
* Multiple dumps can be put on a single spool of
* tape by dumping to the no rewind device. The restore is
* done by positioning the tape using the `skip' command and
* restoring using the `x' option.
*/
#include <stdio.h>
#include <dumptape.h>
#include <canon.h>
#include <filsys.h>
#include <fblk.h>
#include <discbuf.h>
#include <signal.h>
#define NRBUF 10 /* # of restore cache buffers */
/*
* This structure is used
* to remember the names and i numbers
* of the files being extracted.
*/
struct xf
{
char *xf_path; /* Path name */
ino_t xf_ino; /* The associated inumber */
};
/*
* Structure used to remember
* things about the directories that
* were on the tape.
*/
struct dlist
{
struct dlist *dl_dlp; /* Link */
ino_t dl_ino; /* Inumber of the directory */
long dl_seek; /* Temp file seek address */
long dl_size; /* Size in bytes */
};
int key; /* Operation */
int vflag; /* A verbose flag */
char *dtn = DTAPE; /* Dump file name */
FILE *dtp; /* Its file pointer */
struct dumpheader dh; /* Header buffer */
int reel = 1; /* Reel # */
size_t length = 512; /* Length of volume */
size_t nread; /* Bytes read from volume */
char tfn[30] = "/tmp/ddxxxxxx"; /* Temp file name */
FILE *tfp; /* Its file pointer */
struct dlist *dlist; /* List of directory nodes */
struct dlist *droot; /* Root (first) directory node */
char *ddbuf; /* Big buffer */
char *ddend; /* End of the big buffer */
int ddnbuf; /* Size of the big buffer */
union dumpdata *ddptr; /* Current buffer pointer */
char *map; /* Directory map */
int nxf; /* # of `x' files */
ino_t nindisc; /* # of inodes on the disc */
ino_t ningrab; /* # of inodes to grab */
struct xf *xfp; /* Pointer for x names */
/*
* Block mapping tables.
*/
#define LNBN ((daddr_t) NBN)
char offs[] = {
0,
ND,
ND+1,
ND+1+1,
ND+1+1+1
};
daddr_t ranges[] = {
ND,
ND + 1*LNBN,
ND + 1*LNBN + 1*LNBN*LNBN,
ND + 1*LNBN + 1*LNBN*LNBN + 1*LNBN*LNBN*LNBN
};
char shifts[] = {
0,
L2NBN,
2*L2NBN,
3*L2NBN
};
daddr_t masks[] = {
0,
LNBN-1,
LNBN*LNBN-1,
LNBN*LNBN*LNBN-1
};
/*
* Forward references for the
* one pass compiler.
*/
ino_t lookup();
ino_t numfile();
daddr_t balloc();
char *ctime();
int cleanup();
struct dlist *findnode();
union dumpdata *readdump();
char *calloc();
DISCBUF *dbimap();
main(argc, argv)
char *argv[];
{
register char *p;
register c, i;
register struct xf *rxfp;
char *name, *path;
ino_t ino;
if (argc < 2)
usage();
p = argv[1];
i = 1;
while ((c = *p++) != '\0') {
switch (c) {
case 'f':
if (++i >= argc)
usage();
dtn = argv[i];
break;
case 'r':
case 'R':
case 'x':
case 'X':
case 't':
if (key != 0)
usage();
key = c;
break;
case 'v':
vflag = 1;
break;
case '-':
{
/* Cf. nextvol() */
extern long RESTMIN, RESTMAX;
if (++i >= argc)
usage();
RESTMIN = atoi(argv[i]);
if (++i >= argc)
usage();
RESTMAX = atoi(argv[i]);
break;
}
default:
usage();
}
}
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, cleanup);
switch (key) {
case 'r':
case 'R':
if (++i >= argc)
usage();
if ((dbfp = fopen(argv[i], "r+w")) == NULL)
message(1, "%s: cannot open filesystem", argv[i]);
dbclaim(NRBUF);
if (key == 'r') {
opendump();
nextvol(1);
} else {
for (;;) {
reel = getreel();
opendump();
if (readhead(0) != 0)
break;
fclose(dtp);
}
}
restore();
dbflush(1);
break;
case 'x':
case 'X':
opendump();
nextvol(1);
mktemp(tfn);
if ((tfp = fopen(tfn, "w")) == NULL
|| (tfp = freopen(tfn, "r+w", tfp)) == NULL)
message(1, "cannot create temporary file");
readdirs();
xfp = (struct xf *)malloc((argc-i)*sizeof(struct xf));
if (xfp == NULL)
message(1, "too many restore names");
rxfp = xfp;
while (++i < argc) {
name = argv[i];
if ((ino = numfile(name)) != 0) {
if (ino<ROOTIN || ino>dh.dh_nino) {
message(0, "%s: bad inumber", name);
continue;
}
path = "(by ino)";
} else if ((ino = lookup(name)) != 0)
path = name;
else {
message(0, "%s: not found", name);
continue;
}
if (getmap(ino) == 0) {
message(0, "%s: not dumped", name);
continue;
}
rxfp->xf_path = path;
rxfp->xf_ino = ino;
rxfp++;
++nxf;
}
if (nxf == 0)
break;
for (i=0; i<nxf; ++i)
printf("%u\t%s\n", xfp[i].xf_ino, xfp[i].xf_path);
if (key == 'x')
readfile(0);
else {
for (;;) {
fclose(dtp);
reel = getreel();
opendump();
readfile(1);
for (i=0; i<nxf && xfp[i].xf_ino==0; ++i)
;
if (i == nxf)
break;
}
}
fclose(dtp);
for (i=0; i<nxf; ++i)
if (xfp[i].xf_ino != 0)
message(0, "%s: not restored", xfp[i].xf_path);
break;
case 't':
opendump();
readhead(1);
fprintf(stderr, "Dump since %s", ctime(&dh.dh_ddate));
fprintf(stderr, "Dumped on %s", ctime(&dh.dh_bdate));
break;
default:
usage();
}
delexit(0);
}
/*
* If the supplied character string
* is all number convert it to binary and
* return it. Otherwise return 0. A
* file name that is all numeric is taken
* to be an inumber.
*/
ino_t
numfile(s)
register char *s;
{
register ino_t ino;
register c;
ino = 0;
while ((c = *s++)>='0' && c<='9')
ino = 10*ino + c - '0';
if (c != '\0')
return (0);
return (ino);
}
/*
* Open the dump tape.
* Die if the tape cannot be opened
* for any reason.
*/
opendump()
{
if ((dtp = fopen(dtn, "r")) == NULL)
message(1, "%s: cannot open dump file", dtn);
}
/*
* Read reel number.
*/
getreel()
{
register c, flag, reel;
for (;;) {
fprintf(stderr, "restor: desired volume? ");
reel = 0;
flag = 0;
while ((c = getchar())>='0' && c<='9') {
flag = 1;
reel = 10*reel + c - '0';
}
if (c == EOF)
delexit(1);
if (c=='\n' && flag!=0)
return (reel);
message(0, "bad reel number");
while (c!=EOF && c!='\n')
c = getchar();
if (c == EOF)
delexit(1);
}
}
/*
* Do the hard work of a
* restore.
* (NOTE: I think that the flag is now a fossil).
*/
readfile(flag)
{
register union dumpdata *ddp;
register ino_t ino;
register FILE *rfp;
register i;
int bwerror, outsync;
char rfn[20];
if (flag) {
while ((ddp = readdump()) != NULL)
if (ddp->dd_type != DD_DATA)
break;
#if 0
if (readhead(0) == 0)
return;
while ((ddp = readdump()) != NULL) {
if (ddp->dd_type != DD_MAP)
break;
canino(ddp->dd_ino);
canint(ddp->dd_nmap);
setmap(ddp);
}
#endif
} else
ddp = readdump();
if (ddp==NULL || anyfiles()==0)
return;
outsync = 0;
do {
switch (ddp->dd_type) {
case DD_EOT:
return;
case DD_INO:
canino(ddp->dd_ino);
ino = ddp->dd_ino;
rfp = NULL;
bwerror = 0;
if (outsync == 1)
message(0, "skipped 1 item");
else if (outsync != 0)
message(0, "skipped %d items", outsync);
outsync = 0;
for (i=0; i<nxf && xfp[i].xf_ino!=ino; ++i)
;
if (i != nxf) {
sprintf(rfn, "%u", ino);
if ((rfp = fopen(rfn, "w")) == NULL)
message(0, "%s: cannot create", rfn);
else
xfp[i].xf_ino = 0;
}
while ((ddp = readdump()) != NULL) {
if (ddp->dd_type != DD_DATA)
break;
canino(ddp->dd_ino);
if (ddp->dd_ino != ino) {
if (outsync == 0)
message(0, "data sync");
++outsync;
continue;
}
if (rfp != NULL) {
candaddr(ddp->dd_block);
canint(ddp->dd_size);
if (bwrite(rfp, ddp) == 0)
bwerror = 1;
}
}
if (bwerror)
message("%s: write error", rfn);
if (rfp != NULL)
fclose(rfp);
if (anyfiles() == 0)
return;
break;
default:
if (outsync == 0)
message(0, "inode sync");
++outsync;
}
} while (ddp != NULL);
}
/*
* Do a restore.
* The tape is open and the header
* has been checked.
*/
restore()
{
register union dumpdata *ddp;
register DISCBUF *dbp;
struct filsys *fsp;
register ino_t ino;
struct dinode *dip;
struct dinode dinode;
int me, outsync;
int ifmt, ndeleted;
/*
* If the target file system is not
* large enough, complain about it and pretend
* that all of the inodes that are beyond the
* end are not there. This may, of course, leave
* the file system addled.
*/
dbp = dbread((long) SUPERI);
fsp = (struct filsys *) dbp->db_data;
nindisc = fsp->s_isize;
canino(nindisc);
nindisc = INOPB * (nindisc-INODEI);
ningrab = dh.dh_nino;
if (ningrab > nindisc) {
message(0, "I-list too small, some I-nodes may be deleted");
ningrab = nindisc;
}
/*
* Read in the map.
*/
while ((ddp=readdump()) != NULL) {
if (ddp->dd_type != DD_MAP)
break;
canino(ddp->dd_ino);
canint(ddp->dd_nmap);
setmap(ddp);
}
/*
* Do required inode clears.
* Never clear the badblock inode.
* Clear only as far as we are restoring;
* that is, ningrab inodes.
*/
for (ino=ROOTIN; ino<=ningrab; ++ino) {
me = getmap(ino);
if ((me&DD_BUSY)==0 || (me&DD_HERE)==DD_HERE) {
if (vflag)
message(0, "clri I#%u", ino);
clri(ino);
}
}
/*
* Read through the tape.
* Look for files that we are going to
* restore and do so.
*/
outsync = 0;
ndeleted = 0;
while (ddp!=NULL && ddp->dd_type!=DD_EOT) {
if (ddp->dd_type != DD_INO) {
if (outsync++ == 0)
message(0, "inode sync");
ddp = readdump();
continue;
}
/*
* Restore the file.
* Block by block.
* Don't move anything.
*/
canino(ddp->dd_ino);
if ((ino=ddp->dd_ino) > ningrab) {
if (vflag != 0)
message(0, "deleted I#%u", (unsigned)ino);
++ndeleted;
printskip(outsync);
outsync = 0;
while ((ddp=readdump()) != NULL) {
if (ddp->dd_type != DD_DATA)
break;
canino(ddp->dd_ino);
if (ddp->dd_ino!=ino && outsync++==0)
message(0, "skip sync");
}
continue;
}
if (vflag != 0)
message(0, "restoring I#%u", (unsigned)ino);
copyb(&dinode, &ddp->dd_dinode, sizeof(dinode));
canshort(ddp->dd_dinode.di_mode);
ifmt = ddp->dd_dinode.di_mode&IFMT;
if (ifmt==IFREG || ifmt==IFDIR)
zerob(dinode.di_addr, sizeof(dinode.di_addr));
printskip(outsync);
outsync = 0;
while ((ddp=readdump()) != NULL) {
if (ddp->dd_type != DD_DATA)
break;
canino(ddp->dd_ino);
if (ddp->dd_ino != ino) {
if (outsync++ == 0)
message(0, "data sync");
continue;
}
candaddr(ddp->dd_block);
canint(ddp->dd_size);
dbp = dbimap(&dinode, ddp->dd_block);
copyb(dbp->db_data,ddp->dd_data,ddp->dd_size);
dbfree(dbp, DB_DIRT);
}
dbp = dbread((long) (--ino/INOPB + INODEI));
dip = (struct dinode *)(dbp->db_data) + ino%INOPB;
if (dip->di_mode != 0) {
message(0, "I#%u busy", (unsigned)ino+1);
clri(ino+1);
}
copyb((char *)dip, (char *)&dinode, sizeof(dinode));
dbfree(dbp, DB_DIRT);
}
if (ndeleted != 0)
message(0, "%d I-nodes deleted", ndeleted);
fixilist();
}
/*
* Print out a message that
* tells the number of data items that were
* skipped on the tape. Special stuff for
* handling 0 and 1 items.
*/
printskip(n)
{
if (n == 1)
message(0, "skipped 1 item");
else if (n != 0)
message(0, "skipped %d items", n);
}
/*
* Fix the ifree list in
* the super block. It is safer to
* always reconstruct it.
*/
fixilist()
{
DISCBUF *ibp, *sbp;
register struct filsys *fsp;
register struct dinode *dip;
register ino_t ino;
short ninode, tinode, minode;
ino_t tmpino;
if (vflag)
message(0, "building I-free list");
sbp = dbread((long) SUPERI);
fsp = (struct filsys *)(sbp->db_data);
tinode = 0;
ninode = 0;
minode = fsp->s_isize;
canshort(minode);
minode = INOPB * (minode-INODEI);
ibp = NULL;
for (ino=1; ino<=minode; ++ino) {
if ((ino-1)%INOPB == 0) {
if (ibp != NULL)
dbfree(ibp, 0);
ibp = dbread((long) ((ino-1)/INOPB + INODEI));
dip = (struct dinode *)(ibp->db_data);
}
if (dip->di_mode == 0) {
++tinode;
if (ninode < NICINOD) {
tmpino = ino;
canino(tmpino);
fsp->s_inode[ninode++] = tmpino;
}
}
++dip;
}
dbfree(ibp, 0);
canshort(tinode);
fsp->s_tinode = tinode;
canshort(ninode);
fsp->s_ninode = ninode;
strncpy(fsp->s_fname, dh.dh_fname, sizeof(dh.dh_fname));
strncpy(fsp->s_fpack, dh.dh_fpack, sizeof(dh.dh_fpack));
dbfree(sbp, DB_DIRT);
}
/*
* Clear an inode.
* Free all of its blocks and
* zero the on disc inode. Don't worry about
* the super block as it is always rebuilt
* at the end.
*/
clri(ino)
ino_t ino;
{
register DISCBUF *dbp;
register struct dinode *dip;
register i;
short dimode;
daddr_t addr[NADDR];
dbp = dbread((long) ((ino-1)/INOPB + INODEI));
dip = (struct dinode *)(dbp->db_data) + (ino-1)%INOPB;
dimode = dip->di_mode;
canshort(dimode);
if ((dimode&IFMT)==IFDIR || (dimode&IFMT)==IFREG) {
l3tol(addr, dip->di_addr, NADDR);
for (i=0; i<NADDR-3; ++i)
bfree(addr[i], 0);
bfree(addr[NADDR-3], 1);
bfree(addr[NADDR-2], 2);
bfree(addr[NADDR-1], 3);
}
zerob((char *) dip, sizeof(struct dinode));
dbfree(dbp, DB_DIRT);
}
/*
* Free a block.
* The first argument is the block
* number. 0 here means no block is allocated
* and the call is a nop. The second argument
* is the number of levels of indirect blocks
* to read through.
*/
bfree(bn, nil)
daddr_t bn;
{
register DISCBUF *dbp, *dbp1;
struct filsys *fsp;
struct fblk *fbp;
int dbp1flag;
int i;
daddr_t ibn;
if (bn == 0)
return;
dbp1 = NULL;
if (nil != 0) {
dbp1flag = 0;
dbp1 = dbread((long) bn);
for (i=0; i<NBN; ++i) {
ibn = ((daddr_t *) dbp1->db_data)[i];
if (ibn != 0) {
candaddr(ibn); /* Added by Mike */
bfree(ibn, nil-1);
}
}
}
dbp = dbread((long) SUPERI);
fsp = (struct filsys *) dbp->db_data;
canshort(fsp->s_nfree);
if (fsp->s_nfree == NICFREE) {
if (dbp1 == NULL)
dbp1 = dbread((long) bn);
dbp1flag = DB_DIRT;
fbp = (struct fblk *) dbp1->db_data;
fbp->df_nfree = fsp->s_nfree;
canshort(fbp->df_nfree);
copyb(fbp->df_free, fsp->s_free, sizeof(fsp->s_free));
fsp->s_nfree = 0;
}
candaddr(bn);
fsp->s_free[fsp->s_nfree++] = bn;
canshort(fsp->s_nfree);
candaddr(fsp->s_tfree);
++fsp->s_tfree;
candaddr(fsp->s_tfree);
if (dbp1 != NULL)
dbfree(dbp1, dbp1flag);
dbfree(dbp, DB_DIRT);
}
/*
* Allocate a block.
* Return 0 if there are no blocks
* remaining.
*/
daddr_t
balloc()
{
register struct filsys *fsp;
register DISCBUF *dbp;
register DISCBUF *dbp1;
register struct fblk *fbp;
short nfree;
daddr_t tfree, bn;
dbp = dbread((long) SUPERI);
fsp = (struct filsys *) dbp->db_data;
if ((tfree = fsp->s_tfree) == 0)
message(1, "out of space");
candaddr(tfree);
nfree = fsp->s_nfree;
canshort(nfree);
if ((bn = fsp->s_free[--nfree]) == 0)
message(1, "out of space and tfree lied");
candaddr(bn);
if (nfree == 0) {
dbp1 = dbread((long) bn);
fbp = (struct fblk *) dbp1->db_data;
nfree = fbp->df_nfree;
canshort(nfree);
copyb(fsp->s_free, fbp->df_free, sizeof(fsp->s_free));
dbfree(dbp1, 0);
}
--tfree;
canshort(nfree);
fsp->s_nfree = nfree;
candaddr(tfree);
fsp->s_tfree = tfree;
dbfree(dbp, DB_DIRT);
return (bn);
}
/*
* Quickly zero out a block of
* memory. Used to clear out disc inodes
* and other similar things.
*/
zerob(ap, an)
char *ap;
{
register char *p;
register n;
if ((n = an) != 0) {
p = ap;
do {
*p++ = 0;
} while (--n);
}
}
/*
* Quickly move a block of
* memory from one place to another
* place.
*/
copyb(atp, afp, an)
char *atp;
char *afp;
{
register char *tp, *fp;
register n;
if ((n = an) != 0) {
tp = atp;
fp = afp;
do {
*tp++ = *fp++;
} while (--n);
}
}
/*
* Yet another version of
* the inode mapping code. This version
* allocates blocks if they are not present
* in the file. It makes good use of the
* buffer cache.
* A pointer to a DISCBUF holding the
* block is returned. Usually this will be
* a buffer created by `dbzero'.
*/
DISCBUF *
dbimap(dip, lb)
struct dinode *dip;
daddr_t lb;
{
register DISCBUF *dbp;
register il, newblock;
daddr_t addr[NADDR];
daddr_t pb, bpos, *bkp;
l3tol(addr, dip->di_addr, NADDR);
for (il=0; il<4; ++il) {
if (lb < ranges[il]) {
if (il > 0)
lb -= ranges[il-1];
bpos = lb >> shifts[il];
lb &= masks[il];
bkp = &addr[(int)bpos + offs[il]];
newblock = 0;
if ((pb = *bkp) == 0) {
newblock = 1;
*bkp = pb = balloc();
ltol3(dip->di_addr, addr, NADDR);
}
if (pb != 0) {
while (il-- > 0) {
if (newblock)
dbp = dbzero(pb); else
dbp = dbread(pb);
bpos = lb >> shifts[il];
lb &= masks[il];
bkp = (long *)dbp->db_data + bpos;
pb = *bkp;
candaddr(pb);
if (pb == 0) {
newblock = 1;
pb = balloc();
*bkp = pb;
candaddr(*bkp);
dbfree(dbp, DB_DIRT);
} else {
newblock = 0;
dbfree(dbp, 0);
}
if (pb == 0)
break;
}
}
if (pb != 0) {
if (newblock)
dbp = dbzero(pb); else
dbp = dbread(pb);
return (dbp);
}
return (NULL);
}
}
message(0, "file too large to map");
return (NULL);
}
/*
* Write a block.
*/
bwrite(fp, ddp)
register FILE *fp;
register union dumpdata *ddp;
{
lseek(fileno(fp), BUFSIZ*ddp->dd_block, 0);
if (write(fileno(fp), ddp->dd_data, ddp->dd_size) != ddp->dd_size)
return (0);
return (1);
}
/*
* Check if any files in the
* `x' file list remain on this
* tape (as indicated by the
* map).
*/
anyfiles()
{
register ino_t ino;
register i;
for (i=0; i<nxf; ++i) {
if ((ino = xfp[i].xf_ino)!=0 && getmap(ino)!=0)
return (1);
}
return (0);
}
/*
* Read and validate tape header.
* The `quit' flag is true if errors
* are fatal.
* Only allocate the map first time.
*/
readhead(quit)
{
register char *p;
register checksum;
if (read(fileno(dtp), &dh, sizeof dh) != sizeof dh) {
message(quit, "header read error");
return (0);
}
nread = sizeof dh;
canint(dh.dh_magic);
canino(dh.dh_nino);
cantime(dh.dh_bdate);
cantime(dh.dh_ddate);
canint(dh.dh_level);
canint(dh.dh_reel);
canint(dh.dh_blocking);
cansize(dh.dh_nbyte);
canint(dh.dh_checksum);
if (dh.dh_magic != DH_MAG) {
message(quit, "not a dump");
return (0);
}
p = (char *) &dh;
checksum = 0;
while (p < (char *) &dh.dh_checksum)
checksum += (*p++) & 0377;
if (checksum != dh.dh_checksum) {
message(quit, "checksum error");
return (0);
}
if (dh.dh_reel != reel) {
message(quit, "wrong reel (is %d, not %d)", dh.dh_reel, reel);
return (0);
}
++reel;
length = dh.dh_nbyte;
if (map == NULL) {
if ((map = calloc(sizeof(char), dh.dh_nino)) == NULL)
message(1, "out of memory (map)");
}
if (ddbuf != NULL)
free(ddbuf);
ddnbuf = dh.dh_blocking * sizeof(union dumpdata);
if ((ddbuf = malloc(ddnbuf)) == NULL)
message(1, "out of memory (big buffer)");
ddend = &ddbuf[ddnbuf];
ddptr = (union dumpdata *) ddend;
return (1);
}
/*
* Read in directories and set up
* the map. The last tape record is ungotten
* so that the extract code can be made a
* little simpler.
*/
readdirs()
{
register union dumpdata *ddp;
register struct dlist *dlp;
unsigned short mode;
while ((ddp = readdump()) != NULL) {
switch (ddp->dd_type) {
case DD_EOT:
--ddptr;
return;
case DD_MAP:
canino(ddp->dd_ino);
canint(ddp->dd_nmap);
setmap(ddp);
break;
case DD_INO:
mode = ddp->dd_dinode.di_mode;
canshort(mode);
if ((mode&IFMT) != IFDIR) {
--ddptr;
return;
}
canino(ddp->dd_ino);
cansize(ddp->dd_dinode.di_size);
dlp = (struct dlist *) malloc(sizeof(struct dlist));
if (dlp == NULL)
message(1, "out of memory (dlist)");
dlp->dl_dlp = dlist;
dlist = dlp;
if (droot == NULL)
droot = dlp;
dlp->dl_ino = ddp->dd_ino;
dlp->dl_seek = ftell(tfp);
dlp->dl_size = ddp->dd_dinode.di_size;
break;
case DD_DATA:
canino(ddp->dd_ino);
candaddr(ddp->dd_block);
canint(ddp->dd_size);
if (dlist==NULL || dlist->dl_ino!=ddp->dd_ino)
message(1, "directory out of sync");
fseek(tfp, dlp->dl_seek+(BUFSIZ*ddp->dd_block), 0);
fwrite(ddp->dd_data, sizeof(char), ddp->dd_size, tfp);
if (ferror(tfp))
message(1, "directory write error");
break;
default:
message(1, "bad type %d", ddp->dd_type);
}
}
}
/*
* Fill in map.
*/
setmap(ddp)
union dumpdata *ddp;
{
register char *p1, *p2;
register nb;
if ((nb = ddp->dd_nmap) != 0) {
p1 = &map[ddp->dd_ino-1];
p2 = ddp->dd_map;
do {
*p1++ = *p2++;
} while (--nb);
}
}
/*
* Get map item.
*/
getmap(ino)
ino_t ino;
{
return (map[ino-1]);
}
/*
* Read dump file.
* Canonize the type and look after
* multi-volume (reel) dumps.
*/
union dumpdata *
readdump()
{
register nb;
while ((char *) ddptr == ddend) {
if (length != 0 && (nread+ddnbuf) > length) {
nextvol(0);
continue;
}
if ((nb = read(fileno(dtp), ddbuf, ddnbuf)) != ddnbuf) {
if (nb != 0)
message(1, "dump read error");
nextvol(0);
continue;
}
ddptr = (union dumpdata *) ddbuf;
nread += nb;
break;
}
canint(ddptr->dd_type);
return (ddptr++);
}
/*
* Read the next volume (reel or diskette)
* from the dump.
* The flag is passed onto readhead for quiting.
*
* RESTMIN, RESTMAX, and restime are used to bound the time taken
* to restor a volume in hopes of preventing unbounded copies of
* Coherent dump distributions. The values are passed with an
* undocumented '-' option which specifies RESTMIN and RESTMAX.
*/
long RESTMIN, RESTMAX, restime, time();
nextvol(flag)
int flag;
{
register int c;
register char *vtype = "reel";
restime += time(NULL);
/* Spurious error to detect copies of dump volumes
* made with ms-dos formatter/copier. Activated by
* '-' key modifier in command list.
* Not documented in manual.
*/
if (RESTMIN && reel > 1 && (restime < RESTMIN || restime > RESTMAX))
message(1, "volume sync: %D", restime);
for (;;) {
fclose(dtp);
if (length != 0)
vtype = "volume";
fprintf(stderr, "restor: mount %s %d, type return key...",
vtype, reel);
while ((c = getchar())!=EOF && c!='\n')
;
if (c == EOF)
delexit(1);
restime = -time(NULL);
opendump();
if (readhead(flag) != 0)
break;
}
}
/*
* Lookup a file, by name.
* Return the inumber.
* This routine only looks in
* directories. The file may
* not actually be on the tape.
*/
ino_t
lookup(cp)
register char *cp;
{
char db[DIRSIZ];
struct direct dirbuf;
ino_t ino;
long seek;
struct dlist *dlp;
ino = ROOTIN;
for (;;) {
{
register char *dp;
register c;
while ((c = *cp++) == '/')
;
if (c == '\0')
return (ino);
dp = db;
for (;;) {
if (dp < &db[DIRSIZ])
*dp++ = c;
if ((c = *cp)=='\0' || c=='/')
break;
++cp;
}
while (dp < &db[DIRSIZ])
*dp++ = 0;
}
if ((dlp = findnode(ino)) == NULL)
return (0);
seek = dlp->dl_seek;
for (;;) {
if (seek-dlp->dl_seek >= dlp->dl_size)
return (0);
fseek(tfp, seek, 0);
fread(&dirbuf, sizeof(dirbuf), 1, tfp);
if (ferror(tfp))
message(1, "temporary file read error");
canino(dirbuf.d_ino);
ino = dirbuf.d_ino;
if (ino!=0 && strncmp(db, dirbuf.d_name, DIRSIZ)==0)
break;
seek += sizeof(struct direct);
}
}
}
/*
* Look for a directory inode
* in the dlist.
*/
struct dlist *
findnode(ino)
register ino_t ino;
{
register struct dlist *dlp;
dlp = dlist;
while (dlp != NULL) {
if (dlp->dl_ino == ino)
break;
dlp = dlp->dl_dlp;
}
return (dlp);
}
/*
* Usage message.
*/
usage()
{
fprintf(stderr, "Usage: restor key [args]\n");
delexit(1);
}
/*
* Message output.
*/
message(quit, a)
{
fprintf(stderr, "restor: %r\n", &a);
if (quit)
delexit(1);
}
/*
* Cleanup function.
* Called from the interrupt signal.
*/
cleanup()
{
delexit(1);
}
/*
* Exit.
* Delete the temp file, if there.
*/
delexit(s)
{
if (tfp != NULL)
unlink(tfn);
exit(s);
}