]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Merge cpio test refactorings into tar and libarchive test harnesses,
authorTim Kientzle <kientzle@gmail.com>
Sat, 12 Sep 2009 18:08:48 +0000 (14:08 -0400)
committerTim Kientzle <kientzle@gmail.com>
Sat, 12 Sep 2009 18:08:48 +0000 (14:08 -0400)
apply a few minor reorgs to further reduce diffs among the test
harnesses, update a bunch of tests to match the harness changes,
update some comments, rewrite the gzip/gunzip platform probes to the
new "canFoo()" style, sprinkle a few new symlink support checks.  This
hasn't been tested on Windows yet, but should chip away a few more
test failures there.

SVN-Revision: 1456

cpio/test/main.c
cpio/test/test.h
libarchive/test/main.c
libarchive/test/test.h
libarchive/test/test_read_compress_program.c
libarchive/test/test_write_compress_program.c
libarchive/test/test_write_disk_hardlink.c
tar/test/main.c
tar/test/test.h
tar/test/test_basic.c
tar/test/test_copy.c

index 15ee5671933f8f099e09f22bd7f6fa1fa2174c1c..d0d58013d699b17177adac3113893d0f7165c089 100644 (file)
  * TODO: Move this into a separate configuration header, have all test
  * suites share one copy of this file.
  */
+__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.3 2008/08/24 04:58:22 kientzle Exp $");
+#define KNOWNREF       "test_option_f.cpio.uu"
+#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */
 #define        PROGRAM "bsdcpio" /* Name of program being tested. */
 #undef LIBRARY           /* Not testing a library. */
-#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */
 #undef EXTRA_DUMP           /* How to dump extra data */
 /* How to generate extra version info. */
 #define        EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
-#define KNOWNREF       "test_option_f.cpio.uu"
-__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.3 2008/08/24 04:58:22 kientzle Exp $");
 
 /*
  *
@@ -1347,6 +1347,42 @@ canSymlink(void)
        return (value);
 }
 
+/*
+ * Can this platform run the gzip program?
+ */
+/* Platform-dependent options for hiding the output of a subcommand. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
+#else
+static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
+#endif
+int
+canGzip(void)
+{
+       static int tested = 0, value = 0;
+       if (!tested) {
+               tested = 1;
+               if (systemf("gzip -V %s", redirectArgs) == 0)
+                       value = 1;
+       }
+       return (value);
+}
+
+/*
+ * Can this platform run the gunzip program?
+ */
+int
+canGunzip(void)
+{
+       static int tested = 0, value = 0;
+       if (!tested) {
+               tested = 1;
+               if (systemf("gunzip -V %s", redirectArgs) == 0)
+                       value = 1;
+       }
+       return (value);
+}
+
 /*
  * Sleep as needed; useful for verifying disk timestamp changes by
  * ensuring that the wall-clock time has actually changed before we
index e2e83b3ef798d11276c9512e91d176df564bfb94..b275da4777c7cb3467b969162877e52a857c964e 100644 (file)
@@ -253,6 +253,12 @@ void sleepUntilAfter(time_t);
 /* Return true if this platform can create symlinks. */
 int canSymlink(void);
 
+/* Return true if this platform can run the "gzip" program. */
+int canGzip(void);
+
+/* Return true if this platform can run the "gunzip" program. */
+int canGunzip(void);
+
 /* Suck file into string allocated via malloc(). Call free() when done. */
 /* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
 char *slurpfile(size_t *, const char *fmt, ...);
index 296e3f56f4920d772f73e767c155a2f90986bfd2..0436ca6d564437e5c65e3148d3a5da55310c048a 100644 (file)
  * TODO: Move this into a separate configuration header, have all test
  * suites share one copy of this file.
  */
+__FBSDID("$FreeBSD: src/lib/libarchive/test/main.c,v 1.17 2008/12/21 00:13:50 kientzle Exp $");
+#define KNOWNREF       "test_compat_gtar_1.tar.uu"
+#define        ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */
 #undef PROGRAM              /* Testing a library, not a program. */
 #define        LIBRARY "libarchive"
-#define        ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */
 #define        EXTRA_DUMP(x)   archive_error_string((struct archive *)(x))
 #define        EXTRA_VERSION   archive_version()
-#define KNOWNREF       "test_compat_gtar_1.tar.uu"
-__FBSDID("$FreeBSD: src/lib/libarchive/test/main.c,v 1.17 2008/12/21 00:13:50 kientzle Exp $");
 
 /*
  *
@@ -132,6 +132,21 @@ my_CreateHardLinkA(const char *linkname, const char *target)
        }
        return f == NULL ? 0 : (*f)(linkname, target, NULL);
 }
+
+int
+my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
+{
+       HANDLE h;
+       int r;
+
+       h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
+               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+       if (h == INVALID_HANDLE_VALUE)
+               return (0);
+       r = GetFileInformationByHandle(h, bhfi);
+       CloseHandle(h);
+       return (r);
+}
 #endif
 
 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__)
@@ -793,11 +808,32 @@ assertion_text_file_contents(const char *buff, const char *fn)
        return (0);
 }
 
-/* Verify that two paths point to the same file. */
-int
-assertion_file_hardlinks(const char *file, int line,
+/* Test that two paths point to the same file. */
+/* As a side-effect, asserts that both files exist. */
+static int
+is_hardlink(const char *file, int line,
     const char *path1, const char *path2)
 {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
+       int r;
+
+       assertion_count(file, line);
+       r = my_GetFileInformationByName(path1, &bhfi1);
+       if (r == 0) {
+               failure_start(file, line, "File %s can't be inspected?", path1);
+               failure_finish(NULL);
+               return (0);
+       }
+       r = my_GetFileInformationByName(path2, &bhfi2);
+       if (r == 0) {
+               failure_start(file, line, "File %s can't be inspected?", path2);
+               failure_finish(NULL);
+               return (0);
+       }
+       return (bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
+               && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
+#else
        struct stat st1, st2;
        int r;
 
@@ -814,13 +850,32 @@ assertion_file_hardlinks(const char *file, int line,
                failure_finish(NULL);
                return (0);
        }
-       if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
-               failure_start(file, line,
-                   "Files %s and %s are not hardlinked", path1, path2);
-               failure_finish(NULL);
-               return (0);
-       }
-       return (1);
+       return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
+#endif
+}
+
+int
+assertion_is_hardlink(const char *file, int line,
+    const char *path1, const char *path2)
+{
+       if (is_hardlink(file, line, path1, path2))
+               return (1);
+       failure_start(file, line,
+           "Files %s and %s are not hardlinked", path1, path2);
+       failure_finish(NULL);
+       return (0);
+}
+
+int
+assertion_is_not_hardlink(const char *file, int line,
+    const char *path1, const char *path2)
+{
+       if (!is_hardlink(file, line, path1, path2))
+               return (1);
+       failure_start(file, line,
+           "Files %s and %s should not be hardlinked", path1, path2);
+       failure_finish(NULL);
+       return (0);
 }
 
 /* Verify a/b/mtime of 'pathname'. */
@@ -971,19 +1026,11 @@ assertion_file_nlinks(const char *file, int line,
     const char *pathname, int nlinks)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-       HANDLE h;
        BY_HANDLE_FILE_INFORMATION bhfi;
        int r;
 
        assertion_count(file, line);
-       h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
-               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-       if (h == INVALID_HANDLE_VALUE) {
-               failure_start(file, line, "Can't access %s", pathname);
-               failure_finish(NULL);
-               return (0);
-       }
-       r = GetFileInformationByHandle(h, &bhfi);
+       r = my_GetFileInformationByName(pathname, &bhfi);
        if (r != 0 && bhfi.nNumberOfLinks == nlinks)
                return (1);
        failure_start(file, line, "File %s has %d links, expected %d",
@@ -1086,17 +1133,14 @@ assertion_is_reg(const char *file, int line, const char *pathname, int mode)
        return (1);
 }
 
-/* Verify that 'pathname' is a symbolic link.  If 'contents' is
+/* Check whether 'pathname' is a symbolic link.  If 'contents' is
  * non-NULL, verify that the symlink has those contents. */
-int
-assertion_is_symlink(const char *file, int line,
+static int
+is_symlink(const char *file, int line,
     const char *pathname, const char *contents)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
        assertion_count(file, line);
-       /* TODO: Vista supports symlinks */
-       failure_start(file, line, "Symlink %s not supported", pathname);
-       failure_finish(NULL);
        return (0);
 #else
        char buff[300];
@@ -1112,11 +1156,8 @@ assertion_is_symlink(const char *file, int line,
                failure_finish(NULL);
                return (0);
        }
-       if (!S_ISLNK(st.st_mode)) {
-               failure_start(file, line, "%s should be a symlink", pathname);
-               failure_finish(NULL);
+       if (!S_ISLNK(st.st_mode))
                return (0);
-       }
        if (contents == NULL)
                return (1);
        linklen = readlink(pathname, buff, sizeof(buff));
@@ -1126,17 +1167,29 @@ assertion_is_symlink(const char *file, int line,
                return (0);
        }
        buff[linklen] = '\0';
-       if (strcmp(buff, contents) != 0) {
-               failure_start(file, line, "Wrong symlink %s", pathname);
-               logprintf("   Expected: %s\n", contents);
-               logprintf("   Found: %s\n", buff);
-               failure_finish(NULL);
+       if (strcmp(buff, contents) != 0)
                return (0);
-       }
        return (1);
 #endif
 }
 
+/* Assert that path is a symlink that (optionally) contains contents. */
+int
+assertion_is_symlink(const char *file, int line,
+    const char *path, const char *contents)
+{
+       if (is_symlink(file, line, path, contents))
+               return (1);
+       if (contents)
+               failure_start(file, line, "File %s is not a symlink to %s",
+                   path, contents);
+       else
+               failure_start(file, line, "File %s is not a symlink", path);
+       failure_finish(NULL);
+       return (0);
+}
+
+
 /* Create a directory and report any errors. */
 int
 assertion_make_dir(const char *file, int line, const char *dirname, int mode)
@@ -1267,6 +1320,68 @@ assertion_umask(const char *file, int line, int mask)
  *
  */
 
+/*
+ * Check whether platform supports symlinks.  This is intended
+ * for tests to use in deciding whether to bother testing symlink
+ * support; if the platform doesn't support symlinks, there's no point
+ * in checking whether the program being tested can create them.
+ */
+int
+canSymlink(void)
+{
+       /* Remember the test result */
+       static int value = 0, tested = 1;
+       if (tested)
+               return (value);
+
+       ++tested;
+       assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a");
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
+           && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
+#elif HAVE_SYMLINK
+       value = (0 == symlink("canSymlink.0", "canSymlink.1"))
+           && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
+#endif
+       return (value);
+}
+
+/*
+ * Can this platform run the gzip program?
+ */
+/* Platform-dependent options for hiding the output of a subcommand. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
+#else
+static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
+#endif
+int
+canGzip(void)
+{
+       static int tested = 0, value = 0;
+       if (!tested) {
+               tested = 1;
+               if (systemf("gzip -V %s", redirectArgs) == 0)
+                       value = 1;
+       }
+       return (value);
+}
+
+/*
+ * Can this platform run the gunzip program?
+ */
+int
+canGunzip(void)
+{
+       static int tested = 0, value = 0;
+       if (!tested) {
+               tested = 1;
+               if (systemf("gunzip -V %s", redirectArgs) == 0)
+                       value = 1;
+       }
+       return (value);
+}
+
 /*
  * Sleep as needed; useful for verifying disk timestamp changes by
  * ensuring that the wall-clock time has actually changed before we
@@ -1926,38 +2041,3 @@ main(int argc, char **argv)
 
        return (tests_failed ? 1 : 0);
 }
-
-/*
- *
- * Special support specifically for libarchive.
- *
- */
-
-/* Since gzip is by far the most popular external compression program
- * available, we try to use it in the read_program and write_program
- * tests.  But if it's not available, then we can't use it.  This
- * function just tries to run gzip/gunzip to see if they're available.
- * If not, some of the external compression program tests will be
- * skipped. */
-const char *
-external_gzip_program(int un)
-{
-       static int tested = 0;
-       static const char *compress_prog = NULL;
-       static const char *decompress_prog = NULL;
-       /* Args vary depending on the command interpreter we're using. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-       static const char *args = "-V >NUL 2>NUL"; /* Win32 cmd.exe */
-#else
-       static const char *args = "-V >/dev/null 2>/dev/null"; /* POSIX 'sh' */
-#endif
-
-       if (!tested) {
-               if (systemf("gunzip %s", args) == 0)
-                       decompress_prog = "gunzip";
-               if (systemf("gzip %s", args) == 0)
-                       compress_prog = "gzip";
-               tested = 1;
-       }
-       return (un ? decompress_prog : compress_prog);
-}
index d5c06b331091541b9a9a926c97a5117b708955a8..9c3ad7fea6394b0e8219ae79ae8977f11e051f6a 100644 (file)
 /* Assert that file contents match a string; supports printf-style arguments. */
 #define assertFileContents             \
   assertion_setup(__FILE__, __LINE__);assertion_file_contents
-#define assertFileHardlinks(path1, path2)      \
-  assertion_file_hardlinks(__FILE__, __LINE__, path1, path2)
 #define assertFileMtime(pathname, sec, nsec)   \
   assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
 #define assertFileMtimeRecent(pathname) \
   assertion_setup(__FILE__, __LINE__);assertion_text_file_contents
 #define assertIsDir(pathname, mode)            \
   assertion_is_dir(__FILE__, __LINE__, pathname, mode)
+#define assertIsHardlink(path1, path2) \
+  assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
+#define assertIsNotHardlink(path1, path2)      \
+  assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
 #define assertIsReg(pathname, mode)            \
   assertion_is_reg(__FILE__, __LINE__, pathname, mode)
 #define assertIsSymlink(pathname, contents)    \
@@ -220,13 +222,14 @@ int assertion_file_birthtime(const char *, int, const char *, long, long);
 int assertion_file_birthtime_recent(const char *, int, const char *);
 int assertion_file_contents(const void *, int, const char *, ...);
 int assertion_file_exists(const char *, ...);
-int assertion_file_hardlinks(const char *, int, const char *, const char *);
 int assertion_file_mtime(const char *, int, const char *, long, long);
 int assertion_file_mtime_recent(const char *, int, const char *);
 int assertion_file_nlinks(const char *, int, const char *, int);
 int assertion_file_not_exists(const char *, ...);
 int assertion_file_size(const char *, int, const char *, long);
 int assertion_is_dir(const char *, int, const char *, int);
+int assertion_is_hardlink(const char *, int, const char *, const char *);
+int assertion_is_not_hardlink(const char *, int, const char *, const char *);
 int assertion_is_reg(const char *, int, const char *, int);
 int assertion_is_symlink(const char *, int, const char *, const char *);
 int assertion_make_dir(const char *, int, const char *, int);
@@ -237,6 +240,7 @@ int assertion_non_empty_file(const char *, ...);
 int assertion_text_file_contents(const char *buff, const char *f);
 int assertion_umask(const char *, int, int);
 void assertion_setup(const char *, int);
+
 void test_skipping(const char *fmt, ...);
 
 /* Like sprintf, then system() */
@@ -245,6 +249,15 @@ int systemf(const char * fmt, ...);
 /* Delay until time() returns a value after this. */
 void sleepUntilAfter(time_t);
 
+/* Return true if this platform can create symlinks. */
+int canSymlink(void);
+
+/* Return true if this platform can run the "gzip" program. */
+int canGzip(void);
+
+/* Return true if this platform can run the "gunzip" program. */
+int canGunzip(void);
+
 /* Suck file into string allocated via malloc(). Call free() when done. */
 /* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
 char *slurpfile(size_t *, const char *fmt, ...);
@@ -256,9 +269,6 @@ void extract_reference_file(const char *);
  * Special interfaces for libarchive test harness.
  */
 
-/* Get external gzip program name */
-const char *external_gzip_program(int un);
-
 #include "archive.h"
 #include "archive_entry.h"
 
@@ -267,17 +277,6 @@ int read_open_memory(struct archive *, void *, size_t, size_t);
 /* "2" version exercises a slightly different set of libarchive APIs. */
 int read_open_memory2(struct archive *, void *, size_t, size_t);
 
-/*
- * ARCHIVE_VERSION_STAMP first appeared in 1.9 and libarchive 2.2.4.
- * We can approximate it for earlier versions, though.
- * This is used to disable tests of features not present in the current
- * version.
- */
-#ifndef ARCHIVE_VERSION_STAMP
-#define ARCHIVE_VERSION_STAMP  \
-               (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
-#endif
-
 /* Versions of above that accept an archive argument for additional info. */
 #define assertA(e)   assertion_assert(__FILE__, __LINE__, (e), #e, (a))
 #define assertEqualIntA(a,v1,v2)   \
index 2d9e22b0b9b05ae07a0f9c41ac386094b940ec48..bb5fde84a7acb16c09a606770bf65a5f8ae9dcdc 100644 (file)
@@ -37,7 +37,6 @@ DEFINE_TEST(test_read_compress_program)
        int r;
        struct archive_entry *ae;
        struct archive *a;
-       const char *extprog;
 
        /*
         * First, test handling when a non-existent compression
@@ -61,16 +60,15 @@ DEFINE_TEST(test_read_compress_program)
        /*
         * If we have "gzip -d", try using that.
         */
-       if ((extprog = external_gzip_program(1)) == NULL) {
-               skipping("There is no gzip uncompression "
-                   "program in this platform");
+       if (!canGunzip()) {
+               skipping("Can't run gunzip program on this platform");
                return;
        }
        assert((a = archive_read_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK,
            archive_read_support_compression_none(a));
        assertEqualIntA(a, ARCHIVE_OK,
-           archive_read_support_compression_program(a, extprog));
+           archive_read_support_compression_program(a, "gunzip"));
        assertEqualIntA(a, ARCHIVE_OK,
            archive_read_support_format_all(a));
        assertEqualIntA(a, ARCHIVE_OK,
index c67c57749b661cc4fda41e9587360653af882c43..aaec28fb9f286434cad909013a78064561d651b3 100644 (file)
@@ -38,12 +38,9 @@ DEFINE_TEST(test_write_compress_program)
        size_t used;
        int blocksize = 1024;
        int r;
-       const char *compprog, *decompprog;
 
-       decompprog = external_gzip_program(1);
-       if ((compprog = external_gzip_program(0)) == NULL) {
-               skipping("There is no gzip compression "
-                   "program in this platform");
+       if (!canGzip()) {
+               skipping("Cannot run 'gzip'");
                return;
        }
 
@@ -51,7 +48,7 @@ DEFINE_TEST(test_write_compress_program)
        /* Write it through an external "gzip" program. */
        assert((a = archive_write_new()) != NULL);
        assertA(0 == archive_write_set_format_ustar(a));
-       r = archive_write_set_compression_program(a, compprog);
+       r = archive_write_set_compression_program(a, "gzip");
        if (r == ARCHIVE_FATAL) {
                skipping("Write compression via external "
                    "program unsupported on this platform");
@@ -91,8 +88,8 @@ DEFINE_TEST(test_write_compress_program)
        /* The compression_gzip() handler will fall back to gunzip
         * automatically, but if we know gunzip isn't available, then
         * skip the rest. */
-       if (r != ARCHIVE_OK && decompprog == NULL) {
-               skipping("No gzip decompression is available; "
+       if (r != ARCHIVE_OK && !canGunzip()) {
+               skipping("No libz and no gunzip program, "
                    "unable to verify gzip compression");
                assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
                return;
index faf4b425d63ab202a56cab281d8d860740cdb552..121407535e55d4816a4c82cd728b208e60222616 100644 (file)
@@ -194,7 +194,7 @@ DEFINE_TEST(test_write_disk_hardlink)
        assertIsReg("link1a", 0755 & ~UMASK);
        assertFileSize("link1a", sizeof(data));
        assertFileNLinks("link1a", 2);
-       assertFileHardlinks("link1a", "link1b");
+       assertIsHardlink("link1a", "link1b");
 
        /* Test #2: Should produce identical results to test #1 */
        /* Note that marking a hardlink with size = 0 is treated the
@@ -206,18 +206,18 @@ DEFINE_TEST(test_write_disk_hardlink)
        assertIsReg("link2a", 0755 & ~UMASK);
        assertFileSize("link2a", sizeof(data));
        assertFileNLinks("link2a", 2);
-       assertFileHardlinks("link2a", "link2b");
+       assertIsHardlink("link2a", "link2b");
 
        /* Test #3 */
        assertIsReg("link3a", 0755 & ~UMASK);
        assertFileSize("link3a", sizeof(data));
        assertFileNLinks("link3a", 2);
-       assertFileHardlinks("link3a", "link3b");
+       assertIsHardlink("link3a", "link3b");
 
        /* Test #4 */
        assertIsReg("link4a", 0755 & ~UMASK);
        assertFileNLinks("link4a", 2);
        assertFileSize("link4a", sizeof(data));
-       assertFileHardlinks("link4a", "link4b");
+       assertIsHardlink("link4a", "link4b");
 #endif
 }
index b955b33d6e743e106f48a553adabba94600b1ad9..51a468393fe2759b1a38c1c595be6e756888582b 100644 (file)
  * TODO: Move this into a separate configuration header, have all test
  * suites share one copy of this file.
  */
+__FBSDID("$FreeBSD: src/usr.bin/tar/test/main.c,v 1.6 2008/11/05 06:40:53 kientzle Exp $");
+#define KNOWNREF       "test_patterns_2.tar.uu"
+#define ENVBASE "BSDTAR"  /* Prefix for environment variables. */
 #define        PROGRAM "bsdtar"  /* Name of program being tested. */
 #undef LIBRARY           /* Not testing a library. */
-#define ENVBASE "BSDTAR"  /* Prefix for environment variables. */
 #undef EXTRA_DUMP           /* How to dump extra data */
 /* How to generate extra version info. */
 #define        EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
-#define KNOWNREF       "test_patterns_2.tar.uu"
-__FBSDID("$FreeBSD: src/usr.bin/tar/test/main.c,v 1.6 2008/11/05 06:40:53 kientzle Exp $");
 
 /*
  *
@@ -132,6 +132,21 @@ my_CreateHardLinkA(const char *linkname, const char *target)
        }
        return f == NULL ? 0 : (*f)(linkname, target, NULL);
 }
+
+int
+my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
+{
+       HANDLE h;
+       int r;
+
+       h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
+               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+       if (h == INVALID_HANDLE_VALUE)
+               return (0);
+       r = GetFileInformationByHandle(h, bhfi);
+       CloseHandle(h);
+       return (r);
+}
 #endif
 
 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__)
@@ -793,11 +808,32 @@ assertion_text_file_contents(const char *buff, const char *fn)
        return (0);
 }
 
-/* Verify that two paths point to the same file. */
-int
-assertion_file_hardlinks(const char *file, int line,
+/* Test that two paths point to the same file. */
+/* As a side-effect, asserts that both files exist. */
+static int
+is_hardlink(const char *file, int line,
     const char *path1, const char *path2)
 {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
+       int r;
+
+       assertion_count(file, line);
+       r = my_GetFileInformationByName(path1, &bhfi1);
+       if (r == 0) {
+               failure_start(file, line, "File %s can't be inspected?", path1);
+               failure_finish(NULL);
+               return (0);
+       }
+       r = my_GetFileInformationByName(path2, &bhfi2);
+       if (r == 0) {
+               failure_start(file, line, "File %s can't be inspected?", path2);
+               failure_finish(NULL);
+               return (0);
+       }
+       return (bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
+               && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
+#else
        struct stat st1, st2;
        int r;
 
@@ -814,13 +850,32 @@ assertion_file_hardlinks(const char *file, int line,
                failure_finish(NULL);
                return (0);
        }
-       if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
-               failure_start(file, line,
-                   "Files %s and %s are not hardlinked", path1, path2);
-               failure_finish(NULL);
-               return (0);
-       }
-       return (1);
+       return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
+#endif
+}
+
+int
+assertion_is_hardlink(const char *file, int line,
+    const char *path1, const char *path2)
+{
+       if (is_hardlink(file, line, path1, path2))
+               return (1);
+       failure_start(file, line,
+           "Files %s and %s are not hardlinked", path1, path2);
+       failure_finish(NULL);
+       return (0);
+}
+
+int
+assertion_is_not_hardlink(const char *file, int line,
+    const char *path1, const char *path2)
+{
+       if (!is_hardlink(file, line, path1, path2))
+               return (1);
+       failure_start(file, line,
+           "Files %s and %s should not be hardlinked", path1, path2);
+       failure_finish(NULL);
+       return (0);
 }
 
 /* Verify a/b/mtime of 'pathname'. */
@@ -971,19 +1026,11 @@ assertion_file_nlinks(const char *file, int line,
     const char *pathname, int nlinks)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-       HANDLE h;
        BY_HANDLE_FILE_INFORMATION bhfi;
        int r;
 
        assertion_count(file, line);
-       h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
-               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-       if (h == INVALID_HANDLE_VALUE) {
-               failure_start(file, line, "Can't access %s", pathname);
-               failure_finish(NULL);
-               return (0);
-       }
-       r = GetFileInformationByHandle(h, &bhfi);
+       r = my_GetFileInformationByName(pathname, &bhfi);
        if (r != 0 && bhfi.nNumberOfLinks == nlinks)
                return (1);
        failure_start(file, line, "File %s has %d links, expected %d",
@@ -1086,17 +1133,14 @@ assertion_is_reg(const char *file, int line, const char *pathname, int mode)
        return (1);
 }
 
-/* Verify that 'pathname' is a symbolic link.  If 'contents' is
+/* Check whether 'pathname' is a symbolic link.  If 'contents' is
  * non-NULL, verify that the symlink has those contents. */
-int
-assertion_is_symlink(const char *file, int line,
+static int
+is_symlink(const char *file, int line,
     const char *pathname, const char *contents)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
        assertion_count(file, line);
-       /* TODO: Vista supports symlinks */
-       failure_start(file, line, "Symlink %s not supported", pathname);
-       failure_finish(NULL);
        return (0);
 #else
        char buff[300];
@@ -1112,11 +1156,8 @@ assertion_is_symlink(const char *file, int line,
                failure_finish(NULL);
                return (0);
        }
-       if (!S_ISLNK(st.st_mode)) {
-               failure_start(file, line, "%s should be a symlink", pathname);
-               failure_finish(NULL);
+       if (!S_ISLNK(st.st_mode))
                return (0);
-       }
        if (contents == NULL)
                return (1);
        linklen = readlink(pathname, buff, sizeof(buff));
@@ -1126,17 +1167,29 @@ assertion_is_symlink(const char *file, int line,
                return (0);
        }
        buff[linklen] = '\0';
-       if (strcmp(buff, contents) != 0) {
-               failure_start(file, line, "Wrong symlink %s", pathname);
-               logprintf("   Expected: %s\n", contents);
-               logprintf("   Found: %s\n", buff);
-               failure_finish(NULL);
+       if (strcmp(buff, contents) != 0)
                return (0);
-       }
        return (1);
 #endif
 }
 
+/* Assert that path is a symlink that (optionally) contains contents. */
+int
+assertion_is_symlink(const char *file, int line,
+    const char *path, const char *contents)
+{
+       if (is_symlink(file, line, path, contents))
+               return (1);
+       if (contents)
+               failure_start(file, line, "File %s is not a symlink to %s",
+                   path, contents);
+       else
+               failure_start(file, line, "File %s is not a symlink", path);
+       failure_finish(NULL);
+       return (0);
+}
+
+
 /* Create a directory and report any errors. */
 int
 assertion_make_dir(const char *file, int line, const char *dirname, int mode)
@@ -1267,6 +1320,68 @@ assertion_umask(const char *file, int line, int mask)
  *
  */
 
+/*
+ * Check whether platform supports symlinks.  This is intended
+ * for tests to use in deciding whether to bother testing symlink
+ * support; if the platform doesn't support symlinks, there's no point
+ * in checking whether the program being tested can create them.
+ */
+int
+canSymlink(void)
+{
+       /* Remember the test result */
+       static int value = 0, tested = 1;
+       if (tested)
+               return (value);
+
+       ++tested;
+       assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a");
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
+           && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
+#elif HAVE_SYMLINK
+       value = (0 == symlink("canSymlink.0", "canSymlink.1"))
+           && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
+#endif
+       return (value);
+}
+
+/*
+ * Can this platform run the gzip program?
+ */
+/* Platform-dependent options for hiding the output of a subcommand. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
+#else
+static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
+#endif
+int
+canGzip(void)
+{
+       static int tested = 0, value = 0;
+       if (!tested) {
+               tested = 1;
+               if (systemf("gzip -V %s", redirectArgs) == 0)
+                       value = 1;
+       }
+       return (value);
+}
+
+/*
+ * Can this platform run the gunzip program?
+ */
+int
+canGunzip(void)
+{
+       static int tested = 0, value = 0;
+       if (!tested) {
+               tested = 1;
+               if (systemf("gunzip -V %s", redirectArgs) == 0)
+                       value = 1;
+       }
+       return (value);
+}
+
 /*
  * Sleep as needed; useful for verifying disk timestamp changes by
  * ensuring that the wall-clock time has actually changed before we
index 01e870baf46a51c3ad939bc88993b7cc81779bfb..ad667ac04516fff09b7cb1913aecbe36869ab871 100644 (file)
 /* Assert that file contents match a string; supports printf-style arguments. */
 #define assertFileContents             \
   assertion_setup(__FILE__, __LINE__);assertion_file_contents
-#define assertFileHardlinks(path1, path2)      \
-  assertion_file_hardlinks(__FILE__, __LINE__, path1, path2)
 #define assertFileMtime(pathname, sec, nsec)   \
   assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
 #define assertFileMtimeRecent(pathname) \
   assertion_setup(__FILE__, __LINE__);assertion_text_file_contents
 #define assertIsDir(pathname, mode)            \
   assertion_is_dir(__FILE__, __LINE__, pathname, mode)
+#define assertIsHardlink(path1, path2) \
+  assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
+#define assertIsNotHardlink(path1, path2)      \
+  assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
 #define assertIsReg(pathname, mode)            \
   assertion_is_reg(__FILE__, __LINE__, pathname, mode)
 #define assertIsSymlink(pathname, contents)    \
@@ -221,13 +223,14 @@ int assertion_file_birthtime(const char *, int, const char *, long, long);
 int assertion_file_birthtime_recent(const char *, int, const char *);
 int assertion_file_contents(const void *, int, const char *, ...);
 int assertion_file_exists(const char *, ...);
-int assertion_file_hardlinks(const char *, int, const char *, const char *);
 int assertion_file_mtime(const char *, int, const char *, long, long);
 int assertion_file_mtime_recent(const char *, int, const char *);
 int assertion_file_nlinks(const char *, int, const char *, int);
 int assertion_file_not_exists(const char *, ...);
 int assertion_file_size(const char *, int, const char *, long);
 int assertion_is_dir(const char *, int, const char *, int);
+int assertion_is_hardlink(const char *, int, const char *, const char *);
+int assertion_is_not_hardlink(const char *, int, const char *, const char *);
 int assertion_is_reg(const char *, int, const char *, int);
 int assertion_is_symlink(const char *, int, const char *, const char *);
 int assertion_make_dir(const char *, int, const char *, int);
@@ -238,6 +241,7 @@ int assertion_non_empty_file(const char *, ...);
 int assertion_text_file_contents(const char *buff, const char *f);
 int assertion_umask(const char *, int, int);
 void assertion_setup(const char *, int);
+
 void test_skipping(const char *fmt, ...);
 
 /* Like sprintf, then system() */
@@ -246,6 +250,15 @@ int systemf(const char * fmt, ...);
 /* Delay until time() returns a value after this. */
 void sleepUntilAfter(time_t);
 
+/* Return true if this platform can create symlinks. */
+int canSymlink(void);
+
+/* Return true if this platform can run the "gzip" program. */
+int canGzip(void);
+
+/* Return true if this platform can run the "gunzip" program. */
+int canGunzip(void);
+
 /* Suck file into string allocated via malloc(). Call free() when done. */
 /* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
 char *slurpfile(size_t *, const char *fmt, ...);
index aa5995f5f005bc4c6811d1779d41714892537445..ed8785cac9cb33f8b8be07e3b7187f9d7d4ec8dd 100644 (file)
@@ -67,12 +67,11 @@ basic_tar(const char *target, const char *pack_options,
        assertIsReg("linkfile", -1);
        assertFileSize("linkfile", 10);
        assertFileNLinks("linkfile", 2);
-       assertFileHardlinks("file", "linkfile");
+       assertIsHardlink("file", "linkfile");
 
-#if !defined(_WIN32) || defined(__CYGWIN__)
        /* Symlink */
-       assertIsSymlink("symlink", "file");
-#endif
+       if (canSymlink())
+               assertIsSymlink("symlink", "file");
 
        /* dir */
        assertIsDir("dir", 0775);
@@ -96,12 +95,16 @@ DEFINE_TEST(test_basic)
        assertMakeHardlink("linkfile", "file");
 
        /* Symlink to above file. */
-       assertMakeSymlink("symlink", "file");
+       if (canSymlink())
+               assertMakeSymlink("symlink", "file");
 
        /* Directory. */
        assertMakeDir("dir", 0775);
 
-       flist = "file linkfile symlink dir";
+       if (canSymlink())
+               flist = "file linkfile symlink dir";
+       else
+               flist = "file linkfile dir";
        /* Archive/dearchive with a variety of options. */
        basic_tar("copy", "", "", flist);
        /* tar doesn't handle cpio symlinks correctly */
index 7e0c6938bb0b3354efdadad5fbe738391dcb93c8..8ddaafd2f5760f8f8f6804e9e2198cda62b4a2b9 100644 (file)
@@ -30,12 +30,27 @@ __FBSDID("$FreeBSD: src/usr.bin/tar/test/test_copy.c,v 1.3 2008/08/15 06:12:02 k
 # include <sys/cygwin.h>
 #endif
 
-/* assumes that cwd is the top of the test tree. Furthermore,
- * assumes that this function is first called with the "longest"
- * cwd involved in the tests.  That is, from
- *  <testdir>/original
- * as opposed to
- *  <testdir>/plain or <testdir>/ustar
+/*
+ * Try to figure out how deep we can go in our tests.  Assumes that
+ * the first call to this function has the longest starting cwd (which
+ * is currently "<testdir>/original").  This is mostly to work around
+ * limits in our Win32 support.
+ *
+ * Background: On Posix systems, PATH_MAX is merely a limit on the
+ * length of the string passed into a system call.  By repeatedly
+ * calling chdir(), you can work with arbitrarily long paths on such
+ * systems.  In contrast, Win32 APIs apply PATH_MAX limits to the full
+ * absolute path, so the permissible length of a system call argument
+ * varies with the cwd. Some APIs actually enforce limits
+ * significantly less than PATH_MAX to ensure that you can create
+ * files within the current working directory.  The Win32 limits also
+ * apply to Cygwin before 1.7.
+ *
+ * Someday, I want to convert the Win32 support to use newer
+ * wide-character paths with '\\?\' prefix, which has a 32k PATH_MAX
+ * instead of the rather anemic 260 character limit of the older
+ * system calls.  Then we can drop this mess (unless we want to
+ * continue to special-case Cygwin 1.5 and earlier).
  */
 static int
 compute_loop_max(void)
@@ -48,15 +63,10 @@ compute_loop_max(void)
        if (LOOP_MAX == 0) {
                assert(_getcwd(buf, MAX_PATH) != NULL);
                cwdlen = strlen(buf);
-               /* on windows, can't create a directory in which there is not
-                * enough room left in MAX_PATH to /also/ create an 8.3 file.
-                * Thus, max path len for mkdir is MAX_PATH - 12 ("12345678.123")
-                * It is possible also that windows counts the length of cwd against
-                * the MAX_PATH maximum, so account for that. Next, account also for
-                * "/".  And lastly, account for the fact that the relative path
-                * has 4 characters when the loop count i = 0.
-                */
-                LOOP_MAX = MAX_PATH - 12 - (int)cwdlen - 1 - 4;
+               /* 12 characters = length of 8.3 filename */
+               /* 4 characters = length of "/../" used in symlink tests */
+               /* 1 character = length of extra "/" separator */
+               LOOP_MAX = MAX_PATH - (int)cwdlen - 12 - 4 - 1;
        }
        return LOOP_MAX;
 #elif defined(__CYGWIN__) && !defined(HAVE_CYGWIN_CONV_PATH)
@@ -72,19 +82,8 @@ compute_loop_max(void)
                cygwin_conv_to_full_win32_path(pbuf, wbuf);
                wcwdlen = strlen(wbuf);
                cwdlen = ((wcwdlen > pcwdlen) ? wcwdlen : pcwdlen);
-               /* on windows, can't create a directory in which there is not
-                * enough room left in PATH_MAX to /also/ create an 8.3 file.
-                * Thus, max path len for mkdir is PATH_MAX - 12 ("12345678.123")
-                * Then, because cygwin treats even relative paths as if they were
-                * absolute, and cwd counts against the PATH_MAX maximum, we must
-                * account for that (using worst case of posix or win32 equivalents).
-                * Next, account also for "/../" (as used in symlink creation test).
-                * And lastly, account for the fact that the relative path has 4
-                * characters when the loop count i = 0. These calculations do not
-                * apply to cygwin-1.7, because unlike older cygwin, it uses the "wide"
-                * functions of the win32 system for all file and directory access.
-                */
-               LOOP_MAX = PATH_MAX - 12 - (int)cwdlen - 4 - 4;
+               /* Cygwin helper needs an extra few characters. */
+               LOOP_MAX = PATH_MAX - (int)cwdlen - 12 - 4 - 4;
        }
        return LOOP_MAX;
 #else
@@ -134,18 +133,18 @@ create_tree(void)
                buff2[0] = 'm';
                assertMakeHardlink(buff2, buff);
 
-#if !defined(_WIN32) || defined(__CYGWIN__)
-               /* Create a symlink named "s/abcdef..." to the above. */
-               strcpy(buff2 + 3, buff);
-               buff[0] = 's';
-               buff2[0] = '.';
-               buff2[1] = '.';
-               buff2[2] = '/';
-               failure("buff=\"%s\" buff2=\"%s\"", buff, buff2);
-               assertMakeSymlink(buff, buff2);
-#else
-               skipping("create a symlink to the above");
-#endif
+               if (canSymlink()) {
+                       /* Create a symlink named "s/abcdef..." to the above. */
+                       strcpy(buff2 + 3, buff);
+                       buff[0] = 's';
+                       buff2[0] = '.';
+                       buff2[1] = '.';
+                       buff2[2] = '/';
+                       failure("buff=\"%s\" buff2=\"%s\"", buff, buff2);
+                       assertMakeSymlink(buff, buff2);
+               } else {
+                       skipping("Symlink tests");
+               }
                /* Create a dir named "d/abcdef...". */
                buff[0] = 'd';
                failure("buff=\"%s\"", buff);
@@ -196,23 +195,21 @@ verify_tree(int limit)
                strcat(name2, filename);
                if (limit != LIMIT_USTAR || strlen(name2) <= 100) {
                        /* Verify hardlink "l/abcdef..." */
-                       assertFileHardlinks(name1, name2);
+                       assertIsHardlink(name1, name2);
                        /* Verify hardlink "m/abcdef..." */
                        name2[0] = 'm';
-                       assertFileHardlinks(name1, name2);
+                       assertIsHardlink(name1, name2);
                }
 
-#if !defined(_WIN32) || defined(__CYGWIN__)
-               /* Verify symlink "s/abcdef..." */
-               strcpy(name1, "s/");
-               strcat(name1, filename);
-               strcpy(name2, "../f/");
-               strcat(name2, filename);
-               if (limit != LIMIT_USTAR || strlen(name2) <= 100)
-                       assertIsSymlink(name1, name2);
-#else
-               skipping("verify symlink");
-#endif
+               if (canSymlink()) {
+                       /* Verify symlink "s/abcdef..." */
+                       strcpy(name1, "s/");
+                       strcat(name1, filename);
+                       strcpy(name2, "../f/");
+                       strcat(name2, filename);
+                       if (limit != LIMIT_USTAR || strlen(name2) <= 100)
+                               assertIsSymlink(name1, name2);
+               }
 
                /* Verify dir "d/abcdef...". */
                strcpy(name1, "d/");