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