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
main(argc,argv)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
doit(command,argc,argv)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
pass1()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 */
getfile(n,f1,f2,size)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 */
readtape(b,part)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
flsht()586 flsht()
587 {
588 bct = NTREC+1;
589 }
590
copy(f,t,s)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
clearbuf(cp,part)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
putent(cp)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
getent(bf)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 */
writec(c)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
readc()661 readc()
662 {
663 if (bpt >= BSIZE) {
664 read(df, drblock, BSIZE);
665 bpt = 0;
666 }
667 return(drblock[bpt++]);
668 }
669
mseek(pt)670 mseek(pt)
671 daddr_t pt;
672 {
673 bpt = BSIZE;
674 lseek(df, pt, 0);
675 }
676
flsh()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
search(inum,cp)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 */
psearch(n)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
direq(s1,s2)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 */
dwrite(bno,b)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
dread(bno,buf,cnt)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 */
itrunc(ip)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
tloop(bn,f1,f2)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
bfree(bn)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
balloc()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
bmap(iaddr,bn)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
checksum(b)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
xtrfile(b,size)1093 xtrfile(b, size)
1094 char *b;
1095 long size;
1096 {
1097 write(ofile, b, (int) size);
1098 }
1099
null()1100 null() {;}
1101
skip()1102 skip()
1103 {
1104 lseek(ofile, (long) OBSIZE, 1);
1105 }
1106 #endif
1107
1108
rstrfile(b,s)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
rstrskip(b,s)1120 rstrskip(b, s)
1121 char *b;
1122 long s;
1123 {
1124 curbno += 1;
1125 }
1126
1127 #ifndef STANDALONE
putdir(b)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 */
getdino(inum,b)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
putdino(inum,b)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 */
readbits(m)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
done()1189 done()
1190 {
1191 unlink(dirfile);
1192 exit(0);
1193 }
1194