dave@onfcanim.UUCP (Dave Martindale) (06/19/86)
Description: The tar tape utility distributed with 4.2BSD (and all the other versions I know of) copies all of the data going to and from the tape from one buffer to another. This is wasteful. It also does its filesystem I/O 512 bytes at a time. If you are handling lots of little files, the copying is only a small part of the total time, but when handling large files it predominates. For example, writing and reading a single 24.6Mb file gives these timings: write read old: 15.2u 99.8s 4:46 20.7u 202.0s 6:34 new: 0.6u 37.3s 3:29 1.1u 57.5s 3:48 These were measured using a 50 IPS 6250 BPI tape drive on the Unibus and Eagle/Emulex/Massbus disk on a 780. With a faster tape drive, the difference in real time would likely be more dramatic. Not only do you get your data faster, but there is more left of your VAX while doing it. (We use tar tapes for images, and have two tape drives reading at once sometimes. Quite a difference). Fix: Make the following changes. The diffs are relative to the tar.c on the 4.2BSD distribution tape, which probably hasn't changed too much since v7. The major part of this is adding routines to read and write files directly into/out of the tape buffer. It also takes care not to copy data it is going to throw away while skipping a file. Most of the rest of the changes just make tar pass lint. (You lint something after working on it, don't you?) Dave Martindale watmath!onfcanim!dave ================================================================= *** otar.c Wed Jun 18 20:51:57 1986 --- tar.c Wed Jun 18 22:51:26 1986 *************** *** 14,19 #include <sys/time.h> #include <signal.h> #include <errno.h> #define TBLOCK 512 #define NBLOCK 20 --- 14,20 ----- #include <sys/time.h> #include <signal.h> #include <errno.h> + extern errno; #define TBLOCK 512 #define NBLOCK 20 *************** *** 81,86 FILE *tfile; char tname[] = "/tmp/tarXXXXXX"; char *usefile; char magtape[] = "/dev/rmt8"; char *malloc(); --- 82,88 ----- FILE *tfile; char tname[] = "/tmp/tarXXXXXX"; + char *mktemp(); char *usefile; char magtape[] = "/dev/rmt8"; char *malloc(); *************** *** 85,91 char magtape[] = "/dev/rmt8"; char *malloc(); char *sprintf(); - char *strcat(); char *rindex(); char *getcwd(); char *getwd(); --- 87,92 ----- char magtape[] = "/dev/rmt8"; char *malloc(); char *sprintf(); char *rindex(); char *strcpy(); char *getcwd(); *************** *** 87,92 char *sprintf(); char *strcat(); char *rindex(); char *getcwd(); char *getwd(); --- 88,94 ----- char *malloc(); char *sprintf(); char *rindex(); + char *strcpy(); char *getcwd(); char *getwd(); *************** *** 219,225 if (!rflag && !xflag && !tflag) usage(); ! tbuf = (union hblock *)malloc(nblock*TBLOCK); if (tbuf == NULL) { fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", nblock); --- 221,227 ----- if (!rflag && !xflag && !tflag) usage(); ! tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); if (tbuf == NULL) { fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", nblock); *************** *** 247,253 mt = dup(1); nblock = 1; } else if ((mt = open(usefile, 2)) < 0) { ! if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { fprintf(stderr, "tar: cannot open %s\n", usefile); done(1); --- 249,256 ----- mt = dup(1); nblock = 1; } else if ((mt = open(usefile, 2)) < 0) { ! if (errno != ENOENT || cflag == 0 || ! (mt = creat(usefile, 0666)) < 0) { fprintf(stderr, "tar: cannot open %s\n", usefile); done(1); *************** *** 388,394 passtape() { long blocks; - char buf[TBLOCK]; if (dblock.dbuf.linkflag == '1') return; --- 391,396 ----- passtape() { long blocks; if (dblock.dbuf.linkflag == '1') return; *************** *** 397,403 blocks /= TBLOCK; while (blocks-- > 0) ! readtape(buf); } putfile(longname, shortname, parent) --- 399,405 ----- blocks /= TBLOCK; while (blocks-- > 0) ! readtape((char *)0); } putfile(longname, shortname, parent) *************** *** 407,414 { int infile = 0; long blocks; ! char buf[TBLOCK]; ! register char *cp, *cp2; struct direct *dp; DIR *dirp; int i, j; --- 409,416 ----- { int infile = 0; long blocks; ! char buf[NAMSIZ+64]; ! register char *cp; struct direct *dp; DIR *dirp; long i; *************** *** 411,417 register char *cp, *cp2; struct direct *dp; DIR *dirp; ! int i, j; char newparent[NAMSIZ+64]; extern int errno; --- 413,419 ----- register char *cp; struct direct *dp; DIR *dirp; ! long i; char newparent[NAMSIZ+64]; extern int errno; *************** *** 438,444 return; if (checkw('r', longname) == 0) return; ! if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) return; switch (stbuf.st_mode & S_IFMT) { --- 440,446 ----- return; if (checkw('r', longname) == 0) return; ! if (Fflag && checkf(shortname, (int)stbuf.st_mode, Fflag) == 0) return; switch (stbuf.st_mode & S_IFMT) { *************** *** 476,484 while ((dp = readdir(dirp)) != NULL && !term) { if (dp->d_ino == 0) continue; ! if (!strcmp(".", dp->d_name) || ! !strcmp("..", dp->d_name)) ! continue; strcpy(cp, dp->d_name); i = telldir(dirp); closedir(dirp); --- 478,487 ----- while ((dp = readdir(dirp)) != NULL && !term) { if (dp->d_ino == 0) continue; ! if (*dp->d_name == '.') ! if (!strcmp(".", dp->d_name) || ! !strcmp("..", dp->d_name)) ! continue; strcpy(cp, dp->d_name); i = telldir(dirp); closedir(dirp); *************** *** 532,537 if (strlen(longname) >= NAMSIZ) { fprintf(stderr, "tar: %s: file name too long\n", longname); return; } strcpy(dblock.dbuf.name, longname); --- 535,541 ----- if (strlen(longname) >= NAMSIZ) { fprintf(stderr, "tar: %s: file name too long\n", longname); + close(infile); return; } strcpy(dblock.dbuf.name, longname); *************** *** 536,542 } strcpy(dblock.dbuf.name, longname); if (stbuf.st_nlink > 1) { ! struct linkbuf *lp; int found = 0; for (lp = ihead; lp != NULL; lp = lp->nextp) --- 540,546 ----- } strcpy(dblock.dbuf.name, longname); if (stbuf.st_nlink > 1) { ! register struct linkbuf *lp; int found = 0; for (lp = ihead; lp != NULL; lp = lp->nextp) *************** *** 583,594 sprintf(dblock.dbuf.chksum, "%6o", checksum()); writetape((char *)&dblock); ! while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { ! writetape(buf); ! blocks--; ! } ! close(infile); ! if (blocks != 0 || i != 0) fprintf(stderr, "tar: %s: file changed size\n", longname); while (--blocks >= 0) --- 587,593 ----- sprintf(dblock.dbuf.chksum, "%6o", checksum()); writetape((char *)&dblock); ! if (writefile((long)stbuf.st_size, infile)) fprintf(stderr, "tar: %s: file changed size\n", longname); close(infile); *************** *** 591,598 if (blocks != 0 || i != 0) fprintf(stderr, "tar: %s: file changed size\n", longname); ! while (--blocks >= 0) ! putempty(); break; default: --- 590,596 ----- if (writefile((long)stbuf.st_size, infile)) fprintf(stderr, "tar: %s: file changed size\n", longname); ! close(infile); break; default: *************** *** 606,612 char *argv[]; { long blocks, bytes; - char buf[TBLOCK]; char **cp; int ofile; --- 604,609 ----- char *argv[]; { long blocks, bytes; char **cp; int ofile; *************** *** 634,640 s = dblock.dbuf.name; else s++; ! if (checkf(s, stbuf.st_mode, Fflag) == 0) { passtape(); continue; } --- 631,637 ----- s = dblock.dbuf.name; else s++; ! if (checkf(s, (int)stbuf.st_mode, Fflag) == 0) { passtape(); continue; } *************** *** 680,686 dblock.dbuf.name, dblock.dbuf.linkname); continue; } ! if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { fprintf(stderr, "tar: %s - cannot create\n", dblock.dbuf.name); passtape(); --- 677,684 ----- dblock.dbuf.name, dblock.dbuf.linkname); continue; } ! if ((ofile = creat(dblock.dbuf.name, ! (int)stbuf.st_mode&0xfff)) < 0) { fprintf(stderr, "tar: %s - cannot create\n", dblock.dbuf.name); passtape(); *************** *** 691,714 if (vflag) fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", dblock.dbuf.name, bytes, blocks); ! for (; blocks-- > 0; bytes -= TBLOCK) { ! readtape(buf); ! if (bytes > TBLOCK) { ! if (write(ofile, buf, TBLOCK) < 0) { ! fprintf(stderr, ! "tar: %s: HELP - extract write error\n", ! dblock.dbuf.name); ! done(2); ! } ! continue; ! } ! if (write(ofile, buf, (int) bytes) < 0) { ! fprintf(stderr, ! "tar: %s: HELP - extract write error\n", ! dblock.dbuf.name); ! done(2); ! } ! } close(ofile); if (mflag == 0) { struct timeval tv[2]; --- 689,695 ----- if (vflag) fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", dblock.dbuf.name, bytes, blocks); ! readfile(bytes, ofile); close(ofile); if (mflag == 0) { struct timeval tv[2]; *************** *** 712,717 close(ofile); if (mflag == 0) { struct timeval tv[2]; tv[0].tv_sec = time(0); tv[0].tv_usec = 0; --- 693,699 ----- close(ofile); if (mflag == 0) { struct timeval tv[2]; + time_t time(); tv[0].tv_sec = time((time_t *)0); tv[0].tv_usec = 0; *************** *** 713,719 if (mflag == 0) { struct timeval tv[2]; ! tv[0].tv_sec = time(0); tv[0].tv_usec = 0; tv[1].tv_sec = stbuf.st_mtime; tv[1].tv_usec = 0; --- 695,701 ----- struct timeval tv[2]; time_t time(); ! tv[0].tv_sec = time((time_t *)0); tv[0].tv_usec = 0; tv[1].tv_sec = stbuf.st_mtime; tv[1].tv_usec = 0; *************** *** 720,726 utimes(dblock.dbuf.name, tv); } if (pflag) ! chmod(dblock.dbuf.name, stbuf.st_mode & 07777); } } --- 702,708 ----- utimes(dblock.dbuf.name, tv); } if (pflag) ! chmod(dblock.dbuf.name, (int)(stbuf.st_mode & 07777)); } } *************** *** 757,764 char *ctime(); pmode(st); ! printf("%3d/%1d", st->st_uid, st->st_gid); ! printf("%7D", st->st_size); cp = ctime(&st->st_mtime); printf(" %-12.12s %-4.4s ", cp+4, cp+20); } --- 739,746 ----- char *ctime(); pmode(st); ! printf("%3d/%-2d", st->st_uid, st->st_gid); ! printf("%9D", st->st_size); cp = ctime(&st->st_mtime); printf(" %-12.12s %-4.4s ", cp+4, cp+20); } *************** *** 793,799 register int **mp; for (mp = &m[0]; mp < &m[9];) ! select(*mp++, st); } select(pairp, st) --- 775,781 ----- register int **mp; for (mp = &m[0]; mp < &m[9];) ! mselect(*mp++, st); } mselect(pairp, st) *************** *** 796,802 select(*mp++, st); } ! select(pairp, st) int *pairp; struct stat *st; { --- 778,784 ----- mselect(*mp++, st); } ! mselect(pairp, st) int *pairp; struct stat *st; { *************** *** 841,847 } chown(name, stbuf.st_uid, stbuf.st_gid); if (pflag && cp[1] == '\0') ! chmod(name, stbuf.st_mode & 0777); } *cp = '/'; } --- 823,829 ----- } chown(name, stbuf.st_uid, stbuf.st_gid); if (pflag && cp[1] == '\0') ! chmod(name, (int)(stbuf.st_mode & 0777)); } *cp = '/'; } *************** *** 866,871 term++; } onterm() { signal(SIGTERM, SIG_IGN); --- 848,854 ----- term++; } + #ifdef notdef onterm() { signal(SIGTERM, SIG_IGN); *************** *** 871,876 signal(SIGTERM, SIG_IGN); term++; } tomodes(sp) register struct stat *sp; --- 854,860 ----- signal(SIGTERM, SIG_IGN); term++; } + #endif tomodes(sp) register struct stat *sp; *************** *** 892,899 register char *cp; for (cp = dblock.dbuf.chksum; ! cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) ! *cp = ' '; i = 0; for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) i += *cp; --- 876,883 ----- register char *cp; for (cp = dblock.dbuf.chksum; ! cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; ) ! *cp++ = ' '; i = 0; for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; ) i += *cp++; *************** *** 895,902 cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) *cp = ' '; i = 0; ! for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) ! i += *cp; return (i); } --- 879,886 ----- cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; ) *cp++ = ' '; i = 0; ! for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; ) ! i += *cp++; return (i); } *************** *** 914,920 response() { ! char c; c = getchar(); if (c != '\n') --- 898,904 ----- response() { ! int c; c = getchar(); if (c != '\n') *************** *** 985,991 daddr_t lookup(s) ! char *s; { register i; daddr_t a; --- 969,975 ----- daddr_t lookup(s) ! register char *s; { register i; *************** *** 988,994 char *s; { register i; - daddr_t a; for(i=0; s[i]; i++) if (s[i] == ' ') --- 972,977 ----- register char *s; { register i; for(i=0; s[i]; i++) if (s[i] == ' ') *************** *** 993,1000 for(i=0; s[i]; i++) if (s[i] == ' ') break; ! a = bsrch(s, i, low, high); ! return (a); } daddr_t --- 976,982 ----- for(i=0; s[i]; i++) if (s[i] == ' ') break; ! return bsrch(s, i, low, high); } daddr_t *************** *** 1044,1050 } cmp(b, s, n) ! char *b, *s; { register i; --- 1026,1032 ----- } cmp(b, s, n) ! register char *b, *s; { register i; *************** *** 1062,1068 readtape(buffer) char *buffer; { ! register int i; if (recno >= nblock || first == 0) { if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { --- 1044,1050 ----- readtape(buffer) char *buffer; { ! register int want, i; if (recno >= nblock || first == 0) { want = TBLOCK*nblock; *************** *** 1065,1077 register int i; if (recno >= nblock || first == 0) { ! if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { ! fprintf(stderr, "tar: tape read error\n"); ! done(3); ! } ! if (first == 0) { ! if ((i % TBLOCK) != 0) { ! fprintf(stderr, "tar: tape blocksize error\n"); done(3); } i /= TBLOCK; --- 1047,1079 ----- register int want, i; if (recno >= nblock || first == 0) { ! want = TBLOCK*nblock; ! if ((i = bread(mt, (char *)tbuf, want)) != want) { ! if (i > 0) { ! if (first == 0) { ! if ((i % TBLOCK) != 0) { ! fprintf(stderr, ! "tar: tape blocksize error\n"); ! done(3); ! } ! i /= TBLOCK; ! if (i != nblock) { ! if (vflag) ! fprintf(stderr, ! "tar: blocksize = %d\n", i); ! nblock = i; ! } ! } else { ! ! fprintf(stderr, ! "tar: short read, got %d wanted %d\n", ! i, want); ! done(3); ! } ! } else { ! fprintf(stderr, "tar: %s\n", ! i < 0 ? "tape read error" : ! "unexpected EOF"); done(3); } } *************** *** 1074,1084 fprintf(stderr, "tar: tape blocksize error\n"); done(3); } - i /= TBLOCK; - if (i != nblock) { - fprintf(stderr, "tar: blocksize = %d\n", i); - nblock = i; - } } recno = 0; } --- 1076,1081 ----- "unexpected EOF"); done(3); } } recno = 0; } *************** *** 1083,1089 recno = 0; } first = 1; ! bcopy((char *)&tbuf[recno++], buffer, TBLOCK); return (TBLOCK); } --- 1080,1088 ----- recno = 0; } first = 1; ! if (buffer != (char *)0) ! bcopy((char *)&tbuf[recno], buffer, TBLOCK); ! recno++; return (TBLOCK); } *************** *** 1087,1092 return (TBLOCK); } writetape(buffer) char *buffer; { --- 1086,1130 ----- return (TBLOCK); } + readfile(bytes, file) + long bytes; + int file; + { + register int i, avail, nbytes; + register char *where; + + where = (char *)&tbuf[recno]; + avail = (nblock - recno) * TBLOCK; + while (bytes > 0) { + if (avail <= 0) { + nbytes = TBLOCK*nblock; + if ((i = bread(mt, (char *)tbuf, nbytes)) != nbytes) { + if (i > 0) + fprintf(stderr, + "tar: short read, got %d wanted %d\n", + i, nbytes); + else + fprintf(stderr, "tar: %s\n", + i < 0 ? "tape read error" : + "unexpected EOF"); + done(3); + } + avail = nbytes; + where = (char *)tbuf; + } + nbytes = avail; + if (bytes < nbytes) + nbytes = bytes; + if (write(file, where, (int)nbytes) != nbytes) { + perror(dblock.dbuf.name); + done(2); + } + bytes -= nbytes; + avail -= nbytes; + } + recno = nblock - (avail/TBLOCK); + } + writetape(buffer) char *buffer; { *************** *** 1092,1098 { first = 1; if (recno >= nblock) { ! if (write(mt, tbuf, TBLOCK*nblock) < 0) { fprintf(stderr, "tar: tape write error\n"); done(2); } --- 1130,1136 ----- { first = 1; if (recno >= nblock) { ! if (write(mt, (char *)tbuf, TBLOCK*nblock) < 0) { fprintf(stderr, "tar: tape write error\n"); done(2); } *************** *** 1099,1104 recno = 0; } bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); if (recno >= nblock) { if (write(mt, tbuf, TBLOCK*nblock) < 0) { fprintf(stderr, "tar: tape write error\n"); --- 1137,1144 ----- recno = 0; } bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); + #if 0 + /* why is this being done again? -dmm */ if (recno >= nblock) { if (write(mt, tbuf, TBLOCK*nblock) < 0) { fprintf(stderr, "tar: tape write error\n"); *************** *** 1106,1111 } recno = 0; } return (TBLOCK); } --- 1146,1152 ----- } recno = 0; } + #endif return (TBLOCK); } *************** *** 1109,1114 return (TBLOCK); } backtape() { static int mtdev = 1; --- 1150,1199 ----- return (TBLOCK); } + writefile(bytes, file) + long bytes; + int file; + { + register int avail, nbytes, i; + register char *where; + int eof = 0; + char junk; + + where = (char *)&tbuf[recno]; + avail = (nblock - recno) * TBLOCK; + while (bytes > 0) { + if (avail <= 0) { + nbytes = TBLOCK*nblock; + if (write(mt, (char *)tbuf, nbytes) != nbytes) { + perror("tape write error"); + done(2); + } + avail = nbytes; + where = (char *)tbuf; + } + nbytes = avail; + if (bytes < nbytes) + nbytes = bytes; + if (eof) + bzero(where, nbytes); + else if ((i = read(file, where, nbytes)) != nbytes) { + if (i < 0) { + perror(dblock.dbuf.name); + done(2); + } + eof = 1; + bzero(where + i, nbytes - i); + } + bytes -= nbytes; + avail -= nbytes; + } + recno = nblock - (avail/TBLOCK); + + if (eof || read(file, &junk, sizeof(junk)) != 0) + return (1); + return (0); + } + backtape() { static int mtdev = 1; *************** *** 1116,1122 struct mtget mtget; if (mtdev == 1) ! mtdev = ioctl(mt, MTIOCGET, &mtget); if (mtdev == 0) { if (ioctl(mt, MTIOCTOP, &mtop) < 0) { fprintf(stderr, "tar: tape backspace error\n"); --- 1201,1207 ----- struct mtget mtget; if (mtdev == 1) ! mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); if (mtdev == 0) { if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { fprintf(stderr, "tar: tape backspace error\n"); *************** *** 1118,1124 if (mtdev == 1) mtdev = ioctl(mt, MTIOCGET, &mtget); if (mtdev == 0) { ! if (ioctl(mt, MTIOCTOP, &mtop) < 0) { fprintf(stderr, "tar: tape backspace error\n"); done(4); } --- 1203,1209 ----- if (mtdev == 1) mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); if (mtdev == 0) { ! if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { fprintf(stderr, "tar: tape backspace error\n"); done(4); } *************** *** 1123,1129 done(4); } } else ! lseek(mt, (long) -TBLOCK*nblock, 1); recno--; } --- 1208,1214 ----- done(4); } } else ! lseek(mt, (off_t) -TBLOCK*nblock, 1); recno--; } *************** *** 1129,1135 flushtape() { ! write(mt, tbuf, TBLOCK*nblock); } bread(fd, buf, size) --- 1214,1223 ----- flushtape() { ! if (write(mt, (char *)tbuf, TBLOCK*nblock) < 0) { ! fprintf(stderr, "tape write error"); ! exit(2); ! } } bread(fd, buf, size)
dpk@mcvax.uucp (Doug Kingston) (06/24/86)
I posted a similar fix well over two years ago. My changes are in 4.3BSD. -Doug-