1*8150Smckusick static char *sccsid = "@(#)tar.c 4.10 (Berkeley) 82/09/11"; 26250Sroot 36250Sroot /* 46250Sroot * Tape Archival Program 56250Sroot */ 61119Sbill #include <stdio.h> 76413Smckusic #include <sys/param.h> 81119Sbill #include <sys/stat.h> 96654Smckusick #include <dir.h> 10*8150Smckusick #include <sys/ioctl.h> 113457Swnj #include <sys/mtio.h> 121119Sbill #include <signal.h> 131119Sbill 141119Sbill #define TBLOCK 512 153355Swnj #define NBLOCK 20 161119Sbill #define NAMSIZ 100 176250Sroot 181119Sbill union hblock { 191119Sbill char dummy[TBLOCK]; 201119Sbill struct header { 211119Sbill char name[NAMSIZ]; 221119Sbill char mode[8]; 231119Sbill char uid[8]; 241119Sbill char gid[8]; 251119Sbill char size[12]; 261119Sbill char mtime[12]; 271119Sbill char chksum[8]; 281119Sbill char linkflag; 291119Sbill char linkname[NAMSIZ]; 301119Sbill } dbuf; 316250Sroot }; 321119Sbill 331119Sbill struct linkbuf { 341119Sbill ino_t inum; 351119Sbill dev_t devnum; 361119Sbill int count; 371119Sbill char pathname[NAMSIZ]; 381119Sbill struct linkbuf *nextp; 396250Sroot }; 401119Sbill 416250Sroot union hblock dblock; 426250Sroot union hblock tbuf[NBLOCK]; 436250Sroot struct linkbuf *ihead; 446250Sroot struct stat stbuf; 451119Sbill 466250Sroot int rflag; 476250Sroot int xflag; 486250Sroot int vflag; 496250Sroot int tflag; 506250Sroot int cflag; 516250Sroot int mflag; 526250Sroot int fflag; 536250Sroot int oflag; 546250Sroot int pflag; 556250Sroot int wflag; 566250Sroot int hflag; 576250Sroot 586250Sroot int mt; 596250Sroot int term; 606250Sroot int chksum; 616250Sroot int recno; 626250Sroot int first; 636250Sroot int linkerrok; 641119Sbill int freemem = 1; 653457Swnj int nblock = NBLOCK; 666250Sroot int onintr(); 676250Sroot int onquit(); 686250Sroot int onhup(); 696250Sroot int onterm(); 701119Sbill 711119Sbill daddr_t low; 721119Sbill daddr_t high; 736250Sroot daddr_t bsrch(); 741119Sbill 751119Sbill FILE *tfile; 761119Sbill char tname[] = "/tmp/tarXXXXXX"; 771119Sbill char *usefile; 786250Sroot char magtape[] = "/dev/rmt8"; 791119Sbill char *malloc(); 806250Sroot char *sprintf(); 816250Sroot char *strcat(); 821119Sbill 831119Sbill main(argc, argv) 841119Sbill int argc; 851119Sbill char *argv[]; 861119Sbill { 871119Sbill char *cp; 881119Sbill 891119Sbill if (argc < 2) 901119Sbill usage(); 911119Sbill 921119Sbill tfile = NULL; 931119Sbill usefile = magtape; 941119Sbill argv[argc] = 0; 951119Sbill argv++; 961119Sbill for (cp = *argv++; *cp; cp++) 971119Sbill switch(*cp) { 986250Sroot 991119Sbill case 'f': 1001119Sbill usefile = *argv++; 1011119Sbill fflag++; 1021119Sbill break; 1036250Sroot 1041119Sbill case 'c': 1051119Sbill cflag++; 1061119Sbill rflag++; 1071119Sbill break; 1086250Sroot 1091119Sbill case 'o': 1101119Sbill oflag++; 1111119Sbill break; 1126250Sroot 1131119Sbill case 'p': 1141119Sbill pflag++; 1151119Sbill break; 1166250Sroot 1171119Sbill case 'u': 1181119Sbill mktemp(tname); 1191119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1206250Sroot fprintf(stderr, 1216250Sroot "Tar: cannot create temporary file (%s)\n", 1226250Sroot tname); 1231119Sbill done(1); 1241119Sbill } 1251119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1266250Sroot /*FALL THRU*/ 1276250Sroot 1281119Sbill case 'r': 1291119Sbill rflag++; 1301119Sbill break; 1316250Sroot 1321119Sbill case 'v': 1331119Sbill vflag++; 1341119Sbill break; 1356250Sroot 1361119Sbill case 'w': 1371119Sbill wflag++; 1381119Sbill break; 1396250Sroot 1401119Sbill case 'x': 1411119Sbill xflag++; 1421119Sbill break; 1436250Sroot 1441119Sbill case 't': 1451119Sbill tflag++; 1461119Sbill break; 1476250Sroot 1481119Sbill case 'm': 1491119Sbill mflag++; 1501119Sbill break; 1516250Sroot 1521119Sbill case '-': 1531119Sbill break; 1546250Sroot 1551119Sbill case '0': 1561119Sbill case '1': 1571119Sbill case '4': 1581119Sbill case '5': 1591119Sbill case '7': 1601119Sbill case '8': 1611119Sbill magtape[8] = *cp; 1621119Sbill usefile = magtape; 1631119Sbill break; 1646250Sroot 1651119Sbill case 'b': 1661119Sbill nblock = atoi(*argv++); 1671119Sbill if (nblock > NBLOCK || nblock <= 0) { 1686250Sroot fprintf(stderr, "Invalid blocksize. (Max %d)\n", 1696250Sroot NBLOCK); 1701119Sbill done(1); 1711119Sbill } 1721119Sbill break; 1736250Sroot 1741119Sbill case 'l': 1751119Sbill linkerrok++; 1761119Sbill break; 1776250Sroot 1786250Sroot case 'h': 1796250Sroot hflag++; 1806250Sroot break; 1816250Sroot 1821119Sbill default: 1831119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 1841119Sbill usage(); 1851119Sbill } 1861119Sbill 1876250Sroot if (!rflag && !xflag && !tflag) 1886250Sroot usage(); 1891119Sbill if (rflag) { 1906250Sroot if (cflag && tfile != NULL) 1911119Sbill usage(); 1921119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1931119Sbill signal(SIGINT, onintr); 1941119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 1951119Sbill signal(SIGHUP, onhup); 1961119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 1971119Sbill signal(SIGQUIT, onquit); 1986250Sroot #ifdef notdef 1991119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2001119Sbill signal(SIGTERM, onterm); 2016250Sroot #endif 2021119Sbill if (strcmp(usefile, "-") == 0) { 2031119Sbill if (cflag == 0) { 2046250Sroot fprintf(stderr, 2056250Sroot "Can only create standard output archives\n"); 2061119Sbill done(1); 2071119Sbill } 2081119Sbill mt = dup(1); 2091119Sbill nblock = 1; 2106250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2111119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2126250Sroot fprintf(stderr, 2136250Sroot "tar: cannot open %s\n", usefile); 2141119Sbill done(1); 2151119Sbill } 2161119Sbill } 2171119Sbill dorep(argv); 2186250Sroot done(0); 2191119Sbill } 2206250Sroot if (strcmp(usefile, "-") == 0) { 2216250Sroot mt = dup(0); 2226250Sroot nblock = 1; 2236250Sroot } else if ((mt = open(usefile, 0)) < 0) { 2246250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 2256250Sroot done(1); 2266250Sroot } 2276250Sroot if (xflag) 2281119Sbill doxtract(argv); 2296250Sroot else 2301119Sbill dotable(); 2311119Sbill done(0); 2321119Sbill } 2331119Sbill 2341119Sbill usage() 2351119Sbill { 2366250Sroot fprintf(stderr, 2376250Sroot "tar: usage tar -{txru}[cvfblmh] [tapefile] [blocksize] file1 file2...\n"); 2381119Sbill done(1); 2391119Sbill } 2401119Sbill 2411119Sbill dorep(argv) 2426250Sroot char *argv[]; 2431119Sbill { 2441119Sbill register char *cp, *cp2; 2451119Sbill char wdir[60]; 2461119Sbill 2471119Sbill if (!cflag) { 2481119Sbill getdir(); 2491119Sbill do { 2501119Sbill passtape(); 2511119Sbill if (term) 2521119Sbill done(0); 2531119Sbill getdir(); 2541119Sbill } while (!endtape()); 2551119Sbill if (tfile != NULL) { 2561119Sbill char buf[200]; 2571119Sbill 2586250Sroot sprintf(buf, 2596250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 2601119Sbill tname, tname, tname, tname, tname, tname); 2611119Sbill fflush(tfile); 2621119Sbill system(buf); 2631119Sbill freopen(tname, "r", tfile); 2641119Sbill fstat(fileno(tfile), &stbuf); 2651119Sbill high = stbuf.st_size; 2661119Sbill } 2671119Sbill } 2681119Sbill 2691119Sbill getwdir(wdir); 2701119Sbill while (*argv && ! term) { 2711119Sbill cp2 = *argv; 2721119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 2731119Sbill argv++; 2741119Sbill if (chdir(*argv) < 0) 2751119Sbill perror(*argv); 2761119Sbill else 2771119Sbill getwdir(wdir); 2781119Sbill argv++; 2791119Sbill continue; 2801119Sbill } 2811119Sbill for (cp = *argv; *cp; cp++) 2821119Sbill if (*cp == '/') 2831119Sbill cp2 = cp; 2841119Sbill if (cp2 != *argv) { 2851119Sbill *cp2 = '\0'; 2861119Sbill chdir(*argv); 2871119Sbill *cp2 = '/'; 2881119Sbill cp2++; 2891119Sbill } 2901119Sbill putfile(*argv++, cp2); 2911119Sbill chdir(wdir); 2921119Sbill } 2931119Sbill putempty(); 2941119Sbill putempty(); 2951119Sbill flushtape(); 2966250Sroot if (linkerrok == 0) 2976250Sroot return; 2986250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 2996250Sroot if (ihead->count == 0) 3006250Sroot continue; 3016250Sroot fprintf(stderr, "Missing links to %s\n", ihead->pathname); 3026250Sroot } 3031119Sbill } 3041119Sbill 3051119Sbill endtape() 3061119Sbill { 3076250Sroot if (dblock.dbuf.name[0] != '\0') 3086250Sroot return (0); 3096250Sroot backtape(); 3106250Sroot return (1); 3111119Sbill } 3121119Sbill 3131119Sbill getdir() 3141119Sbill { 3151119Sbill register struct stat *sp; 3161119Sbill int i; 3171119Sbill 3186250Sroot readtape((char *)&dblock); 3191119Sbill if (dblock.dbuf.name[0] == '\0') 3201119Sbill return; 3211119Sbill sp = &stbuf; 3221119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3231119Sbill sp->st_mode = i; 3241119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3251119Sbill sp->st_uid = i; 3261119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3271119Sbill sp->st_gid = i; 3281119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3291119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3301119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 3311119Sbill if (chksum != checksum()) { 3321119Sbill fprintf(stderr, "directory checksum error\n"); 3331119Sbill done(2); 3341119Sbill } 3351119Sbill if (tfile != NULL) 3361119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3371119Sbill } 3381119Sbill 3391119Sbill passtape() 3401119Sbill { 3411119Sbill long blocks; 3421119Sbill char buf[TBLOCK]; 3431119Sbill 3441119Sbill if (dblock.dbuf.linkflag == '1') 3451119Sbill return; 3461119Sbill blocks = stbuf.st_size; 3471119Sbill blocks += TBLOCK-1; 3481119Sbill blocks /= TBLOCK; 3491119Sbill 3501119Sbill while (blocks-- > 0) 3511119Sbill readtape(buf); 3521119Sbill } 3531119Sbill 3541119Sbill putfile(longname, shortname) 3556250Sroot char *longname; 3566250Sroot char *shortname; 3571119Sbill { 3581119Sbill int infile; 3591119Sbill long blocks; 3601119Sbill char buf[TBLOCK]; 3611119Sbill register char *cp, *cp2; 3625931Smckusic struct direct *dp; 3635931Smckusic DIR *dirp; 3641119Sbill int i, j; 3651119Sbill 3661119Sbill infile = open(shortname, 0); 3671119Sbill if (infile < 0) { 3681119Sbill fprintf(stderr, "tar: %s: cannot open file\n", longname); 3691119Sbill return; 3701119Sbill } 371*8150Smckusick lstat(shortname, &stbuf); 3721119Sbill if (tfile != NULL && checkupdate(longname) == 0) { 3731119Sbill close(infile); 3741119Sbill return; 3751119Sbill } 3761119Sbill if (checkw('r', longname) == 0) { 3771119Sbill close(infile); 3781119Sbill return; 3791119Sbill } 3801119Sbill 3811119Sbill if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3826250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 3836250Sroot ; 3841119Sbill *--cp = '/'; 3851119Sbill *++cp = 0 ; 3861119Sbill if (!oflag) { 3876250Sroot if ((cp - buf) >= NAMSIZ) { 3886250Sroot fprintf(stderr, "%s: file name too long\n", 3896250Sroot longname); 3906250Sroot close(infile); 3916250Sroot return; 3926250Sroot } 3936250Sroot stbuf.st_size = 0; 3946250Sroot tomodes(&stbuf); 3956250Sroot strcpy(dblock.dbuf.name,buf); 3966250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 3976250Sroot writetape((char *)&dblock); 3981119Sbill } 3991119Sbill chdir(shortname); 4005931Smckusic close(infile); 4015931Smckusic if ((dirp = opendir(".")) == NULL) { 4025931Smckusic fprintf(stderr, "%s: directory read error\n", longname); 4035931Smckusic return; 4045931Smckusic } 4055931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4065931Smckusic if (dp->d_ino == 0) 4071119Sbill continue; 4086250Sroot if (!strcmp(".", dp->d_name) || 4096250Sroot !strcmp("..", dp->d_name)) 4101119Sbill continue; 4115931Smckusic strcpy(cp, dp->d_name); 4125931Smckusic i = telldir(dirp); 4135931Smckusic closedir(dirp); 4141119Sbill putfile(buf, cp); 4155931Smckusic dirp = opendir("."); 4165931Smckusic seekdir(dirp, i); 4171119Sbill } 4185931Smckusic closedir(dirp); 4191119Sbill chdir(".."); 4201119Sbill return; 4211119Sbill } 4226250Sroot i = stbuf.st_mode & S_IFMT; 4236250Sroot if (i != S_IFREG && i != S_IFLNK) { 4246250Sroot fprintf(stderr, "tar: %s is not a file. Not dumped\n", 4256250Sroot longname); 4261119Sbill return; 4271119Sbill } 4281119Sbill tomodes(&stbuf); 4296250Sroot cp2 = longname; cp = dblock.dbuf.name; i = 0; 4306250Sroot while ((*cp++ = *cp2++) && i < NAMSIZ) 4316250Sroot i++; 4321119Sbill if (i >= NAMSIZ) { 4331119Sbill fprintf(stderr, "%s: file name too long\n", longname); 4341119Sbill close(infile); 4351119Sbill return; 4361119Sbill } 4376250Sroot if ((stbuf.st_mode & S_IFMT) == S_IFLNK) { 4386250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 4396250Sroot fprintf(stderr, "%s: symbolic link too long\n", 4406250Sroot longname); 4416250Sroot close(infile); 4426250Sroot return; 4436250Sroot } 4446250Sroot i = readlink(longname, dblock.dbuf.linkname, NAMSIZ - 1); 4456250Sroot if (i < 0) { 4466250Sroot perror("readlink"); 4476250Sroot close(infile); 4486250Sroot return; 4496250Sroot } 4506250Sroot dblock.dbuf.linkname[i] = '\0'; 4516250Sroot dblock.dbuf.linkflag = '2'; 4526250Sroot if (vflag) { 4536250Sroot fprintf(stderr, "a %s ", longname); 4546250Sroot fprintf(stderr, "symbolic link to %s\n", 4556250Sroot dblock.dbuf.linkname); 4566250Sroot } 4576250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 4586250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4596250Sroot writetape((char *)&dblock); 4606250Sroot close(infile); 4616250Sroot return; 4626250Sroot } 4631119Sbill if (stbuf.st_nlink > 1) { 4641119Sbill struct linkbuf *lp; 4651119Sbill int found = 0; 4661119Sbill 4676250Sroot for (lp = ihead; lp != NULL; lp = lp->nextp) 4686250Sroot if (lp->inum == stbuf.st_ino && 4696250Sroot lp->devnum == stbuf.st_dev) { 4701119Sbill found++; 4711119Sbill break; 4721119Sbill } 4731119Sbill if (found) { 4741119Sbill strcpy(dblock.dbuf.linkname, lp->pathname); 4751119Sbill dblock.dbuf.linkflag = '1'; 4761119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4771119Sbill writetape( (char *) &dblock); 4781119Sbill if (vflag) { 4791119Sbill fprintf(stderr, "a %s ", longname); 4801119Sbill fprintf(stderr, "link to %s\n", lp->pathname); 4811119Sbill } 4821119Sbill lp->count--; 4831119Sbill close(infile); 4841119Sbill return; 4851119Sbill } 4866250Sroot lp = (struct linkbuf *) malloc(sizeof(*lp)); 4876250Sroot if (lp == NULL) { 4886250Sroot if (freemem) { 4896250Sroot fprintf(stderr, 4906250Sroot "Out of memory. Link information lost\n"); 4916250Sroot freemem = 0; 4921119Sbill } 4936250Sroot } else { 4946250Sroot lp->nextp = ihead; 4956250Sroot ihead = lp; 4966250Sroot lp->inum = stbuf.st_ino; 4976250Sroot lp->devnum = stbuf.st_dev; 4986250Sroot lp->count = stbuf.st_nlink - 1; 4996250Sroot strcpy(lp->pathname, longname); 5001119Sbill } 5011119Sbill } 5021119Sbill blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 5031119Sbill if (vflag) { 5041119Sbill fprintf(stderr, "a %s ", longname); 5051119Sbill fprintf(stderr, "%ld blocks\n", blocks); 5061119Sbill } 5071119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5086250Sroot writetape((char *)&dblock); 5091119Sbill 5101119Sbill while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 5111119Sbill writetape(buf); 5121119Sbill blocks--; 5131119Sbill } 5141119Sbill close(infile); 5151119Sbill if (blocks != 0 || i != 0) 5161119Sbill fprintf(stderr, "%s: file changed size\n", longname); 5176250Sroot while (--blocks >= 0) 5181119Sbill putempty(); 5191119Sbill } 5201119Sbill 5211119Sbill doxtract(argv) 5226250Sroot char *argv[]; 5231119Sbill { 5241119Sbill long blocks, bytes; 5251119Sbill char buf[TBLOCK]; 5261119Sbill char **cp; 5271119Sbill int ofile; 5281119Sbill 5291119Sbill for (;;) { 5301119Sbill getdir(); 5311119Sbill if (endtape()) 5321119Sbill break; 5331119Sbill if (*argv == 0) 5341119Sbill goto gotit; 5351119Sbill for (cp = argv; *cp; cp++) 5361119Sbill if (prefix(*cp, dblock.dbuf.name)) 5371119Sbill goto gotit; 5381119Sbill passtape(); 5391119Sbill continue; 5401119Sbill 5411119Sbill gotit: 5421119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 5431119Sbill passtape(); 5441119Sbill continue; 5451119Sbill } 5466250Sroot if (checkdir(dblock.dbuf.name)) 5476250Sroot continue; 5486250Sroot if (dblock.dbuf.linkflag == '2') { 5496250Sroot unlink(dblock.dbuf.name); 5506250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 5516250Sroot fprintf(stderr, "%s: symbolic link failed\n", 5526250Sroot dblock.dbuf.name); 5536250Sroot continue; 5546250Sroot } 5556250Sroot if (vflag) 5566250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 5576250Sroot dblock.dbuf.name, dblock.dbuf.linkname); 558*8150Smckusick #ifdef notdef 559*8150Smckusick /* ignore alien orders */ 5606250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 5616250Sroot if (mflag == 0) { 5626250Sroot time_t timep[2]; 5631119Sbill 5646250Sroot timep[0] = time(0); 5656250Sroot timep[1] = stbuf.st_mtime; 5666250Sroot utime(dblock.dbuf.name, timep); 5676250Sroot } 5686250Sroot if (pflag) 5696250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 570*8150Smckusick #endif 5711119Sbill continue; 5726250Sroot } 5731119Sbill if (dblock.dbuf.linkflag == '1') { 5741119Sbill unlink(dblock.dbuf.name); 5751119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 5766250Sroot fprintf(stderr, "%s: cannot link\n", 5776250Sroot dblock.dbuf.name); 5781119Sbill continue; 5791119Sbill } 5801119Sbill if (vflag) 5813457Swnj fprintf(stderr, "%s linked to %s\n", 5823457Swnj dblock.dbuf.name, dblock.dbuf.linkname); 5831119Sbill continue; 5841119Sbill } 5856250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 5866250Sroot fprintf(stderr, "tar: %s - cannot create\n", 5876250Sroot dblock.dbuf.name); 5881119Sbill passtape(); 5891119Sbill continue; 5901119Sbill } 5911926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 5921119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 5931119Sbill if (vflag) 5943457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 5953457Swnj dblock.dbuf.name, bytes, blocks); 5966250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 5971119Sbill readtape(buf); 5981119Sbill if (bytes > TBLOCK) { 5991119Sbill if (write(ofile, buf, TBLOCK) < 0) { 6006250Sroot fprintf(stderr, 6016250Sroot "tar: %s: HELP - extract write error\n", 6026250Sroot dblock.dbuf.name); 6031119Sbill done(2); 6041119Sbill } 6056250Sroot continue; 6066250Sroot } 6076250Sroot if (write(ofile, buf, (int) bytes) < 0) { 6086250Sroot fprintf(stderr, 6096250Sroot "tar: %s: HELP - extract write error\n", 6106250Sroot dblock.dbuf.name); 6116250Sroot done(2); 6126250Sroot } 6131119Sbill } 6141119Sbill close(ofile); 6151119Sbill if (mflag == 0) { 6161119Sbill time_t timep[2]; 6171119Sbill 6181119Sbill timep[0] = time(NULL); 6191119Sbill timep[1] = stbuf.st_mtime; 6201119Sbill utime(dblock.dbuf.name, timep); 6211119Sbill } 6221926Swnj if (pflag) 6236250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6241119Sbill } 6251119Sbill } 6261119Sbill 6271119Sbill dotable() 6281119Sbill { 6291119Sbill for (;;) { 6301119Sbill getdir(); 6311119Sbill if (endtape()) 6321119Sbill break; 6331119Sbill if (vflag) 6341119Sbill longt(&stbuf); 6351119Sbill printf("%s", dblock.dbuf.name); 6361119Sbill if (dblock.dbuf.linkflag == '1') 6371119Sbill printf(" linked to %s", dblock.dbuf.linkname); 6386250Sroot if (dblock.dbuf.linkflag == '2') 6396250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 6401119Sbill printf("\n"); 6411119Sbill passtape(); 6421119Sbill } 6431119Sbill } 6441119Sbill 6451119Sbill putempty() 6461119Sbill { 6471119Sbill char buf[TBLOCK]; 6481119Sbill char *cp; 6491119Sbill 6501119Sbill for (cp = buf; cp < &buf[TBLOCK]; ) 6511119Sbill *cp++ = '\0'; 6521119Sbill writetape(buf); 6531119Sbill } 6541119Sbill 6551119Sbill longt(st) 6566250Sroot register struct stat *st; 6571119Sbill { 6581119Sbill register char *cp; 6591119Sbill char *ctime(); 6601119Sbill 6611119Sbill pmode(st); 6621119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 6631119Sbill printf("%7D", st->st_size); 6641119Sbill cp = ctime(&st->st_mtime); 6651119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 6661119Sbill } 6671119Sbill 6681119Sbill #define SUID 04000 6691119Sbill #define SGID 02000 6701119Sbill #define ROWN 0400 6711119Sbill #define WOWN 0200 6721119Sbill #define XOWN 0100 6731119Sbill #define RGRP 040 6741119Sbill #define WGRP 020 6751119Sbill #define XGRP 010 6761119Sbill #define ROTH 04 6771119Sbill #define WOTH 02 6781119Sbill #define XOTH 01 6791119Sbill #define STXT 01000 6801119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 6811119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 6821119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 6831119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 6841119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 6851119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 6861119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 6871119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 6881119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 6891119Sbill 6901119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 6911119Sbill 6921119Sbill pmode(st) 6936250Sroot register struct stat *st; 6941119Sbill { 6951119Sbill register int **mp; 6961119Sbill 6971119Sbill for (mp = &m[0]; mp < &m[9];) 6981119Sbill select(*mp++, st); 6991119Sbill } 7001119Sbill 7011119Sbill select(pairp, st) 7026250Sroot int *pairp; 7036250Sroot struct stat *st; 7041119Sbill { 7051119Sbill register int n, *ap; 7061119Sbill 7071119Sbill ap = pairp; 7081119Sbill n = *ap++; 7091119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 7101119Sbill ap++; 7111119Sbill printf("%c", *ap); 7121119Sbill } 7131119Sbill 7141119Sbill checkdir(name) 7156250Sroot register char *name; 7161119Sbill { 7171119Sbill register char *cp; 7186250Sroot 7191119Sbill for (cp = name; *cp; cp++) { 7206250Sroot if (*cp != '/') 7216250Sroot continue; 7226250Sroot *cp = '\0'; 7236250Sroot if (access(name, 1) < 0) { 7246250Sroot register int pid, rp; 7256250Sroot int i; 7261119Sbill 7276250Sroot if ((pid = fork()) == 0) { 7286250Sroot execl("/bin/mkdir", "mkdir", name, 0); 7296250Sroot execl("/usr/bin/mkdir", "mkdir", name, 0); 7306250Sroot fprintf(stderr, "tar: cannot find mkdir!\n"); 7316250Sroot done(0); 7321119Sbill } 7336250Sroot while ((rp = wait(&i)) >= 0 && rp != pid) 7346250Sroot ; 7356250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 7366250Sroot if (pflag) 7376250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 0777); 7381119Sbill } 7396250Sroot *cp = '/'; 7401119Sbill } 7416250Sroot return (cp[-1]=='/'); 7421119Sbill } 7431119Sbill 7441119Sbill onintr() 7451119Sbill { 7461119Sbill signal(SIGINT, SIG_IGN); 7471119Sbill term++; 7481119Sbill } 7491119Sbill 7501119Sbill onquit() 7511119Sbill { 7521119Sbill signal(SIGQUIT, SIG_IGN); 7531119Sbill term++; 7541119Sbill } 7551119Sbill 7561119Sbill onhup() 7571119Sbill { 7581119Sbill signal(SIGHUP, SIG_IGN); 7591119Sbill term++; 7601119Sbill } 7611119Sbill 7621119Sbill onterm() 7631119Sbill { 7641119Sbill signal(SIGTERM, SIG_IGN); 7651119Sbill term++; 7661119Sbill } 7671119Sbill 7681119Sbill tomodes(sp) 7691119Sbill register struct stat *sp; 7701119Sbill { 7711119Sbill register char *cp; 7721119Sbill 7731119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 7741119Sbill *cp = '\0'; 7751119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 7761119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 7771119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 7781119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 7791119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 7801119Sbill } 7811119Sbill 7821119Sbill checksum() 7831119Sbill { 7841119Sbill register i; 7851119Sbill register char *cp; 7861119Sbill 7876250Sroot for (cp = dblock.dbuf.chksum; 7886250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 7891119Sbill *cp = ' '; 7901119Sbill i = 0; 7911119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 7921119Sbill i += *cp; 7936250Sroot return (i); 7941119Sbill } 7951119Sbill 7961119Sbill checkw(c, name) 7976250Sroot char *name; 7981119Sbill { 7996250Sroot if (!wflag) 8006250Sroot return (1); 8016250Sroot printf("%c ", c); 8026250Sroot if (vflag) 8036250Sroot longt(&stbuf); 8046250Sroot printf("%s: ", name); 8056250Sroot return (response() == 'y'); 8061119Sbill } 8071119Sbill 8081119Sbill response() 8091119Sbill { 8101119Sbill char c; 8111119Sbill 8121119Sbill c = getchar(); 8131119Sbill if (c != '\n') 8146250Sroot while (getchar() != '\n') 8156250Sroot ; 8166250Sroot else 8176250Sroot c = 'n'; 8186250Sroot return (c); 8191119Sbill } 8201119Sbill 8211119Sbill checkupdate(arg) 8226250Sroot char *arg; 8231119Sbill { 8241119Sbill char name[100]; 8256250Sroot long mtime; 8261119Sbill daddr_t seekp; 8271119Sbill daddr_t lookup(); 8281119Sbill 8291119Sbill rewind(tfile); 8301119Sbill for (;;) { 8311119Sbill if ((seekp = lookup(arg)) < 0) 8326250Sroot return (1); 8331119Sbill fseek(tfile, seekp, 0); 8341119Sbill fscanf(tfile, "%s %lo", name, &mtime); 8356250Sroot return (stbuf.st_mtime > mtime); 8361119Sbill } 8371119Sbill } 8381119Sbill 8391119Sbill done(n) 8401119Sbill { 8411119Sbill unlink(tname); 8421119Sbill exit(n); 8431119Sbill } 8441119Sbill 8451119Sbill prefix(s1, s2) 8466250Sroot register char *s1, *s2; 8471119Sbill { 8481119Sbill while (*s1) 8491119Sbill if (*s1++ != *s2++) 8506250Sroot return (0); 8511119Sbill if (*s2) 8526250Sroot return (*s2 == '/'); 8536250Sroot return (1); 8541119Sbill } 8551119Sbill 8561119Sbill getwdir(s) 8576250Sroot char *s; 8581119Sbill { 8596250Sroot int i, pipdes[2]; 8601119Sbill 8611119Sbill pipe(pipdes); 8621119Sbill if ((i = fork()) == 0) { 8631119Sbill close(1); 8641119Sbill dup(pipdes[1]); 8651119Sbill execl("/bin/pwd", "pwd", 0); 8661119Sbill execl("/usr/bin/pwd", "pwd", 0); 8671119Sbill fprintf(stderr, "pwd failed!\n"); 8681119Sbill printf("/\n"); 8691119Sbill exit(1); 8701119Sbill } 8711119Sbill while (wait((int *)NULL) != -1) 8721119Sbill ; 8731119Sbill read(pipdes[0], s, 50); 8746250Sroot while (*s != '\n') 8751119Sbill s++; 8761119Sbill *s = '\0'; 8771119Sbill close(pipdes[0]); 8781119Sbill close(pipdes[1]); 8791119Sbill } 8801119Sbill 8811119Sbill #define N 200 8821119Sbill int njab; 8836250Sroot 8841119Sbill daddr_t 8851119Sbill lookup(s) 8866250Sroot char *s; 8871119Sbill { 8881119Sbill register i; 8891119Sbill daddr_t a; 8901119Sbill 8911119Sbill for(i=0; s[i]; i++) 8926250Sroot if (s[i] == ' ') 8931119Sbill break; 8941119Sbill a = bsrch(s, i, low, high); 8956250Sroot return (a); 8961119Sbill } 8971119Sbill 8981119Sbill daddr_t 8991119Sbill bsrch(s, n, l, h) 9006250Sroot daddr_t l, h; 9016250Sroot char *s; 9021119Sbill { 9031119Sbill register i, j; 9041119Sbill char b[N]; 9051119Sbill daddr_t m, m1; 9061119Sbill 9071119Sbill njab = 0; 9081119Sbill 9091119Sbill loop: 9106250Sroot if (l >= h) 9116250Sroot return (-1L); 9121119Sbill m = l + (h-l)/2 - N/2; 9136250Sroot if (m < l) 9141119Sbill m = l; 9151119Sbill fseek(tfile, m, 0); 9161119Sbill fread(b, 1, N, tfile); 9171119Sbill njab++; 9181119Sbill for(i=0; i<N; i++) { 9196250Sroot if (b[i] == '\n') 9201119Sbill break; 9211119Sbill m++; 9221119Sbill } 9236250Sroot if (m >= h) 9246250Sroot return (-1L); 9251119Sbill m1 = m; 9261119Sbill j = i; 9271119Sbill for(i++; i<N; i++) { 9281119Sbill m1++; 9296250Sroot if (b[i] == '\n') 9301119Sbill break; 9311119Sbill } 9321119Sbill i = cmp(b+j, s, n); 9336250Sroot if (i < 0) { 9341119Sbill h = m; 9351119Sbill goto loop; 9361119Sbill } 9376250Sroot if (i > 0) { 9381119Sbill l = m1; 9391119Sbill goto loop; 9401119Sbill } 9416250Sroot return (m); 9421119Sbill } 9431119Sbill 9441119Sbill cmp(b, s, n) 9456250Sroot char *b, *s; 9461119Sbill { 9471119Sbill register i; 9481119Sbill 9496250Sroot if (b[0] != '\n') 9501119Sbill exit(2); 9511119Sbill for(i=0; i<n; i++) { 9526250Sroot if (b[i+1] > s[i]) 9536250Sroot return (-1); 9546250Sroot if (b[i+1] < s[i]) 9556250Sroot return (1); 9561119Sbill } 9576250Sroot return (b[i+1] == ' '? 0 : -1); 9581119Sbill } 9591119Sbill 9601119Sbill readtape(buffer) 9616250Sroot char *buffer; 9621119Sbill { 9633457Swnj register int i; 9641119Sbill 9651119Sbill if (recno >= nblock || first == 0) { 9663457Swnj if ((i = read(mt, tbuf, TBLOCK*nblock)) < 0) { 9671119Sbill fprintf(stderr, "Tar: tape read error\n"); 9681119Sbill done(3); 9691119Sbill } 9701119Sbill if (first == 0) { 9711119Sbill if ((i % TBLOCK) != 0) { 9721119Sbill fprintf(stderr, "Tar: tape blocksize error\n"); 9731119Sbill done(3); 9741119Sbill } 9751119Sbill i /= TBLOCK; 9763457Swnj if (i != nblock) { 9771119Sbill fprintf(stderr, "Tar: blocksize = %d\n", i); 9781119Sbill nblock = i; 9791119Sbill } 9801119Sbill } 9811119Sbill recno = 0; 9821119Sbill } 9831119Sbill first = 1; 9841119Sbill copy(buffer, &tbuf[recno++]); 9856250Sroot return (TBLOCK); 9861119Sbill } 9871119Sbill 9881119Sbill writetape(buffer) 9896250Sroot char *buffer; 9901119Sbill { 9911119Sbill first = 1; 9921119Sbill if (recno >= nblock) { 9931119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 9941119Sbill fprintf(stderr, "Tar: tape write error\n"); 9951119Sbill done(2); 9961119Sbill } 9971119Sbill recno = 0; 9981119Sbill } 9991119Sbill copy(&tbuf[recno++], buffer); 10001119Sbill if (recno >= nblock) { 10011119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 10021119Sbill fprintf(stderr, "Tar: tape write error\n"); 10031119Sbill done(2); 10041119Sbill } 10051119Sbill recno = 0; 10061119Sbill } 10076250Sroot return (TBLOCK); 10081119Sbill } 10091119Sbill 10101119Sbill backtape() 10111119Sbill { 10123457Swnj static int mtdev = 1; 10133457Swnj static struct mtop mtop = {MTBSR, 1}; 10143457Swnj struct mtget mtget; 10153457Swnj 10163457Swnj if (mtdev == 1) 10173457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 10183457Swnj if (mtdev == 0) { 10193457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 10203457Swnj fprintf(stderr, "Tar: tape backspace error\n"); 10211119Sbill done(4); 10221119Sbill } 10233457Swnj } else 10243457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 10253457Swnj recno--; 10261119Sbill } 10271119Sbill 10281119Sbill flushtape() 10291119Sbill { 10301119Sbill write(mt, tbuf, TBLOCK*nblock); 10311119Sbill } 10321119Sbill 10331119Sbill copy(to, from) 10346250Sroot register char *to, *from; 10351119Sbill { 10361119Sbill register i; 10371119Sbill 10381119Sbill i = TBLOCK; 10391119Sbill do { 10401119Sbill *to++ = *from++; 10411119Sbill } while (--i); 10421119Sbill } 1043