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