xref: /csrg-svn/sbin/restore/main.c (revision 8302)
16847Smckusick /* Copyright (c) 1982 Regents of the University of California */
24610Smckusick 
36846Smckusick #ifndef lint
4*8302Smckusick char version[] = "@(#)main.c 2.8 10/04/82";
56846Smckusick #endif
64610Smckusick 
74610Smckusick /*	Modified to include h option (recursively extract all files within
84610Smckusick  *	a subtree) and m option (recreate the heirarchical structure of
94610Smckusick  *	that subtree and move extracted files to their proper homes).
104610Smckusick  *	8/29/80		by Mike Litzkow
114610Smckusick  *
126846Smckusick  *	Modified to work on the new file system
136846Smckusick  *	1/19/82		by Kirk McKusick
146846Smckusick  *
154610Smckusick  *	Includes the s (skip files) option for use with multiple dumps on
164610Smckusick  *	a single tape.
174610Smckusick  */
184610Smckusick 
194610Smckusick #define MAXINO	3000
204610Smckusick #define BITS	8
214610Smckusick #define NCACHE	3
224610Smckusick #define SIZEINC 10
234610Smckusick 
244610Smckusick #include <stdio.h>
254610Smckusick #include <signal.h>
266844Smckusick #include <fstab.h>
276847Smckusick #ifndef SIMFS
286847Smckusick #include <sys/param.h>
296847Smckusick #include <sys/inode.h>
306847Smckusick #include <sys/fs.h>
316847Smckusick #include <dir.h>
326847Smckusick #include <stat.h>
336847Smckusick #include <dumprestor.h>
346847Smckusick #else
356844Smckusick #include "../h/param.h"
366844Smckusick #include "../h/dir.h"
376844Smckusick #include "../h/stat.h"
386844Smckusick #include "../h/inode.h"
396844Smckusick #include "../h/fs.h"
406844Smckusick #include "../h/dumprestor.h"
416847Smckusick #endif
428296Smckusick #include <sys/ioctl.h>
435038Smckusic #include <sys/mtio.h>
444610Smckusick 
455943Smckusic #define ODIRSIZ 14
465038Smckusic struct odirect {
475038Smckusic 	u_short	d_ino;
485943Smckusic 	char	d_name[ODIRSIZ];
495038Smckusic };
505038Smckusic 
515327Smckusic #define	MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
525327Smckusic #define	MBIT(i)	(1<<((unsigned)(i-1)%NBBY))
534610Smckusick #define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
544610Smckusick #define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
554610Smckusick #define	BIT(i,w)	(MWORD(w,i) & MBIT(i))
564610Smckusick 
576846Smckusick ino_t	ino;
584610Smckusick 
59*8302Smckusick int	eflag = 0, hflag = 0, mflag = 0, cvtflag = 0, cvtdir = 0;
604776Smckusic 
616844Smckusick long	fssize;
624610Smckusick char	tapename[] = "/dev/rmt8";
634610Smckusick char	*magtape = tapename;
645038Smckusic int	mt;
655038Smckusic int	dumpnum = 1;
665038Smckusic int	volno = 1;
675038Smckusic int	curblk = 0;
685038Smckusic int	bct = NTREC+1;
695038Smckusic char	tbf[NTREC*TP_BSIZE];
704610Smckusick 
714610Smckusick daddr_t	seekpt;
724837Smckusic FILE	*df;
735943Smckusic DIR	*dirp;
744837Smckusic int	ofile;
756847Smckusick char	dirfile[] = "/tmp/rstXXXXXX";
766289Smckusick char	lnkbuf[MAXPATHLEN + 1];
776289Smckusick int	pathlen;
784610Smckusick 
794837Smckusic #define INOHASH(val) (val % MAXINO)
804837Smckusic struct inotab {
814837Smckusic 	struct inotab *t_next;
824610Smckusick 	ino_t	t_ino;
834610Smckusick 	daddr_t	t_seekpt;
844837Smckusic } *inotab[MAXINO];
854610Smckusick 
864837Smckusic #define XISDIR	1
874610Smckusick #define XTRACTD	2
884610Smckusick #define XINUSE	4
894837Smckusic #define XLINKED	8
904610Smckusick struct xtrlist {
914837Smckusic 	struct xtrlist	*x_next;
924837Smckusic 	struct xtrlist	*x_linkedto;
934843Smckusic 	time_t		x_timep[2];
944837Smckusic 	ino_t		x_ino;
954837Smckusic 	char		x_flags;
964843Smckusic 	char 		x_name[1];
974843Smckusic 	/* actually longer */
984837Smckusic } *xtrlist[MAXINO];
994776Smckusic int xtrcnt = 0;
1004610Smckusick 
1015327Smckusic char	*dumpmap;
1025327Smckusic char	*clrimap;
1034610Smckusick 
1045327Smckusic char	clearedbuf[MAXBSIZE];
1055327Smckusic 
1064837Smckusic extern char *ctime();
1076846Smckusick extern int seek();
1084843Smckusic ino_t search();
1095943Smckusic int dirwrite();
1106849Smckusick #ifdef RRESTOR
1116849Smckusick char *host;
1126849Smckusick #endif
1134610Smckusick 
1146846Smckusick main(argc, argv)
1154700Smckusic 	int argc;
1164700Smckusic 	char *argv[];
1174610Smckusick {
1184610Smckusick 	register char *cp;
1194610Smckusick 	char command;
1204700Smckusic 	int (*signal())();
1214610Smckusick 	int done();
1224610Smckusick 
1234843Smckusic 	if (signal(SIGINT, done) == SIG_IGN)
1244843Smckusic 		signal(SIGINT, SIG_IGN);
1254843Smckusic 	if (signal(SIGTERM, done) == SIG_IGN)
1264843Smckusic 		signal(SIGTERM, SIG_IGN);
1276844Smckusick 	mktemp(dirfile);
1284610Smckusick 	if (argc < 2) {
1294610Smckusick usage:
1304837Smckusic 		fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
1314700Smckusic 		done(1);
1324610Smckusick 	}
1334610Smckusick 	argv++;
1344610Smckusick 	argc -= 2;
1354610Smckusick 	for (cp = *argv++; *cp; cp++) {
1364610Smckusick 		switch (*cp) {
1374610Smckusick 		case '-':
1384610Smckusick 			break;
139*8302Smckusick 		case 'c':
140*8302Smckusick 			cvtflag++;
141*8302Smckusick 			break;
1424610Smckusick 		case 'f':
1434610Smckusick 			magtape = *argv++;
1446849Smckusick #ifdef RRESTOR
1456849Smckusick 		{ char *index();
1466849Smckusick 		  host = magtape;
1476849Smckusick 		  magtape = index(host, ':');
1486849Smckusick 		  if (magtape == 0) {
1496849Smckusick nohost:
1506849Smckusick 			msg("need keyletter ``f'' and device ``host:tape''");
1516849Smckusick 			done(1);
1526849Smckusick 		  }
1536849Smckusick 		  *magtape++ = 0;
1546849Smckusick 		  if (rmthost(host) == 0)
1556849Smckusick 			done(1);
1566849Smckusick 		}
1576849Smckusick #endif
1584610Smckusick 			argc--;
1594610Smckusick 			break;
1604610Smckusick 		/* s dumpnum (skip to) for multifile dump tapes */
1614610Smckusick 		case 's':
1624610Smckusick 			dumpnum = atoi(*argv++);
1636847Smckusick 			if (dumpnum <= 0) {
1644700Smckusic 				fprintf(stderr, "Dump number must be a positive integer\n");
1654700Smckusic 				done(1);
1664610Smckusick 			}
1674610Smckusick 			argc--;
1684610Smckusick 			break;
1694610Smckusick 		case 'h':
1704610Smckusick 			hflag++;
1714610Smckusick 			break;
1724610Smckusick 		case 'm':
1734610Smckusick 			mflag++;
1744610Smckusick 			break;
1754610Smckusick 		case 'r':
1764610Smckusick 		case 'R':
1776844Smckusick 			hflag++;
1786844Smckusick 			mflag++;
1794610Smckusick 		case 't':
1804610Smckusick 		case 'x':
1814610Smckusick 			command = *cp;
1824610Smckusick 			break;
1834610Smckusick 		default:
1844700Smckusic 			fprintf(stderr, "Bad key character %c\n", *cp);
1854610Smckusick 			goto usage;
1864610Smckusick 		}
1874610Smckusick 	}
1886849Smckusick #ifdef RRESTOR
1896849Smckusick 	if (host == 0)
1906849Smckusick 		goto nohost;
1916849Smckusick #endif
1924610Smckusick 	doit(command, argc, argv);
1934700Smckusic 	done(0);
1944610Smckusick }
1954610Smckusick 
1964610Smckusick doit(command, argc, argv)
1974700Smckusic 	char	command;
1984700Smckusic 	int	argc;
1994700Smckusic 	char	*argv[];
2004610Smckusick {
2015038Smckusic 	struct mtop tcom;
2025038Smckusic 
2036849Smckusick #ifdef RRESTOR
2046849Smckusick 	if ((mt = rmtopen(magtape, 0)) < 0) {
2056849Smckusick #else
2064610Smckusick 	if ((mt = open(magtape, 0)) < 0) {
2076849Smckusick #endif
2084700Smckusic 		fprintf(stderr, "%s: cannot open tape\n", magtape);
2094700Smckusic 		done(1);
2104610Smckusick 	}
2114843Smckusic 	if (dumpnum != 1) {
2124610Smckusick 		tcom.mt_op = MTFSF;
2134610Smckusick 		tcom.mt_count = dumpnum -1;
2146849Smckusick #ifdef RRESTOR
2156849Smckusick 		rmtioctl(MTFSF,dumpnum - 1);
2166849Smckusick #else
2174843Smckusic 		if (ioctl(mt,MTIOCTOP,&tcom) < 0)
2184610Smckusick 			perror("ioctl MTFSF");
2196849Smckusick #endif
2204610Smckusick 	}
2216846Smckusick 	blkclr(clearedbuf, (long)MAXBSIZE);
2224610Smckusick 	switch(command) {
2234610Smckusick 	case 't':
2244610Smckusick 		if (readhdr(&spcl) == 0) {
2254700Smckusic 			fprintf(stderr, "Tape is not a dump tape\n");
2264700Smckusic 			done(1);
2274610Smckusick 		}
2284843Smckusic 		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
2294843Smckusic 		fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
2304610Smckusick 		return;
2316844Smckusick 	case 'R':
2326844Smckusick 	case 'r':
2336844Smckusick 		setdir(*argv);
2346844Smckusick 		argc = 1;
2356844Smckusick 		*argv = ".";
2366844Smckusick 		/* and then extract it all */
2374610Smckusick 	case 'x':
2386844Smckusick 		df = fopen(dirfile, "w");
2396844Smckusick 		if (df == 0) {
2406844Smckusick 			fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
2416844Smckusick 			done(1);
2426844Smckusick 		}
2434837Smckusic 		extractfiles(argc, argv);
2444837Smckusic 		return;
2454837Smckusic 	}
2464837Smckusic }
2474837Smckusic 
2484837Smckusic extractfiles(argc, argv)
2494837Smckusic 	int argc;
2504837Smckusic 	char **argv;
2514837Smckusic {
2524843Smckusic 	char	*ststore();
2534837Smckusic 	register struct xtrlist *xp;
2544837Smckusic 	struct xtrlist **xpp;
2554837Smckusic 	ino_t	d;
2566289Smckusick 	int	xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(),
2576289Smckusick 		xtrlnkfile(), xtrlnkskip(), null();
2586845Smckusick 	int	mode, uid, gid, i;
2594843Smckusic 	char	name[BUFSIZ + 1];
2606844Smckusick 	struct	stat stbuf;
2614837Smckusic 
2626844Smckusick 	if (stat(".", &stbuf) < 0) {
2636844Smckusick 		fprintf(stderr, "cannot stat .\n");
2646844Smckusick 		done(1);
2656844Smckusick 	}
2666844Smckusick 	/*
2676844Smckusick 	 * should be!!!
2686844Smckusick 	 *
2696844Smckusick 	fssize = stbuf.st_blksize;
2706844Smckusick 	 */
2716844Smckusick 	fssize = MAXBSIZE;
2724837Smckusic 	if (readhdr(&spcl) == 0) {
2734837Smckusic 		fprintf(stderr, "Tape is not a dump tape\n");
2744837Smckusic 		done(1);
2754837Smckusic 	}
2764837Smckusic 	if (checkvol(&spcl, 1) == 0) {
2774837Smckusic 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
2784837Smckusic 	}
2796844Smckusick 	clrimap = 0;
2806844Smckusick 	dumpmap = 0;
2815038Smckusic 	pass1(1);  /* This sets the various maps on the way by */
2824843Smckusic 	while (argc--) {
2834837Smckusic 		if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
2846844Smckusick 			printf("d = %d\n", d);
2854843Smckusic 			fprintf(stdout, "%s: not on tape\n", *argv++);
2864837Smckusic 			continue;
2874610Smckusick 		}
2884843Smckusic 		if (mflag)
2894843Smckusic 			checkdir(*argv);
2906847Smckusick 		if (hflag)
2914837Smckusic 			getleaves(d, *argv++);
2924843Smckusic 		else
2934843Smckusic 			allocxtr(d, *argv++, XINUSE);
2944837Smckusic 	}
2954843Smckusic 	if (dumpnum > 1) {
2965038Smckusic 		/*
2975038Smckusic 		 * if this is a multi-dump tape we always start with
2985038Smckusic 		 * volume 1, so as to avoid accidentally restoring
2995038Smckusic 		 * from a different dump!
3005038Smckusic 		 */
3015038Smckusic 		resetmt();
3025038Smckusic 		dumpnum = 1;
3035038Smckusic 		volno = 1;
3045038Smckusic 		readhdr(&spcl);
3055038Smckusic 		goto rbits;
3064837Smckusic 	}
3075038Smckusic newvol:
3086849Smckusick #ifdef RRESTOR
3096849Smckusick 	rmtclose();
3106849Smckusick #else
3116847Smckusick 	close(mt);
3126849Smckusick #endif
3134610Smckusick getvol:
3145038Smckusic 	fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
3154837Smckusic 	if (gets(tbf) == NULL)
3164837Smckusic 		return;
3174837Smckusic 	volno = atoi(tbf);
3184837Smckusic 	if (volno <= 0) {
3194837Smckusic 		fprintf(stderr, "Volume numbers are positive numerics\n");
3204837Smckusic 		goto getvol;
3214837Smckusic 	}
3226849Smckusick #ifdef RRESTOR
3236849Smckusick 	if ((mt = rmtopen(magtape, 0)) == -1) {
3246849Smckusick #else
3256847Smckusick 	if ((mt = open(magtape, 0)) == -1) {
3266849Smckusick #endif
3276847Smckusick 		fprintf(stderr, "Cannot open tape!\n");
3286847Smckusick 		goto getvol;
3296847Smckusick 	}
3306847Smckusick 	if (dumpnum > 1)
3316847Smckusick 		resetmt();
3324837Smckusic 	if (readhdr(&spcl) == 0) {
3334837Smckusic 		fprintf(stderr, "tape is not dump tape\n");
3344837Smckusic 		goto newvol;
3354837Smckusic 	}
3364837Smckusic 	if (checkvol(&spcl, volno) == 0) {
3374837Smckusic 		fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
3384837Smckusic 		goto newvol;
3394837Smckusic 	}
3404610Smckusick rbits:
3414837Smckusic 	while (gethead(&spcl) == 0)
3424837Smckusic 		;
3434837Smckusic 	if (checktype(&spcl, TS_INODE) == 1) {
3444837Smckusic 		fprintf(stderr, "Can't find inode mask!\n");
3454837Smckusic 		goto newvol;
3464837Smckusic 	}
3474837Smckusic 	if (checktype(&spcl, TS_BITS) == 0)
3484837Smckusic 		goto rbits;
3496844Smckusick 	readbits(&dumpmap);
3504837Smckusic 	while (xtrcnt > 0) {
3514837Smckusic again:
3526845Smckusick 		if (ishead(&spcl) == 0) {
3536845Smckusick 			i = 0;
3546847Smckusick 			while (gethead(&spcl) == 0)
3556845Smckusick 				i++;
3566845Smckusick 			fprintf(stderr, "resync restor, skipped %i blocks\n",
3576845Smckusick 			    i);
3586845Smckusick 		}
3594837Smckusic 		if (checktype(&spcl, TS_END) == 1) {
3604837Smckusic 			fprintf(stderr, "end of tape\n");
3614837Smckusic 			break;
3624610Smckusick 		}
3634837Smckusic 		if (checktype(&spcl, TS_INODE) == 0) {
3644837Smckusic 			gethead(&spcl);
3654837Smckusic 			goto again;
3664610Smckusick 		}
3674837Smckusic 		d = spcl.c_inumber;
3684837Smckusic 		for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
3694837Smckusic 			if (d != xp->x_ino)
3704837Smckusic 				continue;
3714837Smckusic 			if (xp->x_flags & XLINKED)
3724837Smckusic 				continue;
3734837Smckusic 			xp->x_timep[0] = spcl.c_dinode.di_atime;
3744837Smckusic 			xp->x_timep[1] = spcl.c_dinode.di_mtime;
3754837Smckusic 			mode = spcl.c_dinode.di_mode;
3764837Smckusic 			if (mflag)
3774843Smckusic 				strcpy(name, xp->x_name);
3784837Smckusic 			else
3794837Smckusic 				sprintf(name, "%u", xp->x_ino);
3804837Smckusic 			switch (mode & IFMT) {
3814837Smckusic 			default:
3826847Smckusick 				fprintf(stderr, "%s: unknown file mode 0%o\n",
3836847Smckusick 				    name, mode);
3844837Smckusic 				xp->x_flags |= XTRACTD;
3854837Smckusic 				xtrcnt--;
3864837Smckusic 				goto skipfile;
3874837Smckusic 			case IFCHR:
3884837Smckusic 			case IFBLK:
3894843Smckusic 				fprintf(stdout, "extract special file %s\n", name);
3906844Smckusick 				if (mknod(name, mode, spcl.c_dinode.di_rdev)) {
3914837Smckusic 					fprintf(stderr, "%s: cannot create special file\n", name);
3924837Smckusic 					xp->x_flags |= XTRACTD;
3934837Smckusic 					xtrcnt--;
3944837Smckusic 					goto skipfile;
3954776Smckusic 				}
3964837Smckusic 				getfile(null, null, spcl.c_dinode.di_size);
3974837Smckusic 				break;
3984837Smckusic 			case IFDIR:
3994837Smckusic 				if (mflag) {
4004843Smckusic 					fprintf(stdout, "extract directory %s\n", name);
4014837Smckusic 					strncat(name, "/.", BUFSIZ);
4024843Smckusic 					checkdir(name);
4036844Smckusick 					chown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4044837Smckusic 					getfile(null, null, spcl.c_dinode.di_size);
4054837Smckusic 					break;
4064610Smckusick 				}
4075038Smckusic 				fprintf(stdout, "extract file %s\n", name);
4086844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
4095038Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
4105038Smckusic 					xp->x_flags |= XTRACTD;
4115038Smckusic 					xtrcnt--;
4125038Smckusic 					goto skipfile;
4135038Smckusic 				}
4146844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4155943Smckusic 				if (cvtdir) {
4165038Smckusic 					getfile(xtrcvtdir, xtrcvtskip,
4175038Smckusic 					    spcl.c_dinode.di_size);
4185943Smckusic 					flushent(xtrfile);
4195943Smckusic 				} else
4205038Smckusic 					getfile(xtrfile, xtrskip,
4215038Smckusic 					    spcl.c_dinode.di_size);
4226844Smckusick 				close(ofile);
4235038Smckusic 				break;
4246289Smckusick 			case IFLNK:
4256289Smckusick 				fprintf(stdout, "extract symbolic link %s\n", name);
4266289Smckusick 				uid = spcl.c_dinode.di_uid;
4276289Smckusick 				gid = spcl.c_dinode.di_gid;
4286289Smckusick 				lnkbuf[0] = '\0';
4296289Smckusick 				pathlen = 0;
4306289Smckusick 				getfile(xtrlnkfile, xtrlnkskip, spcl.c_dinode.di_size);
4316844Smckusick 				if (symlink(lnkbuf, name) < 0) {
4326289Smckusick 					fprintf(stderr, "%s: cannot create symbolic link\n", name);
4336289Smckusick 					xp->x_flags |= XTRACTD;
4346289Smckusick 					xtrcnt--;
4356289Smckusick 					goto finished;
4366289Smckusick 				}
4376844Smckusick 				chown(name, uid, gid);
4386289Smckusick 				break;
4394837Smckusic 			case IFREG:
4404843Smckusic 				fprintf(stdout, "extract file %s\n", name);
4416844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
4424837Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
4434837Smckusic 					xp->x_flags |= XTRACTD;
4444837Smckusic 					xtrcnt--;
4454837Smckusic 					goto skipfile;
4464837Smckusic 				}
4476844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4485038Smckusic 				getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
4496844Smckusick 				close(ofile);
4504837Smckusic 				break;
4514610Smckusick 			}
4526844Smckusick 			chmod(name, mode);
4536844Smckusick 			utime(name, xp->x_timep);
4544837Smckusic 			xp->x_flags |= XTRACTD;
4554837Smckusic 			xtrcnt--;
4564837Smckusic 			goto finished;
4574837Smckusic 		}
4584837Smckusic skipfile:
4594837Smckusic 		getfile(null, null, spcl.c_dinode.di_size);
4604700Smckusic finished:
4614837Smckusic 		;
4624837Smckusic 	}
4634837Smckusic 	if (xtrcnt == 0 && !mflag)
4644837Smckusic 		return;
4654837Smckusic 	for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
4664837Smckusic 		for (xp = *xpp; xp; xp = xp->x_next) {
4674837Smckusic 			if (mflag && (xp->x_flags & XISDIR))
4686844Smckusick 				utime(xp->x_name, xp->x_timep);
4694837Smckusic 			if (xp->x_flags & XTRACTD)
4704837Smckusic 				continue;
4714837Smckusic 			if ((xp->x_flags & XLINKED) == 0) {
4724837Smckusic 				fprintf(stderr, "cannot find file %s\n",
4734837Smckusic 					xp->x_name);
4744837Smckusic 				continue;
4754837Smckusic 			}
4764843Smckusic 			if (!mflag)
4774843Smckusic 				continue;
4784843Smckusic 			fprintf(stdout, "link %s to %s\n",
4794843Smckusic 				xp->x_linkedto->x_name, xp->x_name);
4806844Smckusick 			if (link(xp->x_linkedto->x_name, xp->x_name) < 0)
4814843Smckusic 				fprintf(stderr, "link %s to %s failed\n",
4824837Smckusic 					xp->x_linkedto->x_name, xp->x_name);
4834610Smckusick 		}
4844837Smckusic 	}
4854837Smckusic }
4864837Smckusic 
4874610Smckusick /*
4884610Smckusick  * Read the tape, bulding up a directory structure for extraction
4894610Smckusick  * by name
4904610Smckusick  */
4915038Smckusic pass1(savedir)
4925038Smckusic 	int savedir;
4934610Smckusick {
4944776Smckusic 	register int i;
4954837Smckusic 	register struct dinode *ip;
4964837Smckusic 	struct direct nulldir;
4975038Smckusic 	char buf[TP_BSIZE];
4985943Smckusic 	int putdir(), null(), dirwrite();
4994610Smckusick 
5005943Smckusic 	nulldir.d_ino = 1;
5015943Smckusic 	nulldir.d_namlen = 1;
5025943Smckusic 	strncpy(nulldir.d_name, "/", nulldir.d_namlen);
5035943Smckusic 	nulldir.d_reclen = DIRSIZ(&nulldir);
5044610Smckusick 	while (gethead(&spcl) == 0) {
5054700Smckusic 		fprintf(stderr, "Can't find directory header!\n");
5064610Smckusick 	}
5074610Smckusick 	for (;;) {
5084610Smckusick 		if (checktype(&spcl, TS_BITS) == 1) {
5096844Smckusick 			readbits(&dumpmap);
5104610Smckusick 			continue;
5114610Smckusick 		}
5124610Smckusick 		if (checktype(&spcl, TS_CLRI) == 1) {
5136844Smckusick 			readbits(&clrimap);
5144610Smckusick 			continue;
5154610Smckusick 		}
5164610Smckusick 		if (checktype(&spcl, TS_INODE) == 0) {
5174610Smckusick finish:
5185943Smckusic 			if (savedir) {
5195943Smckusic 				fclose(df);
5205943Smckusic 				dirp = opendir(dirfile);
5215943Smckusic 				if (dirp == NULL)
5225943Smckusic 					perror("opendir");
5235943Smckusic 			}
5245038Smckusic 			resetmt();
5254610Smckusick 			return;
5264610Smckusick 		}
5274610Smckusick 		ip = &spcl.c_dinode;
5284610Smckusick 		i = ip->di_mode & IFMT;
5294610Smckusick 		if (i != IFDIR) {
5304610Smckusick 			goto finish;
5314610Smckusick 		}
5325038Smckusic 		if (spcl.c_inumber == ROOTINO) {
5335038Smckusic 			readtape(buf);
5345038Smckusic 			bct--; /* push back this block */
5355038Smckusic 			if (((struct direct *)buf)->d_ino != ROOTINO) {
5365038Smckusic 				if (((struct odirect *)buf)->d_ino != ROOTINO) {
5375038Smckusic 					fprintf(stderr, "bad root directory\n");
5385038Smckusic 					done(1);
5395038Smckusic 				}
5405038Smckusic 				fprintf(stderr, "converting to new directory format\n");
5415038Smckusic 				cvtdir = 1;
542*8302Smckusick 				cvtflag = 1;
5435038Smckusic 			}
5445038Smckusic 			if (!savedir && !cvtdir) {
5455038Smckusic 				/* if no conversion, just return */
5465038Smckusic 				goto finish;
5475038Smckusic 			}
5485038Smckusic 		}
5494843Smckusic 		allocinotab(spcl.c_inumber, seekpt);
5505038Smckusic 		if (savedir) {
5515038Smckusic 			getfile(putdir, null, spcl.c_dinode.di_size);
5525943Smckusic 			putent(&nulldir, dirwrite);
5535943Smckusic 			flushent(dirwrite);
5545038Smckusic 		} else {
5555038Smckusic 			getfile(null, null, spcl.c_dinode.di_size);
5565038Smckusic 		}
5574610Smckusick 	}
5584610Smckusick }
5594610Smckusick 
5604610Smckusick /*
5614843Smckusic  * Put the directory entries in the directory file
5624843Smckusic  */
5634843Smckusic putdir(buf, size)
5644843Smckusic 	char *buf;
5654843Smckusic 	int size;
5664843Smckusic {
5675038Smckusic 	struct direct cvtbuf;
5685038Smckusic 	register struct odirect *odp;
5695038Smckusic 	struct odirect *eodp;
5704843Smckusic 	register struct direct *dp;
5716289Smckusick 	long loc, i;
5724843Smckusic 
5735038Smckusic 	if (cvtdir) {
5745038Smckusic 		eodp = (struct odirect *)&buf[size];
5755038Smckusic 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
5765038Smckusic 			if (odp->d_ino != 0) {
5775038Smckusic 				dcvt(odp, &cvtbuf);
5785943Smckusic 				putent(&cvtbuf, dirwrite);
5795038Smckusic 			}
5805038Smckusic 	} else {
5815943Smckusic 		for (loc = 0; loc < size; ) {
5825943Smckusic 			dp = (struct direct *)(buf + loc);
5836289Smckusick 			i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
5846289Smckusick 			if (dp->d_reclen <= 0 || dp->d_reclen > i) {
5856289Smckusick 				loc += i;
5866289Smckusick 				continue;
5876289Smckusick 			}
5886289Smckusick 			loc += dp->d_reclen;
5896847Smckusick 			if (dp->d_ino != 0) {
5905943Smckusic 				putent(dp, dirwrite);
5916847Smckusick 			}
5925943Smckusic 		}
5935038Smckusic 	}
5944843Smckusic }
5954843Smckusic 
5964843Smckusic /*
5974843Smckusic  *	Recursively find names and inumbers of all files in subtree
5984843Smckusic  *	pname and put them in xtrlist[]
5994843Smckusic  */
6004843Smckusic getleaves(ino, pname)
6014843Smckusic 	ino_t ino;
6024843Smckusic 	char *pname;
6034843Smckusic {
6044843Smckusic 	register struct inotab *itp;
6054843Smckusic 	int namelen;
6066846Smckusick 	daddr_t bpt;
6075943Smckusic 	register struct direct *dp;
6085943Smckusic 	char locname[BUFSIZ + 1];
6094843Smckusic 
6104843Smckusic 	if (BIT(ino, dumpmap) == 0) {
6114843Smckusic 		fprintf(stdout, "%s: not on the tape\n", pname);
6124843Smckusic 		return;
6134843Smckusic 	}
6144843Smckusic 	for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
6154843Smckusic 		if (itp->t_ino != ino)
6164843Smckusic 			continue;
6174843Smckusic 		/*
6184843Smckusic 		 * pname is a directory name
6194843Smckusic 		 */
6204843Smckusic 		allocxtr(ino, pname, XISDIR);
6214843Smckusic 		/*
6224843Smckusic 		 * begin search through the directory
6234843Smckusic 		 * skipping over "." and ".."
6244843Smckusic 		 */
6254843Smckusic 		strncpy(locname, pname, BUFSIZ);
6264843Smckusic 		strncat(locname, "/", BUFSIZ);
6274843Smckusic 		namelen = strlen(locname);
6285943Smckusic 		seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
6295943Smckusic 		dp = readdir(dirp);
6305943Smckusic 		dp = readdir(dirp);
6315943Smckusic 		dp = readdir(dirp);
6325943Smckusic 		bpt = telldir(dirp);
6334843Smckusic 		/*
6344843Smckusic 		 * "/" signals end of directory
6354843Smckusic 		 */
6365943Smckusic 		while (dp->d_namlen != 1 || dp->d_name[0] != '/') {
6374843Smckusic 			locname[namelen] = '\0';
6385943Smckusic 			if (namelen + dp->d_namlen >= BUFSIZ) {
6395943Smckusic 				fprintf(stderr, "%s%s: name exceedes %d char\n",
6405943Smckusic 					locname, dp->d_name, BUFSIZ);
6414843Smckusic 				continue;
6424843Smckusic 			}
6435943Smckusic 			strncat(locname, dp->d_name, dp->d_namlen);
6445943Smckusic 			getleaves(dp->d_ino, locname);
6455943Smckusic 			seekdir(dirp, bpt, itp->t_seekpt);
6465943Smckusic 			dp = readdir(dirp);
6475943Smckusic 			bpt = telldir(dirp);
6484843Smckusic 		}
6494843Smckusic 		return;
6504843Smckusic 	}
6514843Smckusic 	/*
6524843Smckusic 	 * locname is name of a simple file
6534843Smckusic 	 */
6544843Smckusic 	allocxtr(ino, pname, XINUSE);
6554843Smckusic }
6564843Smckusic 
6574843Smckusic /*
6584843Smckusic  * Search the directory tree rooted at inode ROOTINO
6594843Smckusic  * for the path pointed at by n
6604843Smckusic  */
6614843Smckusic psearch(n)
6624843Smckusic 	char	*n;
6634843Smckusic {
6644843Smckusic 	register char *cp, *cp1;
6654843Smckusic 	char c;
6664843Smckusic 
6674843Smckusic 	ino = ROOTINO;
6684843Smckusic 	if (*(cp = n) == '/')
6694843Smckusic 		cp++;
6704843Smckusic next:
6714843Smckusic 	cp1 = cp + 1;
6724843Smckusic 	while (*cp1 != '/' && *cp1)
6734843Smckusic 		cp1++;
6744843Smckusic 	c = *cp1;
6754843Smckusic 	*cp1 = 0;
6764843Smckusic 	ino = search(ino, cp);
6774843Smckusic 	if (ino == 0) {
6784843Smckusic 		*cp1 = c;
6794843Smckusic 		return(0);
6804843Smckusic 	}
6814843Smckusic 	*cp1 = c;
6824843Smckusic 	if (c == '/') {
6834843Smckusic 		cp = cp1+1;
6844843Smckusic 		goto next;
6854843Smckusic 	}
6864843Smckusic 	return(ino);
6874843Smckusic }
6884843Smckusic 
6894843Smckusic /*
6904843Smckusic  * search the directory inode ino
6914843Smckusic  * looking for entry cp
6924843Smckusic  */
6934843Smckusic ino_t
6944843Smckusic search(inum, cp)
6954843Smckusic 	ino_t	inum;
6964843Smckusic 	char	*cp;
6974843Smckusic {
6985943Smckusic 	register struct direct *dp;
6994843Smckusic 	register struct inotab *itp;
7005943Smckusic 	int len;
7014843Smckusic 
7024843Smckusic 	for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
7034843Smckusic 		if (itp->t_ino == inum)
7044843Smckusic 			goto found;
7054843Smckusic 	return(0);
7064843Smckusic found:
7075943Smckusic 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
7085943Smckusic 	len = strlen(cp);
7094843Smckusic 	do {
7105943Smckusic 		dp = readdir(dirp);
7115943Smckusic 		if (dp->d_namlen == 1 && dp->d_name[0] == '/')
7124843Smckusic 			return(0);
7135943Smckusic 	} while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
7145943Smckusic 	return(dp->d_ino);
7154843Smckusic }
7164843Smckusic 
7174843Smckusic /*
7184610Smckusick  * Do the file extraction, calling the supplied functions
7194610Smckusick  * with the blocks
7204610Smckusick  */
7214700Smckusic getfile(f1, f2, size)
7224700Smckusic 	int	(*f2)(), (*f1)();
7236846Smckusick 	off_t	size;
7244610Smckusick {
7254776Smckusic 	register int i;
7265327Smckusic 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
7274837Smckusic 	union u_spcl addrblk;
7284837Smckusic #	define addrblock addrblk.s_spcl
7294610Smckusick 
7304837Smckusic 	addrblock = spcl;
7314610Smckusick 	for (;;) {
7324837Smckusic 		for (i = 0; i < addrblock.c_count; i++) {
7334837Smckusic 			if (addrblock.c_addr[i]) {
7344776Smckusic 				readtape(&buf[curblk++][0]);
7356844Smckusick 				if (curblk == fssize / TP_BSIZE) {
7364776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
7376844Smckusick 					     (long) (fssize) :
7384776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
7394776Smckusic 					curblk = 0;
7404776Smckusic 				}
7415327Smckusic 			} else {
7424776Smckusic 				if (curblk > 0) {
7434776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
7444776Smckusic 					     (long) (curblk * TP_BSIZE) :
7454776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
7464776Smckusic 					curblk = 0;
7474776Smckusic 				}
7485327Smckusic 				(*f2)(clearedbuf, size > TP_BSIZE ?
7495327Smckusic 					(long) TP_BSIZE : size);
7504610Smckusick 			}
7514776Smckusic 			if ((size -= TP_BSIZE) <= 0) {
7524610Smckusick eloop:
7534610Smckusick 				while (gethead(&spcl) == 0)
7544610Smckusick 					;
7554610Smckusick 				if (checktype(&spcl, TS_ADDR) == 1)
7564610Smckusick 					goto eloop;
7574776Smckusic 				goto out;
7584610Smckusick 			}
7594610Smckusick 		}
7604837Smckusic 		if (gethead(&addrblock) == 0) {
7614776Smckusic 			fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
7624700Smckusic 			goto eloop;
7634700Smckusic 		}
7644837Smckusic 		if (checktype(&addrblock, TS_ADDR) == 0) {
7654837Smckusic 			spcl = addrblock;
7664776Smckusic 			goto out;
7674700Smckusic 		}
7684610Smckusick 	}
7694776Smckusic out:
7704776Smckusic 	if (curblk > 0) {
7714776Smckusic 		(*f1)(buf, (curblk * TP_BSIZE) + size);
7724776Smckusic 		curblk = 0;
7734776Smckusic 	}
7744610Smckusick }
7754610Smckusick 
7764610Smckusick /*
7774843Smckusic  * The next routines are called during file extraction to
7784843Smckusic  * put the data into the right form and place.
7794843Smckusic  */
7804843Smckusic xtrfile(buf, size)
7814843Smckusic 	char	*buf;
7824843Smckusic 	long	size;
7834843Smckusic {
7846847Smckusick 
7856844Smckusick 	if (write(ofile, buf, (int) size) == -1) {
7865038Smckusic 		perror("extract write");
7874843Smckusic 		done(1);
7884843Smckusic 	}
7894843Smckusic }
7904843Smckusic 
7915038Smckusic xtrskip(buf, size)
7924843Smckusic 	char *buf;
7934843Smckusic 	long size;
7944843Smckusic {
7956847Smckusick 
7966846Smckusick #ifdef lint
7976846Smckusick 	buf = buf;
7986846Smckusick #endif
7996844Smckusick 	if (lseek(ofile, size, 1) == -1) {
8005038Smckusic 		perror("extract seek");
8014843Smckusic 		done(1);
8024843Smckusic 	}
8034843Smckusic }
8045038Smckusic 
8055038Smckusic xtrcvtdir(buf, size)
8065038Smckusic 	struct odirect *buf;
8075038Smckusic 	long size;
8085038Smckusic {
8095038Smckusic 	struct odirect *odp, *edp;
8106846Smckusick 	struct direct cvtbuf;
8115038Smckusic 
8125038Smckusic 	edp = &buf[size / sizeof(struct odirect)];
8135943Smckusic 	for (odp = buf; odp < edp; odp++) {
8145943Smckusic 		dcvt(odp, &cvtbuf);
8155943Smckusic 		putent(&cvtbuf, xtrfile);
8165038Smckusic 	}
8175038Smckusic }
8185038Smckusic 
8195038Smckusic xtrcvtskip(buf, size)
8205038Smckusic 	char *buf;
8215038Smckusic 	long size;
8225038Smckusic {
8236847Smckusick 
8245038Smckusic 	fprintf(stderr, "unallocated block in directory\n");
8255943Smckusic 	xtrskip(buf, size);
8265038Smckusic }
8276289Smckusick 
8286289Smckusick xtrlnkfile(buf, size)
8296289Smckusick 	char	*buf;
8306289Smckusick 	long	size;
8316289Smckusick {
8326847Smckusick 
8336289Smckusick 	pathlen += size;
8346289Smckusick 	if (pathlen > MAXPATHLEN) {
8356289Smckusick 		fprintf(stderr, "symbolic link name: %s; too long %d\n",
8366289Smckusick 		    buf, size);
8376289Smckusick 		done(1);
8386289Smckusick 	}
8396289Smckusick 	strcat(lnkbuf, buf);
8406289Smckusick }
8416289Smckusick 
8426289Smckusick xtrlnkskip(buf, size)
8436289Smckusick 	char *buf;
8446289Smckusick 	long size;
8456289Smckusick {
8466847Smckusick 
8476846Smckusick #ifdef lint
8486846Smckusick 	buf = buf, size = size;
8496846Smckusick #endif
8506289Smckusick 	fprintf(stderr, "unallocated block in symbolic link\n");
8516289Smckusick 	done(1);
8526289Smckusick }
8534843Smckusic 
8544843Smckusic null() {;}
8554843Smckusic 
8564843Smckusic /*
8574776Smckusic  * Do the tape i/o, dealing with volume changes
8584610Smckusick  * etc..
8594610Smckusick  */
8604610Smckusick readtape(b)
8614700Smckusic 	char *b;
8624610Smckusick {
8636846Smckusick 	register long i;
8646847Smckusick 	struct u_spcl tmpbuf;
8656845Smckusick 	char c;
8664610Smckusick 
8674610Smckusick 	if (bct >= NTREC) {
8684610Smckusick 		for (i = 0; i < NTREC; i++)
8694776Smckusic 			((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
8704610Smckusick 		bct = 0;
8716849Smckusick #ifdef RRESTOR
8726849Smckusick 		if ((i = rmtread(tbf, NTREC*TP_BSIZE)) < 0) {
8736849Smckusick #else
8744776Smckusic 		if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
8756849Smckusick #endif
8766845Smckusick 			fprintf(stderr, "Tape read error, continue?");
8776845Smckusick 			do	{
8786845Smckusick 				fprintf(stderr, "[yn]\n");
8796845Smckusick 				c = getchar();
8806845Smckusick 				while (getchar() != '\n')
8816845Smckusick 					/* void */;
8826845Smckusick 			} while (c != 'y' && c != 'n');
8834610Smckusick 			eflag++;
8846845Smckusick 			if (c == 'n')
8856845Smckusick 				done(1);
8866845Smckusick 			i = NTREC*TP_BSIZE;
8876845Smckusick 			blkclr(tbf, i);
8886849Smckusick #ifdef RRESTOR
8896849Smckusick 			if (rmtseek(i, 1) < 0) {
8906849Smckusick #else
8916846Smckusick 			if (lseek(mt, i, 1) < 0) {
8926849Smckusick #endif
8936846Smckusick 				fprintf(stderr, "continuation failed\n");
8946846Smckusick 				done(1);
8956846Smckusick 			}
8964610Smckusick 		}
8974610Smckusick 		if (i == 0) {
8984610Smckusick 			bct = NTREC + 1;
8994610Smckusick 			volno++;
9004610Smckusick loop:
9014610Smckusick 			flsht();
9026849Smckusick #ifdef RRESTOR
9036849Smckusick 			rmtclose();
9046849Smckusick #else
9054610Smckusick 			close(mt);
9066849Smckusick #endif
9074700Smckusic 			fprintf(stderr, "Mount volume %d\n", volno);
9084610Smckusick 			while (getchar() != '\n')
9094610Smckusick 				;
9106849Smckusick #ifdef RRESTOR
9116849Smckusick 			if ((mt = rmtopen(magtape, 0)) == -1) {
9126849Smckusick #else
9134610Smckusick 			if ((mt = open(magtape, 0)) == -1) {
9146849Smckusick #endif
9154700Smckusic 				fprintf(stderr, "Cannot open tape!\n");
9164610Smckusick 				goto loop;
9174610Smckusick 			}
9184610Smckusick 			if (readhdr(&tmpbuf) == 0) {
9194700Smckusic 				fprintf(stderr, "Not a dump tape.Try again\n");
9204610Smckusick 				goto loop;
9214610Smckusick 			}
9224610Smckusick 			if (checkvol(&tmpbuf, volno) == 0) {
9234700Smckusic 				fprintf(stderr, "Wrong tape. Try again\n");
9244610Smckusick 				goto loop;
9254610Smckusick 			}
9264610Smckusick 			readtape(b);
9274610Smckusick 			return;
9284610Smckusick 		}
9294610Smckusick 	}
9306846Smckusick 	blkcpy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
9314610Smckusick }
9324610Smckusick 
9334610Smckusick flsht()
9344610Smckusick {
9356847Smckusick 
9364610Smckusick 	bct = NTREC+1;
9374610Smckusick }
9384610Smckusick 
9395943Smckusic blkcpy(from, to, size)
9405943Smckusic 	char *from, *to;
9416846Smckusick 	long size;
9424610Smckusick {
9436847Smckusick 
9446846Smckusick #ifdef lint
9456846Smckusick 	from = from, to = to, size = size;
9466846Smckusick #endif
9475943Smckusic 	asm("	movc3	12(ap),*4(ap),*8(ap)");
9484610Smckusick }
9494610Smckusick 
9505038Smckusic blkclr(buf, size)
9515038Smckusic 	char *buf;
9526846Smckusick 	long size;
9535038Smckusic {
9546847Smckusick 
9556846Smckusick #ifdef lint
9566846Smckusick 	buf = buf, size = size;
9576846Smckusick #endif
9585038Smckusic 	asm("movc5	$0,(r0),$0,8(ap),*4(ap)");
9595038Smckusic }
9605038Smckusic 
9615038Smckusic resetmt()
9625038Smckusic {
9635038Smckusic 	struct mtop tcom;
9645038Smckusic 
9656847Smckusick 	if (dumpnum > 1)
9665038Smckusic 		tcom.mt_op = MTBSF;
9675038Smckusic 	else
9685038Smckusic 		tcom.mt_op = MTREW;
9695038Smckusic 	tcom.mt_count = 1;
9705038Smckusic 	flsht();
9716849Smckusick #ifdef RRESTOR
9726849Smckusick 	if (rmtioctl(tcom.mt_op, 1) == -1) {
9736849Smckusick 		/* kludge for disk dumps */
9746849Smckusick 		rmtseek((long)0, 0);
9756849Smckusick 	}
9766849Smckusick #else
9775038Smckusic 	if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
9785038Smckusic 		/* kludge for disk dumps */
9795038Smckusic 		lseek(mt, (long)0, 0);
9805038Smckusic 	}
9816849Smckusick #endif
9825038Smckusic 	if (dumpnum > 1) {
9836849Smckusick #ifdef RRESTOR
9846849Smckusick 		rmtioctl(MTFSF, 1);
9856849Smckusick #else
9865038Smckusic 		tcom.mt_op = MTFSF;
9875038Smckusic 		tcom.mt_count = 1;
9885038Smckusic 		ioctl(mt,MTIOCTOP,&tcom);
9896849Smckusick #endif
9905038Smckusic 	}
9915038Smckusic }
9925038Smckusic 
9934843Smckusic checkvol(b, t)
9944843Smckusic 	struct s_spcl *b;
9954843Smckusic 	int t;
9964610Smckusick {
9976847Smckusick 
9984843Smckusic 	if (b->c_volume == t)
9994843Smckusic 		return(1);
10004610Smckusick 	return(0);
10014610Smckusick }
10024610Smckusick 
10034843Smckusic readhdr(b)
10044843Smckusic 	struct s_spcl *b;
10054610Smckusick {
10066847Smckusick 
10074843Smckusic 	if (gethead(b) == 0)
10084610Smckusick 		return(0);
10094843Smckusic 	if (checktype(b, TS_TAPE) == 0)
10104843Smckusic 		return(0);
10114843Smckusic 	return(1);
10124610Smckusick }
10134610Smckusick 
10144610Smckusick /*
10154610Smckusick  * read the tape into buf, then return whether or
10164610Smckusick  * or not it is a header block.
10174610Smckusick  */
10184610Smckusick gethead(buf)
10194837Smckusic 	struct s_spcl *buf;
10204610Smckusick {
1021*8302Smckusick 	union u_ospcl {
1022*8302Smckusick 		char dummy[TP_BSIZE];
1023*8302Smckusick 		struct	s_ospcl {
1024*8302Smckusick 			int	c_type;
1025*8302Smckusick 			time_t	c_date;
1026*8302Smckusick 			time_t	c_ddate;
1027*8302Smckusick 			int	c_volume;
1028*8302Smckusick 			daddr_t	c_tapea;
1029*8302Smckusick 			ino_t	c_inumber;
1030*8302Smckusick 			int	c_magic;
1031*8302Smckusick 			int	c_checksum;
1032*8302Smckusick 			struct odinode {
1033*8302Smckusick 				unsigned short odi_mode;
1034*8302Smckusick 				short	odi_nlink;
1035*8302Smckusick 				short	odi_uid;
1036*8302Smckusick 				short	odi_gid;
1037*8302Smckusick 				off_t	odi_size;
1038*8302Smckusick 				daddr_t	odi_rdev;
1039*8302Smckusick 				char	odi_addr[36];
1040*8302Smckusick 				time_t	odi_atime;
1041*8302Smckusick 				time_t	odi_mtime;
1042*8302Smckusick 				time_t	odi_ctime;
1043*8302Smckusick 			} c_dinode;
1044*8302Smckusick 			int	c_count;
1045*8302Smckusick 			char	c_addr[TP_NINDIR];
1046*8302Smckusick 		} s_ospcl;
1047*8302Smckusick 	} u_ospcl;
10486847Smckusick 
1049*8302Smckusick 	if (!cvtflag) {
1050*8302Smckusick 		readtape((char *)buf);
1051*8302Smckusick 		if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
1052*8302Smckusick 			return(0);
1053*8302Smckusick 		return(1);
1054*8302Smckusick 	}
1055*8302Smckusick 	readtape((char *)(&u_ospcl.s_ospcl));
1056*8302Smckusick 	if (u_ospcl.s_ospcl.c_magic != MAGIC ||
1057*8302Smckusick 	    checksum((int *)(&u_ospcl.s_ospcl)) == 0)
10584610Smckusick 		return(0);
1059*8302Smckusick 	blkclr((char *)buf, TP_BSIZE);
1060*8302Smckusick 	buf->c_type = u_ospcl.s_ospcl.c_type;
1061*8302Smckusick 	buf->c_date = u_ospcl.s_ospcl.c_date;
1062*8302Smckusick 	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1063*8302Smckusick 	buf->c_volume = u_ospcl.s_ospcl.c_volume;
1064*8302Smckusick 	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1065*8302Smckusick 	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1066*8302Smckusick 	buf->c_magic = u_ospcl.s_ospcl.c_magic;
1067*8302Smckusick 	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1068*8302Smckusick 	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1069*8302Smckusick 	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1070*8302Smckusick 	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1071*8302Smckusick 	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1072*8302Smckusick 	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1073*8302Smckusick 	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1074*8302Smckusick 	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1075*8302Smckusick 	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1076*8302Smckusick 	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1077*8302Smckusick 	buf->c_count = u_ospcl.s_ospcl.c_count;
1078*8302Smckusick 	blkcpy(u_ospcl.s_ospcl.c_addr, buf->c_addr, TP_NINDIR);
10794610Smckusick 	return(1);
10804610Smckusick }
10814610Smckusick 
10824610Smckusick /*
10834610Smckusick  * return whether or not the buffer contains a header block
10844610Smckusick  */
10854610Smckusick ishead(buf)
10864837Smckusic 	struct s_spcl *buf;
10874610Smckusick {
10886847Smckusick 
1089*8302Smckusick 	if (buf->c_magic != MAGIC)
10904610Smckusick 		return(0);
10914610Smckusick 	return(1);
10924610Smckusick }
10934610Smckusick 
10944610Smckusick checktype(b, t)
10954837Smckusic 	struct s_spcl *b;
10964700Smckusic 	int	t;
10974610Smckusick {
10986847Smckusick 
10994837Smckusic 	return(b->c_type == t);
11004610Smckusick }
11014610Smckusick 
11025038Smckusic /*
11035038Smckusic  * read a bit mask from the tape into m.
11045038Smckusic  */
11056844Smckusick readbits(mapp)
11066844Smckusick 	char **mapp;
11075038Smckusic {
11085038Smckusic 	register int i;
11096844Smckusick 	char	*m;
11104610Smckusick 
11115038Smckusic 	i = spcl.c_count;
11125038Smckusic 
11136844Smckusick 	if (*mapp == 0)
11146846Smckusick 		*mapp = (char *)calloc(i, (TP_BSIZE/(NBBY/BITS)));
11156844Smckusick 	m = *mapp;
11165038Smckusic 	while (i--) {
11175038Smckusic 		readtape((char *) m);
11185327Smckusic 		m += (TP_BSIZE/(NBBY/BITS));
11195038Smckusic 	}
11205038Smckusic 	while (gethead(&spcl) == 0)
11215038Smckusic 		;
11225038Smckusic }
11235038Smckusic 
11244610Smckusick checksum(b)
1125*8302Smckusick 	register int *b;
11264610Smckusick {
11274776Smckusic 	register int i, j;
11284610Smckusick 
11294776Smckusic 	j = sizeof(union u_spcl) / sizeof(int);
11304610Smckusick 	i = 0;
11314610Smckusick 	do
11324610Smckusick 		i += *b++;
11334610Smckusick 	while (--j);
11344610Smckusick 	if (i != CHECKSUM) {
11354776Smckusic 		fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
11364610Smckusick 		return(0);
11374610Smckusick 	}
11384610Smckusick 	return(1);
11394610Smckusick }
11404610Smckusick 
11414610Smckusick /*
11425038Smckusic  *	Check for access into each directory in the pathname of an extracted
11435038Smckusic  *	file and create such a directory if needed in preparation for moving
11445038Smckusic  *	the file to its proper home.
11455038Smckusic  */
11465038Smckusic checkdir(name)
11475038Smckusic 	register char *name;
11485038Smckusic {
11495038Smckusic 	register char *cp;
11505038Smckusic 	int i;
11515038Smckusic 
11525038Smckusic 	for (cp = name; *cp; cp++) {
11535038Smckusic 		if (*cp == '/') {
11545038Smckusic 			*cp = '\0';
11556844Smckusick 			if (access(name, 01) < 0) {
11565038Smckusic 				register int pid, rp;
11575038Smckusic 
11585038Smckusic 				if ((pid = fork()) == 0) {
11596844Smckusick 					execl("/bin/mkdir", "mkdir", name, 0);
11606844Smckusick 					execl("/usr/bin/mkdir", "mkdir", name, 0);
11616844Smckusick 					fprintf(stderr, "restor: cannot find mkdir!\n");
11625038Smckusic 					done(0);
11635038Smckusic 				}
11645038Smckusic 				while ((rp = wait(&i)) >= 0 && rp != pid)
11655038Smckusic 					;
11665038Smckusic 			}
11675038Smckusic 			*cp = '/';
11685038Smckusic 		}
11695038Smckusic 	}
11705038Smckusic }
11715038Smckusic 
11726844Smckusick setdir(dev)
11736844Smckusick 	char *dev;
11746844Smckusick {
11756844Smckusick 	struct fstab *fsp;
11766844Smckusick 
11776844Smckusick 	if (setfsent() == 0) {
11786844Smckusick 		fprintf(stderr, "Can't open checklist file: %s\n", FSTAB);
11796844Smckusick 		done(1);
11806844Smckusick 	}
11816844Smckusick 	while ((fsp = getfsent()) != 0) {
11826844Smckusick 		if (strcmp(fsp->fs_spec, dev) == 0) {
11836844Smckusick 			printf("%s mounted on %s\n", dev, fsp->fs_file);
11846844Smckusick 			if (chdir(fsp->fs_file) >= 0)
11856844Smckusick 				return;
11866844Smckusick 			fprintf(stderr, "%s cannot chdir to %s\n",
11876844Smckusick 			    fsp->fs_file);
11886844Smckusick 			done(1);
11896844Smckusick 		}
11906844Smckusick 	}
11916844Smckusick 	fprintf(stderr, "%s not mounted\n", dev);
11926844Smckusick 	done(1);
11936844Smckusick }
11946844Smckusick 
11955038Smckusic /*
11965943Smckusic  * These variables are "local" to the following two functions.
11975943Smckusic  */
11985943Smckusic char dirbuf[DIRBLKSIZ];
11995943Smckusic long dirloc = 0;
12005943Smckusic long prev = 0;
12015943Smckusic 
12025943Smckusic /*
12035943Smckusic  * add a new directory entry to a file.
12045943Smckusic  */
12055943Smckusic putent(dp, wrtfunc)
12065943Smckusic 	struct direct *dp;
12075943Smckusic 	int (*wrtfunc)();
12085943Smckusic {
12096847Smckusick 
12105943Smckusic 	if (dp->d_ino == 0)
12115943Smckusic 		return;
12126847Smckusick 	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
12136847Smckusick 		((struct direct *)(dirbuf + prev))->d_reclen =
12146847Smckusick 		    DIRBLKSIZ - prev;
12155943Smckusic 		(*wrtfunc)(dirbuf, DIRBLKSIZ);
12165943Smckusic 		dirloc = 0;
12175943Smckusic 	}
12186847Smckusick 	blkcpy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
12196847Smckusick 	prev = dirloc;
12206847Smckusick 	dirloc += dp->d_reclen;
12215943Smckusic }
12225943Smckusic 
12235943Smckusic /*
12245943Smckusic  * flush out a directory that is finished.
12255943Smckusic  */
12265943Smckusic flushent(wrtfunc)
12275943Smckusic 	int (*wrtfunc)();
12285943Smckusic {
12296847Smckusick 
12305943Smckusic 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
12315943Smckusic 	(*wrtfunc)(dirbuf, dirloc);
12325943Smckusic 	dirloc = 0;
12335943Smckusic }
12345943Smckusic 
12355943Smckusic dirwrite(buf, size)
12365943Smckusic 	char *buf;
12375943Smckusic 	int size;
12385943Smckusic {
12396847Smckusick 
12405943Smckusic 	fwrite(buf, 1, size, df);
12415943Smckusic 	seekpt = ftell(df);
12425943Smckusic }
12435943Smckusic 
12445943Smckusic dcvt(odp, ndp)
12455943Smckusic 	register struct odirect *odp;
12465943Smckusic 	register struct direct *ndp;
12475943Smckusic {
12486847Smckusick 
12496846Smckusick 	blkclr((char *)ndp, (long)(sizeof *ndp));
12505943Smckusic 	ndp->d_ino =  odp->d_ino;
12515943Smckusic 	strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
12525943Smckusic 	ndp->d_namlen = strlen(ndp->d_name);
12535943Smckusic 	ndp->d_reclen = DIRSIZ(ndp);
12545943Smckusic 	/*
12555943Smckusic 	 * this quickly calculates if this inode is a directory.
12565943Smckusic 	 * Currently not maintained.
12575943Smckusic 	 *
12585943Smckusic 	for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
12595943Smckusic 		if (itp->t_ino != odp->d_ino)
12605943Smckusic 			continue;
12615943Smckusic 		ndp->d_fmt = IFDIR;
12625943Smckusic 		break;
12635943Smckusic 	}
12645943Smckusic 	 */
12655943Smckusic }
12665943Smckusic 
12675943Smckusic /*
12686289Smckusick  * Open a directory.
12696289Smckusick  * Modified to allow any random file to be a legal directory.
12706289Smckusick  */
12716289Smckusick DIR *
12726289Smckusick opendir(name)
12736289Smckusick 	char *name;
12746289Smckusick {
12756289Smckusick 	register DIR *dirp;
12766289Smckusick 
12776289Smckusick 	dirp = (DIR *)malloc(sizeof(DIR));
12786289Smckusick 	dirp->dd_fd = open(name, 0);
12796289Smckusick 	if (dirp->dd_fd == -1) {
12806846Smckusick 		free((char *)dirp);
12816289Smckusick 		return NULL;
12826289Smckusick 	}
12836289Smckusick 	dirp->dd_loc = 0;
12846289Smckusick 	return dirp;
12856289Smckusick }
12866289Smckusick 
12876289Smckusick /*
12886289Smckusick  * Seek to an entry in a directory.
12895943Smckusic  * Only values returned by ``telldir'' should be passed to seekdir.
12905943Smckusic  * Modified to have many directories based in one file.
12915943Smckusic  */
12925943Smckusic void
12935943Smckusic seekdir(dirp, loc, base)
12945943Smckusic 	register DIR *dirp;
12956846Smckusick 	daddr_t loc, base;
12965943Smckusic {
12976847Smckusick 
12985943Smckusic 	if (loc == telldir(dirp))
12995943Smckusic 		return;
13005943Smckusic 	loc -= base;
13015943Smckusic 	if (loc < 0)
13025943Smckusic 		fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
13036846Smckusick 	(void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
13045943Smckusic 	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
13055943Smckusic 	if (dirp->dd_loc != 0)
13065943Smckusic 		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
13075943Smckusic }
13085943Smckusic 
13095943Smckusic /*
13106844Smckusick  * get next entry in a directory.
13114700Smckusic  */
13126844Smckusick struct direct *
13136844Smckusick readdir(dirp)
13146844Smckusick 	register DIR *dirp;
13154610Smckusick {
13166844Smckusick 	register struct direct *dp;
13174700Smckusic 
13186844Smckusick 	for (;;) {
13196844Smckusick 		if (dirp->dd_loc == 0) {
13206844Smckusick 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
13216844Smckusick 			    DIRBLKSIZ);
13226844Smckusick 			if (dirp->dd_size <= 0)
13236844Smckusick 				return NULL;
13246844Smckusick 		}
13256844Smckusick 		if (dirp->dd_loc >= dirp->dd_size) {
13266844Smckusick 			dirp->dd_loc = 0;
13276844Smckusick 			continue;
13286844Smckusick 		}
13296844Smckusick 		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
13306844Smckusick 		if (dp->d_reclen <= 0 ||
13316844Smckusick 		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc)
13326844Smckusick 			return NULL;
13336844Smckusick 		dirp->dd_loc += dp->d_reclen;
13346844Smckusick 		if (dp->d_ino == 0)
13356844Smckusick 			continue;
13366844Smckusick 		return (dp);
13375948Smckusic 	}
13384610Smckusick }
13394610Smckusick 
13404843Smckusic allocinotab(ino, seekpt)
13414837Smckusic 	ino_t ino;
13424843Smckusic 	daddr_t seekpt;
13434610Smckusick {
13444837Smckusic 	register struct inotab	*itp;
13454776Smckusic 
13464837Smckusic 	itp = (struct inotab *)calloc(1, sizeof(struct inotab));
13474837Smckusic 	itp->t_next = inotab[INOHASH(ino)];
13484837Smckusic 	inotab[INOHASH(ino)] = itp;
13494837Smckusic 	itp->t_ino = ino;
13504843Smckusic 	itp->t_seekpt = seekpt;
13514610Smckusick }
13524610Smckusick 
13534843Smckusic allocxtr(ino, name, flags)
13544837Smckusic 	ino_t ino;
13554843Smckusic 	char *name;
13564843Smckusic 	char flags;
13574610Smckusick {
13584843Smckusic 	register struct xtrlist	*xp, *pxp;
13594776Smckusic 
13604843Smckusic 	xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
13614837Smckusic 	xp->x_next = xtrlist[INOHASH(ino)];
13624837Smckusic 	xtrlist[INOHASH(ino)] = xp;
13634837Smckusic 	xp->x_ino = ino;
13644843Smckusic 	strcpy(xp->x_name, name);
13654837Smckusic 	xtrcnt++;
13664843Smckusic 	xp->x_flags = flags;
13674843Smckusic 	for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
13684843Smckusic 		if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
13694843Smckusic 			xp->x_flags |= XLINKED;
13704843Smckusic 			xp->x_linkedto = pxp;
13714843Smckusic 			xtrcnt--;
13724843Smckusic 			break;
13734843Smckusic 		}
13744843Smckusic 	if (xp->x_flags & XLINKED)
13754843Smckusic 		fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
13764843Smckusic 	else if (xp->x_flags & XISDIR)
13774843Smckusic 		fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
13784843Smckusic 	else
13794843Smckusic 		fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
13804610Smckusick }
13814610Smckusick 
13825038Smckusic done(exitcode)
13835038Smckusic 	int exitcode;
13844610Smckusick {
13856847Smckusick 
13865038Smckusic 	unlink(dirfile);
13875038Smckusic 	exit(exitcode);
13884610Smckusick }
1389