Prof. Dr. Jan Bredereke

Bugfix for Gnu Tar Concerning Multiple Volumes and Reading From Pipes

Please note: The info following below is out of date now. I had contact with the maintainer of Gnu Tar in the mean time. Unfortunately, my bug fix does not fix the problems completely. I hope to find some spare time in the next time to look into the problem again. - If you like, you can take my patch as a starting point four your own fix, of course.


I have discovered and fixed two bugs in tar-1.13.17 (from the SuSE 7.0 Linux edition). In this version, multiple volumes do not work when used together with reading from a pipe, even when using the option --read-full-records to handle short reads from a pipe.

While fixing this bug, I found another one in the source code. It occurs when using multiple volumes together with a block size of one or two.

I posted a fix on January 17, 2001 to bug-tar@gnu.org. I never got a reply, nor found the fix in a new version of tar. Therefore, I now provide it here. Maybe you find it through a search engine.

I wrote a (GNU) makefile that demonstrates both problems. The makefile creates the appropriate test data and then runs tar, printing comments on what it is currently doing. See also the comments at the beginning of the makefile.

Both bugs are in the source file src/buffer.c. The first bug is in the function flush_read(). There is a handling for multi-volume, and there is a handling for short reads due to reading from a pipe (obeying the option --read-full-records). The latter handling jumps to label short_read. But then the multi-volume handling is skipped, so both features cannot be used together.

I have written a fix for the file src/buffer.c and provide a patch for it. The fix introduces the function rmtread_full() and replaces most, but not all, calls to rmtread() in buffer.c by rmtread_full(). This new function retries to read until it gets sufficient data, when read_full_records_option is set, except at EOF.

While fixing this bug, I found that the function flush_read() does not consider that a full record might be shorter than three blocks (i.e., --blocking-factor=1 or 2). It therefore just reads one record and then increments the block cursor up to two times, still expecting data to be left. I fixed this by checking for the amount of data left, when incrementing, and by performing more reads when necessary. The makefile demonstrates this bug, too. With an unpatched version of tar, the tar command crashes already when writing, since the write code does not consider the above case, too. My patch fixes both reading and writing.

Note: the reason to use pipes with multi-volume in the first place was that tar does not stop reading immediately when the specified length of the tape is exhausted. This lead to some ugly device errors with my CD drive. Therefore I used dd to read the right amount of data, and fed it into tar through a pipe.

I found also a third, minor problem with tar: when running ./configure, the file lib/fnmatch.h is not created for my platform, SuSE Linux (presumably correct, since the system provides it). But in the makefile in the src directory, this file is a prerequisite for several targets, nevertheless. Therefore I had to create a symbolic link from the file lib/fnmatch.hno to lib/fnmatch.h to let "make" run smoothly.