112154Ssam #ifndef lint 2*13492Ssam static char *sccsid = "@(#)tar.c 4.17 (Berkeley) 06/30/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; 46*13492Ssam 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': 181*13492Ssam if (*argv == 0) { 182*13492Ssam fprintf(stderr, 183*13492Ssam "tar: blocksize must be specified with 'b' option\n"); 184*13492Ssam usage(); 185*13492Ssam } 186*13492Ssam nblock = atoi(*argv); 187*13492Ssam if (nblock <= 0) { 188*13492Ssam fprintf(stderr, 189*13492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 1901119Sbill done(1); 1911119Sbill } 192*13492Ssam 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(); 222*13492Ssam tbuf = (union hblock *)malloc(nblock*TBLOCK); 223*13492Ssam if (tbuf == NULL) { 224*13492Ssam fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 225*13492Ssam nblock); 226*13492Ssam done(1); 227*13492Ssam } 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, 244*13492Ssam "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, 276*13492Ssam "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()); 294*13492Ssam 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); 3361119Sbill chdir(wdir); 3371119Sbill } 3381119Sbill putempty(); 3391119Sbill putempty(); 3401119Sbill flushtape(); 3416250Sroot if (linkerrok == 0) 3426250Sroot return; 3436250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3446250Sroot if (ihead->count == 0) 3456250Sroot continue; 346*13492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3476250Sroot } 3481119Sbill } 3491119Sbill 3501119Sbill endtape() 3511119Sbill { 352*13492Ssam return (dblock.dbuf.name[0] == '\0'); 3531119Sbill } 3541119Sbill 3551119Sbill getdir() 3561119Sbill { 3571119Sbill register struct stat *sp; 3581119Sbill int i; 3591119Sbill 36012154Ssam top: 3616250Sroot readtape((char *)&dblock); 3621119Sbill if (dblock.dbuf.name[0] == '\0') 3631119Sbill return; 3641119Sbill sp = &stbuf; 3651119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3661119Sbill sp->st_mode = i; 3671119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3681119Sbill sp->st_uid = i; 3691119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3701119Sbill sp->st_gid = i; 3711119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3721119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3731119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 37412154Ssam if (chksum != (i = checksum())) { 375*13492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 37612154Ssam chksum, i); 37712154Ssam if (iflag) 37812154Ssam goto top; 3791119Sbill done(2); 3801119Sbill } 3811119Sbill if (tfile != NULL) 3821119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3831119Sbill } 3841119Sbill 3851119Sbill passtape() 3861119Sbill { 3871119Sbill long blocks; 3881119Sbill char buf[TBLOCK]; 3891119Sbill 3901119Sbill if (dblock.dbuf.linkflag == '1') 3911119Sbill return; 3921119Sbill blocks = stbuf.st_size; 3931119Sbill blocks += TBLOCK-1; 3941119Sbill blocks /= TBLOCK; 3951119Sbill 3961119Sbill while (blocks-- > 0) 3971119Sbill readtape(buf); 3981119Sbill } 3991119Sbill 4009601Ssam putfile(longname, shortname, parent) 4016250Sroot char *longname; 4026250Sroot char *shortname; 4039601Ssam char *parent; 4041119Sbill { 40512154Ssam int infile = 0; 4061119Sbill long blocks; 4071119Sbill char buf[TBLOCK]; 4081119Sbill register char *cp, *cp2; 4095931Smckusic struct direct *dp; 4105931Smckusic DIR *dirp; 4111119Sbill int i, j; 4129601Ssam char newparent[NAMSIZ+64]; 41312154Ssam extern int errno; 4141119Sbill 4159601Ssam if (!hflag) 41612154Ssam i = lstat(shortname, &stbuf); 41712154Ssam else 41812154Ssam i = stat(shortname, &stbuf); 41912154Ssam if (i < 0) { 42012154Ssam switch (errno) { 42112154Ssam case EACCES: 42212154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 42312154Ssam break; 42412154Ssam case ENOENT: 42512154Ssam fprintf(stderr, "tar: %s: no such file or directory\n", 42612154Ssam longname); 42712154Ssam break; 42812154Ssam default: 42912154Ssam fprintf(stderr, "tar: %s: cannot stat file\n", longname); 43012154Ssam break; 43112154Ssam } 4329601Ssam return; 4339601Ssam } 43412154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4351119Sbill return; 43612154Ssam if (checkw('r', longname) == 0) 4371119Sbill return; 43812154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 43912154Ssam return; 4401119Sbill 44112154Ssam switch (stbuf.st_mode & S_IFMT) { 44212154Ssam case S_IFDIR: 4436250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4446250Sroot ; 4451119Sbill *--cp = '/'; 4461119Sbill *++cp = 0 ; 4471119Sbill if (!oflag) { 4486250Sroot if ((cp - buf) >= NAMSIZ) { 449*13492Ssam fprintf(stderr, "tar: %s: file name too long\n", 450*13492Ssam longname); 4516250Sroot return; 4526250Sroot } 4536250Sroot stbuf.st_size = 0; 4546250Sroot tomodes(&stbuf); 4556250Sroot strcpy(dblock.dbuf.name,buf); 4566250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4576250Sroot writetape((char *)&dblock); 4581119Sbill } 4599601Ssam sprintf(newparent, "%s/%s", parent, shortname); 4601119Sbill chdir(shortname); 4615931Smckusic if ((dirp = opendir(".")) == NULL) { 462*13492Ssam fprintf(stderr, "tar: %s: directory read error\n", 463*13492Ssam longname); 4649601Ssam chdir(parent); 4655931Smckusic return; 4665931Smckusic } 4675931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4685931Smckusic if (dp->d_ino == 0) 4691119Sbill continue; 4706250Sroot if (!strcmp(".", dp->d_name) || 4716250Sroot !strcmp("..", dp->d_name)) 4721119Sbill continue; 4735931Smckusic strcpy(cp, dp->d_name); 4745931Smckusic i = telldir(dirp); 4755931Smckusic closedir(dirp); 4769601Ssam putfile(buf, cp, newparent); 4775931Smckusic dirp = opendir("."); 4785931Smckusic seekdir(dirp, i); 4791119Sbill } 4805931Smckusic closedir(dirp); 4819601Ssam chdir(parent); 48212154Ssam break; 48312154Ssam 48412154Ssam case S_IFLNK: 48512154Ssam tomodes(&stbuf); 48612154Ssam if (strlen(longname) >= NAMSIZ) { 487*13492Ssam fprintf(stderr, "tar: %s: file name too long\n", 488*13492Ssam longname); 48912154Ssam return; 49012154Ssam } 49112154Ssam strcpy(dblock.dbuf.name, longname); 4926250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 493*13492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 494*13492Ssam longname); 4956250Sroot return; 4966250Sroot } 4979601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 4986250Sroot if (i < 0) { 4999601Ssam perror(longname); 5006250Sroot return; 5016250Sroot } 5026250Sroot dblock.dbuf.linkname[i] = '\0'; 5036250Sroot dblock.dbuf.linkflag = '2'; 5046250Sroot if (vflag) { 5056250Sroot fprintf(stderr, "a %s ", longname); 5066250Sroot fprintf(stderr, "symbolic link to %s\n", 507*13492Ssam dblock.dbuf.linkname); 5086250Sroot } 5096250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 5106250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5116250Sroot writetape((char *)&dblock); 51212154Ssam break; 5131119Sbill 51412154Ssam case S_IFREG: 51512154Ssam if ((infile = open(shortname, 0)) < 0) { 51612154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 5171119Sbill return; 5181119Sbill } 51912154Ssam tomodes(&stbuf); 52012154Ssam if (strlen(longname) >= NAMSIZ) { 521*13492Ssam fprintf(stderr, "tar: %s: file name too long\n", 522*13492Ssam longname); 52312154Ssam return; 52412154Ssam } 52512154Ssam strcpy(dblock.dbuf.name, longname); 52612154Ssam if (stbuf.st_nlink > 1) { 52712154Ssam struct linkbuf *lp; 52812154Ssam int found = 0; 52912154Ssam 53012154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 53112154Ssam if (lp->inum == stbuf.st_ino && 53212154Ssam lp->devnum == stbuf.st_dev) { 53312154Ssam found++; 53412154Ssam break; 53512154Ssam } 53612154Ssam if (found) { 53712154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 53812154Ssam dblock.dbuf.linkflag = '1'; 53912154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 54012154Ssam writetape( (char *) &dblock); 54112154Ssam if (vflag) { 54212154Ssam fprintf(stderr, "a %s ", longname); 543*13492Ssam fprintf(stderr, "link to %s\n", 544*13492Ssam lp->pathname); 54512154Ssam } 54612154Ssam lp->count--; 54712154Ssam close(infile); 54812154Ssam return; 5491119Sbill } 55012154Ssam lp = (struct linkbuf *) malloc(sizeof(*lp)); 55112154Ssam if (lp == NULL) { 55212154Ssam if (freemem) { 55312154Ssam fprintf(stderr, 554*13492Ssam "tar: out of memory, link information lost\n"); 55512154Ssam freemem = 0; 55612154Ssam } 55712154Ssam } else { 55812154Ssam lp->nextp = ihead; 55912154Ssam ihead = lp; 56012154Ssam lp->inum = stbuf.st_ino; 56112154Ssam lp->devnum = stbuf.st_dev; 56212154Ssam lp->count = stbuf.st_nlink - 1; 56312154Ssam strcpy(lp->pathname, longname); 56412154Ssam } 5651119Sbill } 56612154Ssam blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 56712154Ssam if (vflag) { 56812154Ssam fprintf(stderr, "a %s ", longname); 56912154Ssam fprintf(stderr, "%ld blocks\n", blocks); 57012154Ssam } 57112154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 57212154Ssam writetape((char *)&dblock); 5731119Sbill 57412154Ssam while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 57512154Ssam writetape(buf); 57612154Ssam blocks--; 57712154Ssam } 57812154Ssam close(infile); 57912154Ssam if (blocks != 0 || i != 0) 580*13492Ssam fprintf(stderr, "tar: %s: file changed size\n", 581*13492Ssam longname); 58212154Ssam while (--blocks >= 0) 58312154Ssam putempty(); 58412154Ssam break; 58512154Ssam 58612154Ssam default: 58712154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 588*13492Ssam longname); 58912154Ssam break; 5901119Sbill } 5911119Sbill } 5921119Sbill 5931119Sbill doxtract(argv) 5946250Sroot char *argv[]; 5951119Sbill { 5961119Sbill long blocks, bytes; 5971119Sbill char buf[TBLOCK]; 5981119Sbill char **cp; 5991119Sbill int ofile; 6001119Sbill 6011119Sbill for (;;) { 6021119Sbill getdir(); 6031119Sbill if (endtape()) 6041119Sbill break; 6051119Sbill if (*argv == 0) 6061119Sbill goto gotit; 6071119Sbill for (cp = argv; *cp; cp++) 6081119Sbill if (prefix(*cp, dblock.dbuf.name)) 6091119Sbill goto gotit; 6101119Sbill passtape(); 6111119Sbill continue; 6121119Sbill 6131119Sbill gotit: 6141119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6151119Sbill passtape(); 6161119Sbill continue; 6171119Sbill } 61812154Ssam if (Fflag) { 61912154Ssam char *s; 62012154Ssam 62112154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 62212154Ssam s = dblock.dbuf.name; 62312154Ssam else 62412154Ssam s++; 62512154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 62612154Ssam passtape(); 62712154Ssam continue; 62812154Ssam } 62912154Ssam } 6306250Sroot if (checkdir(dblock.dbuf.name)) 6316250Sroot continue; 6326250Sroot if (dblock.dbuf.linkflag == '2') { 6336250Sroot unlink(dblock.dbuf.name); 6346250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 635*13492Ssam fprintf(stderr, "tar: %s: symbolic link failed\n", 636*13492Ssam dblock.dbuf.name); 6376250Sroot continue; 6386250Sroot } 6396250Sroot if (vflag) 6406250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 641*13492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 6428150Smckusick #ifdef notdef 6438150Smckusick /* ignore alien orders */ 6446250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6456250Sroot if (mflag == 0) { 64612983Ssam struct timeval tv[2]; 6471119Sbill 64812983Ssam tv[0].tv_sec = time(0); 64912983Ssam tv[0].tv_usec = 0; 65012983Ssam tv[1].tv_sec = stbuf.st_mtime; 65112983Ssam tv[1].tv_usec = 0; 65212983Ssam utimes(dblock.dbuf.name, tv); 6536250Sroot } 6546250Sroot if (pflag) 6556250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6568150Smckusick #endif 6571119Sbill continue; 6586250Sroot } 6591119Sbill if (dblock.dbuf.linkflag == '1') { 6601119Sbill unlink(dblock.dbuf.name); 6611119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 662*13492Ssam fprintf(stderr, "tar: %s: cannot link\n", 663*13492Ssam dblock.dbuf.name); 6641119Sbill continue; 6651119Sbill } 6661119Sbill if (vflag) 6673457Swnj fprintf(stderr, "%s linked to %s\n", 668*13492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 6691119Sbill continue; 6701119Sbill } 6716250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 6726250Sroot fprintf(stderr, "tar: %s - cannot create\n", 673*13492Ssam dblock.dbuf.name); 6741119Sbill passtape(); 6751119Sbill continue; 6761119Sbill } 6771926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6781119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 6791119Sbill if (vflag) 6803457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 681*13492Ssam dblock.dbuf.name, bytes, blocks); 6826250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 6831119Sbill readtape(buf); 6841119Sbill if (bytes > TBLOCK) { 6851119Sbill if (write(ofile, buf, TBLOCK) < 0) { 6866250Sroot fprintf(stderr, 6876250Sroot "tar: %s: HELP - extract write error\n", 688*13492Ssam dblock.dbuf.name); 6891119Sbill done(2); 6901119Sbill } 6916250Sroot continue; 6926250Sroot } 6936250Sroot if (write(ofile, buf, (int) bytes) < 0) { 6946250Sroot fprintf(stderr, 695*13492Ssam "tar: %s: HELP - extract write error\n", 696*13492Ssam dblock.dbuf.name); 6976250Sroot done(2); 6986250Sroot } 6991119Sbill } 7001119Sbill close(ofile); 7011119Sbill if (mflag == 0) { 70212983Ssam struct timeval tv[2]; 7031119Sbill 70412983Ssam tv[0].tv_sec = time(0); 70512983Ssam tv[0].tv_usec = 0; 70612983Ssam tv[1].tv_sec = stbuf.st_mtime; 70712983Ssam tv[1].tv_usec = 0; 70812983Ssam utimes(dblock.dbuf.name, tv); 7091119Sbill } 7101926Swnj if (pflag) 7116250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7121119Sbill } 7131119Sbill } 7141119Sbill 7151119Sbill dotable() 7161119Sbill { 7171119Sbill for (;;) { 7181119Sbill getdir(); 7191119Sbill if (endtape()) 7201119Sbill break; 7211119Sbill if (vflag) 7221119Sbill longt(&stbuf); 7231119Sbill printf("%s", dblock.dbuf.name); 7241119Sbill if (dblock.dbuf.linkflag == '1') 7251119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7266250Sroot if (dblock.dbuf.linkflag == '2') 7276250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7281119Sbill printf("\n"); 7291119Sbill passtape(); 7301119Sbill } 7311119Sbill } 7321119Sbill 7331119Sbill putempty() 7341119Sbill { 7351119Sbill char buf[TBLOCK]; 7361119Sbill 737*13492Ssam bzero(buf, sizeof (buf)); 7381119Sbill writetape(buf); 7391119Sbill } 7401119Sbill 7411119Sbill longt(st) 7426250Sroot register struct stat *st; 7431119Sbill { 7441119Sbill register char *cp; 7451119Sbill char *ctime(); 7461119Sbill 7471119Sbill pmode(st); 7481119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 7491119Sbill printf("%7D", st->st_size); 7501119Sbill cp = ctime(&st->st_mtime); 7511119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 7521119Sbill } 7531119Sbill 7541119Sbill #define SUID 04000 7551119Sbill #define SGID 02000 7561119Sbill #define ROWN 0400 7571119Sbill #define WOWN 0200 7581119Sbill #define XOWN 0100 7591119Sbill #define RGRP 040 7601119Sbill #define WGRP 020 7611119Sbill #define XGRP 010 7621119Sbill #define ROTH 04 7631119Sbill #define WOTH 02 7641119Sbill #define XOTH 01 7651119Sbill #define STXT 01000 7661119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 7671119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 7681119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 7691119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 7701119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 7711119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 7721119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 7731119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 7741119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 7751119Sbill 7761119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 7771119Sbill 7781119Sbill pmode(st) 7796250Sroot register struct stat *st; 7801119Sbill { 7811119Sbill register int **mp; 7821119Sbill 7831119Sbill for (mp = &m[0]; mp < &m[9];) 7841119Sbill select(*mp++, st); 7851119Sbill } 7861119Sbill 7871119Sbill select(pairp, st) 7886250Sroot int *pairp; 7896250Sroot struct stat *st; 7901119Sbill { 7911119Sbill register int n, *ap; 7921119Sbill 7931119Sbill ap = pairp; 7941119Sbill n = *ap++; 7951119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 7961119Sbill ap++; 7971119Sbill printf("%c", *ap); 7981119Sbill } 7991119Sbill 8001119Sbill checkdir(name) 8016250Sroot register char *name; 8021119Sbill { 8031119Sbill register char *cp; 8046250Sroot 80512154Ssam /* 80612154Ssam * Quick check for existance of directory. 80712154Ssam */ 80812154Ssam if ((cp = rindex(name, '/')) == 0) 80912154Ssam return (0); 81012154Ssam *cp = '\0'; 81112154Ssam if (access(name, 0) >= 0) { 81212154Ssam *cp = '/'; 81312154Ssam return (cp[1] == '\0'); 81412154Ssam } 81512154Ssam *cp = '/'; 81612154Ssam 81712154Ssam /* 81812154Ssam * No luck, try to make all directories in path. 81912154Ssam */ 8201119Sbill for (cp = name; *cp; cp++) { 8216250Sroot if (*cp != '/') 8226250Sroot continue; 8236250Sroot *cp = '\0'; 82412154Ssam if (access(name, 0) < 0) { 8259844Ssam if (mkdir(name, 0777) < 0) { 8269844Ssam perror(name); 82712154Ssam *cp = '/'; 82812154Ssam return (0); 8291119Sbill } 8306250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 8316250Sroot if (pflag) 8329844Ssam chmod(name, stbuf.st_mode & 0777); 8331119Sbill } 8346250Sroot *cp = '/'; 8351119Sbill } 8366250Sroot return (cp[-1]=='/'); 8371119Sbill } 8381119Sbill 8391119Sbill onintr() 8401119Sbill { 8411119Sbill signal(SIGINT, SIG_IGN); 8421119Sbill term++; 8431119Sbill } 8441119Sbill 8451119Sbill onquit() 8461119Sbill { 8471119Sbill signal(SIGQUIT, SIG_IGN); 8481119Sbill term++; 8491119Sbill } 8501119Sbill 8511119Sbill onhup() 8521119Sbill { 8531119Sbill signal(SIGHUP, SIG_IGN); 8541119Sbill term++; 8551119Sbill } 8561119Sbill 8571119Sbill onterm() 8581119Sbill { 8591119Sbill signal(SIGTERM, SIG_IGN); 8601119Sbill term++; 8611119Sbill } 8621119Sbill 8631119Sbill tomodes(sp) 8641119Sbill register struct stat *sp; 8651119Sbill { 8661119Sbill register char *cp; 8671119Sbill 8681119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8691119Sbill *cp = '\0'; 8701119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 8711119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 8721119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 8731119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 8741119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 8751119Sbill } 8761119Sbill 8771119Sbill checksum() 8781119Sbill { 8791119Sbill register i; 8801119Sbill register char *cp; 8811119Sbill 8826250Sroot for (cp = dblock.dbuf.chksum; 8836250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 8841119Sbill *cp = ' '; 8851119Sbill i = 0; 8861119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8871119Sbill i += *cp; 8886250Sroot return (i); 8891119Sbill } 8901119Sbill 8911119Sbill checkw(c, name) 8926250Sroot char *name; 8931119Sbill { 8946250Sroot if (!wflag) 8956250Sroot return (1); 8966250Sroot printf("%c ", c); 8976250Sroot if (vflag) 8986250Sroot longt(&stbuf); 8996250Sroot printf("%s: ", name); 9006250Sroot return (response() == 'y'); 9011119Sbill } 9021119Sbill 9031119Sbill response() 9041119Sbill { 9051119Sbill char c; 9061119Sbill 9071119Sbill c = getchar(); 9081119Sbill if (c != '\n') 9096250Sroot while (getchar() != '\n') 9106250Sroot ; 9116250Sroot else 9126250Sroot c = 'n'; 9136250Sroot return (c); 9141119Sbill } 9151119Sbill 91612154Ssam checkf(name, mode, howmuch) 91712154Ssam char *name; 91812154Ssam int mode, howmuch; 91912154Ssam { 92012154Ssam int l; 92112154Ssam 92212154Ssam if ((mode & S_IFMT) == S_IFDIR) 92312154Ssam return (strcmp(name, "SCCS") != 0); 92412154Ssam if ((l = strlen(name)) < 3) 92512154Ssam return (1); 92612154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 92712154Ssam return (0); 92812154Ssam if (strcmp(name, "core") == 0 || 92912154Ssam strcmp(name, "errs") == 0 || 93012154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 93112154Ssam return (0); 93212154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 93312154Ssam return (1); 93412154Ssam } 93512154Ssam 9361119Sbill checkupdate(arg) 9376250Sroot char *arg; 9381119Sbill { 9391119Sbill char name[100]; 9406250Sroot long mtime; 9411119Sbill daddr_t seekp; 9421119Sbill daddr_t lookup(); 9431119Sbill 9441119Sbill rewind(tfile); 9451119Sbill for (;;) { 9461119Sbill if ((seekp = lookup(arg)) < 0) 9476250Sroot return (1); 9481119Sbill fseek(tfile, seekp, 0); 9491119Sbill fscanf(tfile, "%s %lo", name, &mtime); 9506250Sroot return (stbuf.st_mtime > mtime); 9511119Sbill } 9521119Sbill } 9531119Sbill 9541119Sbill done(n) 9551119Sbill { 9561119Sbill unlink(tname); 9571119Sbill exit(n); 9581119Sbill } 9591119Sbill 9601119Sbill prefix(s1, s2) 9616250Sroot register char *s1, *s2; 9621119Sbill { 9631119Sbill while (*s1) 9641119Sbill if (*s1++ != *s2++) 9656250Sroot return (0); 9661119Sbill if (*s2) 9676250Sroot return (*s2 == '/'); 9686250Sroot return (1); 9691119Sbill } 9701119Sbill 9711119Sbill #define N 200 9721119Sbill int njab; 9736250Sroot 9741119Sbill daddr_t 9751119Sbill lookup(s) 9766250Sroot char *s; 9771119Sbill { 9781119Sbill register i; 9791119Sbill daddr_t a; 9801119Sbill 9811119Sbill for(i=0; s[i]; i++) 9826250Sroot if (s[i] == ' ') 9831119Sbill break; 9841119Sbill a = bsrch(s, i, low, high); 9856250Sroot return (a); 9861119Sbill } 9871119Sbill 9881119Sbill daddr_t 9891119Sbill bsrch(s, n, l, h) 9906250Sroot daddr_t l, h; 9916250Sroot char *s; 9921119Sbill { 9931119Sbill register i, j; 9941119Sbill char b[N]; 9951119Sbill daddr_t m, m1; 9961119Sbill 9971119Sbill njab = 0; 9981119Sbill 9991119Sbill loop: 10006250Sroot if (l >= h) 10016250Sroot return (-1L); 10021119Sbill m = l + (h-l)/2 - N/2; 10036250Sroot if (m < l) 10041119Sbill m = l; 10051119Sbill fseek(tfile, m, 0); 10061119Sbill fread(b, 1, N, tfile); 10071119Sbill njab++; 10081119Sbill for(i=0; i<N; i++) { 10096250Sroot if (b[i] == '\n') 10101119Sbill break; 10111119Sbill m++; 10121119Sbill } 10136250Sroot if (m >= h) 10146250Sroot return (-1L); 10151119Sbill m1 = m; 10161119Sbill j = i; 10171119Sbill for(i++; i<N; i++) { 10181119Sbill m1++; 10196250Sroot if (b[i] == '\n') 10201119Sbill break; 10211119Sbill } 10221119Sbill i = cmp(b+j, s, n); 10236250Sroot if (i < 0) { 10241119Sbill h = m; 10251119Sbill goto loop; 10261119Sbill } 10276250Sroot if (i > 0) { 10281119Sbill l = m1; 10291119Sbill goto loop; 10301119Sbill } 10316250Sroot return (m); 10321119Sbill } 10331119Sbill 10341119Sbill cmp(b, s, n) 10356250Sroot char *b, *s; 10361119Sbill { 10371119Sbill register i; 10381119Sbill 10396250Sroot if (b[0] != '\n') 10401119Sbill exit(2); 10411119Sbill for(i=0; i<n; i++) { 10426250Sroot if (b[i+1] > s[i]) 10436250Sroot return (-1); 10446250Sroot if (b[i+1] < s[i]) 10456250Sroot return (1); 10461119Sbill } 10476250Sroot return (b[i+1] == ' '? 0 : -1); 10481119Sbill } 10491119Sbill 10501119Sbill readtape(buffer) 10516250Sroot char *buffer; 10521119Sbill { 10533457Swnj register int i; 10541119Sbill 10551119Sbill if (recno >= nblock || first == 0) { 10568737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 1057*13492Ssam fprintf(stderr, "tar: tape read error\n"); 10581119Sbill done(3); 10591119Sbill } 10601119Sbill if (first == 0) { 10611119Sbill if ((i % TBLOCK) != 0) { 1062*13492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 10631119Sbill done(3); 10641119Sbill } 10651119Sbill i /= TBLOCK; 10663457Swnj if (i != nblock) { 1067*13492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 10681119Sbill nblock = i; 10691119Sbill } 10701119Sbill } 10711119Sbill recno = 0; 10721119Sbill } 10731119Sbill first = 1; 1074*13492Ssam bcopy((char *)&tbuf[recno++], buffer, TBLOCK); 10756250Sroot return (TBLOCK); 10761119Sbill } 10771119Sbill 10781119Sbill writetape(buffer) 10796250Sroot char *buffer; 10801119Sbill { 10811119Sbill first = 1; 10821119Sbill if (recno >= nblock) { 10831119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 1084*13492Ssam fprintf(stderr, "tar: tape write error\n"); 10851119Sbill done(2); 10861119Sbill } 10871119Sbill recno = 0; 10881119Sbill } 1089*13492Ssam bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 10901119Sbill if (recno >= nblock) { 10911119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 1092*13492Ssam fprintf(stderr, "tar: tape write error\n"); 10931119Sbill done(2); 10941119Sbill } 10951119Sbill recno = 0; 10961119Sbill } 10976250Sroot return (TBLOCK); 10981119Sbill } 10991119Sbill 11001119Sbill backtape() 11011119Sbill { 11023457Swnj static int mtdev = 1; 11033457Swnj static struct mtop mtop = {MTBSR, 1}; 11043457Swnj struct mtget mtget; 11053457Swnj 11063457Swnj if (mtdev == 1) 11073457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 11083457Swnj if (mtdev == 0) { 11093457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 1110*13492Ssam fprintf(stderr, "tar: tape backspace error\n"); 11111119Sbill done(4); 11121119Sbill } 11133457Swnj } else 11143457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 11153457Swnj recno--; 11161119Sbill } 11171119Sbill 11181119Sbill flushtape() 11191119Sbill { 11201119Sbill write(mt, tbuf, TBLOCK*nblock); 11211119Sbill } 11221119Sbill 11238737Smckusick bread(fd, buf, size) 11248737Smckusick int fd; 11258737Smckusick char *buf; 11268737Smckusick int size; 11278737Smckusick { 11288737Smckusick int count; 11298737Smckusick static int lastread = 0; 11308737Smckusick 11318737Smckusick if (!Bflag) 11328737Smckusick return (read(fd, buf, size)); 11338737Smckusick for (count = 0; count < size; count += lastread) { 11348737Smckusick if (lastread < 0) { 11358737Smckusick if (count > 0) 11368737Smckusick return (count); 11378737Smckusick return (lastread); 11388737Smckusick } 11398737Smckusick lastread = read(fd, buf, size - count); 11408737Smckusick buf += lastread; 11418737Smckusick } 11428737Smckusick return (count); 11438737Smckusick } 114410165Ssam 114510165Ssam char * 114610165Ssam getcwd(buf) 114710165Ssam char *buf; 114810165Ssam { 114910165Ssam 115010165Ssam if (getwd(buf) == NULL) { 115110165Ssam fprintf(stderr, "tar: %s\n", buf); 115210165Ssam exit(1); 115310165Ssam } 115410165Ssam return (buf); 115510165Ssam } 1156