From: Tim Kientzle Date: Sat, 12 Sep 2009 18:08:48 +0000 (-0400) Subject: Merge cpio test refactorings into tar and libarchive test harnesses, X-Git-Tag: v2.8.0~352 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=454f37f78be5f3bcad492a453fccc3a6fd3c9d92;p=thirdparty%2Flibarchive.git Merge cpio test refactorings into tar and libarchive test harnesses, 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 --- diff --git a/cpio/test/main.c b/cpio/test/main.c index 15ee56719..d0d58013d 100644 --- a/cpio/test/main.c +++ b/cpio/test/main.c @@ -36,14 +36,14 @@ * 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 diff --git a/cpio/test/test.h b/cpio/test/test.h index e2e83b3ef..b275da477 100644 --- a/cpio/test/test.h +++ b/cpio/test/test.h @@ -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, ...); diff --git a/libarchive/test/main.c b/libarchive/test/main.c index 296e3f56f..0436ca6d5 100644 --- a/libarchive/test/main.c +++ b/libarchive/test/main.c @@ -36,13 +36,13 @@ * 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); -} diff --git a/libarchive/test/test.h b/libarchive/test/test.h index d5c06b331..9c3ad7fea 100644 --- a/libarchive/test/test.h +++ b/libarchive/test/test.h @@ -165,8 +165,6 @@ /* 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) \ @@ -179,6 +177,10 @@ 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) \ diff --git a/libarchive/test/test_read_compress_program.c b/libarchive/test/test_read_compress_program.c index 2d9e22b0b..bb5fde84a 100644 --- a/libarchive/test/test_read_compress_program.c +++ b/libarchive/test/test_read_compress_program.c @@ -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, diff --git a/libarchive/test/test_write_compress_program.c b/libarchive/test/test_write_compress_program.c index c67c57749..aaec28fb9 100644 --- a/libarchive/test/test_write_compress_program.c +++ b/libarchive/test/test_write_compress_program.c @@ -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; diff --git a/libarchive/test/test_write_disk_hardlink.c b/libarchive/test/test_write_disk_hardlink.c index faf4b425d..121407535 100644 --- a/libarchive/test/test_write_disk_hardlink.c +++ b/libarchive/test/test_write_disk_hardlink.c @@ -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 } diff --git a/tar/test/main.c b/tar/test/main.c index b955b33d6..51a468393 100644 --- a/tar/test/main.c +++ b/tar/test/main.c @@ -36,14 +36,14 @@ * 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 diff --git a/tar/test/test.h b/tar/test/test.h index 01e870baf..ad667ac04 100644 --- a/tar/test/test.h +++ b/tar/test/test.h @@ -166,8 +166,6 @@ /* 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) \ @@ -180,6 +178,10 @@ 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, ...); diff --git a/tar/test/test_basic.c b/tar/test/test_basic.c index aa5995f5f..ed8785cac 100644 --- a/tar/test/test_basic.c +++ b/tar/test/test_basic.c @@ -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 */ diff --git a/tar/test/test_copy.c b/tar/test/test_copy.c index 7e0c6938b..8ddaafd2f 100644 --- a/tar/test/test_copy.c +++ b/tar/test/test_copy.c @@ -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 #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 - * /original - * as opposed to - * /plain or /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 "/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/");