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"; 1122502Sdist #endif not lint 126250Sroot 1322502Sdist #ifndef lint 14*27445Slepreau static char sccsid[] = "@(#)tar.c 5.7 (Berkeley) 04/26/86"; 1522502Sdist #endif not lint 1622502Sdist 176250Sroot /* 186250Sroot * Tape Archival Program 196250Sroot */ 201119Sbill #include <stdio.h> 216413Smckusic #include <sys/param.h> 221119Sbill #include <sys/stat.h> 2312154Ssam #include <sys/dir.h> 248150Smckusick #include <sys/ioctl.h> 253457Swnj #include <sys/mtio.h> 2612983Ssam #include <sys/time.h> 271119Sbill #include <signal.h> 2812154Ssam #include <errno.h> 2927058Smckusick #include <fcntl.h> 301119Sbill 311119Sbill #define TBLOCK 512 323355Swnj #define NBLOCK 20 331119Sbill #define NAMSIZ 100 346250Sroot 3521457Skjd #define writetape(b) writetbuf(b, 1) 3621457Skjd #define min(a,b) ((a) < (b) ? (a) : (b)) 3721457Skjd #define max(a,b) ((a) > (b) ? (a) : (b)) 3821457Skjd 391119Sbill union hblock { 401119Sbill char dummy[TBLOCK]; 411119Sbill struct header { 421119Sbill char name[NAMSIZ]; 431119Sbill char mode[8]; 441119Sbill char uid[8]; 451119Sbill char gid[8]; 461119Sbill char size[12]; 471119Sbill char mtime[12]; 481119Sbill char chksum[8]; 491119Sbill char linkflag; 501119Sbill char linkname[NAMSIZ]; 511119Sbill } dbuf; 526250Sroot }; 531119Sbill 541119Sbill struct linkbuf { 551119Sbill ino_t inum; 561119Sbill dev_t devnum; 571119Sbill int count; 581119Sbill char pathname[NAMSIZ]; 591119Sbill struct linkbuf *nextp; 606250Sroot }; 611119Sbill 626250Sroot union hblock dblock; 6313492Ssam union hblock *tbuf; 646250Sroot struct linkbuf *ihead; 656250Sroot struct stat stbuf; 661119Sbill 676250Sroot int rflag; 686250Sroot int xflag; 696250Sroot int vflag; 706250Sroot int tflag; 716250Sroot int cflag; 726250Sroot int mflag; 736250Sroot int fflag; 7412154Ssam int iflag; 756250Sroot int oflag; 766250Sroot int pflag; 776250Sroot int wflag; 786250Sroot int hflag; 798737Smckusick int Bflag; 8012154Ssam int Fflag; 816250Sroot 826250Sroot int mt; 836250Sroot int term; 846250Sroot int chksum; 856250Sroot int recno; 8622688Slepreau int first; 8722688Slepreau int prtlinkerr; 881119Sbill int freemem = 1; 8922353Skjd int nblock = 0; 906250Sroot int onintr(); 916250Sroot int onquit(); 926250Sroot int onhup(); 9322688Slepreau #ifdef notdef 946250Sroot int onterm(); 9522688Slepreau #endif 961119Sbill 971119Sbill daddr_t low; 981119Sbill daddr_t high; 996250Sroot daddr_t bsrch(); 1001119Sbill 10121910Skjd FILE *vfile = stdout; 1021119Sbill FILE *tfile; 1031119Sbill char tname[] = "/tmp/tarXXXXXX"; 1041119Sbill char *usefile; 1056250Sroot char magtape[] = "/dev/rmt8"; 1061119Sbill char *malloc(); 107*27445Slepreau long time(); 108*27445Slepreau off_t lseek(); 109*27445Slepreau char *mktemp(); 1106250Sroot char *sprintf(); 1116250Sroot char *strcat(); 11227058Smckusick char *strcpy(); 11312154Ssam char *rindex(); 11410165Ssam char *getcwd(); 1159844Ssam char *getwd(); 11622688Slepreau char *getmem(); 1171119Sbill 1181119Sbill main(argc, argv) 1191119Sbill int argc; 1201119Sbill char *argv[]; 1211119Sbill { 1221119Sbill char *cp; 1231119Sbill 1241119Sbill if (argc < 2) 1251119Sbill usage(); 1261119Sbill 1271119Sbill tfile = NULL; 1281119Sbill usefile = magtape; 1291119Sbill argv[argc] = 0; 1301119Sbill argv++; 1311119Sbill for (cp = *argv++; *cp; cp++) 1321119Sbill switch(*cp) { 1336250Sroot 1341119Sbill case 'f': 13512154Ssam if (*argv == 0) { 13612154Ssam fprintf(stderr, 13712154Ssam "tar: tapefile must be specified with 'f' option\n"); 13812154Ssam usage(); 13912154Ssam } 1401119Sbill usefile = *argv++; 1411119Sbill fflag++; 1421119Sbill break; 1436250Sroot 1441119Sbill case 'c': 1451119Sbill cflag++; 1461119Sbill rflag++; 1471119Sbill break; 1486250Sroot 1491119Sbill case 'o': 1501119Sbill oflag++; 1511119Sbill break; 1526250Sroot 1531119Sbill case 'p': 1541119Sbill pflag++; 1551119Sbill break; 1566250Sroot 1571119Sbill case 'u': 1581119Sbill mktemp(tname); 1591119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1606250Sroot fprintf(stderr, 16122688Slepreau "tar: cannot create temporary file (%s)\n", 1626250Sroot tname); 1631119Sbill done(1); 1641119Sbill } 1651119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1666250Sroot /*FALL THRU*/ 1676250Sroot 1681119Sbill case 'r': 1691119Sbill rflag++; 1701119Sbill break; 1716250Sroot 1721119Sbill case 'v': 1731119Sbill vflag++; 1741119Sbill break; 1756250Sroot 1761119Sbill case 'w': 1771119Sbill wflag++; 1781119Sbill break; 1796250Sroot 1801119Sbill case 'x': 1811119Sbill xflag++; 1821119Sbill break; 1836250Sroot 1841119Sbill case 't': 1851119Sbill tflag++; 1861119Sbill break; 1876250Sroot 1881119Sbill case 'm': 1891119Sbill mflag++; 1901119Sbill break; 1916250Sroot 1921119Sbill case '-': 1931119Sbill break; 1946250Sroot 1951119Sbill case '0': 1961119Sbill case '1': 1971119Sbill case '4': 1981119Sbill case '5': 19921457Skjd case '7': 2001119Sbill case '8': 2011119Sbill magtape[8] = *cp; 2021119Sbill usefile = magtape; 2031119Sbill break; 2046250Sroot 2051119Sbill case 'b': 20613492Ssam if (*argv == 0) { 20713492Ssam fprintf(stderr, 20813492Ssam "tar: blocksize must be specified with 'b' option\n"); 20913492Ssam usage(); 21013492Ssam } 21113492Ssam nblock = atoi(*argv); 21213492Ssam if (nblock <= 0) { 21313492Ssam fprintf(stderr, 21413492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2151119Sbill done(1); 2161119Sbill } 21713492Ssam argv++; 2181119Sbill break; 2196250Sroot 2201119Sbill case 'l': 22122688Slepreau prtlinkerr++; 2221119Sbill break; 2236250Sroot 2246250Sroot case 'h': 2256250Sroot hflag++; 2266250Sroot break; 2276250Sroot 22812154Ssam case 'i': 22912154Ssam iflag++; 23012154Ssam break; 23112154Ssam 2328737Smckusick case 'B': 2338737Smckusick Bflag++; 2348737Smckusick break; 2358737Smckusick 23612154Ssam case 'F': 23712154Ssam Fflag++; 23812154Ssam break; 23912154Ssam 2401119Sbill default: 2411119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2421119Sbill usage(); 2431119Sbill } 2441119Sbill 2456250Sroot if (!rflag && !xflag && !tflag) 2466250Sroot usage(); 2471119Sbill if (rflag) { 2486250Sroot if (cflag && tfile != NULL) 2491119Sbill usage(); 2501119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 251*27445Slepreau (void) signal(SIGINT, onintr); 2521119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 253*27445Slepreau (void) signal(SIGHUP, onhup); 2541119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 255*27445Slepreau (void) signal(SIGQUIT, onquit); 2566250Sroot #ifdef notdef 2571119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 258*27445Slepreau (void) signal(SIGTERM, onterm); 2596250Sroot #endif 26027058Smckusick mt = openmt(usefile, 1); 2611119Sbill dorep(argv); 2626250Sroot done(0); 2631119Sbill } 26427058Smckusick mt = openmt(usefile, 0); 2656250Sroot if (xflag) 2661119Sbill doxtract(argv); 2676250Sroot else 268*27445Slepreau dotable(argv); 2691119Sbill done(0); 2701119Sbill } 2711119Sbill 2721119Sbill usage() 2731119Sbill { 2746250Sroot fprintf(stderr, 27521457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2761119Sbill done(1); 2771119Sbill } 2781119Sbill 27927058Smckusick int 28027058Smckusick openmt(tape, writing) 28127058Smckusick char *tape; 28227058Smckusick int writing; 28327058Smckusick { 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) 308*27445Slepreau 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) { 31427058Smckusick fprintf(stderr, "tar: "); 31527058Smckusick perror(tape); 31627058Smckusick done(1); 31727058Smckusick } 31827058Smckusick } 31927058Smckusick return(mt); 32027058Smckusick } 32127058Smckusick 3221119Sbill dorep(argv) 3236250Sroot char *argv[]; 3241119Sbill { 3251119Sbill register char *cp, *cp2; 3269601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 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 3406250Sroot 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 35110165Ssam (void) getcwd(wdir); 3521119Sbill while (*argv && ! term) { 3531119Sbill cp2 = *argv; 3541119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3551119Sbill argv++; 35627058Smckusick if (chdir(*argv) < 0) { 35727058Smckusick fprintf(stderr, "tar: can't change directories to "); 3581119Sbill perror(*argv); 35927058Smckusick } else 36010165Ssam (void) getcwd(wdir); 3611119Sbill argv++; 3621119Sbill continue; 3631119Sbill } 3649601Ssam parent = wdir; 3651119Sbill for (cp = *argv; *cp; cp++) 3661119Sbill if (*cp == '/') 3671119Sbill cp2 = cp; 3681119Sbill if (cp2 != *argv) { 3691119Sbill *cp2 = '\0'; 3709601Ssam if (chdir(*argv) < 0) { 37127058Smckusick fprintf(stderr, "tar: can't change directories to "); 3729601Ssam perror(*argv); 3739601Ssam continue; 3749601Ssam } 37510165Ssam parent = getcwd(tempdir); 3761119Sbill *cp2 = '/'; 3771119Sbill cp2++; 3781119Sbill } 3799601Ssam putfile(*argv++, cp2, parent); 38015045Smckusick if (chdir(wdir) < 0) { 38122688Slepreau fprintf(stderr, "tar: cannot change back?: "); 38215045Smckusick perror(wdir); 38315045Smckusick } 3841119Sbill } 3851119Sbill putempty(); 3861119Sbill putempty(); 3871119Sbill flushtape(); 38822688Slepreau if (prtlinkerr == 0) 3896250Sroot return; 3906250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3916250Sroot if (ihead->count == 0) 3926250Sroot continue; 39313492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3946250Sroot } 3951119Sbill } 3961119Sbill 3971119Sbill endtape() 3981119Sbill { 39921457Skjd return (dblock.dbuf.name[0] == '\0'); 4001119Sbill } 4011119Sbill 4021119Sbill getdir() 4031119Sbill { 4041119Sbill register struct stat *sp; 4051119Sbill int i; 4061119Sbill 40712154Ssam top: 4086250Sroot readtape((char *)&dblock); 4091119Sbill if (dblock.dbuf.name[0] == '\0') 4101119Sbill return; 4111119Sbill sp = &stbuf; 4121119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4131119Sbill sp->st_mode = i; 4141119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4151119Sbill sp->st_uid = i; 4161119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4171119Sbill sp->st_gid = i; 4181119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4191119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4201119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 42112154Ssam if (chksum != (i = checksum())) { 42213492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 42312154Ssam chksum, i); 42412154Ssam if (iflag) 42512154Ssam goto top; 4261119Sbill done(2); 4271119Sbill } 4281119Sbill if (tfile != NULL) 4291119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4301119Sbill } 4311119Sbill 4321119Sbill passtape() 4331119Sbill { 4341119Sbill long blocks; 43521457Skjd char *bufp; 4361119Sbill 4371119Sbill if (dblock.dbuf.linkflag == '1') 4381119Sbill return; 4391119Sbill blocks = stbuf.st_size; 4401119Sbill blocks += TBLOCK-1; 4411119Sbill blocks /= TBLOCK; 4421119Sbill 44321457Skjd while (blocks-- > 0) 444*27445Slepreau (void) readtbuf(&bufp, TBLOCK); 4451119Sbill } 4461119Sbill 4479601Ssam putfile(longname, shortname, parent) 4486250Sroot char *longname; 4496250Sroot char *shortname; 4509601Ssam char *parent; 4511119Sbill { 45221457Skjd int infile = 0; 45321457Skjd long blocks; 4541119Sbill char buf[TBLOCK]; 45521457Skjd char *bigbuf; 45622688Slepreau register char *cp; 4575931Smckusic struct direct *dp; 4585931Smckusic DIR *dirp; 459*27445Slepreau register int i; 460*27445Slepreau long l; 4619601Ssam char newparent[NAMSIZ+64]; 46212154Ssam extern int errno; 46321457Skjd int maxread; 46421457Skjd int hint; /* amount to write to get "in sync" */ 4651119Sbill 4669601Ssam if (!hflag) 46712154Ssam i = lstat(shortname, &stbuf); 46812154Ssam else 46912154Ssam i = stat(shortname, &stbuf); 47012154Ssam if (i < 0) { 47127058Smckusick fprintf(stderr, "tar: "); 47227058Smckusick perror(longname); 4739601Ssam return; 4749601Ssam } 47512154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4761119Sbill return; 47712154Ssam if (checkw('r', longname) == 0) 4781119Sbill return; 47912154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 48012154Ssam return; 4811119Sbill 48212154Ssam switch (stbuf.st_mode & S_IFMT) { 48312154Ssam case S_IFDIR: 4846250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4856250Sroot ; 4861119Sbill *--cp = '/'; 4871119Sbill *++cp = 0 ; 4881119Sbill if (!oflag) { 4896250Sroot if ((cp - buf) >= NAMSIZ) { 49013492Ssam fprintf(stderr, "tar: %s: file name too long\n", 49113492Ssam longname); 4926250Sroot return; 4936250Sroot } 4946250Sroot stbuf.st_size = 0; 4956250Sroot tomodes(&stbuf); 4966250Sroot strcpy(dblock.dbuf.name,buf); 4976250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 498*27445Slepreau (void) writetape((char *)&dblock); 4991119Sbill } 5009601Ssam sprintf(newparent, "%s/%s", parent, shortname); 50115045Smckusick if (chdir(shortname) < 0) { 50215045Smckusick perror(shortname); 50315045Smckusick return; 50415045Smckusick } 5055931Smckusic if ((dirp = opendir(".")) == NULL) { 50613492Ssam fprintf(stderr, "tar: %s: directory read error\n", 50713492Ssam longname); 50815045Smckusick if (chdir(parent) < 0) { 50922688Slepreau fprintf(stderr, "tar: cannot change back?: "); 51015045Smckusick perror(parent); 51115045Smckusick } 5125931Smckusic return; 5135931Smckusic } 5145931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5155931Smckusic if (dp->d_ino == 0) 5161119Sbill continue; 5176250Sroot if (!strcmp(".", dp->d_name) || 5186250Sroot !strcmp("..", dp->d_name)) 5191119Sbill continue; 5205931Smckusic strcpy(cp, dp->d_name); 521*27445Slepreau l = telldir(dirp); 5225931Smckusic closedir(dirp); 5239601Ssam putfile(buf, cp, newparent); 5245931Smckusic dirp = opendir("."); 525*27445Slepreau seekdir(dirp, l); 5261119Sbill } 5275931Smckusic closedir(dirp); 52815045Smckusick if (chdir(parent) < 0) { 52922688Slepreau fprintf(stderr, "tar: cannot change back?: "); 53015045Smckusick perror(parent); 53115045Smckusick } 53212154Ssam break; 53312154Ssam 53412154Ssam case S_IFLNK: 53512154Ssam tomodes(&stbuf); 53612154Ssam if (strlen(longname) >= NAMSIZ) { 53713492Ssam fprintf(stderr, "tar: %s: file name too long\n", 53813492Ssam longname); 53912154Ssam return; 54012154Ssam } 54112154Ssam strcpy(dblock.dbuf.name, longname); 5426250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 54313492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 54413492Ssam longname); 5456250Sroot return; 5466250Sroot } 5479601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5486250Sroot if (i < 0) { 54927058Smckusick fprintf(stderr, "tar: can't read symbolic link "); 5509601Ssam perror(longname); 5516250Sroot return; 5526250Sroot } 5536250Sroot dblock.dbuf.linkname[i] = '\0'; 5546250Sroot dblock.dbuf.linkflag = '2'; 55522688Slepreau if (vflag) 55622688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 55722688Slepreau longname, dblock.dbuf.linkname); 5586250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 5596250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 560*27445Slepreau (void) writetape((char *)&dblock); 56112154Ssam break; 5621119Sbill 56312154Ssam case S_IFREG: 56412154Ssam if ((infile = open(shortname, 0)) < 0) { 56527058Smckusick fprintf(stderr, "tar: "); 56627058Smckusick perror(longname); 5671119Sbill return; 5681119Sbill } 56912154Ssam tomodes(&stbuf); 57012154Ssam if (strlen(longname) >= NAMSIZ) { 57113492Ssam fprintf(stderr, "tar: %s: file name too long\n", 57213492Ssam longname); 57321457Skjd close(infile); 57412154Ssam return; 57512154Ssam } 57612154Ssam strcpy(dblock.dbuf.name, longname); 57712154Ssam if (stbuf.st_nlink > 1) { 57812154Ssam struct linkbuf *lp; 57912154Ssam int found = 0; 58012154Ssam 58112154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 58212154Ssam if (lp->inum == stbuf.st_ino && 58312154Ssam lp->devnum == stbuf.st_dev) { 58412154Ssam found++; 58512154Ssam break; 58612154Ssam } 58712154Ssam if (found) { 58812154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 58912154Ssam dblock.dbuf.linkflag = '1'; 59012154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 591*27445Slepreau (void) writetape( (char *) &dblock); 59222688Slepreau if (vflag) 59322688Slepreau fprintf(vfile, "a %s link to %s\n", 59422688Slepreau longname, lp->pathname); 59512154Ssam lp->count--; 59612154Ssam close(infile); 59712154Ssam return; 5981119Sbill } 59922688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 60022688Slepreau if (lp != NULL) { 60112154Ssam lp->nextp = ihead; 60212154Ssam ihead = lp; 60312154Ssam lp->inum = stbuf.st_ino; 60412154Ssam lp->devnum = stbuf.st_dev; 60512154Ssam lp->count = stbuf.st_nlink - 1; 60612154Ssam strcpy(lp->pathname, longname); 60712154Ssam } 6081119Sbill } 60921457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 61022688Slepreau if (vflag) 61122688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 61212154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 61321457Skjd hint = writetape((char *)&dblock); 61421457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 615*27445Slepreau if ((bigbuf = malloc((unsigned)maxread)) == 0) { 61621457Skjd maxread = TBLOCK; 61721457Skjd bigbuf = buf; 61821457Skjd } 6191119Sbill 62021457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 62121457Skjd && blocks > 0) { 62221457Skjd register int nblks; 62321457Skjd 62421457Skjd nblks = ((i-1)/TBLOCK)+1; 62521457Skjd if (nblks > blocks) 62621457Skjd nblks = blocks; 62721457Skjd hint = writetbuf(bigbuf, nblks); 62821457Skjd blocks -= nblks; 62921457Skjd } 63021457Skjd close(infile); 63121457Skjd if (bigbuf != buf) 63221457Skjd free(bigbuf); 63327058Smckusick if (i < 0) { 634*27445Slepreau fprintf(stderr, "tar: Read error on "); 63527058Smckusick perror(longname); 63627058Smckusick } else if (blocks != 0 || i != 0) 63713492Ssam fprintf(stderr, "tar: %s: file changed size\n", 63813492Ssam longname); 63912154Ssam while (--blocks >= 0) 64012154Ssam putempty(); 64112154Ssam break; 64212154Ssam 64312154Ssam default: 64412154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 64513492Ssam longname); 64612154Ssam break; 6471119Sbill } 6481119Sbill } 6491119Sbill 6501119Sbill doxtract(argv) 6516250Sroot char *argv[]; 6521119Sbill { 6531119Sbill long blocks, bytes; 654*27445Slepreau int ofile, i; 6551119Sbill 6561119Sbill for (;;) { 657*27445Slepreau if ((i = wantit(argv)) == 0) 658*27445Slepreau continue; 659*27445Slepreau if (i == -1) 660*27445Slepreau break; /* end of tape */ 6611119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6621119Sbill passtape(); 6631119Sbill continue; 6641119Sbill } 66512154Ssam if (Fflag) { 66612154Ssam char *s; 66712154Ssam 66812154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 66912154Ssam s = dblock.dbuf.name; 67012154Ssam else 67112154Ssam s++; 67212154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 67312154Ssam passtape(); 67412154Ssam continue; 67512154Ssam } 67612154Ssam } 67722688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 67822688Slepreau if (mflag == 0) 67922688Slepreau dodirtimes(&dblock); 6806250Sroot continue; 68122688Slepreau } 68222688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 68325250Sbloom /* 68425250Sbloom * only unlink non directories or empty 68525250Sbloom * directories 68625250Sbloom */ 68725250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 68825250Sbloom if (errno == ENOTDIR) 68925250Sbloom unlink(dblock.dbuf.name); 69025250Sbloom } 6916250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 69227058Smckusick fprintf(stderr, "tar: %s: symbolic link failed: ", 69313492Ssam dblock.dbuf.name); 69427058Smckusick perror(""); 6956250Sroot continue; 6966250Sroot } 6976250Sroot if (vflag) 69821910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 69913492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 70022353Skjd #ifdef notdef 70122353Skjd /* ignore alien orders */ 70222353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 70322688Slepreau if (mflag == 0) 70422688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 70522353Skjd if (pflag) 70622353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 70722353Skjd #endif 7081119Sbill continue; 7096250Sroot } 71022688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 71125250Sbloom /* 71225250Sbloom * only unlink non directories or empty 71325250Sbloom * directories 71425250Sbloom */ 71525250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 71625250Sbloom if (errno == ENOTDIR) 71725250Sbloom unlink(dblock.dbuf.name); 71825250Sbloom } 7191119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 72027058Smckusick fprintf(stderr, "tar: can't link %s to %s: ", 72127058Smckusick dblock.dbuf.name, dblock.dbuf.linkname); 72227058Smckusick perror(""); 7231119Sbill continue; 7241119Sbill } 7251119Sbill if (vflag) 72622688Slepreau fprintf(vfile, "%s linked to %s\n", 72713492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7281119Sbill continue; 7291119Sbill } 7306250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 73127058Smckusick fprintf(stderr, "tar: can't create %s: ", 73213492Ssam dblock.dbuf.name); 73327058Smckusick perror(""); 7341119Sbill passtape(); 7351119Sbill continue; 7361119Sbill } 73721457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7381119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7391119Sbill if (vflag) 74022688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 74113492Ssam dblock.dbuf.name, bytes, blocks); 74221457Skjd for (; blocks > 0;) { 74321457Skjd register int nread; 74421457Skjd char *bufp; 74521457Skjd register int nwant; 74621457Skjd 74721457Skjd nwant = NBLOCK*TBLOCK; 74821457Skjd if (nwant > (blocks*TBLOCK)) 74921457Skjd nwant = (blocks*TBLOCK); 75021457Skjd nread = readtbuf(&bufp, nwant); 75122688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7526250Sroot fprintf(stderr, 75327058Smckusick "tar: %s: HELP - extract write error", 75413492Ssam dblock.dbuf.name); 75527058Smckusick perror(""); 7566250Sroot done(2); 7576250Sroot } 75821457Skjd bytes -= nread; 75921457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7601119Sbill } 7611119Sbill close(ofile); 76222688Slepreau if (mflag == 0) 76322688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7641926Swnj if (pflag) 7656250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7661119Sbill } 76722688Slepreau if (mflag == 0) { 76822688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 76922688Slepreau dodirtimes(&dblock); 77022688Slepreau } 7711119Sbill } 7721119Sbill 773*27445Slepreau dotable(argv) 774*27445Slepreau char *argv[]; 7751119Sbill { 776*27445Slepreau register int i; 777*27445Slepreau 7781119Sbill for (;;) { 779*27445Slepreau if ((i = wantit(argv)) == 0) 780*27445Slepreau continue; 781*27445Slepreau if (i == -1) 782*27445Slepreau break; /* end of tape */ 7831119Sbill if (vflag) 7841119Sbill longt(&stbuf); 7851119Sbill printf("%s", dblock.dbuf.name); 7861119Sbill if (dblock.dbuf.linkflag == '1') 7871119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7886250Sroot if (dblock.dbuf.linkflag == '2') 7896250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7901119Sbill printf("\n"); 7911119Sbill passtape(); 7921119Sbill } 7931119Sbill } 7941119Sbill 7951119Sbill putempty() 7961119Sbill { 7971119Sbill char buf[TBLOCK]; 7981119Sbill 79913492Ssam bzero(buf, sizeof (buf)); 800*27445Slepreau (void) writetape(buf); 8011119Sbill } 8021119Sbill 8031119Sbill longt(st) 8046250Sroot register struct stat *st; 8051119Sbill { 8061119Sbill register char *cp; 8071119Sbill char *ctime(); 8081119Sbill 8091119Sbill pmode(st); 8101119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 811*27445Slepreau printf("%7ld", st->st_size); 8121119Sbill cp = ctime(&st->st_mtime); 8131119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8141119Sbill } 8151119Sbill 8161119Sbill #define SUID 04000 8171119Sbill #define SGID 02000 8181119Sbill #define ROWN 0400 8191119Sbill #define WOWN 0200 8201119Sbill #define XOWN 0100 8211119Sbill #define RGRP 040 8221119Sbill #define WGRP 020 8231119Sbill #define XGRP 010 8241119Sbill #define ROTH 04 8251119Sbill #define WOTH 02 8261119Sbill #define XOTH 01 8271119Sbill #define STXT 01000 8281119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8291119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8301119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8311119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8321119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8331119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8341119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8351119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8361119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8371119Sbill 8381119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8391119Sbill 8401119Sbill pmode(st) 8416250Sroot register struct stat *st; 8421119Sbill { 8431119Sbill register int **mp; 8441119Sbill 8451119Sbill for (mp = &m[0]; mp < &m[9];) 84627058Smckusick selectbits(*mp++, st); 8471119Sbill } 8481119Sbill 84927058Smckusick selectbits(pairp, st) 8506250Sroot int *pairp; 8516250Sroot struct stat *st; 8521119Sbill { 8531119Sbill register int n, *ap; 8541119Sbill 8551119Sbill ap = pairp; 8561119Sbill n = *ap++; 8571119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8581119Sbill ap++; 859*27445Slepreau putchar(*ap); 8601119Sbill } 8611119Sbill 86222688Slepreau /* 86327442Slepreau * Make all directories needed by `name'. If `name' is itself 86427442Slepreau * a directory on the tar tape (indicated by a trailing '/'), 86522688Slepreau * return 1; else 0. 86622688Slepreau */ 8671119Sbill checkdir(name) 8686250Sroot register char *name; 8691119Sbill { 8701119Sbill register char *cp; 8716250Sroot 87212154Ssam /* 87322688Slepreau * Quick check for existence of directory. 87412154Ssam */ 87512154Ssam if ((cp = rindex(name, '/')) == 0) 87612154Ssam return (0); 87712154Ssam *cp = '\0'; 87822688Slepreau if (access(name, 0) == 0) { /* already exists */ 87912154Ssam *cp = '/'; 88022688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 88112154Ssam } 88212154Ssam *cp = '/'; 88312154Ssam 88412154Ssam /* 88512154Ssam * No luck, try to make all directories in path. 88612154Ssam */ 8871119Sbill for (cp = name; *cp; cp++) { 8886250Sroot if (*cp != '/') 8896250Sroot continue; 8906250Sroot *cp = '\0'; 89112154Ssam if (access(name, 0) < 0) { 8929844Ssam if (mkdir(name, 0777) < 0) { 8939844Ssam perror(name); 89412154Ssam *cp = '/'; 89512154Ssam return (0); 8961119Sbill } 89721457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 89827442Slepreau if (pflag && cp[1] == '\0') /* dir on the tape */ 89927442Slepreau chmod(name, stbuf.st_mode & 07777); 9001119Sbill } 9016250Sroot *cp = '/'; 9021119Sbill } 9036250Sroot return (cp[-1]=='/'); 9041119Sbill } 9051119Sbill 9061119Sbill onintr() 9071119Sbill { 908*27445Slepreau (void) signal(SIGINT, SIG_IGN); 9091119Sbill term++; 9101119Sbill } 9111119Sbill 9121119Sbill onquit() 9131119Sbill { 914*27445Slepreau (void) signal(SIGQUIT, SIG_IGN); 9151119Sbill term++; 9161119Sbill } 9171119Sbill 9181119Sbill onhup() 9191119Sbill { 920*27445Slepreau (void) signal(SIGHUP, SIG_IGN); 9211119Sbill term++; 9221119Sbill } 9231119Sbill 92422688Slepreau #ifdef notdef 9251119Sbill onterm() 9261119Sbill { 927*27445Slepreau (void) signal(SIGTERM, SIG_IGN); 9281119Sbill term++; 9291119Sbill } 93022688Slepreau #endif 9311119Sbill 9321119Sbill tomodes(sp) 9331119Sbill register struct stat *sp; 9341119Sbill { 9351119Sbill register char *cp; 9361119Sbill 9371119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9381119Sbill *cp = '\0'; 9391119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 9401119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 9411119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 9421119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 9431119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9441119Sbill } 9451119Sbill 9461119Sbill checksum() 9471119Sbill { 9481119Sbill register i; 9491119Sbill register char *cp; 9501119Sbill 9516250Sroot for (cp = dblock.dbuf.chksum; 9526250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9531119Sbill *cp = ' '; 9541119Sbill i = 0; 9551119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9561119Sbill i += *cp; 9576250Sroot return (i); 9581119Sbill } 9591119Sbill 9601119Sbill checkw(c, name) 9616250Sroot char *name; 9621119Sbill { 9636250Sroot if (!wflag) 9646250Sroot return (1); 9656250Sroot printf("%c ", c); 9666250Sroot if (vflag) 9676250Sroot longt(&stbuf); 9686250Sroot printf("%s: ", name); 9696250Sroot return (response() == 'y'); 9701119Sbill } 9711119Sbill 9721119Sbill response() 9731119Sbill { 9741119Sbill char c; 9751119Sbill 9761119Sbill c = getchar(); 9771119Sbill if (c != '\n') 9786250Sroot while (getchar() != '\n') 9796250Sroot ; 9806250Sroot else 9816250Sroot c = 'n'; 9826250Sroot return (c); 9831119Sbill } 9841119Sbill 98512154Ssam checkf(name, mode, howmuch) 98612154Ssam char *name; 98712154Ssam int mode, howmuch; 98812154Ssam { 98912154Ssam int l; 99012154Ssam 99121910Skjd if ((mode & S_IFMT) == S_IFDIR){ 99221910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 99321910Skjd return(0); 99421910Skjd return(1); 99521910Skjd } 99612154Ssam if ((l = strlen(name)) < 3) 99712154Ssam return (1); 99812154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 99912154Ssam return (0); 100012154Ssam if (strcmp(name, "core") == 0 || 100112154Ssam strcmp(name, "errs") == 0 || 100212154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 100312154Ssam return (0); 100412154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 100512154Ssam return (1); 100612154Ssam } 100712154Ssam 100822688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 10091119Sbill checkupdate(arg) 10106250Sroot char *arg; 10111119Sbill { 10121119Sbill char name[100]; 10136250Sroot long mtime; 10141119Sbill daddr_t seekp; 10151119Sbill daddr_t lookup(); 10161119Sbill 10171119Sbill rewind(tfile); 10181119Sbill for (;;) { 10191119Sbill if ((seekp = lookup(arg)) < 0) 10206250Sroot return (1); 10211119Sbill fseek(tfile, seekp, 0); 10221119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10236250Sroot return (stbuf.st_mtime > mtime); 10241119Sbill } 10251119Sbill } 10261119Sbill 10271119Sbill done(n) 10281119Sbill { 102921457Skjd unlink(tname); 10301119Sbill exit(n); 10311119Sbill } 10321119Sbill 1033*27445Slepreau /* 1034*27445Slepreau * Do we want the next entry on the tape, i.e. is it selected? If 1035*27445Slepreau * not, skip over the entire entry. Return -1 if reached end of tape. 1036*27445Slepreau */ 1037*27445Slepreau wantit(argv) 1038*27445Slepreau char *argv[]; 1039*27445Slepreau { 1040*27445Slepreau register char **cp; 1041*27445Slepreau 1042*27445Slepreau getdir(); 1043*27445Slepreau if (endtape()) 1044*27445Slepreau return (-1); 1045*27445Slepreau if (*argv == 0) 1046*27445Slepreau return (1); 1047*27445Slepreau for (cp = argv; *cp; cp++) 1048*27445Slepreau if (prefix(*cp, dblock.dbuf.name)) 1049*27445Slepreau return (1); 1050*27445Slepreau passtape(); 1051*27445Slepreau return (0); 1052*27445Slepreau } 1053*27445Slepreau 105422688Slepreau /* 105522688Slepreau * Does s2 begin with the string s1, on a directory boundary? 105622688Slepreau */ 10571119Sbill prefix(s1, s2) 10586250Sroot register char *s1, *s2; 10591119Sbill { 10601119Sbill while (*s1) 10611119Sbill if (*s1++ != *s2++) 10626250Sroot return (0); 10631119Sbill if (*s2) 10646250Sroot return (*s2 == '/'); 10656250Sroot return (1); 10661119Sbill } 10671119Sbill 10681119Sbill #define N 200 10691119Sbill int njab; 10706250Sroot 10711119Sbill daddr_t 10721119Sbill lookup(s) 10736250Sroot char *s; 10741119Sbill { 10751119Sbill register i; 10761119Sbill daddr_t a; 10771119Sbill 10781119Sbill for(i=0; s[i]; i++) 10796250Sroot if (s[i] == ' ') 10801119Sbill break; 10811119Sbill a = bsrch(s, i, low, high); 10826250Sroot return (a); 10831119Sbill } 10841119Sbill 10851119Sbill daddr_t 10861119Sbill bsrch(s, n, l, h) 10876250Sroot daddr_t l, h; 10886250Sroot char *s; 10891119Sbill { 10901119Sbill register i, j; 10911119Sbill char b[N]; 10921119Sbill daddr_t m, m1; 10931119Sbill 10941119Sbill njab = 0; 10951119Sbill 10961119Sbill loop: 10976250Sroot if (l >= h) 109822688Slepreau return ((daddr_t) -1); 10991119Sbill m = l + (h-l)/2 - N/2; 11006250Sroot if (m < l) 11011119Sbill m = l; 11021119Sbill fseek(tfile, m, 0); 11031119Sbill fread(b, 1, N, tfile); 11041119Sbill njab++; 11051119Sbill for(i=0; i<N; i++) { 11066250Sroot if (b[i] == '\n') 11071119Sbill break; 11081119Sbill m++; 11091119Sbill } 11106250Sroot if (m >= h) 111122688Slepreau return ((daddr_t) -1); 11121119Sbill m1 = m; 11131119Sbill j = i; 11141119Sbill for(i++; i<N; i++) { 11151119Sbill m1++; 11166250Sroot if (b[i] == '\n') 11171119Sbill break; 11181119Sbill } 11191119Sbill i = cmp(b+j, s, n); 11206250Sroot if (i < 0) { 11211119Sbill h = m; 11221119Sbill goto loop; 11231119Sbill } 11246250Sroot if (i > 0) { 11251119Sbill l = m1; 11261119Sbill goto loop; 11271119Sbill } 11286250Sroot return (m); 11291119Sbill } 11301119Sbill 11311119Sbill cmp(b, s, n) 11326250Sroot char *b, *s; 11331119Sbill { 11341119Sbill register i; 11351119Sbill 11366250Sroot if (b[0] != '\n') 113721457Skjd exit(2); 11381119Sbill for(i=0; i<n; i++) { 11396250Sroot if (b[i+1] > s[i]) 11406250Sroot return (-1); 11416250Sroot if (b[i+1] < s[i]) 11426250Sroot return (1); 11431119Sbill } 11446250Sroot return (b[i+1] == ' '? 0 : -1); 11451119Sbill } 11461119Sbill 114722688Slepreau readtape(buffer) 11486250Sroot char *buffer; 11491119Sbill { 115021457Skjd char *bufp; 115121457Skjd 115222688Slepreau if (first == 0) 115322688Slepreau getbuf(); 1154*27445Slepreau (void) readtbuf(&bufp, TBLOCK); 115521457Skjd bcopy(bufp, buffer, TBLOCK); 115621457Skjd return(TBLOCK); 115721457Skjd } 115821457Skjd 115921457Skjd readtbuf(bufpp, size) 116021457Skjd char **bufpp; 116121457Skjd int size; 116221457Skjd { 11633457Swnj register int i; 11641119Sbill 11651119Sbill if (recno >= nblock || first == 0) { 1166*27445Slepreau if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 116727058Smckusick mterr("read", i, 3); 11681119Sbill if (first == 0) { 11691119Sbill if ((i % TBLOCK) != 0) { 117013492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11711119Sbill done(3); 11721119Sbill } 11731119Sbill i /= TBLOCK; 11743457Swnj if (i != nblock) { 117513492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11761119Sbill nblock = i; 11771119Sbill } 117822353Skjd first = 1; 11791119Sbill } 11801119Sbill recno = 0; 11811119Sbill } 118221457Skjd if (size > ((nblock-recno)*TBLOCK)) 118321457Skjd size = (nblock-recno)*TBLOCK; 118421457Skjd *bufpp = (char *)&tbuf[recno]; 118521457Skjd recno += (size/TBLOCK); 118621457Skjd return (size); 11871119Sbill } 11881119Sbill 118921457Skjd writetbuf(buffer, n) 119021457Skjd register char *buffer; 119121457Skjd register int n; 11921119Sbill { 119327058Smckusick int i; 119422688Slepreau 119522688Slepreau if (first == 0) { 119622353Skjd getbuf(); 119722353Skjd first = 1; 119822353Skjd } 11991119Sbill if (recno >= nblock) { 1200*27445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 120127058Smckusick if (i != TBLOCK*nblock) 120227058Smckusick mterr("write", i, 2); 12031119Sbill recno = 0; 12041119Sbill } 120521457Skjd 120621457Skjd /* 120721457Skjd * Special case: We have an empty tape buffer, and the 120821457Skjd * users data size is >= the tape block size: Avoid 120921457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 121021457Skjd * residual to the tape buffer. 121121457Skjd */ 121221457Skjd while (recno == 0 && n >= nblock) { 121327058Smckusick i = write(mt, buffer, TBLOCK*nblock); 121427058Smckusick if (i != TBLOCK*nblock) 121527058Smckusick mterr("write", i, 2); 121621457Skjd n -= nblock; 121721457Skjd buffer += (nblock * TBLOCK); 12181119Sbill } 121921457Skjd 122021457Skjd while (n-- > 0) { 122121457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 122221457Skjd buffer += TBLOCK; 122321457Skjd if (recno >= nblock) { 1224*27445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 122527058Smckusick if (i != TBLOCK*nblock) 122627058Smckusick mterr("write", i, 2); 122721457Skjd recno = 0; 122821457Skjd } 122921457Skjd } 123021457Skjd 123121457Skjd /* Tell the user how much to write to get in sync */ 123221457Skjd return (nblock - recno); 12331119Sbill } 12341119Sbill 12351119Sbill backtape() 12361119Sbill { 123727058Smckusick static int mtdev = 1; 12383457Swnj static struct mtop mtop = {MTBSR, 1}; 123927058Smckusick struct mtget mtget; 124027058Smckusick 124127058Smckusick if (mtdev == 1) 1242*27445Slepreau mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 12433457Swnj if (mtdev == 0) { 1244*27445Slepreau if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 124527058Smckusick fprintf(stderr, "tar: tape backspace error: "); 124627058Smckusick perror(""); 12471119Sbill done(4); 12481119Sbill } 12493457Swnj } else 125022688Slepreau lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 12513457Swnj recno--; 12521119Sbill } 12531119Sbill 12541119Sbill flushtape() 12551119Sbill { 125627058Smckusick int i; 125727058Smckusick 1258*27445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 125927058Smckusick if (i != TBLOCK*nblock) 126027058Smckusick mterr("write", i, 2); 12611119Sbill } 12621119Sbill 126327058Smckusick mterr(operation, i, exitcode) 126427058Smckusick char *operation; 126527058Smckusick int i; 126627058Smckusick { 126727058Smckusick fprintf(stderr, "tar: tape %s error: ", operation); 126827058Smckusick if (i < 0) 126927058Smckusick perror(""); 127027058Smckusick else 127127058Smckusick fprintf(stderr, "unexpected EOF\n"); 127227058Smckusick done(exitcode); 127327058Smckusick } 127427058Smckusick 12758737Smckusick bread(fd, buf, size) 12768737Smckusick int fd; 12778737Smckusick char *buf; 12788737Smckusick int size; 12798737Smckusick { 12808737Smckusick int count; 12818737Smckusick static int lastread = 0; 12828737Smckusick 128322688Slepreau if (!Bflag) 128422688Slepreau return (read(fd, buf, size)); 128522353Skjd 12868737Smckusick for (count = 0; count < size; count += lastread) { 128724281Smckusick lastread = read(fd, buf, size - count); 128824281Smckusick if (lastread <= 0) { 12898737Smckusick if (count > 0) 12908737Smckusick return (count); 12918737Smckusick return (lastread); 12928737Smckusick } 12938737Smckusick buf += lastread; 12948737Smckusick } 12958737Smckusick return (count); 12968737Smckusick } 129710165Ssam 129810165Ssam char * 129910165Ssam getcwd(buf) 130010165Ssam char *buf; 130110165Ssam { 130210165Ssam if (getwd(buf) == NULL) { 130310165Ssam fprintf(stderr, "tar: %s\n", buf); 130421457Skjd exit(1); 130510165Ssam } 130610165Ssam return (buf); 130710165Ssam } 130821910Skjd 130921910Skjd getbuf() 131021910Skjd { 131122353Skjd 131227058Smckusick if (nblock == 0) { 131321910Skjd fstat(mt, &stbuf); 131421910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 131527058Smckusick nblock = NBLOCK; 131621910Skjd else { 131727058Smckusick nblock = stbuf.st_blksize / TBLOCK; 131827058Smckusick if (nblock == 0) 131927058Smckusick nblock = NBLOCK; 132021910Skjd } 132121910Skjd } 1322*27445Slepreau tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 132321910Skjd if (tbuf == NULL) { 132421910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 132521910Skjd nblock); 132621910Skjd done(1); 132721910Skjd } 132821910Skjd } 132922353Skjd 133022688Slepreau /* 133127442Slepreau * Save this directory and its mtime on the stack, popping and setting 133227442Slepreau * the mtimes of any stacked dirs which aren't parents of this one. 133327442Slepreau * A null directory causes the entire stack to be unwound and set. 133422688Slepreau * 133527442Slepreau * Since all the elements of the directory "stack" share a common 133627442Slepreau * prefix, we can make do with one string. We keep only the current 133727442Slepreau * directory path, with an associated array of mtime's, one for each 133827442Slepreau * '/' in the path. A negative mtime means no mtime. The mtime's are 133927442Slepreau * offset by one (first index 1, not 0) because calling this with a null 134027442Slepreau * directory causes mtime[0] to be set. 134127442Slepreau * 134222688Slepreau * This stack algorithm is not guaranteed to work for tapes created 134322688Slepreau * with the 'r' option, but the vast majority of tapes with 134422688Slepreau * directories are not. This avoids saving every directory record on 134522688Slepreau * the tape and setting all the times at the end. 134622688Slepreau */ 134722688Slepreau char dirstack[NAMSIZ]; 134822688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 134922688Slepreau time_t mtime[NTIM]; 135022353Skjd 135122688Slepreau dodirtimes(hp) 135222688Slepreau union hblock *hp; 135322353Skjd { 135422688Slepreau register char *p = dirstack; 135522688Slepreau register char *q = hp->dbuf.name; 135622688Slepreau register int ndir = 0; 135722688Slepreau char *savp; 135822688Slepreau int savndir; 135922353Skjd 136022688Slepreau /* Find common prefix */ 136122688Slepreau while (*p == *q) { 136222688Slepreau if (*p++ == '/') 136322688Slepreau ++ndir; 136422688Slepreau q++; 136522688Slepreau } 136622353Skjd 136722688Slepreau savp = p; 136822688Slepreau savndir = ndir; 136922688Slepreau while (*p) { 137022688Slepreau /* 137122688Slepreau * Not a child: unwind the stack, setting the times. 137222688Slepreau * The order we do this doesn't matter, so we go "forward." 137322688Slepreau */ 137422688Slepreau if (*p++ == '/') 137522688Slepreau if (mtime[++ndir] >= 0) { 137622688Slepreau *--p = '\0'; /* zap the slash */ 137722688Slepreau setimes(dirstack, mtime[ndir]); 137822688Slepreau *p++ = '/'; 137922688Slepreau } 138022688Slepreau } 138122688Slepreau p = savp; 138222688Slepreau ndir = savndir; 138322353Skjd 138422688Slepreau /* Push this one on the "stack" */ 138522688Slepreau while (*p = *q++) /* append the rest of the new dir */ 138622688Slepreau if (*p++ == '/') 138722688Slepreau mtime[++ndir] = -1; 138822688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 138922688Slepreau } 139022353Skjd 139122688Slepreau setimes(path, mt) 139222688Slepreau char *path; 139322688Slepreau time_t mt; 139422688Slepreau { 139522688Slepreau struct timeval tv[2]; 139622353Skjd 139722688Slepreau tv[0].tv_sec = time((time_t *) 0); 139822688Slepreau tv[1].tv_sec = mt; 139922688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 140027058Smckusick if (utimes(path, tv) < 0) { 140127058Smckusick fprintf(stderr, "tar: can't set time on %s: ", path); 140227058Smckusick perror(""); 140327058Smckusick } 140422688Slepreau } 140522688Slepreau 140622688Slepreau char * 140722688Slepreau getmem(size) 140822688Slepreau { 140922688Slepreau char *p = malloc((unsigned) size); 141022688Slepreau 141122688Slepreau if (p == NULL && freemem) { 141222688Slepreau fprintf(stderr, 141322688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 141422688Slepreau freemem = 0; 141522353Skjd } 141622688Slepreau return (p); 141722353Skjd } 1418