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*37681Sbostic static char sccsid[] = "@(#)tar.c 5.14 (Berkeley) 05/08/89"; 1533082Sbostic #endif /* not lint */ 1622502Sdist 176250Sroot /* 186250Sroot * Tape Archival Program 196250Sroot */ 206413Smckusic #include <sys/param.h> 211119Sbill #include <sys/stat.h> 2236227Sbostic #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> 3036227Sbostic #include <strings.h> 3136227Sbostic #include <stdio.h> 32*37681Sbostic #include "pathnames.h" 331119Sbill 341119Sbill #define TBLOCK 512 353355Swnj #define NBLOCK 20 361119Sbill #define NAMSIZ 100 376250Sroot 3821457Skjd #define writetape(b) writetbuf(b, 1) 3921457Skjd #define min(a,b) ((a) < (b) ? (a) : (b)) 4021457Skjd #define max(a,b) ((a) > (b) ? (a) : (b)) 4121457Skjd 421119Sbill union hblock { 431119Sbill char dummy[TBLOCK]; 441119Sbill struct header { 451119Sbill char name[NAMSIZ]; 461119Sbill char mode[8]; 471119Sbill char uid[8]; 481119Sbill char gid[8]; 491119Sbill char size[12]; 501119Sbill char mtime[12]; 511119Sbill char chksum[8]; 521119Sbill char linkflag; 531119Sbill char linkname[NAMSIZ]; 541119Sbill } dbuf; 556250Sroot }; 561119Sbill 571119Sbill struct linkbuf { 581119Sbill ino_t inum; 591119Sbill dev_t devnum; 601119Sbill int count; 611119Sbill char pathname[NAMSIZ]; 621119Sbill struct linkbuf *nextp; 636250Sroot }; 641119Sbill 656250Sroot union hblock dblock; 6613492Ssam union hblock *tbuf; 676250Sroot struct linkbuf *ihead; 686250Sroot struct stat stbuf; 691119Sbill 706250Sroot int rflag; 7134429Sbostic int sflag; 726250Sroot int xflag; 736250Sroot int vflag; 746250Sroot int tflag; 756250Sroot int cflag; 766250Sroot int mflag; 776250Sroot int fflag; 7812154Ssam int iflag; 796250Sroot int oflag; 806250Sroot int pflag; 816250Sroot int wflag; 826250Sroot int hflag; 838737Smckusick int Bflag; 8412154Ssam int Fflag; 856250Sroot 866250Sroot int mt; 876250Sroot int term; 886250Sroot int chksum; 896250Sroot int recno; 9022688Slepreau int first; 9122688Slepreau int prtlinkerr; 921119Sbill int freemem = 1; 9322353Skjd int nblock = 0; 946250Sroot int onintr(); 956250Sroot int onquit(); 966250Sroot int onhup(); 9722688Slepreau #ifdef notdef 986250Sroot int onterm(); 9922688Slepreau #endif 1001119Sbill 1011119Sbill daddr_t low; 1021119Sbill daddr_t high; 1036250Sroot daddr_t bsrch(); 1041119Sbill 10521910Skjd FILE *vfile = stdout; 1061119Sbill FILE *tfile; 107*37681Sbostic char tname[] = _PATH_TMP; 1081119Sbill char *usefile; 109*37681Sbostic char magtape[] = _PATH_MAGTAPE; 1101119Sbill char *malloc(); 11127445Slepreau long time(); 11227445Slepreau off_t lseek(); 11327445Slepreau char *mktemp(); 11410165Ssam char *getcwd(); 1159844Ssam char *getwd(); 11622688Slepreau char *getmem(); 1171119Sbill 11836227Sbostic extern int errno; 11936227Sbostic 1201119Sbill main(argc, argv) 12136227Sbostic int argc; 12236227Sbostic char **argv; 1231119Sbill { 1241119Sbill char *cp; 1251119Sbill 1261119Sbill if (argc < 2) 1271119Sbill usage(); 1281119Sbill 1291119Sbill tfile = NULL; 1301119Sbill usefile = magtape; 1311119Sbill argv[argc] = 0; 1321119Sbill argv++; 1331119Sbill for (cp = *argv++; *cp; cp++) 1341119Sbill switch(*cp) { 1356250Sroot 1361119Sbill case 'f': 13712154Ssam if (*argv == 0) { 13812154Ssam fprintf(stderr, 13912154Ssam "tar: tapefile must be specified with 'f' option\n"); 14012154Ssam usage(); 14112154Ssam } 1421119Sbill usefile = *argv++; 1431119Sbill fflag++; 1441119Sbill break; 1456250Sroot 1461119Sbill case 'c': 1471119Sbill cflag++; 1481119Sbill rflag++; 1491119Sbill break; 1506250Sroot 1511119Sbill case 'o': 1521119Sbill oflag++; 1531119Sbill break; 1546250Sroot 1551119Sbill case 'p': 1561119Sbill pflag++; 1571119Sbill break; 1586250Sroot 1591119Sbill case 'u': 16036227Sbostic (void)mktemp(tname); 1611119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1626250Sroot fprintf(stderr, 16322688Slepreau "tar: cannot create temporary file (%s)\n", 1646250Sroot tname); 1651119Sbill done(1); 1661119Sbill } 1671119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1686250Sroot /*FALL THRU*/ 1696250Sroot 1701119Sbill case 'r': 1711119Sbill rflag++; 1721119Sbill break; 1736250Sroot 17434429Sbostic case 's': 17534429Sbostic sflag++; 17634429Sbostic break; 17734429Sbostic 1781119Sbill case 'v': 1791119Sbill vflag++; 1801119Sbill break; 1816250Sroot 1821119Sbill case 'w': 1831119Sbill wflag++; 1841119Sbill break; 1856250Sroot 1861119Sbill case 'x': 1871119Sbill xflag++; 1881119Sbill break; 1896250Sroot 1901119Sbill case 't': 1911119Sbill tflag++; 1921119Sbill break; 1936250Sroot 1941119Sbill case 'm': 1951119Sbill mflag++; 1961119Sbill break; 1976250Sroot 1981119Sbill case '-': 1991119Sbill break; 2006250Sroot 2011119Sbill case '0': 2021119Sbill case '1': 2031119Sbill case '4': 2041119Sbill case '5': 20521457Skjd case '7': 2061119Sbill case '8': 2071119Sbill magtape[8] = *cp; 2081119Sbill usefile = magtape; 2091119Sbill break; 2106250Sroot 2111119Sbill case 'b': 21213492Ssam if (*argv == 0) { 21313492Ssam fprintf(stderr, 21413492Ssam "tar: blocksize must be specified with 'b' option\n"); 21513492Ssam usage(); 21613492Ssam } 21713492Ssam nblock = atoi(*argv); 21813492Ssam if (nblock <= 0) { 21913492Ssam fprintf(stderr, 22013492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2211119Sbill done(1); 2221119Sbill } 22313492Ssam argv++; 2241119Sbill break; 2256250Sroot 2261119Sbill case 'l': 22722688Slepreau prtlinkerr++; 2281119Sbill break; 2296250Sroot 2306250Sroot case 'h': 2316250Sroot hflag++; 2326250Sroot break; 2336250Sroot 23412154Ssam case 'i': 23512154Ssam iflag++; 23612154Ssam break; 23712154Ssam 2388737Smckusick case 'B': 2398737Smckusick Bflag++; 2408737Smckusick break; 2418737Smckusick 24212154Ssam case 'F': 24312154Ssam Fflag++; 24412154Ssam break; 24512154Ssam 2461119Sbill default: 2471119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2481119Sbill usage(); 2491119Sbill } 2501119Sbill 2516250Sroot if (!rflag && !xflag && !tflag) 2526250Sroot usage(); 2531119Sbill if (rflag) { 2546250Sroot if (cflag && tfile != NULL) 2551119Sbill usage(); 2561119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 25727445Slepreau (void) signal(SIGINT, onintr); 2581119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 25927445Slepreau (void) signal(SIGHUP, onhup); 2601119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 26127445Slepreau (void) signal(SIGQUIT, onquit); 2626250Sroot #ifdef notdef 2631119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 26427445Slepreau (void) signal(SIGTERM, onterm); 2656250Sroot #endif 26627058Smckusick mt = openmt(usefile, 1); 2671119Sbill dorep(argv); 2686250Sroot done(0); 2691119Sbill } 27027058Smckusick mt = openmt(usefile, 0); 2716250Sroot if (xflag) 2721119Sbill doxtract(argv); 2736250Sroot else 27427445Slepreau dotable(argv); 2751119Sbill done(0); 2761119Sbill } 2771119Sbill 2781119Sbill usage() 2791119Sbill { 2806250Sroot fprintf(stderr, 28121457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2821119Sbill done(1); 2831119Sbill } 2841119Sbill 28527058Smckusick int 28627058Smckusick openmt(tape, writing) 28727058Smckusick char *tape; 28827058Smckusick int writing; 28927058Smckusick { 29027058Smckusick if (strcmp(tape, "-") == 0) { 29127058Smckusick /* 29227058Smckusick * Read from standard input or write to standard output. 29327058Smckusick */ 29427058Smckusick if (writing) { 29527058Smckusick if (cflag == 0) { 29627058Smckusick fprintf(stderr, 29727058Smckusick "tar: can only create standard output archives\n"); 29827058Smckusick done(1); 29927058Smckusick } 30027058Smckusick vfile = stderr; 30127058Smckusick setlinebuf(vfile); 30227058Smckusick mt = dup(1); 30327058Smckusick } else { 30427058Smckusick mt = dup(0); 30527058Smckusick Bflag++; 30627058Smckusick } 30727058Smckusick } else { 30827058Smckusick /* 30927058Smckusick * Use file or tape on local machine. 31027058Smckusick */ 31127058Smckusick if (writing) { 31227058Smckusick if (cflag) 31327445Slepreau mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); 31427058Smckusick else 31527058Smckusick mt = open(tape, O_RDWR); 31627058Smckusick } else 31727058Smckusick mt = open(tape, O_RDONLY); 31827058Smckusick if (mt < 0) { 31936227Sbostic fprintf(stderr, "tar: %s: %s\n", tape, strerror(errno)); 32027058Smckusick done(1); 32127058Smckusick } 32227058Smckusick } 32327058Smckusick return(mt); 32427058Smckusick } 32527058Smckusick 3261119Sbill dorep(argv) 3276250Sroot char *argv[]; 3281119Sbill { 3291119Sbill register char *cp, *cp2; 3309601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 3311119Sbill 3321119Sbill if (!cflag) { 3331119Sbill getdir(); 3341119Sbill do { 3351119Sbill passtape(); 3361119Sbill if (term) 3371119Sbill done(0); 3381119Sbill getdir(); 3391119Sbill } while (!endtape()); 34013492Ssam backtape(); 3411119Sbill if (tfile != NULL) { 3421119Sbill char buf[200]; 3431119Sbill 34432420Sbostic (void)sprintf(buf, 3456250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3461119Sbill tname, tname, tname, tname, tname, tname); 3471119Sbill fflush(tfile); 3481119Sbill system(buf); 3491119Sbill freopen(tname, "r", tfile); 3501119Sbill fstat(fileno(tfile), &stbuf); 3511119Sbill high = stbuf.st_size; 3521119Sbill } 3531119Sbill } 3541119Sbill 35510165Ssam (void) getcwd(wdir); 3561119Sbill while (*argv && ! term) { 3571119Sbill cp2 = *argv; 3581119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3591119Sbill argv++; 36027058Smckusick if (chdir(*argv) < 0) { 36136227Sbostic fprintf(stderr, 36236227Sbostic "tar: can't change directories to %s: %s\n", 36336227Sbostic *argv, strerror(errno)); 36427058Smckusick } else 36510165Ssam (void) getcwd(wdir); 3661119Sbill argv++; 3671119Sbill continue; 3681119Sbill } 3699601Ssam parent = wdir; 3701119Sbill for (cp = *argv; *cp; cp++) 3711119Sbill if (*cp == '/') 3721119Sbill cp2 = cp; 3731119Sbill if (cp2 != *argv) { 3741119Sbill *cp2 = '\0'; 3759601Ssam if (chdir(*argv) < 0) { 37636227Sbostic fprintf(stderr, 37736227Sbostic "tar: can't change directories to %s: %s\n", 37836227Sbostic *argv, strerror(errno)); 3799601Ssam continue; 3809601Ssam } 38110165Ssam parent = getcwd(tempdir); 3821119Sbill *cp2 = '/'; 3831119Sbill cp2++; 3841119Sbill } 3859601Ssam putfile(*argv++, cp2, parent); 38636227Sbostic if (chdir(wdir) < 0) 38736227Sbostic fprintf(stderr, "tar: cannot change back?: %s: %s\n", 38836227Sbostic wdir, strerror(errno)); 3891119Sbill } 3901119Sbill putempty(); 3911119Sbill putempty(); 3921119Sbill flushtape(); 39322688Slepreau if (prtlinkerr == 0) 3946250Sroot return; 3956250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3966250Sroot if (ihead->count == 0) 3976250Sroot continue; 39813492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3996250Sroot } 4001119Sbill } 4011119Sbill 4021119Sbill endtape() 4031119Sbill { 40421457Skjd return (dblock.dbuf.name[0] == '\0'); 4051119Sbill } 4061119Sbill 4071119Sbill getdir() 4081119Sbill { 4091119Sbill register struct stat *sp; 4101119Sbill int i; 4111119Sbill 41212154Ssam top: 4136250Sroot readtape((char *)&dblock); 4141119Sbill if (dblock.dbuf.name[0] == '\0') 4151119Sbill return; 4161119Sbill sp = &stbuf; 4171119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4181119Sbill sp->st_mode = i; 4191119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4201119Sbill sp->st_uid = i; 4211119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4221119Sbill sp->st_gid = i; 4231119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4241119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4251119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 42612154Ssam if (chksum != (i = checksum())) { 42713492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 42812154Ssam chksum, i); 42912154Ssam if (iflag) 43012154Ssam goto top; 4311119Sbill done(2); 4321119Sbill } 43334429Sbostic /* strip off leading "/" if present */ 43434429Sbostic if (sflag && dblock.dbuf.name[0] == '/') { 43534429Sbostic register char *cp1, *cp2; 43634429Sbostic for (cp1 = cp2 = dblock.dbuf.name; *cp2 && *cp2 == '/'; ++cp2); 43734429Sbostic if (!*cp2) 43834429Sbostic goto top; 43934429Sbostic while (*cp1++ = *cp2++); 44034429Sbostic } 4411119Sbill if (tfile != NULL) 4421119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4431119Sbill } 4441119Sbill 4451119Sbill passtape() 4461119Sbill { 4471119Sbill long blocks; 44821457Skjd char *bufp; 4491119Sbill 4501119Sbill if (dblock.dbuf.linkflag == '1') 4511119Sbill return; 4521119Sbill blocks = stbuf.st_size; 4531119Sbill blocks += TBLOCK-1; 4541119Sbill blocks /= TBLOCK; 4551119Sbill 45621457Skjd while (blocks-- > 0) 45727445Slepreau (void) readtbuf(&bufp, TBLOCK); 4581119Sbill } 4591119Sbill 4609601Ssam putfile(longname, shortname, parent) 4616250Sroot char *longname; 4626250Sroot char *shortname; 4639601Ssam char *parent; 4641119Sbill { 46521457Skjd int infile = 0; 46621457Skjd long blocks; 4671119Sbill char buf[TBLOCK]; 46821457Skjd char *bigbuf; 46922688Slepreau register char *cp; 4705931Smckusic struct direct *dp; 4715931Smckusic DIR *dirp; 47227445Slepreau register int i; 47327445Slepreau long l; 4749601Ssam char newparent[NAMSIZ+64]; 47521457Skjd int maxread; 47621457Skjd int hint; /* amount to write to get "in sync" */ 4771119Sbill 4789601Ssam if (!hflag) 47912154Ssam i = lstat(shortname, &stbuf); 48012154Ssam else 48112154Ssam i = stat(shortname, &stbuf); 48212154Ssam if (i < 0) { 48336227Sbostic fprintf(stderr, "tar: %s: %s\n", longname, strerror(errno)); 4849601Ssam return; 4859601Ssam } 48612154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4871119Sbill return; 48812154Ssam if (checkw('r', longname) == 0) 4891119Sbill return; 49012154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 49112154Ssam return; 4921119Sbill 49312154Ssam switch (stbuf.st_mode & S_IFMT) { 49412154Ssam case S_IFDIR: 4956250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4966250Sroot ; 4971119Sbill *--cp = '/'; 4981119Sbill *++cp = 0 ; 4991119Sbill if (!oflag) { 5006250Sroot if ((cp - buf) >= NAMSIZ) { 50113492Ssam fprintf(stderr, "tar: %s: file name too long\n", 50213492Ssam longname); 5036250Sroot return; 5046250Sroot } 5056250Sroot stbuf.st_size = 0; 5066250Sroot tomodes(&stbuf); 5076250Sroot strcpy(dblock.dbuf.name,buf); 50832420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 50927445Slepreau (void) writetape((char *)&dblock); 5101119Sbill } 51132420Sbostic (void)sprintf(newparent, "%s/%s", parent, shortname); 51215045Smckusick if (chdir(shortname) < 0) { 51336227Sbostic fprintf(stderr, "tar: chdir %s: %s\n", 51436227Sbostic shortname, strerror(errno)); 51515045Smckusick return; 51615045Smckusick } 5175931Smckusic if ((dirp = opendir(".")) == NULL) { 51813492Ssam fprintf(stderr, "tar: %s: directory read error\n", 51913492Ssam longname); 52015045Smckusick if (chdir(parent) < 0) { 52136227Sbostic fprintf(stderr, 52236227Sbostic "tar: cannot change back?: %s: %s\n", 52336227Sbostic parent, strerror(errno)); 52415045Smckusick } 5255931Smckusic return; 5265931Smckusic } 5275931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5286250Sroot if (!strcmp(".", dp->d_name) || 5296250Sroot !strcmp("..", dp->d_name)) 5301119Sbill continue; 5315931Smckusic strcpy(cp, dp->d_name); 53227445Slepreau l = telldir(dirp); 5335931Smckusic closedir(dirp); 5349601Ssam putfile(buf, cp, newparent); 5355931Smckusic dirp = opendir("."); 53627445Slepreau seekdir(dirp, l); 5371119Sbill } 5385931Smckusic closedir(dirp); 53915045Smckusick if (chdir(parent) < 0) { 54036227Sbostic fprintf(stderr, 54136227Sbostic "tar: cannot change back?: %s: %s\n", 54236227Sbostic parent, strerror(errno)); 54315045Smckusick } 54412154Ssam break; 54512154Ssam 54612154Ssam case S_IFLNK: 54712154Ssam tomodes(&stbuf); 54812154Ssam if (strlen(longname) >= NAMSIZ) { 54913492Ssam fprintf(stderr, "tar: %s: file name too long\n", 55013492Ssam longname); 55112154Ssam return; 55212154Ssam } 55312154Ssam strcpy(dblock.dbuf.name, longname); 5546250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 55513492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 55613492Ssam longname); 5576250Sroot return; 5586250Sroot } 5599601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5606250Sroot if (i < 0) { 56136227Sbostic fprintf(stderr, 56236227Sbostic "tar: can't read symbolic link %s: %s\n", 56336227Sbostic longname, strerror(errno)); 5646250Sroot return; 5656250Sroot } 5666250Sroot dblock.dbuf.linkname[i] = '\0'; 5676250Sroot dblock.dbuf.linkflag = '2'; 56822688Slepreau if (vflag) 56922688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 57022688Slepreau longname, dblock.dbuf.linkname); 57132420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo", 0L); 57232420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 57327445Slepreau (void) writetape((char *)&dblock); 57412154Ssam break; 5751119Sbill 57612154Ssam case S_IFREG: 57712154Ssam if ((infile = open(shortname, 0)) < 0) { 57836227Sbostic fprintf(stderr, "tar: %s: %s\n", 57936227Sbostic longname, strerror(errno)); 5801119Sbill return; 5811119Sbill } 58212154Ssam tomodes(&stbuf); 58312154Ssam if (strlen(longname) >= NAMSIZ) { 58413492Ssam fprintf(stderr, "tar: %s: file name too long\n", 58513492Ssam longname); 58621457Skjd close(infile); 58712154Ssam return; 58812154Ssam } 58912154Ssam strcpy(dblock.dbuf.name, longname); 59012154Ssam if (stbuf.st_nlink > 1) { 59112154Ssam struct linkbuf *lp; 59212154Ssam int found = 0; 59312154Ssam 59412154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 59512154Ssam if (lp->inum == stbuf.st_ino && 59612154Ssam lp->devnum == stbuf.st_dev) { 59712154Ssam found++; 59812154Ssam break; 59912154Ssam } 60012154Ssam if (found) { 60112154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 60212154Ssam dblock.dbuf.linkflag = '1'; 60332420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 60427445Slepreau (void) writetape( (char *) &dblock); 60522688Slepreau if (vflag) 60622688Slepreau fprintf(vfile, "a %s link to %s\n", 60722688Slepreau longname, lp->pathname); 60812154Ssam lp->count--; 60912154Ssam close(infile); 61012154Ssam return; 6111119Sbill } 61222688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 61322688Slepreau if (lp != NULL) { 61412154Ssam lp->nextp = ihead; 61512154Ssam ihead = lp; 61612154Ssam lp->inum = stbuf.st_ino; 61712154Ssam lp->devnum = stbuf.st_dev; 61812154Ssam lp->count = stbuf.st_nlink - 1; 61912154Ssam strcpy(lp->pathname, longname); 62012154Ssam } 6211119Sbill } 62221457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 62322688Slepreau if (vflag) 62422688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 62532420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 62621457Skjd hint = writetape((char *)&dblock); 62721457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 62827445Slepreau if ((bigbuf = malloc((unsigned)maxread)) == 0) { 62921457Skjd maxread = TBLOCK; 63021457Skjd bigbuf = buf; 63121457Skjd } 6321119Sbill 63321457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 63421457Skjd && blocks > 0) { 63521457Skjd register int nblks; 63621457Skjd 63721457Skjd nblks = ((i-1)/TBLOCK)+1; 63821457Skjd if (nblks > blocks) 63921457Skjd nblks = blocks; 64021457Skjd hint = writetbuf(bigbuf, nblks); 64121457Skjd blocks -= nblks; 64221457Skjd } 64321457Skjd close(infile); 64421457Skjd if (bigbuf != buf) 64521457Skjd free(bigbuf); 64627058Smckusick if (i < 0) { 64736227Sbostic fprintf(stderr, "tar: Read error on %s: %s\n", 64836227Sbostic longname, strerror(errno)); 64927058Smckusick } else if (blocks != 0 || i != 0) 65013492Ssam fprintf(stderr, "tar: %s: file changed size\n", 65113492Ssam longname); 65212154Ssam while (--blocks >= 0) 65312154Ssam putempty(); 65412154Ssam break; 65512154Ssam 65612154Ssam default: 65712154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 65813492Ssam longname); 65912154Ssam break; 6601119Sbill } 6611119Sbill } 6621119Sbill 6631119Sbill doxtract(argv) 6646250Sroot char *argv[]; 6651119Sbill { 6661119Sbill long blocks, bytes; 66727445Slepreau int ofile, i; 6681119Sbill 6691119Sbill for (;;) { 67027445Slepreau if ((i = wantit(argv)) == 0) 67127445Slepreau continue; 67227445Slepreau if (i == -1) 67327445Slepreau break; /* end of tape */ 6741119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6751119Sbill passtape(); 6761119Sbill continue; 6771119Sbill } 67812154Ssam if (Fflag) { 67912154Ssam char *s; 68012154Ssam 68112154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 68212154Ssam s = dblock.dbuf.name; 68312154Ssam else 68412154Ssam s++; 68512154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 68612154Ssam passtape(); 68712154Ssam continue; 68812154Ssam } 68912154Ssam } 69022688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 69122688Slepreau if (mflag == 0) 69222688Slepreau dodirtimes(&dblock); 6936250Sroot continue; 69422688Slepreau } 69522688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 69625250Sbloom /* 69725250Sbloom * only unlink non directories or empty 69825250Sbloom * directories 69925250Sbloom */ 70025250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 70125250Sbloom if (errno == ENOTDIR) 70225250Sbloom unlink(dblock.dbuf.name); 70325250Sbloom } 7046250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 70536227Sbostic fprintf(stderr, 70636227Sbostic "tar: %s: symbolic link failed: %s\n", 70736227Sbostic dblock.dbuf.name, strerror(errno)); 7086250Sroot continue; 7096250Sroot } 7106250Sroot if (vflag) 71121910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 71213492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 71322353Skjd #ifdef notdef 71422353Skjd /* ignore alien orders */ 71522353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 71622688Slepreau if (mflag == 0) 71722688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 71822353Skjd if (pflag) 71922353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 72022353Skjd #endif 7211119Sbill continue; 7226250Sroot } 72322688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 72425250Sbloom /* 72525250Sbloom * only unlink non directories or empty 72625250Sbloom * directories 72725250Sbloom */ 72825250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 72925250Sbloom if (errno == ENOTDIR) 73025250Sbloom unlink(dblock.dbuf.name); 73125250Sbloom } 7321119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 73336227Sbostic fprintf(stderr, 73436227Sbostic "tar: can't link %s to %s: %s\n", 73536227Sbostic dblock.dbuf.name, dblock.dbuf.linkname, 73636227Sbostic strerror(errno)); 7371119Sbill continue; 7381119Sbill } 7391119Sbill if (vflag) 74022688Slepreau fprintf(vfile, "%s linked to %s\n", 74113492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7421119Sbill continue; 7431119Sbill } 7446250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 74536227Sbostic fprintf(stderr, "tar: can't create %s: %s\n", 74636227Sbostic dblock.dbuf.name, strerror(errno)); 7471119Sbill passtape(); 7481119Sbill continue; 7491119Sbill } 75021457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7511119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7521119Sbill if (vflag) 75322688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 75413492Ssam dblock.dbuf.name, bytes, blocks); 75521457Skjd for (; blocks > 0;) { 75621457Skjd register int nread; 75721457Skjd char *bufp; 75821457Skjd register int nwant; 75921457Skjd 76021457Skjd nwant = NBLOCK*TBLOCK; 76121457Skjd if (nwant > (blocks*TBLOCK)) 76221457Skjd nwant = (blocks*TBLOCK); 76321457Skjd nread = readtbuf(&bufp, nwant); 76422688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7656250Sroot fprintf(stderr, 76636227Sbostic "tar: %s: HELP - extract write error: %s\n", 76736227Sbostic dblock.dbuf.name, strerror(errno)); 7686250Sroot done(2); 7696250Sroot } 77021457Skjd bytes -= nread; 77121457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7721119Sbill } 7731119Sbill close(ofile); 77422688Slepreau if (mflag == 0) 77522688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7761926Swnj if (pflag) 7776250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7781119Sbill } 77922688Slepreau if (mflag == 0) { 78022688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 78122688Slepreau dodirtimes(&dblock); 78222688Slepreau } 7831119Sbill } 7841119Sbill 78527445Slepreau dotable(argv) 78627445Slepreau char *argv[]; 7871119Sbill { 78827445Slepreau register int i; 78927445Slepreau 7901119Sbill for (;;) { 79127445Slepreau if ((i = wantit(argv)) == 0) 79227445Slepreau continue; 79327445Slepreau if (i == -1) 79427445Slepreau break; /* end of tape */ 7951119Sbill if (vflag) 7961119Sbill longt(&stbuf); 7971119Sbill printf("%s", dblock.dbuf.name); 7981119Sbill if (dblock.dbuf.linkflag == '1') 7991119Sbill printf(" linked to %s", dblock.dbuf.linkname); 8006250Sroot if (dblock.dbuf.linkflag == '2') 8016250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 8021119Sbill printf("\n"); 8031119Sbill passtape(); 8041119Sbill } 8051119Sbill } 8061119Sbill 8071119Sbill putempty() 8081119Sbill { 8091119Sbill char buf[TBLOCK]; 8101119Sbill 81113492Ssam bzero(buf, sizeof (buf)); 81227445Slepreau (void) writetape(buf); 8131119Sbill } 8141119Sbill 8151119Sbill longt(st) 8166250Sroot register struct stat *st; 8171119Sbill { 8181119Sbill register char *cp; 8191119Sbill char *ctime(); 8201119Sbill 8211119Sbill pmode(st); 82236227Sbostic printf("%3u/%1u", st->st_uid, st->st_gid); 82327445Slepreau printf("%7ld", st->st_size); 8241119Sbill cp = ctime(&st->st_mtime); 8251119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8261119Sbill } 8271119Sbill 8281119Sbill #define SUID 04000 8291119Sbill #define SGID 02000 8301119Sbill #define ROWN 0400 8311119Sbill #define WOWN 0200 8321119Sbill #define XOWN 0100 8331119Sbill #define RGRP 040 8341119Sbill #define WGRP 020 8351119Sbill #define XGRP 010 8361119Sbill #define ROTH 04 8371119Sbill #define WOTH 02 8381119Sbill #define XOTH 01 8391119Sbill #define STXT 01000 8401119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8411119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8421119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8431119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8441119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8451119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8461119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8471119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8481119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8491119Sbill 8501119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8511119Sbill 8521119Sbill pmode(st) 8536250Sroot register struct stat *st; 8541119Sbill { 8551119Sbill register int **mp; 8561119Sbill 8571119Sbill for (mp = &m[0]; mp < &m[9];) 85827058Smckusick selectbits(*mp++, st); 8591119Sbill } 8601119Sbill 86127058Smckusick selectbits(pairp, st) 8626250Sroot int *pairp; 8636250Sroot struct stat *st; 8641119Sbill { 8651119Sbill register int n, *ap; 8661119Sbill 8671119Sbill ap = pairp; 8681119Sbill n = *ap++; 8691119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8701119Sbill ap++; 87127445Slepreau putchar(*ap); 8721119Sbill } 8731119Sbill 87422688Slepreau /* 87527442Slepreau * Make all directories needed by `name'. If `name' is itself 87627442Slepreau * a directory on the tar tape (indicated by a trailing '/'), 87722688Slepreau * return 1; else 0. 87822688Slepreau */ 8791119Sbill checkdir(name) 8806250Sroot register char *name; 8811119Sbill { 8821119Sbill register char *cp; 8836250Sroot 88412154Ssam /* 88522688Slepreau * Quick check for existence of directory. 88612154Ssam */ 88712154Ssam if ((cp = rindex(name, '/')) == 0) 88812154Ssam return (0); 88912154Ssam *cp = '\0'; 89036227Sbostic if (access(name, F_OK) == 0) { /* already exists */ 89112154Ssam *cp = '/'; 89222688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 89312154Ssam } 89412154Ssam *cp = '/'; 89512154Ssam 89612154Ssam /* 89712154Ssam * No luck, try to make all directories in path. 89812154Ssam */ 8991119Sbill for (cp = name; *cp; cp++) { 9006250Sroot if (*cp != '/') 9016250Sroot continue; 9026250Sroot *cp = '\0'; 90336227Sbostic if (access(name, F_OK) < 0) { 9049844Ssam if (mkdir(name, 0777) < 0) { 90536227Sbostic fprintf(stderr, "tar: mkdir: %s: %s\n", 90636227Sbostic name, strerror(errno)); 90712154Ssam *cp = '/'; 90812154Ssam return (0); 9091119Sbill } 91021457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 91127442Slepreau if (pflag && cp[1] == '\0') /* dir on the tape */ 91227442Slepreau chmod(name, stbuf.st_mode & 07777); 9131119Sbill } 9146250Sroot *cp = '/'; 9151119Sbill } 9166250Sroot return (cp[-1]=='/'); 9171119Sbill } 9181119Sbill 9191119Sbill onintr() 9201119Sbill { 92127445Slepreau (void) signal(SIGINT, SIG_IGN); 9221119Sbill term++; 9231119Sbill } 9241119Sbill 9251119Sbill onquit() 9261119Sbill { 92727445Slepreau (void) signal(SIGQUIT, SIG_IGN); 9281119Sbill term++; 9291119Sbill } 9301119Sbill 9311119Sbill onhup() 9321119Sbill { 93327445Slepreau (void) signal(SIGHUP, SIG_IGN); 9341119Sbill term++; 9351119Sbill } 9361119Sbill 93722688Slepreau #ifdef notdef 9381119Sbill onterm() 9391119Sbill { 94027445Slepreau (void) signal(SIGTERM, SIG_IGN); 9411119Sbill term++; 9421119Sbill } 94322688Slepreau #endif 9441119Sbill 9451119Sbill tomodes(sp) 9461119Sbill register struct stat *sp; 9471119Sbill { 9481119Sbill register char *cp; 9491119Sbill 9501119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9511119Sbill *cp = '\0'; 95232420Sbostic (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 95332420Sbostic (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 95432420Sbostic (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 95532420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 95632420Sbostic (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9571119Sbill } 9581119Sbill 9591119Sbill checksum() 9601119Sbill { 9611119Sbill register i; 9621119Sbill register char *cp; 9631119Sbill 9646250Sroot for (cp = dblock.dbuf.chksum; 9656250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9661119Sbill *cp = ' '; 9671119Sbill i = 0; 9681119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9691119Sbill i += *cp; 9706250Sroot return (i); 9711119Sbill } 9721119Sbill 9731119Sbill checkw(c, name) 9746250Sroot char *name; 9751119Sbill { 9766250Sroot if (!wflag) 9776250Sroot return (1); 9786250Sroot printf("%c ", c); 9796250Sroot if (vflag) 9806250Sroot longt(&stbuf); 9816250Sroot printf("%s: ", name); 9826250Sroot return (response() == 'y'); 9831119Sbill } 9841119Sbill 9851119Sbill response() 9861119Sbill { 9871119Sbill char c; 9881119Sbill 9891119Sbill c = getchar(); 9901119Sbill if (c != '\n') 9916250Sroot while (getchar() != '\n') 9926250Sroot ; 9936250Sroot else 9946250Sroot c = 'n'; 9956250Sroot return (c); 9961119Sbill } 9971119Sbill 99812154Ssam checkf(name, mode, howmuch) 99912154Ssam char *name; 100012154Ssam int mode, howmuch; 100112154Ssam { 100212154Ssam int l; 100312154Ssam 100421910Skjd if ((mode & S_IFMT) == S_IFDIR){ 100521910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 100621910Skjd return(0); 100721910Skjd return(1); 100821910Skjd } 100912154Ssam if ((l = strlen(name)) < 3) 101012154Ssam return (1); 101112154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 101212154Ssam return (0); 101312154Ssam if (strcmp(name, "core") == 0 || 101412154Ssam strcmp(name, "errs") == 0 || 101512154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 101612154Ssam return (0); 101712154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 101812154Ssam return (1); 101912154Ssam } 102012154Ssam 102122688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 10221119Sbill checkupdate(arg) 10236250Sroot char *arg; 10241119Sbill { 10251119Sbill char name[100]; 10266250Sroot long mtime; 10271119Sbill daddr_t seekp; 10281119Sbill daddr_t lookup(); 10291119Sbill 10301119Sbill rewind(tfile); 10311119Sbill for (;;) { 10321119Sbill if ((seekp = lookup(arg)) < 0) 10336250Sroot return (1); 10341119Sbill fseek(tfile, seekp, 0); 10351119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10366250Sroot return (stbuf.st_mtime > mtime); 10371119Sbill } 10381119Sbill } 10391119Sbill 10401119Sbill done(n) 10411119Sbill { 104221457Skjd unlink(tname); 10431119Sbill exit(n); 10441119Sbill } 10451119Sbill 104627445Slepreau /* 104727445Slepreau * Do we want the next entry on the tape, i.e. is it selected? If 104827445Slepreau * not, skip over the entire entry. Return -1 if reached end of tape. 104927445Slepreau */ 105027445Slepreau wantit(argv) 105127445Slepreau char *argv[]; 105227445Slepreau { 105327445Slepreau register char **cp; 105427445Slepreau 105527445Slepreau getdir(); 105627445Slepreau if (endtape()) 105727445Slepreau return (-1); 105827445Slepreau if (*argv == 0) 105927445Slepreau return (1); 106027445Slepreau for (cp = argv; *cp; cp++) 106127445Slepreau if (prefix(*cp, dblock.dbuf.name)) 106227445Slepreau return (1); 106327445Slepreau passtape(); 106427445Slepreau return (0); 106527445Slepreau } 106627445Slepreau 106722688Slepreau /* 106822688Slepreau * Does s2 begin with the string s1, on a directory boundary? 106922688Slepreau */ 10701119Sbill prefix(s1, s2) 10716250Sroot register char *s1, *s2; 10721119Sbill { 10731119Sbill while (*s1) 10741119Sbill if (*s1++ != *s2++) 10756250Sroot return (0); 10761119Sbill if (*s2) 10776250Sroot return (*s2 == '/'); 10786250Sroot return (1); 10791119Sbill } 10801119Sbill 10811119Sbill #define N 200 10821119Sbill int njab; 10836250Sroot 10841119Sbill daddr_t 10851119Sbill lookup(s) 10866250Sroot char *s; 10871119Sbill { 10881119Sbill register i; 10891119Sbill daddr_t a; 10901119Sbill 10911119Sbill for(i=0; s[i]; i++) 10926250Sroot if (s[i] == ' ') 10931119Sbill break; 10941119Sbill a = bsrch(s, i, low, high); 10956250Sroot return (a); 10961119Sbill } 10971119Sbill 10981119Sbill daddr_t 10991119Sbill bsrch(s, n, l, h) 11006250Sroot daddr_t l, h; 11016250Sroot char *s; 11021119Sbill { 11031119Sbill register i, j; 11041119Sbill char b[N]; 11051119Sbill daddr_t m, m1; 11061119Sbill 11071119Sbill njab = 0; 11081119Sbill 11091119Sbill loop: 11106250Sroot if (l >= h) 111122688Slepreau return ((daddr_t) -1); 11121119Sbill m = l + (h-l)/2 - N/2; 11136250Sroot if (m < l) 11141119Sbill m = l; 11151119Sbill fseek(tfile, m, 0); 11161119Sbill fread(b, 1, N, tfile); 11171119Sbill njab++; 11181119Sbill for(i=0; i<N; i++) { 11196250Sroot if (b[i] == '\n') 11201119Sbill break; 11211119Sbill m++; 11221119Sbill } 11236250Sroot if (m >= h) 112422688Slepreau return ((daddr_t) -1); 11251119Sbill m1 = m; 11261119Sbill j = i; 11271119Sbill for(i++; i<N; i++) { 11281119Sbill m1++; 11296250Sroot if (b[i] == '\n') 11301119Sbill break; 11311119Sbill } 11321119Sbill i = cmp(b+j, s, n); 11336250Sroot if (i < 0) { 11341119Sbill h = m; 11351119Sbill goto loop; 11361119Sbill } 11376250Sroot if (i > 0) { 11381119Sbill l = m1; 11391119Sbill goto loop; 11401119Sbill } 11416250Sroot return (m); 11421119Sbill } 11431119Sbill 11441119Sbill cmp(b, s, n) 11456250Sroot char *b, *s; 11461119Sbill { 11471119Sbill register i; 11481119Sbill 11496250Sroot if (b[0] != '\n') 115021457Skjd exit(2); 11511119Sbill for(i=0; i<n; i++) { 11526250Sroot if (b[i+1] > s[i]) 11536250Sroot return (-1); 11546250Sroot if (b[i+1] < s[i]) 11556250Sroot return (1); 11561119Sbill } 11576250Sroot return (b[i+1] == ' '? 0 : -1); 11581119Sbill } 11591119Sbill 116022688Slepreau readtape(buffer) 11616250Sroot char *buffer; 11621119Sbill { 116321457Skjd char *bufp; 116421457Skjd 116522688Slepreau if (first == 0) 116622688Slepreau getbuf(); 116727445Slepreau (void) readtbuf(&bufp, TBLOCK); 116821457Skjd bcopy(bufp, buffer, TBLOCK); 116921457Skjd return(TBLOCK); 117021457Skjd } 117121457Skjd 117221457Skjd readtbuf(bufpp, size) 117321457Skjd char **bufpp; 117421457Skjd int size; 117521457Skjd { 11763457Swnj register int i; 11771119Sbill 11781119Sbill if (recno >= nblock || first == 0) { 117927445Slepreau if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 118027058Smckusick mterr("read", i, 3); 11811119Sbill if (first == 0) { 11821119Sbill if ((i % TBLOCK) != 0) { 118313492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11841119Sbill done(3); 11851119Sbill } 11861119Sbill i /= TBLOCK; 11873457Swnj if (i != nblock) { 118813492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11891119Sbill nblock = i; 11901119Sbill } 119122353Skjd first = 1; 11921119Sbill } 11931119Sbill recno = 0; 11941119Sbill } 119521457Skjd if (size > ((nblock-recno)*TBLOCK)) 119621457Skjd size = (nblock-recno)*TBLOCK; 119721457Skjd *bufpp = (char *)&tbuf[recno]; 119821457Skjd recno += (size/TBLOCK); 119921457Skjd return (size); 12001119Sbill } 12011119Sbill 120221457Skjd writetbuf(buffer, n) 120321457Skjd register char *buffer; 120421457Skjd register int n; 12051119Sbill { 120627058Smckusick int i; 120722688Slepreau 120822688Slepreau if (first == 0) { 120922353Skjd getbuf(); 121022353Skjd first = 1; 121122353Skjd } 12121119Sbill if (recno >= nblock) { 121327445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 121427058Smckusick if (i != TBLOCK*nblock) 121527058Smckusick mterr("write", i, 2); 12161119Sbill recno = 0; 12171119Sbill } 121821457Skjd 121921457Skjd /* 122021457Skjd * Special case: We have an empty tape buffer, and the 122121457Skjd * users data size is >= the tape block size: Avoid 122221457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 122321457Skjd * residual to the tape buffer. 122421457Skjd */ 122521457Skjd while (recno == 0 && n >= nblock) { 122627058Smckusick i = write(mt, buffer, TBLOCK*nblock); 122727058Smckusick if (i != TBLOCK*nblock) 122827058Smckusick mterr("write", i, 2); 122921457Skjd n -= nblock; 123021457Skjd buffer += (nblock * TBLOCK); 12311119Sbill } 123221457Skjd 123321457Skjd while (n-- > 0) { 123421457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 123521457Skjd buffer += TBLOCK; 123621457Skjd if (recno >= nblock) { 123727445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 123827058Smckusick if (i != TBLOCK*nblock) 123927058Smckusick mterr("write", i, 2); 124021457Skjd recno = 0; 124121457Skjd } 124221457Skjd } 124321457Skjd 124421457Skjd /* Tell the user how much to write to get in sync */ 124521457Skjd return (nblock - recno); 12461119Sbill } 12471119Sbill 12481119Sbill backtape() 12491119Sbill { 125027058Smckusick static int mtdev = 1; 12513457Swnj static struct mtop mtop = {MTBSR, 1}; 125227058Smckusick struct mtget mtget; 125327058Smckusick 125427058Smckusick if (mtdev == 1) 125527445Slepreau mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 12563457Swnj if (mtdev == 0) { 125727445Slepreau if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 125836227Sbostic fprintf(stderr, "tar: tape backspace error: %s\n", 125936227Sbostic strerror(errno)); 12601119Sbill done(4); 12611119Sbill } 12623457Swnj } else 126336227Sbostic (void)lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 12643457Swnj recno--; 12651119Sbill } 12661119Sbill 12671119Sbill flushtape() 12681119Sbill { 126927058Smckusick int i; 127027058Smckusick 127127445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 127227058Smckusick if (i != TBLOCK*nblock) 127327058Smckusick mterr("write", i, 2); 12741119Sbill } 12751119Sbill 127627058Smckusick mterr(operation, i, exitcode) 127727058Smckusick char *operation; 127827058Smckusick int i; 127927058Smckusick { 128036227Sbostic fprintf(stderr, "tar: tape %s error: %s\n", 128136227Sbostic operation, i < 0 ? strerror(errno) : "unexpected EOF"); 128227058Smckusick done(exitcode); 128327058Smckusick } 128427058Smckusick 12858737Smckusick bread(fd, buf, size) 12868737Smckusick int fd; 12878737Smckusick char *buf; 12888737Smckusick int size; 12898737Smckusick { 12908737Smckusick int count; 12918737Smckusick static int lastread = 0; 12928737Smckusick 129322688Slepreau if (!Bflag) 129422688Slepreau return (read(fd, buf, size)); 129522353Skjd 12968737Smckusick for (count = 0; count < size; count += lastread) { 129724281Smckusick lastread = read(fd, buf, size - count); 129824281Smckusick if (lastread <= 0) { 12998737Smckusick if (count > 0) 13008737Smckusick return (count); 13018737Smckusick return (lastread); 13028737Smckusick } 13038737Smckusick buf += lastread; 13048737Smckusick } 13058737Smckusick return (count); 13068737Smckusick } 130710165Ssam 130810165Ssam char * 130910165Ssam getcwd(buf) 131010165Ssam char *buf; 131110165Ssam { 131210165Ssam if (getwd(buf) == NULL) { 131310165Ssam fprintf(stderr, "tar: %s\n", buf); 131421457Skjd exit(1); 131510165Ssam } 131610165Ssam return (buf); 131710165Ssam } 131821910Skjd 131921910Skjd getbuf() 132021910Skjd { 132122353Skjd 132227058Smckusick if (nblock == 0) { 132321910Skjd fstat(mt, &stbuf); 132421910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 132527058Smckusick nblock = NBLOCK; 132621910Skjd else { 132727058Smckusick nblock = stbuf.st_blksize / TBLOCK; 132827058Smckusick if (nblock == 0) 132927058Smckusick nblock = NBLOCK; 133021910Skjd } 133121910Skjd } 133227445Slepreau tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 133321910Skjd if (tbuf == NULL) { 133421910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 133521910Skjd nblock); 133621910Skjd done(1); 133721910Skjd } 133821910Skjd } 133922353Skjd 134022688Slepreau /* 134127442Slepreau * Save this directory and its mtime on the stack, popping and setting 134227442Slepreau * the mtimes of any stacked dirs which aren't parents of this one. 134327442Slepreau * A null directory causes the entire stack to be unwound and set. 134422688Slepreau * 134527442Slepreau * Since all the elements of the directory "stack" share a common 134627442Slepreau * prefix, we can make do with one string. We keep only the current 134727442Slepreau * directory path, with an associated array of mtime's, one for each 134827442Slepreau * '/' in the path. A negative mtime means no mtime. The mtime's are 134927442Slepreau * offset by one (first index 1, not 0) because calling this with a null 135027442Slepreau * directory causes mtime[0] to be set. 135127442Slepreau * 135222688Slepreau * This stack algorithm is not guaranteed to work for tapes created 135322688Slepreau * with the 'r' option, but the vast majority of tapes with 135422688Slepreau * directories are not. This avoids saving every directory record on 135522688Slepreau * the tape and setting all the times at the end. 135622688Slepreau */ 135722688Slepreau char dirstack[NAMSIZ]; 135822688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 135922688Slepreau time_t mtime[NTIM]; 136022353Skjd 136122688Slepreau dodirtimes(hp) 136222688Slepreau union hblock *hp; 136322353Skjd { 136422688Slepreau register char *p = dirstack; 136522688Slepreau register char *q = hp->dbuf.name; 136622688Slepreau register int ndir = 0; 136722688Slepreau char *savp; 136822688Slepreau int savndir; 136922353Skjd 137022688Slepreau /* Find common prefix */ 137130090Sbostic while (*p == *q && *p) { 137222688Slepreau if (*p++ == '/') 137322688Slepreau ++ndir; 137422688Slepreau q++; 137522688Slepreau } 137622353Skjd 137722688Slepreau savp = p; 137822688Slepreau savndir = ndir; 137922688Slepreau while (*p) { 138022688Slepreau /* 138122688Slepreau * Not a child: unwind the stack, setting the times. 138222688Slepreau * The order we do this doesn't matter, so we go "forward." 138322688Slepreau */ 138422688Slepreau if (*p++ == '/') 138522688Slepreau if (mtime[++ndir] >= 0) { 138622688Slepreau *--p = '\0'; /* zap the slash */ 138722688Slepreau setimes(dirstack, mtime[ndir]); 138822688Slepreau *p++ = '/'; 138922688Slepreau } 139022688Slepreau } 139122688Slepreau p = savp; 139222688Slepreau ndir = savndir; 139322353Skjd 139422688Slepreau /* Push this one on the "stack" */ 139522688Slepreau while (*p = *q++) /* append the rest of the new dir */ 139622688Slepreau if (*p++ == '/') 139722688Slepreau mtime[++ndir] = -1; 139822688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 139922688Slepreau } 140022353Skjd 140122688Slepreau setimes(path, mt) 140222688Slepreau char *path; 140322688Slepreau time_t mt; 140422688Slepreau { 140522688Slepreau struct timeval tv[2]; 140622353Skjd 140722688Slepreau tv[0].tv_sec = time((time_t *) 0); 140822688Slepreau tv[1].tv_sec = mt; 140922688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 141036227Sbostic if (utimes(path, tv) < 0) 141136227Sbostic fprintf(stderr, "tar: can't set time on %s: %s\n", 141236227Sbostic path, strerror(errno)); 141322688Slepreau } 141422688Slepreau 141522688Slepreau char * 141622688Slepreau getmem(size) 141722688Slepreau { 141822688Slepreau char *p = malloc((unsigned) size); 141922688Slepreau 142022688Slepreau if (p == NULL && freemem) { 142122688Slepreau fprintf(stderr, 142222688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 142322688Slepreau freemem = 0; 142422353Skjd } 142522688Slepreau return (p); 142622353Skjd } 1427