1*12154Ssam #ifndef lint 2*12154Ssam static char *sccsid = "@(#)tar.c 4.15 (Berkeley) 04/30/83"; 3*12154Ssam #endif 46250Sroot 56250Sroot /* 66250Sroot * Tape Archival Program 76250Sroot */ 81119Sbill #include <stdio.h> 96413Smckusic #include <sys/param.h> 101119Sbill #include <sys/stat.h> 11*12154Ssam #include <sys/dir.h> 128150Smckusick #include <sys/ioctl.h> 133457Swnj #include <sys/mtio.h> 141119Sbill #include <signal.h> 15*12154Ssam #include <errno.h> 161119Sbill 171119Sbill #define TBLOCK 512 183355Swnj #define NBLOCK 20 191119Sbill #define NAMSIZ 100 206250Sroot 211119Sbill union hblock { 221119Sbill char dummy[TBLOCK]; 231119Sbill struct header { 241119Sbill char name[NAMSIZ]; 251119Sbill char mode[8]; 261119Sbill char uid[8]; 271119Sbill char gid[8]; 281119Sbill char size[12]; 291119Sbill char mtime[12]; 301119Sbill char chksum[8]; 311119Sbill char linkflag; 321119Sbill char linkname[NAMSIZ]; 331119Sbill } dbuf; 346250Sroot }; 351119Sbill 361119Sbill struct linkbuf { 371119Sbill ino_t inum; 381119Sbill dev_t devnum; 391119Sbill int count; 401119Sbill char pathname[NAMSIZ]; 411119Sbill struct linkbuf *nextp; 426250Sroot }; 431119Sbill 446250Sroot union hblock dblock; 456250Sroot union hblock tbuf[NBLOCK]; 466250Sroot struct linkbuf *ihead; 476250Sroot struct stat stbuf; 481119Sbill 496250Sroot int rflag; 506250Sroot int xflag; 516250Sroot int vflag; 526250Sroot int tflag; 536250Sroot int cflag; 546250Sroot int mflag; 556250Sroot int fflag; 56*12154Ssam int iflag; 576250Sroot int oflag; 586250Sroot int pflag; 596250Sroot int wflag; 606250Sroot int hflag; 618737Smckusick int Bflag; 62*12154Ssam int Fflag; 636250Sroot 646250Sroot int mt; 656250Sroot int term; 666250Sroot int chksum; 676250Sroot int recno; 686250Sroot int first; 696250Sroot int linkerrok; 701119Sbill int freemem = 1; 713457Swnj int nblock = NBLOCK; 726250Sroot int onintr(); 736250Sroot int onquit(); 746250Sroot int onhup(); 756250Sroot int onterm(); 761119Sbill 771119Sbill daddr_t low; 781119Sbill daddr_t high; 796250Sroot daddr_t bsrch(); 801119Sbill 811119Sbill FILE *tfile; 821119Sbill char tname[] = "/tmp/tarXXXXXX"; 831119Sbill char *usefile; 846250Sroot char magtape[] = "/dev/rmt8"; 851119Sbill char *malloc(); 866250Sroot char *sprintf(); 876250Sroot char *strcat(); 88*12154Ssam char *rindex(); 8910165Ssam char *getcwd(); 909844Ssam char *getwd(); 911119Sbill 921119Sbill main(argc, argv) 931119Sbill int argc; 941119Sbill char *argv[]; 951119Sbill { 961119Sbill char *cp; 971119Sbill 981119Sbill if (argc < 2) 991119Sbill usage(); 1001119Sbill 1011119Sbill tfile = NULL; 1021119Sbill usefile = magtape; 1031119Sbill argv[argc] = 0; 1041119Sbill argv++; 1051119Sbill for (cp = *argv++; *cp; cp++) 1061119Sbill switch(*cp) { 1076250Sroot 1081119Sbill case 'f': 109*12154Ssam if (*argv == 0) { 110*12154Ssam fprintf(stderr, 111*12154Ssam "tar: tapefile must be specified with 'f' option\n"); 112*12154Ssam usage(); 113*12154Ssam } 1141119Sbill usefile = *argv++; 1151119Sbill fflag++; 1161119Sbill break; 1176250Sroot 1181119Sbill case 'c': 1191119Sbill cflag++; 1201119Sbill rflag++; 1211119Sbill break; 1226250Sroot 1231119Sbill case 'o': 1241119Sbill oflag++; 1251119Sbill break; 1266250Sroot 1271119Sbill case 'p': 1281119Sbill pflag++; 1291119Sbill break; 1306250Sroot 1311119Sbill case 'u': 1321119Sbill mktemp(tname); 1331119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1346250Sroot fprintf(stderr, 1356250Sroot "Tar: cannot create temporary file (%s)\n", 1366250Sroot tname); 1371119Sbill done(1); 1381119Sbill } 1391119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1406250Sroot /*FALL THRU*/ 1416250Sroot 1421119Sbill case 'r': 1431119Sbill rflag++; 1441119Sbill break; 1456250Sroot 1461119Sbill case 'v': 1471119Sbill vflag++; 1481119Sbill break; 1496250Sroot 1501119Sbill case 'w': 1511119Sbill wflag++; 1521119Sbill break; 1536250Sroot 1541119Sbill case 'x': 1551119Sbill xflag++; 1561119Sbill break; 1576250Sroot 1581119Sbill case 't': 1591119Sbill tflag++; 1601119Sbill break; 1616250Sroot 1621119Sbill case 'm': 1631119Sbill mflag++; 1641119Sbill break; 1656250Sroot 1661119Sbill case '-': 1671119Sbill break; 1686250Sroot 1691119Sbill case '0': 1701119Sbill case '1': 1711119Sbill case '4': 1721119Sbill case '5': 1731119Sbill case '7': 1741119Sbill case '8': 1751119Sbill magtape[8] = *cp; 1761119Sbill usefile = magtape; 1771119Sbill break; 1786250Sroot 1791119Sbill case 'b': 1801119Sbill nblock = atoi(*argv++); 1811119Sbill if (nblock > NBLOCK || nblock <= 0) { 1826250Sroot fprintf(stderr, "Invalid blocksize. (Max %d)\n", 1836250Sroot NBLOCK); 1841119Sbill done(1); 1851119Sbill } 1861119Sbill break; 1876250Sroot 1881119Sbill case 'l': 1891119Sbill linkerrok++; 1901119Sbill break; 1916250Sroot 1926250Sroot case 'h': 1936250Sroot hflag++; 1946250Sroot break; 1956250Sroot 196*12154Ssam case 'i': 197*12154Ssam iflag++; 198*12154Ssam break; 199*12154Ssam 2008737Smckusick case 'B': 2018737Smckusick Bflag++; 2028737Smckusick break; 2038737Smckusick 204*12154Ssam case 'F': 205*12154Ssam Fflag++; 206*12154Ssam break; 207*12154Ssam 2081119Sbill default: 2091119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2101119Sbill usage(); 2111119Sbill } 2121119Sbill 2136250Sroot if (!rflag && !xflag && !tflag) 2146250Sroot usage(); 2151119Sbill if (rflag) { 2166250Sroot if (cflag && tfile != NULL) 2171119Sbill usage(); 2181119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2191119Sbill signal(SIGINT, onintr); 2201119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 2211119Sbill signal(SIGHUP, onhup); 2221119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2231119Sbill signal(SIGQUIT, onquit); 2246250Sroot #ifdef notdef 2251119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2261119Sbill signal(SIGTERM, onterm); 2276250Sroot #endif 2281119Sbill if (strcmp(usefile, "-") == 0) { 2291119Sbill if (cflag == 0) { 2306250Sroot fprintf(stderr, 2316250Sroot "Can only create standard output archives\n"); 2321119Sbill done(1); 2331119Sbill } 2341119Sbill mt = dup(1); 2351119Sbill nblock = 1; 2366250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2371119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2386250Sroot fprintf(stderr, 2396250Sroot "tar: cannot open %s\n", usefile); 2401119Sbill done(1); 2411119Sbill } 2421119Sbill } 2431119Sbill dorep(argv); 2446250Sroot done(0); 2451119Sbill } 2466250Sroot if (strcmp(usefile, "-") == 0) { 2476250Sroot mt = dup(0); 2486250Sroot nblock = 1; 2496250Sroot } else if ((mt = open(usefile, 0)) < 0) { 2506250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 2516250Sroot done(1); 2526250Sroot } 2536250Sroot if (xflag) 2541119Sbill doxtract(argv); 2556250Sroot else 2561119Sbill dotable(); 2571119Sbill done(0); 2581119Sbill } 2591119Sbill 2601119Sbill usage() 2611119Sbill { 2626250Sroot fprintf(stderr, 2638737Smckusick "tar: usage tar -{txruB}[cvfblmh] [tapefile] [blocksize] file1 file2...\n"); 2641119Sbill done(1); 2651119Sbill } 2661119Sbill 2671119Sbill dorep(argv) 2686250Sroot char *argv[]; 2691119Sbill { 2701119Sbill register char *cp, *cp2; 2719601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 2721119Sbill 2731119Sbill if (!cflag) { 2741119Sbill getdir(); 2751119Sbill do { 2761119Sbill passtape(); 2771119Sbill if (term) 2781119Sbill done(0); 2791119Sbill getdir(); 2801119Sbill } while (!endtape()); 2811119Sbill if (tfile != NULL) { 2821119Sbill char buf[200]; 2831119Sbill 2846250Sroot sprintf(buf, 2856250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 2861119Sbill tname, tname, tname, tname, tname, tname); 2871119Sbill fflush(tfile); 2881119Sbill system(buf); 2891119Sbill freopen(tname, "r", tfile); 2901119Sbill fstat(fileno(tfile), &stbuf); 2911119Sbill high = stbuf.st_size; 2921119Sbill } 2931119Sbill } 2941119Sbill 29510165Ssam (void) getcwd(wdir); 2961119Sbill while (*argv && ! term) { 2971119Sbill cp2 = *argv; 2981119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 2991119Sbill argv++; 3001119Sbill if (chdir(*argv) < 0) 3011119Sbill perror(*argv); 3021119Sbill else 30310165Ssam (void) getcwd(wdir); 3041119Sbill argv++; 3051119Sbill continue; 3061119Sbill } 3079601Ssam parent = wdir; 3081119Sbill for (cp = *argv; *cp; cp++) 3091119Sbill if (*cp == '/') 3101119Sbill cp2 = cp; 3111119Sbill if (cp2 != *argv) { 3121119Sbill *cp2 = '\0'; 3139601Ssam if (chdir(*argv) < 0) { 3149601Ssam perror(*argv); 3159601Ssam continue; 3169601Ssam } 31710165Ssam parent = getcwd(tempdir); 3181119Sbill *cp2 = '/'; 3191119Sbill cp2++; 3201119Sbill } 3219601Ssam putfile(*argv++, cp2, parent); 3221119Sbill chdir(wdir); 3231119Sbill } 3241119Sbill putempty(); 3251119Sbill putempty(); 3261119Sbill flushtape(); 3276250Sroot if (linkerrok == 0) 3286250Sroot return; 3296250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3306250Sroot if (ihead->count == 0) 3316250Sroot continue; 3326250Sroot fprintf(stderr, "Missing links to %s\n", ihead->pathname); 3336250Sroot } 3341119Sbill } 3351119Sbill 3361119Sbill endtape() 3371119Sbill { 3386250Sroot if (dblock.dbuf.name[0] != '\0') 3396250Sroot return (0); 3406250Sroot backtape(); 3416250Sroot return (1); 3421119Sbill } 3431119Sbill 3441119Sbill getdir() 3451119Sbill { 3461119Sbill register struct stat *sp; 3471119Sbill int i; 3481119Sbill 349*12154Ssam top: 3506250Sroot readtape((char *)&dblock); 3511119Sbill if (dblock.dbuf.name[0] == '\0') 3521119Sbill return; 3531119Sbill sp = &stbuf; 3541119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3551119Sbill sp->st_mode = i; 3561119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3571119Sbill sp->st_uid = i; 3581119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3591119Sbill sp->st_gid = i; 3601119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3611119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3621119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 363*12154Ssam if (chksum != (i = checksum())) { 364*12154Ssam fprintf(stderr, "directory checksum error (%d != %d)\n", 365*12154Ssam chksum, i); 366*12154Ssam if (iflag) 367*12154Ssam goto top; 3681119Sbill done(2); 3691119Sbill } 3701119Sbill if (tfile != NULL) 3711119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3721119Sbill } 3731119Sbill 3741119Sbill passtape() 3751119Sbill { 3761119Sbill long blocks; 3771119Sbill char buf[TBLOCK]; 3781119Sbill 3791119Sbill if (dblock.dbuf.linkflag == '1') 3801119Sbill return; 3811119Sbill blocks = stbuf.st_size; 3821119Sbill blocks += TBLOCK-1; 3831119Sbill blocks /= TBLOCK; 3841119Sbill 3851119Sbill while (blocks-- > 0) 3861119Sbill readtape(buf); 3871119Sbill } 3881119Sbill 3899601Ssam putfile(longname, shortname, parent) 3906250Sroot char *longname; 3916250Sroot char *shortname; 3929601Ssam char *parent; 3931119Sbill { 394*12154Ssam int infile = 0; 3951119Sbill long blocks; 3961119Sbill char buf[TBLOCK]; 3971119Sbill register char *cp, *cp2; 3985931Smckusic struct direct *dp; 3995931Smckusic DIR *dirp; 4001119Sbill int i, j; 4019601Ssam char newparent[NAMSIZ+64]; 402*12154Ssam extern int errno; 4031119Sbill 4049601Ssam if (!hflag) 405*12154Ssam i = lstat(shortname, &stbuf); 406*12154Ssam else 407*12154Ssam i = stat(shortname, &stbuf); 408*12154Ssam if (i < 0) { 409*12154Ssam switch (errno) { 410*12154Ssam case EACCES: 411*12154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 412*12154Ssam break; 413*12154Ssam case ENOENT: 414*12154Ssam fprintf(stderr, "tar: %s: no such file or directory\n", 415*12154Ssam longname); 416*12154Ssam break; 417*12154Ssam default: 418*12154Ssam fprintf(stderr, "tar: %s: cannot stat file\n", longname); 419*12154Ssam break; 420*12154Ssam } 4219601Ssam return; 4229601Ssam } 423*12154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4241119Sbill return; 425*12154Ssam if (checkw('r', longname) == 0) 4261119Sbill return; 427*12154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 428*12154Ssam return; 4291119Sbill 430*12154Ssam switch (stbuf.st_mode & S_IFMT) { 431*12154Ssam case S_IFDIR: 4326250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4336250Sroot ; 4341119Sbill *--cp = '/'; 4351119Sbill *++cp = 0 ; 4361119Sbill if (!oflag) { 4376250Sroot if ((cp - buf) >= NAMSIZ) { 4386250Sroot fprintf(stderr, "%s: file name too long\n", 4396250Sroot longname); 4406250Sroot return; 4416250Sroot } 4426250Sroot stbuf.st_size = 0; 4436250Sroot tomodes(&stbuf); 4446250Sroot strcpy(dblock.dbuf.name,buf); 4456250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4466250Sroot writetape((char *)&dblock); 4471119Sbill } 4489601Ssam sprintf(newparent, "%s/%s", parent, shortname); 4491119Sbill chdir(shortname); 4505931Smckusic if ((dirp = opendir(".")) == NULL) { 4515931Smckusic fprintf(stderr, "%s: directory read error\n", longname); 4529601Ssam chdir(parent); 4535931Smckusic return; 4545931Smckusic } 4555931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4565931Smckusic if (dp->d_ino == 0) 4571119Sbill continue; 4586250Sroot if (!strcmp(".", dp->d_name) || 4596250Sroot !strcmp("..", dp->d_name)) 4601119Sbill continue; 4615931Smckusic strcpy(cp, dp->d_name); 4625931Smckusic i = telldir(dirp); 4635931Smckusic closedir(dirp); 4649601Ssam putfile(buf, cp, newparent); 4655931Smckusic dirp = opendir("."); 4665931Smckusic seekdir(dirp, i); 4671119Sbill } 4685931Smckusic closedir(dirp); 4699601Ssam chdir(parent); 470*12154Ssam break; 471*12154Ssam 472*12154Ssam case S_IFLNK: 473*12154Ssam tomodes(&stbuf); 474*12154Ssam if (strlen(longname) >= NAMSIZ) { 475*12154Ssam fprintf(stderr, "%s: file name too long\n", longname); 476*12154Ssam return; 477*12154Ssam } 478*12154Ssam strcpy(dblock.dbuf.name, longname); 4796250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 4806250Sroot fprintf(stderr, "%s: symbolic link too long\n", 4816250Sroot longname); 4826250Sroot return; 4836250Sroot } 4849601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 4856250Sroot if (i < 0) { 4869601Ssam perror(longname); 4876250Sroot return; 4886250Sroot } 4896250Sroot dblock.dbuf.linkname[i] = '\0'; 4906250Sroot dblock.dbuf.linkflag = '2'; 4916250Sroot if (vflag) { 4926250Sroot fprintf(stderr, "a %s ", longname); 4936250Sroot fprintf(stderr, "symbolic link to %s\n", 4946250Sroot dblock.dbuf.linkname); 4956250Sroot } 4966250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 4976250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4986250Sroot writetape((char *)&dblock); 499*12154Ssam break; 5001119Sbill 501*12154Ssam case S_IFREG: 502*12154Ssam if ((infile = open(shortname, 0)) < 0) { 503*12154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 5041119Sbill return; 5051119Sbill } 506*12154Ssam tomodes(&stbuf); 507*12154Ssam if (strlen(longname) >= NAMSIZ) { 508*12154Ssam fprintf(stderr, "%s: file name too long\n", longname); 509*12154Ssam return; 510*12154Ssam } 511*12154Ssam strcpy(dblock.dbuf.name, longname); 512*12154Ssam if (stbuf.st_nlink > 1) { 513*12154Ssam struct linkbuf *lp; 514*12154Ssam int found = 0; 515*12154Ssam 516*12154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 517*12154Ssam if (lp->inum == stbuf.st_ino && 518*12154Ssam lp->devnum == stbuf.st_dev) { 519*12154Ssam found++; 520*12154Ssam break; 521*12154Ssam } 522*12154Ssam if (found) { 523*12154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 524*12154Ssam dblock.dbuf.linkflag = '1'; 525*12154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 526*12154Ssam writetape( (char *) &dblock); 527*12154Ssam if (vflag) { 528*12154Ssam fprintf(stderr, "a %s ", longname); 529*12154Ssam fprintf(stderr, "link to %s\n", lp->pathname); 530*12154Ssam } 531*12154Ssam lp->count--; 532*12154Ssam close(infile); 533*12154Ssam return; 5341119Sbill } 535*12154Ssam lp = (struct linkbuf *) malloc(sizeof(*lp)); 536*12154Ssam if (lp == NULL) { 537*12154Ssam if (freemem) { 538*12154Ssam fprintf(stderr, 539*12154Ssam "Out of memory. Link information lost\n"); 540*12154Ssam freemem = 0; 541*12154Ssam } 542*12154Ssam } else { 543*12154Ssam lp->nextp = ihead; 544*12154Ssam ihead = lp; 545*12154Ssam lp->inum = stbuf.st_ino; 546*12154Ssam lp->devnum = stbuf.st_dev; 547*12154Ssam lp->count = stbuf.st_nlink - 1; 548*12154Ssam strcpy(lp->pathname, longname); 549*12154Ssam } 5501119Sbill } 551*12154Ssam blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 552*12154Ssam if (vflag) { 553*12154Ssam fprintf(stderr, "a %s ", longname); 554*12154Ssam fprintf(stderr, "%ld blocks\n", blocks); 555*12154Ssam } 556*12154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 557*12154Ssam writetape((char *)&dblock); 5581119Sbill 559*12154Ssam while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 560*12154Ssam writetape(buf); 561*12154Ssam blocks--; 562*12154Ssam } 563*12154Ssam close(infile); 564*12154Ssam if (blocks != 0 || i != 0) 565*12154Ssam fprintf(stderr, "%s: file changed size\n", longname); 566*12154Ssam while (--blocks >= 0) 567*12154Ssam putempty(); 568*12154Ssam break; 569*12154Ssam 570*12154Ssam default: 571*12154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 572*12154Ssam longname); 573*12154Ssam break; 5741119Sbill } 5751119Sbill } 5761119Sbill 5771119Sbill doxtract(argv) 5786250Sroot char *argv[]; 5791119Sbill { 5801119Sbill long blocks, bytes; 5811119Sbill char buf[TBLOCK]; 5821119Sbill char **cp; 5831119Sbill int ofile; 5841119Sbill 5851119Sbill for (;;) { 5861119Sbill getdir(); 5871119Sbill if (endtape()) 5881119Sbill break; 5891119Sbill if (*argv == 0) 5901119Sbill goto gotit; 5911119Sbill for (cp = argv; *cp; cp++) 5921119Sbill if (prefix(*cp, dblock.dbuf.name)) 5931119Sbill goto gotit; 5941119Sbill passtape(); 5951119Sbill continue; 5961119Sbill 5971119Sbill gotit: 5981119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 5991119Sbill passtape(); 6001119Sbill continue; 6011119Sbill } 602*12154Ssam if (Fflag) { 603*12154Ssam char *s; 604*12154Ssam 605*12154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 606*12154Ssam s = dblock.dbuf.name; 607*12154Ssam else 608*12154Ssam s++; 609*12154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 610*12154Ssam passtape(); 611*12154Ssam continue; 612*12154Ssam } 613*12154Ssam } 6146250Sroot if (checkdir(dblock.dbuf.name)) 6156250Sroot continue; 6166250Sroot if (dblock.dbuf.linkflag == '2') { 6176250Sroot unlink(dblock.dbuf.name); 6186250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 6196250Sroot fprintf(stderr, "%s: symbolic link failed\n", 6206250Sroot dblock.dbuf.name); 6216250Sroot continue; 6226250Sroot } 6236250Sroot if (vflag) 6246250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 6256250Sroot dblock.dbuf.name, dblock.dbuf.linkname); 6268150Smckusick #ifdef notdef 6278150Smckusick /* ignore alien orders */ 6286250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6296250Sroot if (mflag == 0) { 6306250Sroot time_t timep[2]; 6311119Sbill 6326250Sroot timep[0] = time(0); 6336250Sroot timep[1] = stbuf.st_mtime; 6346250Sroot utime(dblock.dbuf.name, timep); 6356250Sroot } 6366250Sroot if (pflag) 6376250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6388150Smckusick #endif 6391119Sbill continue; 6406250Sroot } 6411119Sbill if (dblock.dbuf.linkflag == '1') { 6421119Sbill unlink(dblock.dbuf.name); 6431119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 6446250Sroot fprintf(stderr, "%s: cannot link\n", 6456250Sroot dblock.dbuf.name); 6461119Sbill continue; 6471119Sbill } 6481119Sbill if (vflag) 6493457Swnj fprintf(stderr, "%s linked to %s\n", 6503457Swnj dblock.dbuf.name, dblock.dbuf.linkname); 6511119Sbill continue; 6521119Sbill } 6536250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 6546250Sroot fprintf(stderr, "tar: %s - cannot create\n", 6556250Sroot dblock.dbuf.name); 6561119Sbill passtape(); 6571119Sbill continue; 6581119Sbill } 6591926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6601119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 6611119Sbill if (vflag) 6623457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 6633457Swnj dblock.dbuf.name, bytes, blocks); 6646250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 6651119Sbill readtape(buf); 6661119Sbill if (bytes > TBLOCK) { 6671119Sbill if (write(ofile, buf, TBLOCK) < 0) { 6686250Sroot fprintf(stderr, 6696250Sroot "tar: %s: HELP - extract write error\n", 6706250Sroot dblock.dbuf.name); 6711119Sbill done(2); 6721119Sbill } 6736250Sroot continue; 6746250Sroot } 6756250Sroot if (write(ofile, buf, (int) bytes) < 0) { 6766250Sroot fprintf(stderr, 6776250Sroot "tar: %s: HELP - extract write error\n", 6786250Sroot dblock.dbuf.name); 6796250Sroot done(2); 6806250Sroot } 6811119Sbill } 6821119Sbill close(ofile); 6831119Sbill if (mflag == 0) { 6841119Sbill time_t timep[2]; 6851119Sbill 6861119Sbill timep[0] = time(NULL); 6871119Sbill timep[1] = stbuf.st_mtime; 6881119Sbill utime(dblock.dbuf.name, timep); 6891119Sbill } 6901926Swnj if (pflag) 6916250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6921119Sbill } 6931119Sbill } 6941119Sbill 6951119Sbill dotable() 6961119Sbill { 6971119Sbill for (;;) { 6981119Sbill getdir(); 6991119Sbill if (endtape()) 7001119Sbill break; 7011119Sbill if (vflag) 7021119Sbill longt(&stbuf); 7031119Sbill printf("%s", dblock.dbuf.name); 7041119Sbill if (dblock.dbuf.linkflag == '1') 7051119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7066250Sroot if (dblock.dbuf.linkflag == '2') 7076250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7081119Sbill printf("\n"); 7091119Sbill passtape(); 7101119Sbill } 7111119Sbill } 7121119Sbill 7131119Sbill putempty() 7141119Sbill { 7151119Sbill char buf[TBLOCK]; 7161119Sbill char *cp; 7171119Sbill 7181119Sbill for (cp = buf; cp < &buf[TBLOCK]; ) 7191119Sbill *cp++ = '\0'; 7201119Sbill writetape(buf); 7211119Sbill } 7221119Sbill 7231119Sbill longt(st) 7246250Sroot register struct stat *st; 7251119Sbill { 7261119Sbill register char *cp; 7271119Sbill char *ctime(); 7281119Sbill 7291119Sbill pmode(st); 7301119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 7311119Sbill printf("%7D", st->st_size); 7321119Sbill cp = ctime(&st->st_mtime); 7331119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 7341119Sbill } 7351119Sbill 7361119Sbill #define SUID 04000 7371119Sbill #define SGID 02000 7381119Sbill #define ROWN 0400 7391119Sbill #define WOWN 0200 7401119Sbill #define XOWN 0100 7411119Sbill #define RGRP 040 7421119Sbill #define WGRP 020 7431119Sbill #define XGRP 010 7441119Sbill #define ROTH 04 7451119Sbill #define WOTH 02 7461119Sbill #define XOTH 01 7471119Sbill #define STXT 01000 7481119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 7491119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 7501119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 7511119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 7521119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 7531119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 7541119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 7551119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 7561119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 7571119Sbill 7581119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 7591119Sbill 7601119Sbill pmode(st) 7616250Sroot register struct stat *st; 7621119Sbill { 7631119Sbill register int **mp; 7641119Sbill 7651119Sbill for (mp = &m[0]; mp < &m[9];) 7661119Sbill select(*mp++, st); 7671119Sbill } 7681119Sbill 7691119Sbill select(pairp, st) 7706250Sroot int *pairp; 7716250Sroot struct stat *st; 7721119Sbill { 7731119Sbill register int n, *ap; 7741119Sbill 7751119Sbill ap = pairp; 7761119Sbill n = *ap++; 7771119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 7781119Sbill ap++; 7791119Sbill printf("%c", *ap); 7801119Sbill } 7811119Sbill 7821119Sbill checkdir(name) 7836250Sroot register char *name; 7841119Sbill { 7851119Sbill register char *cp; 7866250Sroot 787*12154Ssam /* 788*12154Ssam * Quick check for existance of directory. 789*12154Ssam */ 790*12154Ssam if ((cp = rindex(name, '/')) == 0) 791*12154Ssam return (0); 792*12154Ssam *cp = '\0'; 793*12154Ssam if (access(name, 0) >= 0) { 794*12154Ssam *cp = '/'; 795*12154Ssam return (cp[1] == '\0'); 796*12154Ssam } 797*12154Ssam *cp = '/'; 798*12154Ssam 799*12154Ssam /* 800*12154Ssam * No luck, try to make all directories in path. 801*12154Ssam */ 8021119Sbill for (cp = name; *cp; cp++) { 8036250Sroot if (*cp != '/') 8046250Sroot continue; 8056250Sroot *cp = '\0'; 806*12154Ssam if (access(name, 0) < 0) { 8079844Ssam if (mkdir(name, 0777) < 0) { 8089844Ssam perror(name); 809*12154Ssam *cp = '/'; 810*12154Ssam return (0); 8111119Sbill } 8126250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 8136250Sroot if (pflag) 8149844Ssam chmod(name, stbuf.st_mode & 0777); 8151119Sbill } 8166250Sroot *cp = '/'; 8171119Sbill } 8186250Sroot return (cp[-1]=='/'); 8191119Sbill } 8201119Sbill 8211119Sbill onintr() 8221119Sbill { 8231119Sbill signal(SIGINT, SIG_IGN); 8241119Sbill term++; 8251119Sbill } 8261119Sbill 8271119Sbill onquit() 8281119Sbill { 8291119Sbill signal(SIGQUIT, SIG_IGN); 8301119Sbill term++; 8311119Sbill } 8321119Sbill 8331119Sbill onhup() 8341119Sbill { 8351119Sbill signal(SIGHUP, SIG_IGN); 8361119Sbill term++; 8371119Sbill } 8381119Sbill 8391119Sbill onterm() 8401119Sbill { 8411119Sbill signal(SIGTERM, SIG_IGN); 8421119Sbill term++; 8431119Sbill } 8441119Sbill 8451119Sbill tomodes(sp) 8461119Sbill register struct stat *sp; 8471119Sbill { 8481119Sbill register char *cp; 8491119Sbill 8501119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8511119Sbill *cp = '\0'; 8521119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 8531119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 8541119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 8551119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 8561119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 8571119Sbill } 8581119Sbill 8591119Sbill checksum() 8601119Sbill { 8611119Sbill register i; 8621119Sbill register char *cp; 8631119Sbill 8646250Sroot for (cp = dblock.dbuf.chksum; 8656250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 8661119Sbill *cp = ' '; 8671119Sbill i = 0; 8681119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8691119Sbill i += *cp; 8706250Sroot return (i); 8711119Sbill } 8721119Sbill 8731119Sbill checkw(c, name) 8746250Sroot char *name; 8751119Sbill { 8766250Sroot if (!wflag) 8776250Sroot return (1); 8786250Sroot printf("%c ", c); 8796250Sroot if (vflag) 8806250Sroot longt(&stbuf); 8816250Sroot printf("%s: ", name); 8826250Sroot return (response() == 'y'); 8831119Sbill } 8841119Sbill 8851119Sbill response() 8861119Sbill { 8871119Sbill char c; 8881119Sbill 8891119Sbill c = getchar(); 8901119Sbill if (c != '\n') 8916250Sroot while (getchar() != '\n') 8926250Sroot ; 8936250Sroot else 8946250Sroot c = 'n'; 8956250Sroot return (c); 8961119Sbill } 8971119Sbill 898*12154Ssam checkf(name, mode, howmuch) 899*12154Ssam char *name; 900*12154Ssam int mode, howmuch; 901*12154Ssam { 902*12154Ssam int l; 903*12154Ssam 904*12154Ssam if ((mode & S_IFMT) == S_IFDIR) 905*12154Ssam return (strcmp(name, "SCCS") != 0); 906*12154Ssam if ((l = strlen(name)) < 3) 907*12154Ssam return (1); 908*12154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 909*12154Ssam return (0); 910*12154Ssam if (strcmp(name, "core") == 0 || 911*12154Ssam strcmp(name, "errs") == 0 || 912*12154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 913*12154Ssam return (0); 914*12154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 915*12154Ssam return (1); 916*12154Ssam } 917*12154Ssam 9181119Sbill checkupdate(arg) 9196250Sroot char *arg; 9201119Sbill { 9211119Sbill char name[100]; 9226250Sroot long mtime; 9231119Sbill daddr_t seekp; 9241119Sbill daddr_t lookup(); 9251119Sbill 9261119Sbill rewind(tfile); 9271119Sbill for (;;) { 9281119Sbill if ((seekp = lookup(arg)) < 0) 9296250Sroot return (1); 9301119Sbill fseek(tfile, seekp, 0); 9311119Sbill fscanf(tfile, "%s %lo", name, &mtime); 9326250Sroot return (stbuf.st_mtime > mtime); 9331119Sbill } 9341119Sbill } 9351119Sbill 9361119Sbill done(n) 9371119Sbill { 9381119Sbill unlink(tname); 9391119Sbill exit(n); 9401119Sbill } 9411119Sbill 9421119Sbill prefix(s1, s2) 9436250Sroot register char *s1, *s2; 9441119Sbill { 9451119Sbill while (*s1) 9461119Sbill if (*s1++ != *s2++) 9476250Sroot return (0); 9481119Sbill if (*s2) 9496250Sroot return (*s2 == '/'); 9506250Sroot return (1); 9511119Sbill } 9521119Sbill 9531119Sbill #define N 200 9541119Sbill int njab; 9556250Sroot 9561119Sbill daddr_t 9571119Sbill lookup(s) 9586250Sroot char *s; 9591119Sbill { 9601119Sbill register i; 9611119Sbill daddr_t a; 9621119Sbill 9631119Sbill for(i=0; s[i]; i++) 9646250Sroot if (s[i] == ' ') 9651119Sbill break; 9661119Sbill a = bsrch(s, i, low, high); 9676250Sroot return (a); 9681119Sbill } 9691119Sbill 9701119Sbill daddr_t 9711119Sbill bsrch(s, n, l, h) 9726250Sroot daddr_t l, h; 9736250Sroot char *s; 9741119Sbill { 9751119Sbill register i, j; 9761119Sbill char b[N]; 9771119Sbill daddr_t m, m1; 9781119Sbill 9791119Sbill njab = 0; 9801119Sbill 9811119Sbill loop: 9826250Sroot if (l >= h) 9836250Sroot return (-1L); 9841119Sbill m = l + (h-l)/2 - N/2; 9856250Sroot if (m < l) 9861119Sbill m = l; 9871119Sbill fseek(tfile, m, 0); 9881119Sbill fread(b, 1, N, tfile); 9891119Sbill njab++; 9901119Sbill for(i=0; i<N; i++) { 9916250Sroot if (b[i] == '\n') 9921119Sbill break; 9931119Sbill m++; 9941119Sbill } 9956250Sroot if (m >= h) 9966250Sroot return (-1L); 9971119Sbill m1 = m; 9981119Sbill j = i; 9991119Sbill for(i++; i<N; i++) { 10001119Sbill m1++; 10016250Sroot if (b[i] == '\n') 10021119Sbill break; 10031119Sbill } 10041119Sbill i = cmp(b+j, s, n); 10056250Sroot if (i < 0) { 10061119Sbill h = m; 10071119Sbill goto loop; 10081119Sbill } 10096250Sroot if (i > 0) { 10101119Sbill l = m1; 10111119Sbill goto loop; 10121119Sbill } 10136250Sroot return (m); 10141119Sbill } 10151119Sbill 10161119Sbill cmp(b, s, n) 10176250Sroot char *b, *s; 10181119Sbill { 10191119Sbill register i; 10201119Sbill 10216250Sroot if (b[0] != '\n') 10221119Sbill exit(2); 10231119Sbill for(i=0; i<n; i++) { 10246250Sroot if (b[i+1] > s[i]) 10256250Sroot return (-1); 10266250Sroot if (b[i+1] < s[i]) 10276250Sroot return (1); 10281119Sbill } 10296250Sroot return (b[i+1] == ' '? 0 : -1); 10301119Sbill } 10311119Sbill 10321119Sbill readtape(buffer) 10336250Sroot char *buffer; 10341119Sbill { 10353457Swnj register int i; 10361119Sbill 10371119Sbill if (recno >= nblock || first == 0) { 10388737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 10391119Sbill fprintf(stderr, "Tar: tape read error\n"); 10401119Sbill done(3); 10411119Sbill } 10421119Sbill if (first == 0) { 10431119Sbill if ((i % TBLOCK) != 0) { 10441119Sbill fprintf(stderr, "Tar: tape blocksize error\n"); 10451119Sbill done(3); 10461119Sbill } 10471119Sbill i /= TBLOCK; 10483457Swnj if (i != nblock) { 10491119Sbill fprintf(stderr, "Tar: blocksize = %d\n", i); 10501119Sbill nblock = i; 10511119Sbill } 10521119Sbill } 10531119Sbill recno = 0; 10541119Sbill } 10551119Sbill first = 1; 10561119Sbill copy(buffer, &tbuf[recno++]); 10576250Sroot return (TBLOCK); 10581119Sbill } 10591119Sbill 10601119Sbill writetape(buffer) 10616250Sroot char *buffer; 10621119Sbill { 10631119Sbill first = 1; 10641119Sbill if (recno >= nblock) { 10651119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 10661119Sbill fprintf(stderr, "Tar: tape write error\n"); 10671119Sbill done(2); 10681119Sbill } 10691119Sbill recno = 0; 10701119Sbill } 10711119Sbill copy(&tbuf[recno++], buffer); 10721119Sbill if (recno >= nblock) { 10731119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 10741119Sbill fprintf(stderr, "Tar: tape write error\n"); 10751119Sbill done(2); 10761119Sbill } 10771119Sbill recno = 0; 10781119Sbill } 10796250Sroot return (TBLOCK); 10801119Sbill } 10811119Sbill 10821119Sbill backtape() 10831119Sbill { 10843457Swnj static int mtdev = 1; 10853457Swnj static struct mtop mtop = {MTBSR, 1}; 10863457Swnj struct mtget mtget; 10873457Swnj 10883457Swnj if (mtdev == 1) 10893457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 10903457Swnj if (mtdev == 0) { 10913457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 10923457Swnj fprintf(stderr, "Tar: tape backspace error\n"); 10931119Sbill done(4); 10941119Sbill } 10953457Swnj } else 10963457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 10973457Swnj recno--; 10981119Sbill } 10991119Sbill 11001119Sbill flushtape() 11011119Sbill { 11021119Sbill write(mt, tbuf, TBLOCK*nblock); 11031119Sbill } 11041119Sbill 11051119Sbill copy(to, from) 11066250Sroot register char *to, *from; 11071119Sbill { 11081119Sbill register i; 11091119Sbill 11101119Sbill i = TBLOCK; 11111119Sbill do { 11121119Sbill *to++ = *from++; 11131119Sbill } while (--i); 11141119Sbill } 11158737Smckusick 11168737Smckusick bread(fd, buf, size) 11178737Smckusick int fd; 11188737Smckusick char *buf; 11198737Smckusick int size; 11208737Smckusick { 11218737Smckusick int count; 11228737Smckusick static int lastread = 0; 11238737Smckusick 11248737Smckusick if (!Bflag) 11258737Smckusick return (read(fd, buf, size)); 11268737Smckusick for (count = 0; count < size; count += lastread) { 11278737Smckusick if (lastread < 0) { 11288737Smckusick if (count > 0) 11298737Smckusick return (count); 11308737Smckusick return (lastread); 11318737Smckusick } 11328737Smckusick lastread = read(fd, buf, size - count); 11338737Smckusick buf += lastread; 11348737Smckusick } 11358737Smckusick return (count); 11368737Smckusick } 113710165Ssam 113810165Ssam char * 113910165Ssam getcwd(buf) 114010165Ssam char *buf; 114110165Ssam { 114210165Ssam 114310165Ssam if (getwd(buf) == NULL) { 114410165Ssam fprintf(stderr, "tar: %s\n", buf); 114510165Ssam exit(1); 114610165Ssam } 114710165Ssam return (buf); 114810165Ssam } 1149