From 623fd7d3ad862d37a00f7f78a64c670ec7f6138e Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Sat, 23 Aug 2008 19:37:23 -0400 Subject: [PATCH] IFC SVN-Revision: 184 --- cpio/cpio.c | 4 +- cpio/test/Makefile | 6 +- cpio/test/main.c | 6 +- cpio/test/test_basic.c | 15 ++- cpio/test/test_format_newc.c | 35 +++-- cpio/test/test_gcpio_compat.c | 5 +- cpio/test/test_option_a.c | 3 +- cpio/test/test_passthrough_dotdot.c | 89 +++++++++++++ cpio/test/test_passthrough_reverse.c | 103 +++++++++++++++ libarchive/archive_write_disk.c | 8 +- tar/Makefile | 4 +- tar/bsdtar.c | 4 +- tar/read.c | 23 ++-- tar/test/Makefile | 3 +- tar/test/main.c | 33 ++++- tar/test/test.h | 6 +- tar/test/test_option_q.c | 125 ++++++++++++++++++ tar/test/test_patterns.c | 60 +++++++-- tar/test/test_patterns.tgz.err.uu | 6 - tar/test/test_patterns.tgz.out.uu | 5 - ...patterns.tgz.uu => test_patterns_2.tgz.uu} | 4 +- tar/test/test_patterns_3.tgz.uu | 8 ++ 22 files changed, 487 insertions(+), 68 deletions(-) create mode 100644 cpio/test/test_passthrough_dotdot.c create mode 100644 cpio/test/test_passthrough_reverse.c create mode 100644 tar/test/test_option_q.c delete mode 100644 tar/test/test_patterns.tgz.err.uu delete mode 100644 tar/test/test_patterns.tgz.out.uu rename tar/test/{test_patterns.tgz.uu => test_patterns_2.tgz.uu} (68%) create mode 100644 tar/test/test_patterns_3.tgz.uu diff --git a/cpio/cpio.c b/cpio/cpio.c index ee932c975..607dfb78c 100644 --- a/cpio/cpio.c +++ b/cpio/cpio.c @@ -26,7 +26,7 @@ #include "cpio_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.10 2008/07/30 03:35:45 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.11 2008/08/20 16:39:18 kientzle Exp $"); #include #include @@ -112,6 +112,8 @@ main(int argc, char *argv[]) cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS; cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT; cpio->extract_flags |= ARCHIVE_EXTRACT_PERM; + cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; + cpio->extract_flags |= ARCHIVE_EXTRACT_ACL; if (geteuid() == 0) cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; cpio->bytes_per_block = 512; diff --git a/cpio/test/Makefile b/cpio/test/Makefile index 9ba06a6b8..c19e56670 100644 --- a/cpio/test/Makefile +++ b/cpio/test/Makefile @@ -1,4 +1,4 @@ -# $FreeBSD: src/lib/libarchive/test/Makefile,v 1.11 2007/07/13 15:14:35 kientzle Exp $ +# $FreeBSD: src/usr.bin/cpio/test/Makefile,v 1.3 2008/08/24 05:14:03 kientzle Exp $ # Where to find the cpio sources (for the internal unit tests) CPIO_SRCDIR=${.CURDIR}/.. @@ -27,7 +27,9 @@ TESTS= \ test_option_y.c \ test_option_z.c \ test_owner_parse.c \ - test_pathmatch.c \ + test_passthrough_dotdot.c \ + test_passthrough_reverse.c \ + test_pathmatch.c # Build the test program SRCS= list.h \ diff --git a/cpio/test/main.c b/cpio/test/main.c index e0f8c2e11..379968b1e 100644 --- a/cpio/test/main.c +++ b/cpio/test/main.c @@ -44,7 +44,7 @@ #undef EXTRA_DUMP /* How to dump extra data */ /* How to generate extra version info. */ #define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") -__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.2 2008/06/21 02:17:18 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.3 2008/08/24 04:58:22 kientzle Exp $"); /* * "list.h" is simply created by "grep DEFINE_TEST"; it has @@ -598,8 +598,8 @@ test_assert_file_contents(const void *buff, int s, const char *fpattern, ...) va_end(ap); fd = open(f, O_RDONLY); - contents = malloc(s * 2); - n = read(fd, contents, s * 2); + contents = malloc(s * 2 + 128); + n = read(fd, contents, s * 2 + 128); if (n == s && memcmp(buff, contents, s) == 0) { free(contents); return (1); diff --git a/cpio/test/test_basic.c b/cpio/test/test_basic.c index 6ea0c5d6d..954153e28 100644 --- a/cpio/test/test_basic.c +++ b/cpio/test/test_basic.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_basic.c,v 1.2 2008/08/22 02:27:06 kientzle Exp $"); static void verify_files(const char *target) @@ -155,7 +155,7 @@ passthrough(const char *target) /* * Use cpio passthrough mode to copy files to another directory. */ - r = systemf("%s -p -W quiet %s %s/stdout 2>%s/stderr", + r = systemf("%s -p %s %s/stdout 2>%s/stderr", testprog, target, target, target); failure("Error invoking %s -p", testprog); assertEqualInt(r, 0); @@ -165,7 +165,10 @@ passthrough(const char *target) /* Verify stderr. */ failure("Error invoking %s -p in dir %s", testprog, target); - assertEmptyFile("stderr"); + /* gcpio 2.9 writes "1 block" to stderr */ + /* assertFileContents("1 block\n", 8, "stderr"); */ + /* bsdcpio writes nothing to stderr for passthrough mode */ + assertFileContents("", 0, "stderr"); verify_files(target); chdir(".."); @@ -218,8 +221,10 @@ DEFINE_TEST(test_basic) basic_cpio("copy", "", "", "2 blocks\n"); basic_cpio("copy_odc", "--format=odc", "", "2 blocks\n"); basic_cpio("copy_newc", "-H newc", "", "2 blocks\n"); - basic_cpio("copy_cpio", "-H odc", "", "2 blocks\n"); - basic_cpio("copy_ustar", "-H ustar", "", "9 blocks\n"); + basic_cpio("copy_cpio", "-H odc", "", "1 block\n"); + /* For some reason, gcpio 2.9 writes 7 blocks but only reads 6? */ + /* bsdcpio writes 7 blocks and reads 7 blocks. */ + basic_cpio("copy_ustar", "-H ustar", "", "7 blocks\n"); /* Copy in one step using -p */ passthrough("passthrough"); diff --git a/cpio/test/test_format_newc.c b/cpio/test/test_format_newc.c index 0714bd427..5bae145cd 100644 --- a/cpio/test/test_format_newc.c +++ b/cpio/test/test_format_newc.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_format_newc.c,v 1.2 2008/08/22 02:09:10 kientzle Exp $"); static int is_hex(const char *p, size_t l) @@ -68,7 +68,7 @@ DEFINE_TEST(test_format_newc) int devmajor, devminor, ino, gid; time_t t, t2, now; char *p, *e; - size_t s; + size_t s, fs, ns; mode_t oldmask; oldmask = umask(0); @@ -141,16 +141,21 @@ DEFINE_TEST(test_format_newc) " first appearance should be empty, so this file size\n" " field should be zero"); assertEqualInt(0, from_hex(e + 54, 8)); /* File size */ + fs = from_hex(e + 54, 8); + fs += 3 & -fs; devmajor = from_hex(e + 62, 8); /* devmajor */ devminor = from_hex(e + 70, 8); /* devminor */ assert(is_hex(e + 78, 8)); /* rdevmajor */ assert(is_hex(e + 86, 8)); /* rdevminor */ assertEqualMem(e + 94, "00000006", 8); /* Name size */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ assertEqualMem(e + 110, "file1\0", 6); /* Name contents */ /* Since there's another link, no file contents here. */ /* But add in file size so that an error here doesn't cascade. */ - e += 116 + from_hex(e + 54, 8) + (3 & -from_hex(e + 54, 8)); + e += 110 + fs + ns; + /* "symlink" pointing to "file1" */ assert(is_hex(e, 110)); assertEqualMem(e + 0, "070701", 6); /* Magic */ @@ -163,15 +168,19 @@ DEFINE_TEST(test_format_newc) failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2); assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */ assertEqualMem(e + 54, "00000005", 8); /* File size */ + fs = from_hex(e + 54, 8); + fs += 3 & -fs; assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */ assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */ assert(is_hex(e + 78, 8)); /* rdevmajor */ assert(is_hex(e + 86, 8)); /* rdevminor */ assertEqualMem(e + 94, "00000008", 8); /* Name size */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */ - assertEqualMem(e + 120, "file1\0\0\0", 8); /* symlink target */ - e += 120 + from_hex(e + 54, 8) + (3 & -from_hex(e + 54, 8)); + assertEqualMem(e + 110 + ns, "file1\0\0\0", 8); /* symlink target */ + e += 110 + fs + ns; /* "dir" */ assert(is_hex(e, 110)); @@ -185,16 +194,18 @@ DEFINE_TEST(test_format_newc) failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2); assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */ assertEqualMem(e + 54, "00000000", 8); /* File size */ + fs = from_hex(e + 54, 8); + fs += 3 & -fs; assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */ assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */ assert(is_hex(e + 78, 8)); /* rdevmajor */ assert(is_hex(e + 86, 8)); /* rdevminor */ assertEqualMem(e + 94, "00000004", 8); /* Name size */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ assertEqualMem(e + 110, "dir\0\0\0", 6); /* Name contents */ - e += 116; - - /* TODO: Verify other types of entries. */ + e += 110 + fs + ns; /* Hardlink identical to "file1" */ /* Since we only wrote two of the three links to this @@ -211,15 +222,19 @@ DEFINE_TEST(test_format_newc) failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2); assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */ assertEqualInt(10, from_hex(e + 54, 8)); /* File size */ + fs = from_hex(e + 54, 8); + fs += 3 & -fs; assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */ assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */ assert(is_hex(e + 78, 8)); /* rdevmajor */ assert(is_hex(e + 86, 8)); /* rdevminor */ assertEqualMem(e + 94, "00000009", 8); /* Name size */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ assertEqualMem(e + 110, "hardlink\0\0", 10); /* Name contents */ - assertEqualMem(e + 120, "123456789\0\0\0", 12); /* File contents */ - e += 120 + from_hex(e + 54, 8) + (3 & -from_hex(e + 54, 8)); + assertEqualMem(e + 110 + ns, "123456789\0\0\0", 12); /* File contents */ + e += 110 + ns + fs; /* Last entry is end-of-archive marker. */ assert(is_hex(e, 110)); diff --git a/cpio/test/test_gcpio_compat.c b/cpio/test/test_gcpio_compat.c index 4c69abb63..42ea9e1bb 100644 --- a/cpio/test/test_gcpio_compat.c +++ b/cpio/test/test_gcpio_compat.c @@ -23,8 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD$"); - +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_gcpio_compat.c,v 1.2 2008/08/22 02:27:06 kientzle Exp $"); static void unpack_test(const char *from, const char *options, const char *se) @@ -48,6 +47,7 @@ unpack_test(const char *from, const char *options, const char *se) assertEqualInt(r, 0); /* Verify that nothing went to stderr. */ + failure("Error invoking %s -i %s < %s", testprog, options, from); assertFileContents(se, strlen(se), "unpack.err"); /* @@ -121,6 +121,7 @@ DEFINE_TEST(test_gcpio_compat) unpack_test("test_gcpio_compat_ref.bin", "", "1 block\n"); unpack_test("test_gcpio_compat_ref.crc", "", "2 blocks\n"); unpack_test("test_gcpio_compat_ref.newc", "", "2 blocks\n"); + /* gcpio-2.9 only reads 6 blocks here */ unpack_test("test_gcpio_compat_ref.ustar", "", "7 blocks\n"); umask(oldumask); diff --git a/cpio/test/test_option_a.c b/cpio/test/test_option_a.c index c063280f7..f735b9116 100644 --- a/cpio/test/test_option_a.c +++ b/cpio/test/test_option_a.c @@ -24,7 +24,7 @@ */ #include "test.h" #include -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_option_a.c,v 1.2 2008/08/22 02:27:06 kientzle Exp $"); static struct { const char *name; @@ -118,6 +118,7 @@ DEFINE_TEST(test_option_a) /* Copy the file without -a; should change the atime. */ r = systemf("echo %s | %s -pd copy-no-a > copy-no-a.out 2>copy-no-a.err", files[1].name, testprog); assertEqualInt(r, 0); + /* bsdcpio writes nothing to stderr in -p mode */ assertEmptyFile("copy-no-a.err"); assertEmptyFile("copy-no-a.out"); assertEqualInt(0, stat(files[1].name, &st)); diff --git a/cpio/test/test_passthrough_dotdot.c b/cpio/test/test_passthrough_dotdot.c new file mode 100644 index 000000000..e9d5c617a --- /dev/null +++ b/cpio/test/test_passthrough_dotdot.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_passthrough_dotdot.c,v 1.2 2008/08/24 05:24:52 kientzle Exp $"); + +/* + * Verify that "cpio -p .." works. + */ + +DEFINE_TEST(test_passthrough_dotdot) +{ + struct stat st; + int fd, r; + int filelist; + int oldumask; + + oldumask = umask(0); + + /* + * Create an assortment of files on disk. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* Directory. */ + assertEqualInt(0, mkdir("dir", 0755)); + assertEqualInt(0, chdir("dir")); + + write(filelist, ".\n", 2); + + /* File with 10 bytes content. */ + fd = open("file", O_CREAT | O_WRONLY, 0642); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "file\n", 5); + + /* All done. */ + close(filelist); + + + /* + * Use cpio passthrough mode to copy files to another directory. + */ + r = systemf("%s -pdvm .. <../filelist >../stdout 2>../stderr", + testprog); + failure("Error invoking %s -pd ..", testprog); + assertEqualInt(r, 0); + + assertEqualInt(0, chdir("..")); + + /* Verify stderr and stdout. */ + assertFileContents("../file\n", 8, "stderr"); + assertEmptyFile("stdout"); + + /* Regular file. */ + r = lstat("file", &st); + failure("Failed to stat file, errno=%d", errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); + assertEqualInt(0642, st.st_mode & 0777); + assertEqualInt(10, st.st_size); + assertEqualInt(1, st.st_nlink); + } + + umask(oldumask); +} diff --git a/cpio/test/test_passthrough_reverse.c b/cpio/test/test_passthrough_reverse.c new file mode 100644 index 000000000..00ee2bc02 --- /dev/null +++ b/cpio/test/test_passthrough_reverse.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_passthrough_reverse.c,v 1.1 2008/08/24 04:58:22 kientzle Exp $"); + +/* + * As reported by Bernd Walter: Some people are in the habit of + * using "find -d" to generate a list for cpio -p because that + * copies the top-level dir last, which preserves owner and mode + * information. That's not necessary for bsdcpio (libarchive defers + * restoring directory information), but bsdcpio should still generate + * the correct results with this usage. + */ + +DEFINE_TEST(test_passthrough_reverse) +{ + struct stat st; + int fd, r; + int filelist; + int oldumask; + + oldumask = umask(0); + + /* + * Create an assortment of files on disk. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* Directory. */ + assertEqualInt(0, mkdir("dir", 0743)); + + /* File with 10 bytes content. */ + fd = open("dir/file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "dir/file\n", 9); + + /* Write dir last. */ + write(filelist, "dir\n", 4); + + /* All done. */ + close(filelist); + + + /* + * Use cpio passthrough mode to copy files to another directory. + */ + r = systemf("%s -pdvm out stdout 2>stderr", testprog); + failure("Error invoking %s -pd out", testprog); + assertEqualInt(r, 0); + + assertEqualInt(0, chdir("out")); + + /* Verify stderr and stdout. */ + assertFileContents("out/dir/file\nout/dir\n", 21, "../stderr"); + assertEmptyFile("../stdout"); + + /* dir */ + r = lstat("dir", &st); + if (r == 0) { + assertEqualInt(r, 0); + assert(S_ISDIR(st.st_mode)); + failure("st.st_mode=0%o", st.st_mode); + assertEqualInt(0743, st.st_mode & 0777); + } + + + /* Regular file. */ + r = lstat("dir/file", &st); + failure("Failed to stat dir/file, errno=%d", errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); + assertEqualInt(0644, st.st_mode & 0777); + assertEqualInt(10, st.st_size); + assertEqualInt(1, st.st_nlink); + } + + umask(oldumask); +} diff --git a/libarchive/archive_write_disk.c b/libarchive/archive_write_disk.c index 44e721eb8..d0b3a2cec 100644 --- a/libarchive/archive_write_disk.c +++ b/libarchive/archive_write_disk.c @@ -25,7 +25,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.28 2008/07/05 01:48:33 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.29 2008/08/24 05:01:01 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -906,7 +906,11 @@ restore_entry(struct archive_write_disk *a) /* TODO: if it's a symlink... */ - if (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) { + /* + * NO_OVERWRITE_NEWER doesn't apply to directories. + */ + if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) + && !S_ISDIR(a->st.st_mode)) { if (!older(&(a->st), a->entry)) { archive_set_error(&a->archive, 0, "File on disk is not older; skipping."); diff --git a/tar/Makefile b/tar/Makefile index fa72cfbd1..67f2b0474 100644 --- a/tar/Makefile +++ b/tar/Makefile @@ -1,4 +1,4 @@ -# $FreeBSD: src/usr.bin/tar/Makefile,v 1.37 2008/07/05 02:09:54 kientzle Exp $ +# $FreeBSD: src/usr.bin/tar/Makefile,v 1.38 2008/08/22 01:31:13 kientzle Exp $ PROG= bsdtar BSDTAR_VERSION_STRING=2.5.5 @@ -14,6 +14,6 @@ MLINKS= bsdtar.1 tar.1 .PHONY: check test check test: $(PROG) bsdtar.1.gz - cd ${.CURDIR}/test && make clean test + cd ${.CURDIR}/test && make test .include diff --git a/tar/bsdtar.c b/tar/bsdtar.c index 1c13cc6bf..40ddd78a4 100644 --- a/tar/bsdtar.c +++ b/tar/bsdtar.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.91 2008/05/26 17:10:10 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.92 2008/08/22 01:22:55 kientzle Exp $"); #ifdef HAVE_SYS_PARAM_H #include @@ -118,7 +118,7 @@ static void version(void); * non-option. Otherwise, GNU getopt() permutes the arguments and * screws up -C processing. */ -static const char *tar_opts = "+Bb:C:cf:HhI:jkLlmnOoPprts:ST:UuvW:wX:xyZz"; +static const char *tar_opts = "+Bb:C:cf:HhI:jkLlmnOoPpqrts:ST:UuvW:wX:xyZz"; /* * Most of these long options are deliberately not documented. They diff --git a/tar/read.c b/tar/read.c index fadd57de8..a8cb14ab3 100644 --- a/tar/read.c +++ b/tar/read.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.39 2008/07/05 02:05:55 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.40 2008/08/21 06:41:14 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -210,22 +210,17 @@ read_archive(struct bsdtar *bsdtar, char mode) if (excluded(bsdtar, archive_entry_pathname(entry))) continue; /* Excluded by a pattern test. */ - /* - * Modify the pathname as requested by the user. We - * do this for -t as well to give users a way to - * preview the effects of their rewrites. We also do - * this before extraction security checks (including - * leading '/' removal). Note that some rewrite - * failures prevent extraction. - */ - if (edit_pathname(bsdtar, entry)) - continue; /* Excluded by a rewrite failure. */ - if (mode == 't') { /* Perversely, gtar uses -O to mean "send to stderr" * when used with -t. */ out = bsdtar->option_stdout ? stderr : stdout; + /* + * TODO: Provide some reasonable way to + * preview rewrites. gtar always displays + * the unedited path in -t output, which means + * you cannot easily preview rewrites. + */ if (bsdtar->verbose < 2) safe_fprintf(out, "%s", archive_entry_pathname(entry)); @@ -252,6 +247,10 @@ read_archive(struct bsdtar *bsdtar, char mode) } fprintf(out, "\n"); } else { + /* Note: some rewrite failures prevent extraction. */ + if (edit_pathname(bsdtar, entry)) + continue; /* Excluded by a rewrite failure. */ + if (bsdtar->option_interactive && !yes("extract '%s'", archive_entry_pathname(entry))) continue; diff --git a/tar/test/Makefile b/tar/test/Makefile index 963110896..079210f2a 100644 --- a/tar/test/Makefile +++ b/tar/test/Makefile @@ -1,4 +1,4 @@ -# $FreeBSD: src/usr.bin/tar/test/Makefile,v 1.2 2008/05/26 17:10:10 kientzle Exp $ +# $FreeBSD: src/usr.bin/tar/test/Makefile,v 1.3 2008/08/22 01:22:55 kientzle Exp $ # Where to find the tar sources (for the internal unit tests) TAR_SRCDIR=${.CURDIR}/.. @@ -15,6 +15,7 @@ TESTS= \ test_getdate.c \ test_help.c \ test_option_T.c \ + test_option_q.c \ test_patterns.c \ test_stdio.c \ test_version.c diff --git a/tar/test/main.c b/tar/test/main.c index 27bb48d40..5549d885c 100644 --- a/tar/test/main.c +++ b/tar/test/main.c @@ -44,7 +44,7 @@ #undef EXTRA_DUMP /* How to dump extra data */ /* How to generate extra version info. */ #define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") -__FBSDID("$FreeBSD: src/usr.bin/tar/test/main.c,v 1.3 2008/06/15 10:07:54 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/test/main.c,v 1.4 2008/08/21 07:04:57 kientzle Exp $"); /* * "list.h" is simply created by "grep DEFINE_TEST"; it has @@ -502,6 +502,37 @@ test_assert_empty_file(const char *f1fmt, ...) return (0); } +int +test_assert_non_empty_file(const char *f1fmt, ...) +{ + char f1[1024]; + struct stat st; + va_list ap; + + + va_start(ap, f1fmt); + vsprintf(f1, f1fmt, ap); + va_end(ap); + + if (stat(f1, &st) != 0) { + fprintf(stderr, "%s:%d: Could not stat: %s\n", + test_filename, test_line, f1); + report_failure(NULL); + return (0); + } + if (st.st_size != 0) + return (1); + + failures ++; + if (!verbose && previous_failures(test_filename, test_line)) + return (0); + + fprintf(stderr, "%s:%d: File empty: %s\n", + test_filename, test_line, f1); + report_failure(NULL); + return (0); +} + /* assertEqualFile() asserts that two files have the same contents. */ /* TODO: hexdump the first bytes that actually differ. */ int diff --git a/tar/test/test.h b/tar/test/test.h index 30321e845..276c37eb8 100644 --- a/tar/test/test.h +++ b/tar/test/test.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/usr.bin/tar/test/test.h,v 1.3 2008/06/15 10:07:54 kientzle Exp $ + * $FreeBSD: src/usr.bin/tar/test/test.h,v 1.4 2008/08/21 07:04:57 kientzle Exp $ */ /* Every test program should #include "test.h" as the first thing. */ @@ -98,6 +98,9 @@ /* Assert that a file is empty; supports printf-style arguments. */ #define assertEmptyFile \ test_setup(__FILE__, __LINE__);test_assert_empty_file +/* Assert that a file is not empty; supports printf-style arguments. */ +#define assertNonEmptyFile \ + test_setup(__FILE__, __LINE__);test_assert_non_empty_file /* Assert that a file exists; supports printf-style arguments. */ #define assertFileExists \ test_setup(__FILE__, __LINE__);test_assert_file_exists @@ -123,6 +126,7 @@ void test_setup(const char *, int); void test_skipping(const char *fmt, ...); int test_assert(const char *, int, int, const char *, void *); int test_assert_empty_file(const char *, ...); +int test_assert_non_empty_file(const char *, ...); int test_assert_equal_file(const char *, const char *, ...); int test_assert_equal_int(const char *, int, int, const char *, int, const char *, void *); int test_assert_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *); diff --git a/tar/test/test_option_q.c b/tar/test/test_option_q.c new file mode 100644 index 000000000..d7011c367 --- /dev/null +++ b/tar/test/test_option_q.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_option_q.c,v 1.3 2008/08/22 01:35:08 kientzle Exp $"); + +DEFINE_TEST(test_option_q) +{ + int fd; + + /* + * Create an archive with several different versions of the + * same files. By default, the last version will overwrite + * any earlier versions. The -q/--fast-read option will + * stop early, so we can verify -q/--fast-read by seeing + * which version of each file actually ended up being + * extracted. This also exercises -r mode, since that's + * what we use to build up the test archive. + */ + + fd = open("foo", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(4, write(fd, "foo1", 4)); + close(fd); + + assertEqualInt(0, systemf("%s -cf archive.tar foo", testprog)); + + fd = open("foo", O_TRUNC | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(4, write(fd, "foo2", 4)); + close(fd); + + assertEqualInt(0, systemf("%s -rf archive.tar foo", testprog)); + + fd = open("bar", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(4, write(fd, "bar1", 4)); + close(fd); + + assertEqualInt(0, systemf("%s -rf archive.tar bar", testprog)); + + fd = open("foo", O_TRUNC | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(4, write(fd, "foo3", 4)); + close(fd); + + assertEqualInt(0, systemf("%s -rf archive.tar foo", testprog)); + + fd = open("bar", O_TRUNC | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(4, write(fd, "bar2", 4)); + close(fd); + + assertEqualInt(0, systemf("%s -rf archive.tar bar", testprog)); + + /* + * Now, try extracting from the test archive with various + * combinations of -q. + */ + + /* Test 1: -q foo should only extract the first foo. */ + assertEqualInt(0, mkdir("test1", 0755)); + assertEqualInt(0, chdir("test1")); + assertEqualInt(0, + systemf("%s -xf ../archive.tar -q foo >test.out 2>test.err", + testprog)); + assertFileContents("foo1", 4, "foo"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertEqualInt(0, chdir("..")); + + /* Test 2: -q foo bar should extract up to the first bar. */ + assertEqualInt(0, mkdir("test2", 0755)); + assertEqualInt(0, chdir("test2")); + assertEqualInt(0, + systemf("%s -xf ../archive.tar -q foo bar >test.out 2>test.err", testprog)); + assertFileContents("foo2", 4, "foo"); + assertFileContents("bar1", 4, "bar"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertEqualInt(0, chdir("..")); + + /* Test 3: Same as test 2, but use --fast-read spelling. */ + assertEqualInt(0, mkdir("test3", 0755)); + assertEqualInt(0, chdir("test3")); + assertEqualInt(0, + systemf("%s -xf ../archive.tar --fast-read foo bar >test.out 2>test.err", testprog)); + assertFileContents("foo2", 4, "foo"); + assertFileContents("bar1", 4, "bar"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertEqualInt(0, chdir("..")); + + /* Test 4: Without -q, should extract everything. */ + assertEqualInt(0, mkdir("test4", 0755)); + assertEqualInt(0, chdir("test4")); + assertEqualInt(0, + systemf("%s -xf ../archive.tar foo bar >test.out 2>test.err", testprog)); + assertFileContents("foo3", 4, "foo"); + assertFileContents("bar2", 4, "bar"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertEqualInt(0, chdir("..")); +} diff --git a/tar/test/test_patterns.c b/tar/test/test_patterns.c index b3e61d75a..227b4a53d 100644 --- a/tar/test/test_patterns.c +++ b/tar/test/test_patterns.c @@ -23,20 +23,23 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_patterns.c,v 1.2 2008/08/15 06:12:02 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_patterns.c,v 1.6 2008/08/21 22:28:00 kientzle Exp $"); DEFINE_TEST(test_patterns) { int fd, r; - const char *reffile1 = "test_patterns.tgz"; - const char *reffile1_out = "test_patterns.tgz.out"; - const char *reffile1_err = "test_patterns.tgz.err"; + const char *reffile2 = "test_patterns_2.tgz"; + const char *reffile3 = "test_patterns_3.tgz"; + const char *p; /* * Test basic command-line pattern handling. */ /* + * Test 1: Files on the command line that don't get matched + * didn't produce an error. + * * John Baldwin reported this problem in PR bin/121598 */ fd = open("foo", O_CREAT | O_WRONLY, 0644); @@ -48,13 +51,50 @@ DEFINE_TEST(test_patterns) failure("tar should return non-zero because a file was given on the command line that's not in the archive"); assert(r != 0); - extract_reference_file(reffile1); - extract_reference_file(reffile1_out); - extract_reference_file(reffile1_err); + /* + * Test 2: Check basic matching of full paths that start with / + */ + extract_reference_file(reffile2); r = systemf("%s tf %s /tmp/foo/bar > tar2a.out 2> tar2a.err", - testprog, reffile1); + testprog, reffile2); + assertEqualInt(r, 0); + p = "/tmp/foo/bar/\n/tmp/foo/bar/baz\n"; + assertFileContents(p, strlen(p), "tar2a.out"); + assertEmptyFile("tar2a.err"); + + /* + * Test 3 archive has some entries starting with '/' and some not. + */ + extract_reference_file(reffile3); + + /* Test 3a: Pattern tmp/foo/bar should not match /tmp/foo/bar */ + r = systemf("%s xf %s tmp/foo/bar > tar3a.out 2> tar3a.err", + testprog, reffile3); + assert(r != 0); + assertEmptyFile("tar3a.out"); + + /* Test 3b: Pattern /tmp/foo/baz should not match tmp/foo/baz */ + assertNonEmptyFile("tar3a.err"); + /* Again, with the '/' */ + r = systemf("%s xf %s /tmp/foo/baz > tar3b.out 2> tar3b.err", + testprog, reffile3); + assert(r != 0); + assertEmptyFile("tar3b.out"); + assertNonEmptyFile("tar3b.err"); + + /* Test 3c: ./tmp/foo/bar should not match /tmp/foo/bar */ + r = systemf("%s xf %s ./tmp/foo/bar > tar3c.out 2> tar3c.err", + testprog, reffile3); + assert(r != 0); + assertEmptyFile("tar3c.out"); + assertNonEmptyFile("tar3c.err"); + + /* Test 3d: ./tmp/foo/baz should match tmp/foo/baz */ + r = systemf("%s xf %s ./tmp/foo/baz > tar3d.out 2> tar3d.err", + testprog, reffile3); assertEqualInt(r, 0); - assertEqualFile("tar2a.out", reffile1_out); - assertEqualFile("tar2a.err", reffile1_err); + assertEmptyFile("tar3d.out"); + assertEmptyFile("tar3d.err"); + assertEqualInt(0, access("tmp/foo/baz/bar", F_OK)); } diff --git a/tar/test/test_patterns.tgz.err.uu b/tar/test/test_patterns.tgz.err.uu deleted file mode 100644 index 258082a4c..000000000 --- a/tar/test/test_patterns.tgz.err.uu +++ /dev/null @@ -1,6 +0,0 @@ -$FreeBSD: src/usr.bin/tar/test/test_patterns.tgz.err.uu,v 1.1 2008/08/15 06:12:02 kientzle Exp $ -begin 644 test_patterns.tgz.err -M8G-D=&%R.B!296UO=FEN9R!L96%D:6YG("@H` -` -end diff --git a/tar/test/test_patterns.tgz.uu b/tar/test/test_patterns_2.tgz.uu similarity index 68% rename from tar/test/test_patterns.tgz.uu rename to tar/test/test_patterns_2.tgz.uu index 1171e58dc..bb58aff8e 100644 --- a/tar/test/test_patterns.tgz.uu +++ b/tar/test/test_patterns_2.tgz.uu @@ -1,5 +1,5 @@ -$FreeBSD: src/usr.bin/tar/test/test_patterns.tgz.uu,v 1.1 2008/08/15 06:12:02 kientzle Exp $ -begin 644 test_patterns.tgz +$FreeBSD: src/usr.bin/tar/test/test_patterns_2.tgz.uu,v 1.1 2008/08/20 06:01:53 kientzle Exp $ +begin 644 test_patterns_2.tgz M'XL(`,P5I4@``^W3T0J",!3&<1]E;[!SYC:?Q\`H2`PS@IZ^F5AV(PFMJ__O MYB@;>.:W8X?V;/==9XM\1*0*P:2J59"QCN8ZO:A*4*65]>2CUUQX+TO/\F_@H<0_BWG^I;Z`#?D'X?T#``````````````!\Y0FE&!YR`"@````` +` +end -- 2.47.3