xref: /original-bsd/sbin/restore/main.c (revision 01e9891b)
1 /* Copyright (c) 1981 Regents of the University of California */
2 
3 char version[] = "@(#)main.c 1.14 02/26/82";
4 
5 /*	Modified to include h option (recursively extract all files within
6  *	a subtree) and m option (recreate the heirarchical structure of
7  *	that subtree and move extracted files to their proper homes).
8  *	8/29/80		by Mike Litzkow
9  *
10  *	Includes the s (skip files) option for use with multiple dumps on
11  *	a single tape.
12  */
13 
14 /* static char *sccsid = "@(#)restor.c	4.3 (Berkeley) 6/3/81"; */
15 
16 #define MAXINO	3000
17 #define BITS	8
18 #define NCACHE	3
19 #define SIZEINC 10
20 
21 #ifndef STANDALONE
22 #include <stdio.h>
23 #include <signal.h>
24 #endif
25 #include "../h/param.h"
26 #include "../h/inode.h"
27 #include "../h/fs.h"
28 #include "../h/buf.h"
29 #include "../h/user.h"
30 #include "../h/dumprestor.h"
31 #include <sys/mtio.h>
32 
33 #define ODIRSIZ 14
34 struct odirect {
35 	u_short	d_ino;
36 	char	d_name[ODIRSIZ];
37 };
38 
39 #define	MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
40 #define	MBIT(i)	(1<<((unsigned)(i-1)%NBBY))
41 #define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
42 #define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
43 #define	BIT(i,w)	(MWORD(w,i) & MBIT(i))
44 
45 ino_t	ino, maxi;
46 struct inode *cur_ip;
47 
48 int	eflag = 0, hflag = 0, mflag = 0, cvtdir = 0;
49 
50 char	mounted = 0;
51 dev_t	dev = 0;
52 struct fs *fsptr;
53 struct inode parentino;
54 char	tapename[] = "/dev/rmt8";
55 char	*magtape = tapename;
56 int	mt;
57 int	dumpnum = 1;
58 int	volno = 1;
59 int	curblk = 0;
60 int	bct = NTREC+1;
61 char	tbf[NTREC*TP_BSIZE];
62 
63 #ifdef STANDALONE
64 char	mbuf[50];
65 #endif
66 
67 daddr_t	seekpt;
68 FILE	*df;
69 DIR	*dirp;
70 int	ofile;
71 char	dirfile[] = "rstXXXXXX";
72 
73 #define INOHASH(val) (val % MAXINO)
74 struct inotab {
75 	struct inotab *t_next;
76 	ino_t	t_ino;
77 	daddr_t	t_seekpt;
78 } *inotab[MAXINO];
79 
80 #define XISDIR	1
81 #define XTRACTD	2
82 #define XINUSE	4
83 #define XLINKED	8
84 struct xtrlist {
85 	struct xtrlist	*x_next;
86 	struct xtrlist	*x_linkedto;
87 	time_t		x_timep[2];
88 	ino_t		x_ino;
89 	char		x_flags;
90 	char 		x_name[1];
91 	/* actually longer */
92 } *xtrlist[MAXINO];
93 int xtrcnt = 0;
94 
95 #ifdef STANDALONE
96 #define msiz 8192
97 char	dumpmap[msiz];
98 char	clrimap[msiz];
99 #else
100 int	msiz;
101 char	*dumpmap;
102 char	*clrimap;
103 #endif
104 
105 char	clearedbuf[MAXBSIZE];
106 
107 extern char *ctime();
108 ino_t search();
109 int dirwrite();
110 char **envp;
111 
112 main(argc, argv, arge)
113 	int argc;
114 	char *argv[];
115 	char **arge;
116 {
117 	register char *cp;
118 	char command;
119 	int (*signal())();
120 	int done();
121 
122 	if (signal(SIGINT, done) == SIG_IGN)
123 		signal(SIGINT, SIG_IGN);
124 	if (signal(SIGTERM, done) == SIG_IGN)
125 		signal(SIGTERM, SIG_IGN);
126 #ifndef STANDALONE
127 	envp = arge;
128 	mktmp(dirfile);
129 	if (argc < 2) {
130 usage:
131 		fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
132 		done(1);
133 	}
134 	argv++;
135 	argc -= 2;
136 	for (cp = *argv++; *cp; cp++) {
137 		switch (*cp) {
138 		case '-':
139 			break;
140 		case 'f':
141 			magtape = *argv++;
142 			argc--;
143 			break;
144 		/* s dumpnum (skip to) for multifile dump tapes */
145 		case 's':
146 			dumpnum = atoi(*argv++);
147 			if(dumpnum <= 0) {
148 				fprintf(stderr, "Dump number must be a positive integer\n");
149 				done(1);
150 			}
151 			argc--;
152 			break;
153 		case 'h':
154 			hflag++;
155 			break;
156 		case 'm':
157 			mflag++;
158 			break;
159 		case 'r':
160 		case 'R':
161 		case 't':
162 		case 'x':
163 			command = *cp;
164 			break;
165 		default:
166 			fprintf(stderr, "Bad key character %c\n", *cp);
167 			goto usage;
168 		}
169 	}
170 	if (command == 'x') {
171 		df = fopen(dirfile, "w");
172 		if (df == 0) {
173 			fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
174 			done(1);
175 		}
176 		xmount(envp);
177 		mounted++;
178 	}
179 	doit(command, argc, argv);
180 	done(0);
181 #else
182 	magtape = "tape";
183 	doit('r', 1, 0);
184 #endif
185 }
186 
187 doit(command, argc, argv)
188 	char	command;
189 	int	argc;
190 	char	*argv[];
191 {
192 	struct mtop tcom;
193 
194 #ifndef STANDALONE
195 	if ((mt = open(magtape, 0)) < 0) {
196 		fprintf(stderr, "%s: cannot open tape\n", magtape);
197 		done(1);
198 	}
199 	if (dumpnum != 1) {
200 		tcom.mt_op = MTFSF;
201 		tcom.mt_count = dumpnum -1;
202 		if (ioctl(mt,MTIOCTOP,&tcom) < 0)
203 			perror("ioctl MTFSF");
204 	}
205 #else
206 	do {
207 		fprintf(stderr, "Tape? ");
208 		gets(mbuf);
209 		mt = open(mbuf, 0);
210 	} while (mt == -1);
211 	magtape = mbuf;
212 #endif
213 	blkclr(clearedbuf, MAXBSIZE);
214 	switch(command) {
215 #ifndef STANDALONE
216 	case 't':
217 		if (readhdr(&spcl) == 0) {
218 			fprintf(stderr, "Tape is not a dump tape\n");
219 			done(1);
220 		}
221 		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
222 		fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
223 		return;
224 	case 'x':
225 		extractfiles(argc, argv);
226 		return;
227 #endif
228 	case 'r':
229 	case 'R':
230 		restorfiles(command, argv);
231 		return;
232 	}
233 }
234 
235 #ifndef STANDALONE
236 extractfiles(argc, argv)
237 	int argc;
238 	char **argv;
239 {
240 	char	*ststore();
241 	register struct xtrlist *xp;
242 	struct xtrlist **xpp;
243 	ino_t	d;
244 	int	xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(), null();
245 	int	mode;
246 	char	name[BUFSIZ + 1];
247 
248 	if (readhdr(&spcl) == 0) {
249 		fprintf(stderr, "Tape is not a dump tape\n");
250 		done(1);
251 	}
252 	if (checkvol(&spcl, 1) == 0) {
253 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
254 	}
255 	fsptr = getfs(dev);
256 	msiz = roundup(howmany(fsptr->fs_ipg * fsptr->fs_ncg, NBBY), TP_BSIZE);
257 	clrimap = (char *)calloc(msiz, sizeof(char));
258 	dumpmap = (char *)calloc(msiz, sizeof(char));
259 	pass1(1);  /* This sets the various maps on the way by */
260 	while (argc--) {
261 		if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
262 			fprintf(stdout, "%s: not on tape\n", *argv++);
263 			continue;
264 		}
265 		if (mflag)
266 			checkdir(*argv);
267 		if(hflag)
268 			getleaves(d, *argv++);
269 		else
270 			allocxtr(d, *argv++, XINUSE);
271 	}
272 	if (dumpnum > 1) {
273 		/*
274 		 * if this is a multi-dump tape we always start with
275 		 * volume 1, so as to avoid accidentally restoring
276 		 * from a different dump!
277 		 */
278 		resetmt();
279 		dumpnum = 1;
280 		volno = 1;
281 		readhdr(&spcl);
282 		goto rbits;
283 	}
284 newvol:
285 	resetmt();
286 getvol:
287 	fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
288 	if (gets(tbf) == NULL)
289 		return;
290 	volno = atoi(tbf);
291 	if (volno <= 0) {
292 		fprintf(stderr, "Volume numbers are positive numerics\n");
293 		goto getvol;
294 	}
295 	if (readhdr(&spcl) == 0) {
296 		fprintf(stderr, "tape is not dump tape\n");
297 		goto newvol;
298 	}
299 	if (checkvol(&spcl, volno) == 0) {
300 		fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
301 		goto newvol;
302 	}
303 rbits:
304 	while (gethead(&spcl) == 0)
305 		;
306 	if (checktype(&spcl, TS_INODE) == 1) {
307 		fprintf(stderr, "Can't find inode mask!\n");
308 		goto newvol;
309 	}
310 	if (checktype(&spcl, TS_BITS) == 0)
311 		goto rbits;
312 	readbits(dumpmap);
313 	while (xtrcnt > 0) {
314 again:
315 		if (ishead(&spcl) == 0)
316 			while(gethead(&spcl) == 0)
317 				;
318 		if (checktype(&spcl, TS_END) == 1) {
319 			fprintf(stderr, "end of tape\n");
320 			break;
321 		}
322 		if (checktype(&spcl, TS_INODE) == 0) {
323 			gethead(&spcl);
324 			goto again;
325 		}
326 		d = spcl.c_inumber;
327 		for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
328 			if (d != xp->x_ino)
329 				continue;
330 			if (xp->x_flags & XLINKED)
331 				continue;
332 			xp->x_timep[0] = spcl.c_dinode.di_atime;
333 			xp->x_timep[1] = spcl.c_dinode.di_mtime;
334 			mode = spcl.c_dinode.di_mode;
335 			if (mflag)
336 				strcpy(name, xp->x_name);
337 			else
338 				sprintf(name, "%u", xp->x_ino);
339 			switch (mode & IFMT) {
340 			default:
341 				fprintf(stderr, "%s: unknown file type\n", name);
342 				xp->x_flags |= XTRACTD;
343 				xtrcnt--;
344 				goto skipfile;
345 			case IFCHR:
346 			case IFBLK:
347 				fprintf(stdout, "extract special file %s\n", name);
348 				if (xmknod(name, mode, spcl.c_dinode.di_rdev)) {
349 					fprintf(stderr, "%s: cannot create special file\n", name);
350 					xp->x_flags |= XTRACTD;
351 					xtrcnt--;
352 					goto skipfile;
353 				}
354 				getfile(null, null, spcl.c_dinode.di_size);
355 				break;
356 			case IFDIR:
357 				if (mflag) {
358 					fprintf(stdout, "extract directory %s\n", name);
359 					strncat(name, "/.", BUFSIZ);
360 					checkdir(name);
361 					xchown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
362 					getfile(null, null, spcl.c_dinode.di_size);
363 					break;
364 				}
365 				fprintf(stdout, "extract file %s\n", name);
366 				if ((ofile = xcreat(name, 0666)) < 0) {
367 					fprintf(stderr, "%s: cannot create file\n", name);
368 					xp->x_flags |= XTRACTD;
369 					xtrcnt--;
370 					goto skipfile;
371 				}
372 				xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
373 				if (cvtdir) {
374 					getfile(xtrcvtdir, xtrcvtskip,
375 					    spcl.c_dinode.di_size);
376 					flushent(xtrfile);
377 				} else
378 					getfile(xtrfile, xtrskip,
379 					    spcl.c_dinode.di_size);
380 				xclose(ofile);
381 				break;
382 			case IFREG:
383 				fprintf(stdout, "extract file %s\n", name);
384 				if ((ofile = xcreat(name, 0666)) < 0) {
385 					fprintf(stderr, "%s: cannot create file\n", name);
386 					xp->x_flags |= XTRACTD;
387 					xtrcnt--;
388 					goto skipfile;
389 				}
390 				xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
391 				getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
392 				xclose(ofile);
393 				break;
394 			}
395 			xchmod(name, mode);
396 			xutime(name, xp->x_timep);
397 			xp->x_flags |= XTRACTD;
398 			xtrcnt--;
399 			goto finished;
400 		}
401 skipfile:
402 		getfile(null, null, spcl.c_dinode.di_size);
403 finished:
404 		;
405 	}
406 	if (xtrcnt == 0 && !mflag)
407 		return;
408 	for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
409 		for (xp = *xpp; xp; xp = xp->x_next) {
410 			if (mflag && (xp->x_flags & XISDIR))
411 				xutime(xp->x_name, xp->x_timep);
412 			if (xp->x_flags & XTRACTD)
413 				continue;
414 			if ((xp->x_flags & XLINKED) == 0) {
415 				fprintf(stderr, "cannot find file %s\n",
416 					xp->x_name);
417 				continue;
418 			}
419 			if (!mflag)
420 				continue;
421 			fprintf(stdout, "link %s to %s\n",
422 				xp->x_linkedto->x_name, xp->x_name);
423 			if (xlink(xp->x_linkedto->x_name, xp->x_name) < 0)
424 				fprintf(stderr, "link %s to %s failed\n",
425 					xp->x_linkedto->x_name, xp->x_name);
426 		}
427 	}
428 }
429 #endif
430 
431 restorfiles(command, argv)
432 	char command;
433 	char **argv;
434 {
435 	int null(), rstrfile(), rstrskip(), rstrcvtdir(), rstrcvtskip();
436 	register struct dinode *dp;
437 	register struct inode *ip;
438 	int mode, type;
439 	char mount[BUFSIZ + 1];
440 	char *ptr[2];
441 
442 	mount[0] = '\0';
443 	strcpy(mount, "MOUNT=");
444 #ifndef STANDALONE
445 	strncat(mount, *argv, BUFSIZ);
446 #else
447 	fprintf(stderr, "Disk? ");
448 	gets(&mount[6]);
449 #endif
450 	ptr[0] = mount;
451 	ptr[1] = 0;
452 	xmount(ptr);
453 	mounted++;
454 	iput(u.u_cdir); /* release root inode */
455 	iput(u.u_rdir); /* release root inode */
456 	fsptr = getfs(dev);
457 	parentino.i_fs = fsptr;
458 	parentino.i_dev = dev;
459 	maxi = fsptr->fs_ipg * fsptr->fs_ncg;
460 #ifndef STANDALONE
461 	msiz = roundup(howmany(maxi, NBBY), TP_BSIZE);
462 	clrimap = (char *)calloc(msiz, sizeof(char));
463 	dumpmap = (char *)calloc(msiz, sizeof(char));
464 	if (command == 'R') {
465 		fprintf(stderr, "Enter starting volume number: ");
466 		if (gets(tbf) == EOF) {
467 			volno = 1;
468 			fprintf(stderr, "\n");
469 		}
470 		else
471 			volno = atoi(tbf);
472 	}
473 	else
474 #endif
475 		volno = 1;
476 	fprintf(stderr, "Last chance before scribbling on %s. ",
477 #ifdef STANDALONE
478 							"disk");
479 #else
480 							*argv);
481 #endif
482 	while (getchar() != '\n');
483 	if (readhdr(&spcl) == 0) {
484 		fprintf(stderr, "Missing volume record\n");
485 		done(1);
486 	}
487 	if (checkvol(&spcl, volno) == 0) {
488 		fprintf(stderr, "Tape is not volume %d\n", volno);
489 		done(1);
490 	}
491 	pass1(0);
492 	gethead(&spcl); /* volume header already checked above */
493 	gethead(&spcl);
494 	for (;;) {
495 		if (ishead(&spcl) == 0) {
496 			fprintf(stderr, "Missing header block\n");
497 			while (gethead(&spcl) == 0)
498 				;
499 			eflag++;
500 		}
501 		if (checktype(&spcl, TS_END) == 1) {
502 			fprintf(stderr, "End of tape\n");
503 			close(mt);
504 			return;
505 		}
506 		if (checktype(&spcl, TS_CLRI) == 1) {
507 			readbits(clrimap);
508 			/*
509 			 * if throwing away the root inode, must also
510 			 * discard the predefined lost+found directory.
511 			 */
512 			if (BIT(ROOTINO, clrimap))
513 				BIS(LOSTFOUNDINO + 1, clrimap);
514 			for (ino = ROOTINO; ino <= maxi; ino++)
515 				if (BIT(ino, clrimap) == 0) {
516 					if (!iexist(&parentino, ino))
517 						continue;
518 					ip = iget(dev, fsptr, ino);
519 					if (ip == NULL) {
520 						fprintf(stderr, "can't find inode %u\n", ino);
521 						done(1);
522 					}
523 					ip->i_nlink = 0;
524 					ip->i_flag |= ICHG;
525 					iput(ip);
526 				}
527 			continue;
528 		}
529 		if (checktype(&spcl, TS_BITS) == 1) {
530 			readbits(dumpmap);
531 			continue;
532 		}
533 		if (checktype(&spcl, TS_INODE) == 0) {
534 			fprintf(stderr, "Unknown header type\n");
535 			eflag++;
536 			gethead(&spcl);
537 			continue;
538 		}
539 		ino = spcl.c_inumber;
540 		if (eflag)
541 			fprintf(stderr, "Resynced at inode %u\n", ino);
542 		eflag = 0;
543 		if (ino > maxi) {
544 			fprintf(stderr, "%u: ilist too small\n", ino);
545 			gethead(&spcl);
546 			continue;
547 		}
548 		dp = &spcl.c_dinode;
549 		if (ino < ROOTINO) {
550 			getfile(null, null, dp->di_size);
551 			continue;
552 		}
553 		if (iexist(&parentino, ino)) {
554 			ip = iget(dev, fsptr, ino);
555 			if (ip == NULL) {
556 				fprintf(stderr, "can't find inode %u\n",
557 					ino);
558 				done(1);
559 			}
560 			ip->i_nlink = 0;
561 			ip->i_flag |= ICHG;
562 			iput(ip);
563 		}
564 		ip = ialloc(&parentino, ino, dp->di_mode);
565 		if (ip == NULL || ip->i_number != ino) {
566 			fprintf(stderr, "can't create inode %u\n", ino);
567 			done(1);
568 		}
569 		ip->i_mode = mode = dp->di_mode;
570 		ip->i_nlink = dp->di_nlink;
571 		ip->i_uid = dp->di_uid;
572 		ip->i_gid = dp->di_gid;
573 		ip->i_atime = dp->di_atime;
574 		ip->i_mtime = dp->di_mtime;
575 		ip->i_ctime = dp->di_ctime;
576 		type = ip->i_mode & IFMT;
577 		if (type == IFCHR || type == IFBLK)
578 			ip->i_rdev = dp->di_rdev;
579 		ip->i_size = 0;
580 		cur_ip = ip;
581 		u.u_offset = 0;
582 		u.u_segflg = 1;
583 		if (cvtdir && type == IFDIR) {
584 			getfile(rstrcvtdir, rstrcvtskip, dp->di_size);
585 			flushent(rstrfile);
586 		} else
587 			getfile(rstrfile, rstrskip, dp->di_size);
588 		ip->i_mode = mode;
589 		ip->i_flag &= ~(IUPD|IACC);
590 		ip->i_flag |= ICHG;
591 		iput(ip);
592 	}
593 }
594 
595 /*
596  * Read the tape, bulding up a directory structure for extraction
597  * by name
598  */
599 #ifndef STANDALONE
600 pass1(savedir)
601 	int savedir;
602 {
603 	register int i;
604 	register struct dinode *ip;
605 	struct direct nulldir;
606 	char buf[TP_BSIZE];
607 	int putdir(), null(), dirwrite();
608 
609 	nulldir.d_ino = 1;
610 	nulldir.d_namlen = 1;
611 	strncpy(nulldir.d_name, "/", nulldir.d_namlen);
612 	nulldir.d_reclen = DIRSIZ(&nulldir);
613 	while (gethead(&spcl) == 0) {
614 		fprintf(stderr, "Can't find directory header!\n");
615 	}
616 	for (;;) {
617 		if (checktype(&spcl, TS_BITS) == 1) {
618 			readbits(dumpmap);
619 			continue;
620 		}
621 		if (checktype(&spcl, TS_CLRI) == 1) {
622 			readbits(clrimap);
623 			continue;
624 		}
625 		if (checktype(&spcl, TS_INODE) == 0) {
626 finish:
627 			if (savedir) {
628 				fclose(df);
629 				dirp = opendir(dirfile);
630 				if (dirp == NULL)
631 					perror("opendir");
632 			}
633 			resetmt();
634 			return;
635 		}
636 		ip = &spcl.c_dinode;
637 		i = ip->di_mode & IFMT;
638 		if (i != IFDIR) {
639 			goto finish;
640 		}
641 		if (spcl.c_inumber == ROOTINO) {
642 			readtape(buf);
643 			bct--; /* push back this block */
644 			if (((struct direct *)buf)->d_ino != ROOTINO) {
645 				if (((struct odirect *)buf)->d_ino != ROOTINO) {
646 					fprintf(stderr, "bad root directory\n");
647 					done(1);
648 				}
649 				fprintf(stderr, "converting to new directory format\n");
650 				cvtdir = 1;
651 			}
652 			if (!savedir && !cvtdir) {
653 				/* if no conversion, just return */
654 				goto finish;
655 			}
656 		}
657 		allocinotab(spcl.c_inumber, seekpt);
658 		if (savedir) {
659 			getfile(putdir, null, spcl.c_dinode.di_size);
660 			putent(&nulldir, dirwrite);
661 			flushent(dirwrite);
662 		} else {
663 			getfile(null, null, spcl.c_dinode.di_size);
664 		}
665 	}
666 }
667 #endif
668 
669 /*
670  * Put the directory entries in the directory file
671  */
672 #ifndef STANDALONE
673 putdir(buf, size)
674 	char *buf;
675 	int size;
676 {
677 	struct direct cvtbuf;
678 	register struct odirect *odp;
679 	struct odirect *eodp;
680 	register struct direct *dp;
681 	long loc;
682 
683 	if (cvtdir) {
684 		eodp = (struct odirect *)&buf[size];
685 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
686 			if (odp->d_ino != 0) {
687 				dcvt(odp, &cvtbuf);
688 				putent(&cvtbuf, dirwrite);
689 			}
690 	} else {
691 		for (loc = 0; loc < size; ) {
692 			dp = (struct direct *)(buf + loc);
693 			if (dp->d_ino != 0)
694 				putent(dp, dirwrite);
695 		}
696 	}
697 }
698 
699 /*
700  *	Recursively find names and inumbers of all files in subtree
701  *	pname and put them in xtrlist[]
702  */
703 getleaves(ino, pname)
704 	ino_t ino;
705 	char *pname;
706 {
707 	register struct inotab *itp;
708 	int namelen;
709 	long bpt;
710 	register struct direct *dp;
711 	char locname[BUFSIZ + 1];
712 
713 	if (BIT(ino, dumpmap) == 0) {
714 		fprintf(stdout, "%s: not on the tape\n", pname);
715 		return;
716 	}
717 	for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
718 		if (itp->t_ino != ino)
719 			continue;
720 		/*
721 		 * pname is a directory name
722 		 */
723 		allocxtr(ino, pname, XISDIR);
724 		/*
725 		 * begin search through the directory
726 		 * skipping over "." and ".."
727 		 */
728 		strncpy(locname, pname, BUFSIZ);
729 		strncat(locname, "/", BUFSIZ);
730 		namelen = strlen(locname);
731 		seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
732 		dp = readdir(dirp);
733 		dp = readdir(dirp);
734 		dp = readdir(dirp);
735 		bpt = telldir(dirp);
736 		/*
737 		 * "/" signals end of directory
738 		 */
739 		while (dp->d_namlen != 1 || dp->d_name[0] != '/') {
740 			locname[namelen] = '\0';
741 			if (namelen + dp->d_namlen >= BUFSIZ) {
742 				fprintf(stderr, "%s%s: name exceedes %d char\n",
743 					locname, dp->d_name, BUFSIZ);
744 				continue;
745 			}
746 			strncat(locname, dp->d_name, dp->d_namlen);
747 			getleaves(dp->d_ino, locname);
748 			seekdir(dirp, bpt, itp->t_seekpt);
749 			dp = readdir(dirp);
750 			bpt = telldir(dirp);
751 		}
752 		return;
753 	}
754 	/*
755 	 * locname is name of a simple file
756 	 */
757 	allocxtr(ino, pname, XINUSE);
758 }
759 
760 /*
761  * Search the directory tree rooted at inode ROOTINO
762  * for the path pointed at by n
763  */
764 psearch(n)
765 	char	*n;
766 {
767 	register char *cp, *cp1;
768 	char c;
769 
770 	ino = ROOTINO;
771 	if (*(cp = n) == '/')
772 		cp++;
773 next:
774 	cp1 = cp + 1;
775 	while (*cp1 != '/' && *cp1)
776 		cp1++;
777 	c = *cp1;
778 	*cp1 = 0;
779 	ino = search(ino, cp);
780 	if (ino == 0) {
781 		*cp1 = c;
782 		return(0);
783 	}
784 	*cp1 = c;
785 	if (c == '/') {
786 		cp = cp1+1;
787 		goto next;
788 	}
789 	return(ino);
790 }
791 
792 /*
793  * search the directory inode ino
794  * looking for entry cp
795  */
796 ino_t
797 search(inum, cp)
798 	ino_t	inum;
799 	char	*cp;
800 {
801 	register struct direct *dp;
802 	register struct inotab *itp;
803 	int len;
804 
805 	for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
806 		if (itp->t_ino == inum)
807 			goto found;
808 	return(0);
809 found:
810 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
811 	len = strlen(cp);
812 	do {
813 		dp = readdir(dirp);
814 		if (dp->d_namlen == 1 && dp->d_name[0] == '/')
815 			return(0);
816 	} while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
817 	return(dp->d_ino);
818 }
819 #endif
820 
821 /*
822  * Do the file extraction, calling the supplied functions
823  * with the blocks
824  */
825 getfile(f1, f2, size)
826 	int	(*f2)(), (*f1)();
827 	long	size;
828 {
829 	register int i;
830 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
831 	union u_spcl addrblk;
832 #	define addrblock addrblk.s_spcl
833 
834 	addrblock = spcl;
835 	for (;;) {
836 		for (i = 0; i < addrblock.c_count; i++) {
837 			if (addrblock.c_addr[i]) {
838 				readtape(&buf[curblk++][0]);
839 				if (curblk == BLKING(fsptr) * fsptr->fs_frag) {
840 					(*f1)(buf, size > TP_BSIZE ?
841 					     (long) (BLKING(fsptr) * fsptr->fs_frag * TP_BSIZE) :
842 					     (curblk - 1) * TP_BSIZE + size);
843 					curblk = 0;
844 				}
845 			} else {
846 				if (curblk > 0) {
847 					(*f1)(buf, size > TP_BSIZE ?
848 					     (long) (curblk * TP_BSIZE) :
849 					     (curblk - 1) * TP_BSIZE + size);
850 					curblk = 0;
851 				}
852 				(*f2)(clearedbuf, size > TP_BSIZE ?
853 					(long) TP_BSIZE : size);
854 			}
855 			if ((size -= TP_BSIZE) <= 0) {
856 eloop:
857 				while (gethead(&spcl) == 0)
858 					;
859 				if (checktype(&spcl, TS_ADDR) == 1)
860 					goto eloop;
861 				goto out;
862 			}
863 		}
864 		if (gethead(&addrblock) == 0) {
865 			fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
866 			goto eloop;
867 		}
868 		if (checktype(&addrblock, TS_ADDR) == 0) {
869 			spcl = addrblock;
870 			goto out;
871 		}
872 	}
873 out:
874 	if (curblk > 0) {
875 		(*f1)(buf, (curblk * TP_BSIZE) + size);
876 		curblk = 0;
877 	}
878 }
879 
880 /*
881  * The next routines are called during file extraction to
882  * put the data into the right form and place.
883  */
884 #ifndef STANDALONE
885 xtrfile(buf, size)
886 	char	*buf;
887 	long	size;
888 {
889 	if (xwrite(ofile, buf, (int) size) == -1) {
890 		perror("extract write");
891 		done(1);
892 	}
893 }
894 
895 xtrskip(buf, size)
896 	char *buf;
897 	long size;
898 {
899 	if (xseek(ofile, size, 1) == -1) {
900 		perror("extract seek");
901 		done(1);
902 	}
903 }
904 
905 xtrcvtdir(buf, size)
906 	struct odirect *buf;
907 	long size;
908 {
909 	struct odirect *odp, *edp;
910 	struct direct *dp, cvtbuf;
911 
912 	edp = &buf[size / sizeof(struct odirect)];
913 	for (odp = buf; odp < edp; odp++) {
914 		dcvt(odp, &cvtbuf);
915 		putent(&cvtbuf, xtrfile);
916 	}
917 }
918 
919 xtrcvtskip(buf, size)
920 	char *buf;
921 	long size;
922 {
923 	fprintf(stderr, "unallocated block in directory\n");
924 	xtrskip(buf, size);
925 }
926 #endif
927 
928 rstrfile(buf, size)
929 	char *buf;
930 	long size;
931 {
932 	u.u_base = buf;
933 	u.u_count = size;
934 	writei(cur_ip);
935 	if (u.u_error) {
936 		perror("restor write");
937 		done(1);
938 	}
939 }
940 
941 rstrskip(buf, size)
942 	char *buf;
943 	long size;
944 {
945 	u.u_offset += size;
946 }
947 
948 rstrcvtdir(buf, size)
949 	struct odirect *buf;
950 	long size;
951 {
952 	struct odirect *odp, *edp;
953 	struct direct *dp, cvtbuf;
954 
955 	edp = &buf[size / sizeof(struct odirect)];
956 	for (odp = buf; odp < edp; odp++) {
957 		dcvt(odp, &cvtbuf);
958 		putent(&cvtbuf, rstrfile);
959 	}
960 }
961 
962 rstrcvtskip(buf, size)
963 	char *buf;
964 	long size;
965 {
966 	fprintf(stderr, "unallocated block in directory\n");
967 	rstrskip(buf, size);
968 }
969 
970 null() {;}
971 
972 /*
973  * Do the tape i/o, dealing with volume changes
974  * etc..
975  */
976 readtape(b)
977 	char *b;
978 {
979 	register int i;
980 	struct s_spcl tmpbuf;
981 
982 	if (bct >= NTREC) {
983 		for (i = 0; i < NTREC; i++)
984 			((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
985 		bct = 0;
986 		if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
987 			perror("Tape read error");
988 			eflag++;
989 			done(1);
990 		}
991 		if (i == 0) {
992 			bct = NTREC + 1;
993 			volno++;
994 loop:
995 			flsht();
996 			close(mt);
997 			fprintf(stderr, "Mount volume %d\n", volno);
998 			while (getchar() != '\n')
999 				;
1000 			if ((mt = open(magtape, 0)) == -1) {
1001 				fprintf(stderr, "Cannot open tape!\n");
1002 				goto loop;
1003 			}
1004 			if (readhdr(&tmpbuf) == 0) {
1005 				fprintf(stderr, "Not a dump tape.Try again\n");
1006 				goto loop;
1007 			}
1008 			if (checkvol(&tmpbuf, volno) == 0) {
1009 				fprintf(stderr, "Wrong tape. Try again\n");
1010 				goto loop;
1011 			}
1012 			readtape(b);
1013 			return;
1014 		}
1015 	}
1016 	blkcpy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE);
1017 }
1018 
1019 flsht()
1020 {
1021 	bct = NTREC+1;
1022 }
1023 
1024 blkcpy(from, to, size)
1025 	char *from, *to;
1026 	int size;
1027 {
1028 	asm("	movc3	12(ap),*4(ap),*8(ap)");
1029 }
1030 
1031 blkclr(buf, size)
1032 	char *buf;
1033 	int size;
1034 {
1035 	asm("movc5	$0,(r0),$0,8(ap),*4(ap)");
1036 }
1037 
1038 resetmt()
1039 {
1040 	struct mtop tcom;
1041 
1042 	if(dumpnum > 1)
1043 		tcom.mt_op = MTBSF;
1044 	else
1045 		tcom.mt_op = MTREW;
1046 	tcom.mt_count = 1;
1047 	flsht();
1048 	if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
1049 		/* kludge for disk dumps */
1050 		lseek(mt, (long)0, 0);
1051 	}
1052 	if (dumpnum > 1) {
1053 		tcom.mt_op = MTFSF;
1054 		tcom.mt_count = 1;
1055 		ioctl(mt,MTIOCTOP,&tcom);
1056 	}
1057 }
1058 
1059 checkvol(b, t)
1060 	struct s_spcl *b;
1061 	int t;
1062 {
1063 	if (b->c_volume == t)
1064 		return(1);
1065 	return(0);
1066 }
1067 
1068 readhdr(b)
1069 	struct s_spcl *b;
1070 {
1071 	if (gethead(b) == 0)
1072 		return(0);
1073 	if (checktype(b, TS_TAPE) == 0)
1074 		return(0);
1075 	return(1);
1076 }
1077 
1078 /*
1079  * read the tape into buf, then return whether or
1080  * or not it is a header block.
1081  */
1082 gethead(buf)
1083 	struct s_spcl *buf;
1084 {
1085 	readtape((char *)buf);
1086 	if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
1087 		return(0);
1088 	return(1);
1089 }
1090 
1091 /*
1092  * return whether or not the buffer contains a header block
1093  */
1094 ishead(buf)
1095 	struct s_spcl *buf;
1096 {
1097 	if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
1098 		return(0);
1099 	return(1);
1100 }
1101 
1102 checktype(b, t)
1103 	struct s_spcl *b;
1104 	int	t;
1105 {
1106 	return(b->c_type == t);
1107 }
1108 
1109 /*
1110  * read a bit mask from the tape into m.
1111  */
1112 readbits(m)
1113 	char	*m;
1114 {
1115 	register int i;
1116 
1117 	i = spcl.c_count;
1118 
1119 	while (i--) {
1120 		readtape((char *) m);
1121 		m += (TP_BSIZE/(NBBY/BITS));
1122 	}
1123 	while (gethead(&spcl) == 0)
1124 		;
1125 }
1126 
1127 checksum(b)
1128 	int *b;
1129 {
1130 	register int i, j;
1131 
1132 	j = sizeof(union u_spcl) / sizeof(int);
1133 	i = 0;
1134 	do
1135 		i += *b++;
1136 	while (--j);
1137 	if (i != CHECKSUM) {
1138 		fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
1139 		return(0);
1140 	}
1141 	return(1);
1142 }
1143 
1144 /*
1145  *	Check for access into each directory in the pathname of an extracted
1146  *	file and create such a directory if needed in preparation for moving
1147  *	the file to its proper home.
1148  */
1149 checkdir(name)
1150 	register char *name;
1151 {
1152 	register char *cp;
1153 	int i;
1154 
1155 	for (cp = name; *cp; cp++) {
1156 		if (*cp == '/') {
1157 			*cp = '\0';
1158 			if (xaccess(name, 01) < 0) {
1159 				register int pid, rp;
1160 
1161 				xumount();
1162 				if ((pid = fork()) == 0) {
1163 					execl("/bin/xmkdir", "xmkdir", name, 0);
1164 					execl("/usr/bin/xmkdir", "xmkdir", name, 0);
1165 					execl("./xmkdir", "xmkdir", name, 0);
1166 					fprintf(stderr, "xrestor: cannot find xmkdir!\n");
1167 					done(0);
1168 				}
1169 				while ((rp = wait(&i)) >= 0 && rp != pid)
1170 					;
1171 				xmount(envp);
1172 				fsptr = getfs(dev);
1173 				parentino.i_fs = fsptr;
1174 			}
1175 			*cp = '/';
1176 		}
1177 	}
1178 }
1179 
1180 /*
1181  * These variables are "local" to the following two functions.
1182  */
1183 char dirbuf[DIRBLKSIZ];
1184 long dirloc = 0;
1185 long prev = 0;
1186 
1187 /*
1188  * add a new directory entry to a file.
1189  */
1190 putent(dp, wrtfunc)
1191 	struct direct *dp;
1192 	int (*wrtfunc)();
1193 {
1194 	if (dp->d_ino == 0)
1195 		return;
1196 	for (;;) {
1197 		if (dp->d_reclen < DIRBLKSIZ - dirloc) {
1198 			blkcpy(dp, dirbuf + dirloc, dp->d_reclen);
1199 			prev = dirloc;
1200 			dirloc += dp->d_reclen;
1201 			return;
1202 		}
1203 		((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
1204 		(*wrtfunc)(dirbuf, DIRBLKSIZ);
1205 		dirloc = 0;
1206 	}
1207 }
1208 
1209 /*
1210  * flush out a directory that is finished.
1211  */
1212 flushent(wrtfunc)
1213 	int (*wrtfunc)();
1214 {
1215 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
1216 	(*wrtfunc)(dirbuf, dirloc);
1217 	dirloc = 0;
1218 }
1219 
1220 dirwrite(buf, size)
1221 	char *buf;
1222 	int size;
1223 {
1224 	fwrite(buf, 1, size, df);
1225 	seekpt = ftell(df);
1226 }
1227 
1228 dcvt(odp, ndp)
1229 	register struct odirect *odp;
1230 	register struct direct *ndp;
1231 {
1232 	struct inotab *itp;
1233 
1234 	blkclr(ndp, sizeof *ndp);
1235 	ndp->d_ino =  odp->d_ino;
1236 	strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
1237 	ndp->d_namlen = strlen(ndp->d_name);
1238 	ndp->d_reclen = DIRSIZ(ndp);
1239 	/*
1240 	 * this quickly calculates if this inode is a directory.
1241 	 * Currently not maintained.
1242 	 *
1243 	for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
1244 		if (itp->t_ino != odp->d_ino)
1245 			continue;
1246 		ndp->d_fmt = IFDIR;
1247 		break;
1248 	}
1249 	 */
1250 }
1251 
1252 /*
1253  * seek to an entry in a directory.
1254  * Only values returned by ``telldir'' should be passed to seekdir.
1255  * Modified to have many directories based in one file.
1256  */
1257 void
1258 seekdir(dirp, loc, base)
1259 	register DIR *dirp;
1260 	long loc, base;
1261 {
1262 	if (loc == telldir(dirp))
1263 		return;
1264 	loc -= base;
1265 	if (loc < 0)
1266 		fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
1267 	lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
1268 	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
1269 	if (dirp->dd_loc != 0)
1270 		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
1271 }
1272 
1273 /*
1274  * tell whether an inode is allocated
1275  * this is drawn from ialloccg in sys/alloc.c
1276  */
1277 iexist(ip, ino)
1278 	struct inode *ip;
1279 	ino_t ino;
1280 {
1281 	register struct fs *fs;
1282 	register struct cg *cgp;
1283 	register struct buf *bp;
1284 	int cg;
1285 
1286 	fs = ip->i_fs;
1287 	if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
1288 		return (0);
1289 	cg = itog(fs, ino);
1290 	bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize);
1291 	if (bp->b_flags & B_ERROR) {
1292 		brelse(bp);
1293 		return(0);
1294 	}
1295 	cgp = bp->b_un.b_cg;
1296 	ino %= fs->fs_ipg;
1297 	if (isclr(cgp->cg_iused, ino)) {
1298 		brelse(bp);
1299 		return(0);
1300 	}
1301 	brelse(bp);
1302 	return (1);
1303 }
1304 
1305 allocinotab(ino, seekpt)
1306 	ino_t ino;
1307 	daddr_t seekpt;
1308 {
1309 	register struct inotab	*itp;
1310 
1311 	itp = (struct inotab *)calloc(1, sizeof(struct inotab));
1312 	itp->t_next = inotab[INOHASH(ino)];
1313 	inotab[INOHASH(ino)] = itp;
1314 	itp->t_ino = ino;
1315 	itp->t_seekpt = seekpt;
1316 }
1317 
1318 allocxtr(ino, name, flags)
1319 	ino_t ino;
1320 	char *name;
1321 	char flags;
1322 {
1323 	register struct xtrlist	*xp, *pxp;
1324 
1325 	xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
1326 	xp->x_next = xtrlist[INOHASH(ino)];
1327 	xtrlist[INOHASH(ino)] = xp;
1328 	xp->x_ino = ino;
1329 	strcpy(xp->x_name, name);
1330 	xtrcnt++;
1331 	xp->x_flags = flags;
1332 	for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
1333 		if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
1334 			xp->x_flags |= XLINKED;
1335 			xp->x_linkedto = pxp;
1336 			xtrcnt--;
1337 			break;
1338 		}
1339 	if (xp->x_flags & XLINKED)
1340 		fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
1341 	else if (xp->x_flags & XISDIR)
1342 		fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
1343 	else
1344 		fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
1345 }
1346 
1347 done(exitcode)
1348 	int exitcode;
1349 {
1350 #ifndef STANDALONE
1351 	unlink(dirfile);
1352 #endif
1353 	if (mounted)
1354 		xumount();
1355 	exit(exitcode);
1356 }
1357