112154Ssam #ifndef lint 2*15045Smckusick static char *sccsid = "@(#)tar.c 4.19 (Berkeley) 09/22/83"; 312154Ssam #endif 46250Sroot 56250Sroot /* 66250Sroot * Tape Archival Program 76250Sroot */ 81119Sbill #include <stdio.h> 96413Smckusic #include <sys/param.h> 101119Sbill #include <sys/stat.h> 1112154Ssam #include <sys/dir.h> 128150Smckusick #include <sys/ioctl.h> 133457Swnj #include <sys/mtio.h> 1412983Ssam #include <sys/time.h> 151119Sbill #include <signal.h> 1612154Ssam #include <errno.h> 171119Sbill 181119Sbill #define TBLOCK 512 193355Swnj #define NBLOCK 20 201119Sbill #define NAMSIZ 100 216250Sroot 221119Sbill union hblock { 231119Sbill char dummy[TBLOCK]; 241119Sbill struct header { 251119Sbill char name[NAMSIZ]; 261119Sbill char mode[8]; 271119Sbill char uid[8]; 281119Sbill char gid[8]; 291119Sbill char size[12]; 301119Sbill char mtime[12]; 311119Sbill char chksum[8]; 321119Sbill char linkflag; 331119Sbill char linkname[NAMSIZ]; 341119Sbill } dbuf; 356250Sroot }; 361119Sbill 371119Sbill struct linkbuf { 381119Sbill ino_t inum; 391119Sbill dev_t devnum; 401119Sbill int count; 411119Sbill char pathname[NAMSIZ]; 421119Sbill struct linkbuf *nextp; 436250Sroot }; 441119Sbill 456250Sroot union hblock dblock; 4613492Ssam union hblock *tbuf; 476250Sroot struct linkbuf *ihead; 486250Sroot struct stat stbuf; 491119Sbill 506250Sroot int rflag; 516250Sroot int xflag; 526250Sroot int vflag; 536250Sroot int tflag; 546250Sroot int cflag; 556250Sroot int mflag; 566250Sroot int fflag; 5712154Ssam int iflag; 586250Sroot int oflag; 596250Sroot int pflag; 606250Sroot int wflag; 616250Sroot int hflag; 628737Smckusick int Bflag; 6312154Ssam int Fflag; 646250Sroot 656250Sroot int mt; 666250Sroot int term; 676250Sroot int chksum; 686250Sroot int recno; 696250Sroot int first; 706250Sroot int linkerrok; 711119Sbill int freemem = 1; 723457Swnj int nblock = NBLOCK; 736250Sroot int onintr(); 746250Sroot int onquit(); 756250Sroot int onhup(); 766250Sroot int onterm(); 771119Sbill 781119Sbill daddr_t low; 791119Sbill daddr_t high; 806250Sroot daddr_t bsrch(); 811119Sbill 821119Sbill FILE *tfile; 831119Sbill char tname[] = "/tmp/tarXXXXXX"; 841119Sbill char *usefile; 856250Sroot char magtape[] = "/dev/rmt8"; 861119Sbill char *malloc(); 876250Sroot char *sprintf(); 886250Sroot char *strcat(); 8912154Ssam char *rindex(); 9010165Ssam char *getcwd(); 919844Ssam char *getwd(); 921119Sbill 931119Sbill main(argc, argv) 941119Sbill int argc; 951119Sbill char *argv[]; 961119Sbill { 971119Sbill char *cp; 981119Sbill 991119Sbill if (argc < 2) 1001119Sbill usage(); 1011119Sbill 1021119Sbill tfile = NULL; 1031119Sbill usefile = magtape; 1041119Sbill argv[argc] = 0; 1051119Sbill argv++; 1061119Sbill for (cp = *argv++; *cp; cp++) 1071119Sbill switch(*cp) { 1086250Sroot 1091119Sbill case 'f': 11012154Ssam if (*argv == 0) { 11112154Ssam fprintf(stderr, 11212154Ssam "tar: tapefile must be specified with 'f' option\n"); 11312154Ssam usage(); 11412154Ssam } 1151119Sbill usefile = *argv++; 1161119Sbill fflag++; 1171119Sbill break; 1186250Sroot 1191119Sbill case 'c': 1201119Sbill cflag++; 1211119Sbill rflag++; 1221119Sbill break; 1236250Sroot 1241119Sbill case 'o': 1251119Sbill oflag++; 1261119Sbill break; 1276250Sroot 1281119Sbill case 'p': 1291119Sbill pflag++; 1301119Sbill break; 1316250Sroot 1321119Sbill case 'u': 1331119Sbill mktemp(tname); 1341119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1356250Sroot fprintf(stderr, 1366250Sroot "Tar: cannot create temporary file (%s)\n", 1376250Sroot tname); 1381119Sbill done(1); 1391119Sbill } 1401119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1416250Sroot /*FALL THRU*/ 1426250Sroot 1431119Sbill case 'r': 1441119Sbill rflag++; 1451119Sbill break; 1466250Sroot 1471119Sbill case 'v': 1481119Sbill vflag++; 1491119Sbill break; 1506250Sroot 1511119Sbill case 'w': 1521119Sbill wflag++; 1531119Sbill break; 1546250Sroot 1551119Sbill case 'x': 1561119Sbill xflag++; 1571119Sbill break; 1586250Sroot 1591119Sbill case 't': 1601119Sbill tflag++; 1611119Sbill break; 1626250Sroot 1631119Sbill case 'm': 1641119Sbill mflag++; 1651119Sbill break; 1666250Sroot 1671119Sbill case '-': 1681119Sbill break; 1696250Sroot 1701119Sbill case '0': 1711119Sbill case '1': 1721119Sbill case '4': 1731119Sbill case '5': 1741119Sbill case '7': 1751119Sbill case '8': 1761119Sbill magtape[8] = *cp; 1771119Sbill usefile = magtape; 1781119Sbill break; 1796250Sroot 1801119Sbill case 'b': 18113492Ssam if (*argv == 0) { 18213492Ssam fprintf(stderr, 18313492Ssam "tar: blocksize must be specified with 'b' option\n"); 18413492Ssam usage(); 18513492Ssam } 18613492Ssam nblock = atoi(*argv); 18713492Ssam if (nblock <= 0) { 18813492Ssam fprintf(stderr, 18913492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 1901119Sbill done(1); 1911119Sbill } 19213492Ssam argv++; 1931119Sbill break; 1946250Sroot 1951119Sbill case 'l': 1961119Sbill linkerrok++; 1971119Sbill break; 1986250Sroot 1996250Sroot case 'h': 2006250Sroot hflag++; 2016250Sroot break; 2026250Sroot 20312154Ssam case 'i': 20412154Ssam iflag++; 20512154Ssam break; 20612154Ssam 2078737Smckusick case 'B': 2088737Smckusick Bflag++; 2098737Smckusick break; 2108737Smckusick 21112154Ssam case 'F': 21212154Ssam Fflag++; 21312154Ssam break; 21412154Ssam 2151119Sbill default: 2161119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2171119Sbill usage(); 2181119Sbill } 2191119Sbill 2206250Sroot if (!rflag && !xflag && !tflag) 2216250Sroot usage(); 22213492Ssam tbuf = (union hblock *)malloc(nblock*TBLOCK); 22313492Ssam if (tbuf == NULL) { 22413492Ssam fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 22513492Ssam nblock); 22613492Ssam done(1); 22713492Ssam } 2281119Sbill if (rflag) { 2296250Sroot if (cflag && tfile != NULL) 2301119Sbill usage(); 2311119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2321119Sbill signal(SIGINT, onintr); 2331119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 2341119Sbill signal(SIGHUP, onhup); 2351119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2361119Sbill signal(SIGQUIT, onquit); 2376250Sroot #ifdef notdef 2381119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2391119Sbill signal(SIGTERM, onterm); 2406250Sroot #endif 2411119Sbill if (strcmp(usefile, "-") == 0) { 2421119Sbill if (cflag == 0) { 2436250Sroot fprintf(stderr, 24413492Ssam "tar: can only create standard output archives\n"); 2451119Sbill done(1); 2461119Sbill } 2471119Sbill mt = dup(1); 2481119Sbill nblock = 1; 2496250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2501119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2516250Sroot fprintf(stderr, 2526250Sroot "tar: cannot open %s\n", usefile); 2531119Sbill done(1); 2541119Sbill } 2551119Sbill } 2561119Sbill dorep(argv); 2576250Sroot done(0); 2581119Sbill } 2596250Sroot if (strcmp(usefile, "-") == 0) { 2606250Sroot mt = dup(0); 2616250Sroot nblock = 1; 2626250Sroot } else if ((mt = open(usefile, 0)) < 0) { 2636250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 2646250Sroot done(1); 2656250Sroot } 2666250Sroot if (xflag) 2671119Sbill doxtract(argv); 2686250Sroot else 2691119Sbill dotable(); 2701119Sbill done(0); 2711119Sbill } 2721119Sbill 2731119Sbill usage() 2741119Sbill { 2756250Sroot fprintf(stderr, 27613492Ssam "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2771119Sbill done(1); 2781119Sbill } 2791119Sbill 2801119Sbill dorep(argv) 2816250Sroot char *argv[]; 2821119Sbill { 2831119Sbill register char *cp, *cp2; 2849601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 2851119Sbill 2861119Sbill if (!cflag) { 2871119Sbill getdir(); 2881119Sbill do { 2891119Sbill passtape(); 2901119Sbill if (term) 2911119Sbill done(0); 2921119Sbill getdir(); 2931119Sbill } while (!endtape()); 29413492Ssam backtape(); 2951119Sbill if (tfile != NULL) { 2961119Sbill char buf[200]; 2971119Sbill 2986250Sroot sprintf(buf, 2996250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3001119Sbill tname, tname, tname, tname, tname, tname); 3011119Sbill fflush(tfile); 3021119Sbill system(buf); 3031119Sbill freopen(tname, "r", tfile); 3041119Sbill fstat(fileno(tfile), &stbuf); 3051119Sbill high = stbuf.st_size; 3061119Sbill } 3071119Sbill } 3081119Sbill 30910165Ssam (void) getcwd(wdir); 3101119Sbill while (*argv && ! term) { 3111119Sbill cp2 = *argv; 3121119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3131119Sbill argv++; 3141119Sbill if (chdir(*argv) < 0) 3151119Sbill perror(*argv); 3161119Sbill else 31710165Ssam (void) getcwd(wdir); 3181119Sbill argv++; 3191119Sbill continue; 3201119Sbill } 3219601Ssam parent = wdir; 3221119Sbill for (cp = *argv; *cp; cp++) 3231119Sbill if (*cp == '/') 3241119Sbill cp2 = cp; 3251119Sbill if (cp2 != *argv) { 3261119Sbill *cp2 = '\0'; 3279601Ssam if (chdir(*argv) < 0) { 3289601Ssam perror(*argv); 3299601Ssam continue; 3309601Ssam } 33110165Ssam parent = getcwd(tempdir); 3321119Sbill *cp2 = '/'; 3331119Sbill cp2++; 3341119Sbill } 3359601Ssam putfile(*argv++, cp2, parent); 336*15045Smckusick if (chdir(wdir) < 0) { 337*15045Smckusick fprintf(stderr, "cannot change back?: "); 338*15045Smckusick perror(wdir); 339*15045Smckusick } 3401119Sbill } 3411119Sbill putempty(); 3421119Sbill putempty(); 3431119Sbill flushtape(); 3446250Sroot if (linkerrok == 0) 3456250Sroot return; 3466250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3476250Sroot if (ihead->count == 0) 3486250Sroot continue; 34913492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3506250Sroot } 3511119Sbill } 3521119Sbill 3531119Sbill endtape() 3541119Sbill { 35513492Ssam return (dblock.dbuf.name[0] == '\0'); 3561119Sbill } 3571119Sbill 3581119Sbill getdir() 3591119Sbill { 3601119Sbill register struct stat *sp; 3611119Sbill int i; 3621119Sbill 36312154Ssam top: 3646250Sroot readtape((char *)&dblock); 3651119Sbill if (dblock.dbuf.name[0] == '\0') 3661119Sbill return; 3671119Sbill sp = &stbuf; 3681119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3691119Sbill sp->st_mode = i; 3701119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3711119Sbill sp->st_uid = i; 3721119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3731119Sbill sp->st_gid = i; 3741119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3751119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3761119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 37712154Ssam if (chksum != (i = checksum())) { 37813492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 37912154Ssam chksum, i); 38012154Ssam if (iflag) 38112154Ssam goto top; 3821119Sbill done(2); 3831119Sbill } 3841119Sbill if (tfile != NULL) 3851119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3861119Sbill } 3871119Sbill 3881119Sbill passtape() 3891119Sbill { 3901119Sbill long blocks; 3911119Sbill char buf[TBLOCK]; 3921119Sbill 3931119Sbill if (dblock.dbuf.linkflag == '1') 3941119Sbill return; 3951119Sbill blocks = stbuf.st_size; 3961119Sbill blocks += TBLOCK-1; 3971119Sbill blocks /= TBLOCK; 3981119Sbill 3991119Sbill while (blocks-- > 0) 4001119Sbill readtape(buf); 4011119Sbill } 4021119Sbill 4039601Ssam putfile(longname, shortname, parent) 4046250Sroot char *longname; 4056250Sroot char *shortname; 4069601Ssam char *parent; 4071119Sbill { 40812154Ssam int infile = 0; 4091119Sbill long blocks; 4101119Sbill char buf[TBLOCK]; 4111119Sbill register char *cp, *cp2; 4125931Smckusic struct direct *dp; 4135931Smckusic DIR *dirp; 4141119Sbill int i, j; 4159601Ssam char newparent[NAMSIZ+64]; 41612154Ssam extern int errno; 4171119Sbill 4189601Ssam if (!hflag) 41912154Ssam i = lstat(shortname, &stbuf); 42012154Ssam else 42112154Ssam i = stat(shortname, &stbuf); 42212154Ssam if (i < 0) { 42312154Ssam switch (errno) { 42412154Ssam case EACCES: 42512154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 42612154Ssam break; 42712154Ssam case ENOENT: 42812154Ssam fprintf(stderr, "tar: %s: no such file or directory\n", 42912154Ssam longname); 43012154Ssam break; 43112154Ssam default: 43212154Ssam fprintf(stderr, "tar: %s: cannot stat file\n", longname); 43312154Ssam break; 43412154Ssam } 4359601Ssam return; 4369601Ssam } 43712154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4381119Sbill return; 43912154Ssam if (checkw('r', longname) == 0) 4401119Sbill return; 44112154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 44212154Ssam return; 4431119Sbill 44412154Ssam switch (stbuf.st_mode & S_IFMT) { 44512154Ssam case S_IFDIR: 4466250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4476250Sroot ; 4481119Sbill *--cp = '/'; 4491119Sbill *++cp = 0 ; 4501119Sbill if (!oflag) { 4516250Sroot if ((cp - buf) >= NAMSIZ) { 45213492Ssam fprintf(stderr, "tar: %s: file name too long\n", 45313492Ssam longname); 4546250Sroot return; 4556250Sroot } 4566250Sroot stbuf.st_size = 0; 4576250Sroot tomodes(&stbuf); 4586250Sroot strcpy(dblock.dbuf.name,buf); 4596250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4606250Sroot writetape((char *)&dblock); 4611119Sbill } 4629601Ssam sprintf(newparent, "%s/%s", parent, shortname); 463*15045Smckusick if (chdir(shortname) < 0) { 464*15045Smckusick perror(shortname); 465*15045Smckusick return; 466*15045Smckusick } 4675931Smckusic if ((dirp = opendir(".")) == NULL) { 46813492Ssam fprintf(stderr, "tar: %s: directory read error\n", 46913492Ssam longname); 470*15045Smckusick if (chdir(parent) < 0) { 471*15045Smckusick fprintf(stderr, "cannot change back?: "); 472*15045Smckusick perror(parent); 473*15045Smckusick } 4745931Smckusic return; 4755931Smckusic } 4765931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4775931Smckusic if (dp->d_ino == 0) 4781119Sbill continue; 4796250Sroot if (!strcmp(".", dp->d_name) || 4806250Sroot !strcmp("..", dp->d_name)) 4811119Sbill continue; 4825931Smckusic strcpy(cp, dp->d_name); 4835931Smckusic i = telldir(dirp); 4845931Smckusic closedir(dirp); 4859601Ssam putfile(buf, cp, newparent); 4865931Smckusic dirp = opendir("."); 4875931Smckusic seekdir(dirp, i); 4881119Sbill } 4895931Smckusic closedir(dirp); 490*15045Smckusick if (chdir(parent) < 0) { 491*15045Smckusick fprintf(stderr, "cannot change back?: "); 492*15045Smckusick perror(parent); 493*15045Smckusick } 49412154Ssam break; 49512154Ssam 49612154Ssam case S_IFLNK: 49712154Ssam tomodes(&stbuf); 49812154Ssam if (strlen(longname) >= NAMSIZ) { 49913492Ssam fprintf(stderr, "tar: %s: file name too long\n", 50013492Ssam longname); 50112154Ssam return; 50212154Ssam } 50312154Ssam strcpy(dblock.dbuf.name, longname); 5046250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 50513492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 50613492Ssam longname); 5076250Sroot return; 5086250Sroot } 5099601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5106250Sroot if (i < 0) { 5119601Ssam perror(longname); 5126250Sroot return; 5136250Sroot } 5146250Sroot dblock.dbuf.linkname[i] = '\0'; 5156250Sroot dblock.dbuf.linkflag = '2'; 5166250Sroot if (vflag) { 5176250Sroot fprintf(stderr, "a %s ", longname); 5186250Sroot fprintf(stderr, "symbolic link to %s\n", 51913492Ssam dblock.dbuf.linkname); 5206250Sroot } 5216250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 5226250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5236250Sroot writetape((char *)&dblock); 52412154Ssam break; 5251119Sbill 52612154Ssam case S_IFREG: 52712154Ssam if ((infile = open(shortname, 0)) < 0) { 52812154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 5291119Sbill return; 5301119Sbill } 53112154Ssam tomodes(&stbuf); 53212154Ssam if (strlen(longname) >= NAMSIZ) { 53313492Ssam fprintf(stderr, "tar: %s: file name too long\n", 53413492Ssam longname); 53512154Ssam return; 53612154Ssam } 53712154Ssam strcpy(dblock.dbuf.name, longname); 53812154Ssam if (stbuf.st_nlink > 1) { 53912154Ssam struct linkbuf *lp; 54012154Ssam int found = 0; 54112154Ssam 54212154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 54312154Ssam if (lp->inum == stbuf.st_ino && 54412154Ssam lp->devnum == stbuf.st_dev) { 54512154Ssam found++; 54612154Ssam break; 54712154Ssam } 54812154Ssam if (found) { 54912154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 55012154Ssam dblock.dbuf.linkflag = '1'; 55112154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 55212154Ssam writetape( (char *) &dblock); 55312154Ssam if (vflag) { 55412154Ssam fprintf(stderr, "a %s ", longname); 55513492Ssam fprintf(stderr, "link to %s\n", 55613492Ssam lp->pathname); 55712154Ssam } 55812154Ssam lp->count--; 55912154Ssam close(infile); 56012154Ssam return; 5611119Sbill } 56212154Ssam lp = (struct linkbuf *) malloc(sizeof(*lp)); 56312154Ssam if (lp == NULL) { 56412154Ssam if (freemem) { 56512154Ssam fprintf(stderr, 56613492Ssam "tar: out of memory, link information lost\n"); 56712154Ssam freemem = 0; 56812154Ssam } 56912154Ssam } else { 57012154Ssam lp->nextp = ihead; 57112154Ssam ihead = lp; 57212154Ssam lp->inum = stbuf.st_ino; 57312154Ssam lp->devnum = stbuf.st_dev; 57412154Ssam lp->count = stbuf.st_nlink - 1; 57512154Ssam strcpy(lp->pathname, longname); 57612154Ssam } 5771119Sbill } 57812154Ssam blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 57912154Ssam if (vflag) { 58012154Ssam fprintf(stderr, "a %s ", longname); 58112154Ssam fprintf(stderr, "%ld blocks\n", blocks); 58212154Ssam } 58312154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 58412154Ssam writetape((char *)&dblock); 5851119Sbill 58612154Ssam while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 58712154Ssam writetape(buf); 58812154Ssam blocks--; 58912154Ssam } 59012154Ssam close(infile); 59112154Ssam if (blocks != 0 || i != 0) 59213492Ssam fprintf(stderr, "tar: %s: file changed size\n", 59313492Ssam longname); 59412154Ssam while (--blocks >= 0) 59512154Ssam putempty(); 59612154Ssam break; 59712154Ssam 59812154Ssam default: 59912154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 60013492Ssam longname); 60112154Ssam break; 6021119Sbill } 6031119Sbill } 6041119Sbill 6051119Sbill doxtract(argv) 6066250Sroot char *argv[]; 6071119Sbill { 6081119Sbill long blocks, bytes; 6091119Sbill char buf[TBLOCK]; 6101119Sbill char **cp; 6111119Sbill int ofile; 6121119Sbill 6131119Sbill for (;;) { 6141119Sbill getdir(); 6151119Sbill if (endtape()) 6161119Sbill break; 6171119Sbill if (*argv == 0) 6181119Sbill goto gotit; 6191119Sbill for (cp = argv; *cp; cp++) 6201119Sbill if (prefix(*cp, dblock.dbuf.name)) 6211119Sbill goto gotit; 6221119Sbill passtape(); 6231119Sbill continue; 6241119Sbill 6251119Sbill gotit: 6261119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6271119Sbill passtape(); 6281119Sbill continue; 6291119Sbill } 63012154Ssam if (Fflag) { 63112154Ssam char *s; 63212154Ssam 63312154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 63412154Ssam s = dblock.dbuf.name; 63512154Ssam else 63612154Ssam s++; 63712154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 63812154Ssam passtape(); 63912154Ssam continue; 64012154Ssam } 64112154Ssam } 6426250Sroot if (checkdir(dblock.dbuf.name)) 6436250Sroot continue; 6446250Sroot if (dblock.dbuf.linkflag == '2') { 6456250Sroot unlink(dblock.dbuf.name); 6466250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 64713492Ssam fprintf(stderr, "tar: %s: symbolic link failed\n", 64813492Ssam dblock.dbuf.name); 6496250Sroot continue; 6506250Sroot } 6516250Sroot if (vflag) 6526250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 65313492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 6548150Smckusick #ifdef notdef 6558150Smckusick /* ignore alien orders */ 6566250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6576250Sroot if (mflag == 0) { 65812983Ssam struct timeval tv[2]; 6591119Sbill 66012983Ssam tv[0].tv_sec = time(0); 66112983Ssam tv[0].tv_usec = 0; 66212983Ssam tv[1].tv_sec = stbuf.st_mtime; 66312983Ssam tv[1].tv_usec = 0; 66412983Ssam utimes(dblock.dbuf.name, tv); 6656250Sroot } 6666250Sroot if (pflag) 6676250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6688150Smckusick #endif 6691119Sbill continue; 6706250Sroot } 6711119Sbill if (dblock.dbuf.linkflag == '1') { 6721119Sbill unlink(dblock.dbuf.name); 6731119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 67413492Ssam fprintf(stderr, "tar: %s: cannot link\n", 67513492Ssam dblock.dbuf.name); 6761119Sbill continue; 6771119Sbill } 6781119Sbill if (vflag) 6793457Swnj fprintf(stderr, "%s linked to %s\n", 68013492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 6811119Sbill continue; 6821119Sbill } 6836250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 6846250Sroot fprintf(stderr, "tar: %s - cannot create\n", 68513492Ssam dblock.dbuf.name); 6861119Sbill passtape(); 6871119Sbill continue; 6881119Sbill } 6891926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6901119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 6911119Sbill if (vflag) 6923457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 69313492Ssam dblock.dbuf.name, bytes, blocks); 6946250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 6951119Sbill readtape(buf); 6961119Sbill if (bytes > TBLOCK) { 6971119Sbill if (write(ofile, buf, TBLOCK) < 0) { 6986250Sroot fprintf(stderr, 6996250Sroot "tar: %s: HELP - extract write error\n", 70013492Ssam dblock.dbuf.name); 7011119Sbill done(2); 7021119Sbill } 7036250Sroot continue; 7046250Sroot } 7056250Sroot if (write(ofile, buf, (int) bytes) < 0) { 7066250Sroot fprintf(stderr, 70713492Ssam "tar: %s: HELP - extract write error\n", 70813492Ssam dblock.dbuf.name); 7096250Sroot done(2); 7106250Sroot } 7111119Sbill } 7121119Sbill close(ofile); 7131119Sbill if (mflag == 0) { 71412983Ssam struct timeval tv[2]; 7151119Sbill 71612983Ssam tv[0].tv_sec = time(0); 71712983Ssam tv[0].tv_usec = 0; 71812983Ssam tv[1].tv_sec = stbuf.st_mtime; 71912983Ssam tv[1].tv_usec = 0; 72012983Ssam utimes(dblock.dbuf.name, tv); 7211119Sbill } 7221926Swnj if (pflag) 7236250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7241119Sbill } 7251119Sbill } 7261119Sbill 7271119Sbill dotable() 7281119Sbill { 7291119Sbill for (;;) { 7301119Sbill getdir(); 7311119Sbill if (endtape()) 7321119Sbill break; 7331119Sbill if (vflag) 7341119Sbill longt(&stbuf); 7351119Sbill printf("%s", dblock.dbuf.name); 7361119Sbill if (dblock.dbuf.linkflag == '1') 7371119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7386250Sroot if (dblock.dbuf.linkflag == '2') 7396250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7401119Sbill printf("\n"); 7411119Sbill passtape(); 7421119Sbill } 7431119Sbill } 7441119Sbill 7451119Sbill putempty() 7461119Sbill { 7471119Sbill char buf[TBLOCK]; 7481119Sbill 74913492Ssam bzero(buf, sizeof (buf)); 7501119Sbill writetape(buf); 7511119Sbill } 7521119Sbill 7531119Sbill longt(st) 7546250Sroot register struct stat *st; 7551119Sbill { 7561119Sbill register char *cp; 7571119Sbill char *ctime(); 7581119Sbill 7591119Sbill pmode(st); 7601119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 7611119Sbill printf("%7D", st->st_size); 7621119Sbill cp = ctime(&st->st_mtime); 7631119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 7641119Sbill } 7651119Sbill 7661119Sbill #define SUID 04000 7671119Sbill #define SGID 02000 7681119Sbill #define ROWN 0400 7691119Sbill #define WOWN 0200 7701119Sbill #define XOWN 0100 7711119Sbill #define RGRP 040 7721119Sbill #define WGRP 020 7731119Sbill #define XGRP 010 7741119Sbill #define ROTH 04 7751119Sbill #define WOTH 02 7761119Sbill #define XOTH 01 7771119Sbill #define STXT 01000 7781119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 7791119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 7801119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 7811119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 7821119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 7831119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 7841119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 7851119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 7861119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 7871119Sbill 7881119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 7891119Sbill 7901119Sbill pmode(st) 7916250Sroot register struct stat *st; 7921119Sbill { 7931119Sbill register int **mp; 7941119Sbill 7951119Sbill for (mp = &m[0]; mp < &m[9];) 7961119Sbill select(*mp++, st); 7971119Sbill } 7981119Sbill 7991119Sbill select(pairp, st) 8006250Sroot int *pairp; 8016250Sroot struct stat *st; 8021119Sbill { 8031119Sbill register int n, *ap; 8041119Sbill 8051119Sbill ap = pairp; 8061119Sbill n = *ap++; 8071119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8081119Sbill ap++; 8091119Sbill printf("%c", *ap); 8101119Sbill } 8111119Sbill 8121119Sbill checkdir(name) 8136250Sroot register char *name; 8141119Sbill { 8151119Sbill register char *cp; 8166250Sroot 81712154Ssam /* 81812154Ssam * Quick check for existance of directory. 81912154Ssam */ 82012154Ssam if ((cp = rindex(name, '/')) == 0) 82112154Ssam return (0); 82212154Ssam *cp = '\0'; 82312154Ssam if (access(name, 0) >= 0) { 82412154Ssam *cp = '/'; 82512154Ssam return (cp[1] == '\0'); 82612154Ssam } 82712154Ssam *cp = '/'; 82812154Ssam 82912154Ssam /* 83012154Ssam * No luck, try to make all directories in path. 83112154Ssam */ 8321119Sbill for (cp = name; *cp; cp++) { 8336250Sroot if (*cp != '/') 8346250Sroot continue; 8356250Sroot *cp = '\0'; 83612154Ssam if (access(name, 0) < 0) { 8379844Ssam if (mkdir(name, 0777) < 0) { 8389844Ssam perror(name); 83912154Ssam *cp = '/'; 84012154Ssam return (0); 8411119Sbill } 8426250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 84314956Skarels if (pflag && cp[1] == '\0') 8449844Ssam chmod(name, stbuf.st_mode & 0777); 8451119Sbill } 8466250Sroot *cp = '/'; 8471119Sbill } 8486250Sroot return (cp[-1]=='/'); 8491119Sbill } 8501119Sbill 8511119Sbill onintr() 8521119Sbill { 8531119Sbill signal(SIGINT, SIG_IGN); 8541119Sbill term++; 8551119Sbill } 8561119Sbill 8571119Sbill onquit() 8581119Sbill { 8591119Sbill signal(SIGQUIT, SIG_IGN); 8601119Sbill term++; 8611119Sbill } 8621119Sbill 8631119Sbill onhup() 8641119Sbill { 8651119Sbill signal(SIGHUP, SIG_IGN); 8661119Sbill term++; 8671119Sbill } 8681119Sbill 8691119Sbill onterm() 8701119Sbill { 8711119Sbill signal(SIGTERM, SIG_IGN); 8721119Sbill term++; 8731119Sbill } 8741119Sbill 8751119Sbill tomodes(sp) 8761119Sbill register struct stat *sp; 8771119Sbill { 8781119Sbill register char *cp; 8791119Sbill 8801119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8811119Sbill *cp = '\0'; 8821119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 8831119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 8841119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 8851119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 8861119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 8871119Sbill } 8881119Sbill 8891119Sbill checksum() 8901119Sbill { 8911119Sbill register i; 8921119Sbill register char *cp; 8931119Sbill 8946250Sroot for (cp = dblock.dbuf.chksum; 8956250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 8961119Sbill *cp = ' '; 8971119Sbill i = 0; 8981119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8991119Sbill i += *cp; 9006250Sroot return (i); 9011119Sbill } 9021119Sbill 9031119Sbill checkw(c, name) 9046250Sroot char *name; 9051119Sbill { 9066250Sroot if (!wflag) 9076250Sroot return (1); 9086250Sroot printf("%c ", c); 9096250Sroot if (vflag) 9106250Sroot longt(&stbuf); 9116250Sroot printf("%s: ", name); 9126250Sroot return (response() == 'y'); 9131119Sbill } 9141119Sbill 9151119Sbill response() 9161119Sbill { 9171119Sbill char c; 9181119Sbill 9191119Sbill c = getchar(); 9201119Sbill if (c != '\n') 9216250Sroot while (getchar() != '\n') 9226250Sroot ; 9236250Sroot else 9246250Sroot c = 'n'; 9256250Sroot return (c); 9261119Sbill } 9271119Sbill 92812154Ssam checkf(name, mode, howmuch) 92912154Ssam char *name; 93012154Ssam int mode, howmuch; 93112154Ssam { 93212154Ssam int l; 93312154Ssam 93412154Ssam if ((mode & S_IFMT) == S_IFDIR) 93512154Ssam return (strcmp(name, "SCCS") != 0); 93612154Ssam if ((l = strlen(name)) < 3) 93712154Ssam return (1); 93812154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 93912154Ssam return (0); 94012154Ssam if (strcmp(name, "core") == 0 || 94112154Ssam strcmp(name, "errs") == 0 || 94212154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 94312154Ssam return (0); 94412154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 94512154Ssam return (1); 94612154Ssam } 94712154Ssam 9481119Sbill checkupdate(arg) 9496250Sroot char *arg; 9501119Sbill { 9511119Sbill char name[100]; 9526250Sroot long mtime; 9531119Sbill daddr_t seekp; 9541119Sbill daddr_t lookup(); 9551119Sbill 9561119Sbill rewind(tfile); 9571119Sbill for (;;) { 9581119Sbill if ((seekp = lookup(arg)) < 0) 9596250Sroot return (1); 9601119Sbill fseek(tfile, seekp, 0); 9611119Sbill fscanf(tfile, "%s %lo", name, &mtime); 9626250Sroot return (stbuf.st_mtime > mtime); 9631119Sbill } 9641119Sbill } 9651119Sbill 9661119Sbill done(n) 9671119Sbill { 9681119Sbill unlink(tname); 9691119Sbill exit(n); 9701119Sbill } 9711119Sbill 9721119Sbill prefix(s1, s2) 9736250Sroot register char *s1, *s2; 9741119Sbill { 9751119Sbill while (*s1) 9761119Sbill if (*s1++ != *s2++) 9776250Sroot return (0); 9781119Sbill if (*s2) 9796250Sroot return (*s2 == '/'); 9806250Sroot return (1); 9811119Sbill } 9821119Sbill 9831119Sbill #define N 200 9841119Sbill int njab; 9856250Sroot 9861119Sbill daddr_t 9871119Sbill lookup(s) 9886250Sroot char *s; 9891119Sbill { 9901119Sbill register i; 9911119Sbill daddr_t a; 9921119Sbill 9931119Sbill for(i=0; s[i]; i++) 9946250Sroot if (s[i] == ' ') 9951119Sbill break; 9961119Sbill a = bsrch(s, i, low, high); 9976250Sroot return (a); 9981119Sbill } 9991119Sbill 10001119Sbill daddr_t 10011119Sbill bsrch(s, n, l, h) 10026250Sroot daddr_t l, h; 10036250Sroot char *s; 10041119Sbill { 10051119Sbill register i, j; 10061119Sbill char b[N]; 10071119Sbill daddr_t m, m1; 10081119Sbill 10091119Sbill njab = 0; 10101119Sbill 10111119Sbill loop: 10126250Sroot if (l >= h) 10136250Sroot return (-1L); 10141119Sbill m = l + (h-l)/2 - N/2; 10156250Sroot if (m < l) 10161119Sbill m = l; 10171119Sbill fseek(tfile, m, 0); 10181119Sbill fread(b, 1, N, tfile); 10191119Sbill njab++; 10201119Sbill for(i=0; i<N; i++) { 10216250Sroot if (b[i] == '\n') 10221119Sbill break; 10231119Sbill m++; 10241119Sbill } 10256250Sroot if (m >= h) 10266250Sroot return (-1L); 10271119Sbill m1 = m; 10281119Sbill j = i; 10291119Sbill for(i++; i<N; i++) { 10301119Sbill m1++; 10316250Sroot if (b[i] == '\n') 10321119Sbill break; 10331119Sbill } 10341119Sbill i = cmp(b+j, s, n); 10356250Sroot if (i < 0) { 10361119Sbill h = m; 10371119Sbill goto loop; 10381119Sbill } 10396250Sroot if (i > 0) { 10401119Sbill l = m1; 10411119Sbill goto loop; 10421119Sbill } 10436250Sroot return (m); 10441119Sbill } 10451119Sbill 10461119Sbill cmp(b, s, n) 10476250Sroot char *b, *s; 10481119Sbill { 10491119Sbill register i; 10501119Sbill 10516250Sroot if (b[0] != '\n') 10521119Sbill exit(2); 10531119Sbill for(i=0; i<n; i++) { 10546250Sroot if (b[i+1] > s[i]) 10556250Sroot return (-1); 10566250Sroot if (b[i+1] < s[i]) 10576250Sroot return (1); 10581119Sbill } 10596250Sroot return (b[i+1] == ' '? 0 : -1); 10601119Sbill } 10611119Sbill 10621119Sbill readtape(buffer) 10636250Sroot char *buffer; 10641119Sbill { 10653457Swnj register int i; 10661119Sbill 10671119Sbill if (recno >= nblock || first == 0) { 10688737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 106913492Ssam fprintf(stderr, "tar: tape read error\n"); 10701119Sbill done(3); 10711119Sbill } 10721119Sbill if (first == 0) { 10731119Sbill if ((i % TBLOCK) != 0) { 107413492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 10751119Sbill done(3); 10761119Sbill } 10771119Sbill i /= TBLOCK; 10783457Swnj if (i != nblock) { 107913492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 10801119Sbill nblock = i; 10811119Sbill } 10821119Sbill } 10831119Sbill recno = 0; 10841119Sbill } 10851119Sbill first = 1; 108613492Ssam bcopy((char *)&tbuf[recno++], buffer, TBLOCK); 10876250Sroot return (TBLOCK); 10881119Sbill } 10891119Sbill 10901119Sbill writetape(buffer) 10916250Sroot char *buffer; 10921119Sbill { 10931119Sbill first = 1; 10941119Sbill if (recno >= nblock) { 10951119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 109613492Ssam fprintf(stderr, "tar: tape write error\n"); 10971119Sbill done(2); 10981119Sbill } 10991119Sbill recno = 0; 11001119Sbill } 110113492Ssam bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 11021119Sbill if (recno >= nblock) { 11031119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 110413492Ssam fprintf(stderr, "tar: tape write error\n"); 11051119Sbill done(2); 11061119Sbill } 11071119Sbill recno = 0; 11081119Sbill } 11096250Sroot return (TBLOCK); 11101119Sbill } 11111119Sbill 11121119Sbill backtape() 11131119Sbill { 11143457Swnj static int mtdev = 1; 11153457Swnj static struct mtop mtop = {MTBSR, 1}; 11163457Swnj struct mtget mtget; 11173457Swnj 11183457Swnj if (mtdev == 1) 11193457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 11203457Swnj if (mtdev == 0) { 11213457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 112213492Ssam fprintf(stderr, "tar: tape backspace error\n"); 11231119Sbill done(4); 11241119Sbill } 11253457Swnj } else 11263457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 11273457Swnj recno--; 11281119Sbill } 11291119Sbill 11301119Sbill flushtape() 11311119Sbill { 11321119Sbill write(mt, tbuf, TBLOCK*nblock); 11331119Sbill } 11341119Sbill 11358737Smckusick bread(fd, buf, size) 11368737Smckusick int fd; 11378737Smckusick char *buf; 11388737Smckusick int size; 11398737Smckusick { 11408737Smckusick int count; 11418737Smckusick static int lastread = 0; 11428737Smckusick 11438737Smckusick if (!Bflag) 11448737Smckusick return (read(fd, buf, size)); 11458737Smckusick for (count = 0; count < size; count += lastread) { 11468737Smckusick if (lastread < 0) { 11478737Smckusick if (count > 0) 11488737Smckusick return (count); 11498737Smckusick return (lastread); 11508737Smckusick } 11518737Smckusick lastread = read(fd, buf, size - count); 11528737Smckusick buf += lastread; 11538737Smckusick } 11548737Smckusick return (count); 11558737Smckusick } 115610165Ssam 115710165Ssam char * 115810165Ssam getcwd(buf) 115910165Ssam char *buf; 116010165Ssam { 116110165Ssam 116210165Ssam if (getwd(buf) == NULL) { 116310165Ssam fprintf(stderr, "tar: %s\n", buf); 116410165Ssam exit(1); 116510165Ssam } 116610165Ssam return (buf); 116710165Ssam } 1168