-/* Copyright (c) 1982 Regents of the University of California */
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
#ifndef lint
-char version[] = "@(#)main.c 2.13 %G%";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
-/* Modified to include h option (recursively extract all files within
- * a subtree) and m option (recreate the heirarchical structure of
- * that subtree and move extracted files to their proper homes).
+#ifndef lint
+static char sccsid[] = "@(#)main.c 5.6 (Berkeley) %G%";
+#endif /* not lint */
+
+/*
+ * Modified to recursively extract all files within a subtree
+ * (supressed by the h option) and recreate the heirarchical
+ * structure of that subtree and move extracted files to their
+ * proper homes (supressed by the m option).
+ * Includes the s (skip files) option for use with multiple
+ * dumps on a single tape.
* 8/29/80 by Mike Litzkow
*
- * Modified to work on the new file system
+ * Modified to work on the new file system and to recover from
+ * tape read errors.
* 1/19/82 by Kirk McKusick
*
- * Includes the s (skip files) option for use with multiple dumps on
- * a single tape.
+ * Full incremental restore running entirely in user code and
+ * interactive tape browser.
+ * 1/19/83 by Kirk McKusick
*/
-#define MAXINO 3000
-#define BITS 8
-#define NCACHE 3
-#define SIZEINC 10
-
-#include <stdio.h>
-#include <signal.h>
-#include <fstab.h>
-#ifndef SIMFS
-#include <sys/param.h>
-#include <sys/inode.h>
-#include <sys/fs.h>
-#include <dir.h>
-#include <stat.h>
-#include <dumprestor.h>
-#else
-#include "../h/param.h"
-#include "../h/dir.h"
-#include "../h/stat.h"
-#include "../h/inode.h"
-#include "../h/fs.h"
-#include "../h/dumprestor.h"
-#endif
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-
-#define ODIRSIZ 14
-struct odirect {
- u_short d_ino;
- char d_name[ODIRSIZ];
-};
-
-#define MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
-#define MBIT(i) (1<<((unsigned)(i-1)%NBBY))
-#define BIS(i,w) (MWORD(w,i) |= MBIT(i))
-#define BIC(i,w) (MWORD(w,i) &= ~MBIT(i))
-#define BIT(i,w) (MWORD(w,i) & MBIT(i))
-
-ino_t ino;
-
-int eflag = 0, hflag = 0, mflag = 0, vflag = 0, yflag = 0;
-int cvtflag = 0, cvtdir = 0;
-
-long fssize;
-char tapename[] = "/dev/rmt8";
-char *magtape = tapename;
-int mt;
-int dumpnum = 1;
-int volno = 1;
-int curblk = 0;
-int bct = NTREC+1;
-char tbf[NTREC*TP_BSIZE];
-
-daddr_t seekpt;
-FILE *df;
-DIR *dirp;
-int ofile;
-char dirfile[] = "/tmp/rstaXXXXXX";
-char lnkbuf[MAXPATHLEN + 1];
-int pathlen;
-
-#define INOHASH(val) (val % MAXINO)
-struct inotab {
- struct inotab *t_next;
- ino_t t_ino;
- daddr_t t_seekpt;
-} *inotab[MAXINO];
-int maxino = 0;
-
-#define XISDIR 1
-#define XTRACTD 2
-#define XINUSE 4
-#define XLINKED 8
-struct xtrlist {
- struct xtrlist *x_next;
- struct xtrlist *x_linkedto;
- time_t x_timep[2];
- ino_t x_ino;
- char x_flags;
- char x_name[1];
- /* actually longer */
-} *xtrlist[MAXINO];
-int xtrcnt = 0;
-struct xtrlist *entry;
-struct xtrlist *unknown;
-struct xtrlist *allocxtr();
-
+#include "restore.h"
+#include <protocols/dumprestore.h>
+#include <sys/signal.h>
+#include "pathnames.h"
+
+int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
+int hflag = 1, mflag = 1, Nflag = 0;
+char command = '\0';
+long dumpnum = 1;
+long volno = 0;
+long ntrec;
char *dumpmap;
char *clrimap;
-
-char clearedbuf[MAXBSIZE];
-
-extern char *ctime();
-extern int seek();
-ino_t search();
-int dirwrite();
-#ifdef RRESTOR
-char *host;
-#endif
+ino_t maxino;
+time_t dumptime;
+time_t dumpdate;
+FILE *terminal;
main(argc, argv)
int argc;
char *argv[];
{
register char *cp;
- char command;
+ ino_t ino;
+ char *inputdev = _PATH_DEFTAPE;
+ char *symtbl = "./restoresymtable";
+ char name[MAXPATHLEN];
int (*signal())();
- int done();
+ extern int onintr();
- if (signal(SIGINT, done) == SIG_IGN)
- signal(SIGINT, SIG_IGN);
- if (signal(SIGTERM, done) == SIG_IGN)
- signal(SIGTERM, SIG_IGN);
- mktemp(dirfile);
+ if (signal(SIGINT, onintr) == SIG_IGN)
+ (void) signal(SIGINT, SIG_IGN);
+ if (signal(SIGTERM, onintr) == SIG_IGN)
+ (void) signal(SIGTERM, SIG_IGN);
+ setlinebuf(stderr);
if (argc < 2) {
usage:
- fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
+ fprintf(stderr, "Usage:\n%s%s%s%s%s",
+ "\trestore tfhsvy [file file ...]\n",
+ "\trestore xfhmsvy [file file ...]\n",
+ "\trestore ifhmsvy\n",
+ "\trestore rfsvy\n",
+ "\trestore Rfsvy\n");
done(1);
}
argv++;
argc -= 2;
+ command = '\0';
for (cp = *argv++; *cp; cp++) {
switch (*cp) {
case '-':
case 'c':
cvtflag++;
break;
- case 'f':
- magtape = *argv++;
-#ifdef RRESTOR
- { char *index();
- host = magtape;
- magtape = index(host, ':');
- if (magtape == 0) {
-nohost:
- msg("need keyletter ``f'' and device ``host:tape''");
- done(1);
- }
- *magtape++ = 0;
- if (rmthost(host) == 0)
- done(1);
- }
-#endif
- argc--;
- break;
- /* s dumpnum (skip to) for multifile dump tapes */
- case 's':
- dumpnum = atoi(*argv++);
- if (dumpnum <= 0) {
- fprintf(stderr, "Dump number must be a positive integer\n");
- done(1);
- }
- argc--;
+ case 'd':
+ dflag++;
break;
case 'h':
- hflag++;
+ hflag = 0;
break;
case 'm':
- mflag++;
+ mflag = 0;
+ break;
+ case 'N':
+ Nflag++;
break;
- case 'x':
- command = *cp;
- /* set verbose mode by default */
case 'v':
vflag++;
break;
case 'y':
yflag++;
break;
- case 'r':
- case 'R':
- hflag++;
- mflag++;
+ case 'f':
+ if (argc < 1) {
+ fprintf(stderr, "missing device specifier\n");
+ done(1);
+ }
+ inputdev = *argv++;
+ argc--;
+ break;
+ case 'b':
+ /*
+ * change default tape blocksize
+ */
+ bflag++;
+ if (argc < 1) {
+ fprintf(stderr, "missing block size\n");
+ done(1);
+ }
+ ntrec = atoi(*argv++);
+ if (ntrec <= 0) {
+ fprintf(stderr, "Block size must be a positive integer\n");
+ done(1);
+ }
+ argc--;
+ break;
+ case 's':
+ /*
+ * dumpnum (skip to) for multifile dump tapes
+ */
+ if (argc < 1) {
+ fprintf(stderr, "missing dump number\n");
+ done(1);
+ }
+ dumpnum = atoi(*argv++);
+ if (dumpnum <= 0) {
+ fprintf(stderr, "Dump number must be a positive integer\n");
+ done(1);
+ }
+ argc--;
+ break;
case 't':
+ case 'R':
+ case 'r':
+ case 'x':
+ case 'i':
+ if (command != '\0') {
+ fprintf(stderr,
+ "%c and %c are mutually exclusive\n",
+ *cp, command);
+ goto usage;
+ }
command = *cp;
break;
default:
goto usage;
}
}
-#ifdef RRESTOR
- if (host == 0)
- goto nohost;
-#endif
- doit(command, argc, argv);
- done(0);
-}
-
-doit(command, argc, argv)
- char command;
- int argc;
- char *argv[];
-{
- struct mtop tcom;
-
-#ifdef RRESTOR
- if ((mt = rmtopen(magtape, 0)) < 0) {
-#else
- if ((mt = open(magtape, 0)) < 0) {
-#endif
- fprintf(stderr, "%s: cannot open tape\n", magtape);
- done(1);
- }
- if (dumpnum != 1) {
- tcom.mt_op = MTFSF;
- tcom.mt_count = dumpnum -1;
-#ifdef RRESTOR
- rmtioctl(MTFSF,dumpnum - 1);
-#else
- if (ioctl(mt,MTIOCTOP,&tcom) < 0)
- perror("ioctl MTFSF");
-#endif
- }
- blkclr(clearedbuf, (long)MAXBSIZE);
- if (readhdr(&spcl) == 0) {
- bct--; /* push back this block */
- cvtflag++;
- if (readhdr(&spcl) == 0) {
- fprintf(stderr, "Tape is not a dump tape\n");
- done(1);
- }
- fprintf(stderr, "Converting to new file system format.\n");
+ if (command == '\0') {
+ fprintf(stderr, "must specify i, t, r, R, or x\n");
+ goto usage;
}
- switch(command) {
- case 't':
- fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
- fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
- return;
- case 'R':
- case 'r':
- setdir(*argv);
+ setinput(inputdev);
+ if (argc == 0) {
argc = 1;
- *argv = ".";
- /* and then extract it all */
- case 'x':
- df = fopen(dirfile, "w");
- if (df == 0) {
- fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
- done(1);
- }
- extractfiles(argc, argv);
- return;
- }
-}
-
-extractfiles(argc, argv)
- int argc;
- char **argv;
-{
- char *ststore();
- register struct xtrlist *xp;
- struct xtrlist **xpp;
- ino_t d;
- int xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(),
- xtrlnkfile(), xtrlnkskip(), null();
- int mode, uid, gid, i;
- struct stat stbuf;
- char name[BUFSIZ + 1];
-
- if (stat(".", &stbuf) < 0) {
- fprintf(stderr, "cannot stat .\n");
- done(1);
- }
- fssize = stbuf.st_blksize;
- if (fssize <= 0 || ((fssize - 1) & fssize) != 0) {
- fprintf(stderr, "bad block size %d\n", fssize);
- done(1);
- }
- if (checkvol(&spcl, 1) == 0) {
- fprintf(stderr, "Tape is not volume 1 of the dump\n");
+ *--argv = ".";
}
- clrimap = 0;
- dumpmap = 0;
- unknown = allocxtr(0, "name unknown - not extracted", 0);
- pass1(1); /* This sets the various maps on the way by */
- while (argc--) {
- if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
- fprintf(stderr, "%s: not on tape\n", *argv++);
- continue;
- }
- if (mflag)
- checkdir(*argv);
- if (hflag)
- getleaves(d, *argv++);
- else
- (void)allocxtr(d, *argv++, XINUSE);
- }
- if (dumpnum > 1) {
- /*
- * if this is a multi-dump tape we always start with
- * volume 1, so as to avoid accidentally restoring
- * from a different dump!
- */
- resetmt();
- dumpnum = 1;
- volno = 1;
- readhdr(&spcl);
- goto rbits;
- }
-newvol:
-#ifdef RRESTOR
- rmtclose();
-#else
- close(mt);
-#endif
-getvol:
- fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
- if (gets(tbf) == NULL)
- return;
- volno = atoi(tbf);
- if (volno <= 0) {
- fprintf(stderr, "Volume numbers are positive numerics\n");
- goto getvol;
- }
-#ifdef RRESTOR
- if ((mt = rmtopen(magtape, 0)) == -1) {
-#else
- if ((mt = open(magtape, 0)) == -1) {
-#endif
- fprintf(stderr, "Cannot open tape!\n");
- goto getvol;
- }
- if (dumpnum > 1)
- resetmt();
- if (readhdr(&spcl) == 0) {
- fprintf(stderr, "tape is not dump tape\n");
- goto newvol;
- }
- if (checkvol(&spcl, volno) == 0) {
- fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
- goto newvol;
- }
-rbits:
- while (gethead(&spcl) == 0)
- ;
- if (checktype(&spcl, TS_INODE) == 1) {
- fprintf(stderr, "Can't find inode mask!\n");
- goto newvol;
- }
- if (checktype(&spcl, TS_BITS) == 0)
- goto rbits;
- readbits(&dumpmap);
- while (xtrcnt > 0) {
-again:
- if (ishead(&spcl) == 0) {
- i = 0;
- while (gethead(&spcl) == 0)
- i++;
- fprintf(stderr, "resync restor, skipped %d blocks\n",
- i);
- }
- if (checktype(&spcl, TS_END) == 1) {
- fprintf(stderr, "end of tape\n");
- break;
- }
- if (checktype(&spcl, TS_INODE) == 0) {
- gethead(&spcl);
- goto again;
- }
- d = spcl.c_inumber;
- entry = unknown;
- entry->x_ino = d;
- for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
- if (d != xp->x_ino || (xp->x_flags & XLINKED))
- continue;
- entry = xp;
- xp->x_timep[0] = spcl.c_dinode.di_atime;
- xp->x_timep[1] = spcl.c_dinode.di_mtime;
- mode = spcl.c_dinode.di_mode;
- if (mflag)
- strcpy(name, xp->x_name);
- else
- sprintf(name, "%u", xp->x_ino);
- switch (mode & IFMT) {
- default:
- fprintf(stderr, "%s: unknown file mode 0%o\n",
- name, mode);
- xp->x_flags |= XTRACTD;
- xtrcnt--;
- goto skipfile;
- case IFCHR:
- case IFBLK:
- if (vflag)
- fprintf(stdout, "extract special file %s\n", name);
- if (mknod(name, mode, spcl.c_dinode.di_rdev)) {
- fprintf(stderr, "%s: cannot create special file\n", name);
- xp->x_flags |= XTRACTD;
- xtrcnt--;
- goto skipfile;
- }
- getfile(null, null, spcl.c_dinode.di_size);
- break;
- case IFDIR:
- if (mflag) {
- if (vflag)
- fprintf(stdout, "extract directory %s\n", name);
- strncat(name, "/.", BUFSIZ);
- checkdir(name);
- chown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
- getfile(null, null, spcl.c_dinode.di_size);
- break;
- }
- if (vflag)
- fprintf(stdout, "extract file %s\n", name);
- if ((ofile = creat(name, 0666)) < 0) {
- fprintf(stderr, "%s: cannot create file\n", name);
- xp->x_flags |= XTRACTD;
- xtrcnt--;
- goto skipfile;
- }
- chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
- if (cvtdir) {
- getfile(xtrcvtdir, xtrcvtskip,
- spcl.c_dinode.di_size);
- flushent(xtrfile);
- } else
- getfile(xtrfile, xtrskip,
- spcl.c_dinode.di_size);
- close(ofile);
- break;
- case IFLNK:
- if (vflag)
- fprintf(stdout, "extract symbolic link %s\n", name);
- uid = spcl.c_dinode.di_uid;
- gid = spcl.c_dinode.di_gid;
- lnkbuf[0] = '\0';
- pathlen = 0;
- getfile(xtrlnkfile, xtrlnkskip, spcl.c_dinode.di_size);
- if (symlink(lnkbuf, name) < 0) {
- fprintf(stderr, "%s: cannot create symbolic link\n", name);
- xp->x_flags |= XTRACTD;
- xtrcnt--;
- goto finished;
- }
- chown(name, uid, gid);
- break;
- case IFREG:
- if (vflag)
- fprintf(stdout, "extract file %s\n", name);
- if ((ofile = creat(name, 0666)) < 0) {
- fprintf(stderr, "%s: cannot create file\n", name);
- xp->x_flags |= XTRACTD;
- xtrcnt--;
- goto skipfile;
- }
- chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
- getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
- close(ofile);
- break;
- }
- chmod(name, mode);
- utime(name, xp->x_timep);
- xp->x_flags |= XTRACTD;
- xtrcnt--;
- goto finished;
- }
-skipfile:
- getfile(null, null, spcl.c_dinode.di_size);
-finished:
- ;
- }
- if (xtrcnt == 0 && !mflag)
- return;
- for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
- for (xp = *xpp; xp; xp = xp->x_next) {
- if (mflag && (xp->x_flags & XISDIR))
- utime(xp->x_name, xp->x_timep);
- if (xp->x_flags & XTRACTD)
- continue;
- if ((xp->x_flags & XLINKED) == 0) {
- fprintf(stderr, "cannot find file %s\n",
- xp->x_name);
- continue;
- }
- if (!mflag)
- continue;
- if (vflag)
- fprintf(stdout, "link %s to %s\n",
- xp->x_linkedto->x_name, xp->x_name);
- if (link(xp->x_linkedto->x_name, xp->x_name) < 0)
- fprintf(stderr, "link %s to %s failed\n",
- xp->x_linkedto->x_name, xp->x_name);
- }
- }
-}
-
-/*
- * Read the tape, bulding up a directory structure for extraction
- * by name
- */
-pass1(savedir)
- int savedir;
-{
- register int i;
- register struct dinode *ip;
- struct direct nulldir;
- char buf[TP_BSIZE];
- int putdir(), null(), dirwrite();
-
- nulldir.d_ino = 1;
- nulldir.d_namlen = 1;
- strncpy(nulldir.d_name, "/", nulldir.d_namlen);
- nulldir.d_reclen = DIRSIZ(&nulldir);
- while (gethead(&spcl) == 0) {
- fprintf(stderr, "Can't find directory header!\n");
- }
- for (;;) {
- if (checktype(&spcl, TS_BITS) == 1) {
- readbits(&dumpmap);
- continue;
- }
- if (checktype(&spcl, TS_CLRI) == 1) {
- readbits(&clrimap);
- continue;
- }
- if (checktype(&spcl, TS_INODE) == 0) {
-finish:
- if (savedir) {
- fclose(df);
- dirp = opendir(dirfile);
- if (dirp == NULL)
- perror("opendir");
- }
- resetmt();
- return;
- }
- ip = &spcl.c_dinode;
- i = ip->di_mode & IFMT;
- if (i != IFDIR) {
- goto finish;
- }
- if (spcl.c_inumber == ROOTINO) {
- readtape(buf);
- bct--; /* push back this block */
- if (((struct direct *)buf)->d_ino != ROOTINO) {
- if (((struct odirect *)buf)->d_ino != ROOTINO) {
- fprintf(stderr, "bad root directory\n");
- done(1);
- }
- fprintf(stderr, "converting to new directory format\n");
- cvtdir = 1;
- cvtflag = 1;
- }
- if (!savedir && !cvtdir) {
- /* if no conversion, just return */
- goto finish;
- }
- }
- allocinotab(spcl.c_inumber, seekpt);
- if (savedir) {
- getfile(putdir, null, spcl.c_dinode.di_size);
- putent(&nulldir, dirwrite);
- flushent(dirwrite);
+ switch (command) {
+ /*
+ * Interactive mode.
+ */
+ case 'i':
+ setup();
+ extractdirs(1);
+ initsymtable((char *)0);
+ runcmdshell();
+ done(0);
+ /*
+ * Incremental restoration of a file system.
+ */
+ case 'r':
+ setup();
+ if (dumptime > 0) {
+ /*
+ * This is an incremental dump tape.
+ */
+ vprintf(stdout, "Begin incremental restore\n");
+ initsymtable(symtbl);
+ extractdirs(1);
+ removeoldleaves();
+ vprintf(stdout, "Calculate node updates.\n");
+ treescan(".", ROOTINO, nodeupdates);
+ findunreflinks();
+ removeoldnodes();
} else {
- getfile(null, null, spcl.c_dinode.di_size);
+ /*
+ * This is a level zero dump tape.
+ */
+ vprintf(stdout, "Begin level 0 restore\n");
+ initsymtable((char *)0);
+ extractdirs(1);
+ vprintf(stdout, "Calculate extraction list.\n");
+ treescan(".", ROOTINO, nodeupdates);
}
- }
-}
-
-/*
- * Put the directory entries in the directory file
- */
-putdir(buf, size)
- char *buf;
- int size;
-{
- struct direct cvtbuf;
- register struct odirect *odp;
- struct odirect *eodp;
- register struct direct *dp;
- long loc, i;
-
- if (cvtdir) {
- eodp = (struct odirect *)&buf[size];
- for (odp = (struct odirect *)buf; odp < eodp; odp++)
- if (odp->d_ino != 0) {
- dcvt(odp, &cvtbuf);
- putent(&cvtbuf, dirwrite);
- }
- } else {
- for (loc = 0; loc < size; ) {
- dp = (struct direct *)(buf + loc);
- i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
- if (dp->d_reclen <= 0 || dp->d_reclen > i) {
- loc += i;
- continue;
- }
- loc += dp->d_reclen;
- if (dp->d_ino != 0) {
- putent(dp, dirwrite);
- }
+ createleaves(symtbl);
+ createlinks();
+ setdirmodes();
+ checkrestore();
+ if (dflag) {
+ vprintf(stdout, "Verify the directory structure\n");
+ treescan(".", ROOTINO, verifyfile);
}
- }
-}
-
-/*
- * Recursively find names and inumbers of all files in subtree
- * pname and put them in xtrlist[]
- */
-getleaves(ino, pname)
- ino_t ino;
- char *pname;
-{
- register struct inotab *itp;
- int namelen;
- daddr_t bpt;
- register struct direct *dp;
- char locname[BUFSIZ + 1];
-
- if (BIT(ino, dumpmap) == 0) {
- if (vflag)
- fprintf(stdout, "%s: not on the tape\n", pname);
- return;
- }
- for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
- if (itp->t_ino != ino)
- continue;
- /*
- * pname is a directory name
- */
- (void)allocxtr(ino, pname, XISDIR);
- /*
- * begin search through the directory
- * skipping over "." and ".."
- */
- strncpy(locname, pname, BUFSIZ);
- strncat(locname, "/", BUFSIZ);
- namelen = strlen(locname);
- seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
- dp = readdir(dirp);
- dp = readdir(dirp);
- dp = readdir(dirp);
- bpt = telldir(dirp);
- /*
- * "/" signals end of directory
- */
- while (dp->d_namlen != 1 || dp->d_name[0] != '/') {
- locname[namelen] = '\0';
- if (namelen + dp->d_namlen >= BUFSIZ) {
- fprintf(stderr, "%s%s: name exceedes %d char\n",
- locname, dp->d_name, BUFSIZ);
- continue;
- }
- strncat(locname, dp->d_name, dp->d_namlen);
- getleaves(dp->d_ino, locname);
- seekdir(dirp, bpt, itp->t_seekpt);
- dp = readdir(dirp);
- bpt = telldir(dirp);
- }
- return;
- }
+ dumpsymtable(symtbl, (long)1);
+ done(0);
/*
- * locname is name of a simple file
+ * Resume an incremental file system restoration.
*/
- (void)allocxtr(ino, pname, XINUSE);
-}
-
-/*
- * Search the directory tree rooted at inode ROOTINO
- * for the path pointed at by n
- */
-psearch(n)
- char *n;
-{
- register char *cp, *cp1;
- char c;
-
- ino = ROOTINO;
- if (*(cp = n) == '/')
- cp++;
-next:
- cp1 = cp + 1;
- while (*cp1 != '/' && *cp1)
- cp1++;
- c = *cp1;
- *cp1 = 0;
- ino = search(ino, cp);
- if (ino == 0) {
- *cp1 = c;
- return(0);
- }
- *cp1 = c;
- if (c == '/') {
- cp = cp1+1;
- goto next;
- }
- return(ino);
-}
-
-/*
- * search the directory inode ino
- * looking for entry cp
- */
-ino_t
-search(inum, cp)
- ino_t inum;
- char *cp;
-{
- register struct direct *dp;
- register struct inotab *itp;
- int len;
-
- for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
- if (itp->t_ino == inum)
- goto found;
- return(0);
-found:
- seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
- len = strlen(cp);
- do {
- dp = readdir(dirp);
- if (dp->d_namlen == 1 && dp->d_name[0] == '/')
- return(0);
- } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
- return(dp->d_ino);
-}
-
-/*
- * Do the file extraction, calling the supplied functions
- * with the blocks
- */
-getfile(f1, f2, size)
- int (*f2)(), (*f1)();
- off_t size;
-{
- register int i;
- char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
- union u_spcl addrblk;
-# define addrblock addrblk.s_spcl
-
- addrblock = spcl;
- for (;;) {
- for (i = 0; i < addrblock.c_count; i++) {
- if (addrblock.c_addr[i]) {
- readtape(&buf[curblk++][0]);
- if (curblk == fssize / TP_BSIZE) {
- (*f1)(buf, size > TP_BSIZE ?
- (long) (fssize) :
- (curblk - 1) * TP_BSIZE + size);
- curblk = 0;
- }
- } else {
- if (curblk > 0) {
- (*f1)(buf, size > TP_BSIZE ?
- (long) (curblk * TP_BSIZE) :
- (curblk - 1) * TP_BSIZE + size);
- curblk = 0;
- }
- (*f2)(clearedbuf, size > TP_BSIZE ?
- (long) TP_BSIZE : size);
- }
- if ((size -= TP_BSIZE) <= 0) {
- gethead(&spcl);
- goto out;
- }
- }
- if (gethead(&addrblock) == 0) {
- fprintf(stderr, "Missing address (header) block for %s\n",
- entry->x_name);
- spcl.c_magic = 0;
- goto out;
- }
- if (checktype(&addrblock, TS_ADDR) == 0) {
- spcl = addrblock;
- goto out;
- }
- }
-out:
- if (curblk > 0) {
- (*f1)(buf, (curblk * TP_BSIZE) + size);
- curblk = 0;
- }
-}
-
-/*
- * The next routines are called during file extraction to
- * put the data into the right form and place.
- */
-xtrfile(buf, size)
- char *buf;
- long size;
-{
-
- if (write(ofile, buf, (int) size) == -1) {
- perror("extract write");
- done(1);
- }
-}
-
-xtrskip(buf, size)
- char *buf;
- long size;
-{
-
-#ifdef lint
- buf = buf;
-#endif
- if (lseek(ofile, size, 1) == -1) {
- perror("extract seek");
- done(1);
- }
-}
-
-xtrcvtdir(buf, size)
- struct odirect *buf;
- long size;
-{
- struct odirect *odp, *edp;
- struct direct cvtbuf;
-
- edp = &buf[size / sizeof(struct odirect)];
- for (odp = buf; odp < edp; odp++) {
- dcvt(odp, &cvtbuf);
- putent(&cvtbuf, xtrfile);
- }
-}
-
-xtrcvtskip(buf, size)
- char *buf;
- long size;
-{
-
- fprintf(stderr, "unallocated block in directory %s\n",
- entry->x_name);
- xtrskip(buf, size);
-}
-
-xtrlnkfile(buf, size)
- char *buf;
- long size;
-{
-
- pathlen += size;
- if (pathlen > MAXPATHLEN) {
- fprintf(stderr, "symbolic link name: %s; too long %d\n",
- buf, size);
- done(1);
- }
- strcat(lnkbuf, buf);
-}
-
-xtrlnkskip(buf, size)
- char *buf;
- long size;
-{
-
-#ifdef lint
- buf = buf, size = size;
-#endif
- fprintf(stderr, "unallocated block in symbolic link %s\n",
- entry->x_name);
- done(1);
-}
-
-null() {;}
-
-/*
- * Do the tape i/o, dealing with volume changes
- * etc..
- */
-readtape(b)
- char *b;
-{
- register long i;
- struct u_spcl tmpbuf;
- char c;
-
- if (bct >= NTREC) {
- for (i = 0; i < NTREC; i++)
- ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
- bct = 0;
-#ifdef RRESTOR
- if ((i = rmtread(tbf, NTREC*TP_BSIZE)) < 0) {
-#else
- if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
-#endif
- fprintf(stderr, "Tape read error while restoring %s\n",
- entry->x_name);
- if (!yflag) {
- fprintf(stderr, "continue? ");
- do {
- fprintf(stderr, "[yn] ");
- c = getchar();
- while (getchar() != '\n')
- /* void */;
- } while (c != 'y' && c != 'n');
- if (c == 'n')
- done(1);
- }
- eflag++;
- i = NTREC*TP_BSIZE;
- blkclr(tbf, i);
-#ifdef RRESTOR
- if (rmtseek(i, 1) < 0) {
-#else
- if (lseek(mt, i, 1) < 0) {
-#endif
- fprintf(stderr, "continuation failed\n");
- done(1);
- }
- }
- if (i == 0) {
- bct = NTREC + 1;
- volno++;
-loop:
- flsht();
-#ifdef RRESTOR
- rmtclose();
-#else
- close(mt);
-#endif
- fprintf(stderr, "Mount volume %d\n", volno);
- while (getchar() != '\n')
- ;
-#ifdef RRESTOR
- if ((mt = rmtopen(magtape, 0)) == -1) {
-#else
- if ((mt = open(magtape, 0)) == -1) {
-#endif
- fprintf(stderr, "Cannot open tape!\n");
- goto loop;
- }
- if (readhdr(&tmpbuf) == 0) {
- fprintf(stderr, "Not a dump tape.Try again\n");
- goto loop;
- }
- if (checkvol(&tmpbuf, volno) == 0) {
- fprintf(stderr, "Wrong tape. Try again\n");
- goto loop;
- }
- readtape(b);
- return;
- }
- }
- blkcpy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
-}
-
-flsht()
-{
-
- bct = NTREC+1;
-}
-
-blkcpy(from, to, size)
- char *from, *to;
- long size;
-{
-
-#ifdef lint
- from = from, to = to, size = size;
-#endif
- asm(" movc3 12(ap),*4(ap),*8(ap)");
-}
-
-blkclr(buf, size)
- char *buf;
- long size;
-{
-
-#ifdef lint
- buf = buf, size = size;
-#endif
- asm("movc5 $0,(r0),$0,8(ap),*4(ap)");
-}
-
-resetmt()
-{
- struct mtop tcom;
-
- if (dumpnum > 1)
- tcom.mt_op = MTBSF;
- else
- tcom.mt_op = MTREW;
- tcom.mt_count = 1;
- flsht();
-#ifdef RRESTOR
- if (rmtioctl(tcom.mt_op, 1) == -1) {
- /* kludge for disk dumps */
- rmtseek((long)0, 0);
- }
-#else
- if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
- /* kludge for disk dumps */
- lseek(mt, (long)0, 0);
- }
-#endif
- if (dumpnum > 1) {
-#ifdef RRESTOR
- rmtioctl(MTFSF, 1);
-#else
- tcom.mt_op = MTFSF;
- tcom.mt_count = 1;
- ioctl(mt,MTIOCTOP,&tcom);
-#endif
- }
-}
-
-checkvol(b, t)
- struct s_spcl *b;
- int t;
-{
-
- if (b->c_volume == t)
- return(1);
- return(0);
-}
-
-readhdr(b)
- struct s_spcl *b;
-{
-
- if (gethead(b) == 0)
- return(0);
- if (checktype(b, TS_TAPE) == 0)
- return(0);
- return(1);
-}
-
-/*
- * read the tape into buf, then return whether or
- * or not it is a header block.
- */
-gethead(buf)
- struct s_spcl *buf;
-{
- union u_ospcl {
- char dummy[TP_BSIZE];
- struct s_ospcl {
- int c_type;
- time_t c_date;
- time_t c_ddate;
- int c_volume;
- daddr_t c_tapea;
- ino_t c_inumber;
- int c_magic;
- int c_checksum;
- struct odinode {
- unsigned short odi_mode;
- short odi_nlink;
- short odi_uid;
- short odi_gid;
- off_t odi_size;
- daddr_t odi_rdev;
- char odi_addr[36];
- time_t odi_atime;
- time_t odi_mtime;
- time_t odi_ctime;
- } c_dinode;
- int c_count;
- char c_addr[TP_NINDIR];
- } s_ospcl;
- } u_ospcl;
-
- if (!cvtflag) {
- readtape((char *)buf);
- if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == 0)
- return(0);
- return(1);
- }
- readtape((char *)(&u_ospcl.s_ospcl));
- blkclr((char *)buf, TP_BSIZE);
- buf->c_type = u_ospcl.s_ospcl.c_type;
- buf->c_date = u_ospcl.s_ospcl.c_date;
- buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
- buf->c_volume = u_ospcl.s_ospcl.c_volume;
- buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
- buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
- buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
- buf->c_magic = u_ospcl.s_ospcl.c_magic;
- buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
- buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
- buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
- buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
- buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
- buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
- buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
- buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
- buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
- buf->c_count = u_ospcl.s_ospcl.c_count;
- blkcpy(u_ospcl.s_ospcl.c_addr, buf->c_addr, TP_NINDIR);
- if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
- checksum((int *)(&u_ospcl.s_ospcl)) == 0)
- return(0);
- buf->c_magic = NFS_MAGIC;
- return(1);
-}
-
-/*
- * return whether or not the buffer contains a header block
- */
-ishead(buf)
- struct s_spcl *buf;
-{
-
- if (buf->c_magic != NFS_MAGIC)
- return(0);
- return(1);
-}
-
-checktype(b, t)
- struct s_spcl *b;
- int t;
-{
-
- return(b->c_type == t);
-}
-
-/*
- * read a bit mask from the tape into m.
- */
-readbits(mapp)
- char **mapp;
-{
- register int i;
- char *m;
-
- i = spcl.c_count;
-
- if (*mapp == 0)
- *mapp = (char *)calloc(i, (TP_BSIZE/(NBBY/BITS)));
- m = *mapp;
- while (i--) {
- readtape((char *) m);
- m += (TP_BSIZE/(NBBY/BITS));
- }
- while (gethead(&spcl) == 0)
- ;
-}
-
-checksum(b)
- register int *b;
-{
- register int i, j;
-
- j = sizeof(union u_spcl) / sizeof(int);
- i = 0;
- do
- i += *b++;
- while (--j);
- if (i != CHECKSUM) {
- fprintf(stderr, "Checksum error %o, file %s\n", i,
- entry->x_name);
- return(0);
- }
- return(1);
-}
-
-/*
- * Check for access into each directory in the pathname of an extracted
- * file and create such a directory if needed in preparation for moving
- * the file to its proper home.
- */
-checkdir(name)
- register char *name;
-{
- register char *cp;
- int i;
-
- for (cp = name; *cp; cp++) {
- if (*cp == '/') {
- *cp = '\0';
- if (access(name, 01) < 0) {
- register int pid, rp;
-
- if ((pid = vfork()) == 0) {
- execl("/bin/mkdir", "mkdir", name, 0);
- execl("/usr/bin/mkdir", "mkdir", name, 0);
- fprintf(stderr, "restor: cannot find mkdir!\n");
- done(0);
- }
- while ((rp = wait(&i)) >= 0 && rp != pid)
- ;
- }
- *cp = '/';
- }
- }
-}
-
-setdir(dev)
- char *dev;
-{
- struct fstab *fsp;
-
- if (setfsent() == 0) {
- fprintf(stderr, "Can't open checklist file: %s\n", FSTAB);
- done(1);
- }
- while ((fsp = getfsent()) != 0) {
- if (strcmp(fsp->fs_spec, dev) == 0) {
- fprintf(stderr, "%s mounted on %s\n", dev, fsp->fs_file);
- if (chdir(fsp->fs_file) >= 0)
- return;
- fprintf(stderr, "%s cannot chdir to %s\n",
- fsp->fs_file);
- done(1);
- }
- }
- fprintf(stderr, "%s not mounted\n", dev);
- done(1);
-}
-
-/*
- * These variables are "local" to the following two functions.
- */
-char dirbuf[DIRBLKSIZ];
-long dirloc = 0;
-long prev = 0;
-
-/*
- * add a new directory entry to a file.
- */
-putent(dp, wrtfunc)
- struct direct *dp;
- int (*wrtfunc)();
-{
-
- if (dp->d_ino == 0)
- return;
- if (dirloc + dp->d_reclen > DIRBLKSIZ) {
- ((struct direct *)(dirbuf + prev))->d_reclen =
- DIRBLKSIZ - prev;
- (*wrtfunc)(dirbuf, DIRBLKSIZ);
- dirloc = 0;
- }
- blkcpy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
- prev = dirloc;
- dirloc += dp->d_reclen;
-}
-
-/*
- * flush out a directory that is finished.
- */
-flushent(wrtfunc)
- int (*wrtfunc)();
-{
-
- ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
- (*wrtfunc)(dirbuf, dirloc);
- dirloc = 0;
-}
-
-dirwrite(buf, size)
- char *buf;
- int size;
-{
-
- fwrite(buf, 1, size, df);
- seekpt = ftell(df);
-}
-
-dcvt(odp, ndp)
- register struct odirect *odp;
- register struct direct *ndp;
-{
-
- blkclr((char *)ndp, (long)(sizeof *ndp));
- ndp->d_ino = odp->d_ino;
- strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
- ndp->d_namlen = strlen(ndp->d_name);
- ndp->d_reclen = DIRSIZ(ndp);
+ case 'R':
+ initsymtable(symtbl);
+ skipmaps();
+ skipdirs();
+ createleaves(symtbl);
+ createlinks();
+ setdirmodes();
+ checkrestore();
+ dumpsymtable(symtbl, (long)1);
+ done(0);
/*
- * this quickly calculates if this inode is a directory.
- * Currently not maintained.
- *
- for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
- if (itp->t_ino != odp->d_ino)
- continue;
- ndp->d_fmt = IFDIR;
- break;
- }
+ * List contents of tape.
*/
-}
-
-/*
- * Open a directory.
- * Modified to allow any random file to be a legal directory.
- */
-DIR *
-opendir(name)
- char *name;
-{
- register DIR *dirp;
-
- dirp = (DIR *)malloc(sizeof(DIR));
- dirp->dd_fd = open(name, 0);
- if (dirp->dd_fd == -1) {
- free((char *)dirp);
- return NULL;
- }
- dirp->dd_loc = 0;
- return dirp;
-}
-
-/*
- * Seek to an entry in a directory.
- * Only values returned by ``telldir'' should be passed to seekdir.
- * Modified to have many directories based in one file.
- */
-void
-seekdir(dirp, loc, base)
- register DIR *dirp;
- daddr_t loc, base;
-{
-
- if (loc == telldir(dirp))
- return;
- loc -= base;
- if (loc < 0)
- fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
- (void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
- dirp->dd_loc = loc & (DIRBLKSIZ - 1);
- if (dirp->dd_loc != 0)
- dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
-}
-
-/*
- * get next entry in a directory.
- */
-struct direct *
-readdir(dirp)
- register DIR *dirp;
-{
- register struct direct *dp;
-
- for (;;) {
- if (dirp->dd_loc == 0) {
- dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
- DIRBLKSIZ);
- if (dirp->dd_size <= 0)
- return NULL;
+ case 't':
+ setup();
+ extractdirs(0);
+ initsymtable((char *)0);
+ while (argc--) {
+ canon(*argv++, name);
+ ino = dirlookup(name);
+ if (ino == 0)
+ continue;
+ treescan(name, ino, listfile);
}
- if (dirp->dd_loc >= dirp->dd_size) {
- dirp->dd_loc = 0;
- continue;
+ done(0);
+ /*
+ * Batch extraction of tape contents.
+ */
+ case 'x':
+ setup();
+ extractdirs(1);
+ initsymtable((char *)0);
+ while (argc--) {
+ canon(*argv++, name);
+ ino = dirlookup(name);
+ if (ino == 0)
+ continue;
+ if (mflag)
+ pathcheck(name);
+ treescan(name, ino, addfile);
}
- dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
- if (dp->d_reclen <= 0 ||
- dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc)
- return NULL;
- dirp->dd_loc += dp->d_reclen;
- if (dp->d_ino == 0)
- continue;
- return (dp);
+ createfiles();
+ createlinks();
+ setdirmodes();
+ if (dflag)
+ checkrestore();
+ done(0);
}
}
-
-allocinotab(ino, seekpt)
- ino_t ino;
- daddr_t seekpt;
-{
- register struct inotab *itp;
-
- itp = (struct inotab *)calloc(1, sizeof(struct inotab));
- itp->t_next = inotab[INOHASH(ino)];
- inotab[INOHASH(ino)] = itp;
- itp->t_ino = ino;
- itp->t_seekpt = seekpt;
-}
-
-struct xtrlist *
-allocxtr(ino, name, flags)
- ino_t ino;
- char *name;
- char flags;
-{
- register struct xtrlist *xp, *pxp;
- int size;
-
- size = sizeof(struct xtrlist) + strlen(name);
- xp = (struct xtrlist *)calloc(1, size);
- xp->x_ino = ino;
- xp->x_flags = flags;
- strcpy(xp->x_name, name);
- if (flags == 0)
- return (xp);
- xp->x_next = xtrlist[INOHASH(ino)];
- xtrlist[INOHASH(ino)] = xp;
- xtrcnt++;
- for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
- if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
- xp->x_flags |= XLINKED;
- xp->x_linkedto = pxp;
- xtrcnt--;
- break;
- }
- if (!vflag)
- return (xp);
- if (xp->x_flags & XLINKED)
- fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
- else if (xp->x_flags & XISDIR)
- fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
- else
- fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
- return (xp);
-}
-
-#ifdef RRESTOR
-msg(cp, a1, a2, a3)
- char *cp;
-{
-
- fprintf(stderr, cp, a1, a2, a3);
-}
-#endif RRESTOR
-
-done(exitcode)
- int exitcode;
-{
-
- unlink(dirfile);
- exit(exitcode);
-}