1*10165Ssam static char *sccsid = "@(#)tar.c 4.14 (Berkeley) 83/01/05"; 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> 108150Smckusick #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; 578737Smckusick int Bflag; 586250Sroot 596250Sroot int mt; 606250Sroot int term; 616250Sroot int chksum; 626250Sroot int recno; 636250Sroot int first; 646250Sroot int linkerrok; 651119Sbill int freemem = 1; 663457Swnj int nblock = NBLOCK; 676250Sroot int onintr(); 686250Sroot int onquit(); 696250Sroot int onhup(); 706250Sroot int onterm(); 711119Sbill 721119Sbill daddr_t low; 731119Sbill daddr_t high; 746250Sroot daddr_t bsrch(); 751119Sbill 761119Sbill FILE *tfile; 771119Sbill char tname[] = "/tmp/tarXXXXXX"; 781119Sbill char *usefile; 796250Sroot char magtape[] = "/dev/rmt8"; 801119Sbill char *malloc(); 816250Sroot char *sprintf(); 826250Sroot char *strcat(); 83*10165Ssam char *getcwd(); 849844Ssam char *getwd(); 851119Sbill 861119Sbill main(argc, argv) 871119Sbill int argc; 881119Sbill char *argv[]; 891119Sbill { 901119Sbill char *cp; 911119Sbill 921119Sbill if (argc < 2) 931119Sbill usage(); 941119Sbill 951119Sbill tfile = NULL; 961119Sbill usefile = magtape; 971119Sbill argv[argc] = 0; 981119Sbill argv++; 991119Sbill for (cp = *argv++; *cp; cp++) 1001119Sbill switch(*cp) { 1016250Sroot 1021119Sbill case 'f': 1031119Sbill usefile = *argv++; 1041119Sbill fflag++; 1051119Sbill break; 1066250Sroot 1071119Sbill case 'c': 1081119Sbill cflag++; 1091119Sbill rflag++; 1101119Sbill break; 1116250Sroot 1121119Sbill case 'o': 1131119Sbill oflag++; 1141119Sbill break; 1156250Sroot 1161119Sbill case 'p': 1171119Sbill pflag++; 1181119Sbill break; 1196250Sroot 1201119Sbill case 'u': 1211119Sbill mktemp(tname); 1221119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1236250Sroot fprintf(stderr, 1246250Sroot "Tar: cannot create temporary file (%s)\n", 1256250Sroot tname); 1261119Sbill done(1); 1271119Sbill } 1281119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1296250Sroot /*FALL THRU*/ 1306250Sroot 1311119Sbill case 'r': 1321119Sbill rflag++; 1331119Sbill break; 1346250Sroot 1351119Sbill case 'v': 1361119Sbill vflag++; 1371119Sbill break; 1386250Sroot 1391119Sbill case 'w': 1401119Sbill wflag++; 1411119Sbill break; 1426250Sroot 1431119Sbill case 'x': 1441119Sbill xflag++; 1451119Sbill break; 1466250Sroot 1471119Sbill case 't': 1481119Sbill tflag++; 1491119Sbill break; 1506250Sroot 1511119Sbill case 'm': 1521119Sbill mflag++; 1531119Sbill break; 1546250Sroot 1551119Sbill case '-': 1561119Sbill break; 1576250Sroot 1581119Sbill case '0': 1591119Sbill case '1': 1601119Sbill case '4': 1611119Sbill case '5': 1621119Sbill case '7': 1631119Sbill case '8': 1641119Sbill magtape[8] = *cp; 1651119Sbill usefile = magtape; 1661119Sbill break; 1676250Sroot 1681119Sbill case 'b': 1691119Sbill nblock = atoi(*argv++); 1701119Sbill if (nblock > NBLOCK || nblock <= 0) { 1716250Sroot fprintf(stderr, "Invalid blocksize. (Max %d)\n", 1726250Sroot NBLOCK); 1731119Sbill done(1); 1741119Sbill } 1751119Sbill break; 1766250Sroot 1771119Sbill case 'l': 1781119Sbill linkerrok++; 1791119Sbill break; 1806250Sroot 1816250Sroot case 'h': 1826250Sroot hflag++; 1836250Sroot break; 1846250Sroot 1858737Smckusick case 'B': 1868737Smckusick Bflag++; 1878737Smckusick break; 1888737Smckusick 1891119Sbill default: 1901119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 1911119Sbill usage(); 1921119Sbill } 1931119Sbill 1946250Sroot if (!rflag && !xflag && !tflag) 1956250Sroot usage(); 1961119Sbill if (rflag) { 1976250Sroot if (cflag && tfile != NULL) 1981119Sbill usage(); 1991119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2001119Sbill signal(SIGINT, onintr); 2011119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 2021119Sbill signal(SIGHUP, onhup); 2031119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2041119Sbill signal(SIGQUIT, onquit); 2056250Sroot #ifdef notdef 2061119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2071119Sbill signal(SIGTERM, onterm); 2086250Sroot #endif 2091119Sbill if (strcmp(usefile, "-") == 0) { 2101119Sbill if (cflag == 0) { 2116250Sroot fprintf(stderr, 2126250Sroot "Can only create standard output archives\n"); 2131119Sbill done(1); 2141119Sbill } 2151119Sbill mt = dup(1); 2161119Sbill nblock = 1; 2176250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2181119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2196250Sroot fprintf(stderr, 2206250Sroot "tar: cannot open %s\n", usefile); 2211119Sbill done(1); 2221119Sbill } 2231119Sbill } 2241119Sbill dorep(argv); 2256250Sroot done(0); 2261119Sbill } 2276250Sroot if (strcmp(usefile, "-") == 0) { 2286250Sroot mt = dup(0); 2296250Sroot nblock = 1; 2306250Sroot } else if ((mt = open(usefile, 0)) < 0) { 2316250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 2326250Sroot done(1); 2336250Sroot } 2346250Sroot if (xflag) 2351119Sbill doxtract(argv); 2366250Sroot else 2371119Sbill dotable(); 2381119Sbill done(0); 2391119Sbill } 2401119Sbill 2411119Sbill usage() 2421119Sbill { 2436250Sroot fprintf(stderr, 2448737Smckusick "tar: usage tar -{txruB}[cvfblmh] [tapefile] [blocksize] file1 file2...\n"); 2451119Sbill done(1); 2461119Sbill } 2471119Sbill 2481119Sbill dorep(argv) 2496250Sroot char *argv[]; 2501119Sbill { 2511119Sbill register char *cp, *cp2; 2529601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 2531119Sbill 2541119Sbill if (!cflag) { 2551119Sbill getdir(); 2561119Sbill do { 2571119Sbill passtape(); 2581119Sbill if (term) 2591119Sbill done(0); 2601119Sbill getdir(); 2611119Sbill } while (!endtape()); 2621119Sbill if (tfile != NULL) { 2631119Sbill char buf[200]; 2641119Sbill 2656250Sroot sprintf(buf, 2666250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 2671119Sbill tname, tname, tname, tname, tname, tname); 2681119Sbill fflush(tfile); 2691119Sbill system(buf); 2701119Sbill freopen(tname, "r", tfile); 2711119Sbill fstat(fileno(tfile), &stbuf); 2721119Sbill high = stbuf.st_size; 2731119Sbill } 2741119Sbill } 2751119Sbill 276*10165Ssam (void) getcwd(wdir); 2771119Sbill while (*argv && ! term) { 2781119Sbill cp2 = *argv; 2791119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 2801119Sbill argv++; 2811119Sbill if (chdir(*argv) < 0) 2821119Sbill perror(*argv); 2831119Sbill else 284*10165Ssam (void) getcwd(wdir); 2851119Sbill argv++; 2861119Sbill continue; 2871119Sbill } 2889601Ssam parent = wdir; 2891119Sbill for (cp = *argv; *cp; cp++) 2901119Sbill if (*cp == '/') 2911119Sbill cp2 = cp; 2921119Sbill if (cp2 != *argv) { 2931119Sbill *cp2 = '\0'; 2949601Ssam if (chdir(*argv) < 0) { 2959601Ssam perror(*argv); 2969601Ssam continue; 2979601Ssam } 298*10165Ssam parent = getcwd(tempdir); 2991119Sbill *cp2 = '/'; 3001119Sbill cp2++; 3011119Sbill } 3029601Ssam putfile(*argv++, cp2, parent); 3031119Sbill chdir(wdir); 3041119Sbill } 3051119Sbill putempty(); 3061119Sbill putempty(); 3071119Sbill flushtape(); 3086250Sroot if (linkerrok == 0) 3096250Sroot return; 3106250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3116250Sroot if (ihead->count == 0) 3126250Sroot continue; 3136250Sroot fprintf(stderr, "Missing links to %s\n", ihead->pathname); 3146250Sroot } 3151119Sbill } 3161119Sbill 3171119Sbill endtape() 3181119Sbill { 3196250Sroot if (dblock.dbuf.name[0] != '\0') 3206250Sroot return (0); 3216250Sroot backtape(); 3226250Sroot return (1); 3231119Sbill } 3241119Sbill 3251119Sbill getdir() 3261119Sbill { 3271119Sbill register struct stat *sp; 3281119Sbill int i; 3291119Sbill 3306250Sroot readtape((char *)&dblock); 3311119Sbill if (dblock.dbuf.name[0] == '\0') 3321119Sbill return; 3331119Sbill sp = &stbuf; 3341119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3351119Sbill sp->st_mode = i; 3361119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3371119Sbill sp->st_uid = i; 3381119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3391119Sbill sp->st_gid = i; 3401119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3411119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3421119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 3431119Sbill if (chksum != checksum()) { 3441119Sbill fprintf(stderr, "directory checksum error\n"); 3451119Sbill done(2); 3461119Sbill } 3471119Sbill if (tfile != NULL) 3481119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3491119Sbill } 3501119Sbill 3511119Sbill passtape() 3521119Sbill { 3531119Sbill long blocks; 3541119Sbill char buf[TBLOCK]; 3551119Sbill 3561119Sbill if (dblock.dbuf.linkflag == '1') 3571119Sbill return; 3581119Sbill blocks = stbuf.st_size; 3591119Sbill blocks += TBLOCK-1; 3601119Sbill blocks /= TBLOCK; 3611119Sbill 3621119Sbill while (blocks-- > 0) 3631119Sbill readtape(buf); 3641119Sbill } 3651119Sbill 3669601Ssam putfile(longname, shortname, parent) 3676250Sroot char *longname; 3686250Sroot char *shortname; 3699601Ssam char *parent; 3701119Sbill { 3711119Sbill int infile; 3721119Sbill long blocks; 3731119Sbill char buf[TBLOCK]; 3741119Sbill register char *cp, *cp2; 3755931Smckusic struct direct *dp; 3765931Smckusic DIR *dirp; 3771119Sbill int i, j; 3789601Ssam char newparent[NAMSIZ+64]; 3791119Sbill 3801119Sbill infile = open(shortname, 0); 3811119Sbill if (infile < 0) { 3821119Sbill fprintf(stderr, "tar: %s: cannot open file\n", longname); 3831119Sbill return; 3841119Sbill } 3859601Ssam if (!hflag) 3869601Ssam lstat(shortname, &stbuf); 3879601Ssam else if (stat(shortname, &stbuf) < 0) { 3889601Ssam perror(longname); 3899601Ssam close(infile); 3909601Ssam return; 3919601Ssam } 3921119Sbill if (tfile != NULL && checkupdate(longname) == 0) { 3931119Sbill close(infile); 3941119Sbill return; 3951119Sbill } 3961119Sbill if (checkw('r', longname) == 0) { 3971119Sbill close(infile); 3981119Sbill return; 3991119Sbill } 4001119Sbill 4011119Sbill if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 4026250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4036250Sroot ; 4041119Sbill *--cp = '/'; 4051119Sbill *++cp = 0 ; 4061119Sbill if (!oflag) { 4076250Sroot if ((cp - buf) >= NAMSIZ) { 4086250Sroot fprintf(stderr, "%s: file name too long\n", 4096250Sroot longname); 4106250Sroot close(infile); 4116250Sroot return; 4126250Sroot } 4136250Sroot stbuf.st_size = 0; 4146250Sroot tomodes(&stbuf); 4156250Sroot strcpy(dblock.dbuf.name,buf); 4166250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4176250Sroot writetape((char *)&dblock); 4181119Sbill } 4199601Ssam sprintf(newparent, "%s/%s", parent, shortname); 4201119Sbill chdir(shortname); 4215931Smckusic close(infile); 4225931Smckusic if ((dirp = opendir(".")) == NULL) { 4235931Smckusic fprintf(stderr, "%s: directory read error\n", longname); 4249601Ssam chdir(parent); 4255931Smckusic return; 4265931Smckusic } 4275931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4285931Smckusic if (dp->d_ino == 0) 4291119Sbill continue; 4306250Sroot if (!strcmp(".", dp->d_name) || 4316250Sroot !strcmp("..", dp->d_name)) 4321119Sbill continue; 4335931Smckusic strcpy(cp, dp->d_name); 4345931Smckusic i = telldir(dirp); 4355931Smckusic closedir(dirp); 4369601Ssam putfile(buf, cp, newparent); 4375931Smckusic dirp = opendir("."); 4385931Smckusic seekdir(dirp, i); 4391119Sbill } 4405931Smckusic closedir(dirp); 4419601Ssam chdir(parent); 4421119Sbill return; 4431119Sbill } 4446250Sroot i = stbuf.st_mode & S_IFMT; 4456250Sroot if (i != S_IFREG && i != S_IFLNK) { 4466250Sroot fprintf(stderr, "tar: %s is not a file. Not dumped\n", 4476250Sroot longname); 4481119Sbill return; 4491119Sbill } 4501119Sbill tomodes(&stbuf); 4516250Sroot cp2 = longname; cp = dblock.dbuf.name; i = 0; 4526250Sroot while ((*cp++ = *cp2++) && i < NAMSIZ) 4536250Sroot i++; 4541119Sbill if (i >= NAMSIZ) { 4551119Sbill fprintf(stderr, "%s: file name too long\n", longname); 4561119Sbill close(infile); 4571119Sbill return; 4581119Sbill } 4596250Sroot if ((stbuf.st_mode & S_IFMT) == S_IFLNK) { 4606250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 4616250Sroot fprintf(stderr, "%s: symbolic link too long\n", 4626250Sroot longname); 4636250Sroot close(infile); 4646250Sroot return; 4656250Sroot } 4669601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 4676250Sroot if (i < 0) { 4689601Ssam perror(longname); 4696250Sroot close(infile); 4706250Sroot return; 4716250Sroot } 4726250Sroot dblock.dbuf.linkname[i] = '\0'; 4736250Sroot dblock.dbuf.linkflag = '2'; 4746250Sroot if (vflag) { 4756250Sroot fprintf(stderr, "a %s ", longname); 4766250Sroot fprintf(stderr, "symbolic link to %s\n", 4776250Sroot dblock.dbuf.linkname); 4786250Sroot } 4796250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 4806250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4816250Sroot writetape((char *)&dblock); 4826250Sroot close(infile); 4836250Sroot return; 4846250Sroot } 4851119Sbill if (stbuf.st_nlink > 1) { 4861119Sbill struct linkbuf *lp; 4871119Sbill int found = 0; 4881119Sbill 4896250Sroot for (lp = ihead; lp != NULL; lp = lp->nextp) 4906250Sroot if (lp->inum == stbuf.st_ino && 4916250Sroot lp->devnum == stbuf.st_dev) { 4921119Sbill found++; 4931119Sbill break; 4941119Sbill } 4951119Sbill if (found) { 4961119Sbill strcpy(dblock.dbuf.linkname, lp->pathname); 4971119Sbill dblock.dbuf.linkflag = '1'; 4981119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4991119Sbill writetape( (char *) &dblock); 5001119Sbill if (vflag) { 5011119Sbill fprintf(stderr, "a %s ", longname); 5021119Sbill fprintf(stderr, "link to %s\n", lp->pathname); 5031119Sbill } 5041119Sbill lp->count--; 5051119Sbill close(infile); 5061119Sbill return; 5071119Sbill } 5086250Sroot lp = (struct linkbuf *) malloc(sizeof(*lp)); 5096250Sroot if (lp == NULL) { 5106250Sroot if (freemem) { 5116250Sroot fprintf(stderr, 5126250Sroot "Out of memory. Link information lost\n"); 5136250Sroot freemem = 0; 5141119Sbill } 5156250Sroot } else { 5166250Sroot lp->nextp = ihead; 5176250Sroot ihead = lp; 5186250Sroot lp->inum = stbuf.st_ino; 5196250Sroot lp->devnum = stbuf.st_dev; 5206250Sroot lp->count = stbuf.st_nlink - 1; 5216250Sroot strcpy(lp->pathname, longname); 5221119Sbill } 5231119Sbill } 5241119Sbill blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 5251119Sbill if (vflag) { 5261119Sbill fprintf(stderr, "a %s ", longname); 5271119Sbill fprintf(stderr, "%ld blocks\n", blocks); 5281119Sbill } 5291119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5306250Sroot writetape((char *)&dblock); 5311119Sbill 5321119Sbill while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 5331119Sbill writetape(buf); 5341119Sbill blocks--; 5351119Sbill } 5361119Sbill close(infile); 5371119Sbill if (blocks != 0 || i != 0) 5381119Sbill fprintf(stderr, "%s: file changed size\n", longname); 5396250Sroot while (--blocks >= 0) 5401119Sbill putempty(); 5411119Sbill } 5421119Sbill 5431119Sbill doxtract(argv) 5446250Sroot char *argv[]; 5451119Sbill { 5461119Sbill long blocks, bytes; 5471119Sbill char buf[TBLOCK]; 5481119Sbill char **cp; 5491119Sbill int ofile; 5501119Sbill 5511119Sbill for (;;) { 5521119Sbill getdir(); 5531119Sbill if (endtape()) 5541119Sbill break; 5551119Sbill if (*argv == 0) 5561119Sbill goto gotit; 5571119Sbill for (cp = argv; *cp; cp++) 5581119Sbill if (prefix(*cp, dblock.dbuf.name)) 5591119Sbill goto gotit; 5601119Sbill passtape(); 5611119Sbill continue; 5621119Sbill 5631119Sbill gotit: 5641119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 5651119Sbill passtape(); 5661119Sbill continue; 5671119Sbill } 5686250Sroot if (checkdir(dblock.dbuf.name)) 5696250Sroot continue; 5706250Sroot if (dblock.dbuf.linkflag == '2') { 5716250Sroot unlink(dblock.dbuf.name); 5726250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 5736250Sroot fprintf(stderr, "%s: symbolic link failed\n", 5746250Sroot dblock.dbuf.name); 5756250Sroot continue; 5766250Sroot } 5776250Sroot if (vflag) 5786250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 5796250Sroot dblock.dbuf.name, dblock.dbuf.linkname); 5808150Smckusick #ifdef notdef 5818150Smckusick /* ignore alien orders */ 5826250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 5836250Sroot if (mflag == 0) { 5846250Sroot time_t timep[2]; 5851119Sbill 5866250Sroot timep[0] = time(0); 5876250Sroot timep[1] = stbuf.st_mtime; 5886250Sroot utime(dblock.dbuf.name, timep); 5896250Sroot } 5906250Sroot if (pflag) 5916250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 5928150Smckusick #endif 5931119Sbill continue; 5946250Sroot } 5951119Sbill if (dblock.dbuf.linkflag == '1') { 5961119Sbill unlink(dblock.dbuf.name); 5971119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 5986250Sroot fprintf(stderr, "%s: cannot link\n", 5996250Sroot dblock.dbuf.name); 6001119Sbill continue; 6011119Sbill } 6021119Sbill if (vflag) 6033457Swnj fprintf(stderr, "%s linked to %s\n", 6043457Swnj dblock.dbuf.name, dblock.dbuf.linkname); 6051119Sbill continue; 6061119Sbill } 6076250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 6086250Sroot fprintf(stderr, "tar: %s - cannot create\n", 6096250Sroot dblock.dbuf.name); 6101119Sbill passtape(); 6111119Sbill continue; 6121119Sbill } 6131926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6141119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 6151119Sbill if (vflag) 6163457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 6173457Swnj dblock.dbuf.name, bytes, blocks); 6186250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 6191119Sbill readtape(buf); 6201119Sbill if (bytes > TBLOCK) { 6211119Sbill if (write(ofile, buf, TBLOCK) < 0) { 6226250Sroot fprintf(stderr, 6236250Sroot "tar: %s: HELP - extract write error\n", 6246250Sroot dblock.dbuf.name); 6251119Sbill done(2); 6261119Sbill } 6276250Sroot continue; 6286250Sroot } 6296250Sroot if (write(ofile, buf, (int) bytes) < 0) { 6306250Sroot fprintf(stderr, 6316250Sroot "tar: %s: HELP - extract write error\n", 6326250Sroot dblock.dbuf.name); 6336250Sroot done(2); 6346250Sroot } 6351119Sbill } 6361119Sbill close(ofile); 6371119Sbill if (mflag == 0) { 6381119Sbill time_t timep[2]; 6391119Sbill 6401119Sbill timep[0] = time(NULL); 6411119Sbill timep[1] = stbuf.st_mtime; 6421119Sbill utime(dblock.dbuf.name, timep); 6431119Sbill } 6441926Swnj if (pflag) 6456250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6461119Sbill } 6471119Sbill } 6481119Sbill 6491119Sbill dotable() 6501119Sbill { 6511119Sbill for (;;) { 6521119Sbill getdir(); 6531119Sbill if (endtape()) 6541119Sbill break; 6551119Sbill if (vflag) 6561119Sbill longt(&stbuf); 6571119Sbill printf("%s", dblock.dbuf.name); 6581119Sbill if (dblock.dbuf.linkflag == '1') 6591119Sbill printf(" linked to %s", dblock.dbuf.linkname); 6606250Sroot if (dblock.dbuf.linkflag == '2') 6616250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 6621119Sbill printf("\n"); 6631119Sbill passtape(); 6641119Sbill } 6651119Sbill } 6661119Sbill 6671119Sbill putempty() 6681119Sbill { 6691119Sbill char buf[TBLOCK]; 6701119Sbill char *cp; 6711119Sbill 6721119Sbill for (cp = buf; cp < &buf[TBLOCK]; ) 6731119Sbill *cp++ = '\0'; 6741119Sbill writetape(buf); 6751119Sbill } 6761119Sbill 6771119Sbill longt(st) 6786250Sroot register struct stat *st; 6791119Sbill { 6801119Sbill register char *cp; 6811119Sbill char *ctime(); 6821119Sbill 6831119Sbill pmode(st); 6841119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 6851119Sbill printf("%7D", st->st_size); 6861119Sbill cp = ctime(&st->st_mtime); 6871119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 6881119Sbill } 6891119Sbill 6901119Sbill #define SUID 04000 6911119Sbill #define SGID 02000 6921119Sbill #define ROWN 0400 6931119Sbill #define WOWN 0200 6941119Sbill #define XOWN 0100 6951119Sbill #define RGRP 040 6961119Sbill #define WGRP 020 6971119Sbill #define XGRP 010 6981119Sbill #define ROTH 04 6991119Sbill #define WOTH 02 7001119Sbill #define XOTH 01 7011119Sbill #define STXT 01000 7021119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 7031119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 7041119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 7051119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 7061119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 7071119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 7081119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 7091119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 7101119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 7111119Sbill 7121119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 7131119Sbill 7141119Sbill pmode(st) 7156250Sroot register struct stat *st; 7161119Sbill { 7171119Sbill register int **mp; 7181119Sbill 7191119Sbill for (mp = &m[0]; mp < &m[9];) 7201119Sbill select(*mp++, st); 7211119Sbill } 7221119Sbill 7231119Sbill select(pairp, st) 7246250Sroot int *pairp; 7256250Sroot struct stat *st; 7261119Sbill { 7271119Sbill register int n, *ap; 7281119Sbill 7291119Sbill ap = pairp; 7301119Sbill n = *ap++; 7311119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 7321119Sbill ap++; 7331119Sbill printf("%c", *ap); 7341119Sbill } 7351119Sbill 7361119Sbill checkdir(name) 7376250Sroot register char *name; 7381119Sbill { 7391119Sbill register char *cp; 7406250Sroot 7411119Sbill for (cp = name; *cp; cp++) { 7426250Sroot if (*cp != '/') 7436250Sroot continue; 7446250Sroot *cp = '\0'; 7456250Sroot if (access(name, 1) < 0) { 7469844Ssam if (mkdir(name, 0777) < 0) { 7479844Ssam perror(name); 7486250Sroot done(0); 7491119Sbill } 7506250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 7516250Sroot if (pflag) 7529844Ssam chmod(name, stbuf.st_mode & 0777); 7531119Sbill } 7546250Sroot *cp = '/'; 7551119Sbill } 7566250Sroot return (cp[-1]=='/'); 7571119Sbill } 7581119Sbill 7591119Sbill onintr() 7601119Sbill { 7611119Sbill signal(SIGINT, SIG_IGN); 7621119Sbill term++; 7631119Sbill } 7641119Sbill 7651119Sbill onquit() 7661119Sbill { 7671119Sbill signal(SIGQUIT, SIG_IGN); 7681119Sbill term++; 7691119Sbill } 7701119Sbill 7711119Sbill onhup() 7721119Sbill { 7731119Sbill signal(SIGHUP, SIG_IGN); 7741119Sbill term++; 7751119Sbill } 7761119Sbill 7771119Sbill onterm() 7781119Sbill { 7791119Sbill signal(SIGTERM, SIG_IGN); 7801119Sbill term++; 7811119Sbill } 7821119Sbill 7831119Sbill tomodes(sp) 7841119Sbill register struct stat *sp; 7851119Sbill { 7861119Sbill register char *cp; 7871119Sbill 7881119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 7891119Sbill *cp = '\0'; 7901119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 7911119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 7921119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 7931119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 7941119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 7951119Sbill } 7961119Sbill 7971119Sbill checksum() 7981119Sbill { 7991119Sbill register i; 8001119Sbill register char *cp; 8011119Sbill 8026250Sroot for (cp = dblock.dbuf.chksum; 8036250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 8041119Sbill *cp = ' '; 8051119Sbill i = 0; 8061119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8071119Sbill i += *cp; 8086250Sroot return (i); 8091119Sbill } 8101119Sbill 8111119Sbill checkw(c, name) 8126250Sroot char *name; 8131119Sbill { 8146250Sroot if (!wflag) 8156250Sroot return (1); 8166250Sroot printf("%c ", c); 8176250Sroot if (vflag) 8186250Sroot longt(&stbuf); 8196250Sroot printf("%s: ", name); 8206250Sroot return (response() == 'y'); 8211119Sbill } 8221119Sbill 8231119Sbill response() 8241119Sbill { 8251119Sbill char c; 8261119Sbill 8271119Sbill c = getchar(); 8281119Sbill if (c != '\n') 8296250Sroot while (getchar() != '\n') 8306250Sroot ; 8316250Sroot else 8326250Sroot c = 'n'; 8336250Sroot return (c); 8341119Sbill } 8351119Sbill 8361119Sbill checkupdate(arg) 8376250Sroot char *arg; 8381119Sbill { 8391119Sbill char name[100]; 8406250Sroot long mtime; 8411119Sbill daddr_t seekp; 8421119Sbill daddr_t lookup(); 8431119Sbill 8441119Sbill rewind(tfile); 8451119Sbill for (;;) { 8461119Sbill if ((seekp = lookup(arg)) < 0) 8476250Sroot return (1); 8481119Sbill fseek(tfile, seekp, 0); 8491119Sbill fscanf(tfile, "%s %lo", name, &mtime); 8506250Sroot return (stbuf.st_mtime > mtime); 8511119Sbill } 8521119Sbill } 8531119Sbill 8541119Sbill done(n) 8551119Sbill { 8561119Sbill unlink(tname); 8571119Sbill exit(n); 8581119Sbill } 8591119Sbill 8601119Sbill prefix(s1, s2) 8616250Sroot register char *s1, *s2; 8621119Sbill { 8631119Sbill while (*s1) 8641119Sbill if (*s1++ != *s2++) 8656250Sroot return (0); 8661119Sbill if (*s2) 8676250Sroot return (*s2 == '/'); 8686250Sroot return (1); 8691119Sbill } 8701119Sbill 8711119Sbill #define N 200 8721119Sbill int njab; 8736250Sroot 8741119Sbill daddr_t 8751119Sbill lookup(s) 8766250Sroot char *s; 8771119Sbill { 8781119Sbill register i; 8791119Sbill daddr_t a; 8801119Sbill 8811119Sbill for(i=0; s[i]; i++) 8826250Sroot if (s[i] == ' ') 8831119Sbill break; 8841119Sbill a = bsrch(s, i, low, high); 8856250Sroot return (a); 8861119Sbill } 8871119Sbill 8881119Sbill daddr_t 8891119Sbill bsrch(s, n, l, h) 8906250Sroot daddr_t l, h; 8916250Sroot char *s; 8921119Sbill { 8931119Sbill register i, j; 8941119Sbill char b[N]; 8951119Sbill daddr_t m, m1; 8961119Sbill 8971119Sbill njab = 0; 8981119Sbill 8991119Sbill loop: 9006250Sroot if (l >= h) 9016250Sroot return (-1L); 9021119Sbill m = l + (h-l)/2 - N/2; 9036250Sroot if (m < l) 9041119Sbill m = l; 9051119Sbill fseek(tfile, m, 0); 9061119Sbill fread(b, 1, N, tfile); 9071119Sbill njab++; 9081119Sbill for(i=0; i<N; i++) { 9096250Sroot if (b[i] == '\n') 9101119Sbill break; 9111119Sbill m++; 9121119Sbill } 9136250Sroot if (m >= h) 9146250Sroot return (-1L); 9151119Sbill m1 = m; 9161119Sbill j = i; 9171119Sbill for(i++; i<N; i++) { 9181119Sbill m1++; 9196250Sroot if (b[i] == '\n') 9201119Sbill break; 9211119Sbill } 9221119Sbill i = cmp(b+j, s, n); 9236250Sroot if (i < 0) { 9241119Sbill h = m; 9251119Sbill goto loop; 9261119Sbill } 9276250Sroot if (i > 0) { 9281119Sbill l = m1; 9291119Sbill goto loop; 9301119Sbill } 9316250Sroot return (m); 9321119Sbill } 9331119Sbill 9341119Sbill cmp(b, s, n) 9356250Sroot char *b, *s; 9361119Sbill { 9371119Sbill register i; 9381119Sbill 9396250Sroot if (b[0] != '\n') 9401119Sbill exit(2); 9411119Sbill for(i=0; i<n; i++) { 9426250Sroot if (b[i+1] > s[i]) 9436250Sroot return (-1); 9446250Sroot if (b[i+1] < s[i]) 9456250Sroot return (1); 9461119Sbill } 9476250Sroot return (b[i+1] == ' '? 0 : -1); 9481119Sbill } 9491119Sbill 9501119Sbill readtape(buffer) 9516250Sroot char *buffer; 9521119Sbill { 9533457Swnj register int i; 9541119Sbill 9551119Sbill if (recno >= nblock || first == 0) { 9568737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 9571119Sbill fprintf(stderr, "Tar: tape read error\n"); 9581119Sbill done(3); 9591119Sbill } 9601119Sbill if (first == 0) { 9611119Sbill if ((i % TBLOCK) != 0) { 9621119Sbill fprintf(stderr, "Tar: tape blocksize error\n"); 9631119Sbill done(3); 9641119Sbill } 9651119Sbill i /= TBLOCK; 9663457Swnj if (i != nblock) { 9671119Sbill fprintf(stderr, "Tar: blocksize = %d\n", i); 9681119Sbill nblock = i; 9691119Sbill } 9701119Sbill } 9711119Sbill recno = 0; 9721119Sbill } 9731119Sbill first = 1; 9741119Sbill copy(buffer, &tbuf[recno++]); 9756250Sroot return (TBLOCK); 9761119Sbill } 9771119Sbill 9781119Sbill writetape(buffer) 9796250Sroot char *buffer; 9801119Sbill { 9811119Sbill first = 1; 9821119Sbill if (recno >= nblock) { 9831119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 9841119Sbill fprintf(stderr, "Tar: tape write error\n"); 9851119Sbill done(2); 9861119Sbill } 9871119Sbill recno = 0; 9881119Sbill } 9891119Sbill copy(&tbuf[recno++], buffer); 9901119Sbill if (recno >= nblock) { 9911119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 9921119Sbill fprintf(stderr, "Tar: tape write error\n"); 9931119Sbill done(2); 9941119Sbill } 9951119Sbill recno = 0; 9961119Sbill } 9976250Sroot return (TBLOCK); 9981119Sbill } 9991119Sbill 10001119Sbill backtape() 10011119Sbill { 10023457Swnj static int mtdev = 1; 10033457Swnj static struct mtop mtop = {MTBSR, 1}; 10043457Swnj struct mtget mtget; 10053457Swnj 10063457Swnj if (mtdev == 1) 10073457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 10083457Swnj if (mtdev == 0) { 10093457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 10103457Swnj fprintf(stderr, "Tar: tape backspace error\n"); 10111119Sbill done(4); 10121119Sbill } 10133457Swnj } else 10143457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 10153457Swnj recno--; 10161119Sbill } 10171119Sbill 10181119Sbill flushtape() 10191119Sbill { 10201119Sbill write(mt, tbuf, TBLOCK*nblock); 10211119Sbill } 10221119Sbill 10231119Sbill copy(to, from) 10246250Sroot register char *to, *from; 10251119Sbill { 10261119Sbill register i; 10271119Sbill 10281119Sbill i = TBLOCK; 10291119Sbill do { 10301119Sbill *to++ = *from++; 10311119Sbill } while (--i); 10321119Sbill } 10338737Smckusick 10348737Smckusick bread(fd, buf, size) 10358737Smckusick int fd; 10368737Smckusick char *buf; 10378737Smckusick int size; 10388737Smckusick { 10398737Smckusick int count; 10408737Smckusick static int lastread = 0; 10418737Smckusick 10428737Smckusick if (!Bflag) 10438737Smckusick return (read(fd, buf, size)); 10448737Smckusick for (count = 0; count < size; count += lastread) { 10458737Smckusick if (lastread < 0) { 10468737Smckusick if (count > 0) 10478737Smckusick return (count); 10488737Smckusick return (lastread); 10498737Smckusick } 10508737Smckusick lastread = read(fd, buf, size - count); 10518737Smckusick buf += lastread; 10528737Smckusick } 10538737Smckusick return (count); 10548737Smckusick } 1055*10165Ssam 1056*10165Ssam char * 1057*10165Ssam getcwd(buf) 1058*10165Ssam char *buf; 1059*10165Ssam { 1060*10165Ssam 1061*10165Ssam if (getwd(buf) == NULL) { 1062*10165Ssam fprintf(stderr, "tar: %s\n", buf); 1063*10165Ssam exit(1); 1064*10165Ssam } 1065*10165Ssam return (buf); 1066*10165Ssam } 1067