1*47845Sbostic /*- 2*47845Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*47845Sbostic * All rights reserved. 4*47845Sbostic * 5*47845Sbostic * %sccs.include.proprietary.c% 622502Sdist */ 722502Sdist 812154Ssam #ifndef lint 922502Sdist char copyright[] = 10*47845Sbostic "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 1122502Sdist All rights reserved.\n"; 1233082Sbostic #endif /* not lint */ 136250Sroot 1422502Sdist #ifndef lint 15*47845Sbostic static char sccsid[] = "@(#)tar.c 5.17 (Berkeley) 04/08/91"; 1633082Sbostic #endif /* not lint */ 1722502Sdist 186250Sroot /* 196250Sroot * Tape Archival Program 206250Sroot */ 216413Smckusic #include <sys/param.h> 221119Sbill #include <sys/stat.h> 238150Smckusick #include <sys/ioctl.h> 243457Swnj #include <sys/mtio.h> 2512983Ssam #include <sys/time.h> 2646656Sbostic #include <dirent.h> 2746656Sbostic #include <fcntl.h> 281119Sbill #include <signal.h> 2912154Ssam #include <errno.h> 3027058Smckusick #include <fcntl.h> 3146656Sbostic #include <unistd.h> 3246656Sbostic #include <stdio.h> 3342013Sbostic #include <string.h> 3446656Sbostic #include <stdlib.h> 3537681Sbostic #include "pathnames.h" 361119Sbill 371119Sbill #define TBLOCK 512 383355Swnj #define NBLOCK 20 391119Sbill #define NAMSIZ 100 406250Sroot 4121457Skjd #define writetape(b) writetbuf(b, 1) 4221457Skjd #define min(a,b) ((a) < (b) ? (a) : (b)) 4321457Skjd #define max(a,b) ((a) > (b) ? (a) : (b)) 4421457Skjd 451119Sbill union hblock { 461119Sbill char dummy[TBLOCK]; 471119Sbill struct header { 481119Sbill char name[NAMSIZ]; 491119Sbill char mode[8]; 501119Sbill char uid[8]; 511119Sbill char gid[8]; 521119Sbill char size[12]; 531119Sbill char mtime[12]; 541119Sbill char chksum[8]; 551119Sbill char linkflag; 561119Sbill char linkname[NAMSIZ]; 571119Sbill } dbuf; 586250Sroot }; 591119Sbill 601119Sbill struct linkbuf { 611119Sbill ino_t inum; 621119Sbill dev_t devnum; 631119Sbill int count; 641119Sbill char pathname[NAMSIZ]; 651119Sbill struct linkbuf *nextp; 666250Sroot }; 671119Sbill 686250Sroot union hblock dblock; 6913492Ssam union hblock *tbuf; 706250Sroot struct linkbuf *ihead; 716250Sroot struct stat stbuf; 721119Sbill 736250Sroot int rflag; 7434429Sbostic int sflag; 756250Sroot int xflag; 766250Sroot int vflag; 776250Sroot int tflag; 786250Sroot int cflag; 796250Sroot int mflag; 806250Sroot int fflag; 8112154Ssam int iflag; 826250Sroot int oflag; 836250Sroot int pflag; 846250Sroot int wflag; 856250Sroot int hflag; 868737Smckusick int Bflag; 8712154Ssam int Fflag; 886250Sroot 896250Sroot int mt; 906250Sroot int term; 916250Sroot int chksum; 926250Sroot int recno; 9322688Slepreau int first; 9422688Slepreau int prtlinkerr; 951119Sbill int freemem = 1; 9622353Skjd int nblock = 0; 9746656Sbostic void onintr(), onquit(), onhup(); 9822688Slepreau #ifdef notdef 9946656Sbostic void onterm(); 10022688Slepreau #endif 1011119Sbill 1021119Sbill daddr_t low; 1031119Sbill daddr_t high; 1046250Sroot daddr_t bsrch(); 1051119Sbill 10621910Skjd FILE *vfile = stdout; 1071119Sbill FILE *tfile; 10837681Sbostic char tname[] = _PATH_TMP; 1091119Sbill char *usefile; 11037681Sbostic char magtape[] = _PATH_MAGTAPE; 11146656Sbostic char *cwd(); 11222688Slepreau char *getmem(); 1131119Sbill 11436227Sbostic extern int errno; 11536227Sbostic 1161119Sbill main(argc, argv) 11736227Sbostic int argc; 11836227Sbostic char **argv; 1191119Sbill { 1201119Sbill char *cp; 1211119Sbill 1221119Sbill if (argc < 2) 1231119Sbill usage(); 1241119Sbill 1251119Sbill tfile = NULL; 1261119Sbill usefile = magtape; 1271119Sbill argv[argc] = 0; 1281119Sbill argv++; 1291119Sbill for (cp = *argv++; *cp; cp++) 1301119Sbill switch(*cp) { 1316250Sroot 1321119Sbill case 'f': 13312154Ssam if (*argv == 0) { 13412154Ssam fprintf(stderr, 13512154Ssam "tar: tapefile must be specified with 'f' option\n"); 13612154Ssam usage(); 13712154Ssam } 1381119Sbill usefile = *argv++; 1391119Sbill fflag++; 1401119Sbill break; 1416250Sroot 1421119Sbill case 'c': 1431119Sbill cflag++; 1441119Sbill rflag++; 1451119Sbill break; 1466250Sroot 1471119Sbill case 'o': 1481119Sbill oflag++; 1491119Sbill break; 1506250Sroot 1511119Sbill case 'p': 1521119Sbill pflag++; 1531119Sbill break; 1546250Sroot 1551119Sbill case 'u': 15636227Sbostic (void)mktemp(tname); 1571119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1586250Sroot fprintf(stderr, 15922688Slepreau "tar: cannot create temporary file (%s)\n", 1606250Sroot tname); 1611119Sbill done(1); 1621119Sbill } 1631119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1646250Sroot /*FALL THRU*/ 1656250Sroot 1661119Sbill case 'r': 1671119Sbill rflag++; 1681119Sbill break; 1696250Sroot 17034429Sbostic case 's': 17134429Sbostic sflag++; 17234429Sbostic break; 17334429Sbostic 1741119Sbill case 'v': 1751119Sbill vflag++; 1761119Sbill break; 1776250Sroot 1781119Sbill case 'w': 1791119Sbill wflag++; 1801119Sbill break; 1816250Sroot 1821119Sbill case 'x': 1831119Sbill xflag++; 1841119Sbill break; 1856250Sroot 1861119Sbill case 't': 1871119Sbill tflag++; 1881119Sbill break; 1896250Sroot 1901119Sbill case 'm': 1911119Sbill mflag++; 1921119Sbill break; 1936250Sroot 1941119Sbill case '-': 1951119Sbill break; 1966250Sroot 1971119Sbill case '0': 1981119Sbill case '1': 1991119Sbill case '4': 2001119Sbill case '5': 20121457Skjd case '7': 2021119Sbill case '8': 2031119Sbill magtape[8] = *cp; 2041119Sbill usefile = magtape; 2051119Sbill break; 2066250Sroot 2071119Sbill case 'b': 20813492Ssam if (*argv == 0) { 20913492Ssam fprintf(stderr, 21013492Ssam "tar: blocksize must be specified with 'b' option\n"); 21113492Ssam usage(); 21213492Ssam } 21313492Ssam nblock = atoi(*argv); 21413492Ssam if (nblock <= 0) { 21513492Ssam fprintf(stderr, 21613492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2171119Sbill done(1); 2181119Sbill } 21913492Ssam argv++; 2201119Sbill break; 2216250Sroot 2221119Sbill case 'l': 22322688Slepreau prtlinkerr++; 2241119Sbill break; 2256250Sroot 2266250Sroot case 'h': 2276250Sroot hflag++; 2286250Sroot break; 2296250Sroot 23012154Ssam case 'i': 23112154Ssam iflag++; 23212154Ssam break; 23312154Ssam 2348737Smckusick case 'B': 2358737Smckusick Bflag++; 2368737Smckusick break; 2378737Smckusick 23812154Ssam case 'F': 23912154Ssam Fflag++; 24012154Ssam break; 24112154Ssam 2421119Sbill default: 2431119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2441119Sbill usage(); 2451119Sbill } 2461119Sbill 2476250Sroot if (!rflag && !xflag && !tflag) 2486250Sroot usage(); 2491119Sbill if (rflag) { 2506250Sroot if (cflag && tfile != NULL) 2511119Sbill usage(); 2521119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 25327445Slepreau (void) signal(SIGINT, onintr); 2541119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 25527445Slepreau (void) signal(SIGHUP, onhup); 2561119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 25727445Slepreau (void) signal(SIGQUIT, onquit); 2586250Sroot #ifdef notdef 2591119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 26027445Slepreau (void) signal(SIGTERM, onterm); 2616250Sroot #endif 26227058Smckusick mt = openmt(usefile, 1); 2631119Sbill dorep(argv); 2646250Sroot done(0); 2651119Sbill } 26627058Smckusick mt = openmt(usefile, 0); 2676250Sroot if (xflag) 2681119Sbill doxtract(argv); 2696250Sroot else 27027445Slepreau dotable(argv); 2711119Sbill done(0); 2721119Sbill } 2731119Sbill 2741119Sbill usage() 2751119Sbill { 2766250Sroot fprintf(stderr, 27721457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2781119Sbill done(1); 2791119Sbill } 2801119Sbill 28127058Smckusick int 28227058Smckusick openmt(tape, writing) 28327058Smckusick char *tape; 28427058Smckusick int writing; 28527058Smckusick { 28627058Smckusick if (strcmp(tape, "-") == 0) { 28727058Smckusick /* 28827058Smckusick * Read from standard input or write to standard output. 28927058Smckusick */ 29027058Smckusick if (writing) { 29127058Smckusick if (cflag == 0) { 29227058Smckusick fprintf(stderr, 29327058Smckusick "tar: can only create standard output archives\n"); 29427058Smckusick done(1); 29527058Smckusick } 29627058Smckusick vfile = stderr; 29727058Smckusick setlinebuf(vfile); 29827058Smckusick mt = dup(1); 29927058Smckusick } else { 30027058Smckusick mt = dup(0); 30127058Smckusick Bflag++; 30227058Smckusick } 30327058Smckusick } else { 30427058Smckusick /* 30527058Smckusick * Use file or tape on local machine. 30627058Smckusick */ 30727058Smckusick if (writing) { 30827058Smckusick if (cflag) 30927445Slepreau mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); 31027058Smckusick else 31127058Smckusick mt = open(tape, O_RDWR); 31227058Smckusick } else 31327058Smckusick mt = open(tape, O_RDONLY); 31427058Smckusick if (mt < 0) { 31536227Sbostic fprintf(stderr, "tar: %s: %s\n", tape, strerror(errno)); 31627058Smckusick done(1); 31727058Smckusick } 31827058Smckusick } 31927058Smckusick return(mt); 32027058Smckusick } 32127058Smckusick 3221119Sbill dorep(argv) 3236250Sroot char *argv[]; 3241119Sbill { 3251119Sbill register char *cp, *cp2; 32646656Sbostic char *parent, *wdir; 3271119Sbill 3281119Sbill if (!cflag) { 3291119Sbill getdir(); 3301119Sbill do { 3311119Sbill passtape(); 3321119Sbill if (term) 3331119Sbill done(0); 3341119Sbill getdir(); 3351119Sbill } while (!endtape()); 33613492Ssam backtape(); 3371119Sbill if (tfile != NULL) { 3381119Sbill char buf[200]; 3391119Sbill 34032420Sbostic (void)sprintf(buf, 3416250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3421119Sbill tname, tname, tname, tname, tname, tname); 3431119Sbill fflush(tfile); 3441119Sbill system(buf); 3451119Sbill freopen(tname, "r", tfile); 3461119Sbill fstat(fileno(tfile), &stbuf); 3471119Sbill high = stbuf.st_size; 3481119Sbill } 3491119Sbill } 3501119Sbill 35146656Sbostic wdir = cwd(); 3521119Sbill while (*argv && ! term) { 3531119Sbill cp2 = *argv; 3541119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3551119Sbill argv++; 35627058Smckusick if (chdir(*argv) < 0) { 35736227Sbostic fprintf(stderr, 35836227Sbostic "tar: can't change directories to %s: %s\n", 35936227Sbostic *argv, strerror(errno)); 36046656Sbostic } else { 36146656Sbostic free(wdir); 36246656Sbostic wdir = cwd(); 36346656Sbostic } 3641119Sbill argv++; 3651119Sbill continue; 3661119Sbill } 3679601Ssam parent = wdir; 3681119Sbill for (cp = *argv; *cp; cp++) 3691119Sbill if (*cp == '/') 3701119Sbill cp2 = cp; 3711119Sbill if (cp2 != *argv) { 3721119Sbill *cp2 = '\0'; 3739601Ssam if (chdir(*argv) < 0) { 37436227Sbostic fprintf(stderr, 37536227Sbostic "tar: can't change directories to %s: %s\n", 37636227Sbostic *argv, strerror(errno)); 3779601Ssam continue; 3789601Ssam } 37946656Sbostic parent = cwd(); 3801119Sbill *cp2 = '/'; 3811119Sbill cp2++; 3821119Sbill } 3839601Ssam putfile(*argv++, cp2, parent); 38436227Sbostic if (chdir(wdir) < 0) 38536227Sbostic fprintf(stderr, "tar: cannot change back?: %s: %s\n", 38636227Sbostic wdir, strerror(errno)); 3871119Sbill } 3881119Sbill putempty(); 3891119Sbill putempty(); 3901119Sbill flushtape(); 39122688Slepreau if (prtlinkerr == 0) 3926250Sroot return; 3936250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3946250Sroot if (ihead->count == 0) 3956250Sroot continue; 39613492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3976250Sroot } 3981119Sbill } 3991119Sbill 4001119Sbill endtape() 4011119Sbill { 40221457Skjd return (dblock.dbuf.name[0] == '\0'); 4031119Sbill } 4041119Sbill 4051119Sbill getdir() 4061119Sbill { 4071119Sbill register struct stat *sp; 4081119Sbill int i; 4091119Sbill 41012154Ssam top: 4116250Sroot readtape((char *)&dblock); 4121119Sbill if (dblock.dbuf.name[0] == '\0') 4131119Sbill return; 4141119Sbill sp = &stbuf; 4151119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4161119Sbill sp->st_mode = i; 4171119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4181119Sbill sp->st_uid = i; 4191119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4201119Sbill sp->st_gid = i; 4211119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4221119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4231119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 42412154Ssam if (chksum != (i = checksum())) { 42513492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 42612154Ssam chksum, i); 42712154Ssam if (iflag) 42812154Ssam goto top; 4291119Sbill done(2); 4301119Sbill } 43134429Sbostic /* strip off leading "/" if present */ 43234429Sbostic if (sflag && dblock.dbuf.name[0] == '/') { 43334429Sbostic register char *cp1, *cp2; 43434429Sbostic for (cp1 = cp2 = dblock.dbuf.name; *cp2 && *cp2 == '/'; ++cp2); 43534429Sbostic if (!*cp2) 43634429Sbostic goto top; 43734429Sbostic while (*cp1++ = *cp2++); 43834429Sbostic } 4391119Sbill if (tfile != NULL) 4401119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4411119Sbill } 4421119Sbill 4431119Sbill passtape() 4441119Sbill { 4451119Sbill long blocks; 44621457Skjd char *bufp; 4471119Sbill 4481119Sbill if (dblock.dbuf.linkflag == '1') 4491119Sbill return; 4501119Sbill blocks = stbuf.st_size; 4511119Sbill blocks += TBLOCK-1; 4521119Sbill blocks /= TBLOCK; 4531119Sbill 45421457Skjd while (blocks-- > 0) 45527445Slepreau (void) readtbuf(&bufp, TBLOCK); 4561119Sbill } 4571119Sbill 4589601Ssam putfile(longname, shortname, parent) 4596250Sroot char *longname; 4606250Sroot char *shortname; 4619601Ssam char *parent; 4621119Sbill { 46321457Skjd int infile = 0; 46421457Skjd long blocks; 4651119Sbill char buf[TBLOCK]; 46621457Skjd char *bigbuf; 46722688Slepreau register char *cp; 46846656Sbostic struct dirent *dp; 4695931Smckusic DIR *dirp; 47027445Slepreau register int i; 47127445Slepreau long l; 4729601Ssam char newparent[NAMSIZ+64]; 47321457Skjd int maxread; 47421457Skjd int hint; /* amount to write to get "in sync" */ 4751119Sbill 4769601Ssam if (!hflag) 47712154Ssam i = lstat(shortname, &stbuf); 47812154Ssam else 47912154Ssam i = stat(shortname, &stbuf); 48012154Ssam if (i < 0) { 48136227Sbostic fprintf(stderr, "tar: %s: %s\n", longname, strerror(errno)); 4829601Ssam return; 4839601Ssam } 48412154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4851119Sbill return; 48612154Ssam if (checkw('r', longname) == 0) 4871119Sbill return; 48812154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 48912154Ssam return; 4901119Sbill 49112154Ssam switch (stbuf.st_mode & S_IFMT) { 49212154Ssam case S_IFDIR: 4936250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4946250Sroot ; 4951119Sbill *--cp = '/'; 4961119Sbill *++cp = 0 ; 4971119Sbill if (!oflag) { 4986250Sroot if ((cp - buf) >= NAMSIZ) { 49913492Ssam fprintf(stderr, "tar: %s: file name too long\n", 50013492Ssam longname); 5016250Sroot return; 5026250Sroot } 5036250Sroot stbuf.st_size = 0; 5046250Sroot tomodes(&stbuf); 5056250Sroot strcpy(dblock.dbuf.name,buf); 50632420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 50727445Slepreau (void) writetape((char *)&dblock); 5081119Sbill } 50932420Sbostic (void)sprintf(newparent, "%s/%s", parent, shortname); 51015045Smckusick if (chdir(shortname) < 0) { 51136227Sbostic fprintf(stderr, "tar: chdir %s: %s\n", 51236227Sbostic shortname, strerror(errno)); 51315045Smckusick return; 51415045Smckusick } 5155931Smckusic if ((dirp = opendir(".")) == NULL) { 51613492Ssam fprintf(stderr, "tar: %s: directory read error\n", 51713492Ssam longname); 51815045Smckusick if (chdir(parent) < 0) { 51936227Sbostic fprintf(stderr, 52036227Sbostic "tar: cannot change back?: %s: %s\n", 52136227Sbostic parent, strerror(errno)); 52215045Smckusick } 5235931Smckusic return; 5245931Smckusic } 5255931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5266250Sroot if (!strcmp(".", dp->d_name) || 5276250Sroot !strcmp("..", dp->d_name)) 5281119Sbill continue; 5295931Smckusic strcpy(cp, dp->d_name); 53027445Slepreau l = telldir(dirp); 5315931Smckusic closedir(dirp); 5329601Ssam putfile(buf, cp, newparent); 5335931Smckusic dirp = opendir("."); 53427445Slepreau seekdir(dirp, l); 5351119Sbill } 5365931Smckusic closedir(dirp); 53715045Smckusick if (chdir(parent) < 0) { 53836227Sbostic fprintf(stderr, 53936227Sbostic "tar: cannot change back?: %s: %s\n", 54036227Sbostic parent, strerror(errno)); 54115045Smckusick } 54212154Ssam break; 54312154Ssam 54412154Ssam case S_IFLNK: 54512154Ssam tomodes(&stbuf); 54612154Ssam if (strlen(longname) >= NAMSIZ) { 54713492Ssam fprintf(stderr, "tar: %s: file name too long\n", 54813492Ssam longname); 54912154Ssam return; 55012154Ssam } 55112154Ssam strcpy(dblock.dbuf.name, longname); 5526250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 55313492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 55413492Ssam longname); 5556250Sroot return; 5566250Sroot } 5579601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5586250Sroot if (i < 0) { 55936227Sbostic fprintf(stderr, 56036227Sbostic "tar: can't read symbolic link %s: %s\n", 56136227Sbostic longname, strerror(errno)); 5626250Sroot return; 5636250Sroot } 5646250Sroot dblock.dbuf.linkname[i] = '\0'; 5656250Sroot dblock.dbuf.linkflag = '2'; 56622688Slepreau if (vflag) 56722688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 56822688Slepreau longname, dblock.dbuf.linkname); 56932420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo", 0L); 57032420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 57127445Slepreau (void) writetape((char *)&dblock); 57212154Ssam break; 5731119Sbill 57412154Ssam case S_IFREG: 57512154Ssam if ((infile = open(shortname, 0)) < 0) { 57636227Sbostic fprintf(stderr, "tar: %s: %s\n", 57736227Sbostic longname, strerror(errno)); 5781119Sbill return; 5791119Sbill } 58012154Ssam tomodes(&stbuf); 58112154Ssam if (strlen(longname) >= NAMSIZ) { 58213492Ssam fprintf(stderr, "tar: %s: file name too long\n", 58313492Ssam longname); 58421457Skjd close(infile); 58512154Ssam return; 58612154Ssam } 58712154Ssam strcpy(dblock.dbuf.name, longname); 58812154Ssam if (stbuf.st_nlink > 1) { 58912154Ssam struct linkbuf *lp; 59012154Ssam int found = 0; 59112154Ssam 59212154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 59312154Ssam if (lp->inum == stbuf.st_ino && 59412154Ssam lp->devnum == stbuf.st_dev) { 59512154Ssam found++; 59612154Ssam break; 59712154Ssam } 59812154Ssam if (found) { 59912154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 60012154Ssam dblock.dbuf.linkflag = '1'; 60132420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 60227445Slepreau (void) writetape( (char *) &dblock); 60322688Slepreau if (vflag) 60422688Slepreau fprintf(vfile, "a %s link to %s\n", 60522688Slepreau longname, lp->pathname); 60612154Ssam lp->count--; 60712154Ssam close(infile); 60812154Ssam return; 6091119Sbill } 61022688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 61122688Slepreau if (lp != NULL) { 61212154Ssam lp->nextp = ihead; 61312154Ssam ihead = lp; 61412154Ssam lp->inum = stbuf.st_ino; 61512154Ssam lp->devnum = stbuf.st_dev; 61612154Ssam lp->count = stbuf.st_nlink - 1; 61712154Ssam strcpy(lp->pathname, longname); 61812154Ssam } 6191119Sbill } 62021457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 62122688Slepreau if (vflag) 62222688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 62332420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 62421457Skjd hint = writetape((char *)&dblock); 62521457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 62627445Slepreau if ((bigbuf = malloc((unsigned)maxread)) == 0) { 62721457Skjd maxread = TBLOCK; 62821457Skjd bigbuf = buf; 62921457Skjd } 6301119Sbill 63121457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 63221457Skjd && blocks > 0) { 63321457Skjd register int nblks; 63421457Skjd 63521457Skjd nblks = ((i-1)/TBLOCK)+1; 63621457Skjd if (nblks > blocks) 63721457Skjd nblks = blocks; 63821457Skjd hint = writetbuf(bigbuf, nblks); 63921457Skjd blocks -= nblks; 64021457Skjd } 64121457Skjd close(infile); 64221457Skjd if (bigbuf != buf) 64321457Skjd free(bigbuf); 64427058Smckusick if (i < 0) { 64536227Sbostic fprintf(stderr, "tar: Read error on %s: %s\n", 64636227Sbostic longname, strerror(errno)); 64727058Smckusick } else if (blocks != 0 || i != 0) 64813492Ssam fprintf(stderr, "tar: %s: file changed size\n", 64913492Ssam longname); 65012154Ssam while (--blocks >= 0) 65112154Ssam putempty(); 65212154Ssam break; 65312154Ssam 65412154Ssam default: 65512154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 65613492Ssam longname); 65712154Ssam break; 6581119Sbill } 6591119Sbill } 6601119Sbill 6611119Sbill doxtract(argv) 6626250Sroot char *argv[]; 6631119Sbill { 6641119Sbill long blocks, bytes; 66527445Slepreau int ofile, i; 6661119Sbill 6671119Sbill for (;;) { 66827445Slepreau if ((i = wantit(argv)) == 0) 66927445Slepreau continue; 67027445Slepreau if (i == -1) 67127445Slepreau break; /* end of tape */ 6721119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6731119Sbill passtape(); 6741119Sbill continue; 6751119Sbill } 67612154Ssam if (Fflag) { 67712154Ssam char *s; 67812154Ssam 67912154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 68012154Ssam s = dblock.dbuf.name; 68112154Ssam else 68212154Ssam s++; 68312154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 68412154Ssam passtape(); 68512154Ssam continue; 68612154Ssam } 68712154Ssam } 68822688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 68922688Slepreau if (mflag == 0) 69022688Slepreau dodirtimes(&dblock); 6916250Sroot continue; 69222688Slepreau } 69322688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 69425250Sbloom /* 69525250Sbloom * only unlink non directories or empty 69625250Sbloom * directories 69725250Sbloom */ 69825250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 69925250Sbloom if (errno == ENOTDIR) 70025250Sbloom unlink(dblock.dbuf.name); 70125250Sbloom } 7026250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 70336227Sbostic fprintf(stderr, 70436227Sbostic "tar: %s: symbolic link failed: %s\n", 70536227Sbostic dblock.dbuf.name, strerror(errno)); 7066250Sroot continue; 7076250Sroot } 7086250Sroot if (vflag) 70921910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 71013492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 71122353Skjd #ifdef notdef 71222353Skjd /* ignore alien orders */ 71322353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 71422688Slepreau if (mflag == 0) 71522688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 71622353Skjd if (pflag) 71722353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 71822353Skjd #endif 7191119Sbill continue; 7206250Sroot } 72122688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 72225250Sbloom /* 72325250Sbloom * only unlink non directories or empty 72425250Sbloom * directories 72525250Sbloom */ 72625250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 72725250Sbloom if (errno == ENOTDIR) 72825250Sbloom unlink(dblock.dbuf.name); 72925250Sbloom } 7301119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 73136227Sbostic fprintf(stderr, 73236227Sbostic "tar: can't link %s to %s: %s\n", 73336227Sbostic dblock.dbuf.name, dblock.dbuf.linkname, 73436227Sbostic strerror(errno)); 7351119Sbill continue; 7361119Sbill } 7371119Sbill if (vflag) 73822688Slepreau fprintf(vfile, "%s linked to %s\n", 73913492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7401119Sbill continue; 7411119Sbill } 7426250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 74336227Sbostic fprintf(stderr, "tar: can't create %s: %s\n", 74436227Sbostic dblock.dbuf.name, strerror(errno)); 7451119Sbill passtape(); 7461119Sbill continue; 7471119Sbill } 74821457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7491119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7501119Sbill if (vflag) 75122688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 75213492Ssam dblock.dbuf.name, bytes, blocks); 75321457Skjd for (; blocks > 0;) { 75421457Skjd register int nread; 75521457Skjd char *bufp; 75621457Skjd register int nwant; 75721457Skjd 75821457Skjd nwant = NBLOCK*TBLOCK; 75921457Skjd if (nwant > (blocks*TBLOCK)) 76021457Skjd nwant = (blocks*TBLOCK); 76121457Skjd nread = readtbuf(&bufp, nwant); 76222688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7636250Sroot fprintf(stderr, 76436227Sbostic "tar: %s: HELP - extract write error: %s\n", 76536227Sbostic dblock.dbuf.name, strerror(errno)); 7666250Sroot done(2); 7676250Sroot } 76821457Skjd bytes -= nread; 76921457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7701119Sbill } 7711119Sbill close(ofile); 77222688Slepreau if (mflag == 0) 77322688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7741926Swnj if (pflag) 7756250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7761119Sbill } 77722688Slepreau if (mflag == 0) { 77822688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 77922688Slepreau dodirtimes(&dblock); 78022688Slepreau } 7811119Sbill } 7821119Sbill 78327445Slepreau dotable(argv) 78427445Slepreau char *argv[]; 7851119Sbill { 78627445Slepreau register int i; 78727445Slepreau 7881119Sbill for (;;) { 78927445Slepreau if ((i = wantit(argv)) == 0) 79027445Slepreau continue; 79127445Slepreau if (i == -1) 79227445Slepreau break; /* end of tape */ 7931119Sbill if (vflag) 7941119Sbill longt(&stbuf); 7951119Sbill printf("%s", dblock.dbuf.name); 7961119Sbill if (dblock.dbuf.linkflag == '1') 7971119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7986250Sroot if (dblock.dbuf.linkflag == '2') 7996250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 8001119Sbill printf("\n"); 8011119Sbill passtape(); 8021119Sbill } 8031119Sbill } 8041119Sbill 8051119Sbill putempty() 8061119Sbill { 8071119Sbill char buf[TBLOCK]; 8081119Sbill 80913492Ssam bzero(buf, sizeof (buf)); 81027445Slepreau (void) writetape(buf); 8111119Sbill } 8121119Sbill 8131119Sbill longt(st) 8146250Sroot register struct stat *st; 8151119Sbill { 8161119Sbill register char *cp; 8171119Sbill char *ctime(); 8181119Sbill 8191119Sbill pmode(st); 82036227Sbostic printf("%3u/%1u", st->st_uid, st->st_gid); 82127445Slepreau printf("%7ld", st->st_size); 8221119Sbill cp = ctime(&st->st_mtime); 8231119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8241119Sbill } 8251119Sbill 8261119Sbill #define SUID 04000 8271119Sbill #define SGID 02000 8281119Sbill #define ROWN 0400 8291119Sbill #define WOWN 0200 8301119Sbill #define XOWN 0100 8311119Sbill #define RGRP 040 8321119Sbill #define WGRP 020 8331119Sbill #define XGRP 010 8341119Sbill #define ROTH 04 8351119Sbill #define WOTH 02 8361119Sbill #define XOTH 01 8371119Sbill #define STXT 01000 8381119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8391119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8401119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8411119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8421119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8431119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8441119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8451119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8461119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8471119Sbill 8481119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8491119Sbill 8501119Sbill pmode(st) 8516250Sroot register struct stat *st; 8521119Sbill { 8531119Sbill register int **mp; 8541119Sbill 8551119Sbill for (mp = &m[0]; mp < &m[9];) 85627058Smckusick selectbits(*mp++, st); 8571119Sbill } 8581119Sbill 85927058Smckusick selectbits(pairp, st) 8606250Sroot int *pairp; 8616250Sroot struct stat *st; 8621119Sbill { 8631119Sbill register int n, *ap; 8641119Sbill 8651119Sbill ap = pairp; 8661119Sbill n = *ap++; 8671119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8681119Sbill ap++; 86927445Slepreau putchar(*ap); 8701119Sbill } 8711119Sbill 87222688Slepreau /* 87327442Slepreau * Make all directories needed by `name'. If `name' is itself 87427442Slepreau * a directory on the tar tape (indicated by a trailing '/'), 87522688Slepreau * return 1; else 0. 87622688Slepreau */ 8771119Sbill checkdir(name) 8786250Sroot register char *name; 8791119Sbill { 8801119Sbill register char *cp; 8816250Sroot 88212154Ssam /* 88322688Slepreau * Quick check for existence of directory. 88412154Ssam */ 88512154Ssam if ((cp = rindex(name, '/')) == 0) 88612154Ssam return (0); 88712154Ssam *cp = '\0'; 88836227Sbostic if (access(name, F_OK) == 0) { /* already exists */ 88912154Ssam *cp = '/'; 89022688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 89112154Ssam } 89212154Ssam *cp = '/'; 89312154Ssam 89412154Ssam /* 89512154Ssam * No luck, try to make all directories in path. 89612154Ssam */ 8971119Sbill for (cp = name; *cp; cp++) { 8986250Sroot if (*cp != '/') 8996250Sroot continue; 9006250Sroot *cp = '\0'; 90136227Sbostic if (access(name, F_OK) < 0) { 9029844Ssam if (mkdir(name, 0777) < 0) { 90336227Sbostic fprintf(stderr, "tar: mkdir: %s: %s\n", 90436227Sbostic name, strerror(errno)); 90512154Ssam *cp = '/'; 90612154Ssam return (0); 9071119Sbill } 90821457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 90927442Slepreau if (pflag && cp[1] == '\0') /* dir on the tape */ 91027442Slepreau chmod(name, stbuf.st_mode & 07777); 9111119Sbill } 9126250Sroot *cp = '/'; 9131119Sbill } 9146250Sroot return (cp[-1]=='/'); 9151119Sbill } 9161119Sbill 91746656Sbostic void 9181119Sbill onintr() 9191119Sbill { 92027445Slepreau (void) signal(SIGINT, SIG_IGN); 9211119Sbill term++; 9221119Sbill } 9231119Sbill 92446656Sbostic void 9251119Sbill onquit() 9261119Sbill { 92727445Slepreau (void) signal(SIGQUIT, SIG_IGN); 9281119Sbill term++; 9291119Sbill } 9301119Sbill 93146656Sbostic void 9321119Sbill onhup() 9331119Sbill { 93427445Slepreau (void) signal(SIGHUP, SIG_IGN); 9351119Sbill term++; 9361119Sbill } 9371119Sbill 93822688Slepreau #ifdef notdef 93946656Sbostic void 9401119Sbill onterm() 9411119Sbill { 94227445Slepreau (void) signal(SIGTERM, SIG_IGN); 9431119Sbill term++; 9441119Sbill } 94522688Slepreau #endif 9461119Sbill 9471119Sbill tomodes(sp) 9481119Sbill register struct stat *sp; 9491119Sbill { 9501119Sbill register char *cp; 9511119Sbill 9521119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9531119Sbill *cp = '\0'; 95432420Sbostic (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 95532420Sbostic (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 95632420Sbostic (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 95732420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 95832420Sbostic (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9591119Sbill } 9601119Sbill 9611119Sbill checksum() 9621119Sbill { 9631119Sbill register i; 9641119Sbill register char *cp; 9651119Sbill 9666250Sroot for (cp = dblock.dbuf.chksum; 9676250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9681119Sbill *cp = ' '; 9691119Sbill i = 0; 9701119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9711119Sbill i += *cp; 9726250Sroot return (i); 9731119Sbill } 9741119Sbill 9751119Sbill checkw(c, name) 9766250Sroot char *name; 9771119Sbill { 9786250Sroot if (!wflag) 9796250Sroot return (1); 9806250Sroot printf("%c ", c); 9816250Sroot if (vflag) 9826250Sroot longt(&stbuf); 9836250Sroot printf("%s: ", name); 9846250Sroot return (response() == 'y'); 9851119Sbill } 9861119Sbill 9871119Sbill response() 9881119Sbill { 9891119Sbill char c; 9901119Sbill 9911119Sbill c = getchar(); 9921119Sbill if (c != '\n') 9936250Sroot while (getchar() != '\n') 9946250Sroot ; 9956250Sroot else 9966250Sroot c = 'n'; 9976250Sroot return (c); 9981119Sbill } 9991119Sbill 100012154Ssam checkf(name, mode, howmuch) 100112154Ssam char *name; 100212154Ssam int mode, howmuch; 100312154Ssam { 100412154Ssam int l; 100512154Ssam 100621910Skjd if ((mode & S_IFMT) == S_IFDIR){ 100721910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 100821910Skjd return(0); 100921910Skjd return(1); 101021910Skjd } 101112154Ssam if ((l = strlen(name)) < 3) 101212154Ssam return (1); 101312154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 101412154Ssam return (0); 101512154Ssam if (strcmp(name, "core") == 0 || 101612154Ssam strcmp(name, "errs") == 0 || 101712154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 101812154Ssam return (0); 101912154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 102012154Ssam return (1); 102112154Ssam } 102212154Ssam 102322688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 10241119Sbill checkupdate(arg) 10256250Sroot char *arg; 10261119Sbill { 10271119Sbill char name[100]; 10286250Sroot long mtime; 10291119Sbill daddr_t seekp; 10301119Sbill daddr_t lookup(); 10311119Sbill 10321119Sbill rewind(tfile); 10331119Sbill for (;;) { 10341119Sbill if ((seekp = lookup(arg)) < 0) 10356250Sroot return (1); 10361119Sbill fseek(tfile, seekp, 0); 10371119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10386250Sroot return (stbuf.st_mtime > mtime); 10391119Sbill } 10401119Sbill } 10411119Sbill 10421119Sbill done(n) 10431119Sbill { 104421457Skjd unlink(tname); 10451119Sbill exit(n); 10461119Sbill } 10471119Sbill 104827445Slepreau /* 104927445Slepreau * Do we want the next entry on the tape, i.e. is it selected? If 105027445Slepreau * not, skip over the entire entry. Return -1 if reached end of tape. 105127445Slepreau */ 105227445Slepreau wantit(argv) 105327445Slepreau char *argv[]; 105427445Slepreau { 105527445Slepreau register char **cp; 105627445Slepreau 105727445Slepreau getdir(); 105827445Slepreau if (endtape()) 105927445Slepreau return (-1); 106027445Slepreau if (*argv == 0) 106127445Slepreau return (1); 106227445Slepreau for (cp = argv; *cp; cp++) 106327445Slepreau if (prefix(*cp, dblock.dbuf.name)) 106427445Slepreau return (1); 106527445Slepreau passtape(); 106627445Slepreau return (0); 106727445Slepreau } 106827445Slepreau 106922688Slepreau /* 107022688Slepreau * Does s2 begin with the string s1, on a directory boundary? 107122688Slepreau */ 10721119Sbill prefix(s1, s2) 10736250Sroot register char *s1, *s2; 10741119Sbill { 10751119Sbill while (*s1) 10761119Sbill if (*s1++ != *s2++) 10776250Sroot return (0); 10781119Sbill if (*s2) 10796250Sroot return (*s2 == '/'); 10806250Sroot return (1); 10811119Sbill } 10821119Sbill 10831119Sbill #define N 200 10841119Sbill int njab; 10856250Sroot 10861119Sbill daddr_t 10871119Sbill lookup(s) 10886250Sroot char *s; 10891119Sbill { 10901119Sbill register i; 10911119Sbill daddr_t a; 10921119Sbill 10931119Sbill for(i=0; s[i]; i++) 10946250Sroot if (s[i] == ' ') 10951119Sbill break; 10961119Sbill a = bsrch(s, i, low, high); 10976250Sroot return (a); 10981119Sbill } 10991119Sbill 11001119Sbill daddr_t 11011119Sbill bsrch(s, n, l, h) 11026250Sroot daddr_t l, h; 11036250Sroot char *s; 11041119Sbill { 11051119Sbill register i, j; 11061119Sbill char b[N]; 11071119Sbill daddr_t m, m1; 11081119Sbill 11091119Sbill njab = 0; 11101119Sbill 11111119Sbill loop: 11126250Sroot if (l >= h) 111322688Slepreau return ((daddr_t) -1); 11141119Sbill m = l + (h-l)/2 - N/2; 11156250Sroot if (m < l) 11161119Sbill m = l; 11171119Sbill fseek(tfile, m, 0); 11181119Sbill fread(b, 1, N, tfile); 11191119Sbill njab++; 11201119Sbill for(i=0; i<N; i++) { 11216250Sroot if (b[i] == '\n') 11221119Sbill break; 11231119Sbill m++; 11241119Sbill } 11256250Sroot if (m >= h) 112622688Slepreau return ((daddr_t) -1); 11271119Sbill m1 = m; 11281119Sbill j = i; 11291119Sbill for(i++; i<N; i++) { 11301119Sbill m1++; 11316250Sroot if (b[i] == '\n') 11321119Sbill break; 11331119Sbill } 11341119Sbill i = cmp(b+j, s, n); 11356250Sroot if (i < 0) { 11361119Sbill h = m; 11371119Sbill goto loop; 11381119Sbill } 11396250Sroot if (i > 0) { 11401119Sbill l = m1; 11411119Sbill goto loop; 11421119Sbill } 11436250Sroot return (m); 11441119Sbill } 11451119Sbill 11461119Sbill cmp(b, s, n) 11476250Sroot char *b, *s; 11481119Sbill { 11491119Sbill register i; 11501119Sbill 11516250Sroot if (b[0] != '\n') 115221457Skjd exit(2); 11531119Sbill for(i=0; i<n; i++) { 11546250Sroot if (b[i+1] > s[i]) 11556250Sroot return (-1); 11566250Sroot if (b[i+1] < s[i]) 11576250Sroot return (1); 11581119Sbill } 11596250Sroot return (b[i+1] == ' '? 0 : -1); 11601119Sbill } 11611119Sbill 116222688Slepreau readtape(buffer) 11636250Sroot char *buffer; 11641119Sbill { 116521457Skjd char *bufp; 116621457Skjd 116722688Slepreau if (first == 0) 116822688Slepreau getbuf(); 116927445Slepreau (void) readtbuf(&bufp, TBLOCK); 117021457Skjd bcopy(bufp, buffer, TBLOCK); 117121457Skjd return(TBLOCK); 117221457Skjd } 117321457Skjd 117421457Skjd readtbuf(bufpp, size) 117521457Skjd char **bufpp; 117621457Skjd int size; 117721457Skjd { 11783457Swnj register int i; 11791119Sbill 11801119Sbill if (recno >= nblock || first == 0) { 118127445Slepreau if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 118227058Smckusick mterr("read", i, 3); 11831119Sbill if (first == 0) { 11841119Sbill if ((i % TBLOCK) != 0) { 118513492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11861119Sbill done(3); 11871119Sbill } 11881119Sbill i /= TBLOCK; 11893457Swnj if (i != nblock) { 119013492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11911119Sbill nblock = i; 11921119Sbill } 119322353Skjd first = 1; 11941119Sbill } 11951119Sbill recno = 0; 11961119Sbill } 119721457Skjd if (size > ((nblock-recno)*TBLOCK)) 119821457Skjd size = (nblock-recno)*TBLOCK; 119921457Skjd *bufpp = (char *)&tbuf[recno]; 120021457Skjd recno += (size/TBLOCK); 120121457Skjd return (size); 12021119Sbill } 12031119Sbill 120421457Skjd writetbuf(buffer, n) 120521457Skjd register char *buffer; 120621457Skjd register int n; 12071119Sbill { 120827058Smckusick int i; 120922688Slepreau 121022688Slepreau if (first == 0) { 121122353Skjd getbuf(); 121222353Skjd first = 1; 121322353Skjd } 12141119Sbill if (recno >= nblock) { 121527445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 121627058Smckusick if (i != TBLOCK*nblock) 121727058Smckusick mterr("write", i, 2); 12181119Sbill recno = 0; 12191119Sbill } 122021457Skjd 122121457Skjd /* 122221457Skjd * Special case: We have an empty tape buffer, and the 122321457Skjd * users data size is >= the tape block size: Avoid 122421457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 122521457Skjd * residual to the tape buffer. 122621457Skjd */ 122721457Skjd while (recno == 0 && n >= nblock) { 122827058Smckusick i = write(mt, buffer, TBLOCK*nblock); 122927058Smckusick if (i != TBLOCK*nblock) 123027058Smckusick mterr("write", i, 2); 123121457Skjd n -= nblock; 123221457Skjd buffer += (nblock * TBLOCK); 12331119Sbill } 123421457Skjd 123521457Skjd while (n-- > 0) { 123621457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 123721457Skjd buffer += TBLOCK; 123821457Skjd if (recno >= nblock) { 123927445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 124027058Smckusick if (i != TBLOCK*nblock) 124127058Smckusick mterr("write", i, 2); 124221457Skjd recno = 0; 124321457Skjd } 124421457Skjd } 124521457Skjd 124621457Skjd /* Tell the user how much to write to get in sync */ 124721457Skjd return (nblock - recno); 12481119Sbill } 12491119Sbill 12501119Sbill backtape() 12511119Sbill { 125227058Smckusick static int mtdev = 1; 12533457Swnj static struct mtop mtop = {MTBSR, 1}; 125427058Smckusick struct mtget mtget; 125527058Smckusick 125627058Smckusick if (mtdev == 1) 125727445Slepreau mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 12583457Swnj if (mtdev == 0) { 125927445Slepreau if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 126036227Sbostic fprintf(stderr, "tar: tape backspace error: %s\n", 126136227Sbostic strerror(errno)); 12621119Sbill done(4); 12631119Sbill } 12643457Swnj } else 126536227Sbostic (void)lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 12663457Swnj recno--; 12671119Sbill } 12681119Sbill 12691119Sbill flushtape() 12701119Sbill { 127127058Smckusick int i; 127227058Smckusick 127327445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 127427058Smckusick if (i != TBLOCK*nblock) 127527058Smckusick mterr("write", i, 2); 12761119Sbill } 12771119Sbill 127827058Smckusick mterr(operation, i, exitcode) 127927058Smckusick char *operation; 128027058Smckusick int i; 128127058Smckusick { 128236227Sbostic fprintf(stderr, "tar: tape %s error: %s\n", 128336227Sbostic operation, i < 0 ? strerror(errno) : "unexpected EOF"); 128427058Smckusick done(exitcode); 128527058Smckusick } 128627058Smckusick 12878737Smckusick bread(fd, buf, size) 12888737Smckusick int fd; 12898737Smckusick char *buf; 12908737Smckusick int size; 12918737Smckusick { 12928737Smckusick int count; 12938737Smckusick static int lastread = 0; 12948737Smckusick 129522688Slepreau if (!Bflag) 129622688Slepreau return (read(fd, buf, size)); 129722353Skjd 12988737Smckusick for (count = 0; count < size; count += lastread) { 129924281Smckusick lastread = read(fd, buf, size - count); 130024281Smckusick if (lastread <= 0) { 13018737Smckusick if (count > 0) 13028737Smckusick return (count); 13038737Smckusick return (lastread); 13048737Smckusick } 13058737Smckusick buf += lastread; 13068737Smckusick } 13078737Smckusick return (count); 13088737Smckusick } 130910165Ssam 131010165Ssam char * 131146656Sbostic cwd() 131210165Ssam { 131346656Sbostic char *p; 131446656Sbostic 131546656Sbostic p = getcwd((char *)NULL, 0); 131646656Sbostic if (p == NULL) { 131746656Sbostic (void)fprintf(stderr, "tar: %s\n", strerror(errno)); 131821457Skjd exit(1); 131910165Ssam } 132046656Sbostic return (p); 132110165Ssam } 132221910Skjd 132321910Skjd getbuf() 132421910Skjd { 132522353Skjd 132627058Smckusick if (nblock == 0) { 132721910Skjd fstat(mt, &stbuf); 132821910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 132927058Smckusick nblock = NBLOCK; 133021910Skjd else { 133127058Smckusick nblock = stbuf.st_blksize / TBLOCK; 133227058Smckusick if (nblock == 0) 133327058Smckusick nblock = NBLOCK; 133421910Skjd } 133521910Skjd } 133627445Slepreau tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 133721910Skjd if (tbuf == NULL) { 133821910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 133921910Skjd nblock); 134021910Skjd done(1); 134121910Skjd } 134221910Skjd } 134322353Skjd 134422688Slepreau /* 134527442Slepreau * Save this directory and its mtime on the stack, popping and setting 134627442Slepreau * the mtimes of any stacked dirs which aren't parents of this one. 134727442Slepreau * A null directory causes the entire stack to be unwound and set. 134822688Slepreau * 134927442Slepreau * Since all the elements of the directory "stack" share a common 135027442Slepreau * prefix, we can make do with one string. We keep only the current 135127442Slepreau * directory path, with an associated array of mtime's, one for each 135227442Slepreau * '/' in the path. A negative mtime means no mtime. The mtime's are 135327442Slepreau * offset by one (first index 1, not 0) because calling this with a null 135427442Slepreau * directory causes mtime[0] to be set. 135527442Slepreau * 135622688Slepreau * This stack algorithm is not guaranteed to work for tapes created 135722688Slepreau * with the 'r' option, but the vast majority of tapes with 135822688Slepreau * directories are not. This avoids saving every directory record on 135922688Slepreau * the tape and setting all the times at the end. 136022688Slepreau */ 136122688Slepreau char dirstack[NAMSIZ]; 136222688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 136322688Slepreau time_t mtime[NTIM]; 136422353Skjd 136522688Slepreau dodirtimes(hp) 136622688Slepreau union hblock *hp; 136722353Skjd { 136822688Slepreau register char *p = dirstack; 136922688Slepreau register char *q = hp->dbuf.name; 137022688Slepreau register int ndir = 0; 137122688Slepreau char *savp; 137222688Slepreau int savndir; 137322353Skjd 137422688Slepreau /* Find common prefix */ 137530090Sbostic while (*p == *q && *p) { 137622688Slepreau if (*p++ == '/') 137722688Slepreau ++ndir; 137822688Slepreau q++; 137922688Slepreau } 138022353Skjd 138122688Slepreau savp = p; 138222688Slepreau savndir = ndir; 138322688Slepreau while (*p) { 138422688Slepreau /* 138522688Slepreau * Not a child: unwind the stack, setting the times. 138622688Slepreau * The order we do this doesn't matter, so we go "forward." 138722688Slepreau */ 138822688Slepreau if (*p++ == '/') 138922688Slepreau if (mtime[++ndir] >= 0) { 139022688Slepreau *--p = '\0'; /* zap the slash */ 139122688Slepreau setimes(dirstack, mtime[ndir]); 139222688Slepreau *p++ = '/'; 139322688Slepreau } 139422688Slepreau } 139522688Slepreau p = savp; 139622688Slepreau ndir = savndir; 139722353Skjd 139822688Slepreau /* Push this one on the "stack" */ 139922688Slepreau while (*p = *q++) /* append the rest of the new dir */ 140022688Slepreau if (*p++ == '/') 140122688Slepreau mtime[++ndir] = -1; 140222688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 140322688Slepreau } 140422353Skjd 140522688Slepreau setimes(path, mt) 140622688Slepreau char *path; 140722688Slepreau time_t mt; 140822688Slepreau { 140922688Slepreau struct timeval tv[2]; 141022353Skjd 141122688Slepreau tv[0].tv_sec = time((time_t *) 0); 141222688Slepreau tv[1].tv_sec = mt; 141322688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 141436227Sbostic if (utimes(path, tv) < 0) 141536227Sbostic fprintf(stderr, "tar: can't set time on %s: %s\n", 141636227Sbostic path, strerror(errno)); 141722688Slepreau } 141822688Slepreau 141922688Slepreau char * 142022688Slepreau getmem(size) 142122688Slepreau { 142222688Slepreau char *p = malloc((unsigned) size); 142322688Slepreau 142422688Slepreau if (p == NULL && freemem) { 142522688Slepreau fprintf(stderr, 142622688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 142722688Slepreau freemem = 0; 142822353Skjd } 142922688Slepreau return (p); 143022353Skjd } 1431