112154Ssam #ifndef lint 2*21457Skjd static char *sccsid = "@(#)tar.c 4.21 (Berkeley) 05/30/85"; 312154Ssam #endif 46250Sroot 56250Sroot /* 6*21457Skjd * T A R . C 7*21457Skjd * 8*21457Skjd * $Revision: 1.4 $ 9*21457Skjd * 10*21457Skjd * $Log: tar.c,v $ 11*21457Skjd * Revision 1.4 84/11/14 00:08:15 root 12*21457Skjd * New more efficient version. Minimizes the number of bcopys 13*21457Skjd * and maximizes block buffering. Page aligns block buffers. 14*21457Skjd * 15*21457Skjd * Revision 1.3 84/02/23 20:24:42 dpk 16*21457Skjd * Added missing close(infile) to prevent running out of fd's 17*21457Skjd * 18*21457Skjd * Revision 1.2 84/02/23 20:17:02 dpk 19*21457Skjd * Added distinctive RCS header 20*21457Skjd * 21*21457Skjd */ 22*21457Skjd #ifndef lint 23*21457Skjd static char RCSid[] = "@(#)$Header: tar.c,v 1.4 84/11/14 00:08:15 root Exp $"; 24*21457Skjd #endif 25*21457Skjd 26*21457Skjd 27*21457Skjd /* 286250Sroot * Tape Archival Program 296250Sroot */ 301119Sbill #include <stdio.h> 316413Smckusic #include <sys/param.h> 321119Sbill #include <sys/stat.h> 3312154Ssam #include <sys/dir.h> 348150Smckusick #include <sys/ioctl.h> 353457Swnj #include <sys/mtio.h> 3612983Ssam #include <sys/time.h> 371119Sbill #include <signal.h> 3812154Ssam #include <errno.h> 391119Sbill 401119Sbill #define TBLOCK 512 413355Swnj #define NBLOCK 20 421119Sbill #define NAMSIZ 100 436250Sroot 44*21457Skjd #define writetape(b) writetbuf(b, 1) 45*21457Skjd #define min(a,b) ((a) < (b) ? (a) : (b)) 46*21457Skjd #define max(a,b) ((a) > (b) ? (a) : (b)) 47*21457Skjd 481119Sbill union hblock { 491119Sbill char dummy[TBLOCK]; 501119Sbill struct header { 511119Sbill char name[NAMSIZ]; 521119Sbill char mode[8]; 531119Sbill char uid[8]; 541119Sbill char gid[8]; 551119Sbill char size[12]; 561119Sbill char mtime[12]; 571119Sbill char chksum[8]; 581119Sbill char linkflag; 591119Sbill char linkname[NAMSIZ]; 601119Sbill } dbuf; 616250Sroot }; 621119Sbill 631119Sbill struct linkbuf { 641119Sbill ino_t inum; 651119Sbill dev_t devnum; 661119Sbill int count; 671119Sbill char pathname[NAMSIZ]; 681119Sbill struct linkbuf *nextp; 696250Sroot }; 701119Sbill 716250Sroot union hblock dblock; 7213492Ssam union hblock *tbuf; 736250Sroot struct linkbuf *ihead; 746250Sroot struct stat stbuf; 751119Sbill 766250Sroot int rflag; 776250Sroot int xflag; 786250Sroot int vflag; 796250Sroot int tflag; 806250Sroot int cflag; 816250Sroot int mflag; 826250Sroot int fflag; 8312154Ssam int iflag; 846250Sroot int oflag; 856250Sroot int pflag; 866250Sroot int wflag; 876250Sroot int hflag; 888737Smckusick int Bflag; 8912154Ssam int Fflag; 906250Sroot 916250Sroot int mt; 926250Sroot int term; 936250Sroot int chksum; 946250Sroot int recno; 956250Sroot int first; 966250Sroot int linkerrok; 971119Sbill int freemem = 1; 983457Swnj int nblock = NBLOCK; 996250Sroot int onintr(); 1006250Sroot int onquit(); 1016250Sroot int onhup(); 1026250Sroot int onterm(); 1031119Sbill 1041119Sbill daddr_t low; 1051119Sbill daddr_t high; 1066250Sroot daddr_t bsrch(); 1071119Sbill 1081119Sbill FILE *tfile; 1091119Sbill char tname[] = "/tmp/tarXXXXXX"; 1101119Sbill char *usefile; 1116250Sroot char magtape[] = "/dev/rmt8"; 1121119Sbill char *malloc(); 1136250Sroot char *sprintf(); 1146250Sroot char *strcat(); 11512154Ssam char *rindex(); 11610165Ssam char *getcwd(); 1179844Ssam char *getwd(); 1181119Sbill 1191119Sbill main(argc, argv) 1201119Sbill int argc; 1211119Sbill char *argv[]; 1221119Sbill { 1231119Sbill char *cp; 1241119Sbill 1251119Sbill if (argc < 2) 1261119Sbill usage(); 1271119Sbill 1281119Sbill tfile = NULL; 1291119Sbill usefile = magtape; 1301119Sbill argv[argc] = 0; 1311119Sbill argv++; 1321119Sbill for (cp = *argv++; *cp; cp++) 1331119Sbill switch(*cp) { 1346250Sroot 1351119Sbill case 'f': 13612154Ssam if (*argv == 0) { 13712154Ssam fprintf(stderr, 13812154Ssam "tar: tapefile must be specified with 'f' option\n"); 13912154Ssam usage(); 14012154Ssam } 1411119Sbill usefile = *argv++; 1421119Sbill fflag++; 1431119Sbill break; 1446250Sroot 1451119Sbill case 'c': 1461119Sbill cflag++; 1471119Sbill rflag++; 1481119Sbill break; 1496250Sroot 1501119Sbill case 'o': 1511119Sbill oflag++; 1521119Sbill break; 1536250Sroot 1541119Sbill case 'p': 1551119Sbill pflag++; 1561119Sbill break; 1576250Sroot 1581119Sbill case 'u': 1591119Sbill mktemp(tname); 1601119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1616250Sroot fprintf(stderr, 1626250Sroot "Tar: cannot create temporary file (%s)\n", 1636250Sroot tname); 1641119Sbill done(1); 1651119Sbill } 1661119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1676250Sroot /*FALL THRU*/ 1686250Sroot 1691119Sbill case 'r': 1701119Sbill rflag++; 1711119Sbill break; 1726250Sroot 1731119Sbill case 'v': 1741119Sbill vflag++; 1751119Sbill break; 1766250Sroot 1771119Sbill case 'w': 1781119Sbill wflag++; 1791119Sbill break; 1806250Sroot 1811119Sbill case 'x': 1821119Sbill xflag++; 1831119Sbill break; 1846250Sroot 1851119Sbill case 't': 1861119Sbill tflag++; 1871119Sbill break; 1886250Sroot 1891119Sbill case 'm': 1901119Sbill mflag++; 1911119Sbill break; 1926250Sroot 1931119Sbill case '-': 1941119Sbill break; 1956250Sroot 1961119Sbill case '0': 1971119Sbill case '1': 1981119Sbill case '4': 1991119Sbill case '5': 200*21457Skjd case '7': 2011119Sbill case '8': 2021119Sbill magtape[8] = *cp; 2031119Sbill usefile = magtape; 2041119Sbill break; 2056250Sroot 2061119Sbill case 'b': 20713492Ssam if (*argv == 0) { 20813492Ssam fprintf(stderr, 20913492Ssam "tar: blocksize must be specified with 'b' option\n"); 21013492Ssam usage(); 21113492Ssam } 21213492Ssam nblock = atoi(*argv); 21313492Ssam if (nblock <= 0) { 21413492Ssam fprintf(stderr, 21513492Ssam "tar: invalid blocksize \"%s\"\n", *argv); 2161119Sbill done(1); 2171119Sbill } 21813492Ssam argv++; 2191119Sbill break; 2206250Sroot 2211119Sbill case 'l': 2221119Sbill linkerrok++; 2231119Sbill break; 2246250Sroot 2256250Sroot case 'h': 2266250Sroot hflag++; 2276250Sroot break; 2286250Sroot 22912154Ssam case 'i': 23012154Ssam iflag++; 23112154Ssam break; 23212154Ssam 2338737Smckusick case 'B': 2348737Smckusick Bflag++; 2358737Smckusick break; 2368737Smckusick 23712154Ssam case 'F': 23812154Ssam Fflag++; 23912154Ssam break; 24012154Ssam 2411119Sbill default: 2421119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 2431119Sbill usage(); 2441119Sbill } 2451119Sbill 2466250Sroot if (!rflag && !xflag && !tflag) 2476250Sroot usage(); 248*21457Skjd #ifndef vax 24913492Ssam tbuf = (union hblock *)malloc(nblock*TBLOCK); 250*21457Skjd #else 251*21457Skjd /* 252*21457Skjd * The following is for 4.2BSD and related systems to force 253*21457Skjd * the buffer to be page aligned. The kernel will avoid 254*21457Skjd * bcopy()'s on disk IO this way by manipulating the page tables. 255*21457Skjd */ 256*21457Skjd { 257*21457Skjd int pagesize = getpagesize(); 258*21457Skjd 259*21457Skjd tbuf = (union hblock *)malloc((nblock*TBLOCK)+pagesize); 260*21457Skjd tbuf = (union hblock *)(((int)tbuf+pagesize)&~(pagesize-1)); 261*21457Skjd } 262*21457Skjd #endif vax 26313492Ssam if (tbuf == NULL) { 26413492Ssam fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 26513492Ssam nblock); 26613492Ssam done(1); 26713492Ssam } 2681119Sbill if (rflag) { 2696250Sroot if (cflag && tfile != NULL) 2701119Sbill usage(); 2711119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2721119Sbill signal(SIGINT, onintr); 2731119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 2741119Sbill signal(SIGHUP, onhup); 2751119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2761119Sbill signal(SIGQUIT, onquit); 2776250Sroot #ifdef notdef 2781119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2791119Sbill signal(SIGTERM, onterm); 2806250Sroot #endif 2811119Sbill if (strcmp(usefile, "-") == 0) { 2821119Sbill if (cflag == 0) { 2836250Sroot fprintf(stderr, 28413492Ssam "tar: can only create standard output archives\n"); 2851119Sbill done(1); 2861119Sbill } 2871119Sbill mt = dup(1); 2881119Sbill nblock = 1; 2896250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2901119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2916250Sroot fprintf(stderr, 2926250Sroot "tar: cannot open %s\n", usefile); 2931119Sbill done(1); 2941119Sbill } 2951119Sbill } 2961119Sbill dorep(argv); 2976250Sroot done(0); 2981119Sbill } 2996250Sroot if (strcmp(usefile, "-") == 0) { 3006250Sroot mt = dup(0); 3016250Sroot nblock = 1; 3026250Sroot } else if ((mt = open(usefile, 0)) < 0) { 3036250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 3046250Sroot done(1); 3056250Sroot } 3066250Sroot if (xflag) 3071119Sbill doxtract(argv); 3086250Sroot else 3091119Sbill dotable(); 3101119Sbill done(0); 3111119Sbill } 3121119Sbill 3131119Sbill usage() 3141119Sbill { 3156250Sroot fprintf(stderr, 316*21457Skjd "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 3171119Sbill done(1); 3181119Sbill } 3191119Sbill 3201119Sbill dorep(argv) 3216250Sroot char *argv[]; 3221119Sbill { 3231119Sbill register char *cp, *cp2; 3249601Ssam char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; 3251119Sbill 3261119Sbill if (!cflag) { 3271119Sbill getdir(); 3281119Sbill do { 3291119Sbill passtape(); 3301119Sbill if (term) 3311119Sbill done(0); 3321119Sbill getdir(); 3331119Sbill } while (!endtape()); 33413492Ssam backtape(); 3351119Sbill if (tfile != NULL) { 3361119Sbill char buf[200]; 3371119Sbill 3386250Sroot sprintf(buf, 3396250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 3401119Sbill tname, tname, tname, tname, tname, tname); 3411119Sbill fflush(tfile); 3421119Sbill system(buf); 3431119Sbill freopen(tname, "r", tfile); 3441119Sbill fstat(fileno(tfile), &stbuf); 3451119Sbill high = stbuf.st_size; 3461119Sbill } 3471119Sbill } 3481119Sbill 34910165Ssam (void) getcwd(wdir); 3501119Sbill while (*argv && ! term) { 3511119Sbill cp2 = *argv; 3521119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 3531119Sbill argv++; 3541119Sbill if (chdir(*argv) < 0) 3551119Sbill perror(*argv); 3561119Sbill else 35710165Ssam (void) getcwd(wdir); 3581119Sbill argv++; 3591119Sbill continue; 3601119Sbill } 3619601Ssam parent = wdir; 3621119Sbill for (cp = *argv; *cp; cp++) 3631119Sbill if (*cp == '/') 3641119Sbill cp2 = cp; 3651119Sbill if (cp2 != *argv) { 3661119Sbill *cp2 = '\0'; 3679601Ssam if (chdir(*argv) < 0) { 3689601Ssam perror(*argv); 3699601Ssam continue; 3709601Ssam } 37110165Ssam parent = getcwd(tempdir); 3721119Sbill *cp2 = '/'; 3731119Sbill cp2++; 3741119Sbill } 3759601Ssam putfile(*argv++, cp2, parent); 37615045Smckusick if (chdir(wdir) < 0) { 377*21457Skjd fprintf(stderr, "cannot change back?: "); 37815045Smckusick perror(wdir); 37915045Smckusick } 3801119Sbill } 3811119Sbill putempty(); 3821119Sbill putempty(); 3831119Sbill flushtape(); 3846250Sroot if (linkerrok == 0) 3856250Sroot return; 3866250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3876250Sroot if (ihead->count == 0) 3886250Sroot continue; 38913492Ssam fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 3906250Sroot } 3911119Sbill } 3921119Sbill 3931119Sbill endtape() 3941119Sbill { 395*21457Skjd return (dblock.dbuf.name[0] == '\0'); 3961119Sbill } 3971119Sbill 3981119Sbill getdir() 3991119Sbill { 4001119Sbill register struct stat *sp; 4011119Sbill int i; 4021119Sbill 40312154Ssam top: 4046250Sroot readtape((char *)&dblock); 4051119Sbill if (dblock.dbuf.name[0] == '\0') 4061119Sbill return; 4071119Sbill sp = &stbuf; 4081119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 4091119Sbill sp->st_mode = i; 4101119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 4111119Sbill sp->st_uid = i; 4121119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 4131119Sbill sp->st_gid = i; 4141119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 4151119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 4161119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 41712154Ssam if (chksum != (i = checksum())) { 41813492Ssam fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 41912154Ssam chksum, i); 42012154Ssam if (iflag) 42112154Ssam goto top; 4221119Sbill done(2); 4231119Sbill } 4241119Sbill if (tfile != NULL) 4251119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 4261119Sbill } 4271119Sbill 4281119Sbill passtape() 4291119Sbill { 4301119Sbill long blocks; 431*21457Skjd char *bufp; 4321119Sbill 4331119Sbill if (dblock.dbuf.linkflag == '1') 4341119Sbill return; 4351119Sbill blocks = stbuf.st_size; 4361119Sbill blocks += TBLOCK-1; 4371119Sbill blocks /= TBLOCK; 4381119Sbill 439*21457Skjd while (blocks-- > 0) 440*21457Skjd readtbuf(&bufp, TBLOCK); 4411119Sbill } 4421119Sbill 4439601Ssam putfile(longname, shortname, parent) 4446250Sroot char *longname; 4456250Sroot char *shortname; 4469601Ssam char *parent; 4471119Sbill { 448*21457Skjd int infile = 0; 449*21457Skjd long blocks; 4501119Sbill char buf[TBLOCK]; 451*21457Skjd #ifdef vax 452*21457Skjd char *origbuf; 453*21457Skjd #endif 454*21457Skjd char *bigbuf; 4551119Sbill register char *cp, *cp2; 4565931Smckusic struct direct *dp; 4575931Smckusic DIR *dirp; 458*21457Skjd int i, j; 4599601Ssam char newparent[NAMSIZ+64]; 46012154Ssam extern int errno; 461*21457Skjd int maxread; 462*21457Skjd 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) { 46912154Ssam switch (errno) { 47012154Ssam case EACCES: 47112154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 47212154Ssam break; 47312154Ssam case ENOENT: 47412154Ssam fprintf(stderr, "tar: %s: no such file or directory\n", 47512154Ssam longname); 47612154Ssam break; 47712154Ssam default: 47812154Ssam fprintf(stderr, "tar: %s: cannot stat file\n", longname); 47912154Ssam break; 48012154Ssam } 4819601Ssam return; 4829601Ssam } 48312154Ssam if (tfile != NULL && checkupdate(longname) == 0) 4841119Sbill return; 48512154Ssam if (checkw('r', longname) == 0) 4861119Sbill return; 48712154Ssam if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 48812154Ssam return; 4891119Sbill 49012154Ssam switch (stbuf.st_mode & S_IFMT) { 49112154Ssam case S_IFDIR: 4926250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 4936250Sroot ; 4941119Sbill *--cp = '/'; 4951119Sbill *++cp = 0 ; 4961119Sbill if (!oflag) { 4976250Sroot if ((cp - buf) >= NAMSIZ) { 49813492Ssam fprintf(stderr, "tar: %s: file name too long\n", 49913492Ssam longname); 5006250Sroot return; 5016250Sroot } 5026250Sroot stbuf.st_size = 0; 5036250Sroot tomodes(&stbuf); 5046250Sroot strcpy(dblock.dbuf.name,buf); 5056250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5066250Sroot writetape((char *)&dblock); 5071119Sbill } 5089601Ssam sprintf(newparent, "%s/%s", parent, shortname); 50915045Smckusick if (chdir(shortname) < 0) { 51015045Smckusick perror(shortname); 51115045Smckusick return; 51215045Smckusick } 5135931Smckusic if ((dirp = opendir(".")) == NULL) { 51413492Ssam fprintf(stderr, "tar: %s: directory read error\n", 51513492Ssam longname); 51615045Smckusick if (chdir(parent) < 0) { 517*21457Skjd fprintf(stderr, "cannot change back?: "); 51815045Smckusick perror(parent); 51915045Smckusick } 5205931Smckusic return; 5215931Smckusic } 5225931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 5235931Smckusic if (dp->d_ino == 0) 5241119Sbill continue; 5256250Sroot if (!strcmp(".", dp->d_name) || 5266250Sroot !strcmp("..", dp->d_name)) 5271119Sbill continue; 5285931Smckusic strcpy(cp, dp->d_name); 5295931Smckusic i = telldir(dirp); 5305931Smckusic closedir(dirp); 5319601Ssam putfile(buf, cp, newparent); 5325931Smckusic dirp = opendir("."); 5335931Smckusic seekdir(dirp, i); 5341119Sbill } 5355931Smckusic closedir(dirp); 53615045Smckusick if (chdir(parent) < 0) { 537*21457Skjd fprintf(stderr, "cannot change back?: "); 53815045Smckusick perror(parent); 53915045Smckusick } 54012154Ssam break; 54112154Ssam 54212154Ssam case S_IFLNK: 54312154Ssam tomodes(&stbuf); 54412154Ssam if (strlen(longname) >= NAMSIZ) { 54513492Ssam fprintf(stderr, "tar: %s: file name too long\n", 54613492Ssam longname); 54712154Ssam return; 54812154Ssam } 54912154Ssam strcpy(dblock.dbuf.name, longname); 5506250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 55113492Ssam fprintf(stderr, "tar: %s: symbolic link too long\n", 55213492Ssam longname); 5536250Sroot return; 5546250Sroot } 5559601Ssam i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 5566250Sroot if (i < 0) { 5579601Ssam perror(longname); 5586250Sroot return; 5596250Sroot } 5606250Sroot dblock.dbuf.linkname[i] = '\0'; 5616250Sroot dblock.dbuf.linkflag = '2'; 5626250Sroot if (vflag) { 5636250Sroot fprintf(stderr, "a %s ", longname); 5646250Sroot fprintf(stderr, "symbolic link to %s\n", 56513492Ssam dblock.dbuf.linkname); 5666250Sroot } 5676250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 5686250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5696250Sroot writetape((char *)&dblock); 57012154Ssam break; 5711119Sbill 57212154Ssam case S_IFREG: 57312154Ssam if ((infile = open(shortname, 0)) < 0) { 57412154Ssam fprintf(stderr, "tar: %s: cannot open file\n", longname); 5751119Sbill return; 5761119Sbill } 57712154Ssam tomodes(&stbuf); 57812154Ssam if (strlen(longname) >= NAMSIZ) { 57913492Ssam fprintf(stderr, "tar: %s: file name too long\n", 58013492Ssam longname); 581*21457Skjd close(infile); 58212154Ssam return; 58312154Ssam } 58412154Ssam strcpy(dblock.dbuf.name, longname); 58512154Ssam if (stbuf.st_nlink > 1) { 58612154Ssam struct linkbuf *lp; 58712154Ssam int found = 0; 58812154Ssam 58912154Ssam for (lp = ihead; lp != NULL; lp = lp->nextp) 59012154Ssam if (lp->inum == stbuf.st_ino && 59112154Ssam lp->devnum == stbuf.st_dev) { 59212154Ssam found++; 59312154Ssam break; 59412154Ssam } 59512154Ssam if (found) { 59612154Ssam strcpy(dblock.dbuf.linkname, lp->pathname); 59712154Ssam dblock.dbuf.linkflag = '1'; 59812154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 599*21457Skjd writetape( (char *) &dblock); 60012154Ssam if (vflag) { 60112154Ssam fprintf(stderr, "a %s ", longname); 60213492Ssam fprintf(stderr, "link to %s\n", 60313492Ssam lp->pathname); 60412154Ssam } 60512154Ssam lp->count--; 60612154Ssam close(infile); 60712154Ssam return; 6081119Sbill } 60912154Ssam lp = (struct linkbuf *) malloc(sizeof(*lp)); 61012154Ssam if (lp == NULL) { 61112154Ssam if (freemem) { 61212154Ssam fprintf(stderr, 61313492Ssam "tar: out of memory, link information lost\n"); 61412154Ssam freemem = 0; 61512154Ssam } 61612154Ssam } else { 61712154Ssam lp->nextp = ihead; 61812154Ssam ihead = lp; 61912154Ssam lp->inum = stbuf.st_ino; 62012154Ssam lp->devnum = stbuf.st_dev; 62112154Ssam lp->count = stbuf.st_nlink - 1; 62212154Ssam strcpy(lp->pathname, longname); 62312154Ssam } 6241119Sbill } 625*21457Skjd blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 62612154Ssam if (vflag) { 62712154Ssam fprintf(stderr, "a %s ", longname); 62812154Ssam fprintf(stderr, "%ld blocks\n", blocks); 62912154Ssam } 63012154Ssam sprintf(dblock.dbuf.chksum, "%6o", checksum()); 631*21457Skjd hint = writetape((char *)&dblock); 632*21457Skjd maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 633*21457Skjd #ifndef vax 634*21457Skjd if ((bigbuf = malloc(maxread)) == 0) { 635*21457Skjd maxread = TBLOCK; 636*21457Skjd bigbuf = buf; 637*21457Skjd } 638*21457Skjd #else 639*21457Skjd /* 640*21457Skjd * The following is for 4.2BSD and related systems to force 641*21457Skjd * the buffer to be page aligned. The kernel will avoid 642*21457Skjd * bcopy()'s on disk IO this way by manipulating the page tables. 643*21457Skjd */ 644*21457Skjd { 645*21457Skjd int pagesize = getpagesize(); 6461119Sbill 647*21457Skjd if ((origbuf = malloc(maxread+pagesize)) == 0) { 648*21457Skjd maxread = TBLOCK; 649*21457Skjd bigbuf = buf; 650*21457Skjd } else { 651*21457Skjd bigbuf = (char *)(((int)origbuf+pagesize)&~(pagesize-1)); 652*21457Skjd } 65312154Ssam } 654*21457Skjd #endif vax 655*21457Skjd 656*21457Skjd while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 657*21457Skjd && blocks > 0) { 658*21457Skjd register int nblks; 659*21457Skjd 660*21457Skjd nblks = ((i-1)/TBLOCK)+1; 661*21457Skjd if (nblks > blocks) 662*21457Skjd nblks = blocks; 663*21457Skjd hint = writetbuf(bigbuf, nblks); 664*21457Skjd blocks -= nblks; 665*21457Skjd } 666*21457Skjd close(infile); 667*21457Skjd if (bigbuf != buf) 668*21457Skjd #ifndef vax 669*21457Skjd free(bigbuf); 670*21457Skjd #else 671*21457Skjd free(origbuf); 672*21457Skjd #endif 673*21457Skjd if (blocks != 0 || i != 0) 67413492Ssam fprintf(stderr, "tar: %s: file changed size\n", 67513492Ssam longname); 67612154Ssam while (--blocks >= 0) 67712154Ssam putempty(); 67812154Ssam break; 67912154Ssam 68012154Ssam default: 68112154Ssam fprintf(stderr, "tar: %s is not a file. Not dumped\n", 68213492Ssam longname); 68312154Ssam break; 6841119Sbill } 6851119Sbill } 6861119Sbill 6871119Sbill doxtract(argv) 6886250Sroot char *argv[]; 6891119Sbill { 6901119Sbill long blocks, bytes; 6911119Sbill char **cp; 6921119Sbill int ofile; 6931119Sbill 6941119Sbill for (;;) { 6951119Sbill getdir(); 6961119Sbill if (endtape()) 6971119Sbill break; 6981119Sbill if (*argv == 0) 6991119Sbill goto gotit; 7001119Sbill for (cp = argv; *cp; cp++) 7011119Sbill if (prefix(*cp, dblock.dbuf.name)) 7021119Sbill goto gotit; 7031119Sbill passtape(); 7041119Sbill continue; 7051119Sbill 7061119Sbill gotit: 7071119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 7081119Sbill passtape(); 7091119Sbill continue; 7101119Sbill } 71112154Ssam if (Fflag) { 71212154Ssam char *s; 71312154Ssam 71412154Ssam if ((s = rindex(dblock.dbuf.name, '/')) == 0) 71512154Ssam s = dblock.dbuf.name; 71612154Ssam else 71712154Ssam s++; 71812154Ssam if (checkf(s, stbuf.st_mode, Fflag) == 0) { 71912154Ssam passtape(); 72012154Ssam continue; 72112154Ssam } 72212154Ssam } 7236250Sroot if (checkdir(dblock.dbuf.name)) 7246250Sroot continue; 7256250Sroot if (dblock.dbuf.linkflag == '2') { 7266250Sroot unlink(dblock.dbuf.name); 7276250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 72813492Ssam fprintf(stderr, "tar: %s: symbolic link failed\n", 72913492Ssam dblock.dbuf.name); 7306250Sroot continue; 7316250Sroot } 7326250Sroot if (vflag) 7336250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 73413492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7358150Smckusick #ifdef notdef 7368150Smckusick /* ignore alien orders */ 737*21457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7386250Sroot if (mflag == 0) { 73912983Ssam struct timeval tv[2]; 7401119Sbill 74112983Ssam tv[0].tv_sec = time(0); 74212983Ssam tv[0].tv_usec = 0; 74312983Ssam tv[1].tv_sec = stbuf.st_mtime; 74412983Ssam tv[1].tv_usec = 0; 74512983Ssam utimes(dblock.dbuf.name, tv); 7466250Sroot } 7476250Sroot if (pflag) 7486250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 7498150Smckusick #endif 7501119Sbill continue; 7516250Sroot } 7521119Sbill if (dblock.dbuf.linkflag == '1') { 7531119Sbill unlink(dblock.dbuf.name); 7541119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 75513492Ssam fprintf(stderr, "tar: %s: cannot link\n", 75613492Ssam dblock.dbuf.name); 7571119Sbill continue; 7581119Sbill } 7591119Sbill if (vflag) 7603457Swnj fprintf(stderr, "%s linked to %s\n", 76113492Ssam dblock.dbuf.name, dblock.dbuf.linkname); 7621119Sbill continue; 7631119Sbill } 7646250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 7656250Sroot fprintf(stderr, "tar: %s - cannot create\n", 76613492Ssam dblock.dbuf.name); 7671119Sbill passtape(); 7681119Sbill continue; 7691119Sbill } 770*21457Skjd chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 7711119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 7721119Sbill if (vflag) 7733457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 77413492Ssam dblock.dbuf.name, bytes, blocks); 775*21457Skjd for (; blocks > 0;) { 776*21457Skjd register int nread; 777*21457Skjd char *bufp; 778*21457Skjd register int nwant; 779*21457Skjd 780*21457Skjd nwant = NBLOCK*TBLOCK; 781*21457Skjd if (nwant > (blocks*TBLOCK)) 782*21457Skjd nwant = (blocks*TBLOCK); 783*21457Skjd nread = readtbuf(&bufp, nwant); 784*21457Skjd if (bytes > nread) { 785*21457Skjd if (write(ofile, bufp, nread) < 0) { 786*21457Skjd fprintf(stderr, 787*21457Skjd "tar: %s: HELP - extract write error\n", 788*21457Skjd dblock.dbuf.name); 789*21457Skjd done(2); 790*21457Skjd } 791*21457Skjd } else if (write(ofile, bufp, (int) bytes) < 0) { 7926250Sroot fprintf(stderr, 79313492Ssam "tar: %s: HELP - extract write error\n", 79413492Ssam dblock.dbuf.name); 7956250Sroot done(2); 7966250Sroot } 797*21457Skjd bytes -= nread; 798*21457Skjd blocks -= (((nread-1)/TBLOCK)+1); 7991119Sbill } 8001119Sbill close(ofile); 8011119Sbill if (mflag == 0) { 80212983Ssam struct timeval tv[2]; 8031119Sbill 80412983Ssam tv[0].tv_sec = time(0); 80512983Ssam tv[0].tv_usec = 0; 80612983Ssam tv[1].tv_sec = stbuf.st_mtime; 80712983Ssam tv[1].tv_usec = 0; 80812983Ssam utimes(dblock.dbuf.name, tv); 8091119Sbill } 8101926Swnj if (pflag) 8116250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 8121119Sbill } 8131119Sbill } 8141119Sbill 8151119Sbill dotable() 8161119Sbill { 8171119Sbill for (;;) { 8181119Sbill getdir(); 8191119Sbill if (endtape()) 8201119Sbill break; 8211119Sbill if (vflag) 8221119Sbill longt(&stbuf); 8231119Sbill printf("%s", dblock.dbuf.name); 8241119Sbill if (dblock.dbuf.linkflag == '1') 8251119Sbill printf(" linked to %s", dblock.dbuf.linkname); 8266250Sroot if (dblock.dbuf.linkflag == '2') 8276250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 8281119Sbill printf("\n"); 8291119Sbill passtape(); 8301119Sbill } 8311119Sbill } 8321119Sbill 8331119Sbill putempty() 8341119Sbill { 8351119Sbill char buf[TBLOCK]; 8361119Sbill 83713492Ssam bzero(buf, sizeof (buf)); 8381119Sbill writetape(buf); 8391119Sbill } 8401119Sbill 8411119Sbill longt(st) 8426250Sroot register struct stat *st; 8431119Sbill { 8441119Sbill register char *cp; 8451119Sbill char *ctime(); 8461119Sbill 8471119Sbill pmode(st); 8481119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 8491119Sbill printf("%7D", st->st_size); 8501119Sbill cp = ctime(&st->st_mtime); 8511119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 8521119Sbill } 8531119Sbill 8541119Sbill #define SUID 04000 8551119Sbill #define SGID 02000 8561119Sbill #define ROWN 0400 8571119Sbill #define WOWN 0200 8581119Sbill #define XOWN 0100 8591119Sbill #define RGRP 040 8601119Sbill #define WGRP 020 8611119Sbill #define XGRP 010 8621119Sbill #define ROTH 04 8631119Sbill #define WOTH 02 8641119Sbill #define XOTH 01 8651119Sbill #define STXT 01000 8661119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 8671119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 8681119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 8691119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 8701119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 8711119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 8721119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 8731119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 8741119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 8751119Sbill 8761119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 8771119Sbill 8781119Sbill pmode(st) 8796250Sroot register struct stat *st; 8801119Sbill { 8811119Sbill register int **mp; 8821119Sbill 8831119Sbill for (mp = &m[0]; mp < &m[9];) 8841119Sbill select(*mp++, st); 8851119Sbill } 8861119Sbill 8871119Sbill select(pairp, st) 8886250Sroot int *pairp; 8896250Sroot struct stat *st; 8901119Sbill { 8911119Sbill register int n, *ap; 8921119Sbill 8931119Sbill ap = pairp; 8941119Sbill n = *ap++; 8951119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 8961119Sbill ap++; 8971119Sbill printf("%c", *ap); 8981119Sbill } 8991119Sbill 9001119Sbill checkdir(name) 9016250Sroot register char *name; 9021119Sbill { 9031119Sbill register char *cp; 9046250Sroot 90512154Ssam /* 90612154Ssam * Quick check for existance of directory. 90712154Ssam */ 90812154Ssam if ((cp = rindex(name, '/')) == 0) 90912154Ssam return (0); 91012154Ssam *cp = '\0'; 91112154Ssam if (access(name, 0) >= 0) { 91212154Ssam *cp = '/'; 91312154Ssam return (cp[1] == '\0'); 91412154Ssam } 91512154Ssam *cp = '/'; 91612154Ssam 91712154Ssam /* 91812154Ssam * No luck, try to make all directories in path. 91912154Ssam */ 9201119Sbill for (cp = name; *cp; cp++) { 9216250Sroot if (*cp != '/') 9226250Sroot continue; 9236250Sroot *cp = '\0'; 92412154Ssam if (access(name, 0) < 0) { 9259844Ssam if (mkdir(name, 0777) < 0) { 9269844Ssam perror(name); 92712154Ssam *cp = '/'; 92812154Ssam return (0); 9291119Sbill } 930*21457Skjd chown(name, stbuf.st_uid, stbuf.st_gid); 93114956Skarels if (pflag && cp[1] == '\0') 9329844Ssam chmod(name, stbuf.st_mode & 0777); 9331119Sbill } 9346250Sroot *cp = '/'; 9351119Sbill } 9366250Sroot return (cp[-1]=='/'); 9371119Sbill } 9381119Sbill 9391119Sbill onintr() 9401119Sbill { 9411119Sbill signal(SIGINT, SIG_IGN); 9421119Sbill term++; 9431119Sbill } 9441119Sbill 9451119Sbill onquit() 9461119Sbill { 9471119Sbill signal(SIGQUIT, SIG_IGN); 9481119Sbill term++; 9491119Sbill } 9501119Sbill 9511119Sbill onhup() 9521119Sbill { 9531119Sbill signal(SIGHUP, SIG_IGN); 9541119Sbill term++; 9551119Sbill } 9561119Sbill 9571119Sbill onterm() 9581119Sbill { 9591119Sbill signal(SIGTERM, SIG_IGN); 9601119Sbill term++; 9611119Sbill } 9621119Sbill 9631119Sbill tomodes(sp) 9641119Sbill register struct stat *sp; 9651119Sbill { 9661119Sbill register char *cp; 9671119Sbill 9681119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9691119Sbill *cp = '\0'; 9701119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 9711119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 9721119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 9731119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 9741119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 9751119Sbill } 9761119Sbill 9771119Sbill checksum() 9781119Sbill { 9791119Sbill register i; 9801119Sbill register char *cp; 9811119Sbill 9826250Sroot for (cp = dblock.dbuf.chksum; 9836250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 9841119Sbill *cp = ' '; 9851119Sbill i = 0; 9861119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 9871119Sbill i += *cp; 9886250Sroot return (i); 9891119Sbill } 9901119Sbill 9911119Sbill checkw(c, name) 9926250Sroot char *name; 9931119Sbill { 9946250Sroot if (!wflag) 9956250Sroot return (1); 9966250Sroot printf("%c ", c); 9976250Sroot if (vflag) 9986250Sroot longt(&stbuf); 9996250Sroot printf("%s: ", name); 10006250Sroot return (response() == 'y'); 10011119Sbill } 10021119Sbill 10031119Sbill response() 10041119Sbill { 10051119Sbill char c; 10061119Sbill 10071119Sbill c = getchar(); 10081119Sbill if (c != '\n') 10096250Sroot while (getchar() != '\n') 10106250Sroot ; 10116250Sroot else 10126250Sroot c = 'n'; 10136250Sroot return (c); 10141119Sbill } 10151119Sbill 101612154Ssam checkf(name, mode, howmuch) 101712154Ssam char *name; 101812154Ssam int mode, howmuch; 101912154Ssam { 102012154Ssam int l; 102112154Ssam 102212154Ssam if ((mode & S_IFMT) == S_IFDIR) 102312154Ssam return (strcmp(name, "SCCS") != 0); 102412154Ssam if ((l = strlen(name)) < 3) 102512154Ssam return (1); 102612154Ssam if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 102712154Ssam return (0); 102812154Ssam if (strcmp(name, "core") == 0 || 102912154Ssam strcmp(name, "errs") == 0 || 103012154Ssam (howmuch > 1 && strcmp(name, "a.out") == 0)) 103112154Ssam return (0); 103212154Ssam /* SHOULD CHECK IF IT IS EXECUTABLE */ 103312154Ssam return (1); 103412154Ssam } 103512154Ssam 10361119Sbill checkupdate(arg) 10376250Sroot char *arg; 10381119Sbill { 10391119Sbill char name[100]; 10406250Sroot long mtime; 10411119Sbill daddr_t seekp; 10421119Sbill daddr_t lookup(); 10431119Sbill 10441119Sbill rewind(tfile); 10451119Sbill for (;;) { 10461119Sbill if ((seekp = lookup(arg)) < 0) 10476250Sroot return (1); 10481119Sbill fseek(tfile, seekp, 0); 10491119Sbill fscanf(tfile, "%s %lo", name, &mtime); 10506250Sroot return (stbuf.st_mtime > mtime); 10511119Sbill } 10521119Sbill } 10531119Sbill 10541119Sbill done(n) 10551119Sbill { 1056*21457Skjd unlink(tname); 10571119Sbill exit(n); 10581119Sbill } 10591119Sbill 10601119Sbill prefix(s1, s2) 10616250Sroot register char *s1, *s2; 10621119Sbill { 10631119Sbill while (*s1) 10641119Sbill if (*s1++ != *s2++) 10656250Sroot return (0); 10661119Sbill if (*s2) 10676250Sroot return (*s2 == '/'); 10686250Sroot return (1); 10691119Sbill } 10701119Sbill 10711119Sbill #define N 200 10721119Sbill int njab; 10736250Sroot 10741119Sbill daddr_t 10751119Sbill lookup(s) 10766250Sroot char *s; 10771119Sbill { 10781119Sbill register i; 10791119Sbill daddr_t a; 10801119Sbill 10811119Sbill for(i=0; s[i]; i++) 10826250Sroot if (s[i] == ' ') 10831119Sbill break; 10841119Sbill a = bsrch(s, i, low, high); 10856250Sroot return (a); 10861119Sbill } 10871119Sbill 10881119Sbill daddr_t 10891119Sbill bsrch(s, n, l, h) 10906250Sroot daddr_t l, h; 10916250Sroot char *s; 10921119Sbill { 10931119Sbill register i, j; 10941119Sbill char b[N]; 10951119Sbill daddr_t m, m1; 10961119Sbill 10971119Sbill njab = 0; 10981119Sbill 10991119Sbill loop: 11006250Sroot if (l >= h) 11016250Sroot return (-1L); 11021119Sbill m = l + (h-l)/2 - N/2; 11036250Sroot if (m < l) 11041119Sbill m = l; 11051119Sbill fseek(tfile, m, 0); 11061119Sbill fread(b, 1, N, tfile); 11071119Sbill njab++; 11081119Sbill for(i=0; i<N; i++) { 11096250Sroot if (b[i] == '\n') 11101119Sbill break; 11111119Sbill m++; 11121119Sbill } 11136250Sroot if (m >= h) 11146250Sroot return (-1L); 11151119Sbill m1 = m; 11161119Sbill j = i; 11171119Sbill for(i++; i<N; i++) { 11181119Sbill m1++; 11196250Sroot if (b[i] == '\n') 11201119Sbill break; 11211119Sbill } 11221119Sbill i = cmp(b+j, s, n); 11236250Sroot if (i < 0) { 11241119Sbill h = m; 11251119Sbill goto loop; 11261119Sbill } 11276250Sroot if (i > 0) { 11281119Sbill l = m1; 11291119Sbill goto loop; 11301119Sbill } 11316250Sroot return (m); 11321119Sbill } 11331119Sbill 11341119Sbill cmp(b, s, n) 11356250Sroot char *b, *s; 11361119Sbill { 11371119Sbill register i; 11381119Sbill 11396250Sroot if (b[0] != '\n') 1140*21457Skjd exit(2); 11411119Sbill for(i=0; i<n; i++) { 11426250Sroot if (b[i+1] > s[i]) 11436250Sroot return (-1); 11446250Sroot if (b[i+1] < s[i]) 11456250Sroot return (1); 11461119Sbill } 11476250Sroot return (b[i+1] == ' '? 0 : -1); 11481119Sbill } 11491119Sbill 1150*21457Skjd readtape (buffer) 11516250Sroot char *buffer; 11521119Sbill { 1153*21457Skjd char *bufp; 1154*21457Skjd int nread; 1155*21457Skjd 1156*21457Skjd readtbuf (&bufp, TBLOCK); 1157*21457Skjd bcopy(bufp, buffer, TBLOCK); 1158*21457Skjd return(TBLOCK); 1159*21457Skjd } 1160*21457Skjd 1161*21457Skjd readtbuf(bufpp, size) 1162*21457Skjd char **bufpp; 1163*21457Skjd int size; 1164*21457Skjd { 11653457Swnj register int i; 11661119Sbill 11671119Sbill if (recno >= nblock || first == 0) { 11688737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 116913492Ssam fprintf(stderr, "tar: tape read error\n"); 11701119Sbill done(3); 11711119Sbill } 11721119Sbill if (first == 0) { 11731119Sbill if ((i % TBLOCK) != 0) { 117413492Ssam fprintf(stderr, "tar: tape blocksize error\n"); 11751119Sbill done(3); 11761119Sbill } 11771119Sbill i /= TBLOCK; 11783457Swnj if (i != nblock) { 117913492Ssam fprintf(stderr, "tar: blocksize = %d\n", i); 11801119Sbill nblock = i; 11811119Sbill } 11821119Sbill } 11831119Sbill recno = 0; 11841119Sbill } 11851119Sbill first = 1; 1186*21457Skjd if (size > ((nblock-recno)*TBLOCK)) 1187*21457Skjd size = (nblock-recno)*TBLOCK; 1188*21457Skjd *bufpp = (char *)&tbuf[recno]; 1189*21457Skjd recno += (size/TBLOCK); 1190*21457Skjd return (size); 11911119Sbill } 11921119Sbill 1193*21457Skjd writetbuf(buffer, n) 1194*21457Skjd register char *buffer; 1195*21457Skjd register int n; 11961119Sbill { 11971119Sbill first = 1; 11981119Sbill if (recno >= nblock) { 1199*21457Skjd if (write(mt, tbuf, TBLOCK*nblock) < 0) { 120013492Ssam fprintf(stderr, "tar: tape write error\n"); 12011119Sbill done(2); 12021119Sbill } 12031119Sbill recno = 0; 12041119Sbill } 1205*21457Skjd 1206*21457Skjd /* 1207*21457Skjd * Special case: We have an empty tape buffer, and the 1208*21457Skjd * users data size is >= the tape block size: Avoid 1209*21457Skjd * the bcopy and dma direct to tape. BIG WIN. Add the 1210*21457Skjd * residual to the tape buffer. 1211*21457Skjd */ 1212*21457Skjd while (recno == 0 && n >= nblock) { 1213*21457Skjd if (write(mt, buffer, TBLOCK*nblock) < 0) { 121413492Ssam fprintf(stderr, "tar: tape write error\n"); 12151119Sbill done(2); 12161119Sbill } 1217*21457Skjd n -= nblock; 1218*21457Skjd buffer += (nblock * TBLOCK); 12191119Sbill } 1220*21457Skjd 1221*21457Skjd while (n-- > 0) { 1222*21457Skjd bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 1223*21457Skjd buffer += TBLOCK; 1224*21457Skjd if (recno >= nblock) { 1225*21457Skjd if (write(mt, tbuf, TBLOCK*nblock) < 0) { 1226*21457Skjd fprintf(stderr, "tar: tape write error\n"); 1227*21457Skjd done(2); 1228*21457Skjd } 1229*21457Skjd recno = 0; 1230*21457Skjd } 1231*21457Skjd } 1232*21457Skjd 1233*21457Skjd /* Tell the user how much to write to get in sync */ 1234*21457Skjd return (nblock - recno); 12351119Sbill } 12361119Sbill 12371119Sbill backtape() 12381119Sbill { 12393457Swnj static int mtdev = 1; 12403457Swnj static struct mtop mtop = {MTBSR, 1}; 12413457Swnj struct mtget mtget; 12423457Swnj 12433457Swnj if (mtdev == 1) 12443457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 12453457Swnj if (mtdev == 0) { 12463457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 124713492Ssam fprintf(stderr, "tar: tape backspace error\n"); 12481119Sbill done(4); 12491119Sbill } 12503457Swnj } else 12513457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 12523457Swnj recno--; 12531119Sbill } 12541119Sbill 12551119Sbill flushtape() 12561119Sbill { 1257*21457Skjd write(mt, tbuf, TBLOCK*nblock); 12581119Sbill } 12591119Sbill 12608737Smckusick bread(fd, buf, size) 12618737Smckusick int fd; 12628737Smckusick char *buf; 12638737Smckusick int size; 12648737Smckusick { 12658737Smckusick int count; 12668737Smckusick static int lastread = 0; 12678737Smckusick 1268*21457Skjd if (!Bflag) 1269*21457Skjd return (read(fd, buf, size)); 12708737Smckusick for (count = 0; count < size; count += lastread) { 12718737Smckusick if (lastread < 0) { 12728737Smckusick if (count > 0) 12738737Smckusick return (count); 12748737Smckusick return (lastread); 12758737Smckusick } 12768737Smckusick lastread = read(fd, buf, size - count); 12778737Smckusick buf += lastread; 12788737Smckusick } 12798737Smckusick return (count); 12808737Smckusick } 128110165Ssam 128210165Ssam char * 128310165Ssam getcwd(buf) 128410165Ssam char *buf; 128510165Ssam { 128610165Ssam 128710165Ssam if (getwd(buf) == NULL) { 128810165Ssam fprintf(stderr, "tar: %s\n", buf); 1289*21457Skjd exit(1); 129010165Ssam } 129110165Ssam return (buf); 129210165Ssam } 1293