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