147845Sbostic /*- 247845Sbostic * Copyright (c) 1991 The Regents of the University of California. 347845Sbostic * All rights reserved. 447845Sbostic * 547845Sbostic * %sccs.include.proprietary.c% 622502Sdist */ 722502Sdist 812154Ssam #ifndef lint 922502Sdist char copyright[] = 1047845Sbostic "@(#) 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*53771Selan static char sccsid[] = "@(#)tar.c 5.18 (Berkeley) 06/01/92"; 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 41*53771Selan #define ARGV 0 42*53771Selan #define PUTFILE 1 43*53771Selan 4421457Skjd #define writetape(b) writetbuf(b, 1) 4521457Skjd #define min(a,b) ((a) < (b) ? (a) : (b)) 4621457Skjd #define max(a,b) ((a) > (b) ? (a) : (b)) 4721457Skjd 481119Sbill union hblock { 491119Sbill char dummy[TBLOCK]; 501119Sbill struct header { 511119Sbill char name[NAMSIZ]; 521119Sbill char mode[8]; 531119Sbill char uid[8]; 541119Sbill char gid[8]; 551119Sbill char size[12]; 561119Sbill char mtime[12]; 571119Sbill char chksum[8]; 581119Sbill char linkflag; 591119Sbill char linkname[NAMSIZ]; 601119Sbill } dbuf; 616250Sroot }; 621119Sbill 631119Sbill struct linkbuf { 641119Sbill ino_t inum; 651119Sbill dev_t devnum; 661119Sbill int count; 671119Sbill char pathname[NAMSIZ]; 681119Sbill struct linkbuf *nextp; 696250Sroot }; 701119Sbill 716250Sroot union hblock dblock; 7213492Ssam union hblock *tbuf; 736250Sroot struct linkbuf *ihead; 746250Sroot struct stat stbuf; 751119Sbill 766250Sroot int rflag; 7734429Sbostic int sflag; 786250Sroot int xflag; 796250Sroot int vflag; 806250Sroot int tflag; 816250Sroot int cflag; 826250Sroot int mflag; 836250Sroot int fflag; 8412154Ssam int iflag; 856250Sroot int oflag; 866250Sroot int pflag; 876250Sroot int wflag; 886250Sroot int hflag; 89*53771Selan int Hflag; 908737Smckusick int Bflag; 9112154Ssam int Fflag; 926250Sroot 936250Sroot int mt; 946250Sroot int term; 956250Sroot int chksum; 966250Sroot int recno; 9722688Slepreau int first; 9822688Slepreau int prtlinkerr; 991119Sbill int freemem = 1; 10022353Skjd int nblock = 0; 10146656Sbostic void onintr(), onquit(), onhup(); 10222688Slepreau #ifdef notdef 10346656Sbostic void onterm(); 10422688Slepreau #endif 1051119Sbill 1061119Sbill daddr_t low; 1071119Sbill daddr_t high; 1086250Sroot daddr_t bsrch(); 1091119Sbill 11021910Skjd FILE *vfile = stdout; 1111119Sbill FILE *tfile; 11237681Sbostic char tname[] = _PATH_TMP; 1131119Sbill char *usefile; 11437681Sbostic char magtape[] = _PATH_MAGTAPE; 11546656Sbostic char *cwd(); 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 136*53771Selan case 'H': 137*53771Selan Hflag++; 138*53771Selan break; 1391119Sbill case 'f': 14012154Ssam if (*argv == 0) { 14112154Ssam fprintf(stderr, 14212154Ssam "tar: tapefile must be specified with 'f' option\n"); 14312154Ssam usage(); 14412154Ssam } 1451119Sbill usefile = *argv++; 1461119Sbill fflag++; 1471119Sbill break; 1486250Sroot 1491119Sbill case 'c': 1501119Sbill cflag++; 1511119Sbill rflag++; 1521119Sbill break; 1536250Sroot 1541119Sbill case 'o': 1551119Sbill oflag++; 1561119Sbill break; 1576250Sroot 1581119Sbill case 'p': 1591119Sbill pflag++; 1601119Sbill break; 1616250Sroot 1621119Sbill case 'u': 16336227Sbostic (void)mktemp(tname); 1641119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1656250Sroot fprintf(stderr, 16622688Slepreau "tar: cannot create temporary file (%s)\n", 1676250Sroot tname); 1681119Sbill done(1); 1691119Sbill } 1701119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1716250Sroot /*FALL THRU*/ 1726250Sroot 1731119Sbill case 'r': 1741119Sbill rflag++; 1751119Sbill break; 1766250Sroot 17734429Sbostic case 's': 17834429Sbostic sflag++; 17934429Sbostic break; 18034429Sbostic 1811119Sbill case 'v': 1821119Sbill vflag++; 1831119Sbill break; 1846250Sroot 1851119Sbill case 'w': 1861119Sbill wflag++; 1871119Sbill break; 1886250Sroot 1891119Sbill case 'x': 1901119Sbill xflag++; 1911119Sbill break; 1926250Sroot 1931119Sbill case 't': 1941119Sbill tflag++; 1951119Sbill break; 1966250Sroot 1971119Sbill case 'm': 1981119Sbill mflag++; 1991119Sbill break; 2006250Sroot 2011119Sbill case '-': 2021119Sbill break; 2036250Sroot 2041119Sbill case '0': 2051119Sbill case '1': 2061119Sbill case '4': 2071119Sbill case '5': 20821457Skjd case '7': 2091119Sbill case '8': 2101119Sbill magtape[8] = *cp; 2111119Sbill usefile = magtape; 2121119Sbill break; 2136250Sroot 2141119Sbill case 'b': 21513492Ssam if (*argv == 0) { 21613492Ssam fprintf(stderr, 21713492Ssam "tar: blocksize must be specified with 'b' option\n"); 21813492Ssam usage(); 21913492Ssam } 22013492Ssam nblock = atoi(*argv); 22113492Ssam if (nblock <= 0) { 22213492Ssam fprintf(stderr, 22313492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2241119Sbill done(1); 2251119Sbill } 22613492Ssam argv++; 2271119Sbill break; 2286250Sroot 2291119Sbill case 'l': 23022688Slepreau prtlinkerr++; 2311119Sbill break; 2326250Sroot 2336250Sroot case 'h': 2346250Sroot hflag++; 2356250Sroot break; 2366250Sroot 23712154Ssam case 'i': 23812154Ssam iflag++; 23912154Ssam break; 24012154Ssam 2418737Smckusick case 'B': 2428737Smckusick Bflag++; 2438737Smckusick break; 2448737Smckusick 24512154Ssam case 'F': 24612154Ssam Fflag++; 24712154Ssam break; 24812154Ssam 2491119Sbill default: 2501119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2511119Sbill usage(); 2521119Sbill } 2531119Sbill 2546250Sroot if (!rflag && !xflag && !tflag) 2556250Sroot usage(); 2561119Sbill if (rflag) { 2576250Sroot if (cflag && tfile != NULL) 2581119Sbill usage(); 2591119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 26027445Slepreau (void) signal(SIGINT, onintr); 2611119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 26227445Slepreau (void) signal(SIGHUP, onhup); 2631119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 26427445Slepreau (void) signal(SIGQUIT, onquit); 2656250Sroot #ifdef notdef 2661119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 26727445Slepreau (void) signal(SIGTERM, onterm); 2686250Sroot #endif 26927058Smckusick mt = openmt(usefile, 1); 2701119Sbill dorep(argv); 2716250Sroot done(0); 2721119Sbill } 27327058Smckusick mt = openmt(usefile, 0); 2746250Sroot if (xflag) 2751119Sbill doxtract(argv); 2766250Sroot else 27727445Slepreau dotable(argv); 2781119Sbill done(0); 2791119Sbill } 2801119Sbill 2811119Sbill usage() 2821119Sbill { 2836250Sroot fprintf(stderr, 28421457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2851119Sbill done(1); 2861119Sbill } 2871119Sbill 28827058Smckusick int 28927058Smckusick openmt(tape, writing) 29027058Smckusick char *tape; 29127058Smckusick int writing; 29227058Smckusick { 29327058Smckusick if (strcmp(tape, "-") == 0) { 29427058Smckusick /* 29527058Smckusick * Read from standard input or write to standard output. 29627058Smckusick */ 29727058Smckusick if (writing) { 29827058Smckusick if (cflag == 0) { 29927058Smckusick fprintf(stderr, 30027058Smckusick "tar: can only create standard output archives\n"); 30127058Smckusick done(1); 30227058Smckusick } 30327058Smckusick vfile = stderr; 30427058Smckusick setlinebuf(vfile); 30527058Smckusick mt = dup(1); 30627058Smckusick } else { 30727058Smckusick mt = dup(0); 30827058Smckusick Bflag++; 30927058Smckusick } 31027058Smckusick } else { 31127058Smckusick /* 31227058Smckusick * Use file or tape on local machine. 31327058Smckusick */ 31427058Smckusick if (writing) { 31527058Smckusick if (cflag) 31627445Slepreau mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); 31727058Smckusick else 31827058Smckusick mt = open(tape, O_RDWR); 31927058Smckusick } else 32027058Smckusick mt = open(tape, O_RDONLY); 32127058Smckusick if (mt < 0) { 32236227Sbostic fprintf(stderr, "tar: %s: %s\n", tape, strerror(errno)); 32327058Smckusick done(1); 32427058Smckusick } 32527058Smckusick } 32627058Smckusick return(mt); 32727058Smckusick } 32827058Smckusick 3291119Sbill dorep(argv) 3306250Sroot char *argv[]; 3311119Sbill { 3321119Sbill register char *cp, *cp2; 33346656Sbostic char *parent, *wdir; 3341119Sbill 3351119Sbill if (!cflag) { 3361119Sbill getdir(); 3371119Sbill do { 3381119Sbill passtape(); 3391119Sbill if (term) 3401119Sbill done(0); 3411119Sbill getdir(); 3421119Sbill } while (!endtape()); 34313492Ssam backtape(); 3441119Sbill if (tfile != NULL) { 3451119Sbill char buf[200]; 3461119Sbill 34732420Sbostic (void)sprintf(buf, 3486250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3491119Sbill tname, tname, tname, tname, tname, tname); 3501119Sbill fflush(tfile); 3511119Sbill system(buf); 3521119Sbill freopen(tname, "r", tfile); 3531119Sbill fstat(fileno(tfile), &stbuf); 3541119Sbill high = stbuf.st_size; 3551119Sbill } 3561119Sbill } 3571119Sbill 35846656Sbostic wdir = cwd(); 3591119Sbill while (*argv && ! term) { 3601119Sbill cp2 = *argv; 3611119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3621119Sbill argv++; 36327058Smckusick if (chdir(*argv) < 0) { 36436227Sbostic fprintf(stderr, 36536227Sbostic "tar: can't change directories to %s: %s\n", 36636227Sbostic *argv, strerror(errno)); 36746656Sbostic } else { 36846656Sbostic free(wdir); 36946656Sbostic wdir = cwd(); 37046656Sbostic } 3711119Sbill argv++; 3721119Sbill continue; 3731119Sbill } 3749601Ssam parent = wdir; 3751119Sbill for (cp = *argv; *cp; cp++) 3761119Sbill if (*cp == '/') 3771119Sbill cp2 = cp; 3781119Sbill if (cp2 != *argv) { 3791119Sbill *cp2 = '\0'; 3809601Ssam if (chdir(*argv) < 0) { 38136227Sbostic fprintf(stderr, 38236227Sbostic "tar: can't change directories to %s: %s\n", 38336227Sbostic *argv, strerror(errno)); 3849601Ssam continue; 3859601Ssam } 38646656Sbostic parent = cwd(); 3871119Sbill *cp2 = '/'; 3881119Sbill cp2++; 3891119Sbill } 390*53771Selan putfile(*argv++, cp2, parent, ARGV); 39136227Sbostic if (chdir(wdir) < 0) 39236227Sbostic fprintf(stderr, "tar: cannot change back?: %s: %s\n", 39336227Sbostic wdir, strerror(errno)); 3941119Sbill } 3951119Sbill putempty(); 3961119Sbill putempty(); 3971119Sbill flushtape(); 39822688Slepreau if (prtlinkerr == 0) 3996250Sroot return; 4006250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 4016250Sroot if (ihead->count == 0) 4026250Sroot continue; 40313492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 4046250Sroot } 4051119Sbill } 4061119Sbill 4071119Sbill endtape() 4081119Sbill { 40921457Skjd return (dblock.dbuf.name[0] == '\0'); 4101119Sbill } 4111119Sbill 4121119Sbill getdir() 4131119Sbill { 4141119Sbill register struct stat *sp; 4151119Sbill int i; 4161119Sbill 41712154Ssam top: 4186250Sroot readtape((char *)&dblock); 4191119Sbill if (dblock.dbuf.name[0] == '\0') 4201119Sbill return; 4211119Sbill sp = &stbuf; 4221119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4231119Sbill sp->st_mode = i; 4241119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4251119Sbill sp->st_uid = i; 4261119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4271119Sbill sp->st_gid = i; 4281119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4291119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4301119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 43112154Ssam if (chksum != (i = checksum())) { 43213492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 43312154Ssam chksum, i); 43412154Ssam if (iflag) 43512154Ssam goto top; 4361119Sbill done(2); 4371119Sbill } 43834429Sbostic /* strip off leading "/" if present */ 43934429Sbostic if (sflag && dblock.dbuf.name[0] == '/') { 44034429Sbostic register char *cp1, *cp2; 44134429Sbostic for (cp1 = cp2 = dblock.dbuf.name; *cp2 && *cp2 == '/'; ++cp2); 44234429Sbostic if (!*cp2) 44334429Sbostic goto top; 44434429Sbostic while (*cp1++ = *cp2++); 44534429Sbostic } 4461119Sbill if (tfile != NULL) 4471119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4481119Sbill } 4491119Sbill 4501119Sbill passtape() 4511119Sbill { 4521119Sbill long blocks; 45321457Skjd char *bufp; 4541119Sbill 4551119Sbill if (dblock.dbuf.linkflag == '1') 4561119Sbill return; 4571119Sbill blocks = stbuf.st_size; 4581119Sbill blocks += TBLOCK-1; 4591119Sbill blocks /= TBLOCK; 4601119Sbill 46121457Skjd while (blocks-- > 0) 46227445Slepreau (void) readtbuf(&bufp, TBLOCK); 4631119Sbill } 4641119Sbill 465*53771Selan putfile(longname, shortname, parent, source) 4666250Sroot char *longname; 4676250Sroot char *shortname; 4689601Ssam char *parent; 4691119Sbill { 47021457Skjd int infile = 0; 47121457Skjd long blocks; 4721119Sbill char buf[TBLOCK]; 47321457Skjd char *bigbuf; 47422688Slepreau register char *cp; 47546656Sbostic struct dirent *dp; 4765931Smckusic DIR *dirp; 47727445Slepreau register int i; 47827445Slepreau long l; 4799601Ssam char newparent[NAMSIZ+64]; 48021457Skjd int maxread; 48121457Skjd int hint; /* amount to write to get "in sync" */ 4821119Sbill 483*53771Selan if (hflag || (Hflag && source == ARGV)) 484*53771Selan i = stat(shortname, &stbuf); 485*53771Selan else 48612154Ssam i = lstat(shortname, &stbuf); 487*53771Selan 48812154Ssam if (i < 0) { 48936227Sbostic fprintf(stderr, "tar: %s: %s\n", longname, strerror(errno)); 4909601Ssam return; 4919601Ssam } 49212154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4931119Sbill return; 49412154Ssam if (checkw('r', longname) == 0) 4951119Sbill return; 49612154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 49712154Ssam return; 4981119Sbill 49912154Ssam switch (stbuf.st_mode & S_IFMT) { 50012154Ssam case S_IFDIR: 5016250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 5026250Sroot ; 5031119Sbill *--cp = '/'; 5041119Sbill *++cp = 0 ; 5051119Sbill if (!oflag) { 5066250Sroot if ((cp - buf) >= NAMSIZ) { 50713492Ssam fprintf(stderr, "tar: %s: file name too long\n", 50813492Ssam longname); 5096250Sroot return; 5106250Sroot } 5116250Sroot stbuf.st_size = 0; 5126250Sroot tomodes(&stbuf); 5136250Sroot strcpy(dblock.dbuf.name,buf); 51432420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 51527445Slepreau (void) writetape((char *)&dblock); 5161119Sbill } 51732420Sbostic (void)sprintf(newparent, "%s/%s", parent, shortname); 51815045Smckusick if (chdir(shortname) < 0) { 51936227Sbostic fprintf(stderr, "tar: chdir %s: %s\n", 52036227Sbostic shortname, strerror(errno)); 52115045Smckusick return; 52215045Smckusick } 5235931Smckusic if ((dirp = opendir(".")) == NULL) { 52413492Ssam fprintf(stderr, "tar: %s: directory read error\n", 52513492Ssam longname); 52615045Smckusick if (chdir(parent) < 0) { 52736227Sbostic fprintf(stderr, 52836227Sbostic "tar: cannot change back?: %s: %s\n", 52936227Sbostic parent, strerror(errno)); 53015045Smckusick } 5315931Smckusic return; 5325931Smckusic } 5335931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5346250Sroot if (!strcmp(".", dp->d_name) || 5356250Sroot !strcmp("..", dp->d_name)) 5361119Sbill continue; 5375931Smckusic strcpy(cp, dp->d_name); 53827445Slepreau l = telldir(dirp); 5395931Smckusic closedir(dirp); 540*53771Selan putfile(buf, cp, newparent, PUTFILE); 5415931Smckusic dirp = opendir("."); 54227445Slepreau seekdir(dirp, l); 5431119Sbill } 5445931Smckusic closedir(dirp); 54515045Smckusick if (chdir(parent) < 0) { 54636227Sbostic fprintf(stderr, 54736227Sbostic "tar: cannot change back?: %s: %s\n", 54836227Sbostic parent, strerror(errno)); 54915045Smckusick } 55012154Ssam break; 55112154Ssam 55212154Ssam case S_IFLNK: 55312154Ssam tomodes(&stbuf); 55412154Ssam if (strlen(longname) >= NAMSIZ) { 55513492Ssam fprintf(stderr, "tar: %s: file name too long\n", 55613492Ssam longname); 55712154Ssam return; 55812154Ssam } 55912154Ssam strcpy(dblock.dbuf.name, longname); 5606250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 56113492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 56213492Ssam longname); 5636250Sroot return; 5646250Sroot } 5659601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5666250Sroot if (i < 0) { 56736227Sbostic fprintf(stderr, 56836227Sbostic "tar: can't read symbolic link %s: %s\n", 56936227Sbostic longname, strerror(errno)); 5706250Sroot return; 5716250Sroot } 5726250Sroot dblock.dbuf.linkname[i] = '\0'; 5736250Sroot dblock.dbuf.linkflag = '2'; 57422688Slepreau if (vflag) 57522688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 57622688Slepreau longname, dblock.dbuf.linkname); 57732420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo", 0L); 57832420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 57927445Slepreau (void) writetape((char *)&dblock); 58012154Ssam break; 5811119Sbill 58212154Ssam case S_IFREG: 58312154Ssam if ((infile = open(shortname, 0)) < 0) { 58436227Sbostic fprintf(stderr, "tar: %s: %s\n", 58536227Sbostic longname, strerror(errno)); 5861119Sbill return; 5871119Sbill } 58812154Ssam tomodes(&stbuf); 58912154Ssam if (strlen(longname) >= NAMSIZ) { 59013492Ssam fprintf(stderr, "tar: %s: file name too long\n", 59113492Ssam longname); 59221457Skjd close(infile); 59312154Ssam return; 59412154Ssam } 59512154Ssam strcpy(dblock.dbuf.name, longname); 59612154Ssam if (stbuf.st_nlink > 1) { 59712154Ssam struct linkbuf *lp; 59812154Ssam int found = 0; 59912154Ssam 60012154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 60112154Ssam if (lp->inum == stbuf.st_ino && 60212154Ssam lp->devnum == stbuf.st_dev) { 60312154Ssam found++; 60412154Ssam break; 60512154Ssam } 60612154Ssam if (found) { 60712154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 60812154Ssam dblock.dbuf.linkflag = '1'; 60932420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 61027445Slepreau (void) writetape( (char *) &dblock); 61122688Slepreau if (vflag) 61222688Slepreau fprintf(vfile, "a %s link to %s\n", 61322688Slepreau longname, lp->pathname); 61412154Ssam lp->count--; 61512154Ssam close(infile); 61612154Ssam return; 6171119Sbill } 61822688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 61922688Slepreau if (lp != NULL) { 62012154Ssam lp->nextp = ihead; 62112154Ssam ihead = lp; 62212154Ssam lp->inum = stbuf.st_ino; 62312154Ssam lp->devnum = stbuf.st_dev; 62412154Ssam lp->count = stbuf.st_nlink - 1; 62512154Ssam strcpy(lp->pathname, longname); 62612154Ssam } 6271119Sbill } 62821457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 62922688Slepreau if (vflag) 63022688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 63132420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 63221457Skjd hint = writetape((char *)&dblock); 63321457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 63427445Slepreau if ((bigbuf = malloc((unsigned)maxread)) == 0) { 63521457Skjd maxread = TBLOCK; 63621457Skjd bigbuf = buf; 63721457Skjd } 6381119Sbill 63921457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 64021457Skjd && blocks > 0) { 64121457Skjd register int nblks; 64221457Skjd 64321457Skjd nblks = ((i-1)/TBLOCK)+1; 64421457Skjd if (nblks > blocks) 64521457Skjd nblks = blocks; 64621457Skjd hint = writetbuf(bigbuf, nblks); 64721457Skjd blocks -= nblks; 64821457Skjd } 64921457Skjd close(infile); 65021457Skjd if (bigbuf != buf) 65121457Skjd free(bigbuf); 65227058Smckusick if (i < 0) { 65336227Sbostic fprintf(stderr, "tar: Read error on %s: %s\n", 65436227Sbostic longname, strerror(errno)); 65527058Smckusick } else if (blocks != 0 || i != 0) 65613492Ssam fprintf(stderr, "tar: %s: file changed size\n", 65713492Ssam longname); 65812154Ssam while (--blocks >= 0) 65912154Ssam putempty(); 66012154Ssam break; 66112154Ssam 66212154Ssam default: 66312154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 66413492Ssam longname); 66512154Ssam break; 6661119Sbill } 6671119Sbill } 6681119Sbill 6691119Sbill doxtract(argv) 6706250Sroot char *argv[]; 6711119Sbill { 6721119Sbill long blocks, bytes; 67327445Slepreau int ofile, i; 6741119Sbill 6751119Sbill for (;;) { 67627445Slepreau if ((i = wantit(argv)) == 0) 67727445Slepreau continue; 67827445Slepreau if (i == -1) 67927445Slepreau break; /* end of tape */ 6801119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6811119Sbill passtape(); 6821119Sbill continue; 6831119Sbill } 68412154Ssam if (Fflag) { 68512154Ssam char *s; 68612154Ssam 68712154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 68812154Ssam s = dblock.dbuf.name; 68912154Ssam else 69012154Ssam s++; 69112154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 69212154Ssam passtape(); 69312154Ssam continue; 69412154Ssam } 69512154Ssam } 69622688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 69722688Slepreau if (mflag == 0) 69822688Slepreau dodirtimes(&dblock); 6996250Sroot continue; 70022688Slepreau } 70122688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 70225250Sbloom /* 70325250Sbloom * only unlink non directories or empty 70425250Sbloom * directories 70525250Sbloom */ 70625250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 70725250Sbloom if (errno == ENOTDIR) 70825250Sbloom unlink(dblock.dbuf.name); 70925250Sbloom } 7106250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 71136227Sbostic fprintf(stderr, 71236227Sbostic "tar: %s: symbolic link failed: %s\n", 71336227Sbostic dblock.dbuf.name, strerror(errno)); 7146250Sroot continue; 7156250Sroot } 7166250Sroot if (vflag) 71721910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 71813492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 71922353Skjd #ifdef notdef 72022353Skjd /* ignore alien orders */ 72122353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 72222688Slepreau if (mflag == 0) 72322688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 72422353Skjd if (pflag) 72522353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 72622353Skjd #endif 7271119Sbill continue; 7286250Sroot } 72922688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 73025250Sbloom /* 73125250Sbloom * only unlink non directories or empty 73225250Sbloom * directories 73325250Sbloom */ 73425250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 73525250Sbloom if (errno == ENOTDIR) 73625250Sbloom unlink(dblock.dbuf.name); 73725250Sbloom } 7381119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 73936227Sbostic fprintf(stderr, 74036227Sbostic "tar: can't link %s to %s: %s\n", 74136227Sbostic dblock.dbuf.name, dblock.dbuf.linkname, 74236227Sbostic strerror(errno)); 7431119Sbill continue; 7441119Sbill } 7451119Sbill if (vflag) 74622688Slepreau fprintf(vfile, "%s linked to %s\n", 74713492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7481119Sbill continue; 7491119Sbill } 7506250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 75136227Sbostic fprintf(stderr, "tar: can't create %s: %s\n", 75236227Sbostic dblock.dbuf.name, strerror(errno)); 7531119Sbill passtape(); 7541119Sbill continue; 7551119Sbill } 75621457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7571119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7581119Sbill if (vflag) 75922688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 76013492Ssam dblock.dbuf.name, bytes, blocks); 76121457Skjd for (; blocks > 0;) { 76221457Skjd register int nread; 76321457Skjd char *bufp; 76421457Skjd register int nwant; 76521457Skjd 76621457Skjd nwant = NBLOCK*TBLOCK; 76721457Skjd if (nwant > (blocks*TBLOCK)) 76821457Skjd nwant = (blocks*TBLOCK); 76921457Skjd nread = readtbuf(&bufp, nwant); 77022688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7716250Sroot fprintf(stderr, 77236227Sbostic "tar: %s: HELP - extract write error: %s\n", 77336227Sbostic dblock.dbuf.name, strerror(errno)); 7746250Sroot done(2); 7756250Sroot } 77621457Skjd bytes -= nread; 77721457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7781119Sbill } 7791119Sbill close(ofile); 78022688Slepreau if (mflag == 0) 78122688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7821926Swnj if (pflag) 7836250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7841119Sbill } 78522688Slepreau if (mflag == 0) { 78622688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 78722688Slepreau dodirtimes(&dblock); 78822688Slepreau } 7891119Sbill } 7901119Sbill 79127445Slepreau dotable(argv) 79227445Slepreau char *argv[]; 7931119Sbill { 79427445Slepreau register int i; 79527445Slepreau 7961119Sbill for (;;) { 79727445Slepreau if ((i = wantit(argv)) == 0) 79827445Slepreau continue; 79927445Slepreau if (i == -1) 80027445Slepreau break; /* end of tape */ 8011119Sbill if (vflag) 8021119Sbill longt(&stbuf); 8031119Sbill printf("%s", dblock.dbuf.name); 8041119Sbill if (dblock.dbuf.linkflag == '1') 8051119Sbill printf(" linked to %s", dblock.dbuf.linkname); 8066250Sroot if (dblock.dbuf.linkflag == '2') 8076250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 8081119Sbill printf("\n"); 8091119Sbill passtape(); 8101119Sbill } 8111119Sbill } 8121119Sbill 8131119Sbill putempty() 8141119Sbill { 8151119Sbill char buf[TBLOCK]; 8161119Sbill 81713492Ssam bzero(buf, sizeof (buf)); 81827445Slepreau (void) writetape(buf); 8191119Sbill } 8201119Sbill 8211119Sbill longt(st) 8226250Sroot register struct stat *st; 8231119Sbill { 8241119Sbill register char *cp; 8251119Sbill char *ctime(); 8261119Sbill 8271119Sbill pmode(st); 82836227Sbostic printf("%3u/%1u", st->st_uid, st->st_gid); 82927445Slepreau printf("%7ld", st->st_size); 8301119Sbill cp = ctime(&st->st_mtime); 8311119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8321119Sbill } 8331119Sbill 8341119Sbill #define SUID 04000 8351119Sbill #define SGID 02000 8361119Sbill #define ROWN 0400 8371119Sbill #define WOWN 0200 8381119Sbill #define XOWN 0100 8391119Sbill #define RGRP 040 8401119Sbill #define WGRP 020 8411119Sbill #define XGRP 010 8421119Sbill #define ROTH 04 8431119Sbill #define WOTH 02 8441119Sbill #define XOTH 01 8451119Sbill #define STXT 01000 8461119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8471119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8481119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8491119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8501119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8511119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8521119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8531119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8541119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8551119Sbill 8561119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8571119Sbill 8581119Sbill pmode(st) 8596250Sroot register struct stat *st; 8601119Sbill { 8611119Sbill register int **mp; 8621119Sbill 8631119Sbill for (mp = &m[0]; mp < &m[9];) 86427058Smckusick selectbits(*mp++, st); 8651119Sbill } 8661119Sbill 86727058Smckusick selectbits(pairp, st) 8686250Sroot int *pairp; 8696250Sroot struct stat *st; 8701119Sbill { 8711119Sbill register int n, *ap; 8721119Sbill 8731119Sbill ap = pairp; 8741119Sbill n = *ap++; 8751119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8761119Sbill ap++; 87727445Slepreau putchar(*ap); 8781119Sbill } 8791119Sbill 88022688Slepreau /* 88127442Slepreau * Make all directories needed by `name'. If `name' is itself 88227442Slepreau * a directory on the tar tape (indicated by a trailing '/'), 88322688Slepreau * return 1; else 0. 88422688Slepreau */ 8851119Sbill checkdir(name) 8866250Sroot register char *name; 8871119Sbill { 8881119Sbill register char *cp; 8896250Sroot 89012154Ssam /* 89122688Slepreau * Quick check for existence of directory. 89212154Ssam */ 89312154Ssam if ((cp = rindex(name, '/')) == 0) 89412154Ssam return (0); 89512154Ssam *cp = '\0'; 89636227Sbostic if (access(name, F_OK) == 0) { /* already exists */ 89712154Ssam *cp = '/'; 89822688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 89912154Ssam } 90012154Ssam *cp = '/'; 90112154Ssam 90212154Ssam /* 90312154Ssam * No luck, try to make all directories in path. 90412154Ssam */ 9051119Sbill for (cp = name; *cp; cp++) { 9066250Sroot if (*cp != '/') 9076250Sroot continue; 9086250Sroot *cp = '\0'; 90936227Sbostic if (access(name, F_OK) < 0) { 9109844Ssam if (mkdir(name, 0777) < 0) { 91136227Sbostic fprintf(stderr, "tar: mkdir: %s: %s\n", 91236227Sbostic name, strerror(errno)); 91312154Ssam *cp = '/'; 91412154Ssam return (0); 9151119Sbill } 91621457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 91727442Slepreau if (pflag && cp[1] == '\0') /* dir on the tape */ 91827442Slepreau chmod(name, stbuf.st_mode & 07777); 9191119Sbill } 9206250Sroot *cp = '/'; 9211119Sbill } 9226250Sroot return (cp[-1]=='/'); 9231119Sbill } 9241119Sbill 92546656Sbostic void 9261119Sbill onintr() 9271119Sbill { 92827445Slepreau (void) signal(SIGINT, SIG_IGN); 9291119Sbill term++; 9301119Sbill } 9311119Sbill 93246656Sbostic void 9331119Sbill onquit() 9341119Sbill { 93527445Slepreau (void) signal(SIGQUIT, SIG_IGN); 9361119Sbill term++; 9371119Sbill } 9381119Sbill 93946656Sbostic void 9401119Sbill onhup() 9411119Sbill { 94227445Slepreau (void) signal(SIGHUP, SIG_IGN); 9431119Sbill term++; 9441119Sbill } 9451119Sbill 94622688Slepreau #ifdef notdef 94746656Sbostic void 9481119Sbill onterm() 9491119Sbill { 95027445Slepreau (void) signal(SIGTERM, SIG_IGN); 9511119Sbill term++; 9521119Sbill } 95322688Slepreau #endif 9541119Sbill 9551119Sbill tomodes(sp) 9561119Sbill register struct stat *sp; 9571119Sbill { 9581119Sbill register char *cp; 9591119Sbill 9601119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9611119Sbill *cp = '\0'; 96232420Sbostic (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 96332420Sbostic (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 96432420Sbostic (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 96532420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 96632420Sbostic (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9671119Sbill } 9681119Sbill 9691119Sbill checksum() 9701119Sbill { 9711119Sbill register i; 9721119Sbill register char *cp; 9731119Sbill 9746250Sroot for (cp = dblock.dbuf.chksum; 9756250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9761119Sbill *cp = ' '; 9771119Sbill i = 0; 9781119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9791119Sbill i += *cp; 9806250Sroot return (i); 9811119Sbill } 9821119Sbill 9831119Sbill checkw(c, name) 9846250Sroot char *name; 9851119Sbill { 9866250Sroot if (!wflag) 9876250Sroot return (1); 9886250Sroot printf("%c ", c); 9896250Sroot if (vflag) 9906250Sroot longt(&stbuf); 9916250Sroot printf("%s: ", name); 9926250Sroot return (response() == 'y'); 9931119Sbill } 9941119Sbill 9951119Sbill response() 9961119Sbill { 9971119Sbill char c; 9981119Sbill 9991119Sbill c = getchar(); 10001119Sbill if (c != '\n') 10016250Sroot while (getchar() != '\n') 10026250Sroot ; 10036250Sroot else 10046250Sroot c = 'n'; 10056250Sroot return (c); 10061119Sbill } 10071119Sbill 100812154Ssam checkf(name, mode, howmuch) 100912154Ssam char *name; 101012154Ssam int mode, howmuch; 101112154Ssam { 101212154Ssam int l; 101312154Ssam 101421910Skjd if ((mode & S_IFMT) == S_IFDIR){ 101521910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 101621910Skjd return(0); 101721910Skjd return(1); 101821910Skjd } 101912154Ssam if ((l = strlen(name)) < 3) 102012154Ssam return (1); 102112154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 102212154Ssam return (0); 102312154Ssam if (strcmp(name, "core") == 0 || 102412154Ssam strcmp(name, "errs") == 0 || 102512154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 102612154Ssam return (0); 102712154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 102812154Ssam return (1); 102912154Ssam } 103012154Ssam 103122688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 10321119Sbill checkupdate(arg) 10336250Sroot char *arg; 10341119Sbill { 10351119Sbill char name[100]; 10366250Sroot long mtime; 10371119Sbill daddr_t seekp; 10381119Sbill daddr_t lookup(); 10391119Sbill 10401119Sbill rewind(tfile); 10411119Sbill for (;;) { 10421119Sbill if ((seekp = lookup(arg)) < 0) 10436250Sroot return (1); 10441119Sbill fseek(tfile, seekp, 0); 10451119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10466250Sroot return (stbuf.st_mtime > mtime); 10471119Sbill } 10481119Sbill } 10491119Sbill 10501119Sbill done(n) 10511119Sbill { 105221457Skjd unlink(tname); 10531119Sbill exit(n); 10541119Sbill } 10551119Sbill 105627445Slepreau /* 105727445Slepreau * Do we want the next entry on the tape, i.e. is it selected? If 105827445Slepreau * not, skip over the entire entry. Return -1 if reached end of tape. 105927445Slepreau */ 106027445Slepreau wantit(argv) 106127445Slepreau char *argv[]; 106227445Slepreau { 106327445Slepreau register char **cp; 106427445Slepreau 106527445Slepreau getdir(); 106627445Slepreau if (endtape()) 106727445Slepreau return (-1); 106827445Slepreau if (*argv == 0) 106927445Slepreau return (1); 107027445Slepreau for (cp = argv; *cp; cp++) 107127445Slepreau if (prefix(*cp, dblock.dbuf.name)) 107227445Slepreau return (1); 107327445Slepreau passtape(); 107427445Slepreau return (0); 107527445Slepreau } 107627445Slepreau 107722688Slepreau /* 107822688Slepreau * Does s2 begin with the string s1, on a directory boundary? 107922688Slepreau */ 10801119Sbill prefix(s1, s2) 10816250Sroot register char *s1, *s2; 10821119Sbill { 10831119Sbill while (*s1) 10841119Sbill if (*s1++ != *s2++) 10856250Sroot return (0); 10861119Sbill if (*s2) 10876250Sroot return (*s2 == '/'); 10886250Sroot return (1); 10891119Sbill } 10901119Sbill 10911119Sbill #define N 200 10921119Sbill int njab; 10936250Sroot 10941119Sbill daddr_t 10951119Sbill lookup(s) 10966250Sroot char *s; 10971119Sbill { 10981119Sbill register i; 10991119Sbill daddr_t a; 11001119Sbill 11011119Sbill for(i=0; s[i]; i++) 11026250Sroot if (s[i] == ' ') 11031119Sbill break; 11041119Sbill a = bsrch(s, i, low, high); 11056250Sroot return (a); 11061119Sbill } 11071119Sbill 11081119Sbill daddr_t 11091119Sbill bsrch(s, n, l, h) 11106250Sroot daddr_t l, h; 11116250Sroot char *s; 11121119Sbill { 11131119Sbill register i, j; 11141119Sbill char b[N]; 11151119Sbill daddr_t m, m1; 11161119Sbill 11171119Sbill njab = 0; 11181119Sbill 11191119Sbill loop: 11206250Sroot if (l >= h) 112122688Slepreau return ((daddr_t) -1); 11221119Sbill m = l + (h-l)/2 - N/2; 11236250Sroot if (m < l) 11241119Sbill m = l; 11251119Sbill fseek(tfile, m, 0); 11261119Sbill fread(b, 1, N, tfile); 11271119Sbill njab++; 11281119Sbill for(i=0; i<N; i++) { 11296250Sroot if (b[i] == '\n') 11301119Sbill break; 11311119Sbill m++; 11321119Sbill } 11336250Sroot if (m >= h) 113422688Slepreau return ((daddr_t) -1); 11351119Sbill m1 = m; 11361119Sbill j = i; 11371119Sbill for(i++; i<N; i++) { 11381119Sbill m1++; 11396250Sroot if (b[i] == '\n') 11401119Sbill break; 11411119Sbill } 11421119Sbill i = cmp(b+j, s, n); 11436250Sroot if (i < 0) { 11441119Sbill h = m; 11451119Sbill goto loop; 11461119Sbill } 11476250Sroot if (i > 0) { 11481119Sbill l = m1; 11491119Sbill goto loop; 11501119Sbill } 11516250Sroot return (m); 11521119Sbill } 11531119Sbill 11541119Sbill cmp(b, s, n) 11556250Sroot char *b, *s; 11561119Sbill { 11571119Sbill register i; 11581119Sbill 11596250Sroot if (b[0] != '\n') 116021457Skjd exit(2); 11611119Sbill for(i=0; i<n; i++) { 11626250Sroot if (b[i+1] > s[i]) 11636250Sroot return (-1); 11646250Sroot if (b[i+1] < s[i]) 11656250Sroot return (1); 11661119Sbill } 11676250Sroot return (b[i+1] == ' '? 0 : -1); 11681119Sbill } 11691119Sbill 117022688Slepreau readtape(buffer) 11716250Sroot char *buffer; 11721119Sbill { 117321457Skjd char *bufp; 117421457Skjd 117522688Slepreau if (first == 0) 117622688Slepreau getbuf(); 117727445Slepreau (void) readtbuf(&bufp, TBLOCK); 117821457Skjd bcopy(bufp, buffer, TBLOCK); 117921457Skjd return(TBLOCK); 118021457Skjd } 118121457Skjd 118221457Skjd readtbuf(bufpp, size) 118321457Skjd char **bufpp; 118421457Skjd int size; 118521457Skjd { 11863457Swnj register int i; 11871119Sbill 11881119Sbill if (recno >= nblock || first == 0) { 118927445Slepreau if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 119027058Smckusick mterr("read", i, 3); 11911119Sbill if (first == 0) { 11921119Sbill if ((i % TBLOCK) != 0) { 119313492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11941119Sbill done(3); 11951119Sbill } 11961119Sbill i /= TBLOCK; 11973457Swnj if (i != nblock) { 119813492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11991119Sbill nblock = i; 12001119Sbill } 120122353Skjd first = 1; 12021119Sbill } 12031119Sbill recno = 0; 12041119Sbill } 120521457Skjd if (size > ((nblock-recno)*TBLOCK)) 120621457Skjd size = (nblock-recno)*TBLOCK; 120721457Skjd *bufpp = (char *)&tbuf[recno]; 120821457Skjd recno += (size/TBLOCK); 120921457Skjd return (size); 12101119Sbill } 12111119Sbill 121221457Skjd writetbuf(buffer, n) 121321457Skjd register char *buffer; 121421457Skjd register int n; 12151119Sbill { 121627058Smckusick int i; 121722688Slepreau 121822688Slepreau if (first == 0) { 121922353Skjd getbuf(); 122022353Skjd first = 1; 122122353Skjd } 12221119Sbill if (recno >= nblock) { 122327445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 122427058Smckusick if (i != TBLOCK*nblock) 122527058Smckusick mterr("write", i, 2); 12261119Sbill recno = 0; 12271119Sbill } 122821457Skjd 122921457Skjd /* 123021457Skjd * Special case: We have an empty tape buffer, and the 123121457Skjd * users data size is >= the tape block size: Avoid 123221457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 123321457Skjd * residual to the tape buffer. 123421457Skjd */ 123521457Skjd while (recno == 0 && n >= nblock) { 123627058Smckusick i = write(mt, buffer, TBLOCK*nblock); 123727058Smckusick if (i != TBLOCK*nblock) 123827058Smckusick mterr("write", i, 2); 123921457Skjd n -= nblock; 124021457Skjd buffer += (nblock * TBLOCK); 12411119Sbill } 124221457Skjd 124321457Skjd while (n-- > 0) { 124421457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 124521457Skjd buffer += TBLOCK; 124621457Skjd if (recno >= nblock) { 124727445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 124827058Smckusick if (i != TBLOCK*nblock) 124927058Smckusick mterr("write", i, 2); 125021457Skjd recno = 0; 125121457Skjd } 125221457Skjd } 125321457Skjd 125421457Skjd /* Tell the user how much to write to get in sync */ 125521457Skjd return (nblock - recno); 12561119Sbill } 12571119Sbill 12581119Sbill backtape() 12591119Sbill { 126027058Smckusick static int mtdev = 1; 12613457Swnj static struct mtop mtop = {MTBSR, 1}; 126227058Smckusick struct mtget mtget; 126327058Smckusick 126427058Smckusick if (mtdev == 1) 126527445Slepreau mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 12663457Swnj if (mtdev == 0) { 126727445Slepreau if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 126836227Sbostic fprintf(stderr, "tar: tape backspace error: %s\n", 126936227Sbostic strerror(errno)); 12701119Sbill done(4); 12711119Sbill } 12723457Swnj } else 127336227Sbostic (void)lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 12743457Swnj recno--; 12751119Sbill } 12761119Sbill 12771119Sbill flushtape() 12781119Sbill { 127927058Smckusick int i; 128027058Smckusick 128127445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 128227058Smckusick if (i != TBLOCK*nblock) 128327058Smckusick mterr("write", i, 2); 12841119Sbill } 12851119Sbill 128627058Smckusick mterr(operation, i, exitcode) 128727058Smckusick char *operation; 128827058Smckusick int i; 128927058Smckusick { 129036227Sbostic fprintf(stderr, "tar: tape %s error: %s\n", 129136227Sbostic operation, i < 0 ? strerror(errno) : "unexpected EOF"); 129227058Smckusick done(exitcode); 129327058Smckusick } 129427058Smckusick 12958737Smckusick bread(fd, buf, size) 12968737Smckusick int fd; 12978737Smckusick char *buf; 12988737Smckusick int size; 12998737Smckusick { 13008737Smckusick int count; 13018737Smckusick static int lastread = 0; 13028737Smckusick 130322688Slepreau if (!Bflag) 130422688Slepreau return (read(fd, buf, size)); 130522353Skjd 13068737Smckusick for (count = 0; count < size; count += lastread) { 130724281Smckusick lastread = read(fd, buf, size - count); 130824281Smckusick if (lastread <= 0) { 13098737Smckusick if (count > 0) 13108737Smckusick return (count); 13118737Smckusick return (lastread); 13128737Smckusick } 13138737Smckusick buf += lastread; 13148737Smckusick } 13158737Smckusick return (count); 13168737Smckusick } 131710165Ssam 131810165Ssam char * 131946656Sbostic cwd() 132010165Ssam { 132146656Sbostic char *p; 132246656Sbostic 132346656Sbostic p = getcwd((char *)NULL, 0); 132446656Sbostic if (p == NULL) { 132546656Sbostic (void)fprintf(stderr, "tar: %s\n", strerror(errno)); 132621457Skjd exit(1); 132710165Ssam } 132846656Sbostic return (p); 132910165Ssam } 133021910Skjd 133121910Skjd getbuf() 133221910Skjd { 133322353Skjd 133427058Smckusick if (nblock == 0) { 133521910Skjd fstat(mt, &stbuf); 133621910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 133727058Smckusick nblock = NBLOCK; 133821910Skjd else { 133927058Smckusick nblock = stbuf.st_blksize / TBLOCK; 134027058Smckusick if (nblock == 0) 134127058Smckusick nblock = NBLOCK; 134221910Skjd } 134321910Skjd } 134427445Slepreau tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 134521910Skjd if (tbuf == NULL) { 134621910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 134721910Skjd nblock); 134821910Skjd done(1); 134921910Skjd } 135021910Skjd } 135122353Skjd 135222688Slepreau /* 135327442Slepreau * Save this directory and its mtime on the stack, popping and setting 135427442Slepreau * the mtimes of any stacked dirs which aren't parents of this one. 135527442Slepreau * A null directory causes the entire stack to be unwound and set. 135622688Slepreau * 135727442Slepreau * Since all the elements of the directory "stack" share a common 135827442Slepreau * prefix, we can make do with one string. We keep only the current 135927442Slepreau * directory path, with an associated array of mtime's, one for each 136027442Slepreau * '/' in the path. A negative mtime means no mtime. The mtime's are 136127442Slepreau * offset by one (first index 1, not 0) because calling this with a null 136227442Slepreau * directory causes mtime[0] to be set. 136327442Slepreau * 136422688Slepreau * This stack algorithm is not guaranteed to work for tapes created 136522688Slepreau * with the 'r' option, but the vast majority of tapes with 136622688Slepreau * directories are not. This avoids saving every directory record on 136722688Slepreau * the tape and setting all the times at the end. 136822688Slepreau */ 136922688Slepreau char dirstack[NAMSIZ]; 137022688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 137122688Slepreau time_t mtime[NTIM]; 137222353Skjd 137322688Slepreau dodirtimes(hp) 137422688Slepreau union hblock *hp; 137522353Skjd { 137622688Slepreau register char *p = dirstack; 137722688Slepreau register char *q = hp->dbuf.name; 137822688Slepreau register int ndir = 0; 137922688Slepreau char *savp; 138022688Slepreau int savndir; 138122353Skjd 138222688Slepreau /* Find common prefix */ 138330090Sbostic while (*p == *q && *p) { 138422688Slepreau if (*p++ == '/') 138522688Slepreau ++ndir; 138622688Slepreau q++; 138722688Slepreau } 138822353Skjd 138922688Slepreau savp = p; 139022688Slepreau savndir = ndir; 139122688Slepreau while (*p) { 139222688Slepreau /* 139322688Slepreau * Not a child: unwind the stack, setting the times. 139422688Slepreau * The order we do this doesn't matter, so we go "forward." 139522688Slepreau */ 139622688Slepreau if (*p++ == '/') 139722688Slepreau if (mtime[++ndir] >= 0) { 139822688Slepreau *--p = '\0'; /* zap the slash */ 139922688Slepreau setimes(dirstack, mtime[ndir]); 140022688Slepreau *p++ = '/'; 140122688Slepreau } 140222688Slepreau } 140322688Slepreau p = savp; 140422688Slepreau ndir = savndir; 140522353Skjd 140622688Slepreau /* Push this one on the "stack" */ 140722688Slepreau while (*p = *q++) /* append the rest of the new dir */ 140822688Slepreau if (*p++ == '/') 140922688Slepreau mtime[++ndir] = -1; 141022688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 141122688Slepreau } 141222353Skjd 141322688Slepreau setimes(path, mt) 141422688Slepreau char *path; 141522688Slepreau time_t mt; 141622688Slepreau { 141722688Slepreau struct timeval tv[2]; 141822353Skjd 141922688Slepreau tv[0].tv_sec = time((time_t *) 0); 142022688Slepreau tv[1].tv_sec = mt; 142122688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 142236227Sbostic if (utimes(path, tv) < 0) 142336227Sbostic fprintf(stderr, "tar: can't set time on %s: %s\n", 142436227Sbostic path, strerror(errno)); 142522688Slepreau } 142622688Slepreau 142722688Slepreau char * 142822688Slepreau getmem(size) 142922688Slepreau { 143022688Slepreau char *p = malloc((unsigned) size); 143122688Slepreau 143222688Slepreau if (p == NULL && freemem) { 143322688Slepreau fprintf(stderr, 143422688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 143522688Slepreau freemem = 0; 143622353Skjd } 143722688Slepreau return (p); 143822353Skjd } 1439