122502Sdist /* 222502Sdist * Copyright (c) 1980 Regents of the University of California. 322502Sdist * All rights reserved. The Berkeley software License Agreement 422502Sdist * specifies the terms and conditions for redistribution. 522502Sdist */ 622502Sdist 712154Ssam #ifndef lint 822502Sdist char copyright[] = 922502Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1022502Sdist All rights reserved.\n"; 1133082Sbostic #endif /* not lint */ 126250Sroot 1322502Sdist #ifndef lint 14*36227Sbostic static char sccsid[] = "@(#)tar.c 5.13 (Berkeley) 11/16/88"; 1533082Sbostic #endif /* not lint */ 1622502Sdist 176250Sroot /* 186250Sroot * Tape Archival Program 196250Sroot */ 206413Smckusic #include <sys/param.h> 211119Sbill #include <sys/stat.h> 22*36227Sbostic #include <sys/file.h> 2312154Ssam #include <sys/dir.h> 248150Smckusick #include <sys/ioctl.h> 253457Swnj #include <sys/mtio.h> 2612983Ssam #include <sys/time.h> 271119Sbill #include <signal.h> 2812154Ssam #include <errno.h> 2927058Smckusick #include <fcntl.h> 30*36227Sbostic #include <strings.h> 31*36227Sbostic #include <stdio.h> 321119Sbill 331119Sbill #define TBLOCK 512 343355Swnj #define NBLOCK 20 351119Sbill #define NAMSIZ 100 366250Sroot 3721457Skjd #define writetape(b) writetbuf(b, 1) 3821457Skjd #define min(a,b) ((a) < (b) ? (a) : (b)) 3921457Skjd #define max(a,b) ((a) > (b) ? (a) : (b)) 4021457Skjd 411119Sbill union hblock { 421119Sbill char dummy[TBLOCK]; 431119Sbill struct header { 441119Sbill char name[NAMSIZ]; 451119Sbill char mode[8]; 461119Sbill char uid[8]; 471119Sbill char gid[8]; 481119Sbill char size[12]; 491119Sbill char mtime[12]; 501119Sbill char chksum[8]; 511119Sbill char linkflag; 521119Sbill char linkname[NAMSIZ]; 531119Sbill } dbuf; 546250Sroot }; 551119Sbill 561119Sbill struct linkbuf { 571119Sbill ino_t inum; 581119Sbill dev_t devnum; 591119Sbill int count; 601119Sbill char pathname[NAMSIZ]; 611119Sbill struct linkbuf *nextp; 626250Sroot }; 631119Sbill 646250Sroot union hblock dblock; 6513492Ssam union hblock *tbuf; 666250Sroot struct linkbuf *ihead; 676250Sroot struct stat stbuf; 681119Sbill 696250Sroot int rflag; 7034429Sbostic int sflag; 716250Sroot int xflag; 726250Sroot int vflag; 736250Sroot int tflag; 746250Sroot int cflag; 756250Sroot int mflag; 766250Sroot int fflag; 7712154Ssam int iflag; 786250Sroot int oflag; 796250Sroot int pflag; 806250Sroot int wflag; 816250Sroot int hflag; 828737Smckusick int Bflag; 8312154Ssam int Fflag; 846250Sroot 856250Sroot int mt; 866250Sroot int term; 876250Sroot int chksum; 886250Sroot int recno; 8922688Slepreau int first; 9022688Slepreau int prtlinkerr; 911119Sbill int freemem = 1; 9222353Skjd int nblock = 0; 936250Sroot int onintr(); 946250Sroot int onquit(); 956250Sroot int onhup(); 9622688Slepreau #ifdef notdef 976250Sroot int onterm(); 9822688Slepreau #endif 991119Sbill 1001119Sbill daddr_t low; 1011119Sbill daddr_t high; 1026250Sroot daddr_t bsrch(); 1031119Sbill 10421910Skjd FILE *vfile = stdout; 1051119Sbill FILE *tfile; 1061119Sbill char tname[] = "/tmp/tarXXXXXX"; 1071119Sbill char *usefile; 1086250Sroot char magtape[] = "/dev/rmt8"; 1091119Sbill char *malloc(); 11027445Slepreau long time(); 11127445Slepreau off_t lseek(); 11227445Slepreau char *mktemp(); 11310165Ssam char *getcwd(); 1149844Ssam char *getwd(); 11522688Slepreau char *getmem(); 1161119Sbill 117*36227Sbostic extern int errno; 118*36227Sbostic 1191119Sbill main(argc, argv) 120*36227Sbostic int argc; 121*36227Sbostic char **argv; 1221119Sbill { 1231119Sbill char *cp; 1241119Sbill 1251119Sbill if (argc < 2) 1261119Sbill usage(); 1271119Sbill 1281119Sbill tfile = NULL; 1291119Sbill usefile = magtape; 1301119Sbill argv[argc] = 0; 1311119Sbill argv++; 1321119Sbill for (cp = *argv++; *cp; cp++) 1331119Sbill switch(*cp) { 1346250Sroot 1351119Sbill case 'f': 13612154Ssam if (*argv == 0) { 13712154Ssam fprintf(stderr, 13812154Ssam "tar: tapefile must be specified with 'f' option\n"); 13912154Ssam usage(); 14012154Ssam } 1411119Sbill usefile = *argv++; 1421119Sbill fflag++; 1431119Sbill break; 1446250Sroot 1451119Sbill case 'c': 1461119Sbill cflag++; 1471119Sbill rflag++; 1481119Sbill break; 1496250Sroot 1501119Sbill case 'o': 1511119Sbill oflag++; 1521119Sbill break; 1536250Sroot 1541119Sbill case 'p': 1551119Sbill pflag++; 1561119Sbill break; 1576250Sroot 1581119Sbill case 'u': 159*36227Sbostic (void)mktemp(tname); 1601119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1616250Sroot fprintf(stderr, 16222688Slepreau "tar: cannot create temporary file (%s)\n", 1636250Sroot tname); 1641119Sbill done(1); 1651119Sbill } 1661119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1676250Sroot /*FALL THRU*/ 1686250Sroot 1691119Sbill case 'r': 1701119Sbill rflag++; 1711119Sbill break; 1726250Sroot 17334429Sbostic case 's': 17434429Sbostic sflag++; 17534429Sbostic break; 17634429Sbostic 1771119Sbill case 'v': 1781119Sbill vflag++; 1791119Sbill break; 1806250Sroot 1811119Sbill case 'w': 1821119Sbill wflag++; 1831119Sbill break; 1846250Sroot 1851119Sbill case 'x': 1861119Sbill xflag++; 1871119Sbill break; 1886250Sroot 1891119Sbill case 't': 1901119Sbill tflag++; 1911119Sbill break; 1926250Sroot 1931119Sbill case 'm': 1941119Sbill mflag++; 1951119Sbill break; 1966250Sroot 1971119Sbill case '-': 1981119Sbill break; 1996250Sroot 2001119Sbill case '0': 2011119Sbill case '1': 2021119Sbill case '4': 2031119Sbill case '5': 20421457Skjd case '7': 2051119Sbill case '8': 2061119Sbill magtape[8] = *cp; 2071119Sbill usefile = magtape; 2081119Sbill break; 2096250Sroot 2101119Sbill case 'b': 21113492Ssam if (*argv == 0) { 21213492Ssam fprintf(stderr, 21313492Ssam "tar: blocksize must be specified with 'b' option\n"); 21413492Ssam usage(); 21513492Ssam } 21613492Ssam nblock = atoi(*argv); 21713492Ssam if (nblock <= 0) { 21813492Ssam fprintf(stderr, 21913492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2201119Sbill done(1); 2211119Sbill } 22213492Ssam argv++; 2231119Sbill break; 2246250Sroot 2251119Sbill case 'l': 22622688Slepreau prtlinkerr++; 2271119Sbill break; 2286250Sroot 2296250Sroot case 'h': 2306250Sroot hflag++; 2316250Sroot break; 2326250Sroot 23312154Ssam case 'i': 23412154Ssam iflag++; 23512154Ssam break; 23612154Ssam 2378737Smckusick case 'B': 2388737Smckusick Bflag++; 2398737Smckusick break; 2408737Smckusick 24112154Ssam case 'F': 24212154Ssam Fflag++; 24312154Ssam break; 24412154Ssam 2451119Sbill default: 2461119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2471119Sbill usage(); 2481119Sbill } 2491119Sbill 2506250Sroot if (!rflag && !xflag && !tflag) 2516250Sroot usage(); 2521119Sbill if (rflag) { 2536250Sroot if (cflag && tfile != NULL) 2541119Sbill usage(); 2551119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 25627445Slepreau (void) signal(SIGINT, onintr); 2571119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 25827445Slepreau (void) signal(SIGHUP, onhup); 2591119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 26027445Slepreau (void) signal(SIGQUIT, onquit); 2616250Sroot #ifdef notdef 2621119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 26327445Slepreau (void) signal(SIGTERM, onterm); 2646250Sroot #endif 26527058Smckusick mt = openmt(usefile, 1); 2661119Sbill dorep(argv); 2676250Sroot done(0); 2681119Sbill } 26927058Smckusick mt = openmt(usefile, 0); 2706250Sroot if (xflag) 2711119Sbill doxtract(argv); 2726250Sroot else 27327445Slepreau dotable(argv); 2741119Sbill done(0); 2751119Sbill } 2761119Sbill 2771119Sbill usage() 2781119Sbill { 2796250Sroot fprintf(stderr, 28021457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2811119Sbill done(1); 2821119Sbill } 2831119Sbill 28427058Smckusick int 28527058Smckusick openmt(tape, writing) 28627058Smckusick char *tape; 28727058Smckusick int writing; 28827058Smckusick { 28927058Smckusick if (strcmp(tape, "-") == 0) { 29027058Smckusick /* 29127058Smckusick * Read from standard input or write to standard output. 29227058Smckusick */ 29327058Smckusick if (writing) { 29427058Smckusick if (cflag == 0) { 29527058Smckusick fprintf(stderr, 29627058Smckusick "tar: can only create standard output archives\n"); 29727058Smckusick done(1); 29827058Smckusick } 29927058Smckusick vfile = stderr; 30027058Smckusick setlinebuf(vfile); 30127058Smckusick mt = dup(1); 30227058Smckusick } else { 30327058Smckusick mt = dup(0); 30427058Smckusick Bflag++; 30527058Smckusick } 30627058Smckusick } else { 30727058Smckusick /* 30827058Smckusick * Use file or tape on local machine. 30927058Smckusick */ 31027058Smckusick if (writing) { 31127058Smckusick if (cflag) 31227445Slepreau mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); 31327058Smckusick else 31427058Smckusick mt = open(tape, O_RDWR); 31527058Smckusick } else 31627058Smckusick mt = open(tape, O_RDONLY); 31727058Smckusick if (mt < 0) { 318*36227Sbostic fprintf(stderr, "tar: %s: %s\n", tape, strerror(errno)); 31927058Smckusick done(1); 32027058Smckusick } 32127058Smckusick } 32227058Smckusick return(mt); 32327058Smckusick } 32427058Smckusick 3251119Sbill dorep(argv) 3266250Sroot char *argv[]; 3271119Sbill { 3281119Sbill register char *cp, *cp2; 3299601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 3301119Sbill 3311119Sbill if (!cflag) { 3321119Sbill getdir(); 3331119Sbill do { 3341119Sbill passtape(); 3351119Sbill if (term) 3361119Sbill done(0); 3371119Sbill getdir(); 3381119Sbill } while (!endtape()); 33913492Ssam backtape(); 3401119Sbill if (tfile != NULL) { 3411119Sbill char buf[200]; 3421119Sbill 34332420Sbostic (void)sprintf(buf, 3446250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3451119Sbill tname, tname, tname, tname, tname, tname); 3461119Sbill fflush(tfile); 3471119Sbill system(buf); 3481119Sbill freopen(tname, "r", tfile); 3491119Sbill fstat(fileno(tfile), &stbuf); 3501119Sbill high = stbuf.st_size; 3511119Sbill } 3521119Sbill } 3531119Sbill 35410165Ssam (void) getcwd(wdir); 3551119Sbill while (*argv && ! term) { 3561119Sbill cp2 = *argv; 3571119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3581119Sbill argv++; 35927058Smckusick if (chdir(*argv) < 0) { 360*36227Sbostic fprintf(stderr, 361*36227Sbostic "tar: can't change directories to %s: %s\n", 362*36227Sbostic *argv, strerror(errno)); 36327058Smckusick } else 36410165Ssam (void) getcwd(wdir); 3651119Sbill argv++; 3661119Sbill continue; 3671119Sbill } 3689601Ssam parent = wdir; 3691119Sbill for (cp = *argv; *cp; cp++) 3701119Sbill if (*cp == '/') 3711119Sbill cp2 = cp; 3721119Sbill if (cp2 != *argv) { 3731119Sbill *cp2 = '\0'; 3749601Ssam if (chdir(*argv) < 0) { 375*36227Sbostic fprintf(stderr, 376*36227Sbostic "tar: can't change directories to %s: %s\n", 377*36227Sbostic *argv, strerror(errno)); 3789601Ssam continue; 3799601Ssam } 38010165Ssam parent = getcwd(tempdir); 3811119Sbill *cp2 = '/'; 3821119Sbill cp2++; 3831119Sbill } 3849601Ssam putfile(*argv++, cp2, parent); 385*36227Sbostic if (chdir(wdir) < 0) 386*36227Sbostic fprintf(stderr, "tar: cannot change back?: %s: %s\n", 387*36227Sbostic wdir, strerror(errno)); 3881119Sbill } 3891119Sbill putempty(); 3901119Sbill putempty(); 3911119Sbill flushtape(); 39222688Slepreau if (prtlinkerr == 0) 3936250Sroot return; 3946250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3956250Sroot if (ihead->count == 0) 3966250Sroot continue; 39713492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3986250Sroot } 3991119Sbill } 4001119Sbill 4011119Sbill endtape() 4021119Sbill { 40321457Skjd return (dblock.dbuf.name[0] == '\0'); 4041119Sbill } 4051119Sbill 4061119Sbill getdir() 4071119Sbill { 4081119Sbill register struct stat *sp; 4091119Sbill int i; 4101119Sbill 41112154Ssam top: 4126250Sroot readtape((char *)&dblock); 4131119Sbill if (dblock.dbuf.name[0] == '\0') 4141119Sbill return; 4151119Sbill sp = &stbuf; 4161119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4171119Sbill sp->st_mode = i; 4181119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4191119Sbill sp->st_uid = i; 4201119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4211119Sbill sp->st_gid = i; 4221119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4231119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4241119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 42512154Ssam if (chksum != (i = checksum())) { 42613492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 42712154Ssam chksum, i); 42812154Ssam if (iflag) 42912154Ssam goto top; 4301119Sbill done(2); 4311119Sbill } 43234429Sbostic /* strip off leading "/" if present */ 43334429Sbostic if (sflag && dblock.dbuf.name[0] == '/') { 43434429Sbostic register char *cp1, *cp2; 43534429Sbostic for (cp1 = cp2 = dblock.dbuf.name; *cp2 && *cp2 == '/'; ++cp2); 43634429Sbostic if (!*cp2) 43734429Sbostic goto top; 43834429Sbostic while (*cp1++ = *cp2++); 43934429Sbostic } 4401119Sbill if (tfile != NULL) 4411119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4421119Sbill } 4431119Sbill 4441119Sbill passtape() 4451119Sbill { 4461119Sbill long blocks; 44721457Skjd char *bufp; 4481119Sbill 4491119Sbill if (dblock.dbuf.linkflag == '1') 4501119Sbill return; 4511119Sbill blocks = stbuf.st_size; 4521119Sbill blocks += TBLOCK-1; 4531119Sbill blocks /= TBLOCK; 4541119Sbill 45521457Skjd while (blocks-- > 0) 45627445Slepreau (void) readtbuf(&bufp, TBLOCK); 4571119Sbill } 4581119Sbill 4599601Ssam putfile(longname, shortname, parent) 4606250Sroot char *longname; 4616250Sroot char *shortname; 4629601Ssam char *parent; 4631119Sbill { 46421457Skjd int infile = 0; 46521457Skjd long blocks; 4661119Sbill char buf[TBLOCK]; 46721457Skjd char *bigbuf; 46822688Slepreau register char *cp; 4695931Smckusic struct direct *dp; 4705931Smckusic DIR *dirp; 47127445Slepreau register int i; 47227445Slepreau long l; 4739601Ssam char newparent[NAMSIZ+64]; 47421457Skjd int maxread; 47521457Skjd int hint; /* amount to write to get "in sync" */ 4761119Sbill 4779601Ssam if (!hflag) 47812154Ssam i = lstat(shortname, &stbuf); 47912154Ssam else 48012154Ssam i = stat(shortname, &stbuf); 48112154Ssam if (i < 0) { 482*36227Sbostic fprintf(stderr, "tar: %s: %s\n", longname, strerror(errno)); 4839601Ssam return; 4849601Ssam } 48512154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4861119Sbill return; 48712154Ssam if (checkw('r', longname) == 0) 4881119Sbill return; 48912154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 49012154Ssam return; 4911119Sbill 49212154Ssam switch (stbuf.st_mode & S_IFMT) { 49312154Ssam case S_IFDIR: 4946250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4956250Sroot ; 4961119Sbill *--cp = '/'; 4971119Sbill *++cp = 0 ; 4981119Sbill if (!oflag) { 4996250Sroot if ((cp - buf) >= NAMSIZ) { 50013492Ssam fprintf(stderr, "tar: %s: file name too long\n", 50113492Ssam longname); 5026250Sroot return; 5036250Sroot } 5046250Sroot stbuf.st_size = 0; 5056250Sroot tomodes(&stbuf); 5066250Sroot strcpy(dblock.dbuf.name,buf); 50732420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 50827445Slepreau (void) writetape((char *)&dblock); 5091119Sbill } 51032420Sbostic (void)sprintf(newparent, "%s/%s", parent, shortname); 51115045Smckusick if (chdir(shortname) < 0) { 512*36227Sbostic fprintf(stderr, "tar: chdir %s: %s\n", 513*36227Sbostic shortname, strerror(errno)); 51415045Smckusick return; 51515045Smckusick } 5165931Smckusic if ((dirp = opendir(".")) == NULL) { 51713492Ssam fprintf(stderr, "tar: %s: directory read error\n", 51813492Ssam longname); 51915045Smckusick if (chdir(parent) < 0) { 520*36227Sbostic fprintf(stderr, 521*36227Sbostic "tar: cannot change back?: %s: %s\n", 522*36227Sbostic parent, strerror(errno)); 52315045Smckusick } 5245931Smckusic return; 5255931Smckusic } 5265931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5276250Sroot if (!strcmp(".", dp->d_name) || 5286250Sroot !strcmp("..", dp->d_name)) 5291119Sbill continue; 5305931Smckusic strcpy(cp, dp->d_name); 53127445Slepreau l = telldir(dirp); 5325931Smckusic closedir(dirp); 5339601Ssam putfile(buf, cp, newparent); 5345931Smckusic dirp = opendir("."); 53527445Slepreau seekdir(dirp, l); 5361119Sbill } 5375931Smckusic closedir(dirp); 53815045Smckusick if (chdir(parent) < 0) { 539*36227Sbostic fprintf(stderr, 540*36227Sbostic "tar: cannot change back?: %s: %s\n", 541*36227Sbostic parent, strerror(errno)); 54215045Smckusick } 54312154Ssam break; 54412154Ssam 54512154Ssam case S_IFLNK: 54612154Ssam tomodes(&stbuf); 54712154Ssam if (strlen(longname) >= NAMSIZ) { 54813492Ssam fprintf(stderr, "tar: %s: file name too long\n", 54913492Ssam longname); 55012154Ssam return; 55112154Ssam } 55212154Ssam strcpy(dblock.dbuf.name, longname); 5536250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 55413492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 55513492Ssam longname); 5566250Sroot return; 5576250Sroot } 5589601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5596250Sroot if (i < 0) { 560*36227Sbostic fprintf(stderr, 561*36227Sbostic "tar: can't read symbolic link %s: %s\n", 562*36227Sbostic longname, strerror(errno)); 5636250Sroot return; 5646250Sroot } 5656250Sroot dblock.dbuf.linkname[i] = '\0'; 5666250Sroot dblock.dbuf.linkflag = '2'; 56722688Slepreau if (vflag) 56822688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 56922688Slepreau longname, dblock.dbuf.linkname); 57032420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo", 0L); 57132420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 57227445Slepreau (void) writetape((char *)&dblock); 57312154Ssam break; 5741119Sbill 57512154Ssam case S_IFREG: 57612154Ssam if ((infile = open(shortname, 0)) < 0) { 577*36227Sbostic fprintf(stderr, "tar: %s: %s\n", 578*36227Sbostic longname, strerror(errno)); 5791119Sbill return; 5801119Sbill } 58112154Ssam tomodes(&stbuf); 58212154Ssam if (strlen(longname) >= NAMSIZ) { 58313492Ssam fprintf(stderr, "tar: %s: file name too long\n", 58413492Ssam longname); 58521457Skjd close(infile); 58612154Ssam return; 58712154Ssam } 58812154Ssam strcpy(dblock.dbuf.name, longname); 58912154Ssam if (stbuf.st_nlink > 1) { 59012154Ssam struct linkbuf *lp; 59112154Ssam int found = 0; 59212154Ssam 59312154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 59412154Ssam if (lp->inum == stbuf.st_ino && 59512154Ssam lp->devnum == stbuf.st_dev) { 59612154Ssam found++; 59712154Ssam break; 59812154Ssam } 59912154Ssam if (found) { 60012154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 60112154Ssam dblock.dbuf.linkflag = '1'; 60232420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 60327445Slepreau (void) writetape( (char *) &dblock); 60422688Slepreau if (vflag) 60522688Slepreau fprintf(vfile, "a %s link to %s\n", 60622688Slepreau longname, lp->pathname); 60712154Ssam lp->count--; 60812154Ssam close(infile); 60912154Ssam return; 6101119Sbill } 61122688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 61222688Slepreau if (lp != NULL) { 61312154Ssam lp->nextp = ihead; 61412154Ssam ihead = lp; 61512154Ssam lp->inum = stbuf.st_ino; 61612154Ssam lp->devnum = stbuf.st_dev; 61712154Ssam lp->count = stbuf.st_nlink - 1; 61812154Ssam strcpy(lp->pathname, longname); 61912154Ssam } 6201119Sbill } 62121457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 62222688Slepreau if (vflag) 62322688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 62432420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 62521457Skjd hint = writetape((char *)&dblock); 62621457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 62727445Slepreau if ((bigbuf = malloc((unsigned)maxread)) == 0) { 62821457Skjd maxread = TBLOCK; 62921457Skjd bigbuf = buf; 63021457Skjd } 6311119Sbill 63221457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 63321457Skjd && blocks > 0) { 63421457Skjd register int nblks; 63521457Skjd 63621457Skjd nblks = ((i-1)/TBLOCK)+1; 63721457Skjd if (nblks > blocks) 63821457Skjd nblks = blocks; 63921457Skjd hint = writetbuf(bigbuf, nblks); 64021457Skjd blocks -= nblks; 64121457Skjd } 64221457Skjd close(infile); 64321457Skjd if (bigbuf != buf) 64421457Skjd free(bigbuf); 64527058Smckusick if (i < 0) { 646*36227Sbostic fprintf(stderr, "tar: Read error on %s: %s\n", 647*36227Sbostic longname, strerror(errno)); 64827058Smckusick } else if (blocks != 0 || i != 0) 64913492Ssam fprintf(stderr, "tar: %s: file changed size\n", 65013492Ssam longname); 65112154Ssam while (--blocks >= 0) 65212154Ssam putempty(); 65312154Ssam break; 65412154Ssam 65512154Ssam default: 65612154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 65713492Ssam longname); 65812154Ssam break; 6591119Sbill } 6601119Sbill } 6611119Sbill 6621119Sbill doxtract(argv) 6636250Sroot char *argv[]; 6641119Sbill { 6651119Sbill long blocks, bytes; 66627445Slepreau int ofile, i; 6671119Sbill 6681119Sbill for (;;) { 66927445Slepreau if ((i = wantit(argv)) == 0) 67027445Slepreau continue; 67127445Slepreau if (i == -1) 67227445Slepreau break; /* end of tape */ 6731119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6741119Sbill passtape(); 6751119Sbill continue; 6761119Sbill } 67712154Ssam if (Fflag) { 67812154Ssam char *s; 67912154Ssam 68012154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 68112154Ssam s = dblock.dbuf.name; 68212154Ssam else 68312154Ssam s++; 68412154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 68512154Ssam passtape(); 68612154Ssam continue; 68712154Ssam } 68812154Ssam } 68922688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 69022688Slepreau if (mflag == 0) 69122688Slepreau dodirtimes(&dblock); 6926250Sroot continue; 69322688Slepreau } 69422688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 69525250Sbloom /* 69625250Sbloom * only unlink non directories or empty 69725250Sbloom * directories 69825250Sbloom */ 69925250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 70025250Sbloom if (errno == ENOTDIR) 70125250Sbloom unlink(dblock.dbuf.name); 70225250Sbloom } 7036250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 704*36227Sbostic fprintf(stderr, 705*36227Sbostic "tar: %s: symbolic link failed: %s\n", 706*36227Sbostic dblock.dbuf.name, strerror(errno)); 7076250Sroot continue; 7086250Sroot } 7096250Sroot if (vflag) 71021910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 71113492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 71222353Skjd #ifdef notdef 71322353Skjd /* ignore alien orders */ 71422353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 71522688Slepreau if (mflag == 0) 71622688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 71722353Skjd if (pflag) 71822353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 71922353Skjd #endif 7201119Sbill continue; 7216250Sroot } 72222688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 72325250Sbloom /* 72425250Sbloom * only unlink non directories or empty 72525250Sbloom * directories 72625250Sbloom */ 72725250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 72825250Sbloom if (errno == ENOTDIR) 72925250Sbloom unlink(dblock.dbuf.name); 73025250Sbloom } 7311119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 732*36227Sbostic fprintf(stderr, 733*36227Sbostic "tar: can't link %s to %s: %s\n", 734*36227Sbostic dblock.dbuf.name, dblock.dbuf.linkname, 735*36227Sbostic strerror(errno)); 7361119Sbill continue; 7371119Sbill } 7381119Sbill if (vflag) 73922688Slepreau fprintf(vfile, "%s linked to %s\n", 74013492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7411119Sbill continue; 7421119Sbill } 7436250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 744*36227Sbostic fprintf(stderr, "tar: can't create %s: %s\n", 745*36227Sbostic dblock.dbuf.name, strerror(errno)); 7461119Sbill passtape(); 7471119Sbill continue; 7481119Sbill } 74921457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7501119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7511119Sbill if (vflag) 75222688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 75313492Ssam dblock.dbuf.name, bytes, blocks); 75421457Skjd for (; blocks > 0;) { 75521457Skjd register int nread; 75621457Skjd char *bufp; 75721457Skjd register int nwant; 75821457Skjd 75921457Skjd nwant = NBLOCK*TBLOCK; 76021457Skjd if (nwant > (blocks*TBLOCK)) 76121457Skjd nwant = (blocks*TBLOCK); 76221457Skjd nread = readtbuf(&bufp, nwant); 76322688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7646250Sroot fprintf(stderr, 765*36227Sbostic "tar: %s: HELP - extract write error: %s\n", 766*36227Sbostic dblock.dbuf.name, strerror(errno)); 7676250Sroot done(2); 7686250Sroot } 76921457Skjd bytes -= nread; 77021457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7711119Sbill } 7721119Sbill close(ofile); 77322688Slepreau if (mflag == 0) 77422688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7751926Swnj if (pflag) 7766250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7771119Sbill } 77822688Slepreau if (mflag == 0) { 77922688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 78022688Slepreau dodirtimes(&dblock); 78122688Slepreau } 7821119Sbill } 7831119Sbill 78427445Slepreau dotable(argv) 78527445Slepreau char *argv[]; 7861119Sbill { 78727445Slepreau register int i; 78827445Slepreau 7891119Sbill for (;;) { 79027445Slepreau if ((i = wantit(argv)) == 0) 79127445Slepreau continue; 79227445Slepreau if (i == -1) 79327445Slepreau break; /* end of tape */ 7941119Sbill if (vflag) 7951119Sbill longt(&stbuf); 7961119Sbill printf("%s", dblock.dbuf.name); 7971119Sbill if (dblock.dbuf.linkflag == '1') 7981119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7996250Sroot if (dblock.dbuf.linkflag == '2') 8006250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 8011119Sbill printf("\n"); 8021119Sbill passtape(); 8031119Sbill } 8041119Sbill } 8051119Sbill 8061119Sbill putempty() 8071119Sbill { 8081119Sbill char buf[TBLOCK]; 8091119Sbill 81013492Ssam bzero(buf, sizeof (buf)); 81127445Slepreau (void) writetape(buf); 8121119Sbill } 8131119Sbill 8141119Sbill longt(st) 8156250Sroot register struct stat *st; 8161119Sbill { 8171119Sbill register char *cp; 8181119Sbill char *ctime(); 8191119Sbill 8201119Sbill pmode(st); 821*36227Sbostic printf("%3u/%1u", st->st_uid, st->st_gid); 82227445Slepreau printf("%7ld", st->st_size); 8231119Sbill cp = ctime(&st->st_mtime); 8241119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8251119Sbill } 8261119Sbill 8271119Sbill #define SUID 04000 8281119Sbill #define SGID 02000 8291119Sbill #define ROWN 0400 8301119Sbill #define WOWN 0200 8311119Sbill #define XOWN 0100 8321119Sbill #define RGRP 040 8331119Sbill #define WGRP 020 8341119Sbill #define XGRP 010 8351119Sbill #define ROTH 04 8361119Sbill #define WOTH 02 8371119Sbill #define XOTH 01 8381119Sbill #define STXT 01000 8391119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8401119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8411119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8421119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8431119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8441119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8451119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8461119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8471119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8481119Sbill 8491119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8501119Sbill 8511119Sbill pmode(st) 8526250Sroot register struct stat *st; 8531119Sbill { 8541119Sbill register int **mp; 8551119Sbill 8561119Sbill for (mp = &m[0]; mp < &m[9];) 85727058Smckusick selectbits(*mp++, st); 8581119Sbill } 8591119Sbill 86027058Smckusick selectbits(pairp, st) 8616250Sroot int *pairp; 8626250Sroot struct stat *st; 8631119Sbill { 8641119Sbill register int n, *ap; 8651119Sbill 8661119Sbill ap = pairp; 8671119Sbill n = *ap++; 8681119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8691119Sbill ap++; 87027445Slepreau putchar(*ap); 8711119Sbill } 8721119Sbill 87322688Slepreau /* 87427442Slepreau * Make all directories needed by `name'. If `name' is itself 87527442Slepreau * a directory on the tar tape (indicated by a trailing '/'), 87622688Slepreau * return 1; else 0. 87722688Slepreau */ 8781119Sbill checkdir(name) 8796250Sroot register char *name; 8801119Sbill { 8811119Sbill register char *cp; 8826250Sroot 88312154Ssam /* 88422688Slepreau * Quick check for existence of directory. 88512154Ssam */ 88612154Ssam if ((cp = rindex(name, '/')) == 0) 88712154Ssam return (0); 88812154Ssam *cp = '\0'; 889*36227Sbostic if (access(name, F_OK) == 0) { /* already exists */ 89012154Ssam *cp = '/'; 89122688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 89212154Ssam } 89312154Ssam *cp = '/'; 89412154Ssam 89512154Ssam /* 89612154Ssam * No luck, try to make all directories in path. 89712154Ssam */ 8981119Sbill for (cp = name; *cp; cp++) { 8996250Sroot if (*cp != '/') 9006250Sroot continue; 9016250Sroot *cp = '\0'; 902*36227Sbostic if (access(name, F_OK) < 0) { 9039844Ssam if (mkdir(name, 0777) < 0) { 904*36227Sbostic fprintf(stderr, "tar: mkdir: %s: %s\n", 905*36227Sbostic name, strerror(errno)); 90612154Ssam *cp = '/'; 90712154Ssam return (0); 9081119Sbill } 90921457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 91027442Slepreau if (pflag && cp[1] == '\0') /* dir on the tape */ 91127442Slepreau chmod(name, stbuf.st_mode & 07777); 9121119Sbill } 9136250Sroot *cp = '/'; 9141119Sbill } 9156250Sroot return (cp[-1]=='/'); 9161119Sbill } 9171119Sbill 9181119Sbill onintr() 9191119Sbill { 92027445Slepreau (void) signal(SIGINT, SIG_IGN); 9211119Sbill term++; 9221119Sbill } 9231119Sbill 9241119Sbill onquit() 9251119Sbill { 92627445Slepreau (void) signal(SIGQUIT, SIG_IGN); 9271119Sbill term++; 9281119Sbill } 9291119Sbill 9301119Sbill onhup() 9311119Sbill { 93227445Slepreau (void) signal(SIGHUP, SIG_IGN); 9331119Sbill term++; 9341119Sbill } 9351119Sbill 93622688Slepreau #ifdef notdef 9371119Sbill onterm() 9381119Sbill { 93927445Slepreau (void) signal(SIGTERM, SIG_IGN); 9401119Sbill term++; 9411119Sbill } 94222688Slepreau #endif 9431119Sbill 9441119Sbill tomodes(sp) 9451119Sbill register struct stat *sp; 9461119Sbill { 9471119Sbill register char *cp; 9481119Sbill 9491119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9501119Sbill *cp = '\0'; 95132420Sbostic (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 95232420Sbostic (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 95332420Sbostic (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 95432420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 95532420Sbostic (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9561119Sbill } 9571119Sbill 9581119Sbill checksum() 9591119Sbill { 9601119Sbill register i; 9611119Sbill register char *cp; 9621119Sbill 9636250Sroot for (cp = dblock.dbuf.chksum; 9646250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9651119Sbill *cp = ' '; 9661119Sbill i = 0; 9671119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9681119Sbill i += *cp; 9696250Sroot return (i); 9701119Sbill } 9711119Sbill 9721119Sbill checkw(c, name) 9736250Sroot char *name; 9741119Sbill { 9756250Sroot if (!wflag) 9766250Sroot return (1); 9776250Sroot printf("%c ", c); 9786250Sroot if (vflag) 9796250Sroot longt(&stbuf); 9806250Sroot printf("%s: ", name); 9816250Sroot return (response() == 'y'); 9821119Sbill } 9831119Sbill 9841119Sbill response() 9851119Sbill { 9861119Sbill char c; 9871119Sbill 9881119Sbill c = getchar(); 9891119Sbill if (c != '\n') 9906250Sroot while (getchar() != '\n') 9916250Sroot ; 9926250Sroot else 9936250Sroot c = 'n'; 9946250Sroot return (c); 9951119Sbill } 9961119Sbill 99712154Ssam checkf(name, mode, howmuch) 99812154Ssam char *name; 99912154Ssam int mode, howmuch; 100012154Ssam { 100112154Ssam int l; 100212154Ssam 100321910Skjd if ((mode & S_IFMT) == S_IFDIR){ 100421910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 100521910Skjd return(0); 100621910Skjd return(1); 100721910Skjd } 100812154Ssam if ((l = strlen(name)) < 3) 100912154Ssam return (1); 101012154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 101112154Ssam return (0); 101212154Ssam if (strcmp(name, "core") == 0 || 101312154Ssam strcmp(name, "errs") == 0 || 101412154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 101512154Ssam return (0); 101612154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 101712154Ssam return (1); 101812154Ssam } 101912154Ssam 102022688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 10211119Sbill checkupdate(arg) 10226250Sroot char *arg; 10231119Sbill { 10241119Sbill char name[100]; 10256250Sroot long mtime; 10261119Sbill daddr_t seekp; 10271119Sbill daddr_t lookup(); 10281119Sbill 10291119Sbill rewind(tfile); 10301119Sbill for (;;) { 10311119Sbill if ((seekp = lookup(arg)) < 0) 10326250Sroot return (1); 10331119Sbill fseek(tfile, seekp, 0); 10341119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10356250Sroot return (stbuf.st_mtime > mtime); 10361119Sbill } 10371119Sbill } 10381119Sbill 10391119Sbill done(n) 10401119Sbill { 104121457Skjd unlink(tname); 10421119Sbill exit(n); 10431119Sbill } 10441119Sbill 104527445Slepreau /* 104627445Slepreau * Do we want the next entry on the tape, i.e. is it selected? If 104727445Slepreau * not, skip over the entire entry. Return -1 if reached end of tape. 104827445Slepreau */ 104927445Slepreau wantit(argv) 105027445Slepreau char *argv[]; 105127445Slepreau { 105227445Slepreau register char **cp; 105327445Slepreau 105427445Slepreau getdir(); 105527445Slepreau if (endtape()) 105627445Slepreau return (-1); 105727445Slepreau if (*argv == 0) 105827445Slepreau return (1); 105927445Slepreau for (cp = argv; *cp; cp++) 106027445Slepreau if (prefix(*cp, dblock.dbuf.name)) 106127445Slepreau return (1); 106227445Slepreau passtape(); 106327445Slepreau return (0); 106427445Slepreau } 106527445Slepreau 106622688Slepreau /* 106722688Slepreau * Does s2 begin with the string s1, on a directory boundary? 106822688Slepreau */ 10691119Sbill prefix(s1, s2) 10706250Sroot register char *s1, *s2; 10711119Sbill { 10721119Sbill while (*s1) 10731119Sbill if (*s1++ != *s2++) 10746250Sroot return (0); 10751119Sbill if (*s2) 10766250Sroot return (*s2 == '/'); 10776250Sroot return (1); 10781119Sbill } 10791119Sbill 10801119Sbill #define N 200 10811119Sbill int njab; 10826250Sroot 10831119Sbill daddr_t 10841119Sbill lookup(s) 10856250Sroot char *s; 10861119Sbill { 10871119Sbill register i; 10881119Sbill daddr_t a; 10891119Sbill 10901119Sbill for(i=0; s[i]; i++) 10916250Sroot if (s[i] == ' ') 10921119Sbill break; 10931119Sbill a = bsrch(s, i, low, high); 10946250Sroot return (a); 10951119Sbill } 10961119Sbill 10971119Sbill daddr_t 10981119Sbill bsrch(s, n, l, h) 10996250Sroot daddr_t l, h; 11006250Sroot char *s; 11011119Sbill { 11021119Sbill register i, j; 11031119Sbill char b[N]; 11041119Sbill daddr_t m, m1; 11051119Sbill 11061119Sbill njab = 0; 11071119Sbill 11081119Sbill loop: 11096250Sroot if (l >= h) 111022688Slepreau return ((daddr_t) -1); 11111119Sbill m = l + (h-l)/2 - N/2; 11126250Sroot if (m < l) 11131119Sbill m = l; 11141119Sbill fseek(tfile, m, 0); 11151119Sbill fread(b, 1, N, tfile); 11161119Sbill njab++; 11171119Sbill for(i=0; i<N; i++) { 11186250Sroot if (b[i] == '\n') 11191119Sbill break; 11201119Sbill m++; 11211119Sbill } 11226250Sroot if (m >= h) 112322688Slepreau return ((daddr_t) -1); 11241119Sbill m1 = m; 11251119Sbill j = i; 11261119Sbill for(i++; i<N; i++) { 11271119Sbill m1++; 11286250Sroot if (b[i] == '\n') 11291119Sbill break; 11301119Sbill } 11311119Sbill i = cmp(b+j, s, n); 11326250Sroot if (i < 0) { 11331119Sbill h = m; 11341119Sbill goto loop; 11351119Sbill } 11366250Sroot if (i > 0) { 11371119Sbill l = m1; 11381119Sbill goto loop; 11391119Sbill } 11406250Sroot return (m); 11411119Sbill } 11421119Sbill 11431119Sbill cmp(b, s, n) 11446250Sroot char *b, *s; 11451119Sbill { 11461119Sbill register i; 11471119Sbill 11486250Sroot if (b[0] != '\n') 114921457Skjd exit(2); 11501119Sbill for(i=0; i<n; i++) { 11516250Sroot if (b[i+1] > s[i]) 11526250Sroot return (-1); 11536250Sroot if (b[i+1] < s[i]) 11546250Sroot return (1); 11551119Sbill } 11566250Sroot return (b[i+1] == ' '? 0 : -1); 11571119Sbill } 11581119Sbill 115922688Slepreau readtape(buffer) 11606250Sroot char *buffer; 11611119Sbill { 116221457Skjd char *bufp; 116321457Skjd 116422688Slepreau if (first == 0) 116522688Slepreau getbuf(); 116627445Slepreau (void) readtbuf(&bufp, TBLOCK); 116721457Skjd bcopy(bufp, buffer, TBLOCK); 116821457Skjd return(TBLOCK); 116921457Skjd } 117021457Skjd 117121457Skjd readtbuf(bufpp, size) 117221457Skjd char **bufpp; 117321457Skjd int size; 117421457Skjd { 11753457Swnj register int i; 11761119Sbill 11771119Sbill if (recno >= nblock || first == 0) { 117827445Slepreau if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 117927058Smckusick mterr("read", i, 3); 11801119Sbill if (first == 0) { 11811119Sbill if ((i % TBLOCK) != 0) { 118213492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11831119Sbill done(3); 11841119Sbill } 11851119Sbill i /= TBLOCK; 11863457Swnj if (i != nblock) { 118713492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11881119Sbill nblock = i; 11891119Sbill } 119022353Skjd first = 1; 11911119Sbill } 11921119Sbill recno = 0; 11931119Sbill } 119421457Skjd if (size > ((nblock-recno)*TBLOCK)) 119521457Skjd size = (nblock-recno)*TBLOCK; 119621457Skjd *bufpp = (char *)&tbuf[recno]; 119721457Skjd recno += (size/TBLOCK); 119821457Skjd return (size); 11991119Sbill } 12001119Sbill 120121457Skjd writetbuf(buffer, n) 120221457Skjd register char *buffer; 120321457Skjd register int n; 12041119Sbill { 120527058Smckusick int i; 120622688Slepreau 120722688Slepreau if (first == 0) { 120822353Skjd getbuf(); 120922353Skjd first = 1; 121022353Skjd } 12111119Sbill if (recno >= nblock) { 121227445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 121327058Smckusick if (i != TBLOCK*nblock) 121427058Smckusick mterr("write", i, 2); 12151119Sbill recno = 0; 12161119Sbill } 121721457Skjd 121821457Skjd /* 121921457Skjd * Special case: We have an empty tape buffer, and the 122021457Skjd * users data size is >= the tape block size: Avoid 122121457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 122221457Skjd * residual to the tape buffer. 122321457Skjd */ 122421457Skjd while (recno == 0 && n >= nblock) { 122527058Smckusick i = write(mt, buffer, TBLOCK*nblock); 122627058Smckusick if (i != TBLOCK*nblock) 122727058Smckusick mterr("write", i, 2); 122821457Skjd n -= nblock; 122921457Skjd buffer += (nblock * TBLOCK); 12301119Sbill } 123121457Skjd 123221457Skjd while (n-- > 0) { 123321457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 123421457Skjd buffer += TBLOCK; 123521457Skjd if (recno >= nblock) { 123627445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 123727058Smckusick if (i != TBLOCK*nblock) 123827058Smckusick mterr("write", i, 2); 123921457Skjd recno = 0; 124021457Skjd } 124121457Skjd } 124221457Skjd 124321457Skjd /* Tell the user how much to write to get in sync */ 124421457Skjd return (nblock - recno); 12451119Sbill } 12461119Sbill 12471119Sbill backtape() 12481119Sbill { 124927058Smckusick static int mtdev = 1; 12503457Swnj static struct mtop mtop = {MTBSR, 1}; 125127058Smckusick struct mtget mtget; 125227058Smckusick 125327058Smckusick if (mtdev == 1) 125427445Slepreau mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 12553457Swnj if (mtdev == 0) { 125627445Slepreau if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 1257*36227Sbostic fprintf(stderr, "tar: tape backspace error: %s\n", 1258*36227Sbostic strerror(errno)); 12591119Sbill done(4); 12601119Sbill } 12613457Swnj } else 1262*36227Sbostic (void)lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 12633457Swnj recno--; 12641119Sbill } 12651119Sbill 12661119Sbill flushtape() 12671119Sbill { 126827058Smckusick int i; 126927058Smckusick 127027445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 127127058Smckusick if (i != TBLOCK*nblock) 127227058Smckusick mterr("write", i, 2); 12731119Sbill } 12741119Sbill 127527058Smckusick mterr(operation, i, exitcode) 127627058Smckusick char *operation; 127727058Smckusick int i; 127827058Smckusick { 1279*36227Sbostic fprintf(stderr, "tar: tape %s error: %s\n", 1280*36227Sbostic operation, i < 0 ? strerror(errno) : "unexpected EOF"); 128127058Smckusick done(exitcode); 128227058Smckusick } 128327058Smckusick 12848737Smckusick bread(fd, buf, size) 12858737Smckusick int fd; 12868737Smckusick char *buf; 12878737Smckusick int size; 12888737Smckusick { 12898737Smckusick int count; 12908737Smckusick static int lastread = 0; 12918737Smckusick 129222688Slepreau if (!Bflag) 129322688Slepreau return (read(fd, buf, size)); 129422353Skjd 12958737Smckusick for (count = 0; count < size; count += lastread) { 129624281Smckusick lastread = read(fd, buf, size - count); 129724281Smckusick if (lastread <= 0) { 12988737Smckusick if (count > 0) 12998737Smckusick return (count); 13008737Smckusick return (lastread); 13018737Smckusick } 13028737Smckusick buf += lastread; 13038737Smckusick } 13048737Smckusick return (count); 13058737Smckusick } 130610165Ssam 130710165Ssam char * 130810165Ssam getcwd(buf) 130910165Ssam char *buf; 131010165Ssam { 131110165Ssam if (getwd(buf) == NULL) { 131210165Ssam fprintf(stderr, "tar: %s\n", buf); 131321457Skjd exit(1); 131410165Ssam } 131510165Ssam return (buf); 131610165Ssam } 131721910Skjd 131821910Skjd getbuf() 131921910Skjd { 132022353Skjd 132127058Smckusick if (nblock == 0) { 132221910Skjd fstat(mt, &stbuf); 132321910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 132427058Smckusick nblock = NBLOCK; 132521910Skjd else { 132627058Smckusick nblock = stbuf.st_blksize / TBLOCK; 132727058Smckusick if (nblock == 0) 132827058Smckusick nblock = NBLOCK; 132921910Skjd } 133021910Skjd } 133127445Slepreau tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 133221910Skjd if (tbuf == NULL) { 133321910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 133421910Skjd nblock); 133521910Skjd done(1); 133621910Skjd } 133721910Skjd } 133822353Skjd 133922688Slepreau /* 134027442Slepreau * Save this directory and its mtime on the stack, popping and setting 134127442Slepreau * the mtimes of any stacked dirs which aren't parents of this one. 134227442Slepreau * A null directory causes the entire stack to be unwound and set. 134322688Slepreau * 134427442Slepreau * Since all the elements of the directory "stack" share a common 134527442Slepreau * prefix, we can make do with one string. We keep only the current 134627442Slepreau * directory path, with an associated array of mtime's, one for each 134727442Slepreau * '/' in the path. A negative mtime means no mtime. The mtime's are 134827442Slepreau * offset by one (first index 1, not 0) because calling this with a null 134927442Slepreau * directory causes mtime[0] to be set. 135027442Slepreau * 135122688Slepreau * This stack algorithm is not guaranteed to work for tapes created 135222688Slepreau * with the 'r' option, but the vast majority of tapes with 135322688Slepreau * directories are not. This avoids saving every directory record on 135422688Slepreau * the tape and setting all the times at the end. 135522688Slepreau */ 135622688Slepreau char dirstack[NAMSIZ]; 135722688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 135822688Slepreau time_t mtime[NTIM]; 135922353Skjd 136022688Slepreau dodirtimes(hp) 136122688Slepreau union hblock *hp; 136222353Skjd { 136322688Slepreau register char *p = dirstack; 136422688Slepreau register char *q = hp->dbuf.name; 136522688Slepreau register int ndir = 0; 136622688Slepreau char *savp; 136722688Slepreau int savndir; 136822353Skjd 136922688Slepreau /* Find common prefix */ 137030090Sbostic while (*p == *q && *p) { 137122688Slepreau if (*p++ == '/') 137222688Slepreau ++ndir; 137322688Slepreau q++; 137422688Slepreau } 137522353Skjd 137622688Slepreau savp = p; 137722688Slepreau savndir = ndir; 137822688Slepreau while (*p) { 137922688Slepreau /* 138022688Slepreau * Not a child: unwind the stack, setting the times. 138122688Slepreau * The order we do this doesn't matter, so we go "forward." 138222688Slepreau */ 138322688Slepreau if (*p++ == '/') 138422688Slepreau if (mtime[++ndir] >= 0) { 138522688Slepreau *--p = '\0'; /* zap the slash */ 138622688Slepreau setimes(dirstack, mtime[ndir]); 138722688Slepreau *p++ = '/'; 138822688Slepreau } 138922688Slepreau } 139022688Slepreau p = savp; 139122688Slepreau ndir = savndir; 139222353Skjd 139322688Slepreau /* Push this one on the "stack" */ 139422688Slepreau while (*p = *q++) /* append the rest of the new dir */ 139522688Slepreau if (*p++ == '/') 139622688Slepreau mtime[++ndir] = -1; 139722688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 139822688Slepreau } 139922353Skjd 140022688Slepreau setimes(path, mt) 140122688Slepreau char *path; 140222688Slepreau time_t mt; 140322688Slepreau { 140422688Slepreau struct timeval tv[2]; 140522353Skjd 140622688Slepreau tv[0].tv_sec = time((time_t *) 0); 140722688Slepreau tv[1].tv_sec = mt; 140822688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 1409*36227Sbostic if (utimes(path, tv) < 0) 1410*36227Sbostic fprintf(stderr, "tar: can't set time on %s: %s\n", 1411*36227Sbostic path, strerror(errno)); 141222688Slepreau } 141322688Slepreau 141422688Slepreau char * 141522688Slepreau getmem(size) 141622688Slepreau { 141722688Slepreau char *p = malloc((unsigned) size); 141822688Slepreau 141922688Slepreau if (p == NULL && freemem) { 142022688Slepreau fprintf(stderr, 142122688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 142222688Slepreau freemem = 0; 142322353Skjd } 142422688Slepreau return (p); 142522353Skjd } 1426