#!/bin/bash

[ -f testing.sh ] && . testing.sh

#testing "name" "command" "result" "infile" "stdin"

# For reproducibility: UTC and umask 0002

OLDTZ="$TZ"
export TZ=utc
OLDUMASK=$(umask)
umask 0002

# 255 bytes, longest VFS name
LONG=0123456789abcdef0123456789abcdef
LONG=$LONG$LONG$LONG$LONG$LONG$LONG$LONG$LONG
LONG=${LONG:1:255}

# Reproducible tarballs: override ownership and timestamp. Also amount of
# trailing NUL padding varies (1024 bytes is minimum, gnu/dammit does more)
# so look at first 3 512-byte frames when analyzing header content.

TAR='tar c --owner root --group root --mtime @1234567890'
export BLOCKS=3
SUM='head -c $(($BLOCKS*512)) | sha1sum | sed "s/ .*//"'
[ -n "$TARHD" ] && SUM="tee >(hd >&2) | $SUM"

function LST()
{
  tar tv $LSTARG | sed "s/[ \t][ \t]*/ /g"
}

touch file
testing "create file" "$TAR file | $SUM" \
  "fecaecba936e604bb115627a6ef4db7c7a3a8f81\n" "" ""

testing "pass file" "$TAR file | LST" \
  "-rw-rw-r-- root/root 0 2009-02-13 23:31 file\n" "" ""

# The kernel has two hardwired meaningful UIDs: 0 (root) and 65534 (nobody).
# (Technically changeable via /proc/sys/*/overflowuid but nobody ever does)
skipnot id nobody >/dev/null
testing "pass user" "tar -c --owner nobody --group root --mtime @0 file | LST" \
  "-rw-rw-r-- nobody/root 0 1970-01-01 00:00 file\n" "" ""
skipnot grep nobody /etc/group >/dev/null
testing "pass group" "tar c --owner root --group nobody --mtime @0 file | LST" \
  "-rw-rw-r-- root/nobody 0 1970-01-01 00:00 file\n" "" ""

touch -t 198701231234.56 file
LSTARG=--full-time testing "pass mtime" \
  "tar c --owner root --group root file | LST" \
  "-rw-rw-r-- root/root 0 1987-01-23 12:34:56 file\n" "" ""

mkdir dir
testing "create dir" "$TAR dir | $SUM" \
  "05739c423d7d4a7f12b3dbb7c94149acb2bb4f8d\n" "" ""

testing "pass dir" "$TAR dir | LST" \
  "drwxrwxr-x root/root 0 2009-02-13 23:31 dir/\n" "" ""

# note: does _not_ include dir entry in archive, just file
touch dir/file
testing "create file in dir" "$TAR dir/file | $SUM" \
  "2d7b96c7025987215f5a41f10eaa84311160afdb\n" "" ""

# Tests recursion without worrying about content order
testing "create dir and dir/file" "$TAR dir | $SUM" \
  "0bcc8005a3e07eb63c9b735267aecc5b774795d7\n" "" ""

testing "pass dir/file" "$TAR dir | LST" \
  "drwxrwxr-x root/root 0 2009-02-13 23:31 dir/\n-rw-rw-r-- root/root 0 2009-02-13 23:31 dir/file\n" "" ""

echo boing > dir/that
testing "tar C" "$TAR -C dir that | $SUM" \
  "f0deff71bf4858eb0c5f49d99d052f12f1831feb\n" "" ""

# / and .. only stripped from name, not symlink target.
ln -s ../name.././.. dir/link
testing "create symlink" "$TAR dir/link | $SUM" \
  "7324cafbd9aeec5036b6efc54d741f11528aeb10\n" "" ""

# Also two explicit targets
ln dir/file dir/hardlink
testing "create hardlink" "$TAR dir/file dir/hardlink | $SUM" \
  "c5383651f8c03ec0fe15e8a9e28a4e8e5273990d\n" "" ""

ln dir/link dir/hlink
testing "create hardlink to symlink" "$TAR dir/link dir/hlink | $SUM" \
  "3bc16f8fb6fc8b05f691da8caf989a70ee99284a\n" "" ""

skipnot mkfifo dir/fifo
testing "create dir/fifo" "$TAR dir/fifo | $SUM" \
  "bd1365db6e8ead4c813333f9666994c1899924d9\n" "" ""

# test L and K records

# 4+96=100 (biggest short name), 4+97=101 (shortest long name)
touch dir/${LONG:1:96} dir/${LONG:1:97}
testing "create long fname" "$TAR dir/${LONG:1:97} dir/${LONG:1:96} | $SUM" \
  "99348686fe9c9bf80f5740f1fc0c6f32f2021e3d\n" "" ""

ln -s dir/${LONG:1:96} dir/lshort
ln -s dir/${LONG:1:97} dir/llong
testing "create long symlnk" "$TAR dir/lshort dir/llong | $SUM" \
  "8a5d652dc85f252a2e3b3f47d1ecd699e98a5f4b\n" "" ""

ln -s $LONG dir/${LONG:5}
BLOCKS=7 testing "create long->long" "$TAR dir/${LONG:5} | $SUM" \
  "543116b8e690a116a559ab5b673f9b6d6601c925\n" "" ""
# absolute and relative link names, broken and not

ln -s file dir/linkok
testing "create symlink" "$TAR dir/linkok | $SUM" \
  "55652846506cf0a9d43b3ef03ccf9e98123befaf\n" "" ""

ln -s /dev/null dir/linknull
testing "pass absolute symlink" "$TAR dir/linknull | LST" \
  "lrwxrwxrwx root/root 0 2009-02-13 23:31 dir/linknull -> /dev/null\n" "" ""

ln -s rel/broken dir/relbrok
testing "pass broken symlink" "$TAR dir/relbrok | LST" \
  "lrwxrwxrwx root/root 0 2009-02-13 23:31 dir/relbrok -> rel/broken\n" "" ""

ln -s /does/not/exist dir/linkabsbrok
testing "pass broken absolute symlink" "$TAR dir/linkabsbrok | LST" \
  "lrwxrwxrwx root/root 0 2009-02-13 23:31 dir/linkabsbrok -> /does/not/exist\n" \
  "" ""

# this expects devtmpfs values

testing "pass /dev/null" \
  "tar c --mtime @0 /dev/null 2>/dev/null | LST" \
  "crw-rw-rw- root/root 1,3 1970-01-01 00:00 dev/null\n" "" ""

testing "pass /dev/loop0" \
  "tar c --numeric-owner --mtime @0 /dev/loop0 2>/dev/null | LST" \
  "brw-rw---- 0/6 7,0 1970-01-01 00:00 dev/loop0\n" "" ""

# compression types
testing "autodetect gzip" \
  'tar tvf $FILES/tar/tar.tgz | sed "s/[ \t][ \t]*/ /g"' \
  "drwxr-x--- enh/eng 0 2017-05-13 01:05 dir/\n-rw-r----- enh/eng 12 2017-05-13 01:05 dir/file\n" \
  "" ""

skipnot mknod dir/char c 12 34
testing "create char2" "$TAR /dev/null | $SUM" \
  "" "" ""

#testing "create block" "$TAR /dev/

skipnot mknod dir/block b 56 78
testing "create dir/block" "$TAR dir/block | $SUM" \
  "" "" ""

skipnot chown nobody dir/file
testing "ownership" "$TAR dir/block | $SUM" \
  "blat" "" ""

mkdir -p dd/sub/blah &&
tar cf test.tar dd/sub/blah &&
rm -rf dd/sub &&
ln -s ../.. dd/sub || SKIPNEXT=1
toyonly testing "symlink out of cwd" \
  "tar xf test.tar 2> /dev/null || echo yes ; [ ! -e dd/sub/blah ] && echo yes" \
  "yes\nyes\n" "" ""

# If not root can't preserve ownership, so don't try yet.

testing "extract dir/file from tar" \
  "tar xvCf dd $FILES/tar/tar.tar && stat -c '%A %Y %n' dd/dir dd/dir/file" \
  "dir/\ndir/file\ndrwxr-x--- 1494637555 dd/dir\n-rw-r----- 1494637555 dd/dir/file\n" \
  "" ""

testing "extract dir/file from tgz (autodetect)" \
  "tar xvCf dd $FILES/tar/tar.tgz && stat -c '%A %Y %n' dd/dir dd/dir/file" \
  "dir/\ndir/file\ndrwxr-x--- 1494637555 dd/dir\n-rw-r----- 1494637555 dd/dir/file\n" \
  "" ""

toyonly testing "cat tgz | extract dir/file (autodetect)" \
  "cat $FILES/tar/tar.tgz | tar xvC dd && stat -c '%A %Y %n' dd/dir dd/dir/file" \
  "dir/\ndir/file\ndrwxr-x--- 1494637555 dd/dir\n-rw-r----- 1494637555 dd/dir/file\n" \
  "" ""

testing "extract dir/file from tbz2 (autodetect)" \
  "tar xvCf dd $FILES/tar/tar.tbz2 && stat -c '%A %Y %n' dd/dir dd/dir/file" \
  "dir/\ndir/file\ndrwxr-x--- 1494637555 dd/dir\n-rw-r----- 1494637555 dd/dir/file\n" \
  "" ""

toyonly testing "cat tbz | extract dir/file (autodetect)" \
  "cat $FILES/tar/tar.tbz2 | tar xvC dd && stat -c '%A %Y %n' dd/dir dd/dir/file" \
  "dir/\ndir/file\ndrwxr-x--- 1494637555 dd/dir\n-rw-r----- 1494637555 dd/dir/file\n" \
  "" ""

TZ="$OLDTZ"
umask $OLDUMASK
unset LONG TAR SUM OLDUMASK OLDTZ
unset -f LST