112154Ssam #ifndef lint 2*12983Ssam static char *sccsid = "@(#)tar.c 4.16 (Berkeley) 06/10/83"; 312154Ssam #endif 46250Sroot 56250Sroot /* 66250Sroot * Tape Archival Program 76250Sroot */ 81119Sbill #include <stdio.h> 96413Smckusic #include <sys/param.h> 101119Sbill #include <sys/stat.h> 1112154Ssam #include <sys/dir.h> 128150Smckusick #include <sys/ioctl.h> 133457Swnj #include <sys/mtio.h> 14*12983Ssam #include <sys/time.h> 151119Sbill #include <signal.h> 1612154Ssam #include <errno.h> 171119Sbill 181119Sbill #define TBLOCK 512 193355Swnj #define NBLOCK 20 201119Sbill #define NAMSIZ 100 216250Sroot 221119Sbill union hblock { 231119Sbill char dummy[TBLOCK]; 241119Sbill struct header { 251119Sbill char name[NAMSIZ]; 261119Sbill char mode[8]; 271119Sbill char uid[8]; 281119Sbill char gid[8]; 291119Sbill char size[12]; 301119Sbill char mtime[12]; 311119Sbill char chksum[8]; 321119Sbill char linkflag; 331119Sbill char linkname[NAMSIZ]; 341119Sbill } dbuf; 356250Sroot }; 361119Sbill 371119Sbill struct linkbuf { 381119Sbill ino_t inum; 391119Sbill dev_t devnum; 401119Sbill int count; 411119Sbill char pathname[NAMSIZ]; 421119Sbill struct linkbuf *nextp; 436250Sroot }; 441119Sbill 456250Sroot union hblock dblock; 466250Sroot union hblock tbuf[NBLOCK]; 476250Sroot struct linkbuf *ihead; 486250Sroot struct stat stbuf; 491119Sbill 506250Sroot int rflag; 516250Sroot int xflag; 526250Sroot int vflag; 536250Sroot int tflag; 546250Sroot int cflag; 556250Sroot int mflag; 566250Sroot int fflag; 5712154Ssam int iflag; 586250Sroot int oflag; 596250Sroot int pflag; 606250Sroot int wflag; 616250Sroot int hflag; 628737Smckusick int Bflag; 6312154Ssam int Fflag; 646250Sroot 656250Sroot int mt; 666250Sroot int term; 676250Sroot int chksum; 686250Sroot int recno; 696250Sroot int first; 706250Sroot int linkerrok; 711119Sbill int freemem = 1; 723457Swnj int nblock = NBLOCK; 736250Sroot int onintr(); 746250Sroot int onquit(); 756250Sroot int onhup(); 766250Sroot int onterm(); 771119Sbill 781119Sbill daddr_t low; 791119Sbill daddr_t high; 806250Sroot daddr_t bsrch(); 811119Sbill 821119Sbill FILE *tfile; 831119Sbill char tname[] = "/tmp/tarXXXXXX"; 841119Sbill char *usefile; 856250Sroot char magtape[] = "/dev/rmt8"; 861119Sbill char *malloc(); 876250Sroot char *sprintf(); 886250Sroot char *strcat(); 8912154Ssam char *rindex(); 9010165Ssam char *getcwd(); 919844Ssam char *getwd(); 921119Sbill 931119Sbill main(argc, argv) 941119Sbill int argc; 951119Sbill char *argv[]; 961119Sbill { 971119Sbill char *cp; 981119Sbill 991119Sbill if (argc < 2) 1001119Sbill usage(); 1011119Sbill 1021119Sbill tfile = NULL; 1031119Sbill usefile = magtape; 1041119Sbill argv[argc] = 0; 1051119Sbill argv++; 1061119Sbill for (cp = *argv++; *cp; cp++) 1071119Sbill switch(*cp) { 1086250Sroot 1091119Sbill case 'f': 11012154Ssam if (*argv == 0) { 11112154Ssam fprintf(stderr, 11212154Ssam "tar: tapefile must be specified with 'f' option\n"); 11312154Ssam usage(); 11412154Ssam } 1151119Sbill usefile = *argv++; 1161119Sbill fflag++; 1171119Sbill break; 1186250Sroot 1191119Sbill case 'c': 1201119Sbill cflag++; 1211119Sbill rflag++; 1221119Sbill break; 1236250Sroot 1241119Sbill case 'o': 1251119Sbill oflag++; 1261119Sbill break; 1276250Sroot 1281119Sbill case 'p': 1291119Sbill pflag++; 1301119Sbill break; 1316250Sroot 1321119Sbill case 'u': 1331119Sbill mktemp(tname); 1341119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1356250Sroot fprintf(stderr, 1366250Sroot "Tar: cannot create temporary file (%s)\n", 1376250Sroot tname); 1381119Sbill done(1); 1391119Sbill } 1401119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1416250Sroot /*FALL THRU*/ 1426250Sroot 1431119Sbill case 'r': 1441119Sbill rflag++; 1451119Sbill break; 1466250Sroot 1471119Sbill case 'v': 1481119Sbill vflag++; 1491119Sbill break; 1506250Sroot 1511119Sbill case 'w': 1521119Sbill wflag++; 1531119Sbill break; 1546250Sroot 1551119Sbill case 'x': 1561119Sbill xflag++; 1571119Sbill break; 1586250Sroot 1591119Sbill case 't': 1601119Sbill tflag++; 1611119Sbill break; 1626250Sroot 1631119Sbill case 'm': 1641119Sbill mflag++; 1651119Sbill break; 1666250Sroot 1671119Sbill case '-': 1681119Sbill break; 1696250Sroot 1701119Sbill case '0': 1711119Sbill case '1': 1721119Sbill case '4': 1731119Sbill case '5': 1741119Sbill case '7': 1751119Sbill case '8': 1761119Sbill magtape[8] = *cp; 1771119Sbill usefile = magtape; 1781119Sbill break; 1796250Sroot 1801119Sbill case 'b': 1811119Sbill nblock = atoi(*argv++); 1821119Sbill if (nblock > NBLOCK || nblock <= 0) { 1836250Sroot fprintf(stderr, "Invalid blocksize. (Max %d)\n", 1846250Sroot NBLOCK); 1851119Sbill done(1); 1861119Sbill } 1871119Sbill break; 1886250Sroot 1891119Sbill case 'l': 1901119Sbill linkerrok++; 1911119Sbill break; 1926250Sroot 1936250Sroot case 'h': 1946250Sroot hflag++; 1956250Sroot break; 1966250Sroot 19712154Ssam case 'i': 19812154Ssam iflag++; 19912154Ssam break; 20012154Ssam 2018737Smckusick case 'B': 2028737Smckusick Bflag++; 2038737Smckusick break; 2048737Smckusick 20512154Ssam case 'F': 20612154Ssam Fflag++; 20712154Ssam break; 20812154Ssam 2091119Sbill default: 2101119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2111119Sbill usage(); 2121119Sbill } 2131119Sbill 2146250Sroot if (!rflag && !xflag && !tflag) 2156250Sroot usage(); 2161119Sbill if (rflag) { 2176250Sroot if (cflag && tfile != NULL) 2181119Sbill usage(); 2191119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2201119Sbill signal(SIGINT, onintr); 2211119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 2221119Sbill signal(SIGHUP, onhup); 2231119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2241119Sbill signal(SIGQUIT, onquit); 2256250Sroot #ifdef notdef 2261119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2271119Sbill signal(SIGTERM, onterm); 2286250Sroot #endif 2291119Sbill if (strcmp(usefile, "-") == 0) { 2301119Sbill if (cflag == 0) { 2316250Sroot fprintf(stderr, 2326250Sroot "Can only create standard output archives\n"); 2331119Sbill done(1); 2341119Sbill } 2351119Sbill mt = dup(1); 2361119Sbill nblock = 1; 2376250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2381119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2396250Sroot fprintf(stderr, 2406250Sroot "tar: cannot open %s\n", usefile); 2411119Sbill done(1); 2421119Sbill } 2431119Sbill } 2441119Sbill dorep(argv); 2456250Sroot done(0); 2461119Sbill } 2476250Sroot if (strcmp(usefile, "-") == 0) { 2486250Sroot mt = dup(0); 2496250Sroot nblock = 1; 2506250Sroot } else if ((mt = open(usefile, 0)) < 0) { 2516250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 2526250Sroot done(1); 2536250Sroot } 2546250Sroot if (xflag) 2551119Sbill doxtract(argv); 2566250Sroot else 2571119Sbill dotable(); 2581119Sbill done(0); 2591119Sbill } 2601119Sbill 2611119Sbill usage() 2621119Sbill { 2636250Sroot fprintf(stderr, 2648737Smckusick "tar: usage tar -{txruB}[cvfblmh] [tapefile] [blocksize] file1 file2...\n"); 2651119Sbill done(1); 2661119Sbill } 2671119Sbill 2681119Sbill dorep(argv) 2696250Sroot char *argv[]; 2701119Sbill { 2711119Sbill register char *cp, *cp2; 2729601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 2731119Sbill 2741119Sbill if (!cflag) { 2751119Sbill getdir(); 2761119Sbill do { 2771119Sbill passtape(); 2781119Sbill if (term) 2791119Sbill done(0); 2801119Sbill getdir(); 2811119Sbill } while (!endtape()); 2821119Sbill if (tfile != NULL) { 2831119Sbill char buf[200]; 2841119Sbill 2856250Sroot sprintf(buf, 2866250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 2871119Sbill tname, tname, tname, tname, tname, tname); 2881119Sbill fflush(tfile); 2891119Sbill system(buf); 2901119Sbill freopen(tname, "r", tfile); 2911119Sbill fstat(fileno(tfile), &stbuf); 2921119Sbill high = stbuf.st_size; 2931119Sbill } 2941119Sbill } 2951119Sbill 29610165Ssam (void) getcwd(wdir); 2971119Sbill while (*argv && ! term) { 2981119Sbill cp2 = *argv; 2991119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3001119Sbill argv++; 3011119Sbill if (chdir(*argv) < 0) 3021119Sbill perror(*argv); 3031119Sbill else 30410165Ssam (void) getcwd(wdir); 3051119Sbill argv++; 3061119Sbill continue; 3071119Sbill } 3089601Ssam parent = wdir; 3091119Sbill for (cp = *argv; *cp; cp++) 3101119Sbill if (*cp == '/') 3111119Sbill cp2 = cp; 3121119Sbill if (cp2 != *argv) { 3131119Sbill *cp2 = '\0'; 3149601Ssam if (chdir(*argv) < 0) { 3159601Ssam perror(*argv); 3169601Ssam continue; 3179601Ssam } 31810165Ssam parent = getcwd(tempdir); 3191119Sbill *cp2 = '/'; 3201119Sbill cp2++; 3211119Sbill } 3229601Ssam putfile(*argv++, cp2, parent); 3231119Sbill chdir(wdir); 3241119Sbill } 3251119Sbill putempty(); 3261119Sbill putempty(); 3271119Sbill flushtape(); 3286250Sroot if (linkerrok == 0) 3296250Sroot return; 3306250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3316250Sroot if (ihead->count == 0) 3326250Sroot continue; 3336250Sroot fprintf(stderr, "Missing links to %s\n", ihead->pathname); 3346250Sroot } 3351119Sbill } 3361119Sbill 3371119Sbill endtape() 3381119Sbill { 3396250Sroot if (dblock.dbuf.name[0] != '\0') 3406250Sroot return (0); 3416250Sroot backtape(); 3426250Sroot return (1); 3431119Sbill } 3441119Sbill 3451119Sbill getdir() 3461119Sbill { 3471119Sbill register struct stat *sp; 3481119Sbill int i; 3491119Sbill 35012154Ssam top: 3516250Sroot readtape((char *)&dblock); 3521119Sbill if (dblock.dbuf.name[0] == '\0') 3531119Sbill return; 3541119Sbill sp = &stbuf; 3551119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3561119Sbill sp->st_mode = i; 3571119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3581119Sbill sp->st_uid = i; 3591119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3601119Sbill sp->st_gid = i; 3611119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3621119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3631119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 36412154Ssam if (chksum != (i = checksum())) { 36512154Ssam fprintf(stderr, "directory checksum error (%d != %d)\n", 36612154Ssam chksum, i); 36712154Ssam if (iflag) 36812154Ssam goto top; 3691119Sbill done(2); 3701119Sbill } 3711119Sbill if (tfile != NULL) 3721119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3731119Sbill } 3741119Sbill 3751119Sbill passtape() 3761119Sbill { 3771119Sbill long blocks; 3781119Sbill char buf[TBLOCK]; 3791119Sbill 3801119Sbill if (dblock.dbuf.linkflag == '1') 3811119Sbill return; 3821119Sbill blocks = stbuf.st_size; 3831119Sbill blocks += TBLOCK-1; 3841119Sbill blocks /= TBLOCK; 3851119Sbill 3861119Sbill while (blocks-- > 0) 3871119Sbill readtape(buf); 3881119Sbill } 3891119Sbill 3909601Ssam putfile(longname, shortname, parent) 3916250Sroot char *longname; 3926250Sroot char *shortname; 3939601Ssam char *parent; 3941119Sbill { 39512154Ssam int infile = 0; 3961119Sbill long blocks; 3971119Sbill char buf[TBLOCK]; 3981119Sbill register char *cp, *cp2; 3995931Smckusic struct direct *dp; 4005931Smckusic DIR *dirp; 4011119Sbill int i, j; 4029601Ssam char newparent[NAMSIZ+64]; 40312154Ssam extern int errno; 4041119Sbill 4059601Ssam if (!hflag) 40612154Ssam i = lstat(shortname, &stbuf); 40712154Ssam else 40812154Ssam i = stat(shortname, &stbuf); 40912154Ssam if (i < 0) { 41012154Ssam switch (errno) { 41112154Ssam case EACCES: 41212154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 41312154Ssam break; 41412154Ssam case ENOENT: 41512154Ssam fprintf(stderr, "tar: %s: no such file or directory\n", 41612154Ssam longname); 41712154Ssam break; 41812154Ssam default: 41912154Ssam fprintf(stderr, "tar: %s: cannot stat file\n", longname); 42012154Ssam break; 42112154Ssam } 4229601Ssam return; 4239601Ssam } 42412154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4251119Sbill return; 42612154Ssam if (checkw('r', longname) == 0) 4271119Sbill return; 42812154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 42912154Ssam return; 4301119Sbill 43112154Ssam switch (stbuf.st_mode & S_IFMT) { 43212154Ssam case S_IFDIR: 4336250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4346250Sroot ; 4351119Sbill *--cp = '/'; 4361119Sbill *++cp = 0 ; 4371119Sbill if (!oflag) { 4386250Sroot if ((cp - buf) >= NAMSIZ) { 4396250Sroot fprintf(stderr, "%s: file name too long\n", 4406250Sroot longname); 4416250Sroot return; 4426250Sroot } 4436250Sroot stbuf.st_size = 0; 4446250Sroot tomodes(&stbuf); 4456250Sroot strcpy(dblock.dbuf.name,buf); 4466250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4476250Sroot writetape((char *)&dblock); 4481119Sbill } 4499601Ssam sprintf(newparent, "%s/%s", parent, shortname); 4501119Sbill chdir(shortname); 4515931Smckusic if ((dirp = opendir(".")) == NULL) { 4525931Smckusic fprintf(stderr, "%s: directory read error\n", longname); 4539601Ssam chdir(parent); 4545931Smckusic return; 4555931Smckusic } 4565931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4575931Smckusic if (dp->d_ino == 0) 4581119Sbill continue; 4596250Sroot if (!strcmp(".", dp->d_name) || 4606250Sroot !strcmp("..", dp->d_name)) 4611119Sbill continue; 4625931Smckusic strcpy(cp, dp->d_name); 4635931Smckusic i = telldir(dirp); 4645931Smckusic closedir(dirp); 4659601Ssam putfile(buf, cp, newparent); 4665931Smckusic dirp = opendir("."); 4675931Smckusic seekdir(dirp, i); 4681119Sbill } 4695931Smckusic closedir(dirp); 4709601Ssam chdir(parent); 47112154Ssam break; 47212154Ssam 47312154Ssam case S_IFLNK: 47412154Ssam tomodes(&stbuf); 47512154Ssam if (strlen(longname) >= NAMSIZ) { 47612154Ssam fprintf(stderr, "%s: file name too long\n", longname); 47712154Ssam return; 47812154Ssam } 47912154Ssam strcpy(dblock.dbuf.name, longname); 4806250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 4816250Sroot fprintf(stderr, "%s: symbolic link too long\n", 4826250Sroot longname); 4836250Sroot return; 4846250Sroot } 4859601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 4866250Sroot if (i < 0) { 4879601Ssam perror(longname); 4886250Sroot return; 4896250Sroot } 4906250Sroot dblock.dbuf.linkname[i] = '\0'; 4916250Sroot dblock.dbuf.linkflag = '2'; 4926250Sroot if (vflag) { 4936250Sroot fprintf(stderr, "a %s ", longname); 4946250Sroot fprintf(stderr, "symbolic link to %s\n", 4956250Sroot dblock.dbuf.linkname); 4966250Sroot } 4976250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 4986250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4996250Sroot writetape((char *)&dblock); 50012154Ssam break; 5011119Sbill 50212154Ssam case S_IFREG: 50312154Ssam if ((infile = open(shortname, 0)) < 0) { 50412154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 5051119Sbill return; 5061119Sbill } 50712154Ssam tomodes(&stbuf); 50812154Ssam if (strlen(longname) >= NAMSIZ) { 50912154Ssam fprintf(stderr, "%s: file name too long\n", longname); 51012154Ssam return; 51112154Ssam } 51212154Ssam strcpy(dblock.dbuf.name, longname); 51312154Ssam if (stbuf.st_nlink > 1) { 51412154Ssam struct linkbuf *lp; 51512154Ssam int found = 0; 51612154Ssam 51712154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 51812154Ssam if (lp->inum == stbuf.st_ino && 51912154Ssam lp->devnum == stbuf.st_dev) { 52012154Ssam found++; 52112154Ssam break; 52212154Ssam } 52312154Ssam if (found) { 52412154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 52512154Ssam dblock.dbuf.linkflag = '1'; 52612154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 52712154Ssam writetape( (char *) &dblock); 52812154Ssam if (vflag) { 52912154Ssam fprintf(stderr, "a %s ", longname); 53012154Ssam fprintf(stderr, "link to %s\n", lp->pathname); 53112154Ssam } 53212154Ssam lp->count--; 53312154Ssam close(infile); 53412154Ssam return; 5351119Sbill } 53612154Ssam lp = (struct linkbuf *) malloc(sizeof(*lp)); 53712154Ssam if (lp == NULL) { 53812154Ssam if (freemem) { 53912154Ssam fprintf(stderr, 54012154Ssam "Out of memory. Link information lost\n"); 54112154Ssam freemem = 0; 54212154Ssam } 54312154Ssam } else { 54412154Ssam lp->nextp = ihead; 54512154Ssam ihead = lp; 54612154Ssam lp->inum = stbuf.st_ino; 54712154Ssam lp->devnum = stbuf.st_dev; 54812154Ssam lp->count = stbuf.st_nlink - 1; 54912154Ssam strcpy(lp->pathname, longname); 55012154Ssam } 5511119Sbill } 55212154Ssam blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 55312154Ssam if (vflag) { 55412154Ssam fprintf(stderr, "a %s ", longname); 55512154Ssam fprintf(stderr, "%ld blocks\n", blocks); 55612154Ssam } 55712154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 55812154Ssam writetape((char *)&dblock); 5591119Sbill 56012154Ssam while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 56112154Ssam writetape(buf); 56212154Ssam blocks--; 56312154Ssam } 56412154Ssam close(infile); 56512154Ssam if (blocks != 0 || i != 0) 56612154Ssam fprintf(stderr, "%s: file changed size\n", longname); 56712154Ssam while (--blocks >= 0) 56812154Ssam putempty(); 56912154Ssam break; 57012154Ssam 57112154Ssam default: 57212154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 57312154Ssam longname); 57412154Ssam break; 5751119Sbill } 5761119Sbill } 5771119Sbill 5781119Sbill doxtract(argv) 5796250Sroot char *argv[]; 5801119Sbill { 5811119Sbill long blocks, bytes; 5821119Sbill char buf[TBLOCK]; 5831119Sbill char **cp; 5841119Sbill int ofile; 5851119Sbill 5861119Sbill for (;;) { 5871119Sbill getdir(); 5881119Sbill if (endtape()) 5891119Sbill break; 5901119Sbill if (*argv == 0) 5911119Sbill goto gotit; 5921119Sbill for (cp = argv; *cp; cp++) 5931119Sbill if (prefix(*cp, dblock.dbuf.name)) 5941119Sbill goto gotit; 5951119Sbill passtape(); 5961119Sbill continue; 5971119Sbill 5981119Sbill gotit: 5991119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6001119Sbill passtape(); 6011119Sbill continue; 6021119Sbill } 60312154Ssam if (Fflag) { 60412154Ssam char *s; 60512154Ssam 60612154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 60712154Ssam s = dblock.dbuf.name; 60812154Ssam else 60912154Ssam s++; 61012154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 61112154Ssam passtape(); 61212154Ssam continue; 61312154Ssam } 61412154Ssam } 6156250Sroot if (checkdir(dblock.dbuf.name)) 6166250Sroot continue; 6176250Sroot if (dblock.dbuf.linkflag == '2') { 6186250Sroot unlink(dblock.dbuf.name); 6196250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 6206250Sroot fprintf(stderr, "%s: symbolic link failed\n", 6216250Sroot dblock.dbuf.name); 6226250Sroot continue; 6236250Sroot } 6246250Sroot if (vflag) 6256250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 6266250Sroot dblock.dbuf.name, dblock.dbuf.linkname); 6278150Smckusick #ifdef notdef 6288150Smckusick /* ignore alien orders */ 6296250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6306250Sroot if (mflag == 0) { 631*12983Ssam struct timeval tv[2]; 6321119Sbill 633*12983Ssam tv[0].tv_sec = time(0); 634*12983Ssam tv[0].tv_usec = 0; 635*12983Ssam tv[1].tv_sec = stbuf.st_mtime; 636*12983Ssam tv[1].tv_usec = 0; 637*12983Ssam utimes(dblock.dbuf.name, tv); 6386250Sroot } 6396250Sroot if (pflag) 6406250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6418150Smckusick #endif 6421119Sbill continue; 6436250Sroot } 6441119Sbill if (dblock.dbuf.linkflag == '1') { 6451119Sbill unlink(dblock.dbuf.name); 6461119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 6476250Sroot fprintf(stderr, "%s: cannot link\n", 6486250Sroot dblock.dbuf.name); 6491119Sbill continue; 6501119Sbill } 6511119Sbill if (vflag) 6523457Swnj fprintf(stderr, "%s linked to %s\n", 6533457Swnj dblock.dbuf.name, dblock.dbuf.linkname); 6541119Sbill continue; 6551119Sbill } 6566250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 6576250Sroot fprintf(stderr, "tar: %s - cannot create\n", 6586250Sroot dblock.dbuf.name); 6591119Sbill passtape(); 6601119Sbill continue; 6611119Sbill } 6621926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 6631119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 6641119Sbill if (vflag) 6653457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 6663457Swnj dblock.dbuf.name, bytes, blocks); 6676250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 6681119Sbill readtape(buf); 6691119Sbill if (bytes > TBLOCK) { 6701119Sbill if (write(ofile, buf, TBLOCK) < 0) { 6716250Sroot fprintf(stderr, 6726250Sroot "tar: %s: HELP - extract write error\n", 6736250Sroot dblock.dbuf.name); 6741119Sbill done(2); 6751119Sbill } 6766250Sroot continue; 6776250Sroot } 6786250Sroot if (write(ofile, buf, (int) bytes) < 0) { 6796250Sroot fprintf(stderr, 6806250Sroot "tar: %s: HELP - extract write error\n", 6816250Sroot dblock.dbuf.name); 6826250Sroot done(2); 6836250Sroot } 6841119Sbill } 6851119Sbill close(ofile); 6861119Sbill if (mflag == 0) { 687*12983Ssam struct timeval tv[2]; 6881119Sbill 689*12983Ssam tv[0].tv_sec = time(0); 690*12983Ssam tv[0].tv_usec = 0; 691*12983Ssam tv[1].tv_sec = stbuf.st_mtime; 692*12983Ssam tv[1].tv_usec = 0; 693*12983Ssam utimes(dblock.dbuf.name, tv); 6941119Sbill } 6951926Swnj if (pflag) 6966250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6971119Sbill } 6981119Sbill } 6991119Sbill 7001119Sbill dotable() 7011119Sbill { 7021119Sbill for (;;) { 7031119Sbill getdir(); 7041119Sbill if (endtape()) 7051119Sbill break; 7061119Sbill if (vflag) 7071119Sbill longt(&stbuf); 7081119Sbill printf("%s", dblock.dbuf.name); 7091119Sbill if (dblock.dbuf.linkflag == '1') 7101119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7116250Sroot if (dblock.dbuf.linkflag == '2') 7126250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7131119Sbill printf("\n"); 7141119Sbill passtape(); 7151119Sbill } 7161119Sbill } 7171119Sbill 7181119Sbill putempty() 7191119Sbill { 7201119Sbill char buf[TBLOCK]; 7211119Sbill char *cp; 7221119Sbill 7231119Sbill for (cp = buf; cp < &buf[TBLOCK]; ) 7241119Sbill *cp++ = '\0'; 7251119Sbill writetape(buf); 7261119Sbill } 7271119Sbill 7281119Sbill longt(st) 7296250Sroot register struct stat *st; 7301119Sbill { 7311119Sbill register char *cp; 7321119Sbill char *ctime(); 7331119Sbill 7341119Sbill pmode(st); 7351119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 7361119Sbill printf("%7D", st->st_size); 7371119Sbill cp = ctime(&st->st_mtime); 7381119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 7391119Sbill } 7401119Sbill 7411119Sbill #define SUID 04000 7421119Sbill #define SGID 02000 7431119Sbill #define ROWN 0400 7441119Sbill #define WOWN 0200 7451119Sbill #define XOWN 0100 7461119Sbill #define RGRP 040 7471119Sbill #define WGRP 020 7481119Sbill #define XGRP 010 7491119Sbill #define ROTH 04 7501119Sbill #define WOTH 02 7511119Sbill #define XOTH 01 7521119Sbill #define STXT 01000 7531119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 7541119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 7551119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 7561119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 7571119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 7581119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 7591119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 7601119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 7611119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 7621119Sbill 7631119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 7641119Sbill 7651119Sbill pmode(st) 7666250Sroot register struct stat *st; 7671119Sbill { 7681119Sbill register int **mp; 7691119Sbill 7701119Sbill for (mp = &m[0]; mp < &m[9];) 7711119Sbill select(*mp++, st); 7721119Sbill } 7731119Sbill 7741119Sbill select(pairp, st) 7756250Sroot int *pairp; 7766250Sroot struct stat *st; 7771119Sbill { 7781119Sbill register int n, *ap; 7791119Sbill 7801119Sbill ap = pairp; 7811119Sbill n = *ap++; 7821119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 7831119Sbill ap++; 7841119Sbill printf("%c", *ap); 7851119Sbill } 7861119Sbill 7871119Sbill checkdir(name) 7886250Sroot register char *name; 7891119Sbill { 7901119Sbill register char *cp; 7916250Sroot 79212154Ssam /* 79312154Ssam * Quick check for existance of directory. 79412154Ssam */ 79512154Ssam if ((cp = rindex(name, '/')) == 0) 79612154Ssam return (0); 79712154Ssam *cp = '\0'; 79812154Ssam if (access(name, 0) >= 0) { 79912154Ssam *cp = '/'; 80012154Ssam return (cp[1] == '\0'); 80112154Ssam } 80212154Ssam *cp = '/'; 80312154Ssam 80412154Ssam /* 80512154Ssam * No luck, try to make all directories in path. 80612154Ssam */ 8071119Sbill for (cp = name; *cp; cp++) { 8086250Sroot if (*cp != '/') 8096250Sroot continue; 8106250Sroot *cp = '\0'; 81112154Ssam if (access(name, 0) < 0) { 8129844Ssam if (mkdir(name, 0777) < 0) { 8139844Ssam perror(name); 81412154Ssam *cp = '/'; 81512154Ssam return (0); 8161119Sbill } 8176250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 8186250Sroot if (pflag) 8199844Ssam chmod(name, stbuf.st_mode & 0777); 8201119Sbill } 8216250Sroot *cp = '/'; 8221119Sbill } 8236250Sroot return (cp[-1]=='/'); 8241119Sbill } 8251119Sbill 8261119Sbill onintr() 8271119Sbill { 8281119Sbill signal(SIGINT, SIG_IGN); 8291119Sbill term++; 8301119Sbill } 8311119Sbill 8321119Sbill onquit() 8331119Sbill { 8341119Sbill signal(SIGQUIT, SIG_IGN); 8351119Sbill term++; 8361119Sbill } 8371119Sbill 8381119Sbill onhup() 8391119Sbill { 8401119Sbill signal(SIGHUP, SIG_IGN); 8411119Sbill term++; 8421119Sbill } 8431119Sbill 8441119Sbill onterm() 8451119Sbill { 8461119Sbill signal(SIGTERM, SIG_IGN); 8471119Sbill term++; 8481119Sbill } 8491119Sbill 8501119Sbill tomodes(sp) 8511119Sbill register struct stat *sp; 8521119Sbill { 8531119Sbill register char *cp; 8541119Sbill 8551119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8561119Sbill *cp = '\0'; 8571119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 8581119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 8591119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 8601119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 8611119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 8621119Sbill } 8631119Sbill 8641119Sbill checksum() 8651119Sbill { 8661119Sbill register i; 8671119Sbill register char *cp; 8681119Sbill 8696250Sroot for (cp = dblock.dbuf.chksum; 8706250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 8711119Sbill *cp = ' '; 8721119Sbill i = 0; 8731119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 8741119Sbill i += *cp; 8756250Sroot return (i); 8761119Sbill } 8771119Sbill 8781119Sbill checkw(c, name) 8796250Sroot char *name; 8801119Sbill { 8816250Sroot if (!wflag) 8826250Sroot return (1); 8836250Sroot printf("%c ", c); 8846250Sroot if (vflag) 8856250Sroot longt(&stbuf); 8866250Sroot printf("%s: ", name); 8876250Sroot return (response() == 'y'); 8881119Sbill } 8891119Sbill 8901119Sbill response() 8911119Sbill { 8921119Sbill char c; 8931119Sbill 8941119Sbill c = getchar(); 8951119Sbill if (c != '\n') 8966250Sroot while (getchar() != '\n') 8976250Sroot ; 8986250Sroot else 8996250Sroot c = 'n'; 9006250Sroot return (c); 9011119Sbill } 9021119Sbill 90312154Ssam checkf(name, mode, howmuch) 90412154Ssam char *name; 90512154Ssam int mode, howmuch; 90612154Ssam { 90712154Ssam int l; 90812154Ssam 90912154Ssam if ((mode & S_IFMT) == S_IFDIR) 91012154Ssam return (strcmp(name, "SCCS") != 0); 91112154Ssam if ((l = strlen(name)) < 3) 91212154Ssam return (1); 91312154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 91412154Ssam return (0); 91512154Ssam if (strcmp(name, "core") == 0 || 91612154Ssam strcmp(name, "errs") == 0 || 91712154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 91812154Ssam return (0); 91912154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 92012154Ssam return (1); 92112154Ssam } 92212154Ssam 9231119Sbill checkupdate(arg) 9246250Sroot char *arg; 9251119Sbill { 9261119Sbill char name[100]; 9276250Sroot long mtime; 9281119Sbill daddr_t seekp; 9291119Sbill daddr_t lookup(); 9301119Sbill 9311119Sbill rewind(tfile); 9321119Sbill for (;;) { 9331119Sbill if ((seekp = lookup(arg)) < 0) 9346250Sroot return (1); 9351119Sbill fseek(tfile, seekp, 0); 9361119Sbill fscanf(tfile, "%s %lo", name, &mtime); 9376250Sroot return (stbuf.st_mtime > mtime); 9381119Sbill } 9391119Sbill } 9401119Sbill 9411119Sbill done(n) 9421119Sbill { 9431119Sbill unlink(tname); 9441119Sbill exit(n); 9451119Sbill } 9461119Sbill 9471119Sbill prefix(s1, s2) 9486250Sroot register char *s1, *s2; 9491119Sbill { 9501119Sbill while (*s1) 9511119Sbill if (*s1++ != *s2++) 9526250Sroot return (0); 9531119Sbill if (*s2) 9546250Sroot return (*s2 == '/'); 9556250Sroot return (1); 9561119Sbill } 9571119Sbill 9581119Sbill #define N 200 9591119Sbill int njab; 9606250Sroot 9611119Sbill daddr_t 9621119Sbill lookup(s) 9636250Sroot char *s; 9641119Sbill { 9651119Sbill register i; 9661119Sbill daddr_t a; 9671119Sbill 9681119Sbill for(i=0; s[i]; i++) 9696250Sroot if (s[i] == ' ') 9701119Sbill break; 9711119Sbill a = bsrch(s, i, low, high); 9726250Sroot return (a); 9731119Sbill } 9741119Sbill 9751119Sbill daddr_t 9761119Sbill bsrch(s, n, l, h) 9776250Sroot daddr_t l, h; 9786250Sroot char *s; 9791119Sbill { 9801119Sbill register i, j; 9811119Sbill char b[N]; 9821119Sbill daddr_t m, m1; 9831119Sbill 9841119Sbill njab = 0; 9851119Sbill 9861119Sbill loop: 9876250Sroot if (l >= h) 9886250Sroot return (-1L); 9891119Sbill m = l + (h-l)/2 - N/2; 9906250Sroot if (m < l) 9911119Sbill m = l; 9921119Sbill fseek(tfile, m, 0); 9931119Sbill fread(b, 1, N, tfile); 9941119Sbill njab++; 9951119Sbill for(i=0; i<N; i++) { 9966250Sroot if (b[i] == '\n') 9971119Sbill break; 9981119Sbill m++; 9991119Sbill } 10006250Sroot if (m >= h) 10016250Sroot return (-1L); 10021119Sbill m1 = m; 10031119Sbill j = i; 10041119Sbill for(i++; i<N; i++) { 10051119Sbill m1++; 10066250Sroot if (b[i] == '\n') 10071119Sbill break; 10081119Sbill } 10091119Sbill i = cmp(b+j, s, n); 10106250Sroot if (i < 0) { 10111119Sbill h = m; 10121119Sbill goto loop; 10131119Sbill } 10146250Sroot if (i > 0) { 10151119Sbill l = m1; 10161119Sbill goto loop; 10171119Sbill } 10186250Sroot return (m); 10191119Sbill } 10201119Sbill 10211119Sbill cmp(b, s, n) 10226250Sroot char *b, *s; 10231119Sbill { 10241119Sbill register i; 10251119Sbill 10266250Sroot if (b[0] != '\n') 10271119Sbill exit(2); 10281119Sbill for(i=0; i<n; i++) { 10296250Sroot if (b[i+1] > s[i]) 10306250Sroot return (-1); 10316250Sroot if (b[i+1] < s[i]) 10326250Sroot return (1); 10331119Sbill } 10346250Sroot return (b[i+1] == ' '? 0 : -1); 10351119Sbill } 10361119Sbill 10371119Sbill readtape(buffer) 10386250Sroot char *buffer; 10391119Sbill { 10403457Swnj register int i; 10411119Sbill 10421119Sbill if (recno >= nblock || first == 0) { 10438737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 10441119Sbill fprintf(stderr, "Tar: tape read error\n"); 10451119Sbill done(3); 10461119Sbill } 10471119Sbill if (first == 0) { 10481119Sbill if ((i % TBLOCK) != 0) { 10491119Sbill fprintf(stderr, "Tar: tape blocksize error\n"); 10501119Sbill done(3); 10511119Sbill } 10521119Sbill i /= TBLOCK; 10533457Swnj if (i != nblock) { 10541119Sbill fprintf(stderr, "Tar: blocksize = %d\n", i); 10551119Sbill nblock = i; 10561119Sbill } 10571119Sbill } 10581119Sbill recno = 0; 10591119Sbill } 10601119Sbill first = 1; 10611119Sbill copy(buffer, &tbuf[recno++]); 10626250Sroot return (TBLOCK); 10631119Sbill } 10641119Sbill 10651119Sbill writetape(buffer) 10666250Sroot char *buffer; 10671119Sbill { 10681119Sbill first = 1; 10691119Sbill if (recno >= nblock) { 10701119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 10711119Sbill fprintf(stderr, "Tar: tape write error\n"); 10721119Sbill done(2); 10731119Sbill } 10741119Sbill recno = 0; 10751119Sbill } 10761119Sbill copy(&tbuf[recno++], buffer); 10771119Sbill if (recno >= nblock) { 10781119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 10791119Sbill fprintf(stderr, "Tar: tape write error\n"); 10801119Sbill done(2); 10811119Sbill } 10821119Sbill recno = 0; 10831119Sbill } 10846250Sroot return (TBLOCK); 10851119Sbill } 10861119Sbill 10871119Sbill backtape() 10881119Sbill { 10893457Swnj static int mtdev = 1; 10903457Swnj static struct mtop mtop = {MTBSR, 1}; 10913457Swnj struct mtget mtget; 10923457Swnj 10933457Swnj if (mtdev == 1) 10943457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 10953457Swnj if (mtdev == 0) { 10963457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 10973457Swnj fprintf(stderr, "Tar: tape backspace error\n"); 10981119Sbill done(4); 10991119Sbill } 11003457Swnj } else 11013457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 11023457Swnj recno--; 11031119Sbill } 11041119Sbill 11051119Sbill flushtape() 11061119Sbill { 11071119Sbill write(mt, tbuf, TBLOCK*nblock); 11081119Sbill } 11091119Sbill 11101119Sbill copy(to, from) 11116250Sroot register char *to, *from; 11121119Sbill { 11131119Sbill register i; 11141119Sbill 11151119Sbill i = TBLOCK; 11161119Sbill do { 11171119Sbill *to++ = *from++; 11181119Sbill } while (--i); 11191119Sbill } 11208737Smckusick 11218737Smckusick bread(fd, buf, size) 11228737Smckusick int fd; 11238737Smckusick char *buf; 11248737Smckusick int size; 11258737Smckusick { 11268737Smckusick int count; 11278737Smckusick static int lastread = 0; 11288737Smckusick 11298737Smckusick if (!Bflag) 11308737Smckusick return (read(fd, buf, size)); 11318737Smckusick for (count = 0; count < size; count += lastread) { 11328737Smckusick if (lastread < 0) { 11338737Smckusick if (count > 0) 11348737Smckusick return (count); 11358737Smckusick return (lastread); 11368737Smckusick } 11378737Smckusick lastread = read(fd, buf, size - count); 11388737Smckusick buf += lastread; 11398737Smckusick } 11408737Smckusick return (count); 11418737Smckusick } 114210165Ssam 114310165Ssam char * 114410165Ssam getcwd(buf) 114510165Ssam char *buf; 114610165Ssam { 114710165Ssam 114810165Ssam if (getwd(buf) == NULL) { 114910165Ssam fprintf(stderr, "tar: %s\n", buf); 115010165Ssam exit(1); 115110165Ssam } 115210165Ssam return (buf); 115310165Ssam } 1154