xref: /csrg-svn/sbin/restore/main.c (revision 6846)
14610Smckusick /* Copyright (c) 1981 Regents of the University of California */
24610Smckusick 
3*6846Smckusick #ifndef lint
4*6846Smckusick char version[] = "@(#)main.c 2.4 05/19/82";
5*6846Smckusick #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  *
12*6846Smckusick  *	Modified to work on the new file system
13*6846Smckusick  *	1/19/82		by Kirk McKusick
14*6846Smckusick  *
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>
276844Smckusick #include "../h/param.h"
286844Smckusick #include "../h/dir.h"
296844Smckusick #include "../h/stat.h"
306844Smckusick #include "../h/inode.h"
316844Smckusick #include "../h/fs.h"
326844Smckusick #include "../h/dumprestor.h"
335038Smckusic #include <sys/mtio.h>
344610Smckusick 
355943Smckusic #define ODIRSIZ 14
365038Smckusic struct odirect {
375038Smckusic 	u_short	d_ino;
385943Smckusic 	char	d_name[ODIRSIZ];
395038Smckusic };
405038Smckusic 
415327Smckusic #define	MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
425327Smckusic #define	MBIT(i)	(1<<((unsigned)(i-1)%NBBY))
434610Smckusick #define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
444610Smckusick #define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
454610Smckusick #define	BIT(i,w)	(MWORD(w,i) & MBIT(i))
464610Smckusick 
47*6846Smckusick ino_t	ino;
484610Smckusick 
495038Smckusic int	eflag = 0, hflag = 0, mflag = 0, cvtdir = 0;
504776Smckusic 
516844Smckusick long	fssize;
524610Smckusick char	tapename[] = "/dev/rmt8";
534610Smckusick char	*magtape = tapename;
545038Smckusic int	mt;
555038Smckusic int	dumpnum = 1;
565038Smckusic int	volno = 1;
575038Smckusic int	curblk = 0;
585038Smckusic int	bct = NTREC+1;
595038Smckusic char	tbf[NTREC*TP_BSIZE];
604610Smckusick 
614610Smckusick daddr_t	seekpt;
624837Smckusic FILE	*df;
635943Smckusic DIR	*dirp;
644837Smckusic int	ofile;
654610Smckusick char	dirfile[] = "rstXXXXXX";
666289Smckusick char	lnkbuf[MAXPATHLEN + 1];
676289Smckusick int	pathlen;
684610Smckusick 
694837Smckusic #define INOHASH(val) (val % MAXINO)
704837Smckusic struct inotab {
714837Smckusic 	struct inotab *t_next;
724610Smckusick 	ino_t	t_ino;
734610Smckusick 	daddr_t	t_seekpt;
744837Smckusic } *inotab[MAXINO];
754610Smckusick 
764837Smckusic #define XISDIR	1
774610Smckusick #define XTRACTD	2
784610Smckusick #define XINUSE	4
794837Smckusic #define XLINKED	8
804610Smckusick struct xtrlist {
814837Smckusic 	struct xtrlist	*x_next;
824837Smckusic 	struct xtrlist	*x_linkedto;
834843Smckusic 	time_t		x_timep[2];
844837Smckusic 	ino_t		x_ino;
854837Smckusic 	char		x_flags;
864843Smckusic 	char 		x_name[1];
874843Smckusic 	/* actually longer */
884837Smckusic } *xtrlist[MAXINO];
894776Smckusic int xtrcnt = 0;
904610Smckusick 
915327Smckusic char	*dumpmap;
925327Smckusic char	*clrimap;
934610Smckusick 
945327Smckusic char	clearedbuf[MAXBSIZE];
955327Smckusic 
964837Smckusic extern char *ctime();
97*6846Smckusick extern int seek();
984843Smckusic ino_t search();
995943Smckusic int dirwrite();
1004610Smckusick 
101*6846Smckusick main(argc, argv)
1024700Smckusic 	int argc;
1034700Smckusic 	char *argv[];
1044610Smckusick {
1054610Smckusick 	register char *cp;
1064610Smckusick 	char command;
1074700Smckusic 	int (*signal())();
1084610Smckusick 	int done();
1094610Smckusick 
1104843Smckusic 	if (signal(SIGINT, done) == SIG_IGN)
1114843Smckusic 		signal(SIGINT, SIG_IGN);
1124843Smckusic 	if (signal(SIGTERM, done) == SIG_IGN)
1134843Smckusic 		signal(SIGTERM, SIG_IGN);
1146844Smckusick 	mktemp(dirfile);
1154610Smckusick 	if (argc < 2) {
1164610Smckusick usage:
1174837Smckusic 		fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
1184700Smckusic 		done(1);
1194610Smckusick 	}
1204610Smckusick 	argv++;
1214610Smckusick 	argc -= 2;
1224610Smckusick 	for (cp = *argv++; *cp; cp++) {
1234610Smckusick 		switch (*cp) {
1244610Smckusick 		case '-':
1254610Smckusick 			break;
1264610Smckusick 		case 'f':
1274610Smckusick 			magtape = *argv++;
1284610Smckusick 			argc--;
1294610Smckusick 			break;
1304610Smckusick 		/* s dumpnum (skip to) for multifile dump tapes */
1314610Smckusick 		case 's':
1324610Smckusick 			dumpnum = atoi(*argv++);
1334610Smckusick 			if(dumpnum <= 0) {
1344700Smckusic 				fprintf(stderr, "Dump number must be a positive integer\n");
1354700Smckusic 				done(1);
1364610Smckusick 			}
1374610Smckusick 			argc--;
1384610Smckusick 			break;
1394610Smckusick 		case 'h':
1404610Smckusick 			hflag++;
1414610Smckusick 			break;
1424610Smckusick 		case 'm':
1434610Smckusick 			mflag++;
1444610Smckusick 			break;
1454610Smckusick 		case 'r':
1464610Smckusick 		case 'R':
1476844Smckusick 			hflag++;
1486844Smckusick 			mflag++;
1494610Smckusick 		case 't':
1504610Smckusick 		case 'x':
1514610Smckusick 			command = *cp;
1524610Smckusick 			break;
1534610Smckusick 		default:
1544700Smckusic 			fprintf(stderr, "Bad key character %c\n", *cp);
1554610Smckusick 			goto usage;
1564610Smckusick 		}
1574610Smckusick 	}
1584610Smckusick 	doit(command, argc, argv);
1594700Smckusic 	done(0);
1604610Smckusick }
1614610Smckusick 
1624610Smckusick doit(command, argc, argv)
1634700Smckusic 	char	command;
1644700Smckusic 	int	argc;
1654700Smckusic 	char	*argv[];
1664610Smckusick {
1675038Smckusic 	struct mtop tcom;
1685038Smckusic 
1694610Smckusick 	if ((mt = open(magtape, 0)) < 0) {
1704700Smckusic 		fprintf(stderr, "%s: cannot open tape\n", magtape);
1714700Smckusic 		done(1);
1724610Smckusick 	}
1734843Smckusic 	if (dumpnum != 1) {
1744610Smckusick 		tcom.mt_op = MTFSF;
1754610Smckusick 		tcom.mt_count = dumpnum -1;
1764843Smckusic 		if (ioctl(mt,MTIOCTOP,&tcom) < 0)
1774610Smckusick 			perror("ioctl MTFSF");
1784610Smckusick 	}
179*6846Smckusick 	blkclr(clearedbuf, (long)MAXBSIZE);
1804610Smckusick 	switch(command) {
1814610Smckusick 	case 't':
1824610Smckusick 		if (readhdr(&spcl) == 0) {
1834700Smckusic 			fprintf(stderr, "Tape is not a dump tape\n");
1844700Smckusic 			done(1);
1854610Smckusick 		}
1864843Smckusic 		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
1874843Smckusic 		fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
1884610Smckusick 		return;
1896844Smckusick 	case 'R':
1906844Smckusick 	case 'r':
1916844Smckusick 		setdir(*argv);
1926844Smckusick 		argc = 1;
1936844Smckusick 		*argv = ".";
1946844Smckusick 		/* and then extract it all */
1954610Smckusick 	case 'x':
1966844Smckusick 		df = fopen(dirfile, "w");
1976844Smckusick 		if (df == 0) {
1986844Smckusick 			fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
1996844Smckusick 			done(1);
2006844Smckusick 		}
2014837Smckusic 		extractfiles(argc, argv);
2024837Smckusic 		return;
2034837Smckusic 	}
2044837Smckusic }
2054837Smckusic 
2064837Smckusic extractfiles(argc, argv)
2074837Smckusic 	int argc;
2084837Smckusic 	char **argv;
2094837Smckusic {
2104843Smckusic 	char	*ststore();
2114837Smckusic 	register struct xtrlist *xp;
2124837Smckusic 	struct xtrlist **xpp;
2134837Smckusic 	ino_t	d;
2146289Smckusick 	int	xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(),
2156289Smckusick 		xtrlnkfile(), xtrlnkskip(), null();
2166845Smckusick 	int	mode, uid, gid, i;
2174843Smckusic 	char	name[BUFSIZ + 1];
2186844Smckusick 	struct	stat stbuf;
2194837Smckusic 
2206844Smckusick 	if (stat(".", &stbuf) < 0) {
2216844Smckusick 		fprintf(stderr, "cannot stat .\n");
2226844Smckusick 		done(1);
2236844Smckusick 	}
2246844Smckusick 	/*
2256844Smckusick 	 * should be!!!
2266844Smckusick 	 *
2276844Smckusick 	fssize = stbuf.st_blksize;
2286844Smckusick 	 */
2296844Smckusick 	fssize = MAXBSIZE;
2304837Smckusic 	if (readhdr(&spcl) == 0) {
2314837Smckusic 		fprintf(stderr, "Tape is not a dump tape\n");
2324837Smckusic 		done(1);
2334837Smckusic 	}
2344837Smckusic 	if (checkvol(&spcl, 1) == 0) {
2354837Smckusic 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
2364837Smckusic 	}
2376844Smckusick 	clrimap = 0;
2386844Smckusick 	dumpmap = 0;
2395038Smckusic 	pass1(1);  /* This sets the various maps on the way by */
2404843Smckusic 	while (argc--) {
2414837Smckusic 		if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
2426844Smckusick 			printf("d = %d\n", d);
2434843Smckusic 			fprintf(stdout, "%s: not on tape\n", *argv++);
2444837Smckusic 			continue;
2454610Smckusick 		}
2464843Smckusic 		if (mflag)
2474843Smckusic 			checkdir(*argv);
2484837Smckusic 		if(hflag)
2494837Smckusic 			getleaves(d, *argv++);
2504843Smckusic 		else
2514843Smckusic 			allocxtr(d, *argv++, XINUSE);
2524837Smckusic 	}
2534843Smckusic 	if (dumpnum > 1) {
2545038Smckusic 		/*
2555038Smckusic 		 * if this is a multi-dump tape we always start with
2565038Smckusic 		 * volume 1, so as to avoid accidentally restoring
2575038Smckusic 		 * from a different dump!
2585038Smckusic 		 */
2595038Smckusic 		resetmt();
2605038Smckusic 		dumpnum = 1;
2615038Smckusic 		volno = 1;
2625038Smckusic 		readhdr(&spcl);
2635038Smckusic 		goto rbits;
2644837Smckusic 	}
2655038Smckusic newvol:
2665038Smckusic 	resetmt();
2674610Smckusick getvol:
2685038Smckusic 	fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
2694837Smckusic 	if (gets(tbf) == NULL)
2704837Smckusic 		return;
2714837Smckusic 	volno = atoi(tbf);
2724837Smckusic 	if (volno <= 0) {
2734837Smckusic 		fprintf(stderr, "Volume numbers are positive numerics\n");
2744837Smckusic 		goto getvol;
2754837Smckusic 	}
2764837Smckusic 	if (readhdr(&spcl) == 0) {
2774837Smckusic 		fprintf(stderr, "tape is not dump tape\n");
2784837Smckusic 		goto newvol;
2794837Smckusic 	}
2804837Smckusic 	if (checkvol(&spcl, volno) == 0) {
2814837Smckusic 		fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
2824837Smckusic 		goto newvol;
2834837Smckusic 	}
2844610Smckusick rbits:
2854837Smckusic 	while (gethead(&spcl) == 0)
2864837Smckusic 		;
2874837Smckusic 	if (checktype(&spcl, TS_INODE) == 1) {
2884837Smckusic 		fprintf(stderr, "Can't find inode mask!\n");
2894837Smckusic 		goto newvol;
2904837Smckusic 	}
2914837Smckusic 	if (checktype(&spcl, TS_BITS) == 0)
2924837Smckusic 		goto rbits;
2936844Smckusick 	readbits(&dumpmap);
2944837Smckusic 	while (xtrcnt > 0) {
2954837Smckusic again:
2966845Smckusick 		if (ishead(&spcl) == 0) {
2976845Smckusick 			i = 0;
2984837Smckusic 			while(gethead(&spcl) == 0)
2996845Smckusick 				i++;
3006845Smckusick 			fprintf(stderr, "resync restor, skipped %i blocks\n",
3016845Smckusick 			    i);
3026845Smckusick 		}
3034837Smckusic 		if (checktype(&spcl, TS_END) == 1) {
3044837Smckusic 			fprintf(stderr, "end of tape\n");
3054837Smckusic 			break;
3064610Smckusick 		}
3074837Smckusic 		if (checktype(&spcl, TS_INODE) == 0) {
3084837Smckusic 			gethead(&spcl);
3094837Smckusic 			goto again;
3104610Smckusick 		}
3114837Smckusic 		d = spcl.c_inumber;
3124837Smckusic 		for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
3134837Smckusic 			if (d != xp->x_ino)
3144837Smckusic 				continue;
3154837Smckusic 			if (xp->x_flags & XLINKED)
3164837Smckusic 				continue;
3174837Smckusic 			xp->x_timep[0] = spcl.c_dinode.di_atime;
3184837Smckusic 			xp->x_timep[1] = spcl.c_dinode.di_mtime;
3194837Smckusic 			mode = spcl.c_dinode.di_mode;
3204837Smckusic 			if (mflag)
3214843Smckusic 				strcpy(name, xp->x_name);
3224837Smckusic 			else
3234837Smckusic 				sprintf(name, "%u", xp->x_ino);
3244837Smckusic 			switch (mode & IFMT) {
3254837Smckusic 			default:
3264843Smckusic 				fprintf(stderr, "%s: unknown file type\n", name);
3274837Smckusic 				xp->x_flags |= XTRACTD;
3284837Smckusic 				xtrcnt--;
3294837Smckusic 				goto skipfile;
3304837Smckusic 			case IFCHR:
3314837Smckusic 			case IFBLK:
3324843Smckusic 				fprintf(stdout, "extract special file %s\n", name);
3336844Smckusick 				if (mknod(name, mode, spcl.c_dinode.di_rdev)) {
3344837Smckusic 					fprintf(stderr, "%s: cannot create special file\n", name);
3354837Smckusic 					xp->x_flags |= XTRACTD;
3364837Smckusic 					xtrcnt--;
3374837Smckusic 					goto skipfile;
3384776Smckusic 				}
3394837Smckusic 				getfile(null, null, spcl.c_dinode.di_size);
3404837Smckusic 				break;
3414837Smckusic 			case IFDIR:
3424837Smckusic 				if (mflag) {
3434843Smckusic 					fprintf(stdout, "extract directory %s\n", name);
3444837Smckusic 					strncat(name, "/.", BUFSIZ);
3454843Smckusic 					checkdir(name);
3466844Smckusick 					chown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
3474837Smckusic 					getfile(null, null, spcl.c_dinode.di_size);
3484837Smckusic 					break;
3494610Smckusick 				}
3505038Smckusic 				fprintf(stdout, "extract file %s\n", name);
3516844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
3525038Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
3535038Smckusic 					xp->x_flags |= XTRACTD;
3545038Smckusic 					xtrcnt--;
3555038Smckusic 					goto skipfile;
3565038Smckusic 				}
3576844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
3585943Smckusic 				if (cvtdir) {
3595038Smckusic 					getfile(xtrcvtdir, xtrcvtskip,
3605038Smckusic 					    spcl.c_dinode.di_size);
3615943Smckusic 					flushent(xtrfile);
3625943Smckusic 				} else
3635038Smckusic 					getfile(xtrfile, xtrskip,
3645038Smckusic 					    spcl.c_dinode.di_size);
3656844Smckusick 				close(ofile);
3665038Smckusic 				break;
3676289Smckusick 			case IFLNK:
3686289Smckusick 				fprintf(stdout, "extract symbolic link %s\n", name);
3696289Smckusick 				uid = spcl.c_dinode.di_uid;
3706289Smckusick 				gid = spcl.c_dinode.di_gid;
3716289Smckusick 				lnkbuf[0] = '\0';
3726289Smckusick 				pathlen = 0;
3736289Smckusick 				getfile(xtrlnkfile, xtrlnkskip, spcl.c_dinode.di_size);
3746844Smckusick 				if (symlink(lnkbuf, name) < 0) {
3756289Smckusick 					fprintf(stderr, "%s: cannot create symbolic link\n", name);
3766289Smckusick 					xp->x_flags |= XTRACTD;
3776289Smckusick 					xtrcnt--;
3786289Smckusick 					goto finished;
3796289Smckusick 				}
3806844Smckusick 				chown(name, uid, gid);
3816289Smckusick 				break;
3824837Smckusic 			case IFREG:
3834843Smckusic 				fprintf(stdout, "extract file %s\n", name);
3846844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
3854837Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
3864837Smckusic 					xp->x_flags |= XTRACTD;
3874837Smckusic 					xtrcnt--;
3884837Smckusic 					goto skipfile;
3894837Smckusic 				}
3906844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
3915038Smckusic 				getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
3926844Smckusick 				close(ofile);
3934837Smckusic 				break;
3944610Smckusick 			}
3956844Smckusick 			chmod(name, mode);
3966844Smckusick 			utime(name, xp->x_timep);
3974837Smckusic 			xp->x_flags |= XTRACTD;
3984837Smckusic 			xtrcnt--;
3994837Smckusic 			goto finished;
4004837Smckusic 		}
4014837Smckusic skipfile:
4024837Smckusic 		getfile(null, null, spcl.c_dinode.di_size);
4034700Smckusic finished:
4044837Smckusic 		;
4054837Smckusic 	}
4064837Smckusic 	if (xtrcnt == 0 && !mflag)
4074837Smckusic 		return;
4084837Smckusic 	for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
4094837Smckusic 		for (xp = *xpp; xp; xp = xp->x_next) {
4104837Smckusic 			if (mflag && (xp->x_flags & XISDIR))
4116844Smckusick 				utime(xp->x_name, xp->x_timep);
4124837Smckusic 			if (xp->x_flags & XTRACTD)
4134837Smckusic 				continue;
4144837Smckusic 			if ((xp->x_flags & XLINKED) == 0) {
4154837Smckusic 				fprintf(stderr, "cannot find file %s\n",
4164837Smckusic 					xp->x_name);
4174837Smckusic 				continue;
4184837Smckusic 			}
4194843Smckusic 			if (!mflag)
4204843Smckusic 				continue;
4214843Smckusic 			fprintf(stdout, "link %s to %s\n",
4224843Smckusic 				xp->x_linkedto->x_name, xp->x_name);
4236844Smckusick 			if (link(xp->x_linkedto->x_name, xp->x_name) < 0)
4244843Smckusic 				fprintf(stderr, "link %s to %s failed\n",
4254837Smckusic 					xp->x_linkedto->x_name, xp->x_name);
4264610Smckusick 		}
4274837Smckusic 	}
4284837Smckusic }
4294837Smckusic 
4304610Smckusick /*
4314610Smckusick  * Read the tape, bulding up a directory structure for extraction
4324610Smckusick  * by name
4334610Smckusick  */
4345038Smckusic pass1(savedir)
4355038Smckusic 	int savedir;
4364610Smckusick {
4374776Smckusic 	register int i;
4384837Smckusic 	register struct dinode *ip;
4394837Smckusic 	struct direct nulldir;
4405038Smckusic 	char buf[TP_BSIZE];
4415943Smckusic 	int putdir(), null(), dirwrite();
4424610Smckusick 
4435943Smckusic 	nulldir.d_ino = 1;
4445943Smckusic 	nulldir.d_namlen = 1;
4455943Smckusic 	strncpy(nulldir.d_name, "/", nulldir.d_namlen);
4465943Smckusic 	nulldir.d_reclen = DIRSIZ(&nulldir);
4474610Smckusick 	while (gethead(&spcl) == 0) {
4484700Smckusic 		fprintf(stderr, "Can't find directory header!\n");
4494610Smckusick 	}
4504610Smckusick 	for (;;) {
4514610Smckusick 		if (checktype(&spcl, TS_BITS) == 1) {
4526844Smckusick 			readbits(&dumpmap);
4534610Smckusick 			continue;
4544610Smckusick 		}
4554610Smckusick 		if (checktype(&spcl, TS_CLRI) == 1) {
4566844Smckusick 			readbits(&clrimap);
4574610Smckusick 			continue;
4584610Smckusick 		}
4594610Smckusick 		if (checktype(&spcl, TS_INODE) == 0) {
4604610Smckusick finish:
4615943Smckusic 			if (savedir) {
4625943Smckusic 				fclose(df);
4635943Smckusic 				dirp = opendir(dirfile);
4645943Smckusic 				if (dirp == NULL)
4655943Smckusic 					perror("opendir");
4665943Smckusic 			}
4675038Smckusic 			resetmt();
4684610Smckusick 			return;
4694610Smckusick 		}
4704610Smckusick 		ip = &spcl.c_dinode;
4714610Smckusick 		i = ip->di_mode & IFMT;
4724610Smckusick 		if (i != IFDIR) {
4734610Smckusick 			goto finish;
4744610Smckusick 		}
4755038Smckusic 		if (spcl.c_inumber == ROOTINO) {
4765038Smckusic 			readtape(buf);
4775038Smckusic 			bct--; /* push back this block */
4785038Smckusic 			if (((struct direct *)buf)->d_ino != ROOTINO) {
4795038Smckusic 				if (((struct odirect *)buf)->d_ino != ROOTINO) {
4805038Smckusic 					fprintf(stderr, "bad root directory\n");
4815038Smckusic 					done(1);
4825038Smckusic 				}
4835038Smckusic 				fprintf(stderr, "converting to new directory format\n");
4845038Smckusic 				cvtdir = 1;
4855038Smckusic 			}
4865038Smckusic 			if (!savedir && !cvtdir) {
4875038Smckusic 				/* if no conversion, just return */
4885038Smckusic 				goto finish;
4895038Smckusic 			}
4905038Smckusic 		}
4914843Smckusic 		allocinotab(spcl.c_inumber, seekpt);
4925038Smckusic 		if (savedir) {
4935038Smckusic 			getfile(putdir, null, spcl.c_dinode.di_size);
4945943Smckusic 			putent(&nulldir, dirwrite);
4955943Smckusic 			flushent(dirwrite);
4965038Smckusic 		} else {
4975038Smckusic 			getfile(null, null, spcl.c_dinode.di_size);
4985038Smckusic 		}
4994610Smckusick 	}
5004610Smckusick }
5014610Smckusick 
5024610Smckusick /*
5034843Smckusic  * Put the directory entries in the directory file
5044843Smckusic  */
5054843Smckusic putdir(buf, size)
5064843Smckusic 	char *buf;
5074843Smckusic 	int size;
5084843Smckusic {
5095038Smckusic 	struct direct cvtbuf;
5105038Smckusic 	register struct odirect *odp;
5115038Smckusic 	struct odirect *eodp;
5124843Smckusic 	register struct direct *dp;
5136289Smckusick 	long loc, i;
5144843Smckusic 
5155038Smckusic 	if (cvtdir) {
5165038Smckusic 		eodp = (struct odirect *)&buf[size];
5175038Smckusic 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
5185038Smckusic 			if (odp->d_ino != 0) {
5195038Smckusic 				dcvt(odp, &cvtbuf);
5205943Smckusic 				putent(&cvtbuf, dirwrite);
5215038Smckusic 			}
5225038Smckusic 	} else {
5235943Smckusic 		for (loc = 0; loc < size; ) {
5245943Smckusic 			dp = (struct direct *)(buf + loc);
5256289Smckusick 			i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
5266289Smckusick 			if (dp->d_reclen <= 0 || dp->d_reclen > i) {
5276289Smckusick 				loc += i;
5286289Smckusick 				continue;
5296289Smckusick 			}
5306289Smckusick 			loc += dp->d_reclen;
5315038Smckusic 			if (dp->d_ino != 0)
5325943Smckusic 				putent(dp, dirwrite);
5335943Smckusic 		}
5345038Smckusic 	}
5354843Smckusic }
5364843Smckusic 
5374843Smckusic /*
5384843Smckusic  *	Recursively find names and inumbers of all files in subtree
5394843Smckusic  *	pname and put them in xtrlist[]
5404843Smckusic  */
5414843Smckusic getleaves(ino, pname)
5424843Smckusic 	ino_t ino;
5434843Smckusic 	char *pname;
5444843Smckusic {
5454843Smckusic 	register struct inotab *itp;
5464843Smckusic 	int namelen;
547*6846Smckusick 	daddr_t bpt;
5485943Smckusic 	register struct direct *dp;
5495943Smckusic 	char locname[BUFSIZ + 1];
5504843Smckusic 
5514843Smckusic 	if (BIT(ino, dumpmap) == 0) {
5524843Smckusic 		fprintf(stdout, "%s: not on the tape\n", pname);
5534843Smckusic 		return;
5544843Smckusic 	}
5554843Smckusic 	for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
5564843Smckusic 		if (itp->t_ino != ino)
5574843Smckusic 			continue;
5584843Smckusic 		/*
5594843Smckusic 		 * pname is a directory name
5604843Smckusic 		 */
5614843Smckusic 		allocxtr(ino, pname, XISDIR);
5624843Smckusic 		/*
5634843Smckusic 		 * begin search through the directory
5644843Smckusic 		 * skipping over "." and ".."
5654843Smckusic 		 */
5664843Smckusic 		strncpy(locname, pname, BUFSIZ);
5674843Smckusic 		strncat(locname, "/", BUFSIZ);
5684843Smckusic 		namelen = strlen(locname);
5695943Smckusic 		seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
5705943Smckusic 		dp = readdir(dirp);
5715943Smckusic 		dp = readdir(dirp);
5725943Smckusic 		dp = readdir(dirp);
5735943Smckusic 		bpt = telldir(dirp);
5744843Smckusic 		/*
5754843Smckusic 		 * "/" signals end of directory
5764843Smckusic 		 */
5775943Smckusic 		while (dp->d_namlen != 1 || dp->d_name[0] != '/') {
5784843Smckusic 			locname[namelen] = '\0';
5795943Smckusic 			if (namelen + dp->d_namlen >= BUFSIZ) {
5805943Smckusic 				fprintf(stderr, "%s%s: name exceedes %d char\n",
5815943Smckusic 					locname, dp->d_name, BUFSIZ);
5824843Smckusic 				continue;
5834843Smckusic 			}
5845943Smckusic 			strncat(locname, dp->d_name, dp->d_namlen);
5855943Smckusic 			getleaves(dp->d_ino, locname);
5865943Smckusic 			seekdir(dirp, bpt, itp->t_seekpt);
5875943Smckusic 			dp = readdir(dirp);
5885943Smckusic 			bpt = telldir(dirp);
5894843Smckusic 		}
5904843Smckusic 		return;
5914843Smckusic 	}
5924843Smckusic 	/*
5934843Smckusic 	 * locname is name of a simple file
5944843Smckusic 	 */
5954843Smckusic 	allocxtr(ino, pname, XINUSE);
5964843Smckusic }
5974843Smckusic 
5984843Smckusic /*
5994843Smckusic  * Search the directory tree rooted at inode ROOTINO
6004843Smckusic  * for the path pointed at by n
6014843Smckusic  */
6024843Smckusic psearch(n)
6034843Smckusic 	char	*n;
6044843Smckusic {
6054843Smckusic 	register char *cp, *cp1;
6064843Smckusic 	char c;
6074843Smckusic 
6084843Smckusic 	ino = ROOTINO;
6094843Smckusic 	if (*(cp = n) == '/')
6104843Smckusic 		cp++;
6114843Smckusic next:
6124843Smckusic 	cp1 = cp + 1;
6134843Smckusic 	while (*cp1 != '/' && *cp1)
6144843Smckusic 		cp1++;
6154843Smckusic 	c = *cp1;
6164843Smckusic 	*cp1 = 0;
6174843Smckusic 	ino = search(ino, cp);
6184843Smckusic 	if (ino == 0) {
6194843Smckusic 		*cp1 = c;
6204843Smckusic 		return(0);
6214843Smckusic 	}
6224843Smckusic 	*cp1 = c;
6234843Smckusic 	if (c == '/') {
6244843Smckusic 		cp = cp1+1;
6254843Smckusic 		goto next;
6264843Smckusic 	}
6274843Smckusic 	return(ino);
6284843Smckusic }
6294843Smckusic 
6304843Smckusic /*
6314843Smckusic  * search the directory inode ino
6324843Smckusic  * looking for entry cp
6334843Smckusic  */
6344843Smckusic ino_t
6354843Smckusic search(inum, cp)
6364843Smckusic 	ino_t	inum;
6374843Smckusic 	char	*cp;
6384843Smckusic {
6395943Smckusic 	register struct direct *dp;
6404843Smckusic 	register struct inotab *itp;
6415943Smckusic 	int len;
6424843Smckusic 
6434843Smckusic 	for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
6444843Smckusic 		if (itp->t_ino == inum)
6454843Smckusic 			goto found;
6464843Smckusic 	return(0);
6474843Smckusic found:
6485943Smckusic 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
6495943Smckusic 	len = strlen(cp);
6504843Smckusic 	do {
6515943Smckusic 		dp = readdir(dirp);
6525943Smckusic 		if (dp->d_namlen == 1 && dp->d_name[0] == '/')
6534843Smckusic 			return(0);
6545943Smckusic 	} while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
6555943Smckusic 	return(dp->d_ino);
6564843Smckusic }
6574843Smckusic 
6584843Smckusic /*
6594610Smckusick  * Do the file extraction, calling the supplied functions
6604610Smckusick  * with the blocks
6614610Smckusick  */
6624700Smckusic getfile(f1, f2, size)
6634700Smckusic 	int	(*f2)(), (*f1)();
664*6846Smckusick 	off_t	size;
6654610Smckusick {
6664776Smckusic 	register int i;
6675327Smckusic 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
6684837Smckusic 	union u_spcl addrblk;
6694837Smckusic #	define addrblock addrblk.s_spcl
6704610Smckusick 
6714837Smckusic 	addrblock = spcl;
6724610Smckusick 	for (;;) {
6734837Smckusic 		for (i = 0; i < addrblock.c_count; i++) {
6744837Smckusic 			if (addrblock.c_addr[i]) {
6754776Smckusic 				readtape(&buf[curblk++][0]);
6766844Smckusick 				if (curblk == fssize / TP_BSIZE) {
6774776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
6786844Smckusick 					     (long) (fssize) :
6794776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
6804776Smckusic 					curblk = 0;
6814776Smckusic 				}
6825327Smckusic 			} else {
6834776Smckusic 				if (curblk > 0) {
6844776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
6854776Smckusic 					     (long) (curblk * TP_BSIZE) :
6864776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
6874776Smckusic 					curblk = 0;
6884776Smckusic 				}
6895327Smckusic 				(*f2)(clearedbuf, size > TP_BSIZE ?
6905327Smckusic 					(long) TP_BSIZE : size);
6914610Smckusick 			}
6924776Smckusic 			if ((size -= TP_BSIZE) <= 0) {
6934610Smckusick eloop:
6944610Smckusick 				while (gethead(&spcl) == 0)
6954610Smckusick 					;
6964610Smckusick 				if (checktype(&spcl, TS_ADDR) == 1)
6974610Smckusick 					goto eloop;
6984776Smckusic 				goto out;
6994610Smckusick 			}
7004610Smckusick 		}
7014837Smckusic 		if (gethead(&addrblock) == 0) {
7024776Smckusic 			fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
7034700Smckusic 			goto eloop;
7044700Smckusic 		}
7054837Smckusic 		if (checktype(&addrblock, TS_ADDR) == 0) {
7064837Smckusic 			spcl = addrblock;
7074776Smckusic 			goto out;
7084700Smckusic 		}
7094610Smckusick 	}
7104776Smckusic out:
7114776Smckusic 	if (curblk > 0) {
7124776Smckusic 		(*f1)(buf, (curblk * TP_BSIZE) + size);
7134776Smckusic 		curblk = 0;
7144776Smckusic 	}
7154610Smckusick }
7164610Smckusick 
7174610Smckusick /*
7184843Smckusic  * The next routines are called during file extraction to
7194843Smckusic  * put the data into the right form and place.
7204843Smckusic  */
7214843Smckusic xtrfile(buf, size)
7224843Smckusic 	char	*buf;
7234843Smckusic 	long	size;
7244843Smckusic {
7256844Smckusick 	if (write(ofile, buf, (int) size) == -1) {
7265038Smckusic 		perror("extract write");
7274843Smckusic 		done(1);
7284843Smckusic 	}
7294843Smckusic }
7304843Smckusic 
7315038Smckusic xtrskip(buf, size)
7324843Smckusic 	char *buf;
7334843Smckusic 	long size;
7344843Smckusic {
735*6846Smckusick #ifdef lint
736*6846Smckusick 	buf = buf;
737*6846Smckusick #endif
7386844Smckusick 	if (lseek(ofile, size, 1) == -1) {
7395038Smckusic 		perror("extract seek");
7404843Smckusic 		done(1);
7414843Smckusic 	}
7424843Smckusic }
7435038Smckusic 
7445038Smckusic xtrcvtdir(buf, size)
7455038Smckusic 	struct odirect *buf;
7465038Smckusic 	long size;
7475038Smckusic {
7485038Smckusic 	struct odirect *odp, *edp;
749*6846Smckusick 	struct direct cvtbuf;
7505038Smckusic 
7515038Smckusic 	edp = &buf[size / sizeof(struct odirect)];
7525943Smckusic 	for (odp = buf; odp < edp; odp++) {
7535943Smckusic 		dcvt(odp, &cvtbuf);
7545943Smckusic 		putent(&cvtbuf, xtrfile);
7555038Smckusic 	}
7565038Smckusic }
7575038Smckusic 
7585038Smckusic xtrcvtskip(buf, size)
7595038Smckusic 	char *buf;
7605038Smckusic 	long size;
7615038Smckusic {
7625038Smckusic 	fprintf(stderr, "unallocated block in directory\n");
7635943Smckusic 	xtrskip(buf, size);
7645038Smckusic }
7656289Smckusick 
7666289Smckusick xtrlnkfile(buf, size)
7676289Smckusick 	char	*buf;
7686289Smckusick 	long	size;
7696289Smckusick {
7706289Smckusick 	pathlen += size;
7716289Smckusick 	if (pathlen > MAXPATHLEN) {
7726289Smckusick 		fprintf(stderr, "symbolic link name: %s; too long %d\n",
7736289Smckusick 		    buf, size);
7746289Smckusick 		done(1);
7756289Smckusick 	}
7766289Smckusick 	strcat(lnkbuf, buf);
7776289Smckusick }
7786289Smckusick 
7796289Smckusick xtrlnkskip(buf, size)
7806289Smckusick 	char *buf;
7816289Smckusick 	long size;
7826289Smckusick {
783*6846Smckusick #ifdef lint
784*6846Smckusick 	buf = buf, size = size;
785*6846Smckusick #endif
7866289Smckusick 	fprintf(stderr, "unallocated block in symbolic link\n");
7876289Smckusick 	done(1);
7886289Smckusick }
7894843Smckusic 
7904843Smckusic null() {;}
7914843Smckusic 
7924843Smckusic /*
7934776Smckusic  * Do the tape i/o, dealing with volume changes
7944610Smckusick  * etc..
7954610Smckusick  */
7964610Smckusick readtape(b)
7974700Smckusic 	char *b;
7984610Smckusick {
799*6846Smckusick 	register long i;
8004837Smckusic 	struct s_spcl tmpbuf;
8016845Smckusick 	char c;
8024610Smckusick 
8034610Smckusick 	if (bct >= NTREC) {
8044610Smckusick 		for (i = 0; i < NTREC; i++)
8054776Smckusic 			((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
8064610Smckusick 		bct = 0;
8074776Smckusic 		if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
8086845Smckusick 			fprintf(stderr, "Tape read error, continue?");
8096845Smckusick 			do	{
8106845Smckusick 				fprintf(stderr, "[yn]\n");
8116845Smckusick 				c = getchar();
8126845Smckusick 				while (getchar() != '\n')
8136845Smckusick 					/* void */;
8146845Smckusick 			} while (c != 'y' && c != 'n');
8154610Smckusick 			eflag++;
8166845Smckusick 			if (c == 'n')
8176845Smckusick 				done(1);
8186845Smckusick 			i = NTREC*TP_BSIZE;
8196845Smckusick 			blkclr(tbf, i);
820*6846Smckusick 			if (lseek(mt, i, 1) < 0) {
821*6846Smckusick 				fprintf(stderr, "continuation failed\n");
822*6846Smckusick 				done(1);
823*6846Smckusick 			}
8244610Smckusick 		}
8254610Smckusick 		if (i == 0) {
8264610Smckusick 			bct = NTREC + 1;
8274610Smckusick 			volno++;
8284610Smckusick loop:
8294610Smckusick 			flsht();
8304610Smckusick 			close(mt);
8314700Smckusic 			fprintf(stderr, "Mount volume %d\n", volno);
8324610Smckusick 			while (getchar() != '\n')
8334610Smckusick 				;
8344610Smckusick 			if ((mt = open(magtape, 0)) == -1) {
8354700Smckusic 				fprintf(stderr, "Cannot open tape!\n");
8364610Smckusick 				goto loop;
8374610Smckusick 			}
8384610Smckusick 			if (readhdr(&tmpbuf) == 0) {
8394700Smckusic 				fprintf(stderr, "Not a dump tape.Try again\n");
8404610Smckusick 				goto loop;
8414610Smckusick 			}
8424610Smckusick 			if (checkvol(&tmpbuf, volno) == 0) {
8434700Smckusic 				fprintf(stderr, "Wrong tape. Try again\n");
8444610Smckusick 				goto loop;
8454610Smckusick 			}
8464610Smckusick 			readtape(b);
8474610Smckusick 			return;
8484610Smckusick 		}
8494610Smckusick 	}
850*6846Smckusick 	blkcpy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
8514610Smckusick }
8524610Smckusick 
8534610Smckusick flsht()
8544610Smckusick {
8554610Smckusick 	bct = NTREC+1;
8564610Smckusick }
8574610Smckusick 
8585943Smckusic blkcpy(from, to, size)
8595943Smckusic 	char *from, *to;
860*6846Smckusick 	long size;
8614610Smckusick {
862*6846Smckusick #ifdef lint
863*6846Smckusick 	from = from, to = to, size = size;
864*6846Smckusick #endif
8655943Smckusic 	asm("	movc3	12(ap),*4(ap),*8(ap)");
8664610Smckusick }
8674610Smckusick 
8685038Smckusic blkclr(buf, size)
8695038Smckusic 	char *buf;
870*6846Smckusick 	long size;
8715038Smckusic {
872*6846Smckusick #ifdef lint
873*6846Smckusick 	buf = buf, size = size;
874*6846Smckusick #endif
8755038Smckusic 	asm("movc5	$0,(r0),$0,8(ap),*4(ap)");
8765038Smckusic }
8775038Smckusic 
8785038Smckusic resetmt()
8795038Smckusic {
8805038Smckusic 	struct mtop tcom;
8815038Smckusic 
8825038Smckusic 	if(dumpnum > 1)
8835038Smckusic 		tcom.mt_op = MTBSF;
8845038Smckusic 	else
8855038Smckusic 		tcom.mt_op = MTREW;
8865038Smckusic 	tcom.mt_count = 1;
8875038Smckusic 	flsht();
8885038Smckusic 	if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
8895038Smckusic 		/* kludge for disk dumps */
8905038Smckusic 		lseek(mt, (long)0, 0);
8915038Smckusic 	}
8925038Smckusic 	if (dumpnum > 1) {
8935038Smckusic 		tcom.mt_op = MTFSF;
8945038Smckusic 		tcom.mt_count = 1;
8955038Smckusic 		ioctl(mt,MTIOCTOP,&tcom);
8965038Smckusic 	}
8975038Smckusic }
8985038Smckusic 
8994843Smckusic checkvol(b, t)
9004843Smckusic 	struct s_spcl *b;
9014843Smckusic 	int t;
9024610Smckusick {
9034843Smckusic 	if (b->c_volume == t)
9044843Smckusic 		return(1);
9054610Smckusick 	return(0);
9064610Smckusick }
9074610Smckusick 
9084843Smckusic readhdr(b)
9094843Smckusic 	struct s_spcl *b;
9104610Smckusick {
9114843Smckusic 	if (gethead(b) == 0)
9124610Smckusick 		return(0);
9134843Smckusic 	if (checktype(b, TS_TAPE) == 0)
9144843Smckusic 		return(0);
9154843Smckusic 	return(1);
9164610Smckusick }
9174610Smckusick 
9184610Smckusick /*
9194610Smckusick  * read the tape into buf, then return whether or
9204610Smckusick  * or not it is a header block.
9214610Smckusick  */
9224610Smckusick gethead(buf)
9234837Smckusic 	struct s_spcl *buf;
9244610Smckusick {
9254610Smckusick 	readtape((char *)buf);
9264837Smckusic 	if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
9274610Smckusick 		return(0);
9284610Smckusick 	return(1);
9294610Smckusick }
9304610Smckusick 
9314610Smckusick /*
9324610Smckusick  * return whether or not the buffer contains a header block
9334610Smckusick  */
9344610Smckusick ishead(buf)
9354837Smckusic 	struct s_spcl *buf;
9364610Smckusick {
9374837Smckusic 	if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
9384610Smckusick 		return(0);
9394610Smckusick 	return(1);
9404610Smckusick }
9414610Smckusick 
9424610Smckusick checktype(b, t)
9434837Smckusic 	struct s_spcl *b;
9444700Smckusic 	int	t;
9454610Smckusick {
9464837Smckusic 	return(b->c_type == t);
9474610Smckusick }
9484610Smckusick 
9495038Smckusic /*
9505038Smckusic  * read a bit mask from the tape into m.
9515038Smckusic  */
9526844Smckusick readbits(mapp)
9536844Smckusick 	char **mapp;
9545038Smckusic {
9555038Smckusic 	register int i;
9566844Smckusick 	char	*m;
9574610Smckusick 
9585038Smckusic 	i = spcl.c_count;
9595038Smckusic 
9606844Smckusick 	if (*mapp == 0)
961*6846Smckusick 		*mapp = (char *)calloc(i, (TP_BSIZE/(NBBY/BITS)));
9626844Smckusick 	m = *mapp;
9635038Smckusic 	while (i--) {
9645038Smckusic 		readtape((char *) m);
9655327Smckusic 		m += (TP_BSIZE/(NBBY/BITS));
9665038Smckusic 	}
9675038Smckusic 	while (gethead(&spcl) == 0)
9685038Smckusic 		;
9695038Smckusic }
9705038Smckusic 
9714610Smckusick checksum(b)
9724700Smckusic 	int *b;
9734610Smckusick {
9744776Smckusic 	register int i, j;
9754610Smckusick 
9764776Smckusic 	j = sizeof(union u_spcl) / sizeof(int);
9774610Smckusick 	i = 0;
9784610Smckusick 	do
9794610Smckusick 		i += *b++;
9804610Smckusick 	while (--j);
9814610Smckusick 	if (i != CHECKSUM) {
9824776Smckusic 		fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
9834610Smckusick 		return(0);
9844610Smckusick 	}
9854610Smckusick 	return(1);
9864610Smckusick }
9874610Smckusick 
9884610Smckusick /*
9895038Smckusic  *	Check for access into each directory in the pathname of an extracted
9905038Smckusic  *	file and create such a directory if needed in preparation for moving
9915038Smckusic  *	the file to its proper home.
9925038Smckusic  */
9935038Smckusic checkdir(name)
9945038Smckusic 	register char *name;
9955038Smckusic {
9965038Smckusic 	register char *cp;
9975038Smckusic 	int i;
9985038Smckusic 
9995038Smckusic 	for (cp = name; *cp; cp++) {
10005038Smckusic 		if (*cp == '/') {
10015038Smckusic 			*cp = '\0';
10026844Smckusick 			if (access(name, 01) < 0) {
10035038Smckusic 				register int pid, rp;
10045038Smckusic 
10055038Smckusic 				if ((pid = fork()) == 0) {
10066844Smckusick 					execl("/bin/mkdir", "mkdir", name, 0);
10076844Smckusick 					execl("/usr/bin/mkdir", "mkdir", name, 0);
10086844Smckusick 					fprintf(stderr, "restor: cannot find mkdir!\n");
10095038Smckusic 					done(0);
10105038Smckusic 				}
10115038Smckusic 				while ((rp = wait(&i)) >= 0 && rp != pid)
10125038Smckusic 					;
10135038Smckusic 			}
10145038Smckusic 			*cp = '/';
10155038Smckusic 		}
10165038Smckusic 	}
10175038Smckusic }
10185038Smckusic 
10196844Smckusick setdir(dev)
10206844Smckusick 	char *dev;
10216844Smckusick {
10226844Smckusick 	struct fstab *fsp;
10236844Smckusick 
10246844Smckusick 	if (setfsent() == 0) {
10256844Smckusick 		fprintf(stderr, "Can't open checklist file: %s\n", FSTAB);
10266844Smckusick 		done(1);
10276844Smckusick 	}
10286844Smckusick 	while ((fsp = getfsent()) != 0) {
10296844Smckusick 		if (strcmp(fsp->fs_spec, dev) == 0) {
10306844Smckusick 			printf("%s mounted on %s\n", dev, fsp->fs_file);
10316844Smckusick 			if (chdir(fsp->fs_file) >= 0)
10326844Smckusick 				return;
10336844Smckusick 			fprintf(stderr, "%s cannot chdir to %s\n",
10346844Smckusick 			    fsp->fs_file);
10356844Smckusick 			done(1);
10366844Smckusick 		}
10376844Smckusick 	}
10386844Smckusick 	fprintf(stderr, "%s not mounted\n", dev);
10396844Smckusick 	done(1);
10406844Smckusick }
10416844Smckusick 
10425038Smckusic /*
10435943Smckusic  * These variables are "local" to the following two functions.
10445943Smckusic  */
10455943Smckusic char dirbuf[DIRBLKSIZ];
10465943Smckusic long dirloc = 0;
10475943Smckusic long prev = 0;
10485943Smckusic 
10495943Smckusic /*
10505943Smckusic  * add a new directory entry to a file.
10515943Smckusic  */
10525943Smckusic putent(dp, wrtfunc)
10535943Smckusic 	struct direct *dp;
10545943Smckusic 	int (*wrtfunc)();
10555943Smckusic {
10565943Smckusic 	if (dp->d_ino == 0)
10575943Smckusic 		return;
10585943Smckusic 	for (;;) {
10595943Smckusic 		if (dp->d_reclen < DIRBLKSIZ - dirloc) {
1060*6846Smckusick 			blkcpy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
10615943Smckusic 			prev = dirloc;
10625943Smckusic 			dirloc += dp->d_reclen;
10635943Smckusic 			return;
10645943Smckusic 		}
10655943Smckusic 		((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
10665943Smckusic 		(*wrtfunc)(dirbuf, DIRBLKSIZ);
10675943Smckusic 		dirloc = 0;
10685943Smckusic 	}
10695943Smckusic }
10705943Smckusic 
10715943Smckusic /*
10725943Smckusic  * flush out a directory that is finished.
10735943Smckusic  */
10745943Smckusic flushent(wrtfunc)
10755943Smckusic 	int (*wrtfunc)();
10765943Smckusic {
10775943Smckusic 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
10785943Smckusic 	(*wrtfunc)(dirbuf, dirloc);
10795943Smckusic 	dirloc = 0;
10805943Smckusic }
10815943Smckusic 
10825943Smckusic dirwrite(buf, size)
10835943Smckusic 	char *buf;
10845943Smckusic 	int size;
10855943Smckusic {
10865943Smckusic 	fwrite(buf, 1, size, df);
10875943Smckusic 	seekpt = ftell(df);
10885943Smckusic }
10895943Smckusic 
10905943Smckusic dcvt(odp, ndp)
10915943Smckusic 	register struct odirect *odp;
10925943Smckusic 	register struct direct *ndp;
10935943Smckusic {
1094*6846Smckusick 	blkclr((char *)ndp, (long)(sizeof *ndp));
10955943Smckusic 	ndp->d_ino =  odp->d_ino;
10965943Smckusic 	strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
10975943Smckusic 	ndp->d_namlen = strlen(ndp->d_name);
10985943Smckusic 	ndp->d_reclen = DIRSIZ(ndp);
10995943Smckusic 	/*
11005943Smckusic 	 * this quickly calculates if this inode is a directory.
11015943Smckusic 	 * Currently not maintained.
11025943Smckusic 	 *
11035943Smckusic 	for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
11045943Smckusic 		if (itp->t_ino != odp->d_ino)
11055943Smckusic 			continue;
11065943Smckusic 		ndp->d_fmt = IFDIR;
11075943Smckusic 		break;
11085943Smckusic 	}
11095943Smckusic 	 */
11105943Smckusic }
11115943Smckusic 
11125943Smckusic /*
11136289Smckusick  * Open a directory.
11146289Smckusick  * Modified to allow any random file to be a legal directory.
11156289Smckusick  */
11166289Smckusick DIR *
11176289Smckusick opendir(name)
11186289Smckusick 	char *name;
11196289Smckusick {
11206289Smckusick 	register DIR *dirp;
11216289Smckusick 
11226289Smckusick 	dirp = (DIR *)malloc(sizeof(DIR));
11236289Smckusick 	dirp->dd_fd = open(name, 0);
11246289Smckusick 	if (dirp->dd_fd == -1) {
1125*6846Smckusick 		free((char *)dirp);
11266289Smckusick 		return NULL;
11276289Smckusick 	}
11286289Smckusick 	dirp->dd_loc = 0;
11296289Smckusick 	return dirp;
11306289Smckusick }
11316289Smckusick 
11326289Smckusick /*
11336289Smckusick  * Seek to an entry in a directory.
11345943Smckusic  * Only values returned by ``telldir'' should be passed to seekdir.
11355943Smckusic  * Modified to have many directories based in one file.
11365943Smckusic  */
11375943Smckusic void
11385943Smckusic seekdir(dirp, loc, base)
11395943Smckusic 	register DIR *dirp;
1140*6846Smckusick 	daddr_t loc, base;
11415943Smckusic {
11425943Smckusic 	if (loc == telldir(dirp))
11435943Smckusic 		return;
11445943Smckusic 	loc -= base;
11455943Smckusic 	if (loc < 0)
11465943Smckusic 		fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
1147*6846Smckusick 	(void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
11485943Smckusic 	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
11495943Smckusic 	if (dirp->dd_loc != 0)
11505943Smckusic 		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
11515943Smckusic }
11525943Smckusic 
11535943Smckusic /*
11546844Smckusick  * get next entry in a directory.
11554700Smckusic  */
11566844Smckusick struct direct *
11576844Smckusick readdir(dirp)
11586844Smckusick 	register DIR *dirp;
11594610Smckusick {
11606844Smckusick 	register struct direct *dp;
11614700Smckusic 
11626844Smckusick 	for (;;) {
11636844Smckusick 		if (dirp->dd_loc == 0) {
11646844Smckusick 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
11656844Smckusick 			    DIRBLKSIZ);
11666844Smckusick 			if (dirp->dd_size <= 0)
11676844Smckusick 				return NULL;
11686844Smckusick 		}
11696844Smckusick 		if (dirp->dd_loc >= dirp->dd_size) {
11706844Smckusick 			dirp->dd_loc = 0;
11716844Smckusick 			continue;
11726844Smckusick 		}
11736844Smckusick 		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
11746844Smckusick 		if (dp->d_reclen <= 0 ||
11756844Smckusick 		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc)
11766844Smckusick 			return NULL;
11776844Smckusick 		dirp->dd_loc += dp->d_reclen;
11786844Smckusick 		if (dp->d_ino == 0)
11796844Smckusick 			continue;
11806844Smckusick 		return (dp);
11815948Smckusic 	}
11824610Smckusick }
11834610Smckusick 
11844843Smckusic allocinotab(ino, seekpt)
11854837Smckusic 	ino_t ino;
11864843Smckusic 	daddr_t seekpt;
11874610Smckusick {
11884837Smckusic 	register struct inotab	*itp;
11894776Smckusic 
11904837Smckusic 	itp = (struct inotab *)calloc(1, sizeof(struct inotab));
11914837Smckusic 	itp->t_next = inotab[INOHASH(ino)];
11924837Smckusic 	inotab[INOHASH(ino)] = itp;
11934837Smckusic 	itp->t_ino = ino;
11944843Smckusic 	itp->t_seekpt = seekpt;
11954610Smckusick }
11964610Smckusick 
11974843Smckusic allocxtr(ino, name, flags)
11984837Smckusic 	ino_t ino;
11994843Smckusic 	char *name;
12004843Smckusic 	char flags;
12014610Smckusick {
12024843Smckusic 	register struct xtrlist	*xp, *pxp;
12034776Smckusic 
12044843Smckusic 	xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
12054837Smckusic 	xp->x_next = xtrlist[INOHASH(ino)];
12064837Smckusic 	xtrlist[INOHASH(ino)] = xp;
12074837Smckusic 	xp->x_ino = ino;
12084843Smckusic 	strcpy(xp->x_name, name);
12094837Smckusic 	xtrcnt++;
12104843Smckusic 	xp->x_flags = flags;
12114843Smckusic 	for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
12124843Smckusic 		if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
12134843Smckusic 			xp->x_flags |= XLINKED;
12144843Smckusic 			xp->x_linkedto = pxp;
12154843Smckusic 			xtrcnt--;
12164843Smckusic 			break;
12174843Smckusic 		}
12184843Smckusic 	if (xp->x_flags & XLINKED)
12194843Smckusic 		fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
12204843Smckusic 	else if (xp->x_flags & XISDIR)
12214843Smckusic 		fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
12224843Smckusic 	else
12234843Smckusic 		fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
12244610Smckusick }
12254610Smckusick 
12265038Smckusic done(exitcode)
12275038Smckusic 	int exitcode;
12284610Smckusick {
12295038Smckusic 	unlink(dirfile);
12305038Smckusic 	exit(exitcode);
12314610Smckusick }
1232