# vim: filetype=sh

use_mkgnutar=

test_description="create fs image from GNU tarball"
if ! test -x "$DEBUGFS_EXE"; then
	echo "$test_name: $test_description: skipped (no debugfs)"
	return 0
fi
if [ "$(grep -c 'define HAVE_ARCHIVE_H' ../lib/config.h)" -eq 0 ]; then
	echo "$test_name: $test_description: skipped (no libarchive)"
	exit 0
fi

if test -z "$use_mkgnutar" ; then
    if type ztar > /dev/null 2>&1 && \
	    tar --version 2>&1 | head -1 | grep -q "GNU tar" ; then
	TAR=tar
    elif type gtar > /dev/null 2>&1 && \
	    gtar --version 2>&1 | head -1 | grep -q "GNU tar" ; then
	TAR=gtar
    else
	# if GNU tar is not available, fall back to using mkgnutar.pl
	use_mkgnutar=yes
#	echo "$test_name: $test_description: skipped (no GNU tar)"
#	exit 0
    fi
fi

MKFS_TAR="$TMPFILE.tar"
MKFS_DIR="$TMPFILE.dir"
OUT="$test_name.log"
EXP="$test_dir/expect"
DEBUGFS_EXE_MTIME=$(perl -e 'print((stat ($ARGV[0]))[9])' "$DEBUGFS_EXE")

# we put everything in a subdir because we cannot rdump the root as that would
# require permissions to changing ownership of /lost+found
rm -rf "$MKFS_DIR"
mkdir -p "$MKFS_DIR/test"
touch "$MKFS_DIR/test/emptyfile"
dd if=/dev/zero bs=1024 count=32 2> /dev/null | tr '\0' 'a' > "$MKFS_DIR/test/bigfile"
dd if=/dev/zero of="$MKFS_DIR/test/zerofile" bs=1 count=1 seek=1024 2> /dev/null
ln -s /silly_bs_link "$MKFS_DIR/test/silly_bs_link"
mkdir "$MKFS_DIR/test/emptydir"
mkdir "$MKFS_DIR/test/dir"
echo "will be overwritten" > "$MKFS_DIR/test/dir/file"

if test -z "$use_mkgnutar"; then
	# debugfs rdump does not preserve the timestamps when it extracts the
	# files so we ignore them by using tar --clamp-mtime
	# first write a partial tar
    $TAR --sort=name -C "$MKFS_DIR" --mtime="$DEBUGFS_EXE" --clamp-mtime \
	 --format=gnu -cf "$MKFS_TAR.dupl" test
	# now overwrite the contents of a file
	echo "Test me" > "$MKFS_DIR/test/dir/file"
	# and update the tar so that it contains two entries for the same file
	# we need this to test the code path that first unlinks and then overwrites an
	# existing file
	$TAR -C "$MKFS_DIR" --mtime="$DEBUGFS_EXE" --clamp-mtime \
	     --format=gnu -rf "$MKFS_TAR.dupl" test/dir/file
	# also add a duplicate directory entry because those must not be unlinked
	echo test | $TAR -C "$MKFS_DIR" --mtime="$DEBUGFS_EXE" --clamp-mtime \
			 --format=gnu -rf "$MKFS_TAR.dupl" --no-recursion \
			 --verbatim-files-from --files-from=-
	# also create a tarball of the directory with only one entry per file
	$TAR --sort=name -C "$MKFS_DIR" --mtime="$DEBUGFS_EXE" --clamp-mtime \
	     --format=gnu -cf "$MKFS_TAR.uniq" test
else
	# same as above but without using GNU tar
	perl $test_dir/mkgnutar.pl --nopadding --directory="$MKFS_DIR" --mtime "$DEBUGFS_EXE_MTIME" test > "$MKFS_TAR.dupl"
	echo "Test me" > "$MKFS_DIR/test/dir/file"
	perl $test_dir/mkgnutar.pl --nopadding --directory="$MKFS_DIR" --mtime "$DEBUGFS_EXE_MTIME" test/dir/file >> "$MKFS_TAR.dupl"
	perl $test_dir/mkgnutar.pl --nopadding --directory="$MKFS_DIR" --mtime "$DEBUGFS_EXE_MTIME" --no-recursion test/ >> "$MKFS_TAR.dupl"
	# add end-of-archive entry
	truncate -s +1024 "$MKFS_TAR.dupl"
	# pad to a multiple of the record size
	truncate -s %10240 "$MKFS_TAR.dupl"
	perl $test_dir/mkgnutar.pl --directory="$MKFS_DIR" --mtime "$DEBUGFS_EXE_MTIME" test > "$MKFS_TAR.uniq"
fi

rm -r "$MKFS_DIR"

cat > "$TMPFILE.cmd1" << ENDL
stat /test/emptyfile
stat /test/bigfile
stat /test/zerofile
stat /test/silly_bs_link
stat /test/emptydir
stat /test/dir
stat /test/dir/file
ENDL

cat > "$TMPFILE.cmd2" << ENDL
ex /test/emptyfile
ex /test/bigfile
ex /test/zerofile
ex /test/silly_bs_link
ex /test/emptydir
ex /test/dir
ex /test/dir/file
ENDL

# Create two file systems, one for each tar that was created above. The
# tarballs differ but should result in the same filesystem contents
#
for ext in uniq dupl; do
	mkdir "$MKFS_DIR"
	{
		$MKE2FS -q -F -o Linux -T ext4 -O metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -d "$MKFS_TAR.$ext" "$TMPFILE.$ext" 16384 2>&1;
		echo Exit status is $?;
		$DUMPE2FS "$TMPFILE.$ext" 2>&1;
		echo Exit status is $?;
		$DEBUGFS -f "$TMPFILE.cmd1" "$TMPFILE.$ext" 2>&1 | grep -E "(stat|Size:|Type:|Links:|Blockcount:)"
		echo Exit status is $?;
		$DEBUGFS -f "$TMPFILE.cmd2" "$TMPFILE.$ext" 2>&1;
		echo Exit status is $?;
		$DEBUGFS -R "dump /test/dir/file $TMPFILE.testme" "$TMPFILE.$ext" 2>&1;
		echo Exit status is $?;
		# extract the files and directories from the image and tar them
		# again to make sure that a tarball from the image contents is
		# bit-by-bit identical to the tarball the image was created
		# from -- essentially this checks whether a roundtrip from tar
		# to ext4 to tar remains identical
		$DEBUGFS -R "rdump /test $MKFS_DIR" "$TMPFILE.$ext" 2>&1;
		echo Exit status is $?;
		# debugfs rdump does not preserve the timestamps when it extracts the
		if test -z "$use_mkgnutar"; then
			# files so we ignore them by using tar --clamp-mtime
		    $TAR --sort=name -C "$MKFS_DIR" \
			 --mtime="$DEBUGFS_EXE" --clamp-mtime --format=gnu \
			 -cvf "$TMPFILE.new.tar" test 2>&1;
		else
			perl $test_dir/mkgnutar.pl --verbose --directory="$MKFS_DIR" --mtime "$DEBUGFS_EXE_MTIME" test 2>&1 > "$TMPFILE.new.tar";
		fi;
		echo Exit status is $?;
		$FSCK -f -n "$TMPFILE.$ext" 2>&1;
		echo Exit status is $?;
		# independent from which tarball the ext4 image was created,
		# the tarball created from the files in it should be bit-by-bit
		# identical to the tarball without duplicate entries
		cmp "$MKFS_TAR.uniq" "$TMPFILE.new.tar" 2>&1;
		echo Exit status is $?;
	} | sed -f "$cmd_dir/filter.sed" -f "$test_dir/output.sed" -e "s;$TMPFILE.$ext;test.img;" | {
		# In the first pass, store the output and append to the log
		# file. In the second pass, compare the output to the output
		# to the one from the first.
		case $ext in
			uniq) tee "$TMPFILE.log" >> "$OUT";;
			dupl) cmp - "$TMPFILE.log" >> "$OUT" 2>&1 || echo "cmp failed" >> "$OUT";;
		esac
	}
	rm -r "$MKFS_DIR" "$TMPFILE.new.tar"
done

# Do the verification
cmp -s "$OUT" "$EXP"
status=$?

if [ "$status" = 0 ] ; then
	echo "$test_name: $test_description: ok"
	touch "$test_name.ok"
else
	echo "$test_name: $test_description: failed"
	diff $DIFF_OPTS "$EXP" "$OUT" > "$test_name.failed"
fi

rm -rf "$MKFS_TAR.dupl" "$MKFS_TAR.uniq" "$TMPFILE.cmd1" "$TMPFILE.cmd2" \
   "$TMPFILE.log" "$TMPFILE.dupl" "$TMPFILE.uniq" "$TMPFILE.testme"
unset MKFS_TAR MKFS_DIR OUT EXP
