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