aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/tar.test78
-rw-r--r--toys/pending/tar.c46
2 files changed, 92 insertions, 32 deletions
diff --git a/tests/tar.test b/tests/tar.test
index 27586b67..40cf9c32 100644
--- a/tests/tar.test
+++ b/tests/tar.test
@@ -24,34 +24,38 @@ 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"
-LST='tar tv | sed "s/[ \t][ \t]*/ /g"'
+
+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" \
+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" \
+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" \
+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
-testing "pass mtime" \
- "tar c --owner root --group root file | tar tv --full-time | sed 's/[ \t][ \t]*/ /g'" \
+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" \
+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
@@ -63,9 +67,13 @@ testing "create file in dir" "$TAR dir/file | $SUM" \
testing "create dir and dir/file" "$TAR dir | $SUM" \
"0bcc8005a3e07eb63c9b735267aecc5b774795d7\n" "" ""
-testing "pass dir/file" "$TAR dir | $LST" \
+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" \
@@ -106,28 +114,34 @@ testing "create symlink" "$TAR dir/linkok | $SUM" \
"55652846506cf0a9d43b3ef03ccf9e98123befaf\n" "" ""
ln -s /dev/null dir/linknull
-testing "pass absolute symlink" "$TAR dir/linknull | $LST" \
+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" \
+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" \
+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" \
+ "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" \
+ "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" \
"" "" ""
@@ -142,6 +156,42 @@ 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 LST
+unset LONG TAR SUM OLDUMASK OLDTZ
+unset -f LST
diff --git a/toys/pending/tar.c b/toys/pending/tar.c
index b32a5098..8a09102e 100644
--- a/toys/pending/tar.c
+++ b/toys/pending/tar.c
@@ -453,7 +453,7 @@ static void extract_to_disk(void)
}
// || !FLAG(no_same_permissions))
- if (FLAG(p) && !S_ISLNK(ala)) chmod(TT.hdr.name, ala);
+ if (!S_ISLNK(ala)) chmod(TT.hdr.name, FLAG(p) ? ala : ala&0777);
// Apply mtime.
if (!FLAG(m)) {
@@ -493,14 +493,11 @@ static void unpack_tar(struct tar_hdr *first)
i = readall(TT.fd, &tar, 512);
}
- if (i && i != 512) error_exit("read error");
+ if (i && i!=512) error_exit("short header");
// Two consecutive empty headers ends tar even if there's more data
if (!i || !*tar.name) {
- if (!i || and++) {
- dirflush(0);
- return;
- }
+ if (!i || and++) return;
TT.hdr.size = 0;
continue;
}
@@ -721,35 +718,48 @@ void tar_main(void)
}
if (FLAG(j)||FLAG(z)) {
- int pipefd[2] = {hdr ? -1 : TT.fd, -1}, i;
+ int pipefd[2] = {hdr ? -1 : TT.fd, -1}, i, pid;
xpopen_both((char *[]){FLAG(z)?"gunzip":"bunzip2", "-cf", "-", NULL},
pipefd);
- close(TT.fd);
- TT.fd = pipefd[1];
- // If we autodetected type but then couldn't lseek to put the data back
- if (hdr) {
- // dirty trick: move pipefd[0] to 0 so child closes spare copy
+ if (!hdr) {
+ // If we could seek, child gzip inherited fd and we read its output
+ close(TT.fd);
+ TT.fd = pipefd[1];
+
+ } else {
+
+ // If we autodetected type but then couldn't lseek to put the data back
+ // we have to loop reading data from TT.fd and pass it to gzip ourselves
+ // (starting with the block of data we read to autodetect).
+
+ // dirty trick: move gzip input pipe to stdin so child closes spare copy
dup2(pipefd[0], 0);
if (pipefd[0]) close(pipefd[0]);
- // Fork a copy of ourselves to handle extraction (reads from zip proc)
- pipefd[0] = TT.fd;
+ // Fork a copy of ourselves to handle extraction (reads from zip output
+ // pipe, writes to stdout).
+ pipefd[0] = pipefd[1];
pipefd[1] = 1;
- xpopen_both(0, pipefd);
- close(TT.fd);
+ pid = xpopen_both(0, pipefd);
+ close(pipefd[1]);
// loop writing collated data to zip proc
xwrite(0, hdr, len);
for (;;) {
- if ((i = read(0, toybuf, sizeof(toybuf)))<1) return;
+ if ((i = read(TT.fd, toybuf, sizeof(toybuf)))<1) {
+ close(0);
+ xwaitpid(pid);
+ return;
+ }
xwrite(0, toybuf, i);
}
- } else hdr = 0;
+ }
}
unpack_tar(hdr);
+ dirflush(0);
if (TT.seen != TT.incl) {
if (!TT.seen) TT.seen = TT.incl;
while (TT.incl != TT.seen) {