1*6250Sroot static char *sccsid = "@(#)tar.c 4.7 (Berkeley) 82/03/17"; 2*6250Sroot 3*6250Sroot /* 4*6250Sroot * Tape Archival Program 5*6250Sroot */ 61119Sbill #include <stdio.h> 71119Sbill #include <sys/types.h> 81119Sbill #include <sys/stat.h> 95931Smckusic #include <ndir.h> 103457Swnj #include <sys/mtio.h> 111119Sbill #include <signal.h> 121119Sbill 131119Sbill #define TBLOCK 512 143355Swnj #define NBLOCK 20 151119Sbill #define NAMSIZ 100 16*6250Sroot 171119Sbill union hblock { 181119Sbill char dummy[TBLOCK]; 191119Sbill struct header { 201119Sbill char name[NAMSIZ]; 211119Sbill char mode[8]; 221119Sbill char uid[8]; 231119Sbill char gid[8]; 241119Sbill char size[12]; 251119Sbill char mtime[12]; 261119Sbill char chksum[8]; 271119Sbill char linkflag; 281119Sbill char linkname[NAMSIZ]; 291119Sbill } dbuf; 30*6250Sroot }; 311119Sbill 321119Sbill struct linkbuf { 331119Sbill ino_t inum; 341119Sbill dev_t devnum; 351119Sbill int count; 361119Sbill char pathname[NAMSIZ]; 371119Sbill struct linkbuf *nextp; 38*6250Sroot }; 391119Sbill 40*6250Sroot union hblock dblock; 41*6250Sroot union hblock tbuf[NBLOCK]; 42*6250Sroot struct linkbuf *ihead; 43*6250Sroot struct stat stbuf; 441119Sbill 45*6250Sroot int rflag; 46*6250Sroot int xflag; 47*6250Sroot int vflag; 48*6250Sroot int tflag; 49*6250Sroot int cflag; 50*6250Sroot int mflag; 51*6250Sroot int fflag; 52*6250Sroot int oflag; 53*6250Sroot int pflag; 54*6250Sroot int wflag; 55*6250Sroot int hflag; 56*6250Sroot 57*6250Sroot int mt; 58*6250Sroot int term; 59*6250Sroot int chksum; 60*6250Sroot int recno; 61*6250Sroot int first; 62*6250Sroot int linkerrok; 631119Sbill int freemem = 1; 643457Swnj int nblock = NBLOCK; 65*6250Sroot int onintr(); 66*6250Sroot int onquit(); 67*6250Sroot int onhup(); 68*6250Sroot int onterm(); 691119Sbill 701119Sbill daddr_t low; 711119Sbill daddr_t high; 72*6250Sroot daddr_t bsrch(); 731119Sbill 741119Sbill FILE *tfile; 751119Sbill char tname[] = "/tmp/tarXXXXXX"; 761119Sbill char *usefile; 77*6250Sroot char magtape[] = "/dev/rmt8"; 781119Sbill char *malloc(); 79*6250Sroot char *sprintf(); 80*6250Sroot char *strcat(); 811119Sbill 821119Sbill main(argc, argv) 831119Sbill int argc; 841119Sbill char *argv[]; 851119Sbill { 861119Sbill char *cp; 871119Sbill 881119Sbill if (argc < 2) 891119Sbill usage(); 901119Sbill 911119Sbill tfile = NULL; 921119Sbill usefile = magtape; 931119Sbill argv[argc] = 0; 941119Sbill argv++; 951119Sbill for (cp = *argv++; *cp; cp++) 961119Sbill switch(*cp) { 97*6250Sroot 981119Sbill case 'f': 991119Sbill usefile = *argv++; 1001119Sbill fflag++; 1011119Sbill break; 102*6250Sroot 1031119Sbill case 'c': 1041119Sbill cflag++; 1051119Sbill rflag++; 1061119Sbill break; 107*6250Sroot 1081119Sbill case 'o': 1091119Sbill oflag++; 1101119Sbill break; 111*6250Sroot 1121119Sbill case 'p': 1131119Sbill pflag++; 1141119Sbill break; 115*6250Sroot 1161119Sbill case 'u': 1171119Sbill mktemp(tname); 1181119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 119*6250Sroot fprintf(stderr, 120*6250Sroot "Tar: cannot create temporary file (%s)\n", 121*6250Sroot tname); 1221119Sbill done(1); 1231119Sbill } 1241119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 125*6250Sroot /*FALL THRU*/ 126*6250Sroot 1271119Sbill case 'r': 1281119Sbill rflag++; 1291119Sbill break; 130*6250Sroot 1311119Sbill case 'v': 1321119Sbill vflag++; 1331119Sbill break; 134*6250Sroot 1351119Sbill case 'w': 1361119Sbill wflag++; 1371119Sbill break; 138*6250Sroot 1391119Sbill case 'x': 1401119Sbill xflag++; 1411119Sbill break; 142*6250Sroot 1431119Sbill case 't': 1441119Sbill tflag++; 1451119Sbill break; 146*6250Sroot 1471119Sbill case 'm': 1481119Sbill mflag++; 1491119Sbill break; 150*6250Sroot 1511119Sbill case '-': 1521119Sbill break; 153*6250Sroot 1541119Sbill case '0': 1551119Sbill case '1': 1561119Sbill case '4': 1571119Sbill case '5': 1581119Sbill case '7': 1591119Sbill case '8': 1601119Sbill magtape[8] = *cp; 1611119Sbill usefile = magtape; 1621119Sbill break; 163*6250Sroot 1641119Sbill case 'b': 1651119Sbill nblock = atoi(*argv++); 1661119Sbill if (nblock > NBLOCK || nblock <= 0) { 167*6250Sroot fprintf(stderr, "Invalid blocksize. (Max %d)\n", 168*6250Sroot NBLOCK); 1691119Sbill done(1); 1701119Sbill } 1711119Sbill break; 172*6250Sroot 1731119Sbill case 'l': 1741119Sbill linkerrok++; 1751119Sbill break; 176*6250Sroot 177*6250Sroot case 'h': 178*6250Sroot hflag++; 179*6250Sroot break; 180*6250Sroot 1811119Sbill default: 1821119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 1831119Sbill usage(); 1841119Sbill } 1851119Sbill 186*6250Sroot if (!rflag && !xflag && !tflag) 187*6250Sroot usage(); 1881119Sbill if (rflag) { 189*6250Sroot if (cflag && tfile != NULL) 1901119Sbill usage(); 1911119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1921119Sbill signal(SIGINT, onintr); 1931119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 1941119Sbill signal(SIGHUP, onhup); 1951119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 1961119Sbill signal(SIGQUIT, onquit); 197*6250Sroot #ifdef notdef 1981119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 1991119Sbill signal(SIGTERM, onterm); 200*6250Sroot #endif 2011119Sbill if (strcmp(usefile, "-") == 0) { 2021119Sbill if (cflag == 0) { 203*6250Sroot fprintf(stderr, 204*6250Sroot "Can only create standard output archives\n"); 2051119Sbill done(1); 2061119Sbill } 2071119Sbill mt = dup(1); 2081119Sbill nblock = 1; 209*6250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2101119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 211*6250Sroot fprintf(stderr, 212*6250Sroot "tar: cannot open %s\n", usefile); 2131119Sbill done(1); 2141119Sbill } 2151119Sbill } 2161119Sbill dorep(argv); 217*6250Sroot done(0); 2181119Sbill } 219*6250Sroot if (strcmp(usefile, "-") == 0) { 220*6250Sroot mt = dup(0); 221*6250Sroot nblock = 1; 222*6250Sroot } else if ((mt = open(usefile, 0)) < 0) { 223*6250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 224*6250Sroot done(1); 225*6250Sroot } 226*6250Sroot if (xflag) 2271119Sbill doxtract(argv); 228*6250Sroot else 2291119Sbill dotable(); 2301119Sbill done(0); 2311119Sbill } 2321119Sbill 2331119Sbill usage() 2341119Sbill { 235*6250Sroot fprintf(stderr, 236*6250Sroot "tar: usage tar -{txru}[cvfblmh] [tapefile] [blocksize] file1 file2...\n"); 2371119Sbill done(1); 2381119Sbill } 2391119Sbill 2401119Sbill dorep(argv) 241*6250Sroot char *argv[]; 2421119Sbill { 2431119Sbill register char *cp, *cp2; 2441119Sbill char wdir[60]; 2451119Sbill 2461119Sbill if (!cflag) { 2471119Sbill getdir(); 2481119Sbill do { 2491119Sbill passtape(); 2501119Sbill if (term) 2511119Sbill done(0); 2521119Sbill getdir(); 2531119Sbill } while (!endtape()); 2541119Sbill if (tfile != NULL) { 2551119Sbill char buf[200]; 2561119Sbill 257*6250Sroot sprintf(buf, 258*6250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 2591119Sbill tname, tname, tname, tname, tname, tname); 2601119Sbill fflush(tfile); 2611119Sbill system(buf); 2621119Sbill freopen(tname, "r", tfile); 2631119Sbill fstat(fileno(tfile), &stbuf); 2641119Sbill high = stbuf.st_size; 2651119Sbill } 2661119Sbill } 2671119Sbill 2681119Sbill getwdir(wdir); 2691119Sbill while (*argv && ! term) { 2701119Sbill cp2 = *argv; 2711119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 2721119Sbill argv++; 2731119Sbill if (chdir(*argv) < 0) 2741119Sbill perror(*argv); 2751119Sbill else 2761119Sbill getwdir(wdir); 2771119Sbill argv++; 2781119Sbill continue; 2791119Sbill } 2801119Sbill for (cp = *argv; *cp; cp++) 2811119Sbill if (*cp == '/') 2821119Sbill cp2 = cp; 2831119Sbill if (cp2 != *argv) { 2841119Sbill *cp2 = '\0'; 2851119Sbill chdir(*argv); 2861119Sbill *cp2 = '/'; 2871119Sbill cp2++; 2881119Sbill } 2891119Sbill putfile(*argv++, cp2); 2901119Sbill chdir(wdir); 2911119Sbill } 2921119Sbill putempty(); 2931119Sbill putempty(); 2941119Sbill flushtape(); 295*6250Sroot if (linkerrok == 0) 296*6250Sroot return; 297*6250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 298*6250Sroot if (ihead->count == 0) 299*6250Sroot continue; 300*6250Sroot fprintf(stderr, "Missing links to %s\n", ihead->pathname); 301*6250Sroot } 3021119Sbill } 3031119Sbill 3041119Sbill endtape() 3051119Sbill { 306*6250Sroot if (dblock.dbuf.name[0] != '\0') 307*6250Sroot return (0); 308*6250Sroot backtape(); 309*6250Sroot return (1); 3101119Sbill } 3111119Sbill 3121119Sbill getdir() 3131119Sbill { 3141119Sbill register struct stat *sp; 3151119Sbill int i; 3161119Sbill 317*6250Sroot readtape((char *)&dblock); 3181119Sbill if (dblock.dbuf.name[0] == '\0') 3191119Sbill return; 3201119Sbill sp = &stbuf; 3211119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3221119Sbill sp->st_mode = i; 3231119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3241119Sbill sp->st_uid = i; 3251119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3261119Sbill sp->st_gid = i; 3271119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3281119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3291119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 3301119Sbill if (chksum != checksum()) { 3311119Sbill fprintf(stderr, "directory checksum error\n"); 3321119Sbill done(2); 3331119Sbill } 3341119Sbill if (tfile != NULL) 3351119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3361119Sbill } 3371119Sbill 3381119Sbill passtape() 3391119Sbill { 3401119Sbill long blocks; 3411119Sbill char buf[TBLOCK]; 3421119Sbill 3431119Sbill if (dblock.dbuf.linkflag == '1') 3441119Sbill return; 3451119Sbill blocks = stbuf.st_size; 3461119Sbill blocks += TBLOCK-1; 3471119Sbill blocks /= TBLOCK; 3481119Sbill 3491119Sbill while (blocks-- > 0) 3501119Sbill readtape(buf); 3511119Sbill } 3521119Sbill 3531119Sbill putfile(longname, shortname) 354*6250Sroot char *longname; 355*6250Sroot char *shortname; 3561119Sbill { 3571119Sbill int infile; 3581119Sbill long blocks; 3591119Sbill char buf[TBLOCK]; 3601119Sbill register char *cp, *cp2; 3615931Smckusic struct direct *dp; 3625931Smckusic DIR *dirp; 3631119Sbill int i, j; 3641119Sbill 3651119Sbill infile = open(shortname, 0); 3661119Sbill if (infile < 0) { 3671119Sbill fprintf(stderr, "tar: %s: cannot open file\n", longname); 3681119Sbill return; 3691119Sbill } 370*6250Sroot stat(shortname, &stbuf); 3711119Sbill if (tfile != NULL && checkupdate(longname) == 0) { 3721119Sbill close(infile); 3731119Sbill return; 3741119Sbill } 3751119Sbill if (checkw('r', longname) == 0) { 3761119Sbill close(infile); 3771119Sbill return; 3781119Sbill } 3791119Sbill 3801119Sbill if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 381*6250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 382*6250Sroot ; 3831119Sbill *--cp = '/'; 3841119Sbill *++cp = 0 ; 3851119Sbill if (!oflag) { 386*6250Sroot if ((cp - buf) >= NAMSIZ) { 387*6250Sroot fprintf(stderr, "%s: file name too long\n", 388*6250Sroot longname); 389*6250Sroot close(infile); 390*6250Sroot return; 391*6250Sroot } 392*6250Sroot stbuf.st_size = 0; 393*6250Sroot tomodes(&stbuf); 394*6250Sroot strcpy(dblock.dbuf.name,buf); 395*6250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 396*6250Sroot writetape((char *)&dblock); 3971119Sbill } 3981119Sbill chdir(shortname); 3995931Smckusic close(infile); 4005931Smckusic if ((dirp = opendir(".")) == NULL) { 4015931Smckusic fprintf(stderr, "%s: directory read error\n", longname); 4025931Smckusic return; 4035931Smckusic } 4045931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4055931Smckusic if (dp->d_ino == 0) 4061119Sbill continue; 407*6250Sroot if (!strcmp(".", dp->d_name) || 408*6250Sroot !strcmp("..", dp->d_name)) 4091119Sbill continue; 4105931Smckusic strcpy(cp, dp->d_name); 4115931Smckusic i = telldir(dirp); 4125931Smckusic closedir(dirp); 4131119Sbill putfile(buf, cp); 4145931Smckusic dirp = opendir("."); 4155931Smckusic seekdir(dirp, i); 4161119Sbill } 4175931Smckusic closedir(dirp); 4181119Sbill chdir(".."); 4191119Sbill return; 4201119Sbill } 421*6250Sroot i = stbuf.st_mode & S_IFMT; 422*6250Sroot if (i != S_IFREG && i != S_IFLNK) { 423*6250Sroot fprintf(stderr, "tar: %s is not a file. Not dumped\n", 424*6250Sroot longname); 4251119Sbill return; 4261119Sbill } 4271119Sbill tomodes(&stbuf); 428*6250Sroot cp2 = longname; cp = dblock.dbuf.name; i = 0; 429*6250Sroot while ((*cp++ = *cp2++) && i < NAMSIZ) 430*6250Sroot i++; 4311119Sbill if (i >= NAMSIZ) { 4321119Sbill fprintf(stderr, "%s: file name too long\n", longname); 4331119Sbill close(infile); 4341119Sbill return; 4351119Sbill } 436*6250Sroot if ((stbuf.st_mode & S_IFMT) == S_IFLNK) { 437*6250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 438*6250Sroot fprintf(stderr, "%s: symbolic link too long\n", 439*6250Sroot longname); 440*6250Sroot close(infile); 441*6250Sroot return; 442*6250Sroot } 443*6250Sroot i = readlink(longname, dblock.dbuf.linkname, NAMSIZ - 1); 444*6250Sroot if (i < 0) { 445*6250Sroot perror("readlink"); 446*6250Sroot close(infile); 447*6250Sroot return; 448*6250Sroot } 449*6250Sroot dblock.dbuf.linkname[i] = '\0'; 450*6250Sroot dblock.dbuf.linkflag = '2'; 451*6250Sroot if (vflag) { 452*6250Sroot fprintf(stderr, "a %s ", longname); 453*6250Sroot fprintf(stderr, "symbolic link to %s\n", 454*6250Sroot dblock.dbuf.linkname); 455*6250Sroot } 456*6250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 457*6250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 458*6250Sroot writetape((char *)&dblock); 459*6250Sroot close(infile); 460*6250Sroot return; 461*6250Sroot } 4621119Sbill if (stbuf.st_nlink > 1) { 4631119Sbill struct linkbuf *lp; 4641119Sbill int found = 0; 4651119Sbill 466*6250Sroot for (lp = ihead; lp != NULL; lp = lp->nextp) 467*6250Sroot if (lp->inum == stbuf.st_ino && 468*6250Sroot lp->devnum == stbuf.st_dev) { 4691119Sbill found++; 4701119Sbill break; 4711119Sbill } 4721119Sbill if (found) { 4731119Sbill strcpy(dblock.dbuf.linkname, lp->pathname); 4741119Sbill dblock.dbuf.linkflag = '1'; 4751119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4761119Sbill writetape( (char *) &dblock); 4771119Sbill if (vflag) { 4781119Sbill fprintf(stderr, "a %s ", longname); 4791119Sbill fprintf(stderr, "link to %s\n", lp->pathname); 4801119Sbill } 4811119Sbill lp->count--; 4821119Sbill close(infile); 4831119Sbill return; 4841119Sbill } 485*6250Sroot lp = (struct linkbuf *) malloc(sizeof(*lp)); 486*6250Sroot if (lp == NULL) { 487*6250Sroot if (freemem) { 488*6250Sroot fprintf(stderr, 489*6250Sroot "Out of memory. Link information lost\n"); 490*6250Sroot freemem = 0; 4911119Sbill } 492*6250Sroot } else { 493*6250Sroot lp->nextp = ihead; 494*6250Sroot ihead = lp; 495*6250Sroot lp->inum = stbuf.st_ino; 496*6250Sroot lp->devnum = stbuf.st_dev; 497*6250Sroot lp->count = stbuf.st_nlink - 1; 498*6250Sroot strcpy(lp->pathname, longname); 4991119Sbill } 5001119Sbill } 5011119Sbill blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 5021119Sbill if (vflag) { 5031119Sbill fprintf(stderr, "a %s ", longname); 5041119Sbill fprintf(stderr, "%ld blocks\n", blocks); 5051119Sbill } 5061119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 507*6250Sroot writetape((char *)&dblock); 5081119Sbill 5091119Sbill while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 5101119Sbill writetape(buf); 5111119Sbill blocks--; 5121119Sbill } 5131119Sbill close(infile); 5141119Sbill if (blocks != 0 || i != 0) 5151119Sbill fprintf(stderr, "%s: file changed size\n", longname); 516*6250Sroot while (--blocks >= 0) 5171119Sbill putempty(); 5181119Sbill } 5191119Sbill 5201119Sbill doxtract(argv) 521*6250Sroot char *argv[]; 5221119Sbill { 5231119Sbill long blocks, bytes; 5241119Sbill char buf[TBLOCK]; 5251119Sbill char **cp; 5261119Sbill int ofile; 5271119Sbill 5281119Sbill for (;;) { 5291119Sbill getdir(); 5301119Sbill if (endtape()) 5311119Sbill break; 5321119Sbill if (*argv == 0) 5331119Sbill goto gotit; 5341119Sbill for (cp = argv; *cp; cp++) 5351119Sbill if (prefix(*cp, dblock.dbuf.name)) 5361119Sbill goto gotit; 5371119Sbill passtape(); 5381119Sbill continue; 5391119Sbill 5401119Sbill gotit: 5411119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 5421119Sbill passtape(); 5431119Sbill continue; 5441119Sbill } 545*6250Sroot if (checkdir(dblock.dbuf.name)) 546*6250Sroot continue; 547*6250Sroot if (dblock.dbuf.linkflag == '2') { 548*6250Sroot unlink(dblock.dbuf.name); 549*6250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 550*6250Sroot fprintf(stderr, "%s: symbolic link failed\n", 551*6250Sroot dblock.dbuf.name); 552*6250Sroot continue; 553*6250Sroot } 554*6250Sroot if (vflag) 555*6250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 556*6250Sroot dblock.dbuf.name, dblock.dbuf.linkname); 557*6250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 558*6250Sroot if (mflag == 0) { 559*6250Sroot time_t timep[2]; 5601119Sbill 561*6250Sroot timep[0] = time(0); 562*6250Sroot timep[1] = stbuf.st_mtime; 563*6250Sroot utime(dblock.dbuf.name, timep); 564*6250Sroot } 565*6250Sroot if (pflag) 566*6250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 5671119Sbill continue; 568*6250Sroot } 5691119Sbill if (dblock.dbuf.linkflag == '1') { 5701119Sbill unlink(dblock.dbuf.name); 5711119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 572*6250Sroot fprintf(stderr, "%s: cannot link\n", 573*6250Sroot dblock.dbuf.name); 5741119Sbill continue; 5751119Sbill } 5761119Sbill if (vflag) 5773457Swnj fprintf(stderr, "%s linked to %s\n", 5783457Swnj dblock.dbuf.name, dblock.dbuf.linkname); 5791119Sbill continue; 5801119Sbill } 581*6250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 582*6250Sroot fprintf(stderr, "tar: %s - cannot create\n", 583*6250Sroot dblock.dbuf.name); 5841119Sbill passtape(); 5851119Sbill continue; 5861119Sbill } 5871926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 5881119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 5891119Sbill if (vflag) 5903457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 5913457Swnj dblock.dbuf.name, bytes, blocks); 592*6250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 5931119Sbill readtape(buf); 5941119Sbill if (bytes > TBLOCK) { 5951119Sbill if (write(ofile, buf, TBLOCK) < 0) { 596*6250Sroot fprintf(stderr, 597*6250Sroot "tar: %s: HELP - extract write error\n", 598*6250Sroot dblock.dbuf.name); 5991119Sbill done(2); 6001119Sbill } 601*6250Sroot continue; 602*6250Sroot } 603*6250Sroot if (write(ofile, buf, (int) bytes) < 0) { 604*6250Sroot fprintf(stderr, 605*6250Sroot "tar: %s: HELP - extract write error\n", 606*6250Sroot dblock.dbuf.name); 607*6250Sroot done(2); 608*6250Sroot } 6091119Sbill } 6101119Sbill close(ofile); 6111119Sbill if (mflag == 0) { 6121119Sbill time_t timep[2]; 6131119Sbill 6141119Sbill timep[0] = time(NULL); 6151119Sbill timep[1] = stbuf.st_mtime; 6161119Sbill utime(dblock.dbuf.name, timep); 6171119Sbill } 6181926Swnj if (pflag) 619*6250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6201119Sbill } 6211119Sbill } 6221119Sbill 6231119Sbill dotable() 6241119Sbill { 6251119Sbill for (;;) { 6261119Sbill getdir(); 6271119Sbill if (endtape()) 6281119Sbill break; 6291119Sbill if (vflag) 6301119Sbill longt(&stbuf); 6311119Sbill printf("%s", dblock.dbuf.name); 6321119Sbill if (dblock.dbuf.linkflag == '1') 6331119Sbill printf(" linked to %s", dblock.dbuf.linkname); 634*6250Sroot if (dblock.dbuf.linkflag == '2') 635*6250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 6361119Sbill printf("\n"); 6371119Sbill passtape(); 6381119Sbill } 6391119Sbill } 6401119Sbill 6411119Sbill putempty() 6421119Sbill { 6431119Sbill char buf[TBLOCK]; 6441119Sbill char *cp; 6451119Sbill 6461119Sbill for (cp = buf; cp < &buf[TBLOCK]; ) 6471119Sbill *cp++ = '\0'; 6481119Sbill writetape(buf); 6491119Sbill } 6501119Sbill 6511119Sbill longt(st) 652*6250Sroot register struct stat *st; 6531119Sbill { 6541119Sbill register char *cp; 6551119Sbill char *ctime(); 6561119Sbill 6571119Sbill pmode(st); 6581119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 6591119Sbill printf("%7D", st->st_size); 6601119Sbill cp = ctime(&st->st_mtime); 6611119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 6621119Sbill } 6631119Sbill 6641119Sbill #define SUID 04000 6651119Sbill #define SGID 02000 6661119Sbill #define ROWN 0400 6671119Sbill #define WOWN 0200 6681119Sbill #define XOWN 0100 6691119Sbill #define RGRP 040 6701119Sbill #define WGRP 020 6711119Sbill #define XGRP 010 6721119Sbill #define ROTH 04 6731119Sbill #define WOTH 02 6741119Sbill #define XOTH 01 6751119Sbill #define STXT 01000 6761119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 6771119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 6781119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 6791119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 6801119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 6811119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 6821119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 6831119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 6841119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 6851119Sbill 6861119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 6871119Sbill 6881119Sbill pmode(st) 689*6250Sroot register struct stat *st; 6901119Sbill { 6911119Sbill register int **mp; 6921119Sbill 6931119Sbill for (mp = &m[0]; mp < &m[9];) 6941119Sbill select(*mp++, st); 6951119Sbill } 6961119Sbill 6971119Sbill select(pairp, st) 698*6250Sroot int *pairp; 699*6250Sroot struct stat *st; 7001119Sbill { 7011119Sbill register int n, *ap; 7021119Sbill 7031119Sbill ap = pairp; 7041119Sbill n = *ap++; 7051119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 7061119Sbill ap++; 7071119Sbill printf("%c", *ap); 7081119Sbill } 7091119Sbill 7101119Sbill checkdir(name) 711*6250Sroot register char *name; 7121119Sbill { 7131119Sbill register char *cp; 714*6250Sroot 7151119Sbill for (cp = name; *cp; cp++) { 716*6250Sroot if (*cp != '/') 717*6250Sroot continue; 718*6250Sroot *cp = '\0'; 719*6250Sroot if (access(name, 1) < 0) { 720*6250Sroot register int pid, rp; 721*6250Sroot int i; 7221119Sbill 723*6250Sroot if ((pid = fork()) == 0) { 724*6250Sroot execl("/bin/mkdir", "mkdir", name, 0); 725*6250Sroot execl("/usr/bin/mkdir", "mkdir", name, 0); 726*6250Sroot fprintf(stderr, "tar: cannot find mkdir!\n"); 727*6250Sroot done(0); 7281119Sbill } 729*6250Sroot while ((rp = wait(&i)) >= 0 && rp != pid) 730*6250Sroot ; 731*6250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 732*6250Sroot if (pflag) 733*6250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 0777); 7341119Sbill } 735*6250Sroot *cp = '/'; 7361119Sbill } 737*6250Sroot return (cp[-1]=='/'); 7381119Sbill } 7391119Sbill 7401119Sbill onintr() 7411119Sbill { 7421119Sbill signal(SIGINT, SIG_IGN); 7431119Sbill term++; 7441119Sbill } 7451119Sbill 7461119Sbill onquit() 7471119Sbill { 7481119Sbill signal(SIGQUIT, SIG_IGN); 7491119Sbill term++; 7501119Sbill } 7511119Sbill 7521119Sbill onhup() 7531119Sbill { 7541119Sbill signal(SIGHUP, SIG_IGN); 7551119Sbill term++; 7561119Sbill } 7571119Sbill 7581119Sbill onterm() 7591119Sbill { 7601119Sbill signal(SIGTERM, SIG_IGN); 7611119Sbill term++; 7621119Sbill } 7631119Sbill 7641119Sbill tomodes(sp) 7651119Sbill register struct stat *sp; 7661119Sbill { 7671119Sbill register char *cp; 7681119Sbill 7691119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 7701119Sbill *cp = '\0'; 7711119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 7721119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 7731119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 7741119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 7751119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 7761119Sbill } 7771119Sbill 7781119Sbill checksum() 7791119Sbill { 7801119Sbill register i; 7811119Sbill register char *cp; 7821119Sbill 783*6250Sroot for (cp = dblock.dbuf.chksum; 784*6250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 7851119Sbill *cp = ' '; 7861119Sbill i = 0; 7871119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 7881119Sbill i += *cp; 789*6250Sroot return (i); 7901119Sbill } 7911119Sbill 7921119Sbill checkw(c, name) 793*6250Sroot char *name; 7941119Sbill { 795*6250Sroot if (!wflag) 796*6250Sroot return (1); 797*6250Sroot printf("%c ", c); 798*6250Sroot if (vflag) 799*6250Sroot longt(&stbuf); 800*6250Sroot printf("%s: ", name); 801*6250Sroot return (response() == 'y'); 8021119Sbill } 8031119Sbill 8041119Sbill response() 8051119Sbill { 8061119Sbill char c; 8071119Sbill 8081119Sbill c = getchar(); 8091119Sbill if (c != '\n') 810*6250Sroot while (getchar() != '\n') 811*6250Sroot ; 812*6250Sroot else 813*6250Sroot c = 'n'; 814*6250Sroot return (c); 8151119Sbill } 8161119Sbill 8171119Sbill checkupdate(arg) 818*6250Sroot char *arg; 8191119Sbill { 8201119Sbill char name[100]; 821*6250Sroot long mtime; 8221119Sbill daddr_t seekp; 8231119Sbill daddr_t lookup(); 8241119Sbill 8251119Sbill rewind(tfile); 8261119Sbill for (;;) { 8271119Sbill if ((seekp = lookup(arg)) < 0) 828*6250Sroot return (1); 8291119Sbill fseek(tfile, seekp, 0); 8301119Sbill fscanf(tfile, "%s %lo", name, &mtime); 831*6250Sroot return (stbuf.st_mtime > mtime); 8321119Sbill } 8331119Sbill } 8341119Sbill 8351119Sbill done(n) 8361119Sbill { 8371119Sbill unlink(tname); 8381119Sbill exit(n); 8391119Sbill } 8401119Sbill 8411119Sbill prefix(s1, s2) 842*6250Sroot register char *s1, *s2; 8431119Sbill { 8441119Sbill while (*s1) 8451119Sbill if (*s1++ != *s2++) 846*6250Sroot return (0); 8471119Sbill if (*s2) 848*6250Sroot return (*s2 == '/'); 849*6250Sroot return (1); 8501119Sbill } 8511119Sbill 8521119Sbill getwdir(s) 853*6250Sroot char *s; 8541119Sbill { 855*6250Sroot int i, pipdes[2]; 8561119Sbill 8571119Sbill pipe(pipdes); 8581119Sbill if ((i = fork()) == 0) { 8591119Sbill close(1); 8601119Sbill dup(pipdes[1]); 8611119Sbill execl("/bin/pwd", "pwd", 0); 8621119Sbill execl("/usr/bin/pwd", "pwd", 0); 8631119Sbill fprintf(stderr, "pwd failed!\n"); 8641119Sbill printf("/\n"); 8651119Sbill exit(1); 8661119Sbill } 8671119Sbill while (wait((int *)NULL) != -1) 8681119Sbill ; 8691119Sbill read(pipdes[0], s, 50); 870*6250Sroot while (*s != '\n') 8711119Sbill s++; 8721119Sbill *s = '\0'; 8731119Sbill close(pipdes[0]); 8741119Sbill close(pipdes[1]); 8751119Sbill } 8761119Sbill 8771119Sbill #define N 200 8781119Sbill int njab; 879*6250Sroot 8801119Sbill daddr_t 8811119Sbill lookup(s) 882*6250Sroot char *s; 8831119Sbill { 8841119Sbill register i; 8851119Sbill daddr_t a; 8861119Sbill 8871119Sbill for(i=0; s[i]; i++) 888*6250Sroot if (s[i] == ' ') 8891119Sbill break; 8901119Sbill a = bsrch(s, i, low, high); 891*6250Sroot return (a); 8921119Sbill } 8931119Sbill 8941119Sbill daddr_t 8951119Sbill bsrch(s, n, l, h) 896*6250Sroot daddr_t l, h; 897*6250Sroot char *s; 8981119Sbill { 8991119Sbill register i, j; 9001119Sbill char b[N]; 9011119Sbill daddr_t m, m1; 9021119Sbill 9031119Sbill njab = 0; 9041119Sbill 9051119Sbill loop: 906*6250Sroot if (l >= h) 907*6250Sroot return (-1L); 9081119Sbill m = l + (h-l)/2 - N/2; 909*6250Sroot if (m < l) 9101119Sbill m = l; 9111119Sbill fseek(tfile, m, 0); 9121119Sbill fread(b, 1, N, tfile); 9131119Sbill njab++; 9141119Sbill for(i=0; i<N; i++) { 915*6250Sroot if (b[i] == '\n') 9161119Sbill break; 9171119Sbill m++; 9181119Sbill } 919*6250Sroot if (m >= h) 920*6250Sroot return (-1L); 9211119Sbill m1 = m; 9221119Sbill j = i; 9231119Sbill for(i++; i<N; i++) { 9241119Sbill m1++; 925*6250Sroot if (b[i] == '\n') 9261119Sbill break; 9271119Sbill } 9281119Sbill i = cmp(b+j, s, n); 929*6250Sroot if (i < 0) { 9301119Sbill h = m; 9311119Sbill goto loop; 9321119Sbill } 933*6250Sroot if (i > 0) { 9341119Sbill l = m1; 9351119Sbill goto loop; 9361119Sbill } 937*6250Sroot return (m); 9381119Sbill } 9391119Sbill 9401119Sbill cmp(b, s, n) 941*6250Sroot char *b, *s; 9421119Sbill { 9431119Sbill register i; 9441119Sbill 945*6250Sroot if (b[0] != '\n') 9461119Sbill exit(2); 9471119Sbill for(i=0; i<n; i++) { 948*6250Sroot if (b[i+1] > s[i]) 949*6250Sroot return (-1); 950*6250Sroot if (b[i+1] < s[i]) 951*6250Sroot return (1); 9521119Sbill } 953*6250Sroot return (b[i+1] == ' '? 0 : -1); 9541119Sbill } 9551119Sbill 9561119Sbill readtape(buffer) 957*6250Sroot char *buffer; 9581119Sbill { 9593457Swnj register int i; 9601119Sbill 9611119Sbill if (recno >= nblock || first == 0) { 9623457Swnj if ((i = read(mt, tbuf, TBLOCK*nblock)) < 0) { 9631119Sbill fprintf(stderr, "Tar: tape read error\n"); 9641119Sbill done(3); 9651119Sbill } 9661119Sbill if (first == 0) { 9671119Sbill if ((i % TBLOCK) != 0) { 9681119Sbill fprintf(stderr, "Tar: tape blocksize error\n"); 9691119Sbill done(3); 9701119Sbill } 9711119Sbill i /= TBLOCK; 9723457Swnj if (i != nblock) { 9731119Sbill fprintf(stderr, "Tar: blocksize = %d\n", i); 9741119Sbill nblock = i; 9751119Sbill } 9761119Sbill } 9771119Sbill recno = 0; 9781119Sbill } 9791119Sbill first = 1; 9801119Sbill copy(buffer, &tbuf[recno++]); 981*6250Sroot return (TBLOCK); 9821119Sbill } 9831119Sbill 9841119Sbill writetape(buffer) 985*6250Sroot char *buffer; 9861119Sbill { 9871119Sbill first = 1; 9881119Sbill if (recno >= nblock) { 9891119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 9901119Sbill fprintf(stderr, "Tar: tape write error\n"); 9911119Sbill done(2); 9921119Sbill } 9931119Sbill recno = 0; 9941119Sbill } 9951119Sbill copy(&tbuf[recno++], buffer); 9961119Sbill if (recno >= nblock) { 9971119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 9981119Sbill fprintf(stderr, "Tar: tape write error\n"); 9991119Sbill done(2); 10001119Sbill } 10011119Sbill recno = 0; 10021119Sbill } 1003*6250Sroot return (TBLOCK); 10041119Sbill } 10051119Sbill 10061119Sbill backtape() 10071119Sbill { 10083457Swnj static int mtdev = 1; 10093457Swnj static struct mtop mtop = {MTBSR, 1}; 10103457Swnj struct mtget mtget; 10113457Swnj 10123457Swnj if (mtdev == 1) 10133457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 10143457Swnj if (mtdev == 0) { 10153457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 10163457Swnj fprintf(stderr, "Tar: tape backspace error\n"); 10171119Sbill done(4); 10181119Sbill } 10193457Swnj } else 10203457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 10213457Swnj recno--; 10221119Sbill } 10231119Sbill 10241119Sbill flushtape() 10251119Sbill { 10261119Sbill write(mt, tbuf, TBLOCK*nblock); 10271119Sbill } 10281119Sbill 10291119Sbill copy(to, from) 1030*6250Sroot register char *to, *from; 10311119Sbill { 10321119Sbill register i; 10331119Sbill 10341119Sbill i = TBLOCK; 10351119Sbill do { 10361119Sbill *to++ = *from++; 10371119Sbill } while (--i); 10381119Sbill } 1039