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