[net.bugs.v7] Tar wastes CPU

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-