#
# demonstrate two bugs in GNU tar.
#
# make file for GNU make: it creates all necessary test data files
# and then runs the bug demonstration.
#
# brief overview:
# we create two files, file1 and file2, and roll them into a
# multi-volume tar ball, consisting of two tar files t1-pipe.tar and
# t2-pipe.tar. This works still fine. We then extract them again into a
# sub-directory, called extract-dir-pipe. This would work fine if we
# would just read from the above tar files. But we make it a bit
# harder and read the data through a pipe (correctly using the
# option --read-full-records). This breaks when we start to read the
# second tar file. The file file2 spans both volumes, and it is
# reconstructed wrongly. The first part from the first volume is
# still fine, but the continuation starts 1024 bytes too early and
# therefore includes the header of the second tar volume. The size
# of the file is correct, though, so that some data at the end of
# the reconstructed file2 is missing, due to the insertion of the
# 1024 bytes of header data.
#
# It does not matter whether the first tar volume is read via pipe
# or directly from a file.
#
# The bug is in the source file src/buffer.c, 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.
#
# The second bug occurs when using multiple volumes with small block
# sizes (even on ordinary tar files). When writing the second volume,
# tar accesses memory outside of its write buffer and crashes. The
# same thing would also happen when reading, tar reads from memory
# without checking whether it has to fetch more data first.
#
# author: Jan Bredereke, January 2001
#

# which tar to use:
TAR=tar
#TAR=/bin/tar
#TAR=/usr/local/bin/tar

# the following lengths are in n * 1024 bytes.
TAPE_LENGTH=10
FILE_OVERLAP=3
#FILE1_LENGTH=$(shell echo $$(($(TAPE_LENGTH) - $(FILE_OVERLAP))))
FILE1_LENGTH=7

all:
	@echo "Run either"
	@echo "    $(MAKE) test-pipe"
	@echo "or"
	@echo "    $(MAKE) test-blocksize"
	@echo "To clean up afterwards, run"
	@echo "    $(MAKE) clean"

test-pipe: file1 file2
	@echo "####Demo for multi-volume / pipe bug:"
	ls -l file1 file2
	@echo "####Creating a multi-volume tar archive:"
	$(TAR) -c -v --multi-volume --tape-length=$(TAPE_LENGTH) \
	    --listed-incremental=t.snar \
	    -f t1-pipe.tar -f t2-pipe.tar ./file1 ./file2
	ls -l t?-pipe.tar
	@echo "####Creating a pipe to read through:"
#	mkfifo pipe1
	mkfifo pipe2
	@echo "####Starting to read data into the pipe:"
#	dd if=t1-pipe.tar bs=1024 count=$(TAPE_LENGTH) of=pipe1 &
	dd if=t2-pipe.tar bs=4096 count=$(TAPE_LENGTH) of=pipe2 &
	sleep 2
	@echo "####Making the directory to extract into:"
	mkdir extract-dir-pipe
	@echo "####Extracting from the multi-volume tar archive:"
	-cd extract-dir-pipe ; \
	$(TAR) -x -v --multi-volume --tape-length=$(TAPE_LENGTH) \
	    --read-full-records \
	    -f ../t1-pipe.tar -f ../pipe2
	ls -l extract-dir-pipe
	@echo "####Checking the extracted files for changes:"
	cmp -s file1 extract-dir-pipe/file1
	diff file2 extract-dir-pipe/file2

test-blocksize: file1 file2
	@echo "####Demo for multi-volume / block size bug:"
	ls -l file1 file2
	@echo "####Creating a multi-volume tar archive with block size 1:"
	$(TAR) -c -v --multi-volume --tape-length=$(TAPE_LENGTH) \
	    --listed-incremental=t.snar --blocking-factor=1 \
	    --label=FooLabel \
	    -f t1-block.tar -f t2-block.tar ./file1 ./file2
	ls -l t?-block.tar
	@echo "####Making the directory to extract into:"
	mkdir extract-dir-block
	@echo "####Extracting from the multi-volume tar archive:"
	-cd extract-dir-block ; \
	$(TAR) -x -v --multi-volume --blocking-factor=1 \
	    --label=FooLabel \
	    -f ../t1-block.tar -f ../t2-block.tar
	ls -l extract-dir-block
	@echo "####Checking the extracted files for changes:"
	cmp -s file1 extract-dir-block/file1
	diff file2 extract-dir-block/file2

file1:
	@echo "####Creating $@ of $(FILE1_LENGTH) * 1024 bytes of zeroes:"
	dd if=/dev/zero bs=1024 count=$(FILE1_LENGTH) of=$@

file2:
	@echo "####Creating $@ of size 8192 with a well recognizable pattern:"
	rm -f $@
	for block in " 1" " 2" " 3" " 4" " 5" " 6" " 7" " 8" \
	              " 9" "10" "11" "12" "13" "14" "15" "16" ; do \
	    echo "$@  block $${block} bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla" >> $@ ; \
	    for count in 2 3 4 5 6 7 8 ; do \
		echo "bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla" >> $@ ; \
	    done ; \
	done

clean:
	@echo "####Cleaning away all generated data:"
	rm -f file1 file2
	rm -f t1-pipe.tar t2-pipe.tar t.snar pipe1 pipe2
	rm -f t1-block.tar t2-block.tar
	rm -r -f extract-dir-pipe extract-dir-block
