xref: /original-bsd/old/512restor/512restor.c (revision 0a83ae40)
1 static char *sccsid = "@(#)512restor.c	4.2 (Berkeley) 11/15/80";
2 #define MAXINO	3000
3 #define BITS	8
4 #define MAXXTR	60
5 #define NCACHE	3
6 
7 #ifndef STANDALONE
8 #include <stdio.h>
9 #include <signal.h>
10 #endif
11 #include <sys/param.h>
12 #include <sys/inode.h>
13 #include <sys/ino.h>
14 #include <sys/fblk.h>
15 #include <sys/filsys.h>
16 #include <sys/dir.h>
17 
18 #define	OBSIZE	512
19 
20 /* from old <ino.h> */
21 
22 #define	OINOPB	8	/* 8 inodes per block */
23 
24 /* old <dumprestor.h> */
25 #define NTREC   	20
26 #define MLEN    	16
27 #define MSIZ    	4096
28 
29 #define TS_TAPE 	1
30 #define TS_INODE	2
31 #define TS_BITS 	3
32 #define TS_ADDR 	4
33 #define TS_END  	5
34 #define TS_CLRI 	6
35 #define MAGIC   	(int)60011
36 #define CHECKSUM	(int)84446
37 struct	spcl
38 {
39 	int	c_type;
40 	time_t	c_date;
41 	time_t	c_ddate;
42 	int	c_volume;
43 	daddr_t	c_tapea;
44 	ino_t	c_inumber;
45 	int	c_magic;
46 	int	c_checksum;
47 	struct	dinode	c_dinode;
48 	int	c_count;
49 	char	c_addr[OBSIZE];
50 } spcl;
51 
52 struct	idates
53 {
54 	char	id_name[16];
55 	char	id_incno;
56 	time_t	id_ddate;
57 };
58 
59 /* end of old <dumprestor.h> */
60 
61 #define	MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
62 #define	MBIT(i)	(1<<((unsigned)(i-1)%MLEN))
63 #define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
64 #define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
65 #define	BIT(i,w)	(MWORD(w,i) & MBIT(i))
66 
67 struct	filsys	sblock;
68 
69 int	fi;
70 ino_t	ino, maxi, curino;
71 
72 int	mt;
73 char	tapename[] = "/dev/rmt8";
74 char	*magtape = tapename;
75 #ifdef STANDALONE
76 char	mbuf[50];
77 #endif
78 
79 #ifndef STANDALONE
80 daddr_t	seekpt;
81 int	df, ofile;
82 char	dirfile[] = "rstXXXXXX";
83 
84 struct {
85 	ino_t	t_ino;
86 	daddr_t	t_seekpt;
87 } inotab[MAXINO];
88 int	ipos;
89 
90 #define ONTAPE	1
91 #define XTRACTD	2
92 #define XINUSE	4
93 struct xtrlist {
94 	ino_t	x_ino;
95 	char	x_flags;
96 } xtrlist[MAXXTR];
97 
98 char	name[12];
99 
100 char	drblock[BSIZE];
101 int	bpt;
102 #endif
103 
104 int	eflag;
105 
106 int	volno = 1;
107 
108 struct dinode tino, dino;
109 daddr_t	taddr[NADDR];
110 
111 daddr_t	curbno;
112 
113 short	dumpmap[MSIZ];
114 short	clrimap[MSIZ];
115 
116 
117 int bct = NTREC+1;
118 char tbf[NTREC*OBSIZE];
119 
120 struct	cache {
121 	daddr_t	c_bno;
122 	int	c_time;
123 	char	c_block[BSIZE];
124 } cache[NCACHE];
125 int	curcache;
126 
127 main(argc, argv)
128 char *argv[];
129 {
130 	register char *cp;
131 	char command;
132 	int done();
133 
134 #ifndef STANDALONE
135 	mktemp(dirfile);
136 	if (argc < 2) {
137 usage:
138 		printf("Usage: oldrestor x file file..., oldrestor r filesys, or oldrestor t\n");
139 		exit(1);
140 	}
141 	argv++;
142 	argc -= 2;
143 	for (cp = *argv++; *cp; cp++) {
144 		switch (*cp) {
145 		case '-':
146 			break;
147 		case 'f':
148 			magtape = *argv++;
149 			argc--;
150 			break;
151 		case 'r':
152 		case 'R':
153 		case 't':
154 		case 'x':
155 			command = *cp;
156 			break;
157 		default:
158 			printf("Bad key character %c\n", *cp);
159 			goto usage;
160 		}
161 	}
162 	if (command == 'x') {
163 		if (signal(SIGINT, done) == SIG_IGN)
164 			signal(SIGINT, SIG_IGN);
165 		if (signal(SIGTERM, done) == SIG_IGN)
166 			signal(SIGTERM, SIG_IGN);
167 
168 		df = creat(dirfile, 0666);
169 		if (df < 0) {
170 			printf("restor: %s - cannot create directory temporary\n", dirfile);
171 			exit(1);
172 		}
173 		close(df);
174 		df = open(dirfile, 2);
175 	}
176 	doit(command, argc, argv);
177 	if (command == 'x')
178 		unlink(dirfile);
179 	exit(0);
180 #else
181 	magtape = "tape";
182 	doit('r', 1, 0);
183 #endif
184 }
185 
186 doit(command, argc, argv)
187 char	command;
188 int	argc;
189 char	*argv[];
190 {
191 	extern char *ctime();
192 	register i, k;
193 	ino_t	d;
194 #ifndef STANDALONE
195 	int	xtrfile(), skip();
196 #endif
197 	int	rstrfile(), rstrskip();
198 	struct dinode *ip, *ip1;
199 
200 #ifndef STANDALONE
201 	if ((mt = open(magtape, 0)) < 0) {
202 		printf("%s: cannot open tape\n", magtape);
203 		exit(1);
204 	}
205 #else
206 	do {
207 		printf("Tape? ");
208 		gets(mbuf);
209 		mt = open(mbuf, 0);
210 	} while (mt == -1);
211 	magtape = mbuf;
212 #endif
213 	switch(command) {
214 #ifndef STANDALONE
215 	case 't':
216 		if (readhdr(&spcl) == 0) {
217 			printf("Tape is not a dump tape\n");
218 			exit(1);
219 		}
220 		printf("Dump   date: %s", ctime(&spcl.c_date));
221 		printf("Dumped from: %s", ctime(&spcl.c_ddate));
222 		return;
223 	case 'x':
224 		if (readhdr(&spcl) == 0) {
225 			printf("Tape is not a dump tape\n");
226 			exit(1);
227 		}
228 		if (checkvol(&spcl, 1) == 0) {
229 			printf("Tape is not volume 1 of the dump\n");
230 			exit(1);
231 		}
232 		pass1();  /* This sets the various maps on the way by */
233 		i = 0;
234 		while (i < MAXXTR-1 && argc--) {
235 			if ((d = psearch(*argv)) == 0 || BIT(d, dumpmap) == 0) {
236 				printf("%s: not on the tape\n", *argv++);
237 				continue;
238 			}
239 			xtrlist[i].x_ino = d;
240 			xtrlist[i].x_flags |= XINUSE;
241 			printf("%s: inode %u\n", *argv, d);
242 			argv++;
243 			i++;
244 		}
245 newvol:
246 		flsht();
247 		close(mt);
248 getvol:
249 		printf("Mount desired tape volume: Specify volume #: ");
250 		if (gets(tbf) == NULL)
251 			return;
252 		volno = atoi(tbf);
253 		if (volno <= 0) {
254 			printf("Volume numbers are positive numerics\n");
255 			goto getvol;
256 		}
257 		mt = open(magtape, 0);
258 		if (readhdr(&spcl) == 0) {
259 			printf("tape is not dump tape\n");
260 			goto newvol;
261 		}
262 		if (checkvol(&spcl, volno) == 0) {
263 			printf("Wrong volume (%d)\n", spcl.c_volume);
264 			goto newvol;
265 		}
266 rbits:
267 		while (gethead(&spcl) == 0)
268 			;
269 		if (checktype(&spcl, TS_INODE) == 1) {
270 			printf("Can't find inode mask!\n");
271 			goto newvol;
272 		}
273 		if (checktype(&spcl, TS_BITS) == 0)
274 			goto rbits;
275 		readbits(dumpmap);
276 		i = 0;
277 		for (k = 0; xtrlist[k].x_flags; k++) {
278 			if (BIT(xtrlist[k].x_ino, dumpmap)) {
279 				xtrlist[k].x_flags |= ONTAPE;
280 				i++;
281 			}
282 		}
283 		while (i > 0) {
284 again:
285 			if (ishead(&spcl) == 0)
286 				while(gethead(&spcl) == 0)
287 					;
288 			if (checktype(&spcl, TS_END) == 1) {
289 				printf("end of tape\n");
290 checkdone:
291 				for (k = 0; xtrlist[k].x_flags; k++)
292 					if ((xtrlist[k].x_flags&XTRACTD) == 0)
293 						goto newvol;
294 					return;
295 			}
296 			if (checktype(&spcl, TS_INODE) == 0) {
297 				gethead(&spcl);
298 				goto again;
299 			}
300 			d = spcl.c_inumber;
301 			for (k = 0; xtrlist[k].x_flags; k++) {
302 				if (d == xtrlist[k].x_ino) {
303 					printf("extract file %u\n", xtrlist[k].x_ino);
304 					sprintf(name, "%u", xtrlist[k].x_ino);
305 					if ((ofile = creat(name, 0666)) < 0) {
306 						printf("%s: cannot create file\n", name);
307 						i--;
308 						continue;
309 					}
310 					chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
311 					getfile(ino, xtrfile, skip, spcl.c_dinode.di_size);
312 					i--;
313 					xtrlist[k].x_flags |= XTRACTD;
314 					close(ofile);
315 					goto done;
316 				}
317 			}
318 			gethead(&spcl);
319 done:
320 			;
321 		}
322 		goto checkdone;
323 #endif
324 	case 'r':
325 	case 'R':
326 #ifndef STANDALONE
327 		if ((fi = open(*argv, 2)) < 0) {
328 			printf("%s: cannot open\n", *argv);
329 			exit(1);
330 		}
331 #else
332 		do {
333 			char charbuf[50];
334 
335 			printf("Disk? ");
336 			gets(charbuf);
337 			fi = open(charbuf, 2);
338 		} while (fi == -1);
339 #endif
340 #ifndef STANDALONE
341 		if (command == 'R') {
342 			printf("Enter starting volume number: ");
343 			if (gets(tbf) == EOF) {
344 				volno = 1;
345 				printf("\n");
346 			}
347 			else
348 				volno = atoi(tbf);
349 		}
350 		else
351 #endif
352 			volno = 1;
353 		printf("Last chance before scribbling on %s. ",
354 #ifdef STANDALONE
355 								"disk");
356 #else
357 								*argv);
358 #endif
359 		while (getchar() != '\n');
360 		dread((daddr_t)1, (char *)&sblock, sizeof(sblock));
361 		maxi = (sblock.s_isize-2)*INOPB;
362 		if (readhdr(&spcl) == 0) {
363 			printf("Missing volume record\n");
364 			exit(1);
365 		}
366 		if (checkvol(&spcl, volno) == 0) {
367 			printf("Tape is not volume %d\n", volno);
368 			exit(1);
369 		}
370 		gethead(&spcl);
371 		for (;;) {
372 ragain:
373 			if (ishead(&spcl) == 0) {
374 				printf("Missing header block\n");
375 				while (gethead(&spcl) == 0)
376 					;
377 				eflag++;
378 			}
379 			if (checktype(&spcl, TS_END) == 1) {
380 				printf("End of tape\n");
381 				close(mt);
382 				dwrite( (daddr_t) 1, (char *) &sblock);
383 				return;
384 			}
385 			if (checktype(&spcl, TS_CLRI) == 1) {
386 				readbits(clrimap);
387 				for (ino = 1; ino <= maxi; ino++)
388 					if (BIT(ino, clrimap) == 0) {
389 						getdino(ino, &tino);
390 						if (tino.di_mode == 0)
391 							continue;
392 						itrunc(&tino);
393 						clri(&tino);
394 						putdino(ino, &tino);
395 					}
396 				dwrite( (daddr_t) 1, (char *) &sblock);
397 				goto ragain;
398 			}
399 			if (checktype(&spcl, TS_BITS) == 1) {
400 				readbits(dumpmap);
401 				goto ragain;
402 			}
403 			if (checktype(&spcl, TS_INODE) == 0) {
404 				printf("Unknown header type\n");
405 				eflag++;
406 				gethead(&spcl);
407 				goto ragain;
408 			}
409 			ino = spcl.c_inumber;
410 			if (eflag)
411 				printf("Resynced at inode %u\n", ino);
412 			eflag = 0;
413 			if (ino > maxi) {
414 				printf("%u: ilist too small\n", ino);
415 				gethead(&spcl);
416 				goto ragain;
417 			}
418 			dino = spcl.c_dinode;
419 			getdino(ino, &tino);
420 			curbno = 0;
421 			itrunc(&tino);
422 			clri(&tino);
423 			for (i = 0; i < NADDR; i++)
424 				taddr[i] = 0;
425 			l3tol(taddr, dino.di_addr, 1);
426 			getfile(d, rstrfile, rstrskip, dino.di_size);
427 			ip = &tino;
428 			ltol3(ip->di_addr, taddr, NADDR);
429 			ip1 = &dino;
430 			ip->di_mode = ip1->di_mode;
431 			ip->di_nlink = ip1->di_nlink;
432 			ip->di_uid = ip1->di_uid;
433 			ip->di_gid = ip1->di_gid;
434 			ip->di_size = ip1->di_size;
435 			ip->di_atime = ip1->di_atime;
436 			ip->di_mtime = ip1->di_mtime;
437 			ip->di_ctime = ip1->di_ctime;
438 			putdino(ino, &tino);
439 		}
440 	}
441 }
442 
443 /*
444  * Read the tape, bulding up a directory structure for extraction
445  * by name
446  */
447 #ifndef STANDALONE
448 pass1()
449 {
450 	register i;
451 	struct dinode *ip;
452 	int	putdir(), null();
453 
454 	while (gethead(&spcl) == 0) {
455 		printf("Can't find directory header!\n");
456 	}
457 	for (;;) {
458 		if (checktype(&spcl, TS_BITS) == 1) {
459 			readbits(dumpmap);
460 			continue;
461 		}
462 		if (checktype(&spcl, TS_CLRI) == 1) {
463 			readbits(clrimap);
464 			continue;
465 		}
466 		if (checktype(&spcl, TS_INODE) == 0) {
467 finish:
468 			flsh();
469 			close(mt);
470 			return;
471 		}
472 		ip = &spcl.c_dinode;
473 		i = ip->di_mode & IFMT;
474 		if (i != IFDIR) {
475 			goto finish;
476 		}
477 		inotab[ipos].t_ino = spcl.c_inumber;
478 		inotab[ipos++].t_seekpt = seekpt;
479 		getfile(spcl.c_inumber, putdir, null, spcl.c_dinode.di_size);
480 		putent("\000\000/");
481 	}
482 }
483 #endif
484 
485 /*
486  * Do the file extraction, calling the supplied functions
487  * with the blocks
488  */
489 getfile(n, f1, f2, size)
490 ino_t	n;
491 int	(*f2)(), (*f1)();
492 long	size;
493 {
494 	register i;
495 	struct spcl addrblock;
496 	char buf[BSIZE];
497 
498 	addrblock = spcl;
499 	curino = n;
500 	goto start;
501 	for (;;) {
502 		if (gethead(&addrblock) == 0) {
503 			printf("Missing address (header) block\n");
504 			goto eloop;
505 		}
506 		if (checktype(&addrblock, TS_ADDR) == 0) {
507 			spcl = addrblock;
508 			curino = 0;
509 			curino = 0;
510 			return;
511 		}
512 start:
513 		for (i = 0; i < addrblock.c_count; i += 2) {
514 			if (addrblock.c_addr[i])
515 				readtape(buf, 0);
516 			else
517 				clearbuf(buf, 0);
518 			if (size > OBSIZE && addrblock.c_addr[i+1])
519 				readtape(buf, 1);
520 			else
521 				clearbuf(buf, 1);
522 			if (addrblock.c_addr[i] || size > OBSIZE && addrblock.c_addr[i + 1])
523 				(*f1)(buf, size > BSIZE ? (long) BSIZE : size);
524 			else
525 				(*f2)(buf, size > BSIZE ? (long) BSIZE : size);
526 			if ((size -= BSIZE) <= 0) {
527 eloop:
528 				while (gethead(&spcl) == 0)
529 					;
530 				if (checktype(&spcl, TS_ADDR) == 1)
531 					goto eloop;
532 				curino = 0;
533 				return;
534 			}
535 		}
536 	}
537 }
538 
539 /*
540  * Do the tape i\/o, dealling with volume changes
541  * etc..
542  */
543 readtape(b, part)
544 char *b;
545 {
546 	register i;
547 	struct spcl tmpbuf;
548 
549 	if (bct >= NTREC) {
550 		for (i = 0; i < NTREC; i++)
551 			((struct spcl *)&tbf[i*OBSIZE])->c_magic = 0;
552 		bct = 0;
553 		if ((i = read(mt, tbf, NTREC*OBSIZE)) < 0) {
554 			printf("Tape read error: inode %u\n", curino);
555 			eflag++;
556 			exit(1);
557 		}
558 		if (i == 0) {
559 			bct = NTREC + 1;
560 			volno++;
561 loop:
562 			flsht();
563 			close(mt);
564 			printf("Mount volume %d\n", volno);
565 			while (getchar() != '\n')
566 				;
567 			if ((mt = open(magtape, 0)) == -1) {
568 				printf("Cannot open tape!\n");
569 				goto loop;
570 			}
571 			if (readhdr(&tmpbuf) == 0) {
572 				printf("Not a dump tape.Try again\n");
573 				goto loop;
574 			}
575 			if (checkvol(&tmpbuf, volno) == 0) {
576 				printf("Wrong tape. Try again\n");
577 				goto loop;
578 			}
579 			readtape(b, part);
580 			return;
581 		}
582 	}
583 	copy(&tbf[(bct++*OBSIZE)], b + part * OBSIZE, OBSIZE);
584 }
585 
586 flsht()
587 {
588 	bct = NTREC+1;
589 }
590 
591 copy(f, t, s)
592 register char *f, *t;
593 {
594 	register i;
595 
596 	i = s;
597 	do
598 		*t++ = *f++;
599 	while (--i);
600 }
601 
602 clearbuf(cp, part)
603 register char *cp;
604 {
605 	register i;
606 
607 	cp += part * OBSIZE;
608 	i = OBSIZE;
609 	do
610 		*cp++ = 0;
611 	while (--i);
612 }
613 
614 /*
615  * Put and get the directory entries from the compressed
616  * directory file
617  */
618 #ifndef STANDALONE
619 putent(cp)
620 char	*cp;
621 {
622 	register i;
623 
624 	for (i = 0; i < sizeof(ino_t); i++)
625 		writec(*cp++);
626 	for (i = 0; i < DIRSIZ; i++) {
627 		writec(*cp);
628 		if (*cp++ == 0)
629 			return;
630 	}
631 	return;
632 }
633 
634 getent(bf)
635 register char *bf;
636 {
637 	register i;
638 
639 	for (i = 0; i < sizeof(ino_t); i++)
640 		*bf++ = readc();
641 	for (i = 0; i < DIRSIZ; i++)
642 		if ((*bf++ = readc()) == 0)
643 			return;
644 	return;
645 }
646 
647 /*
648  * read/write te directory file
649  */
650 writec(c)
651 char c;
652 {
653 	drblock[bpt++] = c;
654 	seekpt++;
655 	if (bpt >= BSIZE) {
656 		bpt = 0;
657 		write(df, drblock, BSIZE);
658 	}
659 }
660 
661 readc()
662 {
663 	if (bpt >= BSIZE) {
664 		read(df, drblock, BSIZE);
665 		bpt = 0;
666 	}
667 	return(drblock[bpt++]);
668 }
669 
670 mseek(pt)
671 daddr_t pt;
672 {
673 	bpt = BSIZE;
674 	lseek(df, pt, 0);
675 }
676 
677 flsh()
678 {
679 	write(df, drblock, bpt+1);
680 }
681 
682 /*
683  * search the directory inode ino
684  * looking for entry cp
685  */
686 ino_t
687 search(inum, cp)
688 ino_t	inum;
689 char	*cp;
690 {
691 	register i;
692 	struct direct dir;
693 
694 	for (i = 0; i < MAXINO; i++)
695 		if (inotab[i].t_ino == inum) {
696 			goto found;
697 		}
698 	return(0);
699 found:
700 	mseek(inotab[i].t_seekpt);
701 	do {
702 		getent((char *)&dir);
703 		if (direq(dir.d_name, "/"))
704 			return(0);
705 	} while (direq(dir.d_name, cp) == 0);
706 	return(dir.d_ino);
707 }
708 
709 /*
710  * Search the directory tree rooted at inode 2
711  * for the path pointed at by n
712  */
713 psearch(n)
714 char	*n;
715 {
716 	register char *cp, *cp1;
717 	char c;
718 
719 	ino = 2;
720 	if (*(cp = n) == '/')
721 		cp++;
722 next:
723 	cp1 = cp + 1;
724 	while (*cp1 != '/' && *cp1)
725 		cp1++;
726 	c = *cp1;
727 	*cp1 = 0;
728 	ino = search(ino, cp);
729 	if (ino == 0) {
730 		*cp1 = c;
731 		return(0);
732 	}
733 	*cp1 = c;
734 	if (c == '/') {
735 		cp = cp1+1;
736 		goto next;
737 	}
738 	return(ino);
739 }
740 
741 direq(s1, s2)
742 register char *s1, *s2;
743 {
744 	register i;
745 
746 	for (i = 0; i < DIRSIZ; i++)
747 		if (*s1++ == *s2) {
748 			if (*s2++ == 0)
749 				return(1);
750 		} else
751 			return(0);
752 	return(1);
753 }
754 #endif
755 
756 /*
757  * read/write a disk block, be sure to update the buffer
758  * cache if needed.
759  */
760 dwrite(bno, b)
761 daddr_t	bno;
762 char	*b;
763 {
764 	register i;
765 
766 	for (i = 0; i < NCACHE; i++) {
767 		if (cache[i].c_bno == bno) {
768 			copy(b, cache[i].c_block, BSIZE);
769 			cache[i].c_time = 0;
770 			break;
771 		}
772 		else
773 			cache[i].c_time++;
774 	}
775 	lseek(fi, bno*BSIZE, 0);
776 	if(write(fi, b, BSIZE) != BSIZE) {
777 #ifdef STANDALONE
778 		printf("disk write error %D\n", bno);
779 #else
780 		fprintf(stderr, "disk write error %ld\n", bno);
781 #endif
782 		exit(1);
783 	}
784 }
785 
786 dread(bno, buf, cnt)
787 daddr_t bno;
788 char *buf;
789 {
790 	register i, j;
791 
792 	j = 0;
793 	for (i = 0; i < NCACHE; i++) {
794 		if (++curcache >= NCACHE)
795 			curcache = 0;
796 		if (cache[curcache].c_bno == bno) {
797 			copy(cache[curcache].c_block, buf, cnt);
798 			cache[curcache].c_time = 0;
799 			return;
800 		}
801 		else {
802 			cache[curcache].c_time++;
803 			if (cache[j].c_time < cache[curcache].c_time)
804 				j = curcache;
805 		}
806 	}
807 
808 	lseek(fi, bno*BSIZE, 0);
809 	if (read(fi, cache[j].c_block, BSIZE) != BSIZE) {
810 #ifdef STANDALONE
811 		printf("read error %D\n", bno);
812 #else
813 		printf("read error %ld\n", bno);
814 #endif
815 		exit(1);
816 	}
817 	copy(cache[j].c_block, buf, cnt);
818 	cache[j].c_time = 0;
819 	cache[j].c_bno = bno;
820 }
821 
822 /*
823  * the inode manpulation routines. Like the system.
824  *
825  * clri zeros the inode
826  */
827 clri(ip)
828 struct dinode *ip;
829 {
830 	int i, *p;
831 	i = sizeof(struct dinode)/sizeof(int);
832 	p = (int *)ip;
833 	do
834 		*p++ = 0;
835 	while(--i);
836 }
837 
838 /*
839  * itrunc/tloop/bfree free all of the blocks pointed at by the inode
840  */
841 itrunc(ip)
842 register struct dinode *ip;
843 {
844 	register i;
845 	daddr_t bn, iaddr[NADDR];
846 
847 	if (ip->di_mode == 0)
848 		return;
849 	i = ip->di_mode & IFMT;
850 	if (i != IFDIR && i != IFREG)
851 		return;
852 	l3tol(iaddr, ip->di_addr, NADDR);
853 	for(i=NADDR-1;i>=0;i--) {
854 		bn = iaddr[i];
855 		if(bn == 0) continue;
856 		switch(i) {
857 
858 		default:
859 			bfree(bn);
860 			break;
861 
862 		case NADDR-3:
863 			tloop(bn, 0, 0);
864 			break;
865 
866 		case NADDR-2:
867 			tloop(bn, 1, 0);
868 			break;
869 
870 		case NADDR-1:
871 			tloop(bn, 1, 1);
872 		}
873 	}
874 	ip->di_size = 0;
875 }
876 
877 tloop(bn, f1, f2)
878 daddr_t	bn;
879 int	f1, f2;
880 {
881 	register i;
882 	daddr_t nb;
883 	union {
884 		char	data[BSIZE];
885 		daddr_t	indir[NINDIR];
886 	} ibuf;
887 
888 	dread(bn, ibuf.data, BSIZE);
889 	for(i=NINDIR-1;i>=0;i--) {
890 		nb = ibuf.indir[i];
891 		if(nb) {
892 			if(f1)
893 				tloop(nb, f2, 0);
894 			else
895 				bfree(nb);
896 		}
897 	}
898 	bfree(bn);
899 }
900 
901 bfree(bn)
902 daddr_t	bn;
903 {
904 	register i;
905 	union {
906 		char	data[BSIZE];
907 		struct	fblk frees;
908 	} fbuf;
909 
910 	if(sblock.s_nfree >= NICFREE) {
911 		fbuf.df_nfree = sblock.s_nfree;
912 		for(i=0;i<NICFREE;i++)
913 			fbuf.df_free[i] = sblock.s_free[i];
914 		sblock.s_nfree = 0;
915 		dwrite(bn, fbuf.data);
916 	}
917 	sblock.s_free[sblock.s_nfree++] = bn;
918 }
919 
920 /*
921  * allocate a block off the free list.
922  */
923 daddr_t
924 balloc()
925 {
926 	daddr_t	bno;
927 	register i;
928 	static char zeroes[BSIZE];
929 	union {
930 		char	data[BSIZE];
931 		struct	fblk frees;
932 	} fbuf;
933 
934 	if(sblock.s_nfree == 0 || (bno=sblock.s_free[--sblock.s_nfree]) == 0) {
935 #ifdef STANDALONE
936 		printf("Out of space\n");
937 #else
938 		fprintf(stderr, "Out of space.\n");
939 #endif
940 		exit(1);
941 	}
942 	if(sblock.s_nfree == 0) {
943 		dread(bno, fbuf.data, BSIZE);
944 		sblock.s_nfree = fbuf.df_nfree;
945 		for(i=0;i<NICFREE;i++)
946 			sblock.s_free[i] = fbuf.df_free[i];
947 	}
948 	dwrite(bno, zeroes);
949 	return(bno);
950 }
951 
952 /*
953  * map a block number into a block address, ensuring
954  * all of the correct indirect blocks are around. Allocate
955  * the block requested.
956  */
957 daddr_t
958 bmap(iaddr, bn)
959 daddr_t	iaddr[NADDR];
960 daddr_t	bn;
961 {
962 	register i;
963 	int j, sh;
964 	daddr_t nb, nnb;
965 	daddr_t indir[NINDIR];
966 
967 	/*
968 	 * blocks 0..NADDR-4 are direct blocks
969 	 */
970 	if(bn < NADDR-3) {
971 		iaddr[bn] = nb = balloc();
972 		return(nb);
973 	}
974 
975 	/*
976 	 * addresses NADDR-3, NADDR-2, and NADDR-1
977 	 * have single, double, triple indirect blocks.
978 	 * the first step is to determine
979 	 * how many levels of indirection.
980 	 */
981 	sh = 0;
982 	nb = 1;
983 	bn -= NADDR-3;
984 	for(j=3; j>0; j--) {
985 		sh += NSHIFT;
986 		nb <<= NSHIFT;
987 		if(bn < nb)
988 			break;
989 		bn -= nb;
990 	}
991 	if(j == 0) {
992 		return((daddr_t)0);
993 	}
994 
995 	/*
996 	 * fetch the address from the inode
997 	 */
998 	if((nb = iaddr[NADDR-j]) == 0) {
999 		iaddr[NADDR-j] = nb = balloc();
1000 	}
1001 
1002 	/*
1003 	 * fetch through the indirect blocks
1004 	 */
1005 	for(; j<=3; j++) {
1006 		dread(nb, (char *)indir, BSIZE);
1007 		sh -= NSHIFT;
1008 		i = (bn>>sh) & NMASK;
1009 		nnb = indir[i];
1010 		if(nnb == 0) {
1011 			nnb = balloc();
1012 			indir[i] = nnb;
1013 			dwrite(nb, (char *)indir);
1014 		}
1015 		nb = nnb;
1016 	}
1017 	return(nb);
1018 }
1019 
1020 /*
1021  * read the tape into buf, then return whether or
1022  * or not it is a header block.
1023  */
1024 gethead(buf)
1025 struct spcl *buf;
1026 {
1027 	readtape((char *)buf, 0);
1028 	if (buf->c_magic != MAGIC || checksum((int *) buf) == 0)
1029 		return(0);
1030 	return(1);
1031 }
1032 
1033 /*
1034  * return whether or not the buffer contains a header block
1035  */
1036 ishead(buf)
1037 struct spcl *buf;
1038 {
1039 	if (buf->c_magic != MAGIC || checksum((int *) buf) == 0)
1040 		return(0);
1041 	return(1);
1042 }
1043 
1044 checktype(b, t)
1045 struct	spcl *b;
1046 int	t;
1047 {
1048 	return(b->c_type == t);
1049 }
1050 
1051 
1052 checksum(b)
1053 int *b;
1054 {
1055 	register i, j;
1056 
1057 	j = OBSIZE/sizeof(int);
1058 	i = 0;
1059 	do
1060 		i += *b++;
1061 	while (--j);
1062 	if (i != CHECKSUM) {
1063 		printf("Checksum error %o\n", i);
1064 		return(0);
1065 	}
1066 	return(1);
1067 }
1068 
1069 checkvol(b, t)
1070 struct spcl *b;
1071 int t;
1072 {
1073 	if (b->c_volume == t)
1074 		return(1);
1075 	return(0);
1076 }
1077 
1078 readhdr(b)
1079 struct	spcl *b;
1080 {
1081 	if (gethead(b) == 0)
1082 		return(0);
1083 	if (checktype(b, TS_TAPE) == 0)
1084 		return(0);
1085 	return(1);
1086 }
1087 
1088 /*
1089  * The next routines are called during file extraction to
1090  * put the data into the right form and place.
1091  */
1092 #ifndef STANDALONE
1093 xtrfile(b, size)
1094 char	*b;
1095 long	size;
1096 {
1097 	write(ofile, b, (int) size);
1098 }
1099 
1100 null() {;}
1101 
1102 skip()
1103 {
1104 	lseek(ofile, (long) OBSIZE, 1);
1105 }
1106 #endif
1107 
1108 
1109 rstrfile(b, s)
1110 char *b;
1111 long s;
1112 {
1113 	daddr_t d;
1114 
1115 	d = bmap(taddr, curbno);
1116 	dwrite(d, b);
1117 	curbno += 1;
1118 }
1119 
1120 rstrskip(b, s)
1121 char *b;
1122 long s;
1123 {
1124 	curbno += 1;
1125 }
1126 
1127 #ifndef STANDALONE
1128 putdir(b)
1129 char *b;
1130 {
1131 	register struct direct *dp;
1132 	register i;
1133 
1134 	for (dp = (struct direct *) b, i = 0; i < BSIZE; dp++, i += sizeof(*dp)) {
1135 		if (dp->d_ino == 0)
1136 			continue;
1137 		putent((char *) dp);
1138 	}
1139 }
1140 #endif
1141 
1142 /*
1143  * read/write an inode from the disk
1144  */
1145 getdino(inum, b)
1146 ino_t	inum;
1147 struct	dinode *b;
1148 {
1149 	daddr_t	bno;
1150 	char buf[BSIZE];
1151 
1152 	bno = (ino - 1)/INOPB;
1153 	bno += 2;
1154 	dread(bno, buf, BSIZE);
1155 	copy(&buf[((inum-1)%INOPB)*sizeof(struct dinode)], (char *) b, sizeof(struct dinode));
1156 }
1157 
1158 putdino(inum, b)
1159 ino_t	inum;
1160 struct	dinode *b;
1161 {
1162 	daddr_t bno;
1163 	char buf[BSIZE];
1164 
1165 	bno = ((ino - 1)/INOPB) + 2;
1166 	dread(bno, buf, BSIZE);
1167 	copy((char *) b, &buf[((inum-1)%INOPB)*sizeof(struct dinode)], sizeof(struct dinode));
1168 	dwrite(bno, buf);
1169 }
1170 
1171 /*
1172  * read a bit mask from the tape into m.
1173  */
1174 readbits(m)
1175 short	*m;
1176 {
1177 	register i;
1178 
1179 	i = spcl.c_count;
1180 
1181 	while (i--) {
1182 		readtape((char *) m, 0);
1183 		m += (OBSIZE/(MLEN/BITS));
1184 	}
1185 	while (gethead(&spcl) == 0)
1186 		;
1187 }
1188 
1189 done()
1190 {
1191 	unlink(dirfile);
1192 	exit(0);
1193 }
1194