Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/5/84; site ur-cvsvax.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!rochester!ur-cvsvax!bill From: bill@ur-cvsvax.UUCP (Bill Vaughn) Newsgroups: net.bugs Subject: Tar EOT bug and fix Message-ID: <179@ur-cvsvax.UUCP> Date: Tue, 19-Mar-85 17:05:12 EST Article-I.D.: ur-cvsva.179 Posted: Tue Mar 19 17:05:12 1985 Date-Received: Thu, 21-Mar-85 02:34:37 EST Distribution: net Organization: Center for Visual Science, U. of Rochester Lines: 109 After several people ran tape reels on the end of the drive with tar over the last few months, it became clear that tar wasn't dealing with the EOT mark properly. I know, I know, nobody should use a whole tape, but some persons have VERY large files which I am happy to see archived, and anything to makes life easier for them makes it easier for me. (Rewinding spun-off reels is a pain too.) Tar should be more robust in principle anyway. The problem is the 'write' in the 'writetape' routine. It assumes errors have occured ONLY when 'write' returns a negative value. But tests (and looking at code) confirm that 'write' returns a 0 when the tape driver hits EOT. It's telling a lie, of course, because the record really was written. The fix is easy. Just have tar's 'write' check that the # bytes requested == # bytes written. If not, we either have a write error or are at EOT. In the latter case one can even write out a zeroed block to keep subsequent 'reads' happy. (Tests also confirmed that 'reads' across EOT's don't return errors. They return the actual record that 'write' denied it had written. If it makes any difference, we have a 750 with a TU-80. The driver is /sys/vaxuba/ts.c) 'Tar' has had several fixes and enhancements since the original distribution so I'm only giving the context diff relative to the original 4.2bsd version. Fixes for other versions are very similar. *** tar.org.c --- tar.fix.c Tue Mar 19 16:25:19 1985 *************** *** 1092,1101 { first = 1; if (recno >= nblock) { ! if (write(mt, tbuf, TBLOCK*nblock) < 0) { ! fprintf(stderr, "tar: tape write error\n"); ! done(2); ! } recno = 0; } bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); --- 1092,1098 ----- { first = 1; if (recno >= nblock) { ! flushtape(); recno = 0; } bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); *************** *** 1100,1109 } bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); if (recno >= nblock) { ! if (write(mt, tbuf, TBLOCK*nblock) < 0) { ! fprintf(stderr, "tar: tape write error\n"); ! done(2); ! } recno = 0; } return (TBLOCK); --- 1097,1103 ----- } bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); if (recno >= nblock) { ! flushtape(); recno = 0; } return (TBLOCK); *************** *** 1129,1135 flushtape() { ! write(mt, tbuf, TBLOCK*nblock); } bread(fd, buf, size) --- 1123,1147 ----- flushtape() { ! register int n; ! ! if ((n=write(mt, tbuf, TBLOCK*nblock)) != TBLOCK*nblock) { ! if (n) ! fprintf(stderr, "tar: tape write error\n"); ! else ! fprintf(stderr, "tar: EOT mark encountered. "); ! /* ! * With a little work one could decide if the ! * following is really true. Be conservative. ! */ ! fprintf(stderr, "Last file is incomplete.\n"); ! /* ! * The following keeps subsequent reads happy. ! */ ! bzero(tbuf, TBLOCK*nblock); ! write(mt, tbuf, TBLOCK*nblock); ! done(2); ! } } bread(fd, buf, size) *********************** Bill Vaughn, UNIV. OF ROCHESTER, Center for Visual Science, Rochester NY {allegra,seismo,decvax}!rochester!ur-cvsvax!bill