diff options
author | kientzle <kientzle@FreeBSD.org> | 2008-05-26 17:15:35 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2008-05-26 17:15:35 +0000 |
commit | 30d8209b8c69c616197b5e55f065d60b16235e77 (patch) | |
tree | 77cecd8fd6408385dac912ef7066edb8f24181a8 /usr.bin/cpio/test | |
parent | 0280e5aa4936e9ec440f688cb114b582e7926d28 (diff) | |
download | FreeBSD-src-30d8209b8c69c616197b5e55f065d60b16235e77.zip FreeBSD-src-30d8209b8c69c616197b5e55f065d60b16235e77.tar.gz |
Initial commit of bsdcpio 0.9.11b.
A new implementation of cpio that uses libarchive as it's back-end
archiving/dearchiving infrastructure. Includes test harness;
"make check" in the bsdcpio directory to build and run the test
harness.
Diffstat (limited to 'usr.bin/cpio/test')
32 files changed, 3458 insertions, 0 deletions
diff --git a/usr.bin/cpio/test/Makefile b/usr.bin/cpio/test/Makefile new file mode 100644 index 0000000..a913975 --- /dev/null +++ b/usr.bin/cpio/test/Makefile @@ -0,0 +1,72 @@ +# $FreeBSD$ + +# Where to find the cpio sources (for the internal unit tests) +CPIO_SRCDIR=${.CURDIR}/.. +.PATH: ${CPIO_SRCDIR} + +# Some cpio sources are pulled in for white-box tests +CPIO_SRCS= cmdline.c err.c pathmatch.c + +TESTS= \ + test_0.c \ + test_basic.c \ + test_format_newc.c \ + test_gcpio_compat.c \ + test_option_a.c \ + test_option_B.c \ + test_option_c.c \ + test_option_d.c \ + test_option_f.c \ + test_option_help.c \ + test_option_L.c \ + test_option_ell.c \ + test_option_m.c \ + test_option_t.c \ + test_option_u.c \ + test_option_version.c \ + test_option_y.c \ + test_option_z.c \ + test_owner_parse.c \ + test_pathmatch.c \ + +# Build the test program +SRCS= list.h \ + ${CPIO_SRCS} \ + ${TESTS} \ + main.c + +CLEANFILES+= list.h + +NO_MAN=yes + +PROG=bsdcpio_test +DPADD=${LIBARCHIVE} ${LIBBZ2} ${LIBZ} +CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\" +CFLAGS+= -I.. +LDADD= -larchive -lz -lbz2 +CFLAGS+= -static -g -O2 -Wall +CFLAGS+= -I${.OBJDIR} +CFLAGS+= -I${CPIO_SRCDIR} + +# Uncomment to link against dmalloc +#LDADD+= -L/usr/local/lib -ldmalloc +#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC +WARNS=6 + +check test: bsdcpio_test + ${.OBJDIR}/bsdcpio_test -p ${.OBJDIR}/../bsdcpio -r ${.CURDIR} + +${.OBJDIR}/list.h list.h: ${TESTS} Makefile + (cd ${.CURDIR}; cat ${TESTS}) | grep DEFINE_TEST > list.h + +clean: + rm -f *.out + rm -f *.o + rm -f *.core + rm -f *~ + rm -f list.h + rm -f archive.h ../archive.h + -chmod -R +w /tmp/bsdcpio_test.* + rm -rf /tmp/bsdcpio_test.* + +.include <bsd.prog.mk> diff --git a/usr.bin/cpio/test/main.c b/usr.bin/cpio/test/main.c new file mode 100644 index 0000000..c88dd2a --- /dev/null +++ b/usr.bin/cpio/test/main.c @@ -0,0 +1,970 @@ +/* + * 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. + */ + +/* + * Various utility routines useful for test programs. + * Each test program is linked against this file. + */ +#include <errno.h> +#include <locale.h> +#include <stdarg.h> +#include <time.h> + +#include "test.h" + +/* + * This same file is used pretty much verbatim for all test harnesses. + * + * The next few lines are the only differences. + */ +#define PROGRAM "bsdcpio" /* Name of program being tested. */ +#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) ? "" : "") +__FBSDID("$FreeBSD$"); + +/* + * "list.h" is simply created by "grep DEFINE_TEST"; it has + * a line like + * DEFINE_TEST(test_function) + * for each test. + * Include it here with a suitable DEFINE_TEST to declare all of the + * test functions. + */ +#undef DEFINE_TEST +#define DEFINE_TEST(name) void name(void); +#include "list.h" + +/* Interix doesn't define these in a standard header. */ +#if __INTERIX__ +extern char *optarg; +extern int optind; +#endif + +/* Enable core dump on failure. */ +static int dump_on_failure = 0; +/* Default is to remove temp dirs for successful tests. */ +static int keep_temp_files = 0; +/* Default is to print some basic information about each test. */ +static int quiet_flag = 0; +/* Default is to summarize repeated failures. */ +static int verbose = 0; +/* Cumulative count of component failures. */ +static int failures = 0; +/* Cumulative count of skipped component tests. */ +static int skips = 0; +/* Cumulative count of assertions. */ +static int assertions = 0; + +/* Directory where uuencoded reference files can be found. */ +static char *refdir; + +/* + * My own implementation of the standard assert() macro emits the + * message in the same format as GCC (file:line: message). + * It also includes some additional useful information. + * This makes it a lot easier to skim through test failures in + * Emacs. ;-) + * + * It also supports a few special features specifically to simplify + * test harnesses: + * failure(fmt, args) -- Stores a text string that gets + * printed if the following assertion fails, good for + * explaining subtle tests. + */ +static char msg[4096]; + +/* + * For each test source file, we remember how many times each + * failure was reported. + */ +static const char *failed_filename = NULL; +static struct line { + int line; + int count; +} failed_lines[1000]; + +/* + * Count this failure; return the number of previous failures. + */ +static int +previous_failures(const char *filename, int line) +{ + unsigned int i; + int count; + + if (failed_filename == NULL || strcmp(failed_filename, filename) != 0) + memset(failed_lines, 0, sizeof(failed_lines)); + failed_filename = filename; + + for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { + if (failed_lines[i].line == line) { + count = failed_lines[i].count; + failed_lines[i].count++; + return (count); + } + if (failed_lines[i].line == 0) { + failed_lines[i].line = line; + failed_lines[i].count = 1; + return (0); + } + } + return (0); +} + +/* + * Copy arguments into file-local variables. + */ +static const char *test_filename; +static int test_line; +static void *test_extra; +void test_setup(const char *filename, int line) +{ + test_filename = filename; + test_line = line; +} + +/* + * Inform user that we're skipping a test. + */ +void +test_skipping(const char *fmt, ...) +{ + va_list ap; + + if (previous_failures(test_filename, test_line)) + return; + + va_start(ap, fmt); + fprintf(stderr, " *** SKIPPING: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + ++skips; +} + +/* Common handling of failed tests. */ +static void +report_failure(void *extra) +{ + if (msg[0] != '\0') { + fprintf(stderr, " Description: %s\n", msg); + msg[0] = '\0'; + } + +#ifdef EXTRA_DUMP + if (extra != NULL) + fprintf(stderr, " detail: %s\n", EXTRA_DUMP(extra)); +#else + (void)extra; /* UNUSED */ +#endif + + if (dump_on_failure) { + fprintf(stderr, + " *** forcing core dump so failure can be debugged ***\n"); + *(char *)(NULL) = 0; + exit(1); + } +} + +/* + * Summarize repeated failures in the just-completed test file. + * The reports above suppress multiple failures from the same source + * line; this reports on any tests that did fail multiple times. + */ +static int +summarize_comparator(const void *a0, const void *b0) +{ + const struct line *a = a0, *b = b0; + if (a->line == 0 && b->line == 0) + return (0); + if (a->line == 0) + return (1); + if (b->line == 0) + return (-1); + return (a->line - b->line); +} + +static void +summarize(void) +{ + unsigned int i; + + qsort(failed_lines, sizeof(failed_lines)/sizeof(failed_lines[0]), + sizeof(failed_lines[0]), summarize_comparator); + for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { + if (failed_lines[i].line == 0) + break; + if (failed_lines[i].count > 1) + fprintf(stderr, "%s:%d: Failed %d times\n", + failed_filename, failed_lines[i].line, + failed_lines[i].count); + } + /* Clear the failure history for the next file. */ + memset(failed_lines, 0, sizeof(failed_lines)); +} + +/* Set up a message to display only after a test fails. */ +void +failure(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + va_end(ap); +} + +/* Generic assert() just displays the failed condition. */ +int +test_assert(const char *file, int line, int value, const char *condition, void *extra) +{ + ++assertions; + if (value) { + msg[0] = '\0'; + return (value); + } + failures ++; + if (!verbose && previous_failures(file, line)) + return (value); + fprintf(stderr, "%s:%d: Assertion failed\n", file, line); + fprintf(stderr, " Condition: %s\n", condition); + report_failure(extra); + return (value); +} + +/* assertEqualInt() displays the values of the two integers. */ +int +test_assert_equal_int(const char *file, int line, + int v1, const char *e1, int v2, const char *e2, void *extra) +{ + ++assertions; + if (v1 == v2) { + msg[0] = '\0'; + return (1); + } + failures ++; + if (!verbose && previous_failures(file, line)) + return (0); + fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n", + file, line); + fprintf(stderr, " %s=%d\n", e1, v1); + fprintf(stderr, " %s=%d\n", e2, v2); + report_failure(extra); + return (0); +} + +static void strdump(const char *p) +{ + if (p == NULL) { + fprintf(stderr, "(null)"); + return; + } + fprintf(stderr, "\""); + while (*p != '\0') { + unsigned int c = 0xff & *p++; + switch (c) { + case '\a': fprintf(stderr, "\a"); break; + case '\b': fprintf(stderr, "\b"); break; + case '\n': fprintf(stderr, "\n"); break; + case '\r': fprintf(stderr, "\r"); break; + default: + if (c >= 32 && c < 127) + fprintf(stderr, "%c", c); + else + fprintf(stderr, "\\x%02X", c); + } + } + fprintf(stderr, "\""); +} + +/* assertEqualString() displays the values of the two strings. */ +int +test_assert_equal_string(const char *file, int line, + const char *v1, const char *e1, + const char *v2, const char *e2, + void *extra) +{ + ++assertions; + if (v1 == NULL || v2 == NULL) { + if (v1 == v2) { + msg[0] = '\0'; + return (1); + } + } else if (strcmp(v1, v2) == 0) { + msg[0] = '\0'; + return (1); + } + failures ++; + if (!verbose && previous_failures(file, line)) + return (0); + fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n", + file, line); + fprintf(stderr, " %s = ", e1); + strdump(v1); + fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : strlen(v1)); + fprintf(stderr, " %s = ", e2); + strdump(v2); + fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : strlen(v2)); + report_failure(extra); + return (0); +} + +static void wcsdump(const wchar_t *w) +{ + if (w == NULL) { + fprintf(stderr, "(null)"); + return; + } + fprintf(stderr, "\""); + while (*w != L'\0') { + unsigned int c = *w++; + if (c >= 32 && c < 127) + fprintf(stderr, "%c", c); + else if (c < 256) + fprintf(stderr, "\\x%02X", c); + else if (c < 0x10000) + fprintf(stderr, "\\u%04X", c); + else + fprintf(stderr, "\\U%08X", c); + } + fprintf(stderr, "\""); +} + +/* assertEqualWString() displays the values of the two strings. */ +int +test_assert_equal_wstring(const char *file, int line, + const wchar_t *v1, const char *e1, + const wchar_t *v2, const char *e2, + void *extra) +{ + ++assertions; + if (v1 == NULL) { + if (v2 == NULL) { + msg[0] = '\0'; + return (1); + } + } else if (v2 == NULL) { + if (v1 == NULL) { + msg[0] = '\0'; + return (1); + } + } else if (wcscmp(v1, v2) == 0) { + msg[0] = '\0'; + return (1); + } + failures ++; + if (!verbose && previous_failures(file, line)) + return (0); + fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n", + file, line); + fprintf(stderr, " %s = ", e1); + wcsdump(v1); + fprintf(stderr, "\n"); + fprintf(stderr, " %s = ", e2); + wcsdump(v2); + fprintf(stderr, "\n"); + report_failure(extra); + return (0); +} + +/* + * Pretty standard hexdump routine. As a bonus, if ref != NULL, then + * any bytes in p that differ from ref will be highlighted with '_' + * before and after the hex value. + */ +static void +hexdump(const char *p, const char *ref, size_t l, size_t offset) +{ + size_t i, j; + char sep; + + for(i=0; i < l; i+=16) { + fprintf(stderr, "%04x", i + offset); + sep = ' '; + for (j = 0; j < 16 && i + j < l; j++) { + if (ref != NULL && p[i + j] != ref[i + j]) + sep = '_'; + fprintf(stderr, "%c%02x", sep, 0xff & (int)p[i+j]); + if (ref != NULL && p[i + j] == ref[i + j]) + sep = ' '; + } + for (; j < 16; j++) { + fprintf(stderr, "%c ", sep); + sep = ' '; + } + fprintf(stderr, "%c", sep); + for (j=0; j < 16 && i + j < l; j++) { + int c = p[i + j]; + if (c >= ' ' && c <= 126) + fprintf(stderr, "%c", c); + else + fprintf(stderr, "."); + } + fprintf(stderr, "\n"); + } +} + +/* assertEqualMem() displays the values of the two memory blocks. */ +/* TODO: For long blocks, hexdump the first bytes that actually differ. */ +int +test_assert_equal_mem(const char *file, int line, + const char *v1, const char *e1, + const char *v2, const char *e2, + size_t l, const char *ld, void *extra) +{ + ++assertions; + if (v1 == NULL || v2 == NULL) { + if (v1 == v2) { + msg[0] = '\0'; + return (1); + } + } else if (memcmp(v1, v2, l) == 0) { + msg[0] = '\0'; + return (1); + } + failures ++; + if (!verbose && previous_failures(file, line)) + return (0); + fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n", + file, line); + fprintf(stderr, " size %s = %d\n", ld, (int)l); + fprintf(stderr, " Dump of %s\n", e1); + hexdump(v1, v2, l < 32 ? l : 32, 0); + fprintf(stderr, " Dump of %s\n", e2); + hexdump(v2, v1, l < 32 ? l : 32, 0); + fprintf(stderr, "\n"); + report_failure(extra); + return (0); +} + +int +test_assert_empty_file(const char *f1fmt, ...) +{ + char buff[1024]; + char f1[1024]; + struct stat st; + va_list ap; + ssize_t s; + int fd; + + + 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 not empty: %s\n", test_filename, test_line, f1); + fprintf(stderr, " File size: %d\n", (int)st.st_size); + fprintf(stderr, " Contents:\n"); + fd = open(f1, O_RDONLY); + if (fd < 0) { + fprintf(stderr, " Unable to open %s\n", f1); + } else { + s = sizeof(buff) < st.st_size ? sizeof(buff) : st.st_size; + s = read(fd, buff, s); + hexdump(buff, NULL, s, 0); + } + report_failure(NULL); + return (0); +} + +/* assertEqualFile() asserts that two files have the same contents. */ +/* TODO: hexdump the first bytes that actually differ. */ +int +test_assert_equal_file(const char *f1, const char *f2pattern, ...) +{ + char f2[1024]; + va_list ap; + char buff1[1024]; + char buff2[1024]; + int fd1, fd2; + int n1, n2; + + va_start(ap, f2pattern); + vsprintf(f2, f2pattern, ap); + va_end(ap); + + fd1 = open(f1, O_RDONLY); + fd2 = open(f2, O_RDONLY); + for (;;) { + n1 = read(fd1, buff1, sizeof(buff1)); + n2 = read(fd2, buff2, sizeof(buff2)); + if (n1 != n2) + break; + if (n1 == 0 && n2 == 0) + return (1); + if (memcmp(buff1, buff2, n1) != 0) + break; + } + failures ++; + if (!verbose && previous_failures(test_filename, test_line)) + return (0); + fprintf(stderr, "%s:%d: Files are not identical\n", + test_filename, test_line); + fprintf(stderr, " file1=\"%s\"\n", f1); + fprintf(stderr, " file2=\"%s\"\n", f2); + report_failure(test_extra); + return (0); +} + +/* assertFileContents() asserts the contents of a file. */ +int +test_assert_file_contents(const void *buff, int s, const char *fpattern, ...) +{ + char f[1024]; + va_list ap; + char *contents; + int fd; + int n; + + va_start(ap, fpattern); + vsprintf(f, fpattern, ap); + va_end(ap); + + fd = open(f, O_RDONLY); + contents = malloc(s * 2); + n = read(fd, contents, s * 2); + if (n == s && memcmp(buff, contents, s) == 0) { + free(contents); + return (1); + } + failures ++; + if (!previous_failures(test_filename, test_line)) { + fprintf(stderr, "%s:%d: File contents don't match\n", + test_filename, test_line); + fprintf(stderr, " file=\"%s\"\n", f); + if (n > 0) + hexdump(contents, buff, n, 0); + else { + fprintf(stderr, " File empty, contents should be:\n"); + hexdump(buff, NULL, s, 0); + } + report_failure(test_extra); + } + free(contents); + return (0); +} + +/* + * Call standard system() call, but build up the command line using + * sprintf() conventions. + */ +int +systemf(const char *fmt, ...) +{ + char buff[8192]; + va_list ap; + int r; + + va_start(ap, fmt); + vsprintf(buff, fmt, ap); + r = system(buff); + va_end(ap); + return (r); +} + +/* + * Slurp a file into memory for ease of comparison and testing. + * Returns size of file in 'sizep' if non-NULL, null-terminates + * data in memory for ease of use. + */ +char * +slurpfile(size_t * sizep, const char *fmt, ...) +{ + char filename[8192]; + struct stat st; + va_list ap; + char *p; + ssize_t bytes_read; + int fd; + int r; + + va_start(ap, fmt); + vsprintf(filename, fmt, ap); + va_end(ap); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + /* Note: No error; non-existent file is okay here. */ + return (NULL); + } + r = fstat(fd, &st); + if (r != 0) { + fprintf(stderr, "Can't stat file %s\n", filename); + close(fd); + return (NULL); + } + p = malloc(st.st_size + 1); + if (p == NULL) { + fprintf(stderr, "Can't allocate %ld bytes of memory to read file %s\n", (long int)st.st_size, filename); + close(fd); + return (NULL); + } + bytes_read = read(fd, p, st.st_size); + if (bytes_read < st.st_size) { + fprintf(stderr, "Can't read file %s\n", filename); + close(fd); + free(p); + return (NULL); + } + p[st.st_size] = '\0'; + if (sizep != NULL) + *sizep = (size_t)st.st_size; + close(fd); + return (p); +} + +/* + * "list.h" is automatically generated; it just has a lot of lines like: + * DEFINE_TEST(function_name) + * It's used above to declare all of the test functions. + * We reuse it here to define a list of all tests (functions and names). + */ +#undef DEFINE_TEST +#define DEFINE_TEST(n) { n, #n }, +struct { void (*func)(void); const char *name; } tests[] = { + #include "list.h" +}; + +/* + * Each test is run in a private work dir. Those work dirs + * do have consistent and predictable names, in case a group + * of tests need to collaborate. However, there is no provision + * for requiring that tests run in a certain order. + */ +static int test_run(int i, const char *tmpdir) +{ + int failures_before = failures; + + if (!quiet_flag) + printf("%d: %s\n", i, tests[i].name); + /* + * Always explicitly chdir() in case the last test moved us to + * a strange place. + */ + if (chdir(tmpdir)) { + fprintf(stderr, + "ERROR: Couldn't chdir to temp dir %s\n", + tmpdir); + exit(1); + } + /* Create a temp directory for this specific test. */ + if (mkdir(tests[i].name, 0755)) { + fprintf(stderr, + "ERROR: Couldn't create temp dir ``%s''\n", + tests[i].name); + exit(1); + } + /* Chdir() to that work directory. */ + if (chdir(tests[i].name)) { + fprintf(stderr, + "ERROR: Couldn't chdir to temp dir ``%s''\n", + tests[i].name); + exit(1); + } + /* Explicitly reset the locale before each test. */ + setlocale(LC_ALL, "C"); + /* Run the actual test. */ + (*tests[i].func)(); + /* Summarize the results of this test. */ + summarize(); + /* If there were no failures, we can remove the work dir. */ + if (failures == failures_before) { + if (!keep_temp_files && chdir(tmpdir) == 0) { + systemf("rm -rf %s", tests[i].name); + } + } + /* Return appropriate status. */ + return (failures == failures_before ? 0 : 1); +} + +static void usage(const char *program) +{ + static const int limit = sizeof(tests) / sizeof(tests[0]); + int i; + + printf("Usage: %s [options] <test> <test> ...\n", program); + printf("Default is to run all tests.\n"); + printf("Otherwise, specify the numbers of the tests you wish to run.\n"); + printf("Options:\n"); + printf(" -d Dump core after any failure, for debugging.\n"); + printf(" -k Keep all temp files.\n"); + printf(" Default: temp files for successful tests deleted.\n"); +#ifdef PROGRAM + printf(" -p <path> Path to executable to be tested.\n"); + printf(" Default: path taken from " ENVBASE " environment variable.\n"); +#endif + printf(" -q Quiet.\n"); + printf(" -r <dir> Path to dir containing reference files.\n"); + printf(" Default: Current directory.\n"); + printf(" -v Verbose.\n"); + printf("Available tests:\n"); + for (i = 0; i < limit; i++) + printf(" %d: %s\n", i, tests[i].name); + exit(1); +} + +#define UUDECODE(c) (((c) - 0x20) & 0x3f) + +void +extract_reference_file(const char *name) +{ + char buff[1024]; + FILE *in, *out; + + sprintf(buff, "%s/%s.uu", refdir, name); + in = fopen(buff, "r"); + failure("Couldn't open reference file %s", buff); + assert(in != NULL); + if (in == NULL) + return; + /* Read up to and including the 'begin' line. */ + for (;;) { + if (fgets(buff, sizeof(buff), in) == NULL) { + /* TODO: This is a failure. */ + return; + } + if (memcmp(buff, "begin ", 6) == 0) + break; + } + /* Now, decode the rest and write it. */ + /* Not a lot of error checking here; the input better be right. */ + out = fopen(name, "w"); + while (fgets(buff, sizeof(buff), in) != NULL) { + char *p = buff; + int bytes; + + if (memcmp(buff, "end", 3) == 0) + break; + + bytes = UUDECODE(*p++); + while (bytes > 0) { + int n = 0; + /* Write out 1-3 bytes from that. */ + if (bytes > 0) { + n = UUDECODE(*p++) << 18; + n |= UUDECODE(*p++) << 12; + fputc(n >> 16, out); + --bytes; + } + if (bytes > 0) { + n |= UUDECODE(*p++) << 6; + fputc((n >> 8) & 0xFF, out); + --bytes; + } + if (bytes > 0) { + n |= UUDECODE(*p++); + fputc(n & 0xFF, out); + --bytes; + } + } + } + fclose(out); + fclose(in); +} + + +int main(int argc, char **argv) +{ + static const int limit = sizeof(tests) / sizeof(tests[0]); + int i, tests_run = 0, tests_failed = 0, opt; + time_t now; + char *refdir_alloc = NULL; + char *progname, *p; + char tmpdir[256]; + char tmpdir_timestamp[256]; + + /* + * Name of this program, used to build root of our temp directory + * tree. + */ + progname = p = argv[0]; + while (*p != '\0') { + if (*p == '/') + progname = p + 1; + ++p; + } + +#ifdef PROGRAM + /* Get the target program from environment, if available. */ + testprog = getenv(ENVBASE); +#endif + + /* Allow -d to be controlled through the environment. */ + if (getenv(ENVBASE "_DEBUG") != NULL) + dump_on_failure = 1; + + /* Get the directory holding test files from environment. */ + refdir = getenv(ENVBASE "_TEST_FILES"); + + /* + * Parse options. + */ + while ((opt = getopt(argc, argv, "dkp:qr:v")) != -1) { + switch (opt) { + case 'd': + dump_on_failure = 1; + break; + case 'k': + keep_temp_files = 1; + break; + case 'p': +#ifdef PROGRAM + testprog = optarg; +#else + usage(progname); +#endif + break; + case 'q': + quiet_flag++; + break; + case 'r': + refdir = optarg; + break; + case 'v': + verbose = 1; + break; + case '?': + default: + usage(progname); + } + } + argc -= optind; + argv += optind; + + /* + * Sanity-check that our options make sense. + */ +#ifdef PROGRAM + if (testprog == NULL) + usage(progname); +#endif + + /* + * Create a temp directory for the following tests. + * Include the time the tests started as part of the name, + * to make it easier to track the results of multiple tests. + */ + now = time(NULL); + for (i = 0; i < 1000; i++) { + strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), + "%Y-%m-%dT%H.%M.%S", + localtime(&now)); + sprintf(tmpdir, "/tmp/%s.%s-%03d", progname, tmpdir_timestamp, i); + if (mkdir(tmpdir,0755) == 0) + break; + if (errno == EEXIST) + continue; + fprintf(stderr, "ERROR: Unable to create temp directory %s\n", + tmpdir); + exit(1); + } + + /* + * If the user didn't specify a directory for locating + * reference files, use the current directory for that. + */ + if (refdir == NULL) { + systemf("/bin/pwd > %s/refdir", tmpdir); + refdir = refdir_alloc = slurpfile(NULL, "%s/refdir", tmpdir); + p = refdir + strlen(refdir); + while (p[-1] == '\n') { + --p; + *p = '\0'; + } + systemf("rm %s/refdir", tmpdir); + } + + /* + * Banner with basic information. + */ + if (!quiet_flag) { + printf("Running tests in: %s\n", tmpdir); + printf("Reference files will be read from: %s\n", refdir); +#ifdef PROGRAM + printf("Running tests on: %s\n", testprog); +#endif + printf("Exercising: "); + fflush(stdout); + printf("%s\n", EXTRA_VERSION); + } + + /* + * Run some or all of the individual tests. + */ + if (argc == 0) { + /* Default: Run all tests. */ + for (i = 0; i < limit; i++) { + if (test_run(i, tmpdir)) + tests_failed++; + tests_run++; + } + } else { + while (*(argv) != NULL) { + i = atoi(*argv); + if (**argv < '0' || **argv > '9' || i < 0 || i >= limit) { + printf("*** INVALID Test %s\n", *argv); + usage(progname); + } else { + if (test_run(i, tmpdir)) + tests_failed++; + tests_run++; + } + argv++; + } + } + + /* + * Report summary statistics. + */ + if (!quiet_flag) { + printf("\n"); + printf("%d of %d tests reported failures\n", + tests_failed, tests_run); + printf(" Total of %d assertions checked.\n", assertions); + printf(" Total of %d assertions failed.\n", failures); + printf(" Total of %d assertions skipped.\n", skips); + } + + free(refdir_alloc); + + /* If the final tmpdir is empty, we can remove it. */ + /* This should be the usual case when all tests succeed. */ + rmdir(tmpdir); + + return (tests_failed); +} diff --git a/usr.bin/cpio/test/test.h b/usr.bin/cpio/test/test.h new file mode 100644 index 0000000..06e6d90 --- /dev/null +++ b/usr.bin/cpio/test/test.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2003-2006 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. + * + * $FreeBSD$ + */ + +/* Every test program should #include "test.h" as the first thing. */ + +/* + * The goal of this file (and the matching test.c) is to + * simplify the very repetitive test-*.c test programs. + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#ifndef _WIN32 +#include <unistd.h> +#endif +#include <wchar.h> + +#ifdef USE_DMALLOC +#include <dmalloc.h> +#endif + +#if defined(HAVE_CONFIG_H) +/* Most POSIX platforms use the 'configure' script to build config.h */ +#include "../../config.h" +#elif defined(__FreeBSD__) +/* Building as part of FreeBSD system requires a pre-built config.h. */ +#include "../config_freebsd.h" +#elif defined(_WIN32) +/* Win32 can't run the 'configure' script. */ +#include "../config_windows.h" +#else +/* Warn if the library hasn't been (automatically or manually) configured. */ +#error Oops: No config.h and no pre-built configuration in test.h. +#endif + +/* No non-FreeBSD platform will have __FBSDID, so just define it here. */ +#ifdef __FreeBSD__ +#include <sys/cdefs.h> /* For __FBSDID */ +#else +#define __FBSDID(a) /* null */ +#endif + +/* + * Redefine DEFINE_TEST for use in defining the test functions. + */ +#undef DEFINE_TEST +#define DEFINE_TEST(name) void name(void); void name(void) + +/* An implementation of the standard assert() macro */ +#define assert(e) test_assert(__FILE__, __LINE__, (e), #e, NULL) + +/* Assert two integers are the same. Reports value of each one if not. */ +#define assertEqualInt(v1,v2) \ + test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) + +/* Assert two strings are the same. Reports value of each one if not. */ +#define assertEqualString(v1,v2) \ + test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) +/* As above, but v1 and v2 are wchar_t * */ +#define assertEqualWString(v1,v2) \ + test_assert_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) +/* As above, but raw blocks of bytes. */ +#define assertEqualMem(v1, v2, l) \ + test_assert_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) +/* Assert two files are the same; allow printf-style expansion of second name. + * See below for comments about variable arguments here... + */ +#define assertEqualFile \ + test_setup(__FILE__, __LINE__);test_assert_equal_file +/* Assert that a file is empty; supports printf-style arguments. */ +#define assertEmptyFile \ + test_setup(__FILE__, __LINE__);test_assert_empty_file +/* Assert that file contents match a string; supports printf-style arguments. */ +#define assertFileContents \ + test_setup(__FILE__, __LINE__);test_assert_file_contents + +/* + * This would be simple with C99 variadic macros, but I don't want to + * require that. Instead, I insert a function call before each + * skipping() call to pass the file and line information down. Crude, + * but effective. + */ +#define skipping \ + test_setup(__FILE__, __LINE__);test_skipping + +/* Function declarations. These are defined in test_utility.c. */ +void failure(const char *fmt, ...); +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_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 *); +int test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); +int test_assert_equal_mem(const char *, int, const char *, const char *, const char *, const char *, size_t, const char *, void *); +int test_assert_file_contents(const void *, int, const char *, ...); + +/* Like sprintf, then system() */ +int systemf(const char * fmt, ...); + +/* 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, ...); + +/* Extracts named reference file to the current directory. */ +void extract_reference_file(const char *); + +/* + * Special interfaces for program test harness. + */ + +/* Pathname of exe to be tested. */ +char *testprog; + diff --git a/usr.bin/cpio/test/test_0.c b/usr.bin/cpio/test/test_0.c new file mode 100644 index 0000000..7a72af1 --- /dev/null +++ b/usr.bin/cpio/test/test_0.c @@ -0,0 +1,62 @@ +/*- + * 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$"); + +/* + * This first test does basic sanity checks on the environment. For + * most of these, we just exit on failure. + */ + +DEFINE_TEST(test_0) +{ + struct stat st; + + failure("File %s does not exist?!", testprog); + if (!assertEqualInt(0, stat(testprog, &st))) + exit(1); + + failure("%s is not executable?!", testprog); + if (!assert((st.st_mode & 0111) != 0)) + exit(1); + + /* + * Try to succesfully run the program; this requires that + * we know some option that will succeed. + */ + if (0 == systemf("%s --version >/dev/null", testprog)) { + /* This worked. */ + } else if (0 == systemf("%s -W version >/dev/null", testprog)) { + /* This worked. */ + } else { + failure("Unable to successfully run any of the following:\n" + " * %s --version\n" + " * %s -W version\n", + testprog, testprog); + assert(0); + } + + /* TODO: Ensure that our reference files are available. */ +} diff --git a/usr.bin/cpio/test/test_basic.c b/usr.bin/cpio/test/test_basic.c new file mode 100644 index 0000000..7f1fe6d --- /dev/null +++ b/usr.bin/cpio/test/test_basic.c @@ -0,0 +1,204 @@ +/*- + * 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$"); + +static void +verify_files(const char *target) +{ + struct stat st, st2; + char buff[128]; + int r; + + /* + * Verify unpacked files. + */ + + /* Regular file with 2 links. */ + r = lstat("file", &st); + failure("Failed to stat file %s/file, errno=%d", target, errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); + assertEqualInt(0644, st.st_mode & 0777); + assertEqualInt(10, st.st_size); + failure("file %s/file should have 2 links", target); + assertEqualInt(2, st.st_nlink); + } + + /* Another name for the same file. */ + r = lstat("linkfile", &st2); + failure("Failed to stat file %s/linkfile, errno=%d", target, errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st2.st_mode)); + assertEqualInt(0644, st2.st_mode & 0777); + assertEqualInt(10, st2.st_size); + failure("file %s/linkfile should have 2 links", target); + assertEqualInt(2, st2.st_nlink); + /* Verify that the two are really hardlinked. */ + assertEqualInt(st.st_dev, st2.st_dev); + failure("%s/linkfile and %s/file should be hardlinked", + target, target); + assertEqualInt(st.st_ino, st2.st_ino); + } + + /* Symlink */ + r = lstat("symlink", &st); + failure("Failed to stat file %s/symlink, errno=%d", target, errno); + assertEqualInt(r, 0); + if (r == 0) { + failure("symlink should be a symlink; actual mode is %o", + st.st_mode); + assert(S_ISLNK(st.st_mode)); + if (S_ISLNK(st.st_mode)) { + r = readlink("symlink", buff, sizeof(buff)); + assertEqualInt(r, 4); + buff[r] = '\0'; + assertEqualString(buff, "file"); + } + } + + /* dir */ + r = lstat("dir", &st); + if (r == 0) { + assertEqualInt(r, 0); + assert(S_ISDIR(st.st_mode)); + assertEqualInt(0775, st.st_mode & 0777); + } +} + +static void +basic_cpio(const char *target, + const char *pack_options, + const char *unpack_options, + const char *se) +{ + int r; + + if (!assertEqualInt(0, mkdir(target, 0775))) + return; + + /* Use the cpio program to create an archive. */ + r = systemf("%s -o %s < filelist >%s/archive 2>%s/pack.err", + testprog, pack_options, target, target); + failure("Error invoking %s -o %s", testprog, pack_options); + assertEqualInt(r, 0); + + chdir(target); + + /* Verify stderr. */ + failure("Expected: %s, options=%s", se, pack_options); + assertFileContents(se, strlen(se), "pack.err"); + + /* + * Use cpio to unpack the archive into another directory. + */ + r = systemf("%s -i %s< archive >unpack.out 2>unpack.err", + testprog, unpack_options); + failure("Error invoking %s -i %s", testprog, unpack_options); + assertEqualInt(r, 0); + + /* Verify stderr. */ + failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target); + assertFileContents(se, strlen(se), "unpack.err"); + + verify_files(target); + + chdir(".."); +} + +static void +passthrough(const char *target) +{ + int r; + + if (!assertEqualInt(0, mkdir(target, 0775))) + return; + + /* + * Use cpio passthrough mode to copy files to another directory. + */ + r = systemf("%s -p -W quiet %s <filelist >%s/stdout 2>%s/stderr", + testprog, target, target, target); + failure("Error invoking %s -p", testprog); + assertEqualInt(r, 0); + + chdir(target); + + /* Verify stderr. */ + failure("Error invoking %s -p in dir %s", + testprog, target); + assertEmptyFile("stderr"); + + verify_files(target); + chdir(".."); +} + +DEFINE_TEST(test_basic) +{ + int fd; + int filelist; + int oldumask; + + oldumask = umask(0); + + /* + * Create an assortment of files on disk. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* File with 10 bytes content. */ + fd = open("file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "file\n", 5); + + /* hardlink to above file. */ + assertEqualInt(0, link("file", "linkfile")); + write(filelist, "linkfile\n", 9); + + /* Symlink to above file. */ + assertEqualInt(0, symlink("file", "symlink")); + write(filelist, "symlink\n", 8); + + /* Directory. */ + assertEqualInt(0, mkdir("dir", 0775)); + write(filelist, "dir\n", 4); + /* All done. */ + close(filelist); + + /* Archive/dearchive with a variety of options. */ + basic_cpio("copy", "", "", "1 block\n"); + basic_cpio("copy_odc", "--format=odc", "", "1 block\n"); + basic_cpio("copy_newc", "-H newc", "", "2 blocks\n"); + basic_cpio("copy_cpio", "-H odc", "", "1 block\n"); + basic_cpio("copy_ustar", "-H ustar", "", "7 blocks\n"); + /* Copy in one step using -p */ + passthrough("passthrough"); + + umask(oldumask); +} diff --git a/usr.bin/cpio/test/test_format_newc.c b/usr.bin/cpio/test/test_format_newc.c new file mode 100644 index 0000000..0714bd4 --- /dev/null +++ b/usr.bin/cpio/test/test_format_newc.c @@ -0,0 +1,245 @@ +/*- + * 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$"); + +static int +is_hex(const char *p, size_t l) +{ + while (l > 0) { + if ((*p >= '0' && *p <= '9') + || (*p >= 'a' && *p <= 'f') + || (*p >= 'A' && *p <= 'F')) + { + --l; + ++p; + } else + return (0); + + } + return (1); +} + +static int +from_hex(const char *p, size_t l) +{ + int r = 0; + + while (l > 0) { + r *= 16; + if (*p >= 'a' && *p <= 'f') + r += *p + 10 - 'a'; + else if (*p >= 'A' && *p <= 'F') + r += *p + 10 - 'A'; + else + r += *p - '0'; + --l; + ++p; + } + return (r); +} + +DEFINE_TEST(test_format_newc) +{ + int fd, list; + int r; + int devmajor, devminor, ino, gid; + time_t t, t2, now; + char *p, *e; + size_t s; + mode_t oldmask; + + oldmask = umask(0); + + /* + * Create an assortment of files. + * TODO: Extend this to cover more filetypes. + */ + list = open("list", O_CREAT | O_WRONLY, 0644); + + /* "file1" */ + fd = open("file1", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + assertEqualInt(6, write(list, "file1\n", 6)); + + /* "hardlink" */ + assertEqualInt(0, link("file1", "hardlink")); + assertEqualInt(9, write(list, "hardlink\n", 9)); + + /* Another hardlink, but this one won't be archived. */ + assertEqualInt(0, link("file1", "hardlink2")); + + /* "symlink" */ + assertEqualInt(0, symlink("file1", "symlink")); + assertEqualInt(8, write(list, "symlink\n", 8)); + + /* "dir" */ + assertEqualInt(0, mkdir("dir", 0775)); + assertEqualInt(4, write(list, "dir\n", 4)); + + /* Record some facts about what we just created: */ + now = time(NULL); /* They were all created w/in last two seconds. */ + + /* Use the cpio program to create an archive. */ + close(list); + r = systemf("%s -o --format=newc <list >newc.out 2>newc.err", + testprog); + if (!assertEqualInt(r, 0)) + return; + + /* Verify that nothing went to stderr. */ + assertFileContents("2 blocks\n", 9, "newc.err"); + + /* Verify that stdout is a well-formed cpio file in "newc" format. */ + p = slurpfile(&s, "newc.out"); + assertEqualInt(s, 1024); + e = p; + + /* + * Some of these assertions could be stronger, but it's + * a little tricky because they depend on the local environment. + */ + + /* First entry is "file1" */ + assert(is_hex(e, 110)); /* Entire header is octal digits. */ + assertEqualMem(e + 0, "070701", 6); /* Magic */ + ino = from_hex(e + 6, 8); /* ino */ + assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */ + assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ + gid = from_hex(e + 30, 8); /* gid */ + assertEqualMem(e + 38, "00000003", 8); /* nlink */ + t = from_hex(e + 46, 8); /* mtime */ + failure("t=0x%08x now=0x%08x=%d", t, now, now); + assert(t <= now); /* File wasn't created in future. */ + failure("t=0x%08x now - 2=0x%08x = %d", t, now - 2, now - 2); + assert(t >= now - 2); /* File was created w/in last 2 secs. */ + failure("newc format stores body only with last appearance of a link\n" + " first appearance should be empty, so this file size\n" + " field should be zero"); + assertEqualInt(0, from_hex(e + 54, 8)); /* File size */ + 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 */ + 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)); + /* "symlink" pointing to "file1" */ + assert(is_hex(e, 110)); + assertEqualMem(e + 0, "070701", 6); /* Magic */ + assert(is_hex(e + 6, 8)); /* ino */ + assertEqualInt(0xa1ff, from_hex(e + 14, 8)); /* Mode */ + assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ + assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */ + assertEqualMem(e + 38, "00000001", 8); /* nlink */ + t2 = from_hex(e + 46, 8); /* mtime */ + 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 */ + 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 */ + 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)); + + /* "dir" */ + assert(is_hex(e, 110)); + assertEqualMem(e + 0, "070701", 6); /* Magic */ + assert(is_hex(e + 6, 8)); /* ino */ + assertEqualInt(0x41fd, from_hex(e + 14, 8)); /* Mode */ + assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ + assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */ + assertEqualMem(e + 38, "00000002", 8); /* nlink */ + t2 = from_hex(e + 46, 8); /* mtime */ + 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 */ + 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 */ + 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. */ + + /* Hardlink identical to "file1" */ + /* Since we only wrote two of the three links to this + * file, this link should get deferred by the hardlink logic. */ + assert(is_hex(e, 110)); + assertEqualMem(e + 0, "070701", 6); /* Magic */ + failure("If these aren't the same, then the hardlink detection failed to match them."); + assertEqualInt(ino, from_hex(e + 6, 8)); /* ino */ + assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */ + assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ + assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */ + assertEqualMem(e + 38, "00000003", 8); /* nlink */ + t2 = from_hex(e + 46, 8); /* mtime */ + 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 */ + 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 */ + 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)); + + /* Last entry is end-of-archive marker. */ + assert(is_hex(e, 110)); + assertEqualMem(e + 0, "070701", 6); /* Magic */ + assertEqualMem(e + 8, "00000000", 8); /* ino */ + assertEqualMem(e + 14, "00000000", 8); /* mode */ + assertEqualMem(e + 22, "00000000", 8); /* uid */ + assertEqualMem(e + 30, "00000000", 8); /* gid */ + assertEqualMem(e + 38, "00000001", 8); /* nlink */ + assertEqualMem(e + 46, "00000000", 8); /* mtime */ + assertEqualMem(e + 54, "00000000", 8); /* size */ + assertEqualMem(e + 62, "00000000", 8); /* devmajor */ + assertEqualMem(e + 70, "00000000", 8); /* devminor */ + assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */ + assertEqualMem(e + 86, "00000000", 8); /* rdevminor */ + assertEqualInt(11, from_hex(e + 94, 8)); /* name size */ + assertEqualMem(e + 102, "00000000", 8); /* check field */ + assertEqualMem(e + 110, "TRAILER!!!\0\0", 12); /* Name */ + + free(p); + + umask(oldmask); +} diff --git a/usr.bin/cpio/test/test_gcpio_compat.c b/usr.bin/cpio/test/test_gcpio_compat.c new file mode 100644 index 0000000..4c69abb --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat.c @@ -0,0 +1,127 @@ +/*- + * 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$"); + + +static void +unpack_test(const char *from, const char *options, const char *se) +{ + struct stat st, st2; + char buff[128]; + int r; + + /* Create a work dir named after the file we're unpacking. */ + assertEqualInt(0, mkdir(from, 0775)); + chdir(from); + + /* + * Use cpio to unpack the sample archive + */ + extract_reference_file(from); + r = systemf("%s -i %s < %s >unpack.out 2>unpack.err", + testprog, options, from); + failure("Error invoking %s -i %s < %s", + testprog, options, from); + assertEqualInt(r, 0); + + /* Verify that nothing went to stderr. */ + assertFileContents(se, strlen(se), "unpack.err"); + + /* + * Verify unpacked files. + */ + + /* Regular file with 2 links. */ + r = lstat("file", &st); + failure("Failed to stat file %s/file, errno=%d", from, errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); + assertEqualInt(0644, st.st_mode & 0777); + failure("file %s/file", from); + assertEqualInt(10, st.st_size); + failure("file %s/file", from); + assertEqualInt(2, st.st_nlink); + } + + /* Another name for the same file. */ + r = lstat("linkfile", &st2); + failure("Failed to stat file %s/linkfile, errno=%d", from, errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st2.st_mode)); + assertEqualInt(0644, st2.st_mode & 0777); + failure("file %s/file", from); + assertEqualInt(10, st2.st_size); + failure("file %s/file", from); + assertEqualInt(2, st2.st_nlink); + failure("file and linkfile should be hardlinked"); + assertEqualInt(st.st_dev, st2.st_dev); + failure("file %s/file", from); + assertEqualInt(st.st_ino, st2.st_ino); + } + + /* Symlink */ + r = lstat("symlink", &st); + failure("Failed to stat file %s/symlink, errno=%d", from, errno); + assertEqualInt(r, 0); + if (r == 0) { + failure("symlink should be a symlink; actual mode is %o", + st.st_mode); + assert(S_ISLNK(st.st_mode)); + if (S_ISLNK(st.st_mode)) { + r = readlink("symlink", buff, sizeof(buff)); + assertEqualInt(r, 4); + buff[r] = '\0'; + assertEqualString(buff, "file"); + } + } + + /* dir */ + r = lstat("dir", &st); + if (r == 0) { + assertEqualInt(r, 0); + assert(S_ISDIR(st.st_mode)); + assertEqualInt(0775, st.st_mode & 0777); + } + + chdir(".."); +} + +DEFINE_TEST(test_gcpio_compat) +{ + int oldumask; + + oldumask = umask(0); + + /* Dearchive sample files with a variety of options. */ + 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"); + unpack_test("test_gcpio_compat_ref.ustar", "", "7 blocks\n"); + + umask(oldumask); +} diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref.bin.uu b/usr.bin/cpio/test/test_gcpio_compat_ref.bin.uu new file mode 100644 index 0000000..745d8ab --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref.bin.uu @@ -0,0 +1,16 @@ +$FreeBSD$ +begin 644 test_gcpio_compat_ref.bin +MQW%9`*IWI('H`^@#`@````U'=YD%````"@!F:6QE```Q,C,T-38W.#D*QW%9 +M`*IWI('H`^@#`@````U'=YD)````"@!L:6YK9FEL90``,3(S-#4V-S@Y"L=Q +M60"K=^VAZ`/H`P$````-1X29"`````0`<WEM;&EN:P!F:6QEQW%9`*YW_4'H +M`^@#`@````U'A9D$``````!D:7(`QW$``````````````0`````````+```` +M``!44D%)3$52(2$A```````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +1```````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref.crc.uu b/usr.bin/cpio/test/test_gcpio_compat_ref.crc.uu new file mode 100644 index 0000000..df8dde0 --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref.crc.uu @@ -0,0 +1,27 @@ +$FreeBSD$ +begin 644 test_gcpio_compat_ref.crc +M,#<P-S`R,#`S,S<W86$P,#`P.#%A-#`P,#`P,V4X,#`P,#`S93@P,#`P,#`P +M,C0W,&0Y.3<W,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y,#`P,#`P,#`P,#`P +M,#`P,#`P,#`P,#`U,#`P,#`P,#!F:6QE```P-S`W,#(P,#,S-S=A83`P,#`X +M,6$T,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`R-#<P9#DY-S<P,#`P,#`P83`P +M,#`P,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#DP,#`P,#%E +M-VQI;FMF:6QE```Q,C,T-38W.#D*```P-S`W,#(P,#,S-S=A8C`P,#!A,65D +M,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`Q-#<P9#DY.#0P,#`P,#`P-#`P,#`P +M,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#@P,#`P,#`P,'-Y +M;6QI;FL```!F:6QE,#<P-S`R,#`S,S<W864P,#`P-#%F9#`P,#`P,V4X,#`P +M,#`S93@P,#`P,#`P,C0W,&0Y.3@U,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`T,#`P,#`P,#!D:7(````P-S`W,#(P +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P +M,#`P,&(P,#`P,#`P,%1204E,15(A(2$````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +B```````````````````````````````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref.newc.uu b/usr.bin/cpio/test/test_gcpio_compat_ref.newc.uu new file mode 100644 index 0000000..1e29ba9 --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref.newc.uu @@ -0,0 +1,27 @@ +$FreeBSD$ +begin 644 test_gcpio_compat_ref.newc +M,#<P-S`Q,#`S,S<W86$P,#`P.#%A-#`P,#`P,V4X,#`P,#`S93@P,#`P,#`P +M,C0W,&0Y.3<W,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y,#`P,#`P,#`P,#`P +M,#`P,#`P,#`P,#`U,#`P,#`P,#!F:6QE```P-S`W,#$P,#,S-S=A83`P,#`X +M,6$T,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`R-#<P9#DY-S<P,#`P,#`P83`P +M,#`P,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#DP,#`P,#`P +M,&QI;FMF:6QE```Q,C,T-38W.#D*```P-S`W,#$P,#,S-S=A8C`P,#!A,65D +M,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`Q-#<P9#DY.#0P,#`P,#`P-#`P,#`P +M,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#@P,#`P,#`P,'-Y +M;6QI;FL```!F:6QE,#<P-S`Q,#`S,S<W864P,#`P-#%F9#`P,#`P,V4X,#`P +M,#`S93@P,#`P,#`P,C0W,&0Y.3@U,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`T,#`P,#`P,#!D:7(````P-S`W,#$P +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P +M,#`P,&(P,#`P,#`P,%1204E,15(A(2$````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +B```````````````````````````````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref.ustar.uu b/usr.bin/cpio/test/test_gcpio_compat_ref.ustar.uu new file mode 100644 index 0000000..77989f4 --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref.ustar.uu @@ -0,0 +1,84 @@ +$FreeBSD$ +begin 644 test_gcpio_compat_ref.ustar +M9FEL90`````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````#`P,#`V-#0`,#`P,3<U,``P,#`Q-S4P`#`P,#`P,#`P,#$R +M`#$P-S`S,S$T-38W`#`P,3$S-C,`,``````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````!U<W1A<@`P,'1I;0`` +M````````````````````````````````````=&EM```````````````````` +M```````````````````P,#`P,#`P`#`P,#`P,#`````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````Q,C,T-38W.#D*```````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````````````````````````````````&QI;FMF:6QE```` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````P +M,#`P-C0T`#`P,#$W-3``,#`P,3<U,``P,#`P,#`P,#`P,``Q,#<P,S,Q-#4V +M-P`P,#$S,#<W`#%F:6QE```````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M````````````````````````````=7-T87(`,#!T:6T````````````````` +M`````````````````````'1I;0`````````````````````````````````` +M````,#`P,#`P,``P,#`P,#`P```````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M````````<WEM;&EN:P`````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````````#`P,#`W-34`,#`P,3<U,``P,#`Q-S4P`#`P,#`P +M,#`P,#`P`#$P-S`S,S$T-C`T`#`P,3(W-C0`,F9I;&4````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````````````!U<W1A<@`P +M,'1I;0``````````````````````````````````````=&EM```````````` +M```````````````````````````P,#`P,#`P`#`P,#`P,#`````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````!D:7(O```````````````````````` +M```````````````````````````````````````````````````````````` +M````````````````````````````````````````````,#`P,#<W-0`P,#`Q +M-S4P`#`P,#$W-3``,#`P,#`P,#`P,#``,3`W,#,S,30V,#4`,#`Q,3,P,0`U +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````'5S=&%R`#`P=&EM```````````````````````````````` +M``````!T:6T``````````````````````````````````````#`P,#`P,#`` +M,#`P,#`P,``````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +=```````````````````````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_option_B.c b/usr.bin/cpio/test/test_option_B.c new file mode 100644 index 0000000..8083882 --- /dev/null +++ b/usr.bin/cpio/test/test_option_B.c @@ -0,0 +1,54 @@ +/*- + * 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$"); + + +DEFINE_TEST(test_option_B) +{ + struct stat st; + int r, fd; + + /* + * Create a file on disk. + */ + fd = open("file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + close(fd); + + /* Create an archive without -B; this should be 512 bytes. */ + r = systemf("echo file | %s -o > small.cpio 2>small.err", testprog); + assertEqualInt(r, 0); + assertFileContents("1 block\n", 8, "small.err"); + assertEqualInt(0, stat("small.cpio", &st)); + assertEqualInt(512, st.st_size); + + /* Create an archive with -B; this should be 5120 bytes. */ + r = systemf("echo file | %s -oB > large.cpio 2>large.err", testprog); + assertEqualInt(r, 0); + assertFileContents("1 block\n", 8, "large.err"); + assertEqualInt(0, stat("large.cpio", &st)); + assertEqualInt(5120, st.st_size); +} diff --git a/usr.bin/cpio/test/test_option_L.c b/usr.bin/cpio/test/test_option_L.c new file mode 100644 index 0000000..2d69ab6 --- /dev/null +++ b/usr.bin/cpio/test/test_option_L.c @@ -0,0 +1,84 @@ +/*- + * 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$"); + +DEFINE_TEST(test_option_L) +{ + struct stat st; + int fd, filelist; + int r; + + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* Create a file and a symlink to the file. */ + fd = open("file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "file\n", 5); + + /* Symlink to above file. */ + assertEqualInt(0, symlink("file", "symlink")); + write(filelist, "symlink\n", 8); + + close(filelist); + + r = systemf("cat filelist | %s -pd copy >copy.out 2>copy.err", testprog); + assertEqualInt(r, 0); + assertEqualInt(0, lstat("copy/symlink", &st)); + failure("Regular -p without -L should preserve symlinks."); + assert(S_ISLNK(st.st_mode)); + + r = systemf("cat filelist | %s -pd -L copy-L >copy-L.out 2>copy-L.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("copy-L.out"); + assertEmptyFile("copy-L.err"); + assertEqualInt(0, lstat("copy-L/symlink", &st)); + failure("-pdL should dereference symlinks and turn them into files."); + assert(!S_ISLNK(st.st_mode)); + + r = systemf("cat filelist | %s -o >archive.out 2>archive.err", testprog); + failure("Error invoking %s -o ", testprog); + assertEqualInt(r, 0); + + assertEqualInt(0, mkdir("unpack", 0755)); + r = systemf("cat archive.out | (cd unpack ; %s -i >unpack.out 2>unpack.err)", testprog); + failure("Error invoking %s -i", testprog); + assertEqualInt(r, 0); + assertEqualInt(0, lstat("unpack/symlink", &st)); + assert(S_ISLNK(st.st_mode)); + + r = systemf("cat filelist | %s -oL >archive-L.out 2>archive-L.err", testprog); + failure("Error invoking %s -oL", testprog); + assertEqualInt(r, 0); + + assertEqualInt(0, mkdir("unpack-L", 0755)); + r = systemf("cat archive-L.out | (cd unpack-L ; %s -i >unpack-L.out 2>unpack-L.err)", testprog); + failure("Error invoking %s -i < archive-L.out", testprog); + assertEqualInt(r, 0); + assertEqualInt(0, lstat("unpack-L/symlink", &st)); + assert(!S_ISLNK(st.st_mode)); +} diff --git a/usr.bin/cpio/test/test_option_a.c b/usr.bin/cpio/test/test_option_a.c new file mode 100644 index 0000000..c063280 --- /dev/null +++ b/usr.bin/cpio/test/test_option_a.c @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2003-2008 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" +#include <utime.h> +__FBSDID("$FreeBSD$"); + +static struct { + const char *name; + time_t atime_sec; +} files[] = { + { "f0", 0 }, + { "f1", 0 }, + { "f2", 0 }, + { "f3", 0 }, + { "f4", 0 }, + { "f5", 0 } +}; + +/* + * Create a bunch of test files and record their atimes. + * For the atime preserve/change tests, the files must have + * atimes in the past. We can accomplish this by explicitly invoking + * utime() on platforms that support it or by simply sleeping + * for a second after creating the files. (Creating all of the files + * at once means we only need to sleep once.) + */ +static void +test_create(void) +{ + struct stat st; + struct utimbuf times; + static const int numfiles = sizeof(files) / sizeof(files[0]); + int i; + int fd; + + for (i = 0; i < numfiles; ++i) { + fd = open(files[i].name, O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + /* + * Note: Have to write at least one byte to the file. + * cpio doesn't bother reading the file if it's zero length, + * so the atime never gets changed in that case, which + * makes the tests below rather pointless. + */ + assertEqualInt(1, write(fd, "a", 1)); + close(fd); + + /* If utime() isn't supported on your platform, just + * #ifdef this section out. Most of the test below is + * still valid. */ + memset(×, 0, sizeof(times)); + times.actime = 1; + times.modtime = 3; + assertEqualInt(0, utime(files[i].name, ×)); + + /* Record whatever atime the file ended up with. */ + /* If utime() is available, this should be 1, but there's + * no harm in being careful. */ + assertEqualInt(0, stat(files[i].name, &st)); + files[i].atime_sec = st.st_atime; + } + + /* Wait until the atime on the last file is actually in the past. */ + /* If utime() is supported above, there's no sleep here which + * makes the test faster. */ + while (files[numfiles - 1].atime_sec >= time(NULL)) + sleep(1); +} + +DEFINE_TEST(test_option_a) +{ + struct stat st; + int r; + int f; + char buff[64]; + + /* Create all of the test files. */ + test_create(); + + /* Sanity check; verify that atimes really do get modified. */ + f = open(files[0].name, O_RDONLY); + assertEqualInt(1, read(f,buff, 1)); + assertEqualInt(0, close(f)); + assertEqualInt(0, stat("f0", &st)); + if (st.st_atime == files[0].atime_sec) { + skipping("Cannot verify -a option\n" + " Your system appears to not support atime."); + } + else + { + /* + * If this disk is mounted noatime, then we can't + * verify correct operation without -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); + assertEmptyFile("copy-no-a.err"); + assertEmptyFile("copy-no-a.out"); + assertEqualInt(0, stat(files[1].name, &st)); + failure("Copying file without -a should have changed atime."); + assert(st.st_atime != files[1].atime_sec); + + /* Archive the file without -a; should change the atime. */ + r = systemf("echo %s | %s -o > archive-no-a.out 2>archive-no-a.err", files[2].name, testprog); + assertEqualInt(r, 0); + assertEmptyFile("copy-no-a.err"); + assertEqualInt(0, stat(files[2].name, &st)); + failure("Archiving file without -a should have changed atime."); + assert(st.st_atime != files[2].atime_sec); + } + + /* + * We can, of course, still verify that the atime is unchanged + * when using the -a option. + */ + + /* Copy the file with -a; should not change the atime. */ + r = systemf("echo %s | %s -pad copy-a > copy-a.out 2>copy-a.err", + files[3].name, testprog); + assertEqualInt(r, 0); + assertEmptyFile("copy-a.err"); + assertEmptyFile("copy-a.out"); + assertEqualInt(0, stat(files[3].name, &st)); + failure("Copying file with -a should not have changed atime."); + assertEqualInt(st.st_atime, files[3].atime_sec); + + /* Archive the file with -a; should not change the atime. */ + r = systemf("echo %s | %s -oa > archive-a.out 2>archive-a.err", + files[4].name, testprog); + assertEqualInt(r, 0); + assertEmptyFile("copy-a.err"); + assertEqualInt(0, stat(files[4].name, &st)); + failure("Archiving file with -a should not have changed atime."); + assertEqualInt(st.st_atime, files[4].atime_sec); +} diff --git a/usr.bin/cpio/test/test_option_c.c b/usr.bin/cpio/test/test_option_c.c new file mode 100644 index 0000000..05b48c2 --- /dev/null +++ b/usr.bin/cpio/test/test_option_c.c @@ -0,0 +1,198 @@ +/*- + * 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$"); + +static int +is_octal(const char *p, size_t l) +{ + while (l > 0) { + if (*p < '0' || *p > '7') + return (0); + --l; + ++p; + } + return (1); +} + +static int +from_octal(const char *p, size_t l) +{ + int r = 0; + + while (l > 0) { + r *= 8; + r += *p - '0'; + --l; + ++p; + } + return (r); +} + +DEFINE_TEST(test_option_c) +{ + int fd, filelist; + int r; + int dev, ino, gid; + time_t t, now; + char *p, *e; + size_t s; + mode_t oldmask; + + oldmask = umask(0); + + /* + * Create an assortment of files. + * TODO: Extend this to cover more filetypes. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* "file" */ + fd = open("file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + assertEqualInt(5, write(filelist, "file\n", 5)); + + /* "symlink" */ + assertEqualInt(0, symlink("file", "symlink")); + assertEqualInt(8, write(filelist, "symlink\n", 8)); + + /* "dir" */ + assertEqualInt(0, mkdir("dir", 0775)); + /* Record some facts about what we just created: */ + now = time(NULL); /* They were all created w/in last two seconds. */ + assertEqualInt(4, write(filelist, "dir\n", 4)); + + /* Use the cpio program to create an archive. */ + close(filelist); + r = systemf("%s -oc <filelist >basic.out 2>basic.err", testprog); + /* Verify that nothing went to stderr. */ + assertFileContents("1 block\n", 8, "basic.err"); + + /* Assert that the program finished. */ + failure("%s -oc crashed", testprog); + if (!assertEqualInt(r, 0)) + return; + + /* Verify that stdout is a well-formed cpio file in "odc" format. */ + p = slurpfile(&s, "basic.out"); + assertEqualInt(s, 512); + e = p; + + /* + * Some of these assertions could be stronger, but it's + * a little tricky because they depend on the local environment. + */ + + /* First entry is "file" */ + assert(is_octal(e, 76)); /* Entire header is octal digits. */ + assertEqualMem(e + 0, "070707", 6); /* Magic */ + assert(is_octal(e + 6, 6)); /* dev */ + dev = from_octal(e + 6, 6); + assert(is_octal(e + 12, 6)); /* ino */ + ino = from_octal(e + 12, 6); + assertEqualMem(e + 18, "100644", 6); /* Mode */ + assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */ + assert(is_octal(e + 30, 6)); /* gid */ + gid = from_octal(e + 30, 6); + assertEqualMem(e + 36, "000001", 6); /* nlink */ + failure("file entries should not have rdev set (dev field was 0%o)", + dev); + assertEqualMem(e + 42, "000000", 6); /* rdev */ + t = from_octal(e + 48, 11); /* mtime */ + assert(t <= now); /* File wasn't created in future. */ + assert(t >= now - 2); /* File was created w/in last 2 secs. */ + assertEqualMem(e + 59, "000005", 6); /* Name size */ + assertEqualMem(e + 65, "00000000012", 11); /* File size */ + assertEqualMem(e + 76, "file\0", 5); /* Name contents */ + assertEqualMem(e + 81, "123456789\0", 10); /* File contents */ + e += 91; + + /* Second entry is "symlink" pointing to "file" */ + assert(is_octal(e, 76)); /* Entire header is octal digits. */ + assertEqualMem(e + 0, "070707", 6); /* Magic */ + assertEqualInt(dev, from_octal(e + 6, 6)); /* dev */ + assert(dev != from_octal(e + 12, 6)); /* ino */ + assertEqualMem(e + 18, "120777", 6); /* Mode */ + assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */ + assertEqualInt(gid, from_octal(e + 30, 6)); /* gid */ + assertEqualMem(e + 36, "000001", 6); /* nlink */ + failure("file entries should have rdev == 0 (dev was 0%o)", + from_octal(e + 6, 6)); + assertEqualMem(e + 42, "000000", 6); /* rdev */ + t = from_octal(e + 48, 11); /* mtime */ + assert(t <= now); /* File wasn't created in future. */ + assert(t >= now - 2); /* File was created w/in last 2 secs. */ + assertEqualMem(e + 59, "000010", 6); /* Name size */ + assertEqualMem(e + 65, "00000000004", 11); /* File size */ + assertEqualMem(e + 76, "symlink\0", 8); /* Name contents */ + assertEqualMem(e + 84, "file", 4); /* Symlink target. */ + e += 88; + + /* Second entry is "dir" */ + assert(is_octal(e, 76)); + assertEqualMem(e + 0, "070707", 6); /* Magic */ + /* Dev should be same as first entry. */ + assert(is_octal(e + 6, 6)); /* dev */ + assertEqualInt(dev, from_octal(e + 6, 6)); + /* Ino must be different from first entry. */ + assert(is_octal(e + 12, 6)); /* ino */ + assert(dev != from_octal(e + 12, 6)); + assertEqualMem(e + 18, "040775", 6); /* Mode */ + assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */ + /* Gid should be same as first entry. */ + assert(is_octal(e + 30, 6)); /* gid */ + assertEqualInt(gid, from_octal(e + 30, 6)); + assertEqualMem(e + 36, "000002", 6); /* Nlink */ + t = from_octal(e + 48, 11); /* mtime */ + assert(t <= now); /* File wasn't created in future. */ + assert(t >= now - 2); /* File was created w/in last 2 secs. */ + assertEqualMem(e + 59, "000004", 6); /* Name size */ + assertEqualMem(e + 65, "00000000000", 11); /* File size */ + assertEqualMem(e + 76, "dir\0", 4); /* name */ + e += 80; + + /* TODO: Verify other types of entries. */ + + /* Last entry is end-of-archive marker. */ + assert(is_octal(e, 76)); + assertEqualMem(e + 0, "070707", 6); /* Magic */ + assertEqualMem(e + 6, "000000", 6); /* dev */ + assertEqualMem(e + 12, "000000", 6); /* ino */ + assertEqualMem(e + 18, "000000", 6); /* Mode */ + assertEqualMem(e + 24, "000000", 6); /* uid */ + assertEqualMem(e + 30, "000000", 6); /* gid */ + assertEqualMem(e + 36, "000001", 6); /* Nlink */ + assertEqualMem(e + 42, "000000", 6); /* rdev */ + assertEqualMem(e + 48, "00000000000", 11); /* mtime */ + assertEqualMem(e + 59, "000013", 6); /* Name size */ + assertEqualMem(e + 65, "00000000000", 11); /* File size */ + assertEqualMem(e + 76, "TRAILER!!!\0", 11); /* Name */ + + free(p); + + umask(oldmask); +} diff --git a/usr.bin/cpio/test/test_option_d.c b/usr.bin/cpio/test/test_option_d.c new file mode 100644 index 0000000..370c82a --- /dev/null +++ b/usr.bin/cpio/test/test_option_d.c @@ -0,0 +1,68 @@ +/*- + * 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$"); + + +DEFINE_TEST(test_option_d) +{ + struct stat st; + int r, fd; + + /* + * Create a file in a directory. + */ + assertEqualInt(0, mkdir("dir", 0755)); + fd = open("dir/file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + close(fd); + + /* Create an archive. */ + r = systemf("echo dir/file | %s -o > archive.cpio 2>archive.err", testprog); + assertEqualInt(r, 0); + assertFileContents("1 block\n", 8, "archive.err"); + assertEqualInt(0, stat("archive.cpio", &st)); + assertEqualInt(512, st.st_size); + + /* Dearchive without -d, this should fail. */ + assertEqualInt(0, mkdir("without-d", 0755)); + assertEqualInt(0, chdir("without-d")); + r = systemf("%s -i < ../archive.cpio >out 2>err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("out"); + /* And the file should not be restored. */ + assert(0 != stat("dir/file", &st)); + + /* Dearchive with -d, this should succeed. */ + assertEqualInt(0, chdir("..")); + assertEqualInt(0, mkdir("with-d", 0755)); + assertEqualInt(0, chdir("with-d")); + r = systemf("%s -id < ../archive.cpio >out 2>err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("out"); + assertFileContents("1 block\n", 8, "err"); + /* And the file should be restored. */ + assertEqualInt(0, stat("dir/file", &st)); +} diff --git a/usr.bin/cpio/test/test_option_ell.c b/usr.bin/cpio/test/test_option_ell.c new file mode 100644 index 0000000..36bb0ac --- /dev/null +++ b/usr.bin/cpio/test/test_option_ell.c @@ -0,0 +1,66 @@ +/*- + * 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$"); + +/* + * This is called "test_option_ell" instead of "test_option_l" to + * avoid any conflicts with "test_option_L" on case-insensitive + * filesystems. + */ + +DEFINE_TEST(test_option_ell) +{ + struct stat st, st2; + int fd; + int r; + + /* Create a file. */ + fd = open("f", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(1, write(fd, "a", 1)); + close(fd); + + /* Stat it. */ + assertEqualInt(0, stat("f", &st)); + + /* Copy the file to the "copy" dir. */ + r = systemf("echo f | %s -pd copy >copy.out 2>copy.err", + testprog); + assertEqualInt(r, 0); + + /* Check that the copy is a true copy and not a link. */ + assertEqualInt(0, stat("copy/f", &st2)); + assert(st2.st_ino != st.st_ino); + + /* Copy the file to the "link" dir with the -l option. */ + r = systemf("echo f | %s -pld link >link.out 2>link.err", + testprog); + assertEqualInt(r, 0); + + /* Check that this is a link and not a copy. */ + assertEqualInt(0, stat("link/f", &st2)); + assert(st2.st_ino == st.st_ino); +} diff --git a/usr.bin/cpio/test/test_option_f.c b/usr.bin/cpio/test/test_option_f.c new file mode 100644 index 0000000..d1af912 --- /dev/null +++ b/usr.bin/cpio/test/test_option_f.c @@ -0,0 +1,66 @@ +/*- + * 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$"); + +/* + * Unpack the archive in a new dir. + */ +static void +unpack(const char *dirname, const char *option) +{ + int r; + + assertEqualInt(0, mkdir(dirname, 0755)); + assertEqualInt(0, chdir(dirname)); + extract_reference_file("test_option_f.cpio"); + r = systemf("%s -i %s < test_option_f.cpio > copy-no-a.out 2>copy-no-a.err", testprog, option); + assertEqualInt(0, r); + assertEqualInt(0, chdir("..")); +} + +DEFINE_TEST(test_option_f) +{ + /* Calibrate: No -f option, so everything should be extracted. */ + unpack("t0", ""); + assertEqualInt(0, access("t0/a123", F_OK)); + assertEqualInt(0, access("t0/a234", F_OK)); + assertEqualInt(0, access("t0/b123", F_OK)); + assertEqualInt(0, access("t0/b234", F_OK)); + + /* Don't extract 'a*' files. */ + unpack("t1", "-f 'a*'"); + assert(0 != access("t1/a123", F_OK)); + assert(0 != access("t1/a234", F_OK)); + assertEqualInt(0, access("t1/b123", F_OK)); + assertEqualInt(0, access("t1/b234", F_OK)); + + /* Don't extract 'b*' files. */ + unpack("t2", "-f 'b*'"); + assertEqualInt(0, access("t2/a123", F_OK)); + assertEqualInt(0, access("t2/a234", F_OK)); + assert(0 != access("t2/b123", F_OK)); + assert(0 != access("t2/b234", F_OK)); +} diff --git a/usr.bin/cpio/test/test_option_f.cpio.uu b/usr.bin/cpio/test/test_option_f.cpio.uu new file mode 100644 index 0000000..42c63c3 --- /dev/null +++ b/usr.bin/cpio/test/test_option_f.cpio.uu @@ -0,0 +1,16 @@ +$FreeBSD$ +begin 644 test_option_f.cpio +M,#<P-S`W,#`P,3,Q-C(Q-38Q,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P +M,#`P,3`W,S4Q,3(U,C8P,#`P,#4P,#`P,#`P,#`P,&$Q,C,`,#<P-S`W,#`P +M,3,Q-C(Q-38S,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P,#`P,3`W,S4Q +M,3(U-#`P,#`P,#4P,#`P,#`P,#`P,&$R,S0`,#<P-S`W,#`P,3,Q-C(Q-38R +M,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P,#`P,3`W,S4Q,3(U,S0P,#`P +M,#4P,#`P,#`P,#`P,&(Q,C,`,#<P-S`W,#`P,3,Q-C(Q-38T,3`P-C0T,#`Q +M-S4P,#`Q-S4P,#`P,#`Q,#`P,#`P,3`W,S4Q,3(U-#,P,#`P,#4P,#`P,#`P +M,#`P,&(R,S0`,#<P-S`W,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P +M,#`P,#`Q,#`P,#`P,#`P,#`P,#`P,#`P,#`P,3,P,#`P,#`P,#`P,%1204E, +M15(A(2$````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +1```````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_option_help.c b/usr.bin/cpio/test/test_option_help.c new file mode 100644 index 0000000..b9433a4 --- /dev/null +++ b/usr.bin/cpio/test/test_option_help.c @@ -0,0 +1,81 @@ +/*- + * 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$"); + +/* + * Test that "--help", "-h", and "-W help" options all work and + * generate reasonable output. + */ + +static int +in_first_line(const char *p, const char *substring) +{ + size_t l = strlen(substring); + + while (*p != '\0' && *p != '\n') { + if (memcmp(p, substring, l) == 0) + return (1); + ++p; + } + return (0); +} + +DEFINE_TEST(test_option_help) +{ + int r; + char *p; + size_t plen; + + /* Exercise --help option. */ + r = systemf("%s --help >help.stdout 2>help.stderr", testprog); + failure("--help should generate nothing to stderr."); + assertEmptyFile("help.stderr"); + /* Help message should start with name of program. */ + p = slurpfile(&plen, "help.stdout"); + failure("Help output should be long enough."); + assert(plen >= 7); + failure("First line of help output should contain string 'bsdcpio'"); + assert(in_first_line(p, "bsdcpio")); + /* + * TODO: Extend this check to further verify that --help output + * looks approximately right. + */ + free(p); + + /* -h option should generate the same output. */ + r = systemf("%s -h >h.stdout 2>h.stderr", testprog); + failure("-h should generate nothing to stderr."); + assertEmptyFile("h.stderr"); + failure("stdout should be same for -h and --help"); + assertEqualFile("h.stdout", "help.stdout"); + + /* -W help should be another synonym. */ + r = systemf("%s -W help >Whelp.stdout 2>Whelp.stderr", testprog); + failure("-W help should generate nothing to stderr."); + assertEmptyFile("Whelp.stderr"); + failure("stdout should be same for -W help and --help"); + assertEqualFile("Whelp.stdout", "help.stdout"); +} diff --git a/usr.bin/cpio/test/test_option_m.c b/usr.bin/cpio/test/test_option_m.c new file mode 100644 index 0000000..d5bbad2 --- /dev/null +++ b/usr.bin/cpio/test/test_option_m.c @@ -0,0 +1,70 @@ +/*- + * 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$"); + + +DEFINE_TEST(test_option_m) +{ + struct stat st; + int r; + time_t now; + + /* + * The reference archive has one file with an mtime in 1970, 1 + * second after the start of the epoch. + */ + + /* Restored without -m, the result should have a current mtime. */ + assertEqualInt(0, mkdir("without-m", 0755)); + assertEqualInt(0, chdir("without-m")); + extract_reference_file("test_option_m.cpio"); + r = systemf("%s -i < test_option_m.cpio >out 2>err", testprog); + now = time(NULL); + assertEqualInt(r, 0); + assertEmptyFile("out"); + assertFileContents("1 block\n", 8, "err"); + assertEqualInt(0, stat("file", &st)); + /* Should have been created within the last few seconds. */ + assert(st.st_mtime <= now); + assert(st.st_mtime > now - 5); + + /* With -m, it should have an mtime in 1970. */ + assertEqualInt(0, chdir("..")); + assertEqualInt(0, mkdir("with-m", 0755)); + assertEqualInt(0, chdir("with-m")); + extract_reference_file("test_option_m.cpio"); + r = systemf("%s -im < test_option_m.cpio >out 2>err", testprog); + now = time(NULL); + assertEqualInt(r, 0); + assertEmptyFile("out"); + assertFileContents("1 block\n", 8, "err"); + assertEqualInt(0, stat("file", &st)); + /* + * mtime in reference archive is '1' == 1 second after + * midnight Jan 1, 1970 UTC. + */ + assertEqualInt(1, st.st_mtime); +} diff --git a/usr.bin/cpio/test/test_option_m.cpio.uu b/usr.bin/cpio/test/test_option_m.cpio.uu new file mode 100644 index 0000000..3d20023 --- /dev/null +++ b/usr.bin/cpio/test/test_option_m.cpio.uu @@ -0,0 +1,16 @@ +$FreeBSD$ +begin 644 test_option_m.cpio +M,#<P-S`W,#`P,3,Q-#4P,#8T,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P +M,#`P,#`P,#`P,#`P,#$P,#`P,#4P,#`P,#`P,#`P,&9I;&4`,#<P-S`W,#`P +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P,#`P,#`P +M,#`P,#`P,#`P,3,P,#`P,#`P,#`P,%1204E,15(A(2$````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +1```````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_option_t.c b/usr.bin/cpio/test/test_option_t.c new file mode 100644 index 0000000..c9cdd0b --- /dev/null +++ b/usr.bin/cpio/test/test_option_t.c @@ -0,0 +1,47 @@ +/*- + * 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$"); + + +DEFINE_TEST(test_option_t) +{ + int r; + + /* List reference archive, make sure the TOC is correct. */ + extract_reference_file("test_option_t.cpio"); + r = systemf("%s -it < test_option_t.cpio >t.out 2>t.err", testprog); + assertEqualInt(r, 0); + assertFileContents("1 block\n", 8, "t.err"); + extract_reference_file("test_option_t.stdout"); + assertEqualFile("t.out", "test_option_t.stdout"); + + /* List reference archive verbosely, make sure the TOC is correct. */ + r = systemf("%s -itv < test_option_t.cpio >tv.out 2>tv.err", testprog); + assertEqualInt(r, 0); + assertFileContents("1 block\n", 8, "tv.err"); + extract_reference_file("test_option_tv.stdout"); + assertEqualFile("tv.out", "test_option_tv.stdout"); +} diff --git a/usr.bin/cpio/test/test_option_t.cpio.uu b/usr.bin/cpio/test/test_option_t.cpio.uu new file mode 100644 index 0000000..055fe74 --- /dev/null +++ b/usr.bin/cpio/test/test_option_t.cpio.uu @@ -0,0 +1,16 @@ +$FreeBSD$ +begin 644 test_option_t.cpio +M,#<P-S`W,#`P,3,Q-#4P,#8T,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P +M,#`P,#`P,#`P,#`P,#$P,#`P,#4P,#`P,#`P,#`P,&9I;&4`,#<P-S`W,#`P +M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P,#`P,#`P +M,#`P,#`P,#`P,3,P,#`P,#`P,#`P,%1204E,15(A(2$````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +1```````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_option_t.stdout.uu b/usr.bin/cpio/test/test_option_t.stdout.uu new file mode 100644 index 0000000..2457706 --- /dev/null +++ b/usr.bin/cpio/test/test_option_t.stdout.uu @@ -0,0 +1,5 @@ +$FreeBSD$ +begin 644 test_option_t.stdout +%9FEL90H` +` +end diff --git a/usr.bin/cpio/test/test_option_tv.stdout.uu b/usr.bin/cpio/test/test_option_tv.stdout.uu new file mode 100644 index 0000000..baead3e --- /dev/null +++ b/usr.bin/cpio/test/test_option_tv.stdout.uu @@ -0,0 +1,5 @@ +$FreeBSD$ +begin 644 test_option_tv.stdout +G+7)W+7(M+7(M+2`@(#$@("`H;G5L;"D@("AN=6QL*2`P(&9I;&4* +` +end diff --git a/usr.bin/cpio/test/test_option_u.c b/usr.bin/cpio/test/test_option_u.c new file mode 100644 index 0000000..7abd7f0 --- /dev/null +++ b/usr.bin/cpio/test/test_option_u.c @@ -0,0 +1,84 @@ +/*- + * 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" +#include <utime.h> +__FBSDID("$FreeBSD$"); + +DEFINE_TEST(test_option_u) +{ + struct utimbuf times; + char *p; + size_t s; + int fd; + int r; + + /* Create a file. */ + fd = open("f", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(1, write(fd, "a", 1)); + close(fd); + + /* Copy the file to the "copy" dir. */ + r = systemf("echo f | %s -pd copy >copy.out 2>copy.err", + testprog); + assertEqualInt(r, 0); + + /* Check that the file contains only a single "a" */ + p = slurpfile(&s, "copy/f"); + assertEqualInt(s, 1); + assertEqualMem(p, "a", 1); + + /* Recreate the file with a single "b" */ + fd = open("f", O_CREAT | O_TRUNC | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(1, write(fd, "b", 1)); + close(fd); + + /* Set the mtime to the distant past. */ + memset(×, 0, sizeof(times)); + times.actime = 1; + times.modtime = 3; + assertEqualInt(0, utime("f", ×)); + + /* Copy the file to the "copy" dir. */ + r = systemf("echo f | %s -pd copy >copy.out 2>copy.err", + testprog); + assertEqualInt(r, 0); + + /* Verify that the file hasn't changed (it wasn't overwritten) */ + p = slurpfile(&s, "copy/f"); + assertEqualInt(s, 1); + assertEqualMem(p, "a", 1); + + /* Copy the file to the "copy" dir with -u (force) */ + r = systemf("echo f | %s -pud copy >copy.out 2>copy.err", + testprog); + assertEqualInt(r, 0); + + /* Verify that the file has changed (it was overwritten) */ + p = slurpfile(&s, "copy/f"); + assertEqualInt(s, 1); + assertEqualMem(p, "b", 1); +} diff --git a/usr.bin/cpio/test/test_option_version.c b/usr.bin/cpio/test/test_option_version.c new file mode 100644 index 0000000..95258eb --- /dev/null +++ b/usr.bin/cpio/test/test_option_version.c @@ -0,0 +1,105 @@ +/*- + * 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$"); + +/* + * Test that --version option works and generates reasonable output. + */ + +static void +verify(const char *p, size_t s) +{ + const char *q = p; + + /* Version message should start with name of program, then space. */ + failure("version message too short:", p); + if (!assert(s > 6)) + return; + failure("Version message should begin with 'bsdcpio': %s", p); + if (!assertEqualMem(q, "bsdcpio ", 8)) + /* If we're not testing bsdcpio, don't keep going. */ + return; + q += 8; s -= 8; + /* Version number is a series of digits and periods. */ + while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) { + ++q; + --s; + } + /* Version number terminated by space. */ + failure("Version: %s", p); + assert(s > 1); + /* Skip a single trailing a,b,c, or d. */ + if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd') + ++q; + failure("Version: %s", p); + assert(*q == ' '); + ++q; --s; + /* Separator. */ + failure("Version: %s", p); + assertEqualMem(q, "-- ", 3); + q += 3; s -= 3; + /* libarchive name and version number */ + assert(s > 11); + failure("Version: %s", p); + assertEqualMem(q, "libarchive ", 11); + q += 11; s -= 11; + /* Version number is a series of digits and periods. */ + while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) { + ++q; + --s; + } + /* Skip a single trailing a,b,c, or d. */ + if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd') + ++q; + /* All terminated by a newline. */ + assert(s >= 1); + failure("Version: %s", p); + assertEqualMem(q, "\n", 1); +} + + +DEFINE_TEST(test_option_version) +{ + int r; + char *p; + size_t s; + + r = systemf("%s --version >version.stdout 2>version.stderr", testprog); + if (r != 0) + r = systemf("%s -W version >version.stdout 2>version.stderr", + testprog); + failure("Unable to run either %s --version or %s -W version", + testprog, testprog); + if (!assert(r == 0)) + return; + + /* --version should generate nothing to stderr. */ + assertEmptyFile("version.stderr"); + /* Verify format of version message. */ + p = slurpfile(&s, "version.stdout"); + verify(p, s); + free(p); +} diff --git a/usr.bin/cpio/test/test_option_y.c b/usr.bin/cpio/test/test_option_y.c new file mode 100644 index 0000000..56852a8 --- /dev/null +++ b/usr.bin/cpio/test/test_option_y.c @@ -0,0 +1,52 @@ +/*- + * 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$"); + +DEFINE_TEST(test_option_y) +{ + char *p; + int fd; + int r; + size_t s; + + /* Create a file. */ + fd = open("f", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(1, write(fd, "a", 1)); + close(fd); + + /* Archive it with bzip2 compression. */ + r = systemf("echo f | %s -oy >archive.out 2>archive.err", + testprog); + assertFileContents("1 block\n", 8, "archive.err"); + failure("-y (bzip) option seems to be broken"); + if (assertEqualInt(r, 0)) { + /* Check that the archive file has a bzip2 signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "BZh9", 4); + } +} diff --git a/usr.bin/cpio/test/test_option_z.c b/usr.bin/cpio/test/test_option_z.c new file mode 100644 index 0000000..15337a4 --- /dev/null +++ b/usr.bin/cpio/test/test_option_z.c @@ -0,0 +1,52 @@ +/*- + * 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$"); + +DEFINE_TEST(test_option_z) +{ + char *p; + int fd; + int r; + size_t s; + + /* Create a file. */ + fd = open("f", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(1, write(fd, "a", 1)); + close(fd); + + /* Archive it with gzip compression. */ + r = systemf("echo f | %s -oz >archive.out 2>archive.err", + testprog); + failure("-z option seems to be broken"); + assertEqualInt(r, 0); + if (r == 0) { + /* Check that the archive file has a gzip signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "\x1f\x8b\x08\x00", 4); + } +} diff --git a/usr.bin/cpio/test/test_owner_parse.c b/usr.bin/cpio/test/test_owner_parse.c new file mode 100644 index 0000000..1adbce4 --- /dev/null +++ b/usr.bin/cpio/test/test_owner_parse.c @@ -0,0 +1,68 @@ +/*- + * 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$"); + +#include "../cpio.h" + +DEFINE_TEST(test_owner_parse) +{ + int uid, gid; + + cpio_progname = "Ignore this message"; + + assertEqualInt(0, owner_parse("root", &uid, &gid)); + assertEqualInt(0, uid); + assertEqualInt(-1, gid); + + + assertEqualInt(0, owner_parse("root:", &uid, &gid)); + assertEqualInt(0, uid); + assertEqualInt(0, gid); + + assertEqualInt(0, owner_parse("root.", &uid, &gid)); + assertEqualInt(0, uid); + assertEqualInt(0, gid); + + /* + * TODO: Lookup current user/group name, build strings and + * use those to verify username/groupname lookups for ordinary + * users. + */ + + /* + * TODO: Rework owner_parse to either return a char * pointing + * to an error message or accept a function pointer to an + * error-reporting routine so that the following tests don't + * generate any output. + * + * Alternatively, redirect stderr temporarily to suppress the output. + */ + + assertEqualInt(1, owner_parse(":nonexistentgroup", &uid, &gid)); + assertEqualInt(1, owner_parse("root:nonexistentgroup", &uid, &gid)); + assertEqualInt(1, + owner_parse("nonexistentuser:nonexistentgroup", &uid, &gid)); +} diff --git a/usr.bin/cpio/test/test_pathmatch.c b/usr.bin/cpio/test/test_pathmatch.c new file mode 100644 index 0000000..83528c0 --- /dev/null +++ b/usr.bin/cpio/test/test_pathmatch.c @@ -0,0 +1,165 @@ +/*- + * 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$"); + +#include "../pathmatch.h" + +/* + * Verify that the pattern matcher implements the wildcard logic specified + * in SUSv2 for the cpio command. This is essentially the + * shell glob syntax: + * * - matches any sequence of chars, including '/' + * ? - matches any single char, including '/' + * [...] - matches any of a set of chars, '-' specifies a range, + * initial '!' is undefined + * + * The specification in SUSv2 is a bit incomplete, I assume the following: + * Trailing '-' in [...] is not special. + */ + +DEFINE_TEST(test_pathmatch) +{ + assertEqualInt(1, pathmatch("*","", 0)); + assertEqualInt(1, pathmatch("*","a", 0)); + assertEqualInt(1, pathmatch("*","abcd", 0)); + /* SUSv2: * matches / */ + assertEqualInt(1, pathmatch("*","abcd/efgh/ijkl", 0)); + assertEqualInt(1, pathmatch("abcd*efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(1, pathmatch("abcd***efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(1, pathmatch("abcd***/efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(0, pathmatch("?", "", 0)); + assertEqualInt(0, pathmatch("?", "\0", 0)); + assertEqualInt(1, pathmatch("?", "a", 0)); + assertEqualInt(0, pathmatch("?", "ab", 0)); + assertEqualInt(1, pathmatch("?", ".", 0)); + assertEqualInt(1, pathmatch("?", "?", 0)); + assertEqualInt(1, pathmatch("a", "a", 0)); + assertEqualInt(0, pathmatch("a", "ab", 0)); + assertEqualInt(0, pathmatch("a", "ab", 0)); + assertEqualInt(1, pathmatch("a?c", "abc", 0)); + /* SUSv2: ? matches / */ + assertEqualInt(1, pathmatch("a?c", "a/c", 0)); + assertEqualInt(1, pathmatch("a?*c*", "a/c", 0)); + assertEqualInt(1, pathmatch("*a*", "a/c", 0)); + assertEqualInt(1, pathmatch("*a*", "/a/c", 0)); + assertEqualInt(1, pathmatch("*a*", "defaaaaaaa", 0)); + assertEqualInt(0, pathmatch("a*", "defghi", 0)); + assertEqualInt(0, pathmatch("*a*", "defghi", 0)); + assertEqualInt(1, pathmatch("abc[def", "abc[def", 0)); + assertEqualInt(0, pathmatch("abc[def]", "abc[def", 0)); + assertEqualInt(0, pathmatch("abc[def", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[def]", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[def]", "abce", 0)); + assertEqualInt(1, pathmatch("abc[def]", "abcf", 0)); + assertEqualInt(0, pathmatch("abc[def]", "abcg", 0)); + assertEqualInt(1, pathmatch("abc[d*f]", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[d*f]", "abc*", 0)); + assertEqualInt(0, pathmatch("abc[d*f]", "abcdefghi", 0)); + assertEqualInt(0, pathmatch("abc[d*", "abcdefghi", 0)); + assertEqualInt(1, pathmatch("abc[d*", "abc[defghi", 0)); + assertEqualInt(1, pathmatch("abc[d-f]", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[d-f]", "abce", 0)); + assertEqualInt(1, pathmatch("abc[d-f]", "abcf", 0)); + assertEqualInt(0, pathmatch("abc[d-f]", "abcg", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-k]", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-k]", "abce", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-k]", "abcf", 0)); + assertEqualInt(0, pathmatch("abc[d-fh-k]", "abcg", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-k]", "abch", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-k]", "abci", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-k]", "abcj", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-k]", "abck", 0)); + assertEqualInt(0, pathmatch("abc[d-fh-k]", "abcl", 0)); + assertEqualInt(0, pathmatch("abc[d-fh-k]", "abc-", 0)); + + /* I assume: Trailing '-' is non-special. */ + assertEqualInt(0, pathmatch("abc[d-fh-]", "abcl", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-]", "abch", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-]", "abc-", 0)); + assertEqualInt(1, pathmatch("abc[d-fh-]", "abc-", 0)); + + /* ']' can be backslash-quoted within a character class. */ + assertEqualInt(1, pathmatch("abc[\\]]", "abc]", 0)); + assertEqualInt(1, pathmatch("abc[\\]d]", "abc]", 0)); + assertEqualInt(1, pathmatch("abc[\\]d]", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[d\\]]", "abc]", 0)); + assertEqualInt(1, pathmatch("abc[d\\]]", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[d]e]", "abcde]", 0)); + assertEqualInt(1, pathmatch("abc[d\\]e]", "abc]", 0)); + assertEqualInt(0, pathmatch("abc[d\\]e]", "abcd]e", 0)); + assertEqualInt(0, pathmatch("abc[d]e]", "abc]", 0)); + + /* backslash-quoted chars can appear as either end of a range. */ + assertEqualInt(1, pathmatch("abc[\\d-f]gh", "abcegh", 0)); + assertEqualInt(0, pathmatch("abc[\\d-f]gh", "abcggh", 0)); + assertEqualInt(0, pathmatch("abc[\\d-f]gh", "abc\\gh", 0)); + assertEqualInt(1, pathmatch("abc[d-\\f]gh", "abcegh", 0)); + assertEqualInt(1, pathmatch("abc[\\d-\\f]gh", "abcegh", 0)); + assertEqualInt(1, pathmatch("abc[\\d-\\f]gh", "abcegh", 0)); + /* backslash-quoted '-' isn't special. */ + assertEqualInt(0, pathmatch("abc[d\\-f]gh", "abcegh", 0)); + assertEqualInt(1, pathmatch("abc[d\\-f]gh", "abc-gh", 0)); + + /* Leading '!' negates a character class. */ + assertEqualInt(0, pathmatch("abc[!d]", "abcd", 0)); + assertEqualInt(1, pathmatch("abc[!d]", "abce", 0)); + assertEqualInt(1, pathmatch("abc[!d]", "abcc", 0)); + assertEqualInt(0, pathmatch("abc[!d-z]", "abcq", 0)); + assertEqualInt(1, pathmatch("abc[!d-gi-z]", "abch", 0)); + assertEqualInt(1, pathmatch("abc[!fgijkl]", "abch", 0)); + assertEqualInt(0, pathmatch("abc[!fghijkl]", "abch", 0)); + + /* Backslash quotes next character. */ + assertEqualInt(0, pathmatch("abc\\[def]", "abc\\d", 0)); + assertEqualInt(1, pathmatch("abc\\[def]", "abc[def]", 0)); + assertEqualInt(0, pathmatch("abc\\\\[def]", "abc[def]", 0)); + assertEqualInt(0, pathmatch("abc\\\\[def]", "abc\\[def]", 0)); + assertEqualInt(1, pathmatch("abc\\\\[def]", "abc\\d", 0)); + + /* + * Because '.' and '/' have special meanings, we can + * identify many equivalent paths even if they're expressed + * differently. + */ + assertEqualInt(1, pathmatch("./abc/./def/", "abc/def/", 0)); + assertEqualInt(1, pathmatch("abc/def", "./././abc/./def", 0)); + assertEqualInt(1, pathmatch("abc/def/././//", "./././abc/./def/", 0)); + assertEqualInt(1, pathmatch(".////abc/.//def", "./././abc/./def", 0)); + assertEqualInt(1, pathmatch("./abc?def/", "abc/def/", 0)); + failure("\"?./\" is not the same as \"/./\""); + assertEqualInt(0, pathmatch("./abc?./def/", "abc/def/", 0)); + failure("Trailing '/' should match no trailing '/'"); + assertEqualInt(1, pathmatch("./abc/./def/", "abc/def", 0)); + failure("Trailing '/./' is still the same directory."); + assertEqualInt(1, pathmatch("./abc/./def/./", "abc/def", 0)); + failure("Trailing '/.' is still the same directory."); + assertEqualInt(1, pathmatch("./abc/./def/.", "abc/def", 0)); + assertEqualInt(1, pathmatch("./abc/./def", "abc/def/", 0)); + failure("Trailing '/./' is still the same directory."); + assertEqualInt(1, pathmatch("./abc/./def", "abc/def/./", 0)); + failure("Trailing '/.' is still the same directory."); + assertEqualInt(1, pathmatch("./abc*/./def", "abc/def/.", 0)); +} |