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*22688Slepreau static char sccsid[] = "@(#)tar.c 5.2 (Berkeley) 06/07/85"; 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> 291119Sbill 301119Sbill #define TBLOCK 512 313355Swnj #define NBLOCK 20 321119Sbill #define NAMSIZ 100 3322353Skjd #define FILEBLOCK 20 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; 8322353Skjd int mtdev = 1; 846250Sroot int term; 856250Sroot int chksum; 866250Sroot int recno; 87*22688Slepreau int first; 88*22688Slepreau int prtlinkerr; 891119Sbill int freemem = 1; 9022353Skjd int nblock = 0; 916250Sroot int onintr(); 926250Sroot int onquit(); 936250Sroot int onhup(); 94*22688Slepreau #ifdef notdef 956250Sroot int onterm(); 96*22688Slepreau #endif 971119Sbill 981119Sbill daddr_t low; 991119Sbill daddr_t high; 1006250Sroot daddr_t bsrch(); 1011119Sbill 10221910Skjd FILE *vfile = stdout; 1031119Sbill FILE *tfile; 1041119Sbill char tname[] = "/tmp/tarXXXXXX"; 1051119Sbill char *usefile; 1066250Sroot char magtape[] = "/dev/rmt8"; 1071119Sbill char *malloc(); 1086250Sroot char *sprintf(); 1096250Sroot char *strcat(); 11012154Ssam char *rindex(); 11110165Ssam char *getcwd(); 1129844Ssam char *getwd(); 113*22688Slepreau char *getmem(); 1141119Sbill 1151119Sbill main(argc, argv) 1161119Sbill int argc; 1171119Sbill char *argv[]; 1181119Sbill { 1191119Sbill char *cp; 1201119Sbill 1211119Sbill if (argc < 2) 1221119Sbill usage(); 1231119Sbill 1241119Sbill tfile = NULL; 1251119Sbill usefile = magtape; 1261119Sbill argv[argc] = 0; 1271119Sbill argv++; 1281119Sbill for (cp = *argv++; *cp; cp++) 1291119Sbill switch(*cp) { 1306250Sroot 1311119Sbill case 'f': 13212154Ssam if (*argv == 0) { 13312154Ssam fprintf(stderr, 13412154Ssam "tar: tapefile must be specified with 'f' option\n"); 13512154Ssam usage(); 13612154Ssam } 1371119Sbill usefile = *argv++; 1381119Sbill fflag++; 1391119Sbill break; 1406250Sroot 1411119Sbill case 'c': 1421119Sbill cflag++; 1431119Sbill rflag++; 1441119Sbill break; 1456250Sroot 1461119Sbill case 'o': 1471119Sbill oflag++; 1481119Sbill break; 1496250Sroot 1501119Sbill case 'p': 1511119Sbill pflag++; 1521119Sbill break; 1536250Sroot 1541119Sbill case 'u': 1551119Sbill mktemp(tname); 1561119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1576250Sroot fprintf(stderr, 158*22688Slepreau "tar: cannot create temporary file (%s)\n", 1596250Sroot tname); 1601119Sbill done(1); 1611119Sbill } 1621119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1636250Sroot /*FALL THRU*/ 1646250Sroot 1651119Sbill case 'r': 1661119Sbill rflag++; 1671119Sbill break; 1686250Sroot 1691119Sbill case 'v': 1701119Sbill vflag++; 1711119Sbill break; 1726250Sroot 1731119Sbill case 'w': 1741119Sbill wflag++; 1751119Sbill break; 1766250Sroot 1771119Sbill case 'x': 1781119Sbill xflag++; 1791119Sbill break; 1806250Sroot 1811119Sbill case 't': 1821119Sbill tflag++; 1831119Sbill break; 1846250Sroot 1851119Sbill case 'm': 1861119Sbill mflag++; 1871119Sbill break; 1886250Sroot 1891119Sbill case '-': 1901119Sbill break; 1916250Sroot 1921119Sbill case '0': 1931119Sbill case '1': 1941119Sbill case '4': 1951119Sbill case '5': 19621457Skjd case '7': 1971119Sbill case '8': 1981119Sbill magtape[8] = *cp; 1991119Sbill usefile = magtape; 2001119Sbill break; 2016250Sroot 2021119Sbill case 'b': 20313492Ssam if (*argv == 0) { 20413492Ssam fprintf(stderr, 20513492Ssam "tar: blocksize must be specified with 'b' option\n"); 20613492Ssam usage(); 20713492Ssam } 20813492Ssam nblock = atoi(*argv); 20913492Ssam if (nblock <= 0) { 21013492Ssam fprintf(stderr, 21113492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2121119Sbill done(1); 2131119Sbill } 21413492Ssam argv++; 2151119Sbill break; 2166250Sroot 2171119Sbill case 'l': 218*22688Slepreau prtlinkerr++; 2191119Sbill break; 2206250Sroot 2216250Sroot case 'h': 2226250Sroot hflag++; 2236250Sroot break; 2246250Sroot 22512154Ssam case 'i': 22612154Ssam iflag++; 22712154Ssam break; 22812154Ssam 2298737Smckusick case 'B': 2308737Smckusick Bflag++; 2318737Smckusick break; 2328737Smckusick 23312154Ssam case 'F': 23412154Ssam Fflag++; 23512154Ssam break; 23612154Ssam 2371119Sbill default: 2381119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2391119Sbill usage(); 2401119Sbill } 2411119Sbill 2426250Sroot if (!rflag && !xflag && !tflag) 2436250Sroot usage(); 2441119Sbill if (rflag) { 2456250Sroot if (cflag && tfile != NULL) 2461119Sbill usage(); 2471119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2481119Sbill signal(SIGINT, onintr); 2491119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 2501119Sbill signal(SIGHUP, onhup); 2511119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2521119Sbill signal(SIGQUIT, onquit); 2536250Sroot #ifdef notdef 2541119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2551119Sbill signal(SIGTERM, onterm); 2566250Sroot #endif 2571119Sbill if (strcmp(usefile, "-") == 0) { 2581119Sbill if (cflag == 0) { 2596250Sroot fprintf(stderr, 26013492Ssam "tar: can only create standard output archives\n"); 2611119Sbill done(1); 2621119Sbill } 26321910Skjd vfile = stderr; 26421910Skjd setlinebuf(vfile); 2651119Sbill mt = dup(1); 2666250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2671119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2686250Sroot fprintf(stderr, 2696250Sroot "tar: cannot open %s\n", usefile); 2701119Sbill done(1); 2711119Sbill } 2721119Sbill } 2731119Sbill dorep(argv); 2746250Sroot done(0); 2751119Sbill } 2766250Sroot if (strcmp(usefile, "-") == 0) { 2776250Sroot mt = dup(0); 2786250Sroot } else if ((mt = open(usefile, 0)) < 0) { 2796250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 2806250Sroot done(1); 2816250Sroot } 2826250Sroot if (xflag) 2831119Sbill doxtract(argv); 2846250Sroot else 2851119Sbill dotable(); 2861119Sbill done(0); 2871119Sbill } 2881119Sbill 2891119Sbill usage() 2901119Sbill { 2916250Sroot fprintf(stderr, 29221457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 2931119Sbill done(1); 2941119Sbill } 2951119Sbill 2961119Sbill dorep(argv) 2976250Sroot char *argv[]; 2981119Sbill { 2991119Sbill register char *cp, *cp2; 3009601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 3011119Sbill 3021119Sbill if (!cflag) { 3031119Sbill getdir(); 3041119Sbill do { 3051119Sbill passtape(); 3061119Sbill if (term) 3071119Sbill done(0); 3081119Sbill getdir(); 3091119Sbill } while (!endtape()); 31013492Ssam backtape(); 3111119Sbill if (tfile != NULL) { 3121119Sbill char buf[200]; 3131119Sbill 3146250Sroot sprintf(buf, 3156250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3161119Sbill tname, tname, tname, tname, tname, tname); 3171119Sbill fflush(tfile); 3181119Sbill system(buf); 3191119Sbill freopen(tname, "r", tfile); 3201119Sbill fstat(fileno(tfile), &stbuf); 3211119Sbill high = stbuf.st_size; 3221119Sbill } 3231119Sbill } 3241119Sbill 32510165Ssam (void) getcwd(wdir); 3261119Sbill while (*argv && ! term) { 3271119Sbill cp2 = *argv; 3281119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3291119Sbill argv++; 3301119Sbill if (chdir(*argv) < 0) 3311119Sbill perror(*argv); 3321119Sbill else 33310165Ssam (void) getcwd(wdir); 3341119Sbill argv++; 3351119Sbill continue; 3361119Sbill } 3379601Ssam parent = wdir; 3381119Sbill for (cp = *argv; *cp; cp++) 3391119Sbill if (*cp == '/') 3401119Sbill cp2 = cp; 3411119Sbill if (cp2 != *argv) { 3421119Sbill *cp2 = '\0'; 3439601Ssam if (chdir(*argv) < 0) { 3449601Ssam perror(*argv); 3459601Ssam continue; 3469601Ssam } 34710165Ssam parent = getcwd(tempdir); 3481119Sbill *cp2 = '/'; 3491119Sbill cp2++; 3501119Sbill } 3519601Ssam putfile(*argv++, cp2, parent); 35215045Smckusick if (chdir(wdir) < 0) { 353*22688Slepreau fprintf(stderr, "tar: cannot change back?: "); 35415045Smckusick perror(wdir); 35515045Smckusick } 3561119Sbill } 3571119Sbill putempty(); 3581119Sbill putempty(); 3591119Sbill flushtape(); 360*22688Slepreau if (prtlinkerr == 0) 3616250Sroot return; 3626250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3636250Sroot if (ihead->count == 0) 3646250Sroot continue; 36513492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3666250Sroot } 3671119Sbill } 3681119Sbill 3691119Sbill endtape() 3701119Sbill { 37121457Skjd return (dblock.dbuf.name[0] == '\0'); 3721119Sbill } 3731119Sbill 3741119Sbill getdir() 3751119Sbill { 3761119Sbill register struct stat *sp; 3771119Sbill int i; 3781119Sbill 37912154Ssam top: 3806250Sroot readtape((char *)&dblock); 3811119Sbill if (dblock.dbuf.name[0] == '\0') 3821119Sbill return; 3831119Sbill sp = &stbuf; 3841119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3851119Sbill sp->st_mode = i; 3861119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3871119Sbill sp->st_uid = i; 3881119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3891119Sbill sp->st_gid = i; 3901119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3911119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3921119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 39312154Ssam if (chksum != (i = checksum())) { 39413492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 39512154Ssam chksum, i); 39612154Ssam if (iflag) 39712154Ssam goto top; 3981119Sbill done(2); 3991119Sbill } 4001119Sbill if (tfile != NULL) 4011119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4021119Sbill } 4031119Sbill 4041119Sbill passtape() 4051119Sbill { 4061119Sbill long blocks; 40721457Skjd char *bufp; 4081119Sbill 4091119Sbill if (dblock.dbuf.linkflag == '1') 4101119Sbill return; 4111119Sbill blocks = stbuf.st_size; 4121119Sbill blocks += TBLOCK-1; 4131119Sbill blocks /= TBLOCK; 4141119Sbill 41521457Skjd while (blocks-- > 0) 41621457Skjd readtbuf(&bufp, TBLOCK); 4171119Sbill } 4181119Sbill 4199601Ssam putfile(longname, shortname, parent) 4206250Sroot char *longname; 4216250Sroot char *shortname; 4229601Ssam char *parent; 4231119Sbill { 42421457Skjd int infile = 0; 42521457Skjd long blocks; 4261119Sbill char buf[TBLOCK]; 42721457Skjd char *bigbuf; 428*22688Slepreau register char *cp; 4295931Smckusic struct direct *dp; 4305931Smckusic DIR *dirp; 431*22688Slepreau int i; 4329601Ssam char newparent[NAMSIZ+64]; 43312154Ssam extern int errno; 43421457Skjd int maxread; 43521457Skjd int hint; /* amount to write to get "in sync" */ 4361119Sbill 4379601Ssam if (!hflag) 43812154Ssam i = lstat(shortname, &stbuf); 43912154Ssam else 44012154Ssam i = stat(shortname, &stbuf); 44112154Ssam if (i < 0) { 44212154Ssam switch (errno) { 44312154Ssam case EACCES: 44412154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 44512154Ssam break; 44612154Ssam case ENOENT: 44712154Ssam fprintf(stderr, "tar: %s: no such file or directory\n", 44812154Ssam longname); 44912154Ssam break; 45012154Ssam default: 45112154Ssam fprintf(stderr, "tar: %s: cannot stat file\n", longname); 45212154Ssam break; 45312154Ssam } 4549601Ssam return; 4559601Ssam } 45612154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4571119Sbill return; 45812154Ssam if (checkw('r', longname) == 0) 4591119Sbill return; 46012154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 46112154Ssam return; 4621119Sbill 46312154Ssam switch (stbuf.st_mode & S_IFMT) { 46412154Ssam case S_IFDIR: 4656250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4666250Sroot ; 4671119Sbill *--cp = '/'; 4681119Sbill *++cp = 0 ; 4691119Sbill if (!oflag) { 4706250Sroot if ((cp - buf) >= NAMSIZ) { 47113492Ssam fprintf(stderr, "tar: %s: file name too long\n", 47213492Ssam longname); 4736250Sroot return; 4746250Sroot } 4756250Sroot stbuf.st_size = 0; 4766250Sroot tomodes(&stbuf); 4776250Sroot strcpy(dblock.dbuf.name,buf); 4786250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4796250Sroot writetape((char *)&dblock); 4801119Sbill } 4819601Ssam sprintf(newparent, "%s/%s", parent, shortname); 48215045Smckusick if (chdir(shortname) < 0) { 48315045Smckusick perror(shortname); 48415045Smckusick return; 48515045Smckusick } 4865931Smckusic if ((dirp = opendir(".")) == NULL) { 48713492Ssam fprintf(stderr, "tar: %s: directory read error\n", 48813492Ssam longname); 48915045Smckusick if (chdir(parent) < 0) { 490*22688Slepreau fprintf(stderr, "tar: cannot change back?: "); 49115045Smckusick perror(parent); 49215045Smckusick } 4935931Smckusic return; 4945931Smckusic } 4955931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4965931Smckusic if (dp->d_ino == 0) 4971119Sbill continue; 4986250Sroot if (!strcmp(".", dp->d_name) || 4996250Sroot !strcmp("..", dp->d_name)) 5001119Sbill continue; 5015931Smckusic strcpy(cp, dp->d_name); 5025931Smckusic i = telldir(dirp); 5035931Smckusic closedir(dirp); 5049601Ssam putfile(buf, cp, newparent); 5055931Smckusic dirp = opendir("."); 5065931Smckusic seekdir(dirp, i); 5071119Sbill } 5085931Smckusic closedir(dirp); 50915045Smckusick if (chdir(parent) < 0) { 510*22688Slepreau fprintf(stderr, "tar: cannot change back?: "); 51115045Smckusick perror(parent); 51215045Smckusick } 51312154Ssam break; 51412154Ssam 51512154Ssam case S_IFLNK: 51612154Ssam tomodes(&stbuf); 51712154Ssam if (strlen(longname) >= NAMSIZ) { 51813492Ssam fprintf(stderr, "tar: %s: file name too long\n", 51913492Ssam longname); 52012154Ssam return; 52112154Ssam } 52212154Ssam strcpy(dblock.dbuf.name, longname); 5236250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 52413492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 52513492Ssam longname); 5266250Sroot return; 5276250Sroot } 5289601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5296250Sroot if (i < 0) { 5309601Ssam perror(longname); 5316250Sroot return; 5326250Sroot } 5336250Sroot dblock.dbuf.linkname[i] = '\0'; 5346250Sroot dblock.dbuf.linkflag = '2'; 535*22688Slepreau if (vflag) 536*22688Slepreau fprintf(vfile, "a %s symbolic link to %s\n", 537*22688Slepreau longname, dblock.dbuf.linkname); 5386250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 5396250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5406250Sroot writetape((char *)&dblock); 54112154Ssam break; 5421119Sbill 54312154Ssam case S_IFREG: 54412154Ssam if ((infile = open(shortname, 0)) < 0) { 54512154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 5461119Sbill return; 5471119Sbill } 54812154Ssam tomodes(&stbuf); 54912154Ssam if (strlen(longname) >= NAMSIZ) { 55013492Ssam fprintf(stderr, "tar: %s: file name too long\n", 55113492Ssam longname); 55221457Skjd close(infile); 55312154Ssam return; 55412154Ssam } 55512154Ssam strcpy(dblock.dbuf.name, longname); 55612154Ssam if (stbuf.st_nlink > 1) { 55712154Ssam struct linkbuf *lp; 55812154Ssam int found = 0; 55912154Ssam 56012154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 56112154Ssam if (lp->inum == stbuf.st_ino && 56212154Ssam lp->devnum == stbuf.st_dev) { 56312154Ssam found++; 56412154Ssam break; 56512154Ssam } 56612154Ssam if (found) { 56712154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 56812154Ssam dblock.dbuf.linkflag = '1'; 56912154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 57021457Skjd writetape( (char *) &dblock); 571*22688Slepreau if (vflag) 572*22688Slepreau fprintf(vfile, "a %s link to %s\n", 573*22688Slepreau longname, lp->pathname); 57412154Ssam lp->count--; 57512154Ssam close(infile); 57612154Ssam return; 5771119Sbill } 578*22688Slepreau lp = (struct linkbuf *) getmem(sizeof(*lp)); 579*22688Slepreau if (lp != NULL) { 58012154Ssam lp->nextp = ihead; 58112154Ssam ihead = lp; 58212154Ssam lp->inum = stbuf.st_ino; 58312154Ssam lp->devnum = stbuf.st_dev; 58412154Ssam lp->count = stbuf.st_nlink - 1; 58512154Ssam strcpy(lp->pathname, longname); 58612154Ssam } 5871119Sbill } 58821457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 589*22688Slepreau if (vflag) 590*22688Slepreau fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 59112154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 59221457Skjd hint = writetape((char *)&dblock); 59321457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 59421457Skjd if ((bigbuf = malloc(maxread)) == 0) { 59521457Skjd maxread = TBLOCK; 59621457Skjd bigbuf = buf; 59721457Skjd } 5981119Sbill 59921457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 60021457Skjd && blocks > 0) { 60121457Skjd register int nblks; 60221457Skjd 60321457Skjd nblks = ((i-1)/TBLOCK)+1; 60421457Skjd if (nblks > blocks) 60521457Skjd nblks = blocks; 60621457Skjd hint = writetbuf(bigbuf, nblks); 60721457Skjd blocks -= nblks; 60821457Skjd } 60921457Skjd close(infile); 61021457Skjd if (bigbuf != buf) 61121457Skjd free(bigbuf); 61221457Skjd if (blocks != 0 || i != 0) 61313492Ssam fprintf(stderr, "tar: %s: file changed size\n", 61413492Ssam longname); 61512154Ssam while (--blocks >= 0) 61612154Ssam putempty(); 61712154Ssam break; 61812154Ssam 61912154Ssam default: 62012154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 62113492Ssam longname); 62212154Ssam break; 6231119Sbill } 6241119Sbill } 6251119Sbill 6261119Sbill doxtract(argv) 6276250Sroot char *argv[]; 6281119Sbill { 6291119Sbill long blocks, bytes; 6301119Sbill char **cp; 6311119Sbill int ofile; 6321119Sbill 6331119Sbill for (;;) { 6341119Sbill getdir(); 6351119Sbill if (endtape()) 6361119Sbill break; 6371119Sbill if (*argv == 0) 6381119Sbill goto gotit; 6391119Sbill for (cp = argv; *cp; cp++) 6401119Sbill if (prefix(*cp, dblock.dbuf.name)) 6411119Sbill goto gotit; 6421119Sbill passtape(); 6431119Sbill continue; 6441119Sbill 6451119Sbill gotit: 6461119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 6471119Sbill passtape(); 6481119Sbill continue; 6491119Sbill } 65012154Ssam if (Fflag) { 65112154Ssam char *s; 65212154Ssam 65312154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 65412154Ssam s = dblock.dbuf.name; 65512154Ssam else 65612154Ssam s++; 65712154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 65812154Ssam passtape(); 65912154Ssam continue; 66012154Ssam } 66112154Ssam } 662*22688Slepreau if (checkdir(dblock.dbuf.name)) { /* have a directory */ 663*22688Slepreau if (mflag == 0) 664*22688Slepreau dodirtimes(&dblock); 6656250Sroot continue; 666*22688Slepreau } 667*22688Slepreau if (dblock.dbuf.linkflag == '2') { /* symlink */ 6686250Sroot unlink(dblock.dbuf.name); 6696250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 67013492Ssam fprintf(stderr, "tar: %s: symbolic link failed\n", 67113492Ssam dblock.dbuf.name); 6726250Sroot continue; 6736250Sroot } 6746250Sroot if (vflag) 67521910Skjd fprintf(vfile, "x %s symbolic link to %s\n", 67613492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 67722353Skjd #ifdef notdef 67822353Skjd /* ignore alien orders */ 67922353Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 680*22688Slepreau if (mflag == 0) 681*22688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 68222353Skjd if (pflag) 68322353Skjd chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 68422353Skjd #endif 6851119Sbill continue; 6866250Sroot } 687*22688Slepreau if (dblock.dbuf.linkflag == '1') { /* regular link */ 6881119Sbill unlink(dblock.dbuf.name); 6891119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 69013492Ssam fprintf(stderr, "tar: %s: cannot link\n", 69113492Ssam dblock.dbuf.name); 6921119Sbill continue; 6931119Sbill } 6941119Sbill if (vflag) 695*22688Slepreau fprintf(vfile, "%s linked to %s\n", 69613492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 6971119Sbill continue; 6981119Sbill } 6996250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 7006250Sroot fprintf(stderr, "tar: %s - cannot create\n", 70113492Ssam dblock.dbuf.name); 7021119Sbill passtape(); 7031119Sbill continue; 7041119Sbill } 70521457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7061119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7071119Sbill if (vflag) 708*22688Slepreau fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 70913492Ssam dblock.dbuf.name, bytes, blocks); 71021457Skjd for (; blocks > 0;) { 71121457Skjd register int nread; 71221457Skjd char *bufp; 71321457Skjd register int nwant; 71421457Skjd 71521457Skjd nwant = NBLOCK*TBLOCK; 71621457Skjd if (nwant > (blocks*TBLOCK)) 71721457Skjd nwant = (blocks*TBLOCK); 71821457Skjd nread = readtbuf(&bufp, nwant); 719*22688Slepreau if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 7206250Sroot fprintf(stderr, 72113492Ssam "tar: %s: HELP - extract write error\n", 72213492Ssam dblock.dbuf.name); 7236250Sroot done(2); 7246250Sroot } 72521457Skjd bytes -= nread; 72621457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7271119Sbill } 7281119Sbill close(ofile); 729*22688Slepreau if (mflag == 0) 730*22688Slepreau setimes(dblock.dbuf.name, stbuf.st_mtime); 7311926Swnj if (pflag) 7326250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7331119Sbill } 734*22688Slepreau if (mflag == 0) { 735*22688Slepreau dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 736*22688Slepreau dodirtimes(&dblock); 737*22688Slepreau } 7381119Sbill } 7391119Sbill 7401119Sbill dotable() 7411119Sbill { 7421119Sbill for (;;) { 7431119Sbill getdir(); 7441119Sbill if (endtape()) 7451119Sbill break; 7461119Sbill if (vflag) 7471119Sbill longt(&stbuf); 7481119Sbill printf("%s", dblock.dbuf.name); 7491119Sbill if (dblock.dbuf.linkflag == '1') 7501119Sbill printf(" linked to %s", dblock.dbuf.linkname); 7516250Sroot if (dblock.dbuf.linkflag == '2') 7526250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 7531119Sbill printf("\n"); 7541119Sbill passtape(); 7551119Sbill } 7561119Sbill } 7571119Sbill 7581119Sbill putempty() 7591119Sbill { 7601119Sbill char buf[TBLOCK]; 7611119Sbill 76213492Ssam bzero(buf, sizeof (buf)); 7631119Sbill writetape(buf); 7641119Sbill } 7651119Sbill 7661119Sbill longt(st) 7676250Sroot register struct stat *st; 7681119Sbill { 7691119Sbill register char *cp; 7701119Sbill char *ctime(); 7711119Sbill 7721119Sbill pmode(st); 7731119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 7741119Sbill printf("%7D", st->st_size); 7751119Sbill cp = ctime(&st->st_mtime); 7761119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 7771119Sbill } 7781119Sbill 7791119Sbill #define SUID 04000 7801119Sbill #define SGID 02000 7811119Sbill #define ROWN 0400 7821119Sbill #define WOWN 0200 7831119Sbill #define XOWN 0100 7841119Sbill #define RGRP 040 7851119Sbill #define WGRP 020 7861119Sbill #define XGRP 010 7871119Sbill #define ROTH 04 7881119Sbill #define WOTH 02 7891119Sbill #define XOTH 01 7901119Sbill #define STXT 01000 7911119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 7921119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 7931119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 7941119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 7951119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 7961119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 7971119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 7981119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 7991119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8001119Sbill 8011119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8021119Sbill 8031119Sbill pmode(st) 8046250Sroot register struct stat *st; 8051119Sbill { 8061119Sbill register int **mp; 8071119Sbill 8081119Sbill for (mp = &m[0]; mp < &m[9];) 8091119Sbill select(*mp++, st); 8101119Sbill } 8111119Sbill 8121119Sbill select(pairp, st) 8136250Sroot int *pairp; 8146250Sroot struct stat *st; 8151119Sbill { 8161119Sbill register int n, *ap; 8171119Sbill 8181119Sbill ap = pairp; 8191119Sbill n = *ap++; 8201119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8211119Sbill ap++; 8221119Sbill printf("%c", *ap); 8231119Sbill } 8241119Sbill 825*22688Slepreau /* 826*22688Slepreau * Make all directories needed by `name'. If `name' is a 827*22688Slepreau * directory itself on the tar tape (indicated by a trailing '/'), 828*22688Slepreau * return 1; else 0. 829*22688Slepreau */ 8301119Sbill checkdir(name) 8316250Sroot register char *name; 8321119Sbill { 8331119Sbill register char *cp; 8346250Sroot 83512154Ssam /* 836*22688Slepreau * Quick check for existence of directory. 83712154Ssam */ 83812154Ssam if ((cp = rindex(name, '/')) == 0) 83912154Ssam return (0); 84012154Ssam *cp = '\0'; 841*22688Slepreau if (access(name, 0) == 0) { /* already exists */ 84212154Ssam *cp = '/'; 843*22688Slepreau return (cp[1] == '\0'); /* return (lastchar == '/') */ 84412154Ssam } 84512154Ssam *cp = '/'; 84612154Ssam 84712154Ssam /* 84812154Ssam * No luck, try to make all directories in path. 84912154Ssam */ 8501119Sbill for (cp = name; *cp; cp++) { 8516250Sroot if (*cp != '/') 8526250Sroot continue; 8536250Sroot *cp = '\0'; 85412154Ssam if (access(name, 0) < 0) { 8559844Ssam if (mkdir(name, 0777) < 0) { 8569844Ssam perror(name); 85712154Ssam *cp = '/'; 85812154Ssam return (0); 8591119Sbill } 86021457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 86114956Skarels if (pflag && cp[1] == '\0') 8629844Ssam chmod(name, stbuf.st_mode & 0777); 8631119Sbill } 8646250Sroot *cp = '/'; 8651119Sbill } 8666250Sroot return (cp[-1]=='/'); 8671119Sbill } 8681119Sbill 8691119Sbill onintr() 8701119Sbill { 8711119Sbill signal(SIGINT, SIG_IGN); 8721119Sbill term++; 8731119Sbill } 8741119Sbill 8751119Sbill onquit() 8761119Sbill { 8771119Sbill signal(SIGQUIT, SIG_IGN); 8781119Sbill term++; 8791119Sbill } 8801119Sbill 8811119Sbill onhup() 8821119Sbill { 8831119Sbill signal(SIGHUP, SIG_IGN); 8841119Sbill term++; 8851119Sbill } 8861119Sbill 887*22688Slepreau #ifdef notdef 8881119Sbill onterm() 8891119Sbill { 8901119Sbill signal(SIGTERM, SIG_IGN); 8911119Sbill term++; 8921119Sbill } 893*22688Slepreau #endif 8941119Sbill 8951119Sbill tomodes(sp) 8961119Sbill register struct stat *sp; 8971119Sbill { 8981119Sbill register char *cp; 8991119Sbill 9001119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9011119Sbill *cp = '\0'; 9021119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 9031119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 9041119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 9051119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 9061119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9071119Sbill } 9081119Sbill 9091119Sbill checksum() 9101119Sbill { 9111119Sbill register i; 9121119Sbill register char *cp; 9131119Sbill 9146250Sroot for (cp = dblock.dbuf.chksum; 9156250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9161119Sbill *cp = ' '; 9171119Sbill i = 0; 9181119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9191119Sbill i += *cp; 9206250Sroot return (i); 9211119Sbill } 9221119Sbill 9231119Sbill checkw(c, name) 9246250Sroot char *name; 9251119Sbill { 9266250Sroot if (!wflag) 9276250Sroot return (1); 9286250Sroot printf("%c ", c); 9296250Sroot if (vflag) 9306250Sroot longt(&stbuf); 9316250Sroot printf("%s: ", name); 9326250Sroot return (response() == 'y'); 9331119Sbill } 9341119Sbill 9351119Sbill response() 9361119Sbill { 9371119Sbill char c; 9381119Sbill 9391119Sbill c = getchar(); 9401119Sbill if (c != '\n') 9416250Sroot while (getchar() != '\n') 9426250Sroot ; 9436250Sroot else 9446250Sroot c = 'n'; 9456250Sroot return (c); 9461119Sbill } 9471119Sbill 94812154Ssam checkf(name, mode, howmuch) 94912154Ssam char *name; 95012154Ssam int mode, howmuch; 95112154Ssam { 95212154Ssam int l; 95312154Ssam 95421910Skjd if ((mode & S_IFMT) == S_IFDIR){ 95521910Skjd if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 95621910Skjd return(0); 95721910Skjd return(1); 95821910Skjd } 95912154Ssam if ((l = strlen(name)) < 3) 96012154Ssam return (1); 96112154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 96212154Ssam return (0); 96312154Ssam if (strcmp(name, "core") == 0 || 96412154Ssam strcmp(name, "errs") == 0 || 96512154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 96612154Ssam return (0); 96712154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 96812154Ssam return (1); 96912154Ssam } 97012154Ssam 971*22688Slepreau /* Is the current file a new file, or the newest one of the same name? */ 9721119Sbill checkupdate(arg) 9736250Sroot char *arg; 9741119Sbill { 9751119Sbill char name[100]; 9766250Sroot long mtime; 9771119Sbill daddr_t seekp; 9781119Sbill daddr_t lookup(); 9791119Sbill 9801119Sbill rewind(tfile); 9811119Sbill for (;;) { 9821119Sbill if ((seekp = lookup(arg)) < 0) 9836250Sroot return (1); 9841119Sbill fseek(tfile, seekp, 0); 9851119Sbill fscanf(tfile, "%s %lo", name, &mtime); 9866250Sroot return (stbuf.st_mtime > mtime); 9871119Sbill } 9881119Sbill } 9891119Sbill 9901119Sbill done(n) 9911119Sbill { 99221457Skjd unlink(tname); 9931119Sbill exit(n); 9941119Sbill } 9951119Sbill 996*22688Slepreau /* 997*22688Slepreau * Does s2 begin with the string s1, on a directory boundary? 998*22688Slepreau */ 9991119Sbill prefix(s1, s2) 10006250Sroot register char *s1, *s2; 10011119Sbill { 10021119Sbill while (*s1) 10031119Sbill if (*s1++ != *s2++) 10046250Sroot return (0); 10051119Sbill if (*s2) 10066250Sroot return (*s2 == '/'); 10076250Sroot return (1); 10081119Sbill } 10091119Sbill 10101119Sbill #define N 200 10111119Sbill int njab; 10126250Sroot 10131119Sbill daddr_t 10141119Sbill lookup(s) 10156250Sroot char *s; 10161119Sbill { 10171119Sbill register i; 10181119Sbill daddr_t a; 10191119Sbill 10201119Sbill for(i=0; s[i]; i++) 10216250Sroot if (s[i] == ' ') 10221119Sbill break; 10231119Sbill a = bsrch(s, i, low, high); 10246250Sroot return (a); 10251119Sbill } 10261119Sbill 10271119Sbill daddr_t 10281119Sbill bsrch(s, n, l, h) 10296250Sroot daddr_t l, h; 10306250Sroot char *s; 10311119Sbill { 10321119Sbill register i, j; 10331119Sbill char b[N]; 10341119Sbill daddr_t m, m1; 10351119Sbill 10361119Sbill njab = 0; 10371119Sbill 10381119Sbill loop: 10396250Sroot if (l >= h) 1040*22688Slepreau return ((daddr_t) -1); 10411119Sbill m = l + (h-l)/2 - N/2; 10426250Sroot if (m < l) 10431119Sbill m = l; 10441119Sbill fseek(tfile, m, 0); 10451119Sbill fread(b, 1, N, tfile); 10461119Sbill njab++; 10471119Sbill for(i=0; i<N; i++) { 10486250Sroot if (b[i] == '\n') 10491119Sbill break; 10501119Sbill m++; 10511119Sbill } 10526250Sroot if (m >= h) 1053*22688Slepreau return ((daddr_t) -1); 10541119Sbill m1 = m; 10551119Sbill j = i; 10561119Sbill for(i++; i<N; i++) { 10571119Sbill m1++; 10586250Sroot if (b[i] == '\n') 10591119Sbill break; 10601119Sbill } 10611119Sbill i = cmp(b+j, s, n); 10626250Sroot if (i < 0) { 10631119Sbill h = m; 10641119Sbill goto loop; 10651119Sbill } 10666250Sroot if (i > 0) { 10671119Sbill l = m1; 10681119Sbill goto loop; 10691119Sbill } 10706250Sroot return (m); 10711119Sbill } 10721119Sbill 10731119Sbill cmp(b, s, n) 10746250Sroot char *b, *s; 10751119Sbill { 10761119Sbill register i; 10771119Sbill 10786250Sroot if (b[0] != '\n') 107921457Skjd exit(2); 10801119Sbill for(i=0; i<n; i++) { 10816250Sroot if (b[i+1] > s[i]) 10826250Sroot return (-1); 10836250Sroot if (b[i+1] < s[i]) 10846250Sroot return (1); 10851119Sbill } 10866250Sroot return (b[i+1] == ' '? 0 : -1); 10871119Sbill } 10881119Sbill 1089*22688Slepreau readtape(buffer) 10906250Sroot char *buffer; 10911119Sbill { 109221457Skjd char *bufp; 109321457Skjd 1094*22688Slepreau if (first == 0) 1095*22688Slepreau getbuf(); 1096*22688Slepreau readtbuf(&bufp, TBLOCK); 109721457Skjd bcopy(bufp, buffer, TBLOCK); 109821457Skjd return(TBLOCK); 109921457Skjd } 110021457Skjd 110121457Skjd readtbuf(bufpp, size) 110221457Skjd char **bufpp; 110321457Skjd int size; 110421457Skjd { 11053457Swnj register int i; 11061119Sbill 11071119Sbill if (recno >= nblock || first == 0) { 11088737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 110913492Ssam fprintf(stderr, "tar: tape read error\n"); 11101119Sbill done(3); 11111119Sbill } 11121119Sbill if (first == 0) { 11131119Sbill if ((i % TBLOCK) != 0) { 111413492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11151119Sbill done(3); 11161119Sbill } 11171119Sbill i /= TBLOCK; 11183457Swnj if (i != nblock) { 111913492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11201119Sbill nblock = i; 11211119Sbill } 112222353Skjd first = 1; 11231119Sbill } 11241119Sbill recno = 0; 11251119Sbill } 112621457Skjd if (size > ((nblock-recno)*TBLOCK)) 112721457Skjd size = (nblock-recno)*TBLOCK; 112821457Skjd *bufpp = (char *)&tbuf[recno]; 112921457Skjd recno += (size/TBLOCK); 113021457Skjd return (size); 11311119Sbill } 11321119Sbill 113321457Skjd writetbuf(buffer, n) 113421457Skjd register char *buffer; 113521457Skjd register int n; 11361119Sbill { 1137*22688Slepreau 1138*22688Slepreau if (first == 0) { 113922353Skjd getbuf(); 114022353Skjd first = 1; 114122353Skjd } 11421119Sbill if (recno >= nblock) { 1143*22688Slepreau if (write(mt, tbuf, TBLOCK*nblock) < 0) { 1144*22688Slepreau fprintf(stderr,"tar: tape write error\n"); 11451119Sbill done(2); 11461119Sbill } 11471119Sbill recno = 0; 11481119Sbill } 114921457Skjd 115021457Skjd /* 115121457Skjd * Special case: We have an empty tape buffer, and the 115221457Skjd * users data size is >= the tape block size: Avoid 115321457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 115421457Skjd * residual to the tape buffer. 115521457Skjd */ 115621457Skjd while (recno == 0 && n >= nblock) { 115721457Skjd if (write(mt, buffer, TBLOCK*nblock) < 0) { 1158*22688Slepreau fprintf(stderr,"tar: tape write error\n"); 11591119Sbill done(2); 11601119Sbill } 116121457Skjd n -= nblock; 116221457Skjd buffer += (nblock * TBLOCK); 11631119Sbill } 116421457Skjd 116521457Skjd while (n-- > 0) { 116621457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 116721457Skjd buffer += TBLOCK; 116821457Skjd if (recno >= nblock) { 116921457Skjd if (write(mt, tbuf, TBLOCK*nblock) < 0) { 117022353Skjd fprintf(stderr,"tar: tape write error\n"); 117122353Skjd done(2); 117221457Skjd } 117321457Skjd recno = 0; 117421457Skjd } 117521457Skjd } 117621457Skjd 117721457Skjd /* Tell the user how much to write to get in sync */ 117821457Skjd return (nblock - recno); 11791119Sbill } 11801119Sbill 11811119Sbill backtape() 11821119Sbill { 11833457Swnj static struct mtop mtop = {MTBSR, 1}; 11843457Swnj 11853457Swnj if (mtdev == 0) { 11863457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 118713492Ssam fprintf(stderr, "tar: tape backspace error\n"); 11881119Sbill done(4); 11891119Sbill } 11903457Swnj } else 1191*22688Slepreau lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 11923457Swnj recno--; 11931119Sbill } 11941119Sbill 11951119Sbill flushtape() 11961119Sbill { 119721457Skjd write(mt, tbuf, TBLOCK*nblock); 11981119Sbill } 11991119Sbill 12008737Smckusick bread(fd, buf, size) 12018737Smckusick int fd; 12028737Smckusick char *buf; 12038737Smckusick int size; 12048737Smckusick { 12058737Smckusick int count; 12068737Smckusick static int lastread = 0; 12078737Smckusick 1208*22688Slepreau if (!Bflag) 1209*22688Slepreau return (read(fd, buf, size)); 121022353Skjd 12118737Smckusick for (count = 0; count < size; count += lastread) { 12128737Smckusick if (lastread < 0) { 12138737Smckusick if (count > 0) 12148737Smckusick return (count); 12158737Smckusick return (lastread); 12168737Smckusick } 12178737Smckusick lastread = read(fd, buf, size - count); 12188737Smckusick buf += lastread; 12198737Smckusick } 12208737Smckusick return (count); 12218737Smckusick } 122210165Ssam 122310165Ssam char * 122410165Ssam getcwd(buf) 122510165Ssam char *buf; 122610165Ssam { 122710165Ssam if (getwd(buf) == NULL) { 122810165Ssam fprintf(stderr, "tar: %s\n", buf); 122921457Skjd exit(1); 123010165Ssam } 123110165Ssam return (buf); 123210165Ssam } 123321910Skjd 123421910Skjd getbuf() 123521910Skjd { 123622353Skjd 1237*22688Slepreau if (mtdev == 1) { 123821910Skjd fstat(mt, &stbuf); 123921910Skjd if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 124021910Skjd mtdev = 0; 124121910Skjd else 124221910Skjd mtdev = -1; 124321910Skjd } 1244*22688Slepreau if (nblock == 0) { 124521910Skjd if (mtdev == 0) 124621910Skjd nblock = FILEBLOCK; 124721910Skjd else { 124821910Skjd fstat(mt, &stbuf); 124921910Skjd nblock = stbuf.st_blocks / TBLOCK; 125021910Skjd } 125121910Skjd } 1252*22688Slepreau if (nblock == 0) 1253*22688Slepreau nblock = FILEBLOCK; 125421910Skjd tbuf = (union hblock *)malloc(nblock*TBLOCK); 125521910Skjd if (tbuf == NULL) { 125621910Skjd fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 125721910Skjd nblock); 125821910Skjd done(1); 125921910Skjd } 126021910Skjd } 126122353Skjd 1262*22688Slepreau /* 1263*22688Slepreau * We are really keeping a directory stack, but since all the 1264*22688Slepreau * elements of it share a common prefix, we can make do with one 1265*22688Slepreau * string. We keep only the current directory path, with an associated 1266*22688Slepreau * array of mtime's, one for each '/' in the path. A negative mtime 1267*22688Slepreau * means no mtime. The mtime's are offset by one (first index 1, not 1268*22688Slepreau * 0) because calling this with the null string causes mtime[0] to be set. 1269*22688Slepreau * 1270*22688Slepreau * This stack algorithm is not guaranteed to work for tapes created 1271*22688Slepreau * with the 'r' option, but the vast majority of tapes with 1272*22688Slepreau * directories are not. This avoids saving every directory record on 1273*22688Slepreau * the tape and setting all the times at the end. 1274*22688Slepreau */ 1275*22688Slepreau char dirstack[NAMSIZ]; 1276*22688Slepreau #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 1277*22688Slepreau time_t mtime[NTIM]; 127822353Skjd 1279*22688Slepreau dodirtimes(hp) 1280*22688Slepreau union hblock *hp; 128122353Skjd { 1282*22688Slepreau register char *p = dirstack; 1283*22688Slepreau register char *q = hp->dbuf.name; 1284*22688Slepreau register int ndir = 0; 1285*22688Slepreau char *savp; 1286*22688Slepreau int savndir; 128722353Skjd 1288*22688Slepreau /* Find common prefix */ 1289*22688Slepreau while (*p == *q) { 1290*22688Slepreau if (*p++ == '/') 1291*22688Slepreau ++ndir; 1292*22688Slepreau q++; 1293*22688Slepreau } 129422353Skjd 1295*22688Slepreau savp = p; 1296*22688Slepreau savndir = ndir; 1297*22688Slepreau while (*p) { 1298*22688Slepreau /* 1299*22688Slepreau * Not a child: unwind the stack, setting the times. 1300*22688Slepreau * The order we do this doesn't matter, so we go "forward." 1301*22688Slepreau */ 1302*22688Slepreau if (*p++ == '/') 1303*22688Slepreau if (mtime[++ndir] >= 0) { 1304*22688Slepreau *--p = '\0'; /* zap the slash */ 1305*22688Slepreau setimes(dirstack, mtime[ndir]); 1306*22688Slepreau *p++ = '/'; 1307*22688Slepreau } 1308*22688Slepreau } 1309*22688Slepreau p = savp; 1310*22688Slepreau ndir = savndir; 131122353Skjd 1312*22688Slepreau /* Push this one on the "stack" */ 1313*22688Slepreau while (*p = *q++) /* append the rest of the new dir */ 1314*22688Slepreau if (*p++ == '/') 1315*22688Slepreau mtime[++ndir] = -1; 1316*22688Slepreau mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 1317*22688Slepreau } 131822353Skjd 1319*22688Slepreau setimes(path, mt) 1320*22688Slepreau char *path; 1321*22688Slepreau time_t mt; 1322*22688Slepreau { 1323*22688Slepreau struct timeval tv[2]; 132422353Skjd 1325*22688Slepreau tv[0].tv_sec = time((time_t *) 0); 1326*22688Slepreau tv[1].tv_sec = mt; 1327*22688Slepreau tv[0].tv_usec = tv[1].tv_usec = 0; 1328*22688Slepreau if (utimes(path, tv) < 0) 1329*22688Slepreau fprintf(stderr, "tar: can't set time on %s\n", path); 1330*22688Slepreau } 1331*22688Slepreau 1332*22688Slepreau char * 1333*22688Slepreau getmem(size) 1334*22688Slepreau { 1335*22688Slepreau char *p = malloc((unsigned) size); 1336*22688Slepreau 1337*22688Slepreau if (p == NULL && freemem) { 1338*22688Slepreau fprintf(stderr, 1339*22688Slepreau "tar: out of memory, link and directory modtime info lost\n"); 1340*22688Slepreau freemem = 0; 134122353Skjd } 1342*22688Slepreau return (p); 134322353Skjd } 1344