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"; 11*33082Sbostic #endif /* not lint */ 126250Sroot 1322502Sdist #ifndef lint 14*33082Sbostic static char sccsid[] = "@(#)tar.c 5.11 (Berkeley) 12/21/87"; 15*33082Sbostic #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(); 10727445Slepreau long time(); 10827445Slepreau off_t lseek(); 10927445Slepreau char *mktemp(); 1106250Sroot char *strcat(); 11127058Smckusick char *strcpy(); 11212154Ssam char *rindex(); 11310165Ssam char *getcwd(); 1149844Ssam char *getwd(); 11522688Slepreau char *getmem(); 1161119Sbill 1171119Sbill main(argc, argv) 1181119Sbill int argc; 1191119Sbill char *argv[]; 1201119Sbill { 1211119Sbill char *cp; 1221119Sbill 1231119Sbill if (argc < 2) 1241119Sbill usage(); 1251119Sbill 1261119Sbill tfile = NULL; 1271119Sbill usefile = magtape; 1281119Sbill argv[argc] = 0; 1291119Sbill argv++; 1301119Sbill for (cp = *argv++; *cp; cp++) 1311119Sbill switch(*cp) { 1326250Sroot 1331119Sbill case 'f': 13412154Ssam if (*argv == 0) { 13512154Ssam fprintf(stderr, 13612154Ssam "tar: tapefile must be specified with 'f' option\n"); 13712154Ssam usage(); 13812154Ssam } 1391119Sbill usefile = *argv++; 1401119Sbill fflag++; 1411119Sbill break; 1426250Sroot 1431119Sbill case 'c': 1441119Sbill cflag++; 1451119Sbill rflag++; 1461119Sbill break; 1476250Sroot 1481119Sbill case 'o': 1491119Sbill oflag++; 1501119Sbill break; 1516250Sroot 1521119Sbill case 'p': 1531119Sbill pflag++; 1541119Sbill break; 1556250Sroot 1561119Sbill case 'u': 1571119Sbill mktemp(tname); 1581119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1596250Sroot fprintf(stderr, 16022688Slepreau "tar: cannot create temporary file (%s)\n", 1616250Sroot tname); 1621119Sbill done(1); 1631119Sbill } 1641119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1656250Sroot /*FALL THRU*/ 1666250Sroot 1671119Sbill case 'r': 1681119Sbill rflag++; 1691119Sbill break; 1706250Sroot 1711119Sbill case 'v': 1721119Sbill vflag++; 1731119Sbill break; 1746250Sroot 1751119Sbill case 'w': 1761119Sbill wflag++; 1771119Sbill break; 1786250Sroot 1791119Sbill case 'x': 1801119Sbill xflag++; 1811119Sbill break; 1826250Sroot 1831119Sbill case 't': 1841119Sbill tflag++; 1851119Sbill break; 1866250Sroot 1871119Sbill case 'm': 1881119Sbill mflag++; 1891119Sbill break; 1906250Sroot 1911119Sbill case '-': 1921119Sbill break; 1936250Sroot 1941119Sbill case '0': 1951119Sbill case '1': 1961119Sbill case '4': 1971119Sbill case '5': 19821457Skjd case '7': 1991119Sbill case '8': 2001119Sbill magtape[8] = *cp; 2011119Sbill usefile = magtape; 2021119Sbill break; 2036250Sroot 2041119Sbill case 'b': 20513492Ssam if (*argv == 0) { 20613492Ssam fprintf(stderr, 20713492Ssam "tar: blocksize must be specified with 'b' option\n"); 20813492Ssam usage(); 20913492Ssam } 21013492Ssam nblock = atoi(*argv); 21113492Ssam if (nblock <= 0) { 21213492Ssam fprintf(stderr, 21313492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2141119Sbill done(1); 2151119Sbill } 21613492Ssam argv++; 2171119Sbill break; 2186250Sroot 2191119Sbill case 'l': 22022688Slepreau prtlinkerr++; 2211119Sbill break; 2226250Sroot 2236250Sroot case 'h': 2246250Sroot hflag++; 2256250Sroot break; 2266250Sroot 22712154Ssam case 'i': 22812154Ssam iflag++; 22912154Ssam break; 23012154Ssam 2318737Smckusick case 'B': 2328737Smckusick Bflag++; 2338737Smckusick break; 2348737Smckusick 23512154Ssam case 'F': 23612154Ssam Fflag++; 23712154Ssam break; 23812154Ssam 2391119Sbill default: 2401119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2411119Sbill usage(); 2421119Sbill } 2431119Sbill 2446250Sroot if (!rflag && !xflag && !tflag) 2456250Sroot usage(); 2461119Sbill if (rflag) { 2476250Sroot if (cflag && tfile != NULL) 2481119Sbill usage(); 2491119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 25027445Slepreau (void) signal(SIGINT, onintr); 2511119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 25227445Slepreau (void) signal(SIGHUP, onhup); 2531119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 25427445Slepreau (void) signal(SIGQUIT, onquit); 2556250Sroot #ifdef notdef 2561119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 25727445Slepreau (void) signal(SIGTERM, onterm); 2586250Sroot #endif 25927058Smckusick mt = openmt(usefile, 1); 2601119Sbill dorep(argv); 2616250Sroot done(0); 2621119Sbill } 26327058Smckusick mt = openmt(usefile, 0); 2646250Sroot if (xflag) 2651119Sbill doxtract(argv); 2666250Sroot else 26727445Slepreau dotable(argv); 2681119Sbill done(0); 2691119Sbill } 2701119Sbill 2711119Sbill usage() 2721119Sbill { 2736250Sroot fprintf(stderr, 27421457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2751119Sbill done(1); 2761119Sbill } 2771119Sbill 27827058Smckusick int 27927058Smckusick openmt(tape, writing) 28027058Smckusick char *tape; 28127058Smckusick int writing; 28227058Smckusick { 28327058Smckusick 28427058Smckusick if (strcmp(tape, "-") == 0) { 28527058Smckusick /* 28627058Smckusick * Read from standard input or write to standard output. 28727058Smckusick */ 28827058Smckusick if (writing) { 28927058Smckusick if (cflag == 0) { 29027058Smckusick fprintf(stderr, 29127058Smckusick "tar: can only create standard output archives\n"); 29227058Smckusick done(1); 29327058Smckusick } 29427058Smckusick vfile = stderr; 29527058Smckusick setlinebuf(vfile); 29627058Smckusick mt = dup(1); 29727058Smckusick } else { 29827058Smckusick mt = dup(0); 29927058Smckusick Bflag++; 30027058Smckusick } 30127058Smckusick } else { 30227058Smckusick /* 30327058Smckusick * Use file or tape on local machine. 30427058Smckusick */ 30527058Smckusick if (writing) { 30627058Smckusick if (cflag) 30727445Slepreau mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); 30827058Smckusick else 30927058Smckusick mt = open(tape, O_RDWR); 31027058Smckusick } else 31127058Smckusick mt = open(tape, O_RDONLY); 31227058Smckusick if (mt < 0) { 31327058Smckusick fprintf(stderr, "tar: "); 31427058Smckusick perror(tape); 31527058Smckusick done(1); 31627058Smckusick } 31727058Smckusick } 31827058Smckusick return(mt); 31927058Smckusick } 32027058Smckusick 3211119Sbill dorep(argv) 3226250Sroot char *argv[]; 3231119Sbill { 3241119Sbill register char *cp, *cp2; 3259601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 3261119Sbill 3271119Sbill if (!cflag) { 3281119Sbill getdir(); 3291119Sbill do { 3301119Sbill passtape(); 3311119Sbill if (term) 3321119Sbill done(0); 3331119Sbill getdir(); 3341119Sbill } while (!endtape()); 33513492Ssam backtape(); 3361119Sbill if (tfile != NULL) { 3371119Sbill char buf[200]; 3381119Sbill 33932420Sbostic (void)sprintf(buf, 3406250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3411119Sbill tname, tname, tname, tname, tname, tname); 3421119Sbill fflush(tfile); 3431119Sbill system(buf); 3441119Sbill freopen(tname, "r", tfile); 3451119Sbill fstat(fileno(tfile), &stbuf); 3461119Sbill high = stbuf.st_size; 3471119Sbill } 3481119Sbill } 3491119Sbill 35010165Ssam (void) getcwd(wdir); 3511119Sbill while (*argv && ! term) { 3521119Sbill cp2 = *argv; 3531119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3541119Sbill argv++; 35527058Smckusick if (chdir(*argv) < 0) { 35627058Smckusick fprintf(stderr, "tar: can't change directories to "); 3571119Sbill perror(*argv); 35827058Smckusick } else 35910165Ssam (void) getcwd(wdir); 3601119Sbill argv++; 3611119Sbill continue; 3621119Sbill } 3639601Ssam parent = wdir; 3641119Sbill for (cp = *argv; *cp; cp++) 3651119Sbill if (*cp == '/') 3661119Sbill cp2 = cp; 3671119Sbill if (cp2 != *argv) { 3681119Sbill *cp2 = '\0'; 3699601Ssam if (chdir(*argv) < 0) { 37027058Smckusick fprintf(stderr, "tar: can't change directories to "); 3719601Ssam perror(*argv); 3729601Ssam continue; 3739601Ssam } 37410165Ssam parent = getcwd(tempdir); 3751119Sbill *cp2 = '/'; 3761119Sbill cp2++; 3771119Sbill } 3789601Ssam putfile(*argv++, cp2, parent); 37915045Smckusick if (chdir(wdir) < 0) { 38022688Slepreau fprintf(stderr, "tar: cannot change back?: "); 38115045Smckusick perror(wdir); 38215045Smckusick } 3831119Sbill } 3841119Sbill putempty(); 3851119Sbill putempty(); 3861119Sbill flushtape(); 38722688Slepreau if (prtlinkerr == 0) 3886250Sroot return; 3896250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3906250Sroot if (ihead->count == 0) 3916250Sroot continue; 39213492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3936250Sroot } 3941119Sbill } 3951119Sbill 3961119Sbill endtape() 3971119Sbill { 39821457Skjd return (dblock.dbuf.name[0] == '\0'); 3991119Sbill } 4001119Sbill 4011119Sbill getdir() 4021119Sbill { 4031119Sbill register struct stat *sp; 4041119Sbill int i; 4051119Sbill 40612154Ssam top: 4076250Sroot readtape((char *)&dblock); 4081119Sbill if (dblock.dbuf.name[0] == '\0') 4091119Sbill return; 4101119Sbill sp = &stbuf; 4111119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4121119Sbill sp->st_mode = i; 4131119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4141119Sbill sp->st_uid = i; 4151119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4161119Sbill sp->st_gid = i; 4171119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4181119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4191119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 42012154Ssam if (chksum != (i = checksum())) { 42113492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 42212154Ssam chksum, i); 42312154Ssam if (iflag) 42412154Ssam goto top; 4251119Sbill done(2); 4261119Sbill } 4271119Sbill if (tfile != NULL) 4281119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4291119Sbill } 4301119Sbill 4311119Sbill passtape() 4321119Sbill { 4331119Sbill long blocks; 43421457Skjd char *bufp; 4351119Sbill 4361119Sbill if (dblock.dbuf.linkflag == '1') 4371119Sbill return; 4381119Sbill blocks = stbuf.st_size; 4391119Sbill blocks += TBLOCK-1; 4401119Sbill blocks /= TBLOCK; 4411119Sbill 44221457Skjd while (blocks-- > 0) 44327445Slepreau (void) readtbuf(&bufp, TBLOCK); 4441119Sbill } 4451119Sbill 4469601Ssam putfile(longname, shortname, parent) 4476250Sroot char *longname; 4486250Sroot char *shortname; 4499601Ssam char *parent; 4501119Sbill { 45121457Skjd int infile = 0; 45221457Skjd long blocks; 4531119Sbill char buf[TBLOCK]; 45421457Skjd char *bigbuf; 45522688Slepreau register char *cp; 4565931Smckusic struct direct *dp; 4575931Smckusic DIR *dirp; 45827445Slepreau register int i; 45927445Slepreau long l; 4609601Ssam char newparent[NAMSIZ+64]; 46121457Skjd int maxread; 46221457Skjd int hint; /* amount to write to get "in sync" */ 4631119Sbill 4649601Ssam if (!hflag) 46512154Ssam i = lstat(shortname, &stbuf); 46612154Ssam else 46712154Ssam i = stat(shortname, &stbuf); 46812154Ssam if (i < 0) { 46927058Smckusick fprintf(stderr, "tar: "); 47027058Smckusick perror(longname); 4719601Ssam return; 4729601Ssam } 47312154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4741119Sbill return; 47512154Ssam if (checkw('r', longname) == 0) 4761119Sbill return; 47712154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 47812154Ssam return; 4791119Sbill 48012154Ssam switch (stbuf.st_mode & S_IFMT) { 48112154Ssam case S_IFDIR: 4826250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4836250Sroot ; 4841119Sbill *--cp = '/'; 4851119Sbill *++cp = 0 ; 4861119Sbill if (!oflag) { 4876250Sroot if ((cp - buf) >= NAMSIZ) { 48813492Ssam fprintf(stderr, "tar: %s: file name too long\n", 48913492Ssam longname); 4906250Sroot return; 4916250Sroot } 4926250Sroot stbuf.st_size = 0; 4936250Sroot tomodes(&stbuf); 4946250Sroot strcpy(dblock.dbuf.name,buf); 49532420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 49627445Slepreau (void) writetape((char *)&dblock); 4971119Sbill } 49832420Sbostic (void)sprintf(newparent, "%s/%s", parent, shortname); 49915045Smckusick if (chdir(shortname) < 0) { 50015045Smckusick perror(shortname); 50115045Smckusick return; 50215045Smckusick } 5035931Smckusic if ((dirp = opendir(".")) == NULL) { 50413492Ssam fprintf(stderr, "tar: %s: directory read error\n", 50513492Ssam longname); 50615045Smckusick if (chdir(parent) < 0) { 50722688Slepreau fprintf(stderr, "tar: cannot change back?: "); 50815045Smckusick perror(parent); 50915045Smckusick } 5105931Smckusic return; 5115931Smckusic } 5125931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5136250Sroot if (!strcmp(".", dp->d_name) || 5146250Sroot !strcmp("..", dp->d_name)) 5151119Sbill continue; 5165931Smckusic strcpy(cp, dp->d_name); 51727445Slepreau l = telldir(dirp); 5185931Smckusic closedir(dirp); 5199601Ssam putfile(buf, cp, newparent); 5205931Smckusic dirp = opendir("."); 52127445Slepreau seekdir(dirp, l); 5221119Sbill } 5235931Smckusic closedir(dirp); 52415045Smckusick if (chdir(parent) < 0) { 52522688Slepreau fprintf(stderr, "tar: cannot change back?: "); 52615045Smckusick perror(parent); 52715045Smckusick } 52812154Ssam break; 52912154Ssam 53012154Ssam case S_IFLNK: 53112154Ssam tomodes(&stbuf); 53212154Ssam if (strlen(longname) >= NAMSIZ) { 53313492Ssam fprintf(stderr, "tar: %s: file name too long\n", 53413492Ssam longname); 53512154Ssam return; 53612154Ssam } 53712154Ssam strcpy(dblock.dbuf.name, longname); 5386250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 53913492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 54013492Ssam longname); 5416250Sroot return; 5426250Sroot } 5439601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5446250Sroot if (i < 0) { 54527058Smckusick fprintf(stderr, "tar: can't read symbolic link "); 5469601Ssam perror(longname); 5476250Sroot return; 5486250Sroot } 5496250Sroot dblock.dbuf.linkname[i] = '\0'; 5506250Sroot dblock.dbuf.linkflag = '2'; 55122688Slepreau if (vflag) 55222688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 55322688Slepreau longname, dblock.dbuf.linkname); 55432420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo", 0L); 55532420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 55627445Slepreau (void) writetape((char *)&dblock); 55712154Ssam break; 5581119Sbill 55912154Ssam case S_IFREG: 56012154Ssam if ((infile = open(shortname, 0)) < 0) { 56127058Smckusick fprintf(stderr, "tar: "); 56227058Smckusick perror(longname); 5631119Sbill return; 5641119Sbill } 56512154Ssam tomodes(&stbuf); 56612154Ssam if (strlen(longname) >= NAMSIZ) { 56713492Ssam fprintf(stderr, "tar: %s: file name too long\n", 56813492Ssam longname); 56921457Skjd close(infile); 57012154Ssam return; 57112154Ssam } 57212154Ssam strcpy(dblock.dbuf.name, longname); 57312154Ssam if (stbuf.st_nlink > 1) { 57412154Ssam struct linkbuf *lp; 57512154Ssam int found = 0; 57612154Ssam 57712154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 57812154Ssam if (lp->inum == stbuf.st_ino && 57912154Ssam lp->devnum == stbuf.st_dev) { 58012154Ssam found++; 58112154Ssam break; 58212154Ssam } 58312154Ssam if (found) { 58412154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 58512154Ssam dblock.dbuf.linkflag = '1'; 58632420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 58727445Slepreau (void) writetape( (char *) &dblock); 58822688Slepreau if (vflag) 58922688Slepreau fprintf(vfile, "a %s link to %s\n", 59022688Slepreau longname, lp->pathname); 59112154Ssam lp->count--; 59212154Ssam close(infile); 59312154Ssam return; 5941119Sbill } 59522688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 59622688Slepreau if (lp != NULL) { 59712154Ssam lp->nextp = ihead; 59812154Ssam ihead = lp; 59912154Ssam lp->inum = stbuf.st_ino; 60012154Ssam lp->devnum = stbuf.st_dev; 60112154Ssam lp->count = stbuf.st_nlink - 1; 60212154Ssam strcpy(lp->pathname, longname); 60312154Ssam } 6041119Sbill } 60521457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 60622688Slepreau if (vflag) 60722688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 60832420Sbostic (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 60921457Skjd hint = writetape((char *)&dblock); 61021457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 61127445Slepreau if ((bigbuf = malloc((unsigned)maxread)) == 0) { 61221457Skjd maxread = TBLOCK; 61321457Skjd bigbuf = buf; 61421457Skjd } 6151119Sbill 61621457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 61721457Skjd && blocks > 0) { 61821457Skjd register int nblks; 61921457Skjd 62021457Skjd nblks = ((i-1)/TBLOCK)+1; 62121457Skjd if (nblks > blocks) 62221457Skjd nblks = blocks; 62321457Skjd hint = writetbuf(bigbuf, nblks); 62421457Skjd blocks -= nblks; 62521457Skjd } 62621457Skjd close(infile); 62721457Skjd if (bigbuf != buf) 62821457Skjd free(bigbuf); 62927058Smckusick if (i < 0) { 63027445Slepreau fprintf(stderr, "tar: Read error on "); 63127058Smckusick perror(longname); 63227058Smckusick } else if (blocks != 0 || i != 0) 63313492Ssam fprintf(stderr, "tar: %s: file changed size\n", 63413492Ssam longname); 63512154Ssam while (--blocks >= 0) 63612154Ssam putempty(); 63712154Ssam break; 63812154Ssam 63912154Ssam default: 64012154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 64113492Ssam longname); 64212154Ssam break; 6431119Sbill } 6441119Sbill } 6451119Sbill 6461119Sbill doxtract(argv) 6476250Sroot char *argv[]; 6481119Sbill { 649*33082Sbostic extern int errno; 6501119Sbill long blocks, bytes; 65127445Slepreau int ofile, i; 6521119Sbill 6531119Sbill for (;;) { 65427445Slepreau if ((i = wantit(argv)) == 0) 65527445Slepreau continue; 65627445Slepreau if (i == -1) 65727445Slepreau break; /* end of tape */ 6581119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6591119Sbill passtape(); 6601119Sbill continue; 6611119Sbill } 66212154Ssam if (Fflag) { 66312154Ssam char *s; 66412154Ssam 66512154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 66612154Ssam s = dblock.dbuf.name; 66712154Ssam else 66812154Ssam s++; 66912154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 67012154Ssam passtape(); 67112154Ssam continue; 67212154Ssam } 67312154Ssam } 67422688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 67522688Slepreau if (mflag == 0) 67622688Slepreau dodirtimes(&dblock); 6776250Sroot continue; 67822688Slepreau } 67922688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 68025250Sbloom /* 68125250Sbloom * only unlink non directories or empty 68225250Sbloom * directories 68325250Sbloom */ 68425250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 68525250Sbloom if (errno == ENOTDIR) 68625250Sbloom unlink(dblock.dbuf.name); 68725250Sbloom } 6886250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 68927058Smckusick fprintf(stderr, "tar: %s: symbolic link failed: ", 69013492Ssam dblock.dbuf.name); 69127058Smckusick perror(""); 6926250Sroot continue; 6936250Sroot } 6946250Sroot if (vflag) 69521910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 69613492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 69722353Skjd #ifdef notdef 69822353Skjd /* ignore alien orders */ 69922353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 70022688Slepreau if (mflag == 0) 70122688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 70222353Skjd if (pflag) 70322353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 70422353Skjd #endif 7051119Sbill continue; 7066250Sroot } 70722688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 70825250Sbloom /* 70925250Sbloom * only unlink non directories or empty 71025250Sbloom * directories 71125250Sbloom */ 71225250Sbloom if (rmdir(dblock.dbuf.name) < 0) { 71325250Sbloom if (errno == ENOTDIR) 71425250Sbloom unlink(dblock.dbuf.name); 71525250Sbloom } 7161119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 71727058Smckusick fprintf(stderr, "tar: can't link %s to %s: ", 71827058Smckusick dblock.dbuf.name, dblock.dbuf.linkname); 71927058Smckusick perror(""); 7201119Sbill continue; 7211119Sbill } 7221119Sbill if (vflag) 72322688Slepreau fprintf(vfile, "%s linked to %s\n", 72413492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7251119Sbill continue; 7261119Sbill } 7276250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 72827058Smckusick fprintf(stderr, "tar: can't create %s: ", 72913492Ssam dblock.dbuf.name); 73027058Smckusick perror(""); 7311119Sbill passtape(); 7321119Sbill continue; 7331119Sbill } 73421457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7351119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7361119Sbill if (vflag) 73722688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 73813492Ssam dblock.dbuf.name, bytes, blocks); 73921457Skjd for (; blocks > 0;) { 74021457Skjd register int nread; 74121457Skjd char *bufp; 74221457Skjd register int nwant; 74321457Skjd 74421457Skjd nwant = NBLOCK*TBLOCK; 74521457Skjd if (nwant > (blocks*TBLOCK)) 74621457Skjd nwant = (blocks*TBLOCK); 74721457Skjd nread = readtbuf(&bufp, nwant); 74822688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7496250Sroot fprintf(stderr, 75030090Sbostic "tar: %s: HELP - extract write error: ", 75113492Ssam dblock.dbuf.name); 75227058Smckusick perror(""); 7536250Sroot done(2); 7546250Sroot } 75521457Skjd bytes -= nread; 75621457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7571119Sbill } 7581119Sbill close(ofile); 75922688Slepreau if (mflag == 0) 76022688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7611926Swnj if (pflag) 7626250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7631119Sbill } 76422688Slepreau if (mflag == 0) { 76522688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 76622688Slepreau dodirtimes(&dblock); 76722688Slepreau } 7681119Sbill } 7691119Sbill 77027445Slepreau dotable(argv) 77127445Slepreau char *argv[]; 7721119Sbill { 77327445Slepreau register int i; 77427445Slepreau 7751119Sbill for (;;) { 77627445Slepreau if ((i = wantit(argv)) == 0) 77727445Slepreau continue; 77827445Slepreau if (i == -1) 77927445Slepreau break; /* end of tape */ 7801119Sbill if (vflag) 7811119Sbill longt(&stbuf); 7821119Sbill printf("%s", dblock.dbuf.name); 7831119Sbill if (dblock.dbuf.linkflag == '1') 7841119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7856250Sroot if (dblock.dbuf.linkflag == '2') 7866250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7871119Sbill printf("\n"); 7881119Sbill passtape(); 7891119Sbill } 7901119Sbill } 7911119Sbill 7921119Sbill putempty() 7931119Sbill { 7941119Sbill char buf[TBLOCK]; 7951119Sbill 79613492Ssam bzero(buf, sizeof (buf)); 79727445Slepreau (void) writetape(buf); 7981119Sbill } 7991119Sbill 8001119Sbill longt(st) 8016250Sroot register struct stat *st; 8021119Sbill { 8031119Sbill register char *cp; 8041119Sbill char *ctime(); 8051119Sbill 8061119Sbill pmode(st); 8071119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 80827445Slepreau printf("%7ld", st->st_size); 8091119Sbill cp = ctime(&st->st_mtime); 8101119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8111119Sbill } 8121119Sbill 8131119Sbill #define SUID 04000 8141119Sbill #define SGID 02000 8151119Sbill #define ROWN 0400 8161119Sbill #define WOWN 0200 8171119Sbill #define XOWN 0100 8181119Sbill #define RGRP 040 8191119Sbill #define WGRP 020 8201119Sbill #define XGRP 010 8211119Sbill #define ROTH 04 8221119Sbill #define WOTH 02 8231119Sbill #define XOTH 01 8241119Sbill #define STXT 01000 8251119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8261119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8271119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8281119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8291119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8301119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8311119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8321119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8331119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8341119Sbill 8351119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8361119Sbill 8371119Sbill pmode(st) 8386250Sroot register struct stat *st; 8391119Sbill { 8401119Sbill register int **mp; 8411119Sbill 8421119Sbill for (mp = &m[0]; mp < &m[9];) 84327058Smckusick selectbits(*mp++, st); 8441119Sbill } 8451119Sbill 84627058Smckusick selectbits(pairp, st) 8476250Sroot int *pairp; 8486250Sroot struct stat *st; 8491119Sbill { 8501119Sbill register int n, *ap; 8511119Sbill 8521119Sbill ap = pairp; 8531119Sbill n = *ap++; 8541119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8551119Sbill ap++; 85627445Slepreau putchar(*ap); 8571119Sbill } 8581119Sbill 85922688Slepreau /* 86027442Slepreau * Make all directories needed by `name'. If `name' is itself 86127442Slepreau * a directory on the tar tape (indicated by a trailing '/'), 86222688Slepreau * return 1; else 0. 86322688Slepreau */ 8641119Sbill checkdir(name) 8656250Sroot register char *name; 8661119Sbill { 8671119Sbill register char *cp; 8686250Sroot 86912154Ssam /* 87022688Slepreau * Quick check for existence of directory. 87112154Ssam */ 87212154Ssam if ((cp = rindex(name, '/')) == 0) 87312154Ssam return (0); 87412154Ssam *cp = '\0'; 87522688Slepreau if (access(name, 0) == 0) { /* already exists */ 87612154Ssam *cp = '/'; 87722688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 87812154Ssam } 87912154Ssam *cp = '/'; 88012154Ssam 88112154Ssam /* 88212154Ssam * No luck, try to make all directories in path. 88312154Ssam */ 8841119Sbill for (cp = name; *cp; cp++) { 8856250Sroot if (*cp != '/') 8866250Sroot continue; 8876250Sroot *cp = '\0'; 88812154Ssam if (access(name, 0) < 0) { 8899844Ssam if (mkdir(name, 0777) < 0) { 8909844Ssam perror(name); 89112154Ssam *cp = '/'; 89212154Ssam return (0); 8931119Sbill } 89421457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 89527442Slepreau if (pflag && cp[1] == '\0') /* dir on the tape */ 89627442Slepreau chmod(name, stbuf.st_mode & 07777); 8971119Sbill } 8986250Sroot *cp = '/'; 8991119Sbill } 9006250Sroot return (cp[-1]=='/'); 9011119Sbill } 9021119Sbill 9031119Sbill onintr() 9041119Sbill { 90527445Slepreau (void) signal(SIGINT, SIG_IGN); 9061119Sbill term++; 9071119Sbill } 9081119Sbill 9091119Sbill onquit() 9101119Sbill { 91127445Slepreau (void) signal(SIGQUIT, SIG_IGN); 9121119Sbill term++; 9131119Sbill } 9141119Sbill 9151119Sbill onhup() 9161119Sbill { 91727445Slepreau (void) signal(SIGHUP, SIG_IGN); 9181119Sbill term++; 9191119Sbill } 9201119Sbill 92122688Slepreau #ifdef notdef 9221119Sbill onterm() 9231119Sbill { 92427445Slepreau (void) signal(SIGTERM, SIG_IGN); 9251119Sbill term++; 9261119Sbill } 92722688Slepreau #endif 9281119Sbill 9291119Sbill tomodes(sp) 9301119Sbill register struct stat *sp; 9311119Sbill { 9321119Sbill register char *cp; 9331119Sbill 9341119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9351119Sbill *cp = '\0'; 93632420Sbostic (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 93732420Sbostic (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 93832420Sbostic (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 93932420Sbostic (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 94032420Sbostic (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9411119Sbill } 9421119Sbill 9431119Sbill checksum() 9441119Sbill { 9451119Sbill register i; 9461119Sbill register char *cp; 9471119Sbill 9486250Sroot for (cp = dblock.dbuf.chksum; 9496250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9501119Sbill *cp = ' '; 9511119Sbill i = 0; 9521119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9531119Sbill i += *cp; 9546250Sroot return (i); 9551119Sbill } 9561119Sbill 9571119Sbill checkw(c, name) 9586250Sroot char *name; 9591119Sbill { 9606250Sroot if (!wflag) 9616250Sroot return (1); 9626250Sroot printf("%c ", c); 9636250Sroot if (vflag) 9646250Sroot longt(&stbuf); 9656250Sroot printf("%s: ", name); 9666250Sroot return (response() == 'y'); 9671119Sbill } 9681119Sbill 9691119Sbill response() 9701119Sbill { 9711119Sbill char c; 9721119Sbill 9731119Sbill c = getchar(); 9741119Sbill if (c != '\n') 9756250Sroot while (getchar() != '\n') 9766250Sroot ; 9776250Sroot else 9786250Sroot c = 'n'; 9796250Sroot return (c); 9801119Sbill } 9811119Sbill 98212154Ssam checkf(name, mode, howmuch) 98312154Ssam char *name; 98412154Ssam int mode, howmuch; 98512154Ssam { 98612154Ssam int l; 98712154Ssam 98821910Skjd if ((mode & S_IFMT) == S_IFDIR){ 98921910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 99021910Skjd return(0); 99121910Skjd return(1); 99221910Skjd } 99312154Ssam if ((l = strlen(name)) < 3) 99412154Ssam return (1); 99512154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 99612154Ssam return (0); 99712154Ssam if (strcmp(name, "core") == 0 || 99812154Ssam strcmp(name, "errs") == 0 || 99912154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 100012154Ssam return (0); 100112154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 100212154Ssam return (1); 100312154Ssam } 100412154Ssam 100522688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 10061119Sbill checkupdate(arg) 10076250Sroot char *arg; 10081119Sbill { 10091119Sbill char name[100]; 10106250Sroot long mtime; 10111119Sbill daddr_t seekp; 10121119Sbill daddr_t lookup(); 10131119Sbill 10141119Sbill rewind(tfile); 10151119Sbill for (;;) { 10161119Sbill if ((seekp = lookup(arg)) < 0) 10176250Sroot return (1); 10181119Sbill fseek(tfile, seekp, 0); 10191119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10206250Sroot return (stbuf.st_mtime > mtime); 10211119Sbill } 10221119Sbill } 10231119Sbill 10241119Sbill done(n) 10251119Sbill { 102621457Skjd unlink(tname); 10271119Sbill exit(n); 10281119Sbill } 10291119Sbill 103027445Slepreau /* 103127445Slepreau * Do we want the next entry on the tape, i.e. is it selected? If 103227445Slepreau * not, skip over the entire entry. Return -1 if reached end of tape. 103327445Slepreau */ 103427445Slepreau wantit(argv) 103527445Slepreau char *argv[]; 103627445Slepreau { 103727445Slepreau register char **cp; 103827445Slepreau 103927445Slepreau getdir(); 104027445Slepreau if (endtape()) 104127445Slepreau return (-1); 104227445Slepreau if (*argv == 0) 104327445Slepreau return (1); 104427445Slepreau for (cp = argv; *cp; cp++) 104527445Slepreau if (prefix(*cp, dblock.dbuf.name)) 104627445Slepreau return (1); 104727445Slepreau passtape(); 104827445Slepreau return (0); 104927445Slepreau } 105027445Slepreau 105122688Slepreau /* 105222688Slepreau * Does s2 begin with the string s1, on a directory boundary? 105322688Slepreau */ 10541119Sbill prefix(s1, s2) 10556250Sroot register char *s1, *s2; 10561119Sbill { 10571119Sbill while (*s1) 10581119Sbill if (*s1++ != *s2++) 10596250Sroot return (0); 10601119Sbill if (*s2) 10616250Sroot return (*s2 == '/'); 10626250Sroot return (1); 10631119Sbill } 10641119Sbill 10651119Sbill #define N 200 10661119Sbill int njab; 10676250Sroot 10681119Sbill daddr_t 10691119Sbill lookup(s) 10706250Sroot char *s; 10711119Sbill { 10721119Sbill register i; 10731119Sbill daddr_t a; 10741119Sbill 10751119Sbill for(i=0; s[i]; i++) 10766250Sroot if (s[i] == ' ') 10771119Sbill break; 10781119Sbill a = bsrch(s, i, low, high); 10796250Sroot return (a); 10801119Sbill } 10811119Sbill 10821119Sbill daddr_t 10831119Sbill bsrch(s, n, l, h) 10846250Sroot daddr_t l, h; 10856250Sroot char *s; 10861119Sbill { 10871119Sbill register i, j; 10881119Sbill char b[N]; 10891119Sbill daddr_t m, m1; 10901119Sbill 10911119Sbill njab = 0; 10921119Sbill 10931119Sbill loop: 10946250Sroot if (l >= h) 109522688Slepreau return ((daddr_t) -1); 10961119Sbill m = l + (h-l)/2 - N/2; 10976250Sroot if (m < l) 10981119Sbill m = l; 10991119Sbill fseek(tfile, m, 0); 11001119Sbill fread(b, 1, N, tfile); 11011119Sbill njab++; 11021119Sbill for(i=0; i<N; i++) { 11036250Sroot if (b[i] == '\n') 11041119Sbill break; 11051119Sbill m++; 11061119Sbill } 11076250Sroot if (m >= h) 110822688Slepreau return ((daddr_t) -1); 11091119Sbill m1 = m; 11101119Sbill j = i; 11111119Sbill for(i++; i<N; i++) { 11121119Sbill m1++; 11136250Sroot if (b[i] == '\n') 11141119Sbill break; 11151119Sbill } 11161119Sbill i = cmp(b+j, s, n); 11176250Sroot if (i < 0) { 11181119Sbill h = m; 11191119Sbill goto loop; 11201119Sbill } 11216250Sroot if (i > 0) { 11221119Sbill l = m1; 11231119Sbill goto loop; 11241119Sbill } 11256250Sroot return (m); 11261119Sbill } 11271119Sbill 11281119Sbill cmp(b, s, n) 11296250Sroot char *b, *s; 11301119Sbill { 11311119Sbill register i; 11321119Sbill 11336250Sroot if (b[0] != '\n') 113421457Skjd exit(2); 11351119Sbill for(i=0; i<n; i++) { 11366250Sroot if (b[i+1] > s[i]) 11376250Sroot return (-1); 11386250Sroot if (b[i+1] < s[i]) 11396250Sroot return (1); 11401119Sbill } 11416250Sroot return (b[i+1] == ' '? 0 : -1); 11421119Sbill } 11431119Sbill 114422688Slepreau readtape(buffer) 11456250Sroot char *buffer; 11461119Sbill { 114721457Skjd char *bufp; 114821457Skjd 114922688Slepreau if (first == 0) 115022688Slepreau getbuf(); 115127445Slepreau (void) readtbuf(&bufp, TBLOCK); 115221457Skjd bcopy(bufp, buffer, TBLOCK); 115321457Skjd return(TBLOCK); 115421457Skjd } 115521457Skjd 115621457Skjd readtbuf(bufpp, size) 115721457Skjd char **bufpp; 115821457Skjd int size; 115921457Skjd { 11603457Swnj register int i; 11611119Sbill 11621119Sbill if (recno >= nblock || first == 0) { 116327445Slepreau if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 116427058Smckusick mterr("read", i, 3); 11651119Sbill if (first == 0) { 11661119Sbill if ((i % TBLOCK) != 0) { 116713492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11681119Sbill done(3); 11691119Sbill } 11701119Sbill i /= TBLOCK; 11713457Swnj if (i != nblock) { 117213492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11731119Sbill nblock = i; 11741119Sbill } 117522353Skjd first = 1; 11761119Sbill } 11771119Sbill recno = 0; 11781119Sbill } 117921457Skjd if (size > ((nblock-recno)*TBLOCK)) 118021457Skjd size = (nblock-recno)*TBLOCK; 118121457Skjd *bufpp = (char *)&tbuf[recno]; 118221457Skjd recno += (size/TBLOCK); 118321457Skjd return (size); 11841119Sbill } 11851119Sbill 118621457Skjd writetbuf(buffer, n) 118721457Skjd register char *buffer; 118821457Skjd register int n; 11891119Sbill { 119027058Smckusick int i; 119122688Slepreau 119222688Slepreau if (first == 0) { 119322353Skjd getbuf(); 119422353Skjd first = 1; 119522353Skjd } 11961119Sbill if (recno >= nblock) { 119727445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 119827058Smckusick if (i != TBLOCK*nblock) 119927058Smckusick mterr("write", i, 2); 12001119Sbill recno = 0; 12011119Sbill } 120221457Skjd 120321457Skjd /* 120421457Skjd * Special case: We have an empty tape buffer, and the 120521457Skjd * users data size is >= the tape block size: Avoid 120621457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 120721457Skjd * residual to the tape buffer. 120821457Skjd */ 120921457Skjd while (recno == 0 && n >= nblock) { 121027058Smckusick i = write(mt, buffer, TBLOCK*nblock); 121127058Smckusick if (i != TBLOCK*nblock) 121227058Smckusick mterr("write", i, 2); 121321457Skjd n -= nblock; 121421457Skjd buffer += (nblock * TBLOCK); 12151119Sbill } 121621457Skjd 121721457Skjd while (n-- > 0) { 121821457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 121921457Skjd buffer += TBLOCK; 122021457Skjd if (recno >= nblock) { 122127445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 122227058Smckusick if (i != TBLOCK*nblock) 122327058Smckusick mterr("write", i, 2); 122421457Skjd recno = 0; 122521457Skjd } 122621457Skjd } 122721457Skjd 122821457Skjd /* Tell the user how much to write to get in sync */ 122921457Skjd return (nblock - recno); 12301119Sbill } 12311119Sbill 12321119Sbill backtape() 12331119Sbill { 123427058Smckusick static int mtdev = 1; 12353457Swnj static struct mtop mtop = {MTBSR, 1}; 123627058Smckusick struct mtget mtget; 123727058Smckusick 123827058Smckusick if (mtdev == 1) 123927445Slepreau mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 12403457Swnj if (mtdev == 0) { 124127445Slepreau if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 124227058Smckusick fprintf(stderr, "tar: tape backspace error: "); 124327058Smckusick perror(""); 12441119Sbill done(4); 12451119Sbill } 12463457Swnj } else 124722688Slepreau lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 12483457Swnj recno--; 12491119Sbill } 12501119Sbill 12511119Sbill flushtape() 12521119Sbill { 125327058Smckusick int i; 125427058Smckusick 125527445Slepreau i = write(mt, (char *)tbuf, TBLOCK*nblock); 125627058Smckusick if (i != TBLOCK*nblock) 125727058Smckusick mterr("write", i, 2); 12581119Sbill } 12591119Sbill 126027058Smckusick mterr(operation, i, exitcode) 126127058Smckusick char *operation; 126227058Smckusick int i; 126327058Smckusick { 126427058Smckusick fprintf(stderr, "tar: tape %s error: ", operation); 126527058Smckusick if (i < 0) 126627058Smckusick perror(""); 126727058Smckusick else 126827058Smckusick fprintf(stderr, "unexpected EOF\n"); 126927058Smckusick done(exitcode); 127027058Smckusick } 127127058Smckusick 12728737Smckusick bread(fd, buf, size) 12738737Smckusick int fd; 12748737Smckusick char *buf; 12758737Smckusick int size; 12768737Smckusick { 12778737Smckusick int count; 12788737Smckusick static int lastread = 0; 12798737Smckusick 128022688Slepreau if (!Bflag) 128122688Slepreau return (read(fd, buf, size)); 128222353Skjd 12838737Smckusick for (count = 0; count < size; count += lastread) { 128424281Smckusick lastread = read(fd, buf, size - count); 128524281Smckusick if (lastread <= 0) { 12868737Smckusick if (count > 0) 12878737Smckusick return (count); 12888737Smckusick return (lastread); 12898737Smckusick } 12908737Smckusick buf += lastread; 12918737Smckusick } 12928737Smckusick return (count); 12938737Smckusick } 129410165Ssam 129510165Ssam char * 129610165Ssam getcwd(buf) 129710165Ssam char *buf; 129810165Ssam { 129910165Ssam if (getwd(buf) == NULL) { 130010165Ssam fprintf(stderr, "tar: %s\n", buf); 130121457Skjd exit(1); 130210165Ssam } 130310165Ssam return (buf); 130410165Ssam } 130521910Skjd 130621910Skjd getbuf() 130721910Skjd { 130822353Skjd 130927058Smckusick if (nblock == 0) { 131021910Skjd fstat(mt, &stbuf); 131121910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 131227058Smckusick nblock = NBLOCK; 131321910Skjd else { 131427058Smckusick nblock = stbuf.st_blksize / TBLOCK; 131527058Smckusick if (nblock == 0) 131627058Smckusick nblock = NBLOCK; 131721910Skjd } 131821910Skjd } 131927445Slepreau tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 132021910Skjd if (tbuf == NULL) { 132121910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 132221910Skjd nblock); 132321910Skjd done(1); 132421910Skjd } 132521910Skjd } 132622353Skjd 132722688Slepreau /* 132827442Slepreau * Save this directory and its mtime on the stack, popping and setting 132927442Slepreau * the mtimes of any stacked dirs which aren't parents of this one. 133027442Slepreau * A null directory causes the entire stack to be unwound and set. 133122688Slepreau * 133227442Slepreau * Since all the elements of the directory "stack" share a common 133327442Slepreau * prefix, we can make do with one string. We keep only the current 133427442Slepreau * directory path, with an associated array of mtime's, one for each 133527442Slepreau * '/' in the path. A negative mtime means no mtime. The mtime's are 133627442Slepreau * offset by one (first index 1, not 0) because calling this with a null 133727442Slepreau * directory causes mtime[0] to be set. 133827442Slepreau * 133922688Slepreau * This stack algorithm is not guaranteed to work for tapes created 134022688Slepreau * with the 'r' option, but the vast majority of tapes with 134122688Slepreau * directories are not. This avoids saving every directory record on 134222688Slepreau * the tape and setting all the times at the end. 134322688Slepreau */ 134422688Slepreau char dirstack[NAMSIZ]; 134522688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 134622688Slepreau time_t mtime[NTIM]; 134722353Skjd 134822688Slepreau dodirtimes(hp) 134922688Slepreau union hblock *hp; 135022353Skjd { 135122688Slepreau register char *p = dirstack; 135222688Slepreau register char *q = hp->dbuf.name; 135322688Slepreau register int ndir = 0; 135422688Slepreau char *savp; 135522688Slepreau int savndir; 135622353Skjd 135722688Slepreau /* Find common prefix */ 135830090Sbostic while (*p == *q && *p) { 135922688Slepreau if (*p++ == '/') 136022688Slepreau ++ndir; 136122688Slepreau q++; 136222688Slepreau } 136322353Skjd 136422688Slepreau savp = p; 136522688Slepreau savndir = ndir; 136622688Slepreau while (*p) { 136722688Slepreau /* 136822688Slepreau * Not a child: unwind the stack, setting the times. 136922688Slepreau * The order we do this doesn't matter, so we go "forward." 137022688Slepreau */ 137122688Slepreau if (*p++ == '/') 137222688Slepreau if (mtime[++ndir] >= 0) { 137322688Slepreau *--p = '\0'; /* zap the slash */ 137422688Slepreau setimes(dirstack, mtime[ndir]); 137522688Slepreau *p++ = '/'; 137622688Slepreau } 137722688Slepreau } 137822688Slepreau p = savp; 137922688Slepreau ndir = savndir; 138022353Skjd 138122688Slepreau /* Push this one on the "stack" */ 138222688Slepreau while (*p = *q++) /* append the rest of the new dir */ 138322688Slepreau if (*p++ == '/') 138422688Slepreau mtime[++ndir] = -1; 138522688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 138622688Slepreau } 138722353Skjd 138822688Slepreau setimes(path, mt) 138922688Slepreau char *path; 139022688Slepreau time_t mt; 139122688Slepreau { 139222688Slepreau struct timeval tv[2]; 139322353Skjd 139422688Slepreau tv[0].tv_sec = time((time_t *) 0); 139522688Slepreau tv[1].tv_sec = mt; 139622688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 139727058Smckusick if (utimes(path, tv) < 0) { 139827058Smckusick fprintf(stderr, "tar: can't set time on %s: ", path); 139927058Smckusick perror(""); 140027058Smckusick } 140122688Slepreau } 140222688Slepreau 140322688Slepreau char * 140422688Slepreau getmem(size) 140522688Slepreau { 140622688Slepreau char *p = malloc((unsigned) size); 140722688Slepreau 140822688Slepreau if (p == NULL && freemem) { 140922688Slepreau fprintf(stderr, 141022688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 141122688Slepreau freemem = 0; 141222353Skjd } 141322688Slepreau return (p); 141422353Skjd } 1415