1 static char *sccsid = "@(#)tar.c 4.8 (Berkeley) 82/03/31"; 2 3 /* 4 * Tape Archival Program 5 */ 6 #include <stdio.h> 7 #include <sys/param.h> 8 #include <sys/stat.h> 9 #include <ndir.h> 10 #include <sys/mtio.h> 11 #include <signal.h> 12 13 #define TBLOCK 512 14 #define NBLOCK 20 15 #define NAMSIZ 100 16 17 union hblock { 18 char dummy[TBLOCK]; 19 struct header { 20 char name[NAMSIZ]; 21 char mode[8]; 22 char uid[8]; 23 char gid[8]; 24 char size[12]; 25 char mtime[12]; 26 char chksum[8]; 27 char linkflag; 28 char linkname[NAMSIZ]; 29 } dbuf; 30 }; 31 32 struct linkbuf { 33 ino_t inum; 34 dev_t devnum; 35 int count; 36 char pathname[NAMSIZ]; 37 struct linkbuf *nextp; 38 }; 39 40 union hblock dblock; 41 union hblock tbuf[NBLOCK]; 42 struct linkbuf *ihead; 43 struct stat stbuf; 44 45 int rflag; 46 int xflag; 47 int vflag; 48 int tflag; 49 int cflag; 50 int mflag; 51 int fflag; 52 int oflag; 53 int pflag; 54 int wflag; 55 int hflag; 56 57 int mt; 58 int term; 59 int chksum; 60 int recno; 61 int first; 62 int linkerrok; 63 int freemem = 1; 64 int nblock = NBLOCK; 65 int onintr(); 66 int onquit(); 67 int onhup(); 68 int onterm(); 69 70 daddr_t low; 71 daddr_t high; 72 daddr_t bsrch(); 73 74 FILE *tfile; 75 char tname[] = "/tmp/tarXXXXXX"; 76 char *usefile; 77 char magtape[] = "/dev/rmt8"; 78 char *malloc(); 79 char *sprintf(); 80 char *strcat(); 81 82 main(argc, argv) 83 int argc; 84 char *argv[]; 85 { 86 char *cp; 87 88 if (argc < 2) 89 usage(); 90 91 tfile = NULL; 92 usefile = magtape; 93 argv[argc] = 0; 94 argv++; 95 for (cp = *argv++; *cp; cp++) 96 switch(*cp) { 97 98 case 'f': 99 usefile = *argv++; 100 fflag++; 101 break; 102 103 case 'c': 104 cflag++; 105 rflag++; 106 break; 107 108 case 'o': 109 oflag++; 110 break; 111 112 case 'p': 113 pflag++; 114 break; 115 116 case 'u': 117 mktemp(tname); 118 if ((tfile = fopen(tname, "w")) == NULL) { 119 fprintf(stderr, 120 "Tar: cannot create temporary file (%s)\n", 121 tname); 122 done(1); 123 } 124 fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 125 /*FALL THRU*/ 126 127 case 'r': 128 rflag++; 129 break; 130 131 case 'v': 132 vflag++; 133 break; 134 135 case 'w': 136 wflag++; 137 break; 138 139 case 'x': 140 xflag++; 141 break; 142 143 case 't': 144 tflag++; 145 break; 146 147 case 'm': 148 mflag++; 149 break; 150 151 case '-': 152 break; 153 154 case '0': 155 case '1': 156 case '4': 157 case '5': 158 case '7': 159 case '8': 160 magtape[8] = *cp; 161 usefile = magtape; 162 break; 163 164 case 'b': 165 nblock = atoi(*argv++); 166 if (nblock > NBLOCK || nblock <= 0) { 167 fprintf(stderr, "Invalid blocksize. (Max %d)\n", 168 NBLOCK); 169 done(1); 170 } 171 break; 172 173 case 'l': 174 linkerrok++; 175 break; 176 177 case 'h': 178 hflag++; 179 break; 180 181 default: 182 fprintf(stderr, "tar: %c: unknown option\n", *cp); 183 usage(); 184 } 185 186 if (!rflag && !xflag && !tflag) 187 usage(); 188 if (rflag) { 189 if (cflag && tfile != NULL) 190 usage(); 191 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 192 signal(SIGINT, onintr); 193 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 194 signal(SIGHUP, onhup); 195 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 196 signal(SIGQUIT, onquit); 197 #ifdef notdef 198 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 199 signal(SIGTERM, onterm); 200 #endif 201 if (strcmp(usefile, "-") == 0) { 202 if (cflag == 0) { 203 fprintf(stderr, 204 "Can only create standard output archives\n"); 205 done(1); 206 } 207 mt = dup(1); 208 nblock = 1; 209 } else if ((mt = open(usefile, 2)) < 0) { 210 if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 211 fprintf(stderr, 212 "tar: cannot open %s\n", usefile); 213 done(1); 214 } 215 } 216 dorep(argv); 217 done(0); 218 } 219 if (strcmp(usefile, "-") == 0) { 220 mt = dup(0); 221 nblock = 1; 222 } else if ((mt = open(usefile, 0)) < 0) { 223 fprintf(stderr, "tar: cannot open %s\n", usefile); 224 done(1); 225 } 226 if (xflag) 227 doxtract(argv); 228 else 229 dotable(); 230 done(0); 231 } 232 233 usage() 234 { 235 fprintf(stderr, 236 "tar: usage tar -{txru}[cvfblmh] [tapefile] [blocksize] file1 file2...\n"); 237 done(1); 238 } 239 240 dorep(argv) 241 char *argv[]; 242 { 243 register char *cp, *cp2; 244 char wdir[60]; 245 246 if (!cflag) { 247 getdir(); 248 do { 249 passtape(); 250 if (term) 251 done(0); 252 getdir(); 253 } while (!endtape()); 254 if (tfile != NULL) { 255 char buf[200]; 256 257 sprintf(buf, 258 "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 259 tname, tname, tname, tname, tname, tname); 260 fflush(tfile); 261 system(buf); 262 freopen(tname, "r", tfile); 263 fstat(fileno(tfile), &stbuf); 264 high = stbuf.st_size; 265 } 266 } 267 268 getwdir(wdir); 269 while (*argv && ! term) { 270 cp2 = *argv; 271 if (!strcmp(cp2, "-C") && argv[1]) { 272 argv++; 273 if (chdir(*argv) < 0) 274 perror(*argv); 275 else 276 getwdir(wdir); 277 argv++; 278 continue; 279 } 280 for (cp = *argv; *cp; cp++) 281 if (*cp == '/') 282 cp2 = cp; 283 if (cp2 != *argv) { 284 *cp2 = '\0'; 285 chdir(*argv); 286 *cp2 = '/'; 287 cp2++; 288 } 289 putfile(*argv++, cp2); 290 chdir(wdir); 291 } 292 putempty(); 293 putempty(); 294 flushtape(); 295 if (linkerrok == 0) 296 return; 297 for (; ihead != NULL; ihead = ihead->nextp) { 298 if (ihead->count == 0) 299 continue; 300 fprintf(stderr, "Missing links to %s\n", ihead->pathname); 301 } 302 } 303 304 endtape() 305 { 306 if (dblock.dbuf.name[0] != '\0') 307 return (0); 308 backtape(); 309 return (1); 310 } 311 312 getdir() 313 { 314 register struct stat *sp; 315 int i; 316 317 readtape((char *)&dblock); 318 if (dblock.dbuf.name[0] == '\0') 319 return; 320 sp = &stbuf; 321 sscanf(dblock.dbuf.mode, "%o", &i); 322 sp->st_mode = i; 323 sscanf(dblock.dbuf.uid, "%o", &i); 324 sp->st_uid = i; 325 sscanf(dblock.dbuf.gid, "%o", &i); 326 sp->st_gid = i; 327 sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 328 sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 329 sscanf(dblock.dbuf.chksum, "%o", &chksum); 330 if (chksum != checksum()) { 331 fprintf(stderr, "directory checksum error\n"); 332 done(2); 333 } 334 if (tfile != NULL) 335 fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 336 } 337 338 passtape() 339 { 340 long blocks; 341 char buf[TBLOCK]; 342 343 if (dblock.dbuf.linkflag == '1') 344 return; 345 blocks = stbuf.st_size; 346 blocks += TBLOCK-1; 347 blocks /= TBLOCK; 348 349 while (blocks-- > 0) 350 readtape(buf); 351 } 352 353 putfile(longname, shortname) 354 char *longname; 355 char *shortname; 356 { 357 int infile; 358 long blocks; 359 char buf[TBLOCK]; 360 register char *cp, *cp2; 361 struct direct *dp; 362 DIR *dirp; 363 int i, j; 364 365 infile = open(shortname, 0); 366 if (infile < 0) { 367 fprintf(stderr, "tar: %s: cannot open file\n", longname); 368 return; 369 } 370 stat(shortname, &stbuf); 371 if (tfile != NULL && checkupdate(longname) == 0) { 372 close(infile); 373 return; 374 } 375 if (checkw('r', longname) == 0) { 376 close(infile); 377 return; 378 } 379 380 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 381 for (i = 0, cp = buf; *cp++ = longname[i++];) 382 ; 383 *--cp = '/'; 384 *++cp = 0 ; 385 if (!oflag) { 386 if ((cp - buf) >= NAMSIZ) { 387 fprintf(stderr, "%s: file name too long\n", 388 longname); 389 close(infile); 390 return; 391 } 392 stbuf.st_size = 0; 393 tomodes(&stbuf); 394 strcpy(dblock.dbuf.name,buf); 395 sprintf(dblock.dbuf.chksum, "%6o", checksum()); 396 writetape((char *)&dblock); 397 } 398 chdir(shortname); 399 close(infile); 400 if ((dirp = opendir(".")) == NULL) { 401 fprintf(stderr, "%s: directory read error\n", longname); 402 return; 403 } 404 while ((dp = readdir(dirp)) != NULL && !term) { 405 if (dp->d_ino == 0) 406 continue; 407 if (!strcmp(".", dp->d_name) || 408 !strcmp("..", dp->d_name)) 409 continue; 410 strcpy(cp, dp->d_name); 411 i = telldir(dirp); 412 closedir(dirp); 413 putfile(buf, cp); 414 dirp = opendir("."); 415 seekdir(dirp, i); 416 } 417 closedir(dirp); 418 chdir(".."); 419 return; 420 } 421 i = stbuf.st_mode & S_IFMT; 422 if (i != S_IFREG && i != S_IFLNK) { 423 fprintf(stderr, "tar: %s is not a file. Not dumped\n", 424 longname); 425 return; 426 } 427 tomodes(&stbuf); 428 cp2 = longname; cp = dblock.dbuf.name; i = 0; 429 while ((*cp++ = *cp2++) && i < NAMSIZ) 430 i++; 431 if (i >= NAMSIZ) { 432 fprintf(stderr, "%s: file name too long\n", longname); 433 close(infile); 434 return; 435 } 436 if ((stbuf.st_mode & S_IFMT) == S_IFLNK) { 437 if (stbuf.st_size + 1 >= NAMSIZ) { 438 fprintf(stderr, "%s: symbolic link too long\n", 439 longname); 440 close(infile); 441 return; 442 } 443 i = readlink(longname, dblock.dbuf.linkname, NAMSIZ - 1); 444 if (i < 0) { 445 perror("readlink"); 446 close(infile); 447 return; 448 } 449 dblock.dbuf.linkname[i] = '\0'; 450 dblock.dbuf.linkflag = '2'; 451 if (vflag) { 452 fprintf(stderr, "a %s ", longname); 453 fprintf(stderr, "symbolic link to %s\n", 454 dblock.dbuf.linkname); 455 } 456 sprintf(dblock.dbuf.size, "%11lo", 0); 457 sprintf(dblock.dbuf.chksum, "%6o", checksum()); 458 writetape((char *)&dblock); 459 close(infile); 460 return; 461 } 462 if (stbuf.st_nlink > 1) { 463 struct linkbuf *lp; 464 int found = 0; 465 466 for (lp = ihead; lp != NULL; lp = lp->nextp) 467 if (lp->inum == stbuf.st_ino && 468 lp->devnum == stbuf.st_dev) { 469 found++; 470 break; 471 } 472 if (found) { 473 strcpy(dblock.dbuf.linkname, lp->pathname); 474 dblock.dbuf.linkflag = '1'; 475 sprintf(dblock.dbuf.chksum, "%6o", checksum()); 476 writetape( (char *) &dblock); 477 if (vflag) { 478 fprintf(stderr, "a %s ", longname); 479 fprintf(stderr, "link to %s\n", lp->pathname); 480 } 481 lp->count--; 482 close(infile); 483 return; 484 } 485 lp = (struct linkbuf *) malloc(sizeof(*lp)); 486 if (lp == NULL) { 487 if (freemem) { 488 fprintf(stderr, 489 "Out of memory. Link information lost\n"); 490 freemem = 0; 491 } 492 } else { 493 lp->nextp = ihead; 494 ihead = lp; 495 lp->inum = stbuf.st_ino; 496 lp->devnum = stbuf.st_dev; 497 lp->count = stbuf.st_nlink - 1; 498 strcpy(lp->pathname, longname); 499 } 500 } 501 blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 502 if (vflag) { 503 fprintf(stderr, "a %s ", longname); 504 fprintf(stderr, "%ld blocks\n", blocks); 505 } 506 sprintf(dblock.dbuf.chksum, "%6o", checksum()); 507 writetape((char *)&dblock); 508 509 while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 510 writetape(buf); 511 blocks--; 512 } 513 close(infile); 514 if (blocks != 0 || i != 0) 515 fprintf(stderr, "%s: file changed size\n", longname); 516 while (--blocks >= 0) 517 putempty(); 518 } 519 520 doxtract(argv) 521 char *argv[]; 522 { 523 long blocks, bytes; 524 char buf[TBLOCK]; 525 char **cp; 526 int ofile; 527 528 for (;;) { 529 getdir(); 530 if (endtape()) 531 break; 532 if (*argv == 0) 533 goto gotit; 534 for (cp = argv; *cp; cp++) 535 if (prefix(*cp, dblock.dbuf.name)) 536 goto gotit; 537 passtape(); 538 continue; 539 540 gotit: 541 if (checkw('x', dblock.dbuf.name) == 0) { 542 passtape(); 543 continue; 544 } 545 if (checkdir(dblock.dbuf.name)) 546 continue; 547 if (dblock.dbuf.linkflag == '2') { 548 unlink(dblock.dbuf.name); 549 if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 550 fprintf(stderr, "%s: symbolic link failed\n", 551 dblock.dbuf.name); 552 continue; 553 } 554 if (vflag) 555 fprintf(stderr, "x %s symbolic link to %s\n", 556 dblock.dbuf.name, dblock.dbuf.linkname); 557 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 558 if (mflag == 0) { 559 time_t timep[2]; 560 561 timep[0] = time(0); 562 timep[1] = stbuf.st_mtime; 563 utime(dblock.dbuf.name, timep); 564 } 565 if (pflag) 566 chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 567 continue; 568 } 569 if (dblock.dbuf.linkflag == '1') { 570 unlink(dblock.dbuf.name); 571 if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 572 fprintf(stderr, "%s: cannot link\n", 573 dblock.dbuf.name); 574 continue; 575 } 576 if (vflag) 577 fprintf(stderr, "%s linked to %s\n", 578 dblock.dbuf.name, dblock.dbuf.linkname); 579 continue; 580 } 581 if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 582 fprintf(stderr, "tar: %s - cannot create\n", 583 dblock.dbuf.name); 584 passtape(); 585 continue; 586 } 587 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 588 blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 589 if (vflag) 590 fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 591 dblock.dbuf.name, bytes, blocks); 592 for (; blocks-- > 0; bytes -= TBLOCK) { 593 readtape(buf); 594 if (bytes > TBLOCK) { 595 if (write(ofile, buf, TBLOCK) < 0) { 596 fprintf(stderr, 597 "tar: %s: HELP - extract write error\n", 598 dblock.dbuf.name); 599 done(2); 600 } 601 continue; 602 } 603 if (write(ofile, buf, (int) bytes) < 0) { 604 fprintf(stderr, 605 "tar: %s: HELP - extract write error\n", 606 dblock.dbuf.name); 607 done(2); 608 } 609 } 610 close(ofile); 611 if (mflag == 0) { 612 time_t timep[2]; 613 614 timep[0] = time(NULL); 615 timep[1] = stbuf.st_mtime; 616 utime(dblock.dbuf.name, timep); 617 } 618 if (pflag) 619 chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 620 } 621 } 622 623 dotable() 624 { 625 for (;;) { 626 getdir(); 627 if (endtape()) 628 break; 629 if (vflag) 630 longt(&stbuf); 631 printf("%s", dblock.dbuf.name); 632 if (dblock.dbuf.linkflag == '1') 633 printf(" linked to %s", dblock.dbuf.linkname); 634 if (dblock.dbuf.linkflag == '2') 635 printf(" symbolic link to %s", dblock.dbuf.linkname); 636 printf("\n"); 637 passtape(); 638 } 639 } 640 641 putempty() 642 { 643 char buf[TBLOCK]; 644 char *cp; 645 646 for (cp = buf; cp < &buf[TBLOCK]; ) 647 *cp++ = '\0'; 648 writetape(buf); 649 } 650 651 longt(st) 652 register struct stat *st; 653 { 654 register char *cp; 655 char *ctime(); 656 657 pmode(st); 658 printf("%3d/%1d", st->st_uid, st->st_gid); 659 printf("%7D", st->st_size); 660 cp = ctime(&st->st_mtime); 661 printf(" %-12.12s %-4.4s ", cp+4, cp+20); 662 } 663 664 #define SUID 04000 665 #define SGID 02000 666 #define ROWN 0400 667 #define WOWN 0200 668 #define XOWN 0100 669 #define RGRP 040 670 #define WGRP 020 671 #define XGRP 010 672 #define ROTH 04 673 #define WOTH 02 674 #define XOTH 01 675 #define STXT 01000 676 int m1[] = { 1, ROWN, 'r', '-' }; 677 int m2[] = { 1, WOWN, 'w', '-' }; 678 int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 679 int m4[] = { 1, RGRP, 'r', '-' }; 680 int m5[] = { 1, WGRP, 'w', '-' }; 681 int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 682 int m7[] = { 1, ROTH, 'r', '-' }; 683 int m8[] = { 1, WOTH, 'w', '-' }; 684 int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 685 686 int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 687 688 pmode(st) 689 register struct stat *st; 690 { 691 register int **mp; 692 693 for (mp = &m[0]; mp < &m[9];) 694 select(*mp++, st); 695 } 696 697 select(pairp, st) 698 int *pairp; 699 struct stat *st; 700 { 701 register int n, *ap; 702 703 ap = pairp; 704 n = *ap++; 705 while (--n>=0 && (st->st_mode&*ap++)==0) 706 ap++; 707 printf("%c", *ap); 708 } 709 710 checkdir(name) 711 register char *name; 712 { 713 register char *cp; 714 715 for (cp = name; *cp; cp++) { 716 if (*cp != '/') 717 continue; 718 *cp = '\0'; 719 if (access(name, 1) < 0) { 720 register int pid, rp; 721 int i; 722 723 if ((pid = fork()) == 0) { 724 execl("/bin/mkdir", "mkdir", name, 0); 725 execl("/usr/bin/mkdir", "mkdir", name, 0); 726 fprintf(stderr, "tar: cannot find mkdir!\n"); 727 done(0); 728 } 729 while ((rp = wait(&i)) >= 0 && rp != pid) 730 ; 731 chown(name, stbuf.st_uid, stbuf.st_gid); 732 if (pflag) 733 chmod(dblock.dbuf.name, stbuf.st_mode & 0777); 734 } 735 *cp = '/'; 736 } 737 return (cp[-1]=='/'); 738 } 739 740 onintr() 741 { 742 signal(SIGINT, SIG_IGN); 743 term++; 744 } 745 746 onquit() 747 { 748 signal(SIGQUIT, SIG_IGN); 749 term++; 750 } 751 752 onhup() 753 { 754 signal(SIGHUP, SIG_IGN); 755 term++; 756 } 757 758 onterm() 759 { 760 signal(SIGTERM, SIG_IGN); 761 term++; 762 } 763 764 tomodes(sp) 765 register struct stat *sp; 766 { 767 register char *cp; 768 769 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 770 *cp = '\0'; 771 sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 772 sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 773 sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 774 sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 775 sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 776 } 777 778 checksum() 779 { 780 register i; 781 register char *cp; 782 783 for (cp = dblock.dbuf.chksum; 784 cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 785 *cp = ' '; 786 i = 0; 787 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 788 i += *cp; 789 return (i); 790 } 791 792 checkw(c, name) 793 char *name; 794 { 795 if (!wflag) 796 return (1); 797 printf("%c ", c); 798 if (vflag) 799 longt(&stbuf); 800 printf("%s: ", name); 801 return (response() == 'y'); 802 } 803 804 response() 805 { 806 char c; 807 808 c = getchar(); 809 if (c != '\n') 810 while (getchar() != '\n') 811 ; 812 else 813 c = 'n'; 814 return (c); 815 } 816 817 checkupdate(arg) 818 char *arg; 819 { 820 char name[100]; 821 long mtime; 822 daddr_t seekp; 823 daddr_t lookup(); 824 825 rewind(tfile); 826 for (;;) { 827 if ((seekp = lookup(arg)) < 0) 828 return (1); 829 fseek(tfile, seekp, 0); 830 fscanf(tfile, "%s %lo", name, &mtime); 831 return (stbuf.st_mtime > mtime); 832 } 833 } 834 835 done(n) 836 { 837 unlink(tname); 838 exit(n); 839 } 840 841 prefix(s1, s2) 842 register char *s1, *s2; 843 { 844 while (*s1) 845 if (*s1++ != *s2++) 846 return (0); 847 if (*s2) 848 return (*s2 == '/'); 849 return (1); 850 } 851 852 getwdir(s) 853 char *s; 854 { 855 int i, pipdes[2]; 856 857 pipe(pipdes); 858 if ((i = fork()) == 0) { 859 close(1); 860 dup(pipdes[1]); 861 execl("/bin/pwd", "pwd", 0); 862 execl("/usr/bin/pwd", "pwd", 0); 863 fprintf(stderr, "pwd failed!\n"); 864 printf("/\n"); 865 exit(1); 866 } 867 while (wait((int *)NULL) != -1) 868 ; 869 read(pipdes[0], s, 50); 870 while (*s != '\n') 871 s++; 872 *s = '\0'; 873 close(pipdes[0]); 874 close(pipdes[1]); 875 } 876 877 #define N 200 878 int njab; 879 880 daddr_t 881 lookup(s) 882 char *s; 883 { 884 register i; 885 daddr_t a; 886 887 for(i=0; s[i]; i++) 888 if (s[i] == ' ') 889 break; 890 a = bsrch(s, i, low, high); 891 return (a); 892 } 893 894 daddr_t 895 bsrch(s, n, l, h) 896 daddr_t l, h; 897 char *s; 898 { 899 register i, j; 900 char b[N]; 901 daddr_t m, m1; 902 903 njab = 0; 904 905 loop: 906 if (l >= h) 907 return (-1L); 908 m = l + (h-l)/2 - N/2; 909 if (m < l) 910 m = l; 911 fseek(tfile, m, 0); 912 fread(b, 1, N, tfile); 913 njab++; 914 for(i=0; i<N; i++) { 915 if (b[i] == '\n') 916 break; 917 m++; 918 } 919 if (m >= h) 920 return (-1L); 921 m1 = m; 922 j = i; 923 for(i++; i<N; i++) { 924 m1++; 925 if (b[i] == '\n') 926 break; 927 } 928 i = cmp(b+j, s, n); 929 if (i < 0) { 930 h = m; 931 goto loop; 932 } 933 if (i > 0) { 934 l = m1; 935 goto loop; 936 } 937 return (m); 938 } 939 940 cmp(b, s, n) 941 char *b, *s; 942 { 943 register i; 944 945 if (b[0] != '\n') 946 exit(2); 947 for(i=0; i<n; i++) { 948 if (b[i+1] > s[i]) 949 return (-1); 950 if (b[i+1] < s[i]) 951 return (1); 952 } 953 return (b[i+1] == ' '? 0 : -1); 954 } 955 956 readtape(buffer) 957 char *buffer; 958 { 959 register int i; 960 961 if (recno >= nblock || first == 0) { 962 if ((i = read(mt, tbuf, TBLOCK*nblock)) < 0) { 963 fprintf(stderr, "Tar: tape read error\n"); 964 done(3); 965 } 966 if (first == 0) { 967 if ((i % TBLOCK) != 0) { 968 fprintf(stderr, "Tar: tape blocksize error\n"); 969 done(3); 970 } 971 i /= TBLOCK; 972 if (i != nblock) { 973 fprintf(stderr, "Tar: blocksize = %d\n", i); 974 nblock = i; 975 } 976 } 977 recno = 0; 978 } 979 first = 1; 980 copy(buffer, &tbuf[recno++]); 981 return (TBLOCK); 982 } 983 984 writetape(buffer) 985 char *buffer; 986 { 987 first = 1; 988 if (recno >= nblock) { 989 if (write(mt, tbuf, TBLOCK*nblock) < 0) { 990 fprintf(stderr, "Tar: tape write error\n"); 991 done(2); 992 } 993 recno = 0; 994 } 995 copy(&tbuf[recno++], buffer); 996 if (recno >= nblock) { 997 if (write(mt, tbuf, TBLOCK*nblock) < 0) { 998 fprintf(stderr, "Tar: tape write error\n"); 999 done(2); 1000 } 1001 recno = 0; 1002 } 1003 return (TBLOCK); 1004 } 1005 1006 backtape() 1007 { 1008 static int mtdev = 1; 1009 static struct mtop mtop = {MTBSR, 1}; 1010 struct mtget mtget; 1011 1012 if (mtdev == 1) 1013 mtdev = ioctl(mt, MTIOCGET, &mtget); 1014 if (mtdev == 0) { 1015 if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 1016 fprintf(stderr, "Tar: tape backspace error\n"); 1017 done(4); 1018 } 1019 } else 1020 lseek(mt, (long) -TBLOCK*nblock, 1); 1021 recno--; 1022 } 1023 1024 flushtape() 1025 { 1026 write(mt, tbuf, TBLOCK*nblock); 1027 } 1028 1029 copy(to, from) 1030 register char *to, *from; 1031 { 1032 register i; 1033 1034 i = TBLOCK; 1035 do { 1036 *to++ = *from++; 1037 } while (--i); 1038 } 1039