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*46656Sbostic static char sccsid[] = "@(#)tar.c 5.16 (Berkeley) 02/25/91"; 1533082Sbostic #endif /* not lint */ 1622502Sdist 176250Sroot /* 186250Sroot * Tape Archival Program 196250Sroot */ 206413Smckusic #include <sys/param.h> 211119Sbill #include <sys/stat.h> 228150Smckusick #include <sys/ioctl.h> 233457Swnj #include <sys/mtio.h> 2412983Ssam #include <sys/time.h> 25*46656Sbostic #include <dirent.h> 26*46656Sbostic #include <fcntl.h> 271119Sbill #include <signal.h> 2812154Ssam #include <errno.h> 2927058Smckusick #include <fcntl.h> 30*46656Sbostic #include <unistd.h> 31*46656Sbostic #include <stdio.h> 3242013Sbostic #include <string.h> 33*46656Sbostic #include <stdlib.h> 3437681Sbostic #include "pathnames.h" 351119Sbill 361119Sbill #define TBLOCK 512 373355Swnj #define NBLOCK 20 381119Sbill #define NAMSIZ 100 396250Sroot 4021457Skjd #define writetape(b) writetbuf(b, 1) 4121457Skjd #define min(a,b) ((a) < (b) ? (a) : (b)) 4221457Skjd #define max(a,b) ((a) > (b) ? (a) : (b)) 4321457Skjd 441119Sbill union hblock { 451119Sbill char dummy[TBLOCK]; 461119Sbill struct header { 471119Sbill char name[NAMSIZ]; 481119Sbill char mode[8]; 491119Sbill char uid[8]; 501119Sbill char gid[8]; 511119Sbill char size[12]; 521119Sbill char mtime[12]; 531119Sbill char chksum[8]; 541119Sbill char linkflag; 551119Sbill char linkname[NAMSIZ]; 561119Sbill } dbuf; 576250Sroot }; 581119Sbill 591119Sbill struct linkbuf { 601119Sbill ino_t inum; 611119Sbill dev_t devnum; 621119Sbill int count; 631119Sbill char pathname[NAMSIZ]; 641119Sbill struct linkbuf *nextp; 656250Sroot }; 661119Sbill 676250Sroot union hblock dblock; 6813492Ssam union hblock *tbuf; 696250Sroot struct linkbuf *ihead; 706250Sroot struct stat stbuf; 711119Sbill 726250Sroot int rflag; 7334429Sbostic int sflag; 746250Sroot int xflag; 756250Sroot int vflag; 766250Sroot int tflag; 776250Sroot int cflag; 786250Sroot int mflag; 796250Sroot int fflag; 8012154Ssam int iflag; 816250Sroot int oflag; 826250Sroot int pflag; 836250Sroot int wflag; 846250Sroot int hflag; 858737Smckusick int Bflag; 8612154Ssam int Fflag; 876250Sroot 886250Sroot int mt; 896250Sroot int term; 906250Sroot int chksum; 916250Sroot int recno; 9222688Slepreau int first; 9322688Slepreau int prtlinkerr; 941119Sbill int freemem = 1; 9522353Skjd int nblock = 0; 96*46656Sbostic void onintr(), onquit(), onhup(); 9722688Slepreau #ifdef notdef 98*46656Sbostic void onterm(); 9922688Slepreau #endif 1001119Sbill 1011119Sbill daddr_t low; 1021119Sbill daddr_t high; 1036250Sroot daddr_t bsrch(); 1041119Sbill 10521910Skjd FILE *vfile = stdout; 1061119Sbill FILE *tfile; 10737681Sbostic char tname[] = _PATH_TMP; 1081119Sbill char *usefile; 10937681Sbostic char magtape[] = _PATH_MAGTAPE; 110*46656Sbostic char *cwd(); 11122688Slepreau char *getmem(); 1121119Sbill 11336227Sbostic extern int errno; 11436227Sbostic 1151119Sbill main(argc, argv) 11636227Sbostic int argc; 11736227Sbostic char **argv; 1181119Sbill { 1191119Sbill char *cp; 1201119Sbill 1211119Sbill if (argc < 2) 1221119Sbill usage(); 1231119Sbill 1241119Sbill tfile = NULL; 1251119Sbill usefile = magtape; 1261119Sbill argv[argc] = 0; 1271119Sbill argv++; 1281119Sbill for (cp = *argv++; *cp; cp++) 1291119Sbill switch(*cp) { 1306250Sroot 1311119Sbill case 'f': 13212154Ssam if (*argv == 0) { 13312154Ssam fprintf(stderr, 13412154Ssam "tar: tapefile must be specified with 'f' option\n"); 13512154Ssam usage(); 13612154Ssam } 1371119Sbill usefile = *argv++; 1381119Sbill fflag++; 1391119Sbill break; 1406250Sroot 1411119Sbill case 'c': 1421119Sbill cflag++; 1431119Sbill rflag++; 1441119Sbill break; 1456250Sroot 1461119Sbill case 'o': 1471119Sbill oflag++; 1481119Sbill break; 1496250Sroot 1501119Sbill case 'p': 1511119Sbill pflag++; 1521119Sbill break; 1536250Sroot 1541119Sbill case 'u': 15536227Sbostic (void)mktemp(tname); 1561119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1576250Sroot fprintf(stderr, 15822688Slepreau "tar: cannot create temporary file (%s)\n", 1596250Sroot tname); 1601119Sbill done(1); 1611119Sbill } 1621119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1636250Sroot /*FALL THRU*/ 1646250Sroot 1651119Sbill case 'r': 1661119Sbill rflag++; 1671119Sbill break; 1686250Sroot 16934429Sbostic case 's': 17034429Sbostic sflag++; 17134429Sbostic break; 17234429Sbostic 1731119Sbill case 'v': 1741119Sbill vflag++; 1751119Sbill break; 1766250Sroot 1771119Sbill case 'w': 1781119Sbill wflag++; 1791119Sbill break; 1806250Sroot 1811119Sbill case 'x': 1821119Sbill xflag++; 1831119Sbill break; 1846250Sroot 1851119Sbill case 't': 1861119Sbill tflag++; 1871119Sbill break; 1886250Sroot 1891119Sbill case 'm': 1901119Sbill mflag++; 1911119Sbill break; 1926250Sroot 1931119Sbill case '-': 1941119Sbill break; 1956250Sroot 1961119Sbill case '0': 1971119Sbill case '1': 1981119Sbill case '4': 1991119Sbill case '5': 20021457Skjd case '7': 2011119Sbill case '8': 2021119Sbill magtape[8] = *cp; 2031119Sbill usefile = magtape; 2041119Sbill break; 2056250Sroot 2061119Sbill case 'b': 20713492Ssam if (*argv == 0) { 20813492Ssam fprintf(stderr, 20913492Ssam "tar: blocksize must be specified with 'b' option\n"); 21013492Ssam usage(); 21113492Ssam } 21213492Ssam nblock = atoi(*argv); 21313492Ssam if (nblock <= 0) { 21413492Ssam fprintf(stderr, 21513492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2161119Sbill done(1); 2171119Sbill } 21813492Ssam argv++; 2191119Sbill break; 2206250Sroot 2211119Sbill case 'l': 22222688Slepreau prtlinkerr++; 2231119Sbill break; 2246250Sroot 2256250Sroot case 'h': 2266250Sroot hflag++; 2276250Sroot break; 2286250Sroot 22912154Ssam case 'i': 23012154Ssam iflag++; 23112154Ssam break; 23212154Ssam 2338737Smckusick case 'B': 2348737Smckusick Bflag++; 2358737Smckusick break; 2368737Smckusick 23712154Ssam case 'F': 23812154Ssam Fflag++; 23912154Ssam break; 24012154Ssam 2411119Sbill default: 2421119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2431119Sbill usage(); 2441119Sbill } 2451119Sbill 2466250Sroot if (!rflag && !xflag && !tflag) 2476250Sroot usage(); 2481119Sbill if (rflag) { 2496250Sroot if (cflag && tfile != NULL) 2501119Sbill usage(); 2511119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 25227445Slepreau (void) signal(SIGINT, onintr); 2531119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 25427445Slepreau (void) signal(SIGHUP, onhup); 2551119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 25627445Slepreau (void) signal(SIGQUIT, onquit); 2576250Sroot #ifdef notdef 2581119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 25927445Slepreau (void) signal(SIGTERM, onterm); 2606250Sroot #endif 26127058Smckusick mt = openmt(usefile, 1); 2621119Sbill dorep(argv); 2636250Sroot done(0); 2641119Sbill } 26527058Smckusick mt = openmt(usefile, 0); 2666250Sroot if (xflag) 2671119Sbill doxtract(argv); 2686250Sroot else 26927445Slepreau dotable(argv); 2701119Sbill done(0); 2711119Sbill } 2721119Sbill 2731119Sbill usage() 2741119Sbill { 2756250Sroot fprintf(stderr, 27621457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2771119Sbill done(1); 2781119Sbill } 2791119Sbill 28027058Smckusick int 28127058Smckusick openmt(tape, writing) 28227058Smckusick char *tape; 28327058Smckusick int writing; 28427058Smckusick { 28527058Smckusick if (strcmp(tape, "-") == 0) { 28627058Smckusick /* 28727058Smckusick * Read from standard input or write to standard output. 28827058Smckusick */ 28927058Smckusick if (writing) { 29027058Smckusick if (cflag == 0) { 29127058Smckusick fprintf(stderr, 29227058Smckusick "tar: can only create standard output archives\n"); 29327058Smckusick done(1); 29427058Smckusick } 29527058Smckusick vfile = stderr; 29627058Smckusick setlinebuf(vfile); 29727058Smckusick mt = dup(1); 29827058Smckusick } else { 29927058Smckusick mt = dup(0); 30027058Smckusick Bflag++; 30127058Smckusick } 30227058Smckusick } else { 30327058Smckusick /* 30427058Smckusick * Use file or tape on local machine. 30527058Smckusick */ 30627058Smckusick if (writing) { 30727058Smckusick if (cflag) 30827445Slepreau mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); 30927058Smckusick else 31027058Smckusick mt = open(tape, O_RDWR); 31127058Smckusick } else 31227058Smckusick mt = open(tape, O_RDONLY); 31327058Smckusick if (mt < 0) { 31436227Sbostic fprintf(stderr, "tar: %s: %s\n", tape, strerror(errno)); 31527058Smckusick done(1); 31627058Smckusick } 31727058Smckusick } 31827058Smckusick return(mt); 31927058Smckusick } 32027058Smckusick 3211119Sbill dorep(argv) 3226250Sroot char *argv[]; 3231119Sbill { 3241119Sbill register char *cp, *cp2; 325*46656Sbostic char *parent, *wdir; 3261119Sbill 3271119Sbill if (!cflag) { 3281119Sbill getdir(); 3291119Sbill do { 3301119Sbill passtape(); 3311119Sbill if (term) 3321119Sbill done(0); 3331119Sbill getdir(); 3341119Sbill } while (!endtape()); 33513492Ssam backtape(); 3361119Sbill if (tfile != NULL) { 3371119Sbill char buf[200]; 3381119Sbill 33932420Sbostic (void)sprintf(buf, 3406250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3411119Sbill tname, tname, tname, tname, tname, tname); 3421119Sbill fflush(tfile); 3431119Sbill system(buf); 3441119Sbill freopen(tname, "r", tfile); 3451119Sbill fstat(fileno(tfile), &stbuf); 3461119Sbill high = stbuf.st_size; 3471119Sbill } 3481119Sbill } 3491119Sbill 350*46656Sbostic wdir = cwd(); 3511119Sbill while (*argv && ! term) { 3521119Sbill cp2 = *argv; 3531119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3541119Sbill argv++; 35527058Smckusick if (chdir(*argv) < 0) { 35636227Sbostic fprintf(stderr, 35736227Sbostic "tar: can't change directories to %s: %s\n", 35836227Sbostic *argv, strerror(errno)); 359*46656Sbostic } else { 360*46656Sbostic free(wdir); 361*46656Sbostic wdir = cwd(); 362*46656Sbostic } 3631119Sbill argv++; 3641119Sbill continue; 3651119Sbill } 3669601Ssam parent = wdir; 3671119Sbill for (cp = *argv; *cp; cp++) 3681119Sbill if (*cp == '/') 3691119Sbill cp2 = cp; 3701119Sbill if (cp2 != *argv) { 3711119Sbill *cp2 = '\0'; 3729601Ssam if (chdir(*argv) < 0) { 37336227Sbostic fprintf(stderr, 37436227Sbostic "tar: can't change directories to %s: %s\n", 37536227Sbostic *argv, strerror(errno)); 3769601Ssam continue; 3779601Ssam } 378*46656Sbostic parent = cwd(); 3791119Sbill *cp2 = '/'; 3801119Sbill cp2++; 3811119Sbill } 3829601Ssam putfile(*argv++, cp2, parent); 38336227Sbostic if (chdir(wdir) < 0) 38436227Sbostic fprintf(stderr, "tar: cannot change back?: %s: %s\n", 38536227Sbostic wdir, strerror(errno)); 3861119Sbill } 3871119Sbill putempty(); 3881119Sbill putempty(); 3891119Sbill flushtape(); 39022688Slepreau if (prtlinkerr == 0) 3916250Sroot return; 3926250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3936250Sroot if (ihead->count == 0) 3946250Sroot continue; 39513492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3966250Sroot } 3971119Sbill } 3981119Sbill 3991119Sbill endtape() 4001119Sbill { 40121457Skjd return (dblock.dbuf.name[0] == '\0'); 4021119Sbill } 4031119Sbill 4041119Sbill getdir() 4051119Sbill { 4061119Sbill register struct stat *sp; 4071119Sbill int i; 4081119Sbill 40912154Ssam top: 4106250Sroot readtape((char *)&dblock); 4111119Sbill if (dblock.dbuf.name[0] == '\0') 4121119Sbill return; 4131119Sbill sp = &stbuf; 4141119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4151119Sbill sp->st_mode = i; 4161119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4171119Sbill sp->st_uid = i; 4181119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4191119Sbill sp->st_gid = i; 4201119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4211119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4221119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 42312154Ssam if (chksum != (i = checksum())) { 42413492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 42512154Ssam chksum, i); 42612154Ssam if (iflag) 42712154Ssam goto top; 4281119Sbill done(2); 4291119Sbill } 43034429Sbostic /* strip off leading "/" if present */ 43134429Sbostic if (sflag && dblock.dbuf.name[0] == '/') { 43234429Sbostic register char *cp1, *cp2; 43334429Sbostic for (cp1 = cp2 = dblock.dbuf.name; *cp2 && *cp2 == '/'; ++cp2); 43434429Sbostic if (!*cp2) 43534429Sbostic goto top; 43634429Sbostic while (*cp1++ = *cp2++); 43734429Sbostic } 4381119Sbill if (tfile != NULL) 4391119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4401119Sbill } 4411119Sbill 4421119Sbill passtape() 4431119Sbill { 4441119Sbill long blocks; 44521457Skjd char *bufp; 4461119Sbill 4471119Sbill if (dblock.dbuf.linkflag == '1') 4481119Sbill return; 4491119Sbill blocks = stbuf.st_size; 4501119Sbill blocks += TBLOCK-1; 4511119Sbill blocks /= TBLOCK; 4521119Sbill 45321457Skjd while (blocks-- > 0) 45427445Slepreau (void) readtbuf(&bufp, TBLOCK); 4551119Sbill } 4561119Sbill 4579601Ssam putfile(longname, shortname, parent) 4586250Sroot char *longname; 4596250Sroot char *shortname; 4609601Ssam char *parent; 4611119Sbill { 46221457Skjd int infile = 0; 46321457Skjd long blocks; 4641119Sbill char buf[TBLOCK]; 46521457Skjd char *bigbuf; 46622688Slepreau register char *cp; 467*46656Sbostic struct dirent *dp; 4685931Smckusic DIR *dirp; 46927445Slepreau register int i; 47027445Slepreau long l; 4719601Ssam char newparent[NAMSIZ+64]; 47221457Skjd int maxread; 47321457Skjd int hint; /* amount to write to get "in sync" */ 4741119Sbill 4759601Ssam if (!hflag) 47612154Ssam i = lstat(shortname, &stbuf); 47712154Ssam else 47812154Ssam i = stat(shortname, &stbuf); 47912154Ssam if (i < 0) { 48036227Sbostic fprintf(stderr, "tar: %s: %s\n", longname, strerror(errno)); 4819601Ssam return; 4829601Ssam } 48312154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4841119Sbill return; 48512154Ssam if (checkw('r', longname) == 0) 4861119Sbill return; 48712154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 48812154Ssam return; 4891119Sbill 49012154Ssam switch (stbuf.st_mode & S_IFMT) { 49112154Ssam case S_IFDIR: 4926250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4936250Sroot ; 4941119Sbill *--cp = '/'; 4951119Sbill *++cp = 0 ; 4961119Sbill if (!oflag) { 4976250Sroot if ((cp - buf) >= NAMSIZ) { 49813492Ssam fprintf(stderr, "tar: %s: file name too long\n", 49913492Ssam longname); 5006250Sroot return; 5016250Sroot } 5026250Sroot stbuf.st_size = 0; 5036250Sroot tomodes(&stbuf); 5046250Sroot strcpy(dblock.dbuf.name,buf); 50532420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 50627445Slepreau (void) writetape((char *)&dblock); 5071119Sbill } 50832420Sbostic (void)sprintf(newparent, "%s/%s", parent, shortname); 50915045Smckusick if (chdir(shortname) < 0) { 51036227Sbostic fprintf(stderr, "tar: chdir %s: %s\n", 51136227Sbostic shortname, strerror(errno)); 51215045Smckusick return; 51315045Smckusick } 5145931Smckusic if ((dirp = opendir(".")) == NULL) { 51513492Ssam fprintf(stderr, "tar: %s: directory read error\n", 51613492Ssam longname); 51715045Smckusick if (chdir(parent) < 0) { 51836227Sbostic fprintf(stderr, 51936227Sbostic "tar: cannot change back?: %s: %s\n", 52036227Sbostic parent, strerror(errno)); 52115045Smckusick } 5225931Smckusic return; 5235931Smckusic } 5245931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5256250Sroot if (!strcmp(".", dp->d_name) || 5266250Sroot !strcmp("..", dp->d_name)) 5271119Sbill continue; 5285931Smckusic strcpy(cp, dp->d_name); 52927445Slepreau l = telldir(dirp); 5305931Smckusic closedir(dirp); 5319601Ssam putfile(buf, cp, newparent); 5325931Smckusic dirp = opendir("."); 53327445Slepreau seekdir(dirp, l); 5341119Sbill } 5355931Smckusic closedir(dirp); 53615045Smckusick if (chdir(parent) < 0) { 53736227Sbostic fprintf(stderr, 53836227Sbostic "tar: cannot change back?: %s: %s\n", 53936227Sbostic parent, strerror(errno)); 54015045Smckusick } 54112154Ssam break; 54212154Ssam 54312154Ssam case S_IFLNK: 54412154Ssam tomodes(&stbuf); 54512154Ssam if (strlen(longname) >= NAMSIZ) { 54613492Ssam fprintf(stderr, "tar: %s: file name too long\n", 54713492Ssam longname); 54812154Ssam return; 54912154Ssam } 55012154Ssam strcpy(dblock.dbuf.name, longname); 5516250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 55213492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 55313492Ssam longname); 5546250Sroot return; 5556250Sroot } 5569601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5576250Sroot if (i < 0) { 55836227Sbostic fprintf(stderr, 55936227Sbostic "tar: can't read symbolic link %s: %s\n", 56036227Sbostic longname, strerror(errno)); 5616250Sroot return; 5626250Sroot } 5636250Sroot dblock.dbuf.linkname[i] = '\0'; 5646250Sroot dblock.dbuf.linkflag = '2'; 56522688Slepreau if (vflag) 56622688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 56722688Slepreau longname, dblock.dbuf.linkname); 56832420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo", 0L); 56932420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 57027445Slepreau (void) writetape((char *)&dblock); 57112154Ssam break; 5721119Sbill 57312154Ssam case S_IFREG: 57412154Ssam if ((infile = open(shortname, 0)) < 0) { 57536227Sbostic fprintf(stderr, "tar: %s: %s\n", 57636227Sbostic longname, strerror(errno)); 5771119Sbill return; 5781119Sbill } 57912154Ssam tomodes(&stbuf); 58012154Ssam if (strlen(longname) >= NAMSIZ) { 58113492Ssam fprintf(stderr, "tar: %s: file name too long\n", 58213492Ssam longname); 58321457Skjd close(infile); 58412154Ssam return; 58512154Ssam } 58612154Ssam strcpy(dblock.dbuf.name, longname); 58712154Ssam if (stbuf.st_nlink > 1) { 58812154Ssam struct linkbuf *lp; 58912154Ssam int found = 0; 59012154Ssam 59112154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 59212154Ssam if (lp->inum == stbuf.st_ino && 59312154Ssam lp->devnum == stbuf.st_dev) { 59412154Ssam found++; 59512154Ssam break; 59612154Ssam } 59712154Ssam if (found) { 59812154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 59912154Ssam dblock.dbuf.linkflag = '1'; 60032420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 60127445Slepreau (void) writetape( (char *) &dblock); 60222688Slepreau if (vflag) 60322688Slepreau fprintf(vfile, "a %s link to %s\n", 60422688Slepreau longname, lp->pathname); 60512154Ssam lp->count--; 60612154Ssam close(infile); 60712154Ssam return; 6081119Sbill } 60922688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 61022688Slepreau if (lp != NULL) { 61112154Ssam lp->nextp = ihead; 61212154Ssam ihead = lp; 61312154Ssam lp->inum = stbuf.st_ino; 61412154Ssam lp->devnum = stbuf.st_dev; 61512154Ssam lp->count = stbuf.st_nlink - 1; 61612154Ssam strcpy(lp->pathname, longname); 61712154Ssam } 6181119Sbill } 61921457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 62022688Slepreau if (vflag) 62122688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 62232420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 62321457Skjd hint = writetape((char *)&dblock); 62421457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 62527445Slepreau if ((bigbuf = malloc((unsigned)maxread)) == 0) { 62621457Skjd maxread = TBLOCK; 62721457Skjd bigbuf = buf; 62821457Skjd } 6291119Sbill 63021457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 63121457Skjd && blocks > 0) { 63221457Skjd register int nblks; 63321457Skjd 63421457Skjd nblks = ((i-1)/TBLOCK)+1; 63521457Skjd if (nblks > blocks) 63621457Skjd nblks = blocks; 63721457Skjd hint = writetbuf(bigbuf, nblks); 63821457Skjd blocks -= nblks; 63921457Skjd } 64021457Skjd close(infile); 64121457Skjd if (bigbuf != buf) 64221457Skjd free(bigbuf); 64327058Smckusick if (i < 0) { 64436227Sbostic fprintf(stderr, "tar: Read error on %s: %s\n", 64536227Sbostic longname, strerror(errno)); 64627058Smckusick } else if (blocks != 0 || i != 0) 64713492Ssam fprintf(stderr, "tar: %s: file changed size\n", 64813492Ssam longname); 64912154Ssam while (--blocks >= 0) 65012154Ssam putempty(); 65112154Ssam break; 65212154Ssam 65312154Ssam default: 65412154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 65513492Ssam longname); 65612154Ssam break; 6571119Sbill } 6581119Sbill } 6591119Sbill 6601119Sbill doxtract(argv) 6616250Sroot char *argv[]; 6621119Sbill { 6631119Sbill long blocks, bytes; 66427445Slepreau int ofile, i; 6651119Sbill 6661119Sbill for (;;) { 66727445Slepreau if ((i = wantit(argv)) == 0) 66827445Slepreau continue; 66927445Slepreau if (i == -1) 67027445Slepreau break; /* end of tape */ 6711119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6721119Sbill passtape(); 6731119Sbill continue; 6741119Sbill } 67512154Ssam if (Fflag) { 67612154Ssam char *s; 67712154Ssam 67812154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 67912154Ssam s = dblock.dbuf.name; 68012154Ssam else 68112154Ssam s++; 68212154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 68312154Ssam passtape(); 68412154Ssam continue; 68512154Ssam } 68612154Ssam } 68722688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 68822688Slepreau if (mflag == 0) 68922688Slepreau dodirtimes(&dblock); 6906250Sroot continue; 69122688Slepreau } 69222688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 69325250Sbloom /* 69425250Sbloom * only unlink non directories or empty 69525250Sbloom * directories 69625250Sbloom */ 69725250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 69825250Sbloom if (errno == ENOTDIR) 69925250Sbloom unlink(dblock.dbuf.name); 70025250Sbloom } 7016250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 70236227Sbostic fprintf(stderr, 70336227Sbostic "tar: %s: symbolic link failed: %s\n", 70436227Sbostic dblock.dbuf.name, strerror(errno)); 7056250Sroot continue; 7066250Sroot } 7076250Sroot if (vflag) 70821910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 70913492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 71022353Skjd #ifdef notdef 71122353Skjd /* ignore alien orders */ 71222353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 71322688Slepreau if (mflag == 0) 71422688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 71522353Skjd if (pflag) 71622353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 71722353Skjd #endif 7181119Sbill continue; 7196250Sroot } 72022688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 72125250Sbloom /* 72225250Sbloom * only unlink non directories or empty 72325250Sbloom * directories 72425250Sbloom */ 72525250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 72625250Sbloom if (errno == ENOTDIR) 72725250Sbloom unlink(dblock.dbuf.name); 72825250Sbloom } 7291119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 73036227Sbostic fprintf(stderr, 73136227Sbostic "tar: can't link %s to %s: %s\n", 73236227Sbostic dblock.dbuf.name, dblock.dbuf.linkname, 73336227Sbostic strerror(errno)); 7341119Sbill continue; 7351119Sbill } 7361119Sbill if (vflag) 73722688Slepreau fprintf(vfile, "%s linked to %s\n", 73813492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7391119Sbill continue; 7401119Sbill } 7416250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 74236227Sbostic fprintf(stderr, "tar: can't create %s: %s\n", 74336227Sbostic dblock.dbuf.name, strerror(errno)); 7441119Sbill passtape(); 7451119Sbill continue; 7461119Sbill } 74721457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7481119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7491119Sbill if (vflag) 75022688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 75113492Ssam dblock.dbuf.name, bytes, blocks); 75221457Skjd for (; blocks > 0;) { 75321457Skjd register int nread; 75421457Skjd char *bufp; 75521457Skjd register int nwant; 75621457Skjd 75721457Skjd nwant = NBLOCK*TBLOCK; 75821457Skjd if (nwant > (blocks*TBLOCK)) 75921457Skjd nwant = (blocks*TBLOCK); 76021457Skjd nread = readtbuf(&bufp, nwant); 76122688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7626250Sroot fprintf(stderr, 76336227Sbostic "tar: %s: HELP - extract write error: %s\n", 76436227Sbostic dblock.dbuf.name, strerror(errno)); 7656250Sroot done(2); 7666250Sroot } 76721457Skjd bytes -= nread; 76821457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7691119Sbill } 7701119Sbill close(ofile); 77122688Slepreau if (mflag == 0) 77222688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7731926Swnj if (pflag) 7746250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7751119Sbill } 77622688Slepreau if (mflag == 0) { 77722688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 77822688Slepreau dodirtimes(&dblock); 77922688Slepreau } 7801119Sbill } 7811119Sbill 78227445Slepreau dotable(argv) 78327445Slepreau char *argv[]; 7841119Sbill { 78527445Slepreau register int i; 78627445Slepreau 7871119Sbill for (;;) { 78827445Slepreau if ((i = wantit(argv)) == 0) 78927445Slepreau continue; 79027445Slepreau if (i == -1) 79127445Slepreau break; /* end of tape */ 7921119Sbill if (vflag) 7931119Sbill longt(&stbuf); 7941119Sbill printf("%s", dblock.dbuf.name); 7951119Sbill if (dblock.dbuf.linkflag == '1') 7961119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7976250Sroot if (dblock.dbuf.linkflag == '2') 7986250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7991119Sbill printf("\n"); 8001119Sbill passtape(); 8011119Sbill } 8021119Sbill } 8031119Sbill 8041119Sbill putempty() 8051119Sbill { 8061119Sbill char buf[TBLOCK]; 8071119Sbill 80813492Ssam bzero(buf, sizeof (buf)); 80927445Slepreau (void) writetape(buf); 8101119Sbill } 8111119Sbill 8121119Sbill longt(st) 8136250Sroot register struct stat *st; 8141119Sbill { 8151119Sbill register char *cp; 8161119Sbill char *ctime(); 8171119Sbill 8181119Sbill pmode(st); 81936227Sbostic printf("%3u/%1u", st->st_uid, st->st_gid); 82027445Slepreau printf("%7ld", st->st_size); 8211119Sbill cp = ctime(&st->st_mtime); 8221119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8231119Sbill } 8241119Sbill 8251119Sbill #define SUID 04000 8261119Sbill #define SGID 02000 8271119Sbill #define ROWN 0400 8281119Sbill #define WOWN 0200 8291119Sbill #define XOWN 0100 8301119Sbill #define RGRP 040 8311119Sbill #define WGRP 020 8321119Sbill #define XGRP 010 8331119Sbill #define ROTH 04 8341119Sbill #define WOTH 02 8351119Sbill #define XOTH 01 8361119Sbill #define STXT 01000 8371119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8381119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8391119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8401119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8411119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8421119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8431119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8441119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8451119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8461119Sbill 8471119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8481119Sbill 8491119Sbill pmode(st) 8506250Sroot register struct stat *st; 8511119Sbill { 8521119Sbill register int **mp; 8531119Sbill 8541119Sbill for (mp = &m[0]; mp < &m[9];) 85527058Smckusick selectbits(*mp++, st); 8561119Sbill } 8571119Sbill 85827058Smckusick selectbits(pairp, st) 8596250Sroot int *pairp; 8606250Sroot struct stat *st; 8611119Sbill { 8621119Sbill register int n, *ap; 8631119Sbill 8641119Sbill ap = pairp; 8651119Sbill n = *ap++; 8661119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8671119Sbill ap++; 86827445Slepreau putchar(*ap); 8691119Sbill } 8701119Sbill 87122688Slepreau /* 87227442Slepreau * Make all directories needed by `name'. If `name' is itself 87327442Slepreau * a directory on the tar tape (indicated by a trailing '/'), 87422688Slepreau * return 1; else 0. 87522688Slepreau */ 8761119Sbill checkdir(name) 8776250Sroot register char *name; 8781119Sbill { 8791119Sbill register char *cp; 8806250Sroot 88112154Ssam /* 88222688Slepreau * Quick check for existence of directory. 88312154Ssam */ 88412154Ssam if ((cp = rindex(name, '/')) == 0) 88512154Ssam return (0); 88612154Ssam *cp = '\0'; 88736227Sbostic if (access(name, F_OK) == 0) { /* already exists */ 88812154Ssam *cp = '/'; 88922688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 89012154Ssam } 89112154Ssam *cp = '/'; 89212154Ssam 89312154Ssam /* 89412154Ssam * No luck, try to make all directories in path. 89512154Ssam */ 8961119Sbill for (cp = name; *cp; cp++) { 8976250Sroot if (*cp != '/') 8986250Sroot continue; 8996250Sroot *cp = '\0'; 90036227Sbostic if (access(name, F_OK) < 0) { 9019844Ssam if (mkdir(name, 0777) < 0) { 90236227Sbostic fprintf(stderr, "tar: mkdir: %s: %s\n", 90336227Sbostic name, strerror(errno)); 90412154Ssam *cp = '/'; 90512154Ssam return (0); 9061119Sbill } 90721457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 90827442Slepreau if (pflag && cp[1] == '\0') /* dir on the tape */ 90927442Slepreau chmod(name, stbuf.st_mode & 07777); 9101119Sbill } 9116250Sroot *cp = '/'; 9121119Sbill } 9136250Sroot return (cp[-1]=='/'); 9141119Sbill } 9151119Sbill 916*46656Sbostic void 9171119Sbill onintr() 9181119Sbill { 91927445Slepreau (void) signal(SIGINT, SIG_IGN); 9201119Sbill term++; 9211119Sbill } 9221119Sbill 923*46656Sbostic void 9241119Sbill onquit() 9251119Sbill { 92627445Slepreau (void) signal(SIGQUIT, SIG_IGN); 9271119Sbill term++; 9281119Sbill } 9291119Sbill 930*46656Sbostic void 9311119Sbill onhup() 9321119Sbill { 93327445Slepreau (void) signal(SIGHUP, SIG_IGN); 9341119Sbill term++; 9351119Sbill } 9361119Sbill 93722688Slepreau #ifdef notdef 938*46656Sbostic void 9391119Sbill onterm() 9401119Sbill { 94127445Slepreau (void) signal(SIGTERM, SIG_IGN); 9421119Sbill term++; 9431119Sbill } 94422688Slepreau #endif 9451119Sbill 9461119Sbill tomodes(sp) 9471119Sbill register struct stat *sp; 9481119Sbill { 9491119Sbill register char *cp; 9501119Sbill 9511119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9521119Sbill *cp = '\0'; 95332420Sbostic (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 95432420Sbostic (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 95532420Sbostic (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 95632420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 95732420Sbostic (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9581119Sbill } 9591119Sbill 9601119Sbill checksum() 9611119Sbill { 9621119Sbill register i; 9631119Sbill register char *cp; 9641119Sbill 9656250Sroot for (cp = dblock.dbuf.chksum; 9666250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9671119Sbill *cp = ' '; 9681119Sbill i = 0; 9691119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9701119Sbill i += *cp; 9716250Sroot return (i); 9721119Sbill } 9731119Sbill 9741119Sbill checkw(c, name) 9756250Sroot char *name; 9761119Sbill { 9776250Sroot if (!wflag) 9786250Sroot return (1); 9796250Sroot printf("%c ", c); 9806250Sroot if (vflag) 9816250Sroot longt(&stbuf); 9826250Sroot printf("%s: ", name); 9836250Sroot return (response() == 'y'); 9841119Sbill } 9851119Sbill 9861119Sbill response() 9871119Sbill { 9881119Sbill char c; 9891119Sbill 9901119Sbill c = getchar(); 9911119Sbill if (c != '\n') 9926250Sroot while (getchar() != '\n') 9936250Sroot ; 9946250Sroot else 9956250Sroot c = 'n'; 9966250Sroot return (c); 9971119Sbill } 9981119Sbill 99912154Ssam checkf(name, mode, howmuch) 100012154Ssam char *name; 100112154Ssam int mode, howmuch; 100212154Ssam { 100312154Ssam int l; 100412154Ssam 100521910Skjd if ((mode & S_IFMT) == S_IFDIR){ 100621910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 100721910Skjd return(0); 100821910Skjd return(1); 100921910Skjd } 101012154Ssam if ((l = strlen(name)) < 3) 101112154Ssam return (1); 101212154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 101312154Ssam return (0); 101412154Ssam if (strcmp(name, "core") == 0 || 101512154Ssam strcmp(name, "errs") == 0 || 101612154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 101712154Ssam return (0); 101812154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 101912154Ssam return (1); 102012154Ssam } 102112154Ssam 102222688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 10231119Sbill checkupdate(arg) 10246250Sroot char *arg; 10251119Sbill { 10261119Sbill char name[100]; 10276250Sroot long mtime; 10281119Sbill daddr_t seekp; 10291119Sbill daddr_t lookup(); 10301119Sbill 10311119Sbill rewind(tfile); 10321119Sbill for (;;) { 10331119Sbill if ((seekp = lookup(arg)) < 0) 10346250Sroot return (1); 10351119Sbill fseek(tfile, seekp, 0); 10361119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10376250Sroot return (stbuf.st_mtime > mtime); 10381119Sbill } 10391119Sbill } 10401119Sbill 10411119Sbill done(n) 10421119Sbill { 104321457Skjd unlink(tname); 10441119Sbill exit(n); 10451119Sbill } 10461119Sbill 104727445Slepreau /* 104827445Slepreau * Do we want the next entry on the tape, i.e. is it selected? If 104927445Slepreau * not, skip over the entire entry. Return -1 if reached end of tape. 105027445Slepreau */ 105127445Slepreau wantit(argv) 105227445Slepreau char *argv[]; 105327445Slepreau { 105427445Slepreau register char **cp; 105527445Slepreau 105627445Slepreau getdir(); 105727445Slepreau if (endtape()) 105827445Slepreau return (-1); 105927445Slepreau if (*argv == 0) 106027445Slepreau return (1); 106127445Slepreau for (cp = argv; *cp; cp++) 106227445Slepreau if (prefix(*cp, dblock.dbuf.name)) 106327445Slepreau return (1); 106427445Slepreau passtape(); 106527445Slepreau return (0); 106627445Slepreau } 106727445Slepreau 106822688Slepreau /* 106922688Slepreau * Does s2 begin with the string s1, on a directory boundary? 107022688Slepreau */ 10711119Sbill prefix(s1, s2) 10726250Sroot register char *s1, *s2; 10731119Sbill { 10741119Sbill while (*s1) 10751119Sbill if (*s1++ != *s2++) 10766250Sroot return (0); 10771119Sbill if (*s2) 10786250Sroot return (*s2 == '/'); 10796250Sroot return (1); 10801119Sbill } 10811119Sbill 10821119Sbill #define N 200 10831119Sbill int njab; 10846250Sroot 10851119Sbill daddr_t 10861119Sbill lookup(s) 10876250Sroot char *s; 10881119Sbill { 10891119Sbill register i; 10901119Sbill daddr_t a; 10911119Sbill 10921119Sbill for(i=0; s[i]; i++) 10936250Sroot if (s[i] == ' ') 10941119Sbill break; 10951119Sbill a = bsrch(s, i, low, high); 10966250Sroot return (a); 10971119Sbill } 10981119Sbill 10991119Sbill daddr_t 11001119Sbill bsrch(s, n, l, h) 11016250Sroot daddr_t l, h; 11026250Sroot char *s; 11031119Sbill { 11041119Sbill register i, j; 11051119Sbill char b[N]; 11061119Sbill daddr_t m, m1; 11071119Sbill 11081119Sbill njab = 0; 11091119Sbill 11101119Sbill loop: 11116250Sroot if (l >= h) 111222688Slepreau return ((daddr_t) -1); 11131119Sbill m = l + (h-l)/2 - N/2; 11146250Sroot if (m < l) 11151119Sbill m = l; 11161119Sbill fseek(tfile, m, 0); 11171119Sbill fread(b, 1, N, tfile); 11181119Sbill njab++; 11191119Sbill for(i=0; i<N; i++) { 11206250Sroot if (b[i] == '\n') 11211119Sbill break; 11221119Sbill m++; 11231119Sbill } 11246250Sroot if (m >= h) 112522688Slepreau return ((daddr_t) -1); 11261119Sbill m1 = m; 11271119Sbill j = i; 11281119Sbill for(i++; i<N; i++) { 11291119Sbill m1++; 11306250Sroot if (b[i] == '\n') 11311119Sbill break; 11321119Sbill } 11331119Sbill i = cmp(b+j, s, n); 11346250Sroot if (i < 0) { 11351119Sbill h = m; 11361119Sbill goto loop; 11371119Sbill } 11386250Sroot if (i > 0) { 11391119Sbill l = m1; 11401119Sbill goto loop; 11411119Sbill } 11426250Sroot return (m); 11431119Sbill } 11441119Sbill 11451119Sbill cmp(b, s, n) 11466250Sroot char *b, *s; 11471119Sbill { 11481119Sbill register i; 11491119Sbill 11506250Sroot if (b[0] != '\n') 115121457Skjd exit(2); 11521119Sbill for(i=0; i<n; i++) { 11536250Sroot if (b[i+1] > s[i]) 11546250Sroot return (-1); 11556250Sroot if (b[i+1] < s[i]) 11566250Sroot return (1); 11571119Sbill } 11586250Sroot return (b[i+1] == ' '? 0 : -1); 11591119Sbill } 11601119Sbill 116122688Slepreau readtape(buffer) 11626250Sroot char *buffer; 11631119Sbill { 116421457Skjd char *bufp; 116521457Skjd 116622688Slepreau if (first == 0) 116722688Slepreau getbuf(); 116827445Slepreau (void) readtbuf(&bufp, TBLOCK); 116921457Skjd bcopy(bufp, buffer, TBLOCK); 117021457Skjd return(TBLOCK); 117121457Skjd } 117221457Skjd 117321457Skjd readtbuf(bufpp, size) 117421457Skjd char **bufpp; 117521457Skjd int size; 117621457Skjd { 11773457Swnj register int i; 11781119Sbill 11791119Sbill if (recno >= nblock || first == 0) { 118027445Slepreau if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 118127058Smckusick mterr("read", i, 3); 11821119Sbill if (first == 0) { 11831119Sbill if ((i % TBLOCK) != 0) { 118413492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11851119Sbill done(3); 11861119Sbill } 11871119Sbill i /= TBLOCK; 11883457Swnj if (i != nblock) { 118913492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11901119Sbill nblock = i; 11911119Sbill } 119222353Skjd first = 1; 11931119Sbill } 11941119Sbill recno = 0; 11951119Sbill } 119621457Skjd if (size > ((nblock-recno)*TBLOCK)) 119721457Skjd size = (nblock-recno)*TBLOCK; 119821457Skjd *bufpp = (char *)&tbuf[recno]; 119921457Skjd recno += (size/TBLOCK); 120021457Skjd return (size); 12011119Sbill } 12021119Sbill 120321457Skjd writetbuf(buffer, n) 120421457Skjd register char *buffer; 120521457Skjd register int n; 12061119Sbill { 120727058Smckusick int i; 120822688Slepreau 120922688Slepreau if (first == 0) { 121022353Skjd getbuf(); 121122353Skjd first = 1; 121222353Skjd } 12131119Sbill if (recno >= nblock) { 121427445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 121527058Smckusick if (i != TBLOCK*nblock) 121627058Smckusick mterr("write", i, 2); 12171119Sbill recno = 0; 12181119Sbill } 121921457Skjd 122021457Skjd /* 122121457Skjd * Special case: We have an empty tape buffer, and the 122221457Skjd * users data size is >= the tape block size: Avoid 122321457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 122421457Skjd * residual to the tape buffer. 122521457Skjd */ 122621457Skjd while (recno == 0 && n >= nblock) { 122727058Smckusick i = write(mt, buffer, TBLOCK*nblock); 122827058Smckusick if (i != TBLOCK*nblock) 122927058Smckusick mterr("write", i, 2); 123021457Skjd n -= nblock; 123121457Skjd buffer += (nblock * TBLOCK); 12321119Sbill } 123321457Skjd 123421457Skjd while (n-- > 0) { 123521457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 123621457Skjd buffer += TBLOCK; 123721457Skjd if (recno >= nblock) { 123827445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 123927058Smckusick if (i != TBLOCK*nblock) 124027058Smckusick mterr("write", i, 2); 124121457Skjd recno = 0; 124221457Skjd } 124321457Skjd } 124421457Skjd 124521457Skjd /* Tell the user how much to write to get in sync */ 124621457Skjd return (nblock - recno); 12471119Sbill } 12481119Sbill 12491119Sbill backtape() 12501119Sbill { 125127058Smckusick static int mtdev = 1; 12523457Swnj static struct mtop mtop = {MTBSR, 1}; 125327058Smckusick struct mtget mtget; 125427058Smckusick 125527058Smckusick if (mtdev == 1) 125627445Slepreau mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 12573457Swnj if (mtdev == 0) { 125827445Slepreau if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 125936227Sbostic fprintf(stderr, "tar: tape backspace error: %s\n", 126036227Sbostic strerror(errno)); 12611119Sbill done(4); 12621119Sbill } 12633457Swnj } else 126436227Sbostic (void)lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 12653457Swnj recno--; 12661119Sbill } 12671119Sbill 12681119Sbill flushtape() 12691119Sbill { 127027058Smckusick int i; 127127058Smckusick 127227445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 127327058Smckusick if (i != TBLOCK*nblock) 127427058Smckusick mterr("write", i, 2); 12751119Sbill } 12761119Sbill 127727058Smckusick mterr(operation, i, exitcode) 127827058Smckusick char *operation; 127927058Smckusick int i; 128027058Smckusick { 128136227Sbostic fprintf(stderr, "tar: tape %s error: %s\n", 128236227Sbostic operation, i < 0 ? strerror(errno) : "unexpected EOF"); 128327058Smckusick done(exitcode); 128427058Smckusick } 128527058Smckusick 12868737Smckusick bread(fd, buf, size) 12878737Smckusick int fd; 12888737Smckusick char *buf; 12898737Smckusick int size; 12908737Smckusick { 12918737Smckusick int count; 12928737Smckusick static int lastread = 0; 12938737Smckusick 129422688Slepreau if (!Bflag) 129522688Slepreau return (read(fd, buf, size)); 129622353Skjd 12978737Smckusick for (count = 0; count < size; count += lastread) { 129824281Smckusick lastread = read(fd, buf, size - count); 129924281Smckusick if (lastread <= 0) { 13008737Smckusick if (count > 0) 13018737Smckusick return (count); 13028737Smckusick return (lastread); 13038737Smckusick } 13048737Smckusick buf += lastread; 13058737Smckusick } 13068737Smckusick return (count); 13078737Smckusick } 130810165Ssam 130910165Ssam char * 1310*46656Sbostic cwd() 131110165Ssam { 1312*46656Sbostic char *p; 1313*46656Sbostic 1314*46656Sbostic p = getcwd((char *)NULL, 0); 1315*46656Sbostic if (p == NULL) { 1316*46656Sbostic (void)fprintf(stderr, "tar: %s\n", strerror(errno)); 131721457Skjd exit(1); 131810165Ssam } 1319*46656Sbostic return (p); 132010165Ssam } 132121910Skjd 132221910Skjd getbuf() 132321910Skjd { 132422353Skjd 132527058Smckusick if (nblock == 0) { 132621910Skjd fstat(mt, &stbuf); 132721910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 132827058Smckusick nblock = NBLOCK; 132921910Skjd else { 133027058Smckusick nblock = stbuf.st_blksize / TBLOCK; 133127058Smckusick if (nblock == 0) 133227058Smckusick nblock = NBLOCK; 133321910Skjd } 133421910Skjd } 133527445Slepreau tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 133621910Skjd if (tbuf == NULL) { 133721910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 133821910Skjd nblock); 133921910Skjd done(1); 134021910Skjd } 134121910Skjd } 134222353Skjd 134322688Slepreau /* 134427442Slepreau * Save this directory and its mtime on the stack, popping and setting 134527442Slepreau * the mtimes of any stacked dirs which aren't parents of this one. 134627442Slepreau * A null directory causes the entire stack to be unwound and set. 134722688Slepreau * 134827442Slepreau * Since all the elements of the directory "stack" share a common 134927442Slepreau * prefix, we can make do with one string. We keep only the current 135027442Slepreau * directory path, with an associated array of mtime's, one for each 135127442Slepreau * '/' in the path. A negative mtime means no mtime. The mtime's are 135227442Slepreau * offset by one (first index 1, not 0) because calling this with a null 135327442Slepreau * directory causes mtime[0] to be set. 135427442Slepreau * 135522688Slepreau * This stack algorithm is not guaranteed to work for tapes created 135622688Slepreau * with the 'r' option, but the vast majority of tapes with 135722688Slepreau * directories are not. This avoids saving every directory record on 135822688Slepreau * the tape and setting all the times at the end. 135922688Slepreau */ 136022688Slepreau char dirstack[NAMSIZ]; 136122688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 136222688Slepreau time_t mtime[NTIM]; 136322353Skjd 136422688Slepreau dodirtimes(hp) 136522688Slepreau union hblock *hp; 136622353Skjd { 136722688Slepreau register char *p = dirstack; 136822688Slepreau register char *q = hp->dbuf.name; 136922688Slepreau register int ndir = 0; 137022688Slepreau char *savp; 137122688Slepreau int savndir; 137222353Skjd 137322688Slepreau /* Find common prefix */ 137430090Sbostic while (*p == *q && *p) { 137522688Slepreau if (*p++ == '/') 137622688Slepreau ++ndir; 137722688Slepreau q++; 137822688Slepreau } 137922353Skjd 138022688Slepreau savp = p; 138122688Slepreau savndir = ndir; 138222688Slepreau while (*p) { 138322688Slepreau /* 138422688Slepreau * Not a child: unwind the stack, setting the times. 138522688Slepreau * The order we do this doesn't matter, so we go "forward." 138622688Slepreau */ 138722688Slepreau if (*p++ == '/') 138822688Slepreau if (mtime[++ndir] >= 0) { 138922688Slepreau *--p = '\0'; /* zap the slash */ 139022688Slepreau setimes(dirstack, mtime[ndir]); 139122688Slepreau *p++ = '/'; 139222688Slepreau } 139322688Slepreau } 139422688Slepreau p = savp; 139522688Slepreau ndir = savndir; 139622353Skjd 139722688Slepreau /* Push this one on the "stack" */ 139822688Slepreau while (*p = *q++) /* append the rest of the new dir */ 139922688Slepreau if (*p++ == '/') 140022688Slepreau mtime[++ndir] = -1; 140122688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 140222688Slepreau } 140322353Skjd 140422688Slepreau setimes(path, mt) 140522688Slepreau char *path; 140622688Slepreau time_t mt; 140722688Slepreau { 140822688Slepreau struct timeval tv[2]; 140922353Skjd 141022688Slepreau tv[0].tv_sec = time((time_t *) 0); 141122688Slepreau tv[1].tv_sec = mt; 141222688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 141336227Sbostic if (utimes(path, tv) < 0) 141436227Sbostic fprintf(stderr, "tar: can't set time on %s: %s\n", 141536227Sbostic path, strerror(errno)); 141622688Slepreau } 141722688Slepreau 141822688Slepreau char * 141922688Slepreau getmem(size) 142022688Slepreau { 142122688Slepreau char *p = malloc((unsigned) size); 142222688Slepreau 142322688Slepreau if (p == NULL && freemem) { 142422688Slepreau fprintf(stderr, 142522688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 142622688Slepreau freemem = 0; 142722353Skjd } 142822688Slepreau return (p); 142922353Skjd } 1430