diff options
author | mm <mm@FreeBSD.org> | 2011-07-17 21:42:22 +0000 |
---|---|---|
committer | mm <mm@FreeBSD.org> | 2011-07-17 21:42:22 +0000 |
commit | 84c56da91a08ce9f1a669fa732a156e36b3ad358 (patch) | |
tree | e2aa60b473bd88d42e965988a7bd13041fd17954 /usr.bin | |
parent | 867c8ddd4db0c581c7d6f04f5317cdc34c07dd5c (diff) | |
download | FreeBSD-src-84c56da91a08ce9f1a669fa732a156e36b3ad358.zip FreeBSD-src-84c56da91a08ce9f1a669fa732a156e36b3ad358.tar.gz |
Update bsdcpio to 2.8.4
Use common code from lib/libarchive/libarchive_fe
Approved by: kientzle
MFC after: 2 weeks
Diffstat (limited to 'usr.bin')
43 files changed, 2692 insertions, 2282 deletions
diff --git a/usr.bin/cpio/Makefile b/usr.bin/cpio/Makefile index fe339cd..5868e52 100644 --- a/usr.bin/cpio/Makefile +++ b/usr.bin/cpio/Makefile @@ -3,17 +3,24 @@ .include <bsd.own.mk> PROG= bsdcpio -BSDCPIO_VERSION_STRING=2.8.3 -SRCS= cpio.c cmdline.c err.c line_reader.c matching.c pathmatch.c +BSDCPIO_VERSION_STRING=2.8.4 + +SRCS= cpio.c cmdline.c + +.PATH: ${.CURDIR}/../../lib/libarchive/libarchive_fe +SRCS+= err.c line_reader.c matching.c pathmatch.c + CFLAGS+= -DBSDCPIO_VERSION_STRING=\"${BSDCPIO_VERSION_STRING}\" CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\" +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../../lib/libarchive/libarchive_fe + .ifdef RELEASE_CRUNCH # FreeBSD's installer uses cpio in crunched binaries that are # statically linked, cannot use -lcrypto, and are size sensitive. CFLAGS+= -DSMALLER .endif -DPADD= ${LIBARCHIVE} ${LIBZ} ${LIBBZ2} ${LIBMD} ${LIBLZMA} -LDADD= -larchive -lz -lbz2 -lmd -llzma +DPADD= ${LIBARCHIVE} ${LIBZ} ${LIBBZ2} ${LIBMD} ${LIBLZMA} ${LIBBSDXML} +LDADD= -larchive -lz -lbz2 -lmd -llzma -lbsdxml .if ${MK_OPENSSL} != "no" DPADD+= ${LIBCRYPTO} LDADD+= -lcrypto diff --git a/usr.bin/cpio/cmdline.c b/usr.bin/cpio/cmdline.c index f0e8ba20..687fa62 100644 --- a/usr.bin/cpio/cmdline.c +++ b/usr.bin/cpio/cmdline.c @@ -175,7 +175,7 @@ cpio_getopt(struct cpio *cpio) /* Otherwise, pick up the next word. */ opt_word = *cpio->argv; if (opt_word == NULL) { - warnc(0, + lafe_warnc(0, "Option -%c requires an argument", opt); return ('?'); @@ -226,13 +226,13 @@ cpio_getopt(struct cpio *cpio) /* Fail if there wasn't a unique match. */ if (match == NULL) { - warnc(0, + lafe_warnc(0, "Option %s%s is not supported", long_prefix, opt_word); return ('?'); } if (match2 != NULL) { - warnc(0, + lafe_warnc(0, "Ambiguous option %s%s (matches --%s and --%s)", long_prefix, opt_word, match->name, match2->name); return ('?'); @@ -244,7 +244,7 @@ cpio_getopt(struct cpio *cpio) if (cpio->optarg == NULL) { cpio->optarg = *cpio->argv; if (cpio->optarg == NULL) { - warnc(0, + lafe_warnc(0, "Option %s%s requires an argument", long_prefix, match->name); return ('?'); @@ -255,7 +255,7 @@ cpio_getopt(struct cpio *cpio) } else { /* Argument forbidden: fail if there is one. */ if (cpio->optarg != NULL) { - warnc(0, + lafe_warnc(0, "Option %s%s does not allow an argument", long_prefix, match->name); return ('?'); diff --git a/usr.bin/cpio/config_freebsd.h b/usr.bin/cpio/config_freebsd.h index ec4e441..bf24b9e 100644 --- a/usr.bin/cpio/config_freebsd.h +++ b/usr.bin/cpio/config_freebsd.h @@ -53,4 +53,5 @@ #define HAVE_UNSIGNED_LONG_LONG 1 #define HAVE_UTIME_H 1 #define HAVE_UTIMES 1 +#define HAVE_WCSCMP 1 diff --git a/usr.bin/cpio/cpio.c b/usr.bin/cpio/cpio.c index ab32224..cd81050 100644 --- a/usr.bin/cpio/cpio.c +++ b/usr.bin/cpio/cpio.c @@ -136,19 +136,19 @@ main(int argc, char *argv[]) cpio->buff = buff; cpio->buff_size = sizeof(buff); - /* Need progname before calling warnc. */ + /* Need lafe_progname before calling lafe_warnc. */ if (*argv == NULL) - progname = "bsdcpio"; + lafe_progname = "bsdcpio"; else { #if defined(_WIN32) && !defined(__CYGWIN__) - progname = strrchr(*argv, '\\'); + lafe_progname = strrchr(*argv, '\\'); #else - progname = strrchr(*argv, '/'); + lafe_progname = strrchr(*argv, '/'); #endif - if (progname != NULL) - progname++; + if (lafe_progname != NULL) + lafe_progname++; else - progname = *argv; + lafe_progname = *argv; } cpio->uid_override = -1; @@ -189,7 +189,7 @@ main(int argc, char *argv[]) case 'C': /* NetBSD/OpenBSD */ cpio->bytes_per_block = atoi(cpio->optarg); if (cpio->bytes_per_block <= 0) - errc(1, 0, "Invalid blocksize %s", cpio->optarg); + lafe_errc(1, 0, "Invalid blocksize %s", cpio->optarg); break; case 'c': /* POSIX 1997 */ cpio->format = "odc"; @@ -198,14 +198,14 @@ main(int argc, char *argv[]) cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR; break; case 'E': /* NetBSD/OpenBSD */ - include_from_file(&cpio->matching, + lafe_include_from_file(&cpio->matching, cpio->optarg, cpio->option_null); break; case 'F': /* NetBSD/OpenBSD/GNU cpio */ cpio->filename = cpio->optarg; break; case 'f': /* POSIX 1997 */ - exclude(&cpio->matching, cpio->optarg); + lafe_exclude(&cpio->matching, cpio->optarg); break; case 'H': /* GNU cpio (also --format) */ cpio->format = cpio->optarg; @@ -218,7 +218,7 @@ main(int argc, char *argv[]) break; case 'i': /* POSIX 1997 */ if (cpio->mode != '\0') - errc(1, 0, + lafe_errc(1, 0, "Cannot use both -i and -%c", cpio->mode); cpio->mode = opt; break; @@ -255,13 +255,13 @@ main(int argc, char *argv[]) break; case 'o': /* POSIX 1997 */ if (cpio->mode != '\0') - errc(1, 0, + lafe_errc(1, 0, "Cannot use both -o and -%c", cpio->mode); cpio->mode = opt; break; case 'p': /* POSIX 1997 */ if (cpio->mode != '\0') - errc(1, 0, + lafe_errc(1, 0, "Cannot use both -p and -%c", cpio->mode); cpio->mode = opt; cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; @@ -277,7 +277,7 @@ main(int argc, char *argv[]) * also; use that to set [ug]name_override. */ errmsg = owner_parse(cpio->optarg, &uid, &gid); if (errmsg) { - warnc(-1, "%s", errmsg); + lafe_warnc(-1, "%s", errmsg); usage(); } if (uid != -1) { @@ -335,16 +335,16 @@ main(int argc, char *argv[]) cpio->mode = 'i'; /* -t requires -i */ if (cpio->option_list && cpio->mode != 'i') - errc(1, 0, "Option -t requires -i"); + lafe_errc(1, 0, "Option -t requires -i"); /* -n requires -it */ if (cpio->option_numeric_uid_gid && !cpio->option_list) - errc(1, 0, "Option -n requires -it"); + lafe_errc(1, 0, "Option -n requires -it"); /* Can only specify format when writing */ if (cpio->format != NULL && cpio->mode != 'o') - errc(1, 0, "Option --format requires -o"); + lafe_errc(1, 0, "Option --format requires -o"); /* -l requires -p */ if (cpio->option_link && cpio->mode != 'p') - errc(1, 0, "Option -l requires -p"); + lafe_errc(1, 0, "Option -l requires -p"); /* TODO: Flag other nonsensical combinations. */ switch (cpio->mode) { @@ -358,7 +358,7 @@ main(int argc, char *argv[]) break; case 'i': while (*cpio->argv != NULL) { - include(&cpio->matching, *cpio->argv); + lafe_include(&cpio->matching, *cpio->argv); --cpio->argc; ++cpio->argv; } @@ -369,12 +369,12 @@ main(int argc, char *argv[]) break; case 'p': if (*cpio->argv == NULL || **cpio->argv == '\0') - errc(1, 0, + lafe_errc(1, 0, "-p mode requires a target directory"); mode_pass(cpio, *cpio->argv); break; default: - errc(1, 0, + lafe_errc(1, 0, "Must specify at least one of -i, -o, or -p"); } @@ -388,7 +388,7 @@ usage(void) { const char *p; - p = progname; + p = lafe_progname; fprintf(stderr, "Brief Usage:\n"); fprintf(stderr, " List: %s -it < archive\n", p); @@ -426,7 +426,7 @@ long_help(void) const char *prog; const char *p; - prog = progname; + prog = lafe_progname; fflush(stderr); @@ -459,16 +459,16 @@ static void mode_out(struct cpio *cpio) { struct archive_entry *entry, *spare; - struct line_reader *lr; + struct lafe_line_reader *lr; const char *p; int r; if (cpio->option_append) - errc(1, 0, "Append mode not yet supported."); + lafe_errc(1, 0, "Append mode not yet supported."); cpio->archive_read_disk = archive_read_disk_new(); if (cpio->archive_read_disk == NULL) - errc(1, 0, "Failed to allocate archive object"); + lafe_errc(1, 0, "Failed to allocate archive object"); if (cpio->option_follow_links) archive_read_disk_set_symlink_logical(cpio->archive_read_disk); else @@ -477,7 +477,7 @@ mode_out(struct cpio *cpio) cpio->archive = archive_write_new(); if (cpio->archive == NULL) - errc(1, 0, "Failed to allocate archive object"); + lafe_errc(1, 0, "Failed to allocate archive object"); switch (cpio->compress) { case 'J': r = archive_write_set_compression_xz(cpio->archive); @@ -499,10 +499,10 @@ mode_out(struct cpio *cpio) break; } if (r < ARCHIVE_WARN) - errc(1, 0, "Requested compression not available"); + lafe_errc(1, 0, "Requested compression not available"); r = archive_write_set_format_by_name(cpio->archive, cpio->format); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(cpio->archive)); + lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); archive_write_set_bytes_per_block(cpio->archive, cpio->bytes_per_block); cpio->linkresolver = archive_entry_linkresolver_new(); archive_entry_linkresolver_set_strategy(cpio->linkresolver, @@ -513,11 +513,11 @@ mode_out(struct cpio *cpio) */ r = archive_write_open_file(cpio->archive, cpio->filename); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(cpio->archive)); - lr = line_reader("-", cpio->option_null); - while ((p = line_reader_next(lr)) != NULL) + lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); + lr = lafe_line_reader("-", cpio->option_null); + while ((p = lafe_line_reader_next(lr)) != NULL) file_to_archive(cpio, p); - line_reader_free(lr); + lafe_line_reader_free(lr); /* * The hardlink detection may have queued up a couple of entries @@ -534,7 +534,7 @@ mode_out(struct cpio *cpio) r = archive_write_close(cpio->archive); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(cpio->archive)); + lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); if (!cpio->quiet) { int64_t blocks = @@ -566,15 +566,15 @@ file_to_archive(struct cpio *cpio, const char *srcpath) */ entry = archive_entry_new(); if (entry == NULL) - errc(1, 0, "Couldn't allocate entry"); + lafe_errc(1, 0, "Couldn't allocate entry"); archive_entry_copy_sourcepath(entry, srcpath); r = archive_read_disk_entry_from_file(cpio->archive_read_disk, entry, -1, NULL); if (r < ARCHIVE_FAILED) - errc(1, 0, "%s", + lafe_errc(1, 0, "%s", archive_error_string(cpio->archive_read_disk)); if (r < ARCHIVE_OK) - warnc(0, "%s", + lafe_warnc(0, "%s", archive_error_string(cpio->archive_read_disk)); if (r <= ARCHIVE_FAILED) { cpio->return_value = 1; @@ -607,7 +607,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath) free(cpio->pass_destpath); cpio->pass_destpath = malloc(cpio->pass_destpath_alloc); if (cpio->pass_destpath == NULL) - errc(1, ENOMEM, + lafe_errc(1, ENOMEM, "Can't allocate path buffer"); } strcpy(cpio->pass_destpath, cpio->destdir); @@ -673,7 +673,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) /* Save the original entry in case we need it later. */ t = archive_entry_clone(entry); if (t == NULL) - errc(1, ENOMEM, "Can't create link"); + lafe_errc(1, ENOMEM, "Can't create link"); /* Note: link(2) doesn't create parent directories, * so we use archive_write_header() instead as a * convenience. */ @@ -683,7 +683,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) r = archive_write_header(cpio->archive, t); archive_entry_free(t); if (r != ARCHIVE_OK) - warnc(archive_errno(cpio->archive), + lafe_warnc(archive_errno(cpio->archive), "%s", archive_error_string(cpio->archive)); if (r == ARCHIVE_FATAL) exit(1); @@ -691,7 +691,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) if (r != ARCHIVE_OK && archive_errno(cpio->archive) == EXDEV) { /* Cross-device link: Just fall through and use * the original entry to copy the file over. */ - warnc(0, "Copying file instead"); + lafe_warnc(0, "Copying file instead"); } else #endif return (0); @@ -705,7 +705,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) if (archive_entry_size(entry) > 0) { fd = open(srcpath, O_RDONLY | O_BINARY); if (fd < 0) { - warnc(errno, + lafe_warnc(errno, "%s: could not open file", srcpath); goto cleanup; } @@ -717,7 +717,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) r = archive_write_header(cpio->archive, entry); if (r != ARCHIVE_OK) - warnc(archive_errno(cpio->archive), + lafe_warnc(archive_errno(cpio->archive), "%s: %s", srcpath, archive_error_string(cpio->archive)); @@ -731,10 +731,10 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) r = archive_write_data(cpio->archive, cpio->buff, bytes_read); if (r < 0) - errc(1, archive_errno(cpio->archive), + lafe_errc(1, archive_errno(cpio->archive), "%s", archive_error_string(cpio->archive)); if (r < bytes_read) { - warnc(0, + lafe_warnc(0, "Truncated write; file may have grown while being archived."); } bytes_read = read(fd, cpio->buff, cpio->buff_size); @@ -763,7 +763,7 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, (void)name; /* UNUSED */ if (!warned) - warnc(0, "Can't restore access times on this platform"); + lafe_warnc(0, "Can't restore access times on this platform"); warned = 1; return (fd); #else @@ -801,7 +801,7 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, if ((AE_IFLNK != archive_entry_filetype(entry)) && utimes(name, times) != 0) #endif - warnc(errno, "Can't update time for %s", name); + lafe_warnc(errno, "Can't update time for %s", name); #endif return (fd); } @@ -818,28 +818,28 @@ mode_in(struct cpio *cpio) ext = archive_write_disk_new(); if (ext == NULL) - errc(1, 0, "Couldn't allocate restore object"); + lafe_errc(1, 0, "Couldn't allocate restore object"); r = archive_write_disk_set_options(ext, cpio->extract_flags); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(ext)); + lafe_errc(1, 0, "%s", archive_error_string(ext)); a = archive_read_new(); if (a == NULL) - errc(1, 0, "Couldn't allocate archive object"); + lafe_errc(1, 0, "Couldn't allocate archive object"); archive_read_support_compression_all(a); archive_read_support_format_all(a); if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block)) - errc(1, archive_errno(a), + lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { - errc(1, archive_errno(a), + lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); } - if (excluded(cpio->matching, archive_entry_pathname(entry))) + if (lafe_excluded(cpio->matching, archive_entry_pathname(entry))) continue; if (cpio->option_rename) { destpath = cpio_rename(archive_entry_pathname(entry)); @@ -867,10 +867,10 @@ mode_in(struct cpio *cpio) } r = archive_read_close(a); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(a)); + lafe_errc(1, 0, "%s", archive_error_string(a)); r = archive_write_close(ext); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(ext)); + lafe_errc(1, 0, "%s", archive_error_string(ext)); if (!cpio->quiet) { int64_t blocks = (archive_position_uncompressed(a) + 511) / 512; @@ -899,13 +899,13 @@ extract_data(struct archive *ar, struct archive *aw) if (r == ARCHIVE_EOF) return (ARCHIVE_OK); if (r != ARCHIVE_OK) { - warnc(archive_errno(ar), + lafe_warnc(archive_errno(ar), "%s", archive_error_string(ar)); exit(1); } r = archive_write_data_block(aw, block, size, offset); if (r != ARCHIVE_OK) { - warnc(archive_errno(aw), + lafe_warnc(archive_errno(aw), "%s", archive_error_string(aw)); return (r); } @@ -921,22 +921,22 @@ mode_list(struct cpio *cpio) a = archive_read_new(); if (a == NULL) - errc(1, 0, "Couldn't allocate archive object"); + lafe_errc(1, 0, "Couldn't allocate archive object"); archive_read_support_compression_all(a); archive_read_support_format_all(a); if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block)) - errc(1, archive_errno(a), + lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { - errc(1, archive_errno(a), + lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); } - if (excluded(cpio->matching, archive_entry_pathname(entry))) + if (lafe_excluded(cpio->matching, archive_entry_pathname(entry))) continue; if (cpio->verbose) list_item_verbose(cpio, entry); @@ -945,7 +945,7 @@ mode_list(struct cpio *cpio) } r = archive_read_close(a); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(a)); + lafe_errc(1, 0, "%s", archive_error_string(a)); if (!cpio->quiet) { int64_t blocks = (archive_position_uncompressed(a) + 511) / 512; @@ -1040,7 +1040,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry) static void mode_pass(struct cpio *cpio, const char *destdir) { - struct line_reader *lr; + struct lafe_line_reader *lr; const char *p; int r; @@ -1052,31 +1052,31 @@ mode_pass(struct cpio *cpio, const char *destdir) cpio->archive = archive_write_disk_new(); if (cpio->archive == NULL) - errc(1, 0, "Failed to allocate archive object"); + lafe_errc(1, 0, "Failed to allocate archive object"); r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(cpio->archive)); + lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); cpio->linkresolver = archive_entry_linkresolver_new(); archive_write_disk_set_standard_lookup(cpio->archive); cpio->archive_read_disk = archive_read_disk_new(); if (cpio->archive_read_disk == NULL) - errc(1, 0, "Failed to allocate archive object"); + lafe_errc(1, 0, "Failed to allocate archive object"); if (cpio->option_follow_links) archive_read_disk_set_symlink_logical(cpio->archive_read_disk); else archive_read_disk_set_symlink_physical(cpio->archive_read_disk); archive_read_disk_set_standard_lookup(cpio->archive_read_disk); - lr = line_reader("-", cpio->option_null); - while ((p = line_reader_next(lr)) != NULL) + lr = lafe_line_reader("-", cpio->option_null); + while ((p = lafe_line_reader_next(lr)) != NULL) file_to_archive(cpio, p); - line_reader_free(lr); + lafe_line_reader_free(lr); archive_entry_linkresolver_free(cpio->linkresolver); r = archive_write_close(cpio->archive); if (r != ARCHIVE_OK) - errc(1, 0, "%s", archive_error_string(cpio->archive)); + lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); if (!cpio->quiet) { int64_t blocks = @@ -1160,7 +1160,7 @@ lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable, if (*name_cache_variable == NULL) { *name_cache_variable = malloc(sizeof(struct name_cache)); if (*name_cache_variable == NULL) - errc(1, ENOMEM, "No more memory"); + lafe_errc(1, ENOMEM, "No more memory"); memset(*name_cache_variable, 0, sizeof(struct name_cache)); (*name_cache_variable)->size = name_cache_size; } @@ -1217,7 +1217,7 @@ lookup_uname_helper(struct cpio *cpio, const char **name, id_t id) if (pwent == NULL) { *name = NULL; if (errno != 0 && errno != ENOENT) - warnc(errno, "getpwuid(%d) failed", id); + lafe_warnc(errno, "getpwuid(%d) failed", id); return (errno); } @@ -1244,7 +1244,7 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id) if (grent == NULL) { *name = NULL; if (errno != 0) - warnc(errno, "getgrgid(%d) failed", id); + lafe_warnc(errno, "getgrgid(%d) failed", id); return (errno); } diff --git a/usr.bin/cpio/cpio.h b/usr.bin/cpio/cpio.h index 2afa8f2..2d5b548 100644 --- a/usr.bin/cpio/cpio.h +++ b/usr.bin/cpio/cpio.h @@ -88,7 +88,7 @@ struct cpio { struct name_cache *gname_cache; /* Work data. */ - struct matching *matching; + struct lafe_matching *matching; char *buff; size_t buff_size; }; diff --git a/usr.bin/cpio/line_reader.c b/usr.bin/cpio/line_reader.c deleted file mode 100644 index 8461941..0000000 --- a/usr.bin/cpio/line_reader.c +++ /dev/null @@ -1,171 +0,0 @@ -/*- - * Copyright (c) 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 - * in this position and unchanged. - * 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 "cpio_platform.h" -__FBSDID("$FreeBSD$"); - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "err.h" -#include "line_reader.h" - -#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) -#define strdup _strdup -#endif - -/* - * Read lines from file and do something with each one. If option_null - * is set, lines are terminated with zero bytes; otherwise, they're - * terminated with newlines. - * - * This uses a self-sizing buffer to handle arbitrarily-long lines. - */ -struct line_reader { - FILE *f; - char *buff, *buff_end, *line_start, *line_end, *p; - char *pathname; - size_t buff_length; - int nullSeparator; /* Lines separated by null, not CR/CRLF/etc. */ - int ret; -}; - -struct line_reader * -line_reader(const char *pathname, int nullSeparator) -{ - struct line_reader *lr; - - lr = calloc(1, sizeof(*lr)); - if (lr == NULL) - errc(1, ENOMEM, "Can't open %s", pathname); - - lr->nullSeparator = nullSeparator; - lr->pathname = strdup(pathname); - - if (strcmp(pathname, "-") == 0) - lr->f = stdin; - else - lr->f = fopen(pathname, "r"); - if (lr->f == NULL) - errc(1, errno, "Couldn't open %s", pathname); - lr->buff_length = 8192; - lr->buff = malloc(lr->buff_length); - if (lr->buff == NULL) - errc(1, ENOMEM, "Can't read %s", pathname); - lr->line_start = lr->line_end = lr->buff_end = lr->buff; - - return (lr); -} - -const char * -line_reader_next(struct line_reader *lr) -{ - size_t bytes_wanted, bytes_read, new_buff_size; - char *line_start, *p; - - for (;;) { - /* If there's a line in the buffer, return it immediately. */ - while (lr->line_end < lr->buff_end) { - if (lr->nullSeparator) { - if (*lr->line_end == '\0') { - line_start = lr->line_start; - lr->line_start = lr->line_end + 1; - lr->line_end = lr->line_start; - return (line_start); - } - } else if (*lr->line_end == '\x0a' || *lr->line_end == '\x0d') { - *lr->line_end = '\0'; - line_start = lr->line_start; - lr->line_start = lr->line_end + 1; - lr->line_end = lr->line_start; - if (line_start[0] != '\0') - return (line_start); - } - lr->line_end++; - } - - /* If we're at end-of-file, process the final data. */ - if (lr->f == NULL) { - /* If there's more text, return one last line. */ - if (lr->line_end > lr->line_start) { - *lr->line_end = '\0'; - line_start = lr->line_start; - lr->line_start = lr->line_end + 1; - lr->line_end = lr->line_start; - return (line_start); - } - /* Otherwise, we're done. */ - return (NULL); - } - - /* Buffer only has part of a line. */ - if (lr->line_start > lr->buff) { - /* Move a leftover fractional line to the beginning. */ - memmove(lr->buff, lr->line_start, - lr->buff_end - lr->line_start); - lr->buff_end -= lr->line_start - lr->buff; - lr->line_end -= lr->line_start - lr->buff; - lr->line_start = lr->buff; - } else { - /* Line is too big; enlarge the buffer. */ - new_buff_size = lr->buff_length * 2; - if (new_buff_size <= lr->buff_length) - errc(1, ENOMEM, - "Line too long in %s", lr->pathname); - lr->buff_length = new_buff_size; - p = realloc(lr->buff, new_buff_size); - if (p == NULL) - errc(1, ENOMEM, - "Line too long in %s", lr->pathname); - lr->buff_end = p + (lr->buff_end - lr->buff); - lr->line_end = p + (lr->line_end - lr->buff); - lr->line_start = lr->buff = p; - } - - /* Get some more data into the buffer. */ - bytes_wanted = lr->buff + lr->buff_length - lr->buff_end; - bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f); - lr->buff_end += bytes_read; - - if (ferror(lr->f)) - errc(1, errno, "Can't read %s", lr->pathname); - if (feof(lr->f)) { - if (lr->f != stdin) - fclose(lr->f); - lr->f = NULL; - } - } -} - -void -line_reader_free(struct line_reader *lr) -{ - free(lr->buff); - free(lr->pathname); - free(lr); -} diff --git a/usr.bin/cpio/matching.c b/usr.bin/cpio/matching.c deleted file mode 100644 index 0fd2b6a..0000000 --- a/usr.bin/cpio/matching.c +++ /dev/null @@ -1,284 +0,0 @@ -/*- - * 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 "cpio_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include "err.h" -#include "line_reader.h" -#include "matching.h" -#include "pathmatch.h" - -struct match { - struct match *next; - int matches; - char pattern[1]; -}; - -struct matching { - struct match *exclusions; - int exclusions_count; - struct match *inclusions; - int inclusions_count; - int inclusions_unmatched_count; -}; - -static void add_pattern(struct match **list, const char *pattern); -static void initialize_matching(struct matching **); -static int match_exclusion(struct match *, const char *pathname); -static int match_inclusion(struct match *, const char *pathname); - -/* - * The matching logic here needs to be re-thought. I started out to - * try to mimic gtar's matching logic, but it's not entirely - * consistent. In particular 'tar -t' and 'tar -x' interpret patterns - * on the command line as anchored, but --exclude doesn't. - */ - -/* - * Utility functions to manage exclusion/inclusion patterns - */ - -int -exclude(struct matching **matching, const char *pattern) -{ - - if (*matching == NULL) - initialize_matching(matching); - add_pattern(&((*matching)->exclusions), pattern); - (*matching)->exclusions_count++; - return (0); -} - -int -exclude_from_file(struct matching **matching, const char *pathname) -{ - struct line_reader *lr; - const char *p; - int ret = 0; - - lr = line_reader(pathname, 0); - while ((p = line_reader_next(lr)) != NULL) { - if (exclude(matching, p) != 0) - ret = -1; - } - line_reader_free(lr); - return (ret); -} - -int -include(struct matching **matching, const char *pattern) -{ - - if (*matching == NULL) - initialize_matching(matching); - add_pattern(&((*matching)->inclusions), pattern); - (*matching)->inclusions_count++; - (*matching)->inclusions_unmatched_count++; - return (0); -} - -int -include_from_file(struct matching **matching, const char *pathname, - int nullSeparator) -{ - struct line_reader *lr; - const char *p; - int ret = 0; - - lr = line_reader(pathname, nullSeparator); - while ((p = line_reader_next(lr)) != NULL) { - if (include(matching, p) != 0) - ret = -1; - } - line_reader_free(lr); - return (ret); -} - -static void -add_pattern(struct match **list, const char *pattern) -{ - struct match *match; - size_t len; - - len = strlen(pattern); - match = malloc(sizeof(*match) + len + 1); - if (match == NULL) - errc(1, errno, "Out of memory"); - strcpy(match->pattern, pattern); - /* Both "foo/" and "foo" should match "foo/bar". */ - if (len && match->pattern[len - 1] == '/') - match->pattern[strlen(match->pattern)-1] = '\0'; - match->next = *list; - *list = match; - match->matches = 0; -} - - -int -excluded(struct matching *matching, const char *pathname) -{ - struct match *match; - struct match *matched; - - if (matching == NULL) - return (0); - - /* Exclusions take priority */ - for (match = matching->exclusions; match != NULL; match = match->next){ - if (match_exclusion(match, pathname)) - return (1); - } - - /* Then check for inclusions */ - matched = NULL; - for (match = matching->inclusions; match != NULL; match = match->next){ - if (match_inclusion(match, pathname)) { - /* - * If this pattern has never been matched, - * then we're done. - */ - if (match->matches == 0) { - match->matches++; - matching->inclusions_unmatched_count--; - return (0); - } - /* - * Otherwise, remember the match but keep checking - * in case we can tick off an unmatched pattern. - */ - matched = match; - } - } - /* - * We didn't find a pattern that had never been matched, but - * we did find a match, so count it and exit. - */ - if (matched != NULL) { - matched->matches++; - return (0); - } - - /* If there were inclusions, default is to exclude. */ - if (matching->inclusions != NULL) - return (1); - - /* No explicit inclusions, default is to match. */ - return (0); -} - -/* - * This is a little odd, but it matches the default behavior of - * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' - * - */ -static int -match_exclusion(struct match *match, const char *pathname) -{ - return (pathmatch(match->pattern, - pathname, - PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END)); -} - -/* - * Again, mimic gtar: inclusions are always anchored (have to match - * the beginning of the path) even though exclusions are not anchored. - */ -static int -match_inclusion(struct match *match, const char *pathname) -{ -#if 0 - return (pathmatch(match->pattern, pathname, 0)); -#else - return (pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END)); -#endif -} - -void -cleanup_exclusions(struct matching **matching) -{ - struct match *p, *q; - - if (*matching == NULL) - return; - - for (p = (*matching)->inclusions; p != NULL; ) { - q = p; - p = p->next; - free(q); - } - - for (p = (*matching)->exclusions; p != NULL; ) { - q = p; - p = p->next; - free(q); - } - - free(*matching); - *matching = NULL; -} - -static void -initialize_matching(struct matching **matching) -{ - *matching = calloc(sizeof(**matching), 1); - if (*matching == NULL) - errc(1, errno, "No memory"); -} - -int -unmatched_inclusions(struct matching *matching) -{ - - if (matching == NULL) - return (0); - return (matching->inclusions_unmatched_count); -} - -int -unmatched_inclusions_warn(struct matching *matching, const char *msg) -{ - struct match *p; - - if (matching == NULL) - return (0); - - for (p = matching->inclusions; p != NULL; p = p->next) { - if (p->matches == 0) - warnc(0, "%s: %s", p->pattern, msg); - } - - return (matching->inclusions_unmatched_count); -} diff --git a/usr.bin/cpio/matching.h b/usr.bin/cpio/matching.h deleted file mode 100644 index e98e82e..0000000 --- a/usr.bin/cpio/matching.h +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * 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 - * in this position and unchanged. - * 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$ - */ - -#ifndef MATCHING_H -#define MATCHING_H - -struct matching; - -int exclude(struct matching **matching, const char *pattern); -int exclude_from_file(struct matching **matching, - const char *pathname); -int include(struct matching **matching, const char *pattern); -int include_from_file(struct matching **matching, - const char *pathname, int nullSeparator); - -int excluded(struct matching *, const char *pathname); -void cleanup_exclusions(struct matching **); -int unmatched_inclusions(struct matching *); -int unmatched_inclusions_warn(struct matching *, const char *msg); - -#endif diff --git a/usr.bin/cpio/pathmatch.c b/usr.bin/cpio/pathmatch.c deleted file mode 100644 index 75f9095..0000000 --- a/usr.bin/cpio/pathmatch.c +++ /dev/null @@ -1,255 +0,0 @@ -/*- - * 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 - * in this position and unchanged. - * 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 "cpio_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include "pathmatch.h" - -/* - * Check whether a character 'c' is matched by a list specification [...]: - * * Leading '!' negates the class. - * * <char>-<char> is a range of characters - * * \<char> removes any special meaning for <char> - * - * Some interesting boundary cases: - * a-d-e is one range (a-d) followed by two single characters - and e. - * \a-\d is same as a-d - * a\-d is three single characters: a, d, - - * Trailing - is not special (so [a-] is two characters a and -). - * Initial - is not special ([a-] is same as [-a] is same as [\\-a]) - * This function never sees a trailing \. - * [] always fails - * [!] always succeeds - */ -static int -pm_list(const char *start, const char *end, const char c, int flags) -{ - const char *p = start; - char rangeStart = '\0', nextRangeStart; - int match = 1, nomatch = 0; - - /* This will be used soon... */ - (void)flags; /* UNUSED */ - - /* If this is a negated class, return success for nomatch. */ - if (*p == '!' && p < end) { - match = 0; - nomatch = 1; - ++p; - } - - while (p < end) { - nextRangeStart = '\0'; - switch (*p) { - case '-': - /* Trailing or initial '-' is not special. */ - if ((rangeStart == '\0') || (p == end - 1)) { - if (*p == c) - return (match); - } else { - char rangeEnd = *++p; - if (rangeEnd == '\\') - rangeEnd = *++p; - if ((rangeStart <= c) && (c <= rangeEnd)) - return (match); - } - break; - case '\\': - ++p; - /* Fall through */ - default: - if (*p == c) - return (match); - nextRangeStart = *p; /* Possible start of range. */ - } - rangeStart = nextRangeStart; - ++p; - } - return (nomatch); -} - -/* - * If s is pointing to "./", ".//", "./././" or the like, skip it. - */ -static const char * -pm_slashskip(const char *s) { - while ((*s == '/') - || (s[0] == '.' && s[1] == '/') - || (s[0] == '.' && s[1] == '\0')) - ++s; - return (s); -} - -static int -pm(const char *p, const char *s, int flags) -{ - const char *end; - - /* - * Ignore leading './', './/', '././', etc. - */ - if (s[0] == '.' && s[1] == '/') - s = pm_slashskip(s + 1); - if (p[0] == '.' && p[1] == '/') - p = pm_slashskip(p + 1); - - for (;;) { - switch (*p) { - case '\0': - if (s[0] == '/') { - if (flags & PATHMATCH_NO_ANCHOR_END) - return (1); - /* "dir" == "dir/" == "dir/." */ - s = pm_slashskip(s); - } - return (*s == '\0'); - case '?': - /* ? always succeds, unless we hit end of 's' */ - if (*s == '\0') - return (0); - break; - case '*': - /* "*" == "**" == "***" ... */ - while (*p == '*') - ++p; - /* Trailing '*' always succeeds. */ - if (*p == '\0') - return (1); - while (*s) { - if (pathmatch(p, s, flags)) - return (1); - ++s; - } - return (0); - case '[': - /* - * Find the end of the [...] character class, - * ignoring \] that might occur within the class. - */ - end = p + 1; - while (*end != '\0' && *end != ']') { - if (*end == '\\' && end[1] != '\0') - ++end; - ++end; - } - if (*end == ']') { - /* We found [...], try to match it. */ - if (!pm_list(p + 1, end, *s, flags)) - return (0); - p = end; /* Jump to trailing ']' char. */ - break; - } else - /* No final ']', so just match '['. */ - if (*p != *s) - return (0); - break; - case '\\': - /* Trailing '\\' matches itself. */ - if (p[1] == '\0') { - if (*s != '\\') - return (0); - } else { - ++p; - if (*p != *s) - return (0); - } - break; - case '/': - if (*s != '/' && *s != '\0') - return (0); - /* Note: pattern "/\./" won't match "/"; - * pm_slashskip() correctly stops at backslash. */ - p = pm_slashskip(p); - s = pm_slashskip(s); - if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)) - return (1); - --p; /* Counteract the increment below. */ - --s; - break; - case '$': - /* '$' is special only at end of pattern and only - * if PATHMATCH_NO_ANCHOR_END is specified. */ - if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ - /* "dir" == "dir/" == "dir/." */ - return (*pm_slashskip(s) == '\0'); - } - /* Otherwise, '$' is not special. */ - /* FALL THROUGH */ - default: - if (*p != *s) - return (0); - break; - } - ++p; - ++s; - } -} - -/* Main entry point. */ -int -pathmatch(const char *p, const char *s, int flags) -{ - /* Empty pattern only matches the empty string. */ - if (p == NULL || *p == '\0') - return (s == NULL || *s == '\0'); - - /* Leading '^' anchors the start of the pattern. */ - if (*p == '^') { - ++p; - flags &= ~PATHMATCH_NO_ANCHOR_START; - } - - if (*p == '/' && *s != '/') - return (0); - - /* Certain patterns and file names anchor implicitly. */ - if (*p == '*' || *p == '/' || *p == '/') { - while (*p == '/') - ++p; - while (*s == '/') - ++s; - return (pm(p, s, flags)); - } - - /* If start is unanchored, try to match start of each path element. */ - if (flags & PATHMATCH_NO_ANCHOR_START) { - for ( ; s != NULL; s = strchr(s, '/')) { - if (*s == '/') - s++; - if (pm(p, s, flags)) - return (1); - } - return (0); - } - - /* Default: Match from beginning. */ - return (pm(p, s, flags)); -} diff --git a/usr.bin/cpio/test/Makefile b/usr.bin/cpio/test/Makefile index 111864e..9bdf613 100644 --- a/usr.bin/cpio/test/Makefile +++ b/usr.bin/cpio/test/Makefile @@ -2,24 +2,30 @@ # 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 +.PATH: ${CPIO_SRCDIR} +CPIO_SRCS= cmdline.c + +.PATH: ${.CURDIR}/../../../lib/libarchive/libarchive_fe +TAR_SRCS= err.c pathmatch.c TESTS= \ test_0.c \ test_basic.c \ test_format_newc.c \ test_gcpio_compat.c \ + test_option_B_upper.c \ + test_option_C_upper.c \ + test_option_J_upper.c \ + test_option_L_upper.c \ + test_option_Z_upper.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_l.c \ + test_option_lzma.c \ test_option_m.c \ test_option_t.c \ test_option_u.c \ @@ -34,6 +40,7 @@ TESTS= \ # Build the test program SRCS= list.h \ ${CPIO_SRCS} \ + ${TAR_SRCS} \ ${TESTS} \ main.c @@ -46,9 +53,11 @@ DPADD=${LIBARCHIVE} ${LIBBZ2} ${LIBZ} ${LIBLZMA} CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\" CFLAGS+= -I.. LDADD= -larchive -lz -lbz2 -llzma -CFLAGS+= -static -g -O2 -Wall +#CFLAGS+= -static -g -O2 -Wall +CFLAGS+= -g -O2 -Wall CFLAGS+= -I${.OBJDIR} CFLAGS+= -I${CPIO_SRCDIR} +CFLAGS+= -I${.CURDIR}/../../../lib/libarchive/libarchive_fe # Uncomment to link against dmalloc #LDADD+= -L/usr/local/lib -ldmalloc diff --git a/usr.bin/cpio/test/main.c b/usr.bin/cpio/test/main.c index 5a51752..bca4c96 100644 --- a/usr.bin/cpio/test/main.c +++ b/usr.bin/cpio/test/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2009 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,12 +23,7 @@ * 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 "test.h" - #include <errno.h> #include <locale.h> #include <stdarg.h> @@ -38,149 +33,318 @@ * This same file is used pretty much verbatim for all test harnesses. * * The next few lines are the only differences. + * TODO: Move this into a separate configuration header, have all test + * suites share one copy of this file. */ -#define PROGRAM "bsdcpio" /* Name of program being tested. */ +__FBSDID("$FreeBSD$"); +#define KNOWNREF "test_option_f.cpio.uu" #define ENVBASE "BSDCPIO" /* Prefix for environment variables. */ +#define PROGRAM "bsdcpio" /* Name of program being tested. */ +#undef LIBRARY /* Not testing a library. */ #undef EXTRA_DUMP /* How to dump extra data */ /* How to generate extra version info. */ #define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") -#define KNOWNREF "test_option_f.cpio.uu" -__FBSDID("$FreeBSD$"); /* - * "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. + * + * Windows support routines + * + * Note: Configuration is a tricky issue. Using HAVE_* feature macros + * in the test harness is dangerous because they cover up + * configuration errors. The classic example of this is omitting a + * configure check. If libarchive and libarchive_test both look for + * the same feature macro, such errors are hard to detect. Platform + * macros (e.g., _WIN32 or __GNUC__) are a little better, but can + * easily lead to very messy code. It's best to limit yourself + * to only the most generic programming techniques in the test harness + * and thus avoid conditionals altogether. Where that's not possible, + * try to minimize conditionals by grouping platform-specific tests in + * one place (e.g., test_acl_freebsd) or by adding new assert() + * functions (e.g., assertMakeHardlink()) to cover up platform + * differences. Platform-specific coding in libarchive_test is often + * a symptom that some capability is missing from libarchive itself. */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); -#include "list.h" +#if defined(_WIN32) && !defined(__CYGWIN__) +#include <io.h> +#include <windows.h> +#ifndef F_OK +#define F_OK (0) +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) ((m) & _S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(m) ((m) & _S_IFREG) +#endif +#if !defined(__BORLANDC__) +#define access _access +#define chdir _chdir +#endif +#ifndef fileno +#define fileno _fileno +#endif +/*#define fstat _fstat64*/ +#if !defined(__BORLANDC__) +#define getcwd _getcwd +#endif +#define lstat stat +/*#define lstat _stat64*/ +/*#define stat _stat64*/ +#define rmdir _rmdir +#if !defined(__BORLANDC__) +#define strdup _strdup +#define umask _umask +#endif +#define int64_t __int64 +#endif + +#if defined(HAVE__CrtSetReportMode) +# include <crtdbg.h> +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +void *GetFunctionKernel32(const char *name) +{ + static HINSTANCE lib; + static int set; + if (!set) { + set = 1; + lib = LoadLibrary("kernel32.dll"); + } + if (lib == NULL) { + fprintf(stderr, "Can't load kernel32.dll?!\n"); + exit(1); + } + return (void *)GetProcAddress(lib, name); +} + +static int +my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) +{ + static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD); + static int set; + if (!set) { + set = 1; + f = GetFunctionKernel32("CreateSymbolicLinkA"); + } + return f == NULL ? 0 : (*f)(linkname, target, flags); +} + +static int +my_CreateHardLinkA(const char *linkname, const char *target) +{ + static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); + static int set; + if (!set) { + set = 1; + f = GetFunctionKernel32("CreateHardLinkA"); + } + return f == NULL ? 0 : (*f)(linkname, target, NULL); +} + +int +my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) +{ + HANDLE h; + int r; + + memset(bhfi, 0, sizeof(*bhfi)); + h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return (0); + r = GetFileInformationByHandle(h, bhfi); + CloseHandle(h); + return (r); +} +#endif -/* Interix doesn't define these in a standard header. */ -#if __INTERIX__ -extern char *optarg; -extern int optind; +#if defined(HAVE__CrtSetReportMode) +static void +invalid_parameter_handler(const wchar_t * expression, + const wchar_t * function, const wchar_t * file, + unsigned int line, uintptr_t pReserved) +{ + /* nop */ +} #endif +/* + * + * OPTIONS FLAGS + * + */ + /* Enable core dump on failure. */ static int dump_on_failure = 0; -/* Default is to remove temp dirs for successful tests. */ +/* Default is to remove temp dirs and log data 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. */ +/* Default is to just report pass/fail for each test. */ +static int verbosity = 0; +#define VERBOSITY_SUMMARY_ONLY -1 /* -q */ +#define VERBOSITY_PASSFAIL 0 /* Default */ +#define VERBOSITY_LIGHT_REPORT 1 /* -v */ +#define VERBOSITY_FULL 2 /* -vv */ +/* A few places generate even more output for verbosity > VERBOSITY_FULL, + * mostly for debugging the test harness itself. */ +/* Cumulative count of assertion failures. */ static int failures = 0; -/* Cumulative count of skipped component tests. */ +/* Cumulative count of reported skips. */ static int skips = 0; -/* Cumulative count of assertions. */ +/* Cumulative count of assertions checked. */ static int assertions = 0; /* Directory where uuencoded reference files can be found. */ static const 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. + * Report log information selectively to console and/or disk log. */ -static int -previous_failures(const char *filename, int line) +static int log_console = 0; +static FILE *logfile; +static void +vlogprintf(const char *fmt, va_list ap) { - unsigned int i; - int count; +#ifdef va_copy + va_list lfap; + va_copy(lfap, ap); +#endif + if (log_console) + vfprintf(stdout, fmt, ap); + if (logfile != NULL) +#ifdef va_copy + vfprintf(logfile, fmt, lfap); + va_end(lfap); +#else + vfprintf(logfile, fmt, ap); +#endif +} - if (failed_filename == NULL || strcmp(failed_filename, filename) != 0) - memset(failed_lines, 0, sizeof(failed_lines)); - failed_filename = filename; +static void +logprintf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vlogprintf(fmt, ap); + va_end(ap); +} - 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); +/* Set up a message to display only if next assertion fails. */ +static char msgbuff[4096]; +static const char *msg, *nextmsg; +void +failure(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsprintf(msgbuff, fmt, ap); + va_end(ap); + nextmsg = msgbuff; } /* * Copy arguments into file-local variables. + * This was added to permit vararg assert() functions without needing + * variadic wrapper macros. Turns out that the vararg capability is almost + * never used, so almost all of the vararg assertions can be simplified + * by removing the vararg capability and reworking the wrapper macro to + * pass __FILE__, __LINE__ directly into the function instead of using + * this hook. I suspect this machinery is used so rarely that we + * would be better off just removing it entirely. That would simplify + * the code here noticably. */ static const char *test_filename; static int test_line; static void *test_extra; -void test_setup(const char *filename, int line) +void assertion_setup(const char *filename, int line) { test_filename = filename; test_line = line; } +/* Called at the beginning of each assert() function. */ +static void +assertion_count(const char *file, int line) +{ + (void)file; /* UNUSED */ + (void)line; /* UNUSED */ + ++assertions; + /* Proper handling of "failure()" message. */ + msg = nextmsg; + nextmsg = NULL; + /* Uncomment to print file:line after every assertion. + * Verbose, but occasionally useful in tracking down crashes. */ + /* printf("Checked %s:%d\n", file, line); */ +} + /* - * Inform user that we're skipping a test. + * For each test source file, we remember how many times each + * assertion was reported. Cleared before each new test, + * used by test_summarize(). */ -void -test_skipping(const char *fmt, ...) +static struct line { + int count; + int skip; +} failed_lines[10000]; + +/* Count this failure, setup up log destination and handle initial report. */ +static void +failure_start(const char *filename, int line, const char *fmt, ...) { va_list ap; - if (previous_failures(test_filename, test_line)) - return; + /* Record another failure for this line. */ + ++failures; + /* test_filename = filename; */ + failed_lines[line].count++; + /* Determine whether to log header to console. */ + switch (verbosity) { + case VERBOSITY_FULL: + log_console = 1; + break; + case VERBOSITY_LIGHT_REPORT: + log_console = (failed_lines[line].count < 2); + break; + default: + log_console = 0; + } + + /* Log file:line header for this failure */ va_start(ap, fmt); - fprintf(stderr, " *** SKIPPING: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); +#if _MSC_VER + logprintf("%s(%d): ", filename, line); +#else + logprintf("%s:%d: ", filename, line); +#endif + vlogprintf(fmt, ap); va_end(ap); - ++skips; + logprintf("\n"); + + if (msg != NULL && msg[0] != '\0') { + logprintf(" Description: %s\n", msg); + msg = NULL; + } + + /* Determine whether to log details to console. */ + if (verbosity == VERBOSITY_LIGHT_REPORT) + log_console = 0; } -/* Common handling of failed tests. */ +/* Complete reporting of failed tests. */ +/* + * The 'extra' hook here is used by libarchive to include libarchive + * error messages with assertion failures. It could also be used + * to add strerror() output, for example. Just define the EXTRA_DUMP() + * macro appropriately. + */ static void -report_failure(void *extra) +failure_finish(void *extra) { - if (msg[0] != '\0') { - fprintf(stderr, " Description: %s\n", msg); - msg[0] = '\0'; - } - + (void)extra; /* UNUSED (maybe) */ #ifdef EXTRA_DUMP if (extra != NULL) - fprintf(stderr, " detail: %s\n", EXTRA_DUMP(extra)); -#else - (void)extra; /* UNUSED */ + logprintf(" detail: %s\n", EXTRA_DUMP(extra)); #endif if (dump_on_failure) { @@ -191,203 +355,170 @@ report_failure(void *extra) } } -/* - * 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. */ +/* Inform user that we're skipping some checks. */ void -failure(const char *fmt, ...) +test_skipping(const char *fmt, ...) { + char buff[1024]; va_list ap; + va_start(ap, fmt); - vsprintf(msg, fmt, ap); + vsprintf(buff, fmt, ap); va_end(ap); + /* failure_start() isn't quite right, but is awfully convenient. */ + failure_start(test_filename, test_line, "SKIPPING: %s", buff); + --failures; /* Undo failures++ in failure_start() */ + /* Don't failure_finish() here. */ + /* Mark as skip, so doesn't count as failed test. */ + failed_lines[test_line].skip = 1; + ++skips; } +/* + * + * ASSERTIONS + * + */ + /* Generic assert() just displays the failed condition. */ int -test_assert(const char *file, int line, int value, const char *condition, void *extra) +assertion_assert(const char *file, int line, int value, + const char *condition, void *extra) { - ++assertions; - if (value) { - msg[0] = '\0'; - return (value); + assertion_count(file, line); + if (!value) { + failure_start(file, line, "Assertion failed: %s", condition); + failure_finish(extra); } - 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. */ +/* chdir() and report any errors */ int -test_assert_equal_int(const char *file, int line, - int v1, const char *e1, int v2, const char *e2, void *extra) +assertion_chdir(const char *file, int line, const char *pathname) { - ++assertions; - if (v1 == v2) { - msg[0] = '\0'; + assertion_count(file, line); + if (chdir(pathname) == 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); + failure_start(file, line, "chdir(\"%s\")", pathname); + failure_finish(NULL); return (0); + } -static void strdump(const char *p) +/* Verify two integers are equal. */ +int +assertion_equal_int(const char *file, int line, + long long v1, const char *e1, long long v2, const char *e2, void *extra) +{ + assertion_count(file, line); + if (v1 == v2) + return (1); + failure_start(file, line, "%s != %s", e1, e2); + logprintf(" %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1); + logprintf(" %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2); + failure_finish(extra); + return (0); +} + +static void strdump(const char *e, const char *p) { + const char *q = p; + + logprintf(" %s = ", e); if (p == NULL) { - fprintf(stderr, "(null)"); + logprintf("NULL"); return; } - fprintf(stderr, "\""); + logprintf("\""); 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; + case '\a': printf("\a"); break; + case '\b': printf("\b"); break; + case '\n': printf("\n"); break; + case '\r': printf("\r"); break; default: if (c >= 32 && c < 127) - fprintf(stderr, "%c", c); + logprintf("%c", c); else - fprintf(stderr, "\\x%02X", c); + logprintf("\\x%02X", c); } } - fprintf(stderr, "\""); + logprintf("\""); + logprintf(" (length %d)\n", q == NULL ? -1 : (int)strlen(q)); } -/* assertEqualString() displays the values of the two strings. */ +/* Verify two strings are equal, dump them if not. */ int -test_assert_equal_string(const char *file, int line, +assertion_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'; + assertion_count(file, line); + if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 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 : (int)strlen(v1)); - fprintf(stderr, " %s = ", e2); - strdump(v2); - fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : (int)strlen(v2)); - report_failure(extra); + failure_start(file, line, "%s != %s", e1, e2); + strdump(e1, v1); + strdump(e2, v2); + failure_finish(extra); return (0); } -static void wcsdump(const wchar_t *w) +static void +wcsdump(const char *e, const wchar_t *w) { + logprintf(" %s = ", e); if (w == NULL) { - fprintf(stderr, "(null)"); + logprintf("(null)"); return; } - fprintf(stderr, "\""); + logprintf("\""); while (*w != L'\0') { unsigned int c = *w++; if (c >= 32 && c < 127) - fprintf(stderr, "%c", c); + logprintf("%c", c); else if (c < 256) - fprintf(stderr, "\\x%02X", c); + logprintf("\\x%02X", c); else if (c < 0x10000) - fprintf(stderr, "\\u%04X", c); + logprintf("\\u%04X", c); else - fprintf(stderr, "\\U%08X", c); + logprintf("\\U%08X", c); } - fprintf(stderr, "\""); + logprintf("\"\n"); } -/* assertEqualWString() displays the values of the two strings. */ +#ifndef HAVE_WCSCMP +static int +wcscmp(const wchar_t *s1, const wchar_t *s2) +{ + + while (*s1 == *s2++) { + if (*s1++ == L'\0') + return 0; + } + if (*s1 > *--s2) + return 1; + else + return -1; +} +#endif + +/* Verify that two wide strings are equal, dump them if not. */ int -test_assert_equal_wstring(const char *file, int line, +assertion_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'; + assertion_count(file, line); + if (v1 == v2 || wcscmp(v1, v2) == 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); + failure_start(file, line, "%s != %s", e1, e2); + wcsdump(e1, v1); + wcsdump(e2, v2); + failure_finish(extra); return (0); } @@ -402,249 +533,294 @@ hexdump(const char *p, const char *ref, size_t l, size_t offset) size_t i, j; char sep; + if (p == NULL) { + logprintf("(null)\n"); + return; + } for(i=0; i < l; i+=16) { - fprintf(stderr, "%04x", (unsigned)(i + offset)); + logprintf("%04x", (unsigned)(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]); + logprintf("%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); + logprintf("%c ", sep); sep = ' '; } - fprintf(stderr, "%c", sep); + logprintf("%c", sep); for (j=0; j < 16 && i + j < l; j++) { int c = p[i + j]; if (c >= ' ' && c <= 126) - fprintf(stderr, "%c", c); + logprintf("%c", c); else - fprintf(stderr, "."); + logprintf("."); } - fprintf(stderr, "\n"); + logprintf("\n"); } } -/* assertEqualMem() displays the values of the two memory blocks. */ -/* TODO: For long blocks, hexdump the first bytes that actually differ. */ +/* Verify that two blocks of memory are the same, display the first + * block of differences if they're not. */ int -test_assert_equal_mem(const char *file, int line, - const char *v1, const char *e1, - const char *v2, const char *e2, +assertion_equal_mem(const char *file, int line, + const void *_v1, const char *e1, + const void *_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'; + const char *v1 = (const char *)_v1; + const char *v2 = (const char *)_v2; + size_t offset; + + assertion_count(file, line); + if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0)) return (1); + + failure_start(file, line, "%s != %s", e1, e2); + logprintf(" size %s = %d\n", ld, (int)l); + /* Dump 48 bytes (3 lines) so that the first difference is + * in the second line. */ + offset = 0; + while (l > 64 && memcmp(v1, v2, 32) == 0) { + /* Two lines agree, so step forward one line. */ + v1 += 16; + v2 += 16; + l -= 16; + offset += 16; } - 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); + logprintf(" Dump of %s\n", e1); + hexdump(v1, v2, l < 64 ? l : 64, offset); + logprintf(" Dump of %s\n", e2); + hexdump(v2, v1, l < 64 ? l : 64, offset); + logprintf("\n"); + failure_finish(extra); return (0); } +/* Verify that the named file exists and is empty. */ int -test_assert_empty_file(const char *f1fmt, ...) +assertion_empty_file(const char *f1fmt, ...) { char buff[1024]; char f1[1024]; struct stat st; va_list ap; ssize_t s; - int fd; - + FILE *f; + assertion_count(test_filename, test_line); 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); + failure_start(test_filename, test_line, "Stat failed: %s", f1); + failure_finish(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); + failure_start(test_filename, test_line, "File should be empty: %s", f1); + logprintf(" File size: %d\n", (int)st.st_size); + logprintf(" Contents:\n"); + f = fopen(f1, "rb"); + if (f == NULL) { + logprintf(" Unable to open %s\n", f1); } else { - s = sizeof(buff) < st.st_size ? sizeof(buff) : st.st_size; - s = read(fd, buff, s); + s = ((off_t)sizeof(buff) < st.st_size) ? + (ssize_t)sizeof(buff) : (ssize_t)st.st_size; + s = fread(buff, 1, s, f); hexdump(buff, NULL, s, 0); - close(fd); + fclose(f); } - report_failure(NULL); + failure_finish(NULL); return (0); } -/* assertEqualFile() asserts that two files have the same contents. */ +/* Verify that the named file exists and is not empty. */ +int +assertion_non_empty_file(const char *f1fmt, ...) +{ + char f1[1024]; + struct stat st; + va_list ap; + + assertion_count(test_filename, test_line); + va_start(ap, f1fmt); + vsprintf(f1, f1fmt, ap); + va_end(ap); + + if (stat(f1, &st) != 0) { + failure_start(test_filename, test_line, "Stat failed: %s", f1); + failure_finish(NULL); + return (0); + } + if (st.st_size == 0) { + failure_start(test_filename, test_line, "File empty: %s", f1); + failure_finish(NULL); + return (0); + } + return (1); +} + +/* Verify 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, ...) +assertion_equal_file(const char *fn1, const char *f2pattern, ...) { - char f2[1024]; + char fn2[1024]; va_list ap; char buff1[1024]; char buff2[1024]; - int fd1, fd2; + FILE *f1, *f2; int n1, n2; + assertion_count(test_filename, test_line); va_start(ap, f2pattern); - vsprintf(f2, f2pattern, ap); + vsprintf(fn2, f2pattern, ap); va_end(ap); - fd1 = open(f1, O_RDONLY); - fd2 = open(f2, O_RDONLY); + f1 = fopen(fn1, "rb"); + f2 = fopen(fn2, "rb"); for (;;) { - n1 = read(fd1, buff1, sizeof(buff1)); - n2 = read(fd2, buff2, sizeof(buff2)); + n1 = fread(buff1, 1, sizeof(buff1), f1); + n2 = fread(buff2, 1, sizeof(buff2), f2); if (n1 != n2) break; if (n1 == 0 && n2 == 0) { - close(fd1); - close(fd2); + fclose(f1); + fclose(f2); return (1); } if (memcmp(buff1, buff2, n1) != 0) break; } - close(fd1); - close(fd2); - 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); + fclose(f1); + fclose(f2); + failure_start(test_filename, test_line, "Files not identical"); + logprintf(" file1=\"%s\"\n", fn1); + logprintf(" file2=\"%s\"\n", fn2); + failure_finish(test_extra); return (0); } +/* Verify that the named file does exist. */ int -test_assert_file_exists(const char *fpattern, ...) +assertion_file_exists(const char *fpattern, ...) { char f[1024]; va_list ap; + assertion_count(test_filename, test_line); va_start(ap, fpattern); vsprintf(f, fpattern, ap); va_end(ap); +#if defined(_WIN32) && !defined(__CYGWIN__) + if (!_access(f, 0)) + return (1); +#else if (!access(f, F_OK)) return (1); - if (!previous_failures(test_filename, test_line)) { - fprintf(stderr, "%s:%d: File doesn't exist\n", - test_filename, test_line); - fprintf(stderr, " file=\"%s\"\n", f); - report_failure(test_extra); - } +#endif + failure_start(test_filename, test_line, "File should exist: %s", f); + failure_finish(test_extra); return (0); } +/* Verify that the named file doesn't exist. */ int -test_assert_file_not_exists(const char *fpattern, ...) +assertion_file_not_exists(const char *fpattern, ...) { char f[1024]; va_list ap; + assertion_count(test_filename, test_line); va_start(ap, fpattern); vsprintf(f, fpattern, ap); va_end(ap); +#if defined(_WIN32) && !defined(__CYGWIN__) + if (_access(f, 0)) + return (1); +#else if (access(f, F_OK)) return (1); - if (!previous_failures(test_filename, test_line)) { - fprintf(stderr, "%s:%d: File exists and shouldn't\n", - test_filename, test_line); - fprintf(stderr, " file=\"%s\"\n", f); - report_failure(test_extra); - } +#endif + failure_start(test_filename, test_line, "File should not exist: %s", f); + failure_finish(test_extra); return (0); } -/* assertFileContents() asserts the contents of a file. */ +/* Compare the contents of a file to a block of memory. */ int -test_assert_file_contents(const void *buff, int s, const char *fpattern, ...) +assertion_file_contents(const void *buff, int s, const char *fpattern, ...) { - char f[1024]; + char fn[1024]; va_list ap; char *contents; - int fd; + FILE *f; int n; + assertion_count(test_filename, test_line); va_start(ap, fpattern); - vsprintf(f, fpattern, ap); + vsprintf(fn, fpattern, ap); va_end(ap); - fd = open(f, O_RDONLY); - contents = malloc(s * 2 + 128); - n = read(fd, contents, s * 2 + 128); - close(fd); + f = fopen(fn, "rb"); + if (f == NULL) { + failure_start(test_filename, test_line, + "File should exist: %s", fn); + failure_finish(test_extra); + return (0); + } + contents = malloc(s * 2); + n = fread(contents, 1, s * 2, f); + fclose(f); 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); + failure_start(test_filename, test_line, "File contents don't match"); + logprintf(" file=\"%s\"\n", fn); + if (n > 0) + hexdump(contents, buff, n > 512 ? 512 : n, 0); + else { + logprintf(" File empty, contents should be:\n"); + hexdump(buff, NULL, s > 512 ? 512 : n, 0); } + failure_finish(test_extra); free(contents); return (0); } -/* assertTextFileContents() asserts the contents of a text file. */ +/* Check the contents of a text file, being tolerant of line endings. */ int -test_assert_text_file_contents(const char *buff, const char *f) +assertion_text_file_contents(const char *buff, const char *fn) { char *contents; const char *btxt, *ftxt; - int fd; + FILE *f; int n, s; - fd = open(f, O_RDONLY); + assertion_count(test_filename, test_line); + f = fopen(fn, "r"); + if (f == NULL) { + failure_start(test_filename, test_line, + "File doesn't exist: %s", fn); + failure_finish(test_extra); + return (0); + } s = strlen(buff); contents = malloc(s * 2 + 128); - n = read(fd, contents, s * 2 + 128 -1); + n = fread(contents, 1, s * 2 + 128 - 1, f); if (n >= 0) contents[n] = '\0'; - close(fd); + fclose(f); /* Compare texts. */ btxt = buff; ftxt = (const char *)contents; @@ -666,23 +842,647 @@ test_assert_text_file_contents(const char *buff, const char *f) 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); + failure_start(test_filename, test_line, "Contents don't match"); + logprintf(" file=\"%s\"\n", fn); + if (n > 0) + hexdump(contents, buff, n, 0); + else { + logprintf(" File empty, contents should be:\n"); + hexdump(buff, NULL, s, 0); } + failure_finish(test_extra); free(contents); return (0); } +/* Test that two paths point to the same file. */ +/* As a side-effect, asserts that both files exist. */ +static int +is_hardlink(const char *file, int line, + const char *path1, const char *path2) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; + int r; + + assertion_count(file, line); + r = my_GetFileInformationByName(path1, &bhfi1); + if (r == 0) { + failure_start(file, line, "File %s can't be inspected?", path1); + failure_finish(NULL); + return (0); + } + r = my_GetFileInformationByName(path2, &bhfi2); + if (r == 0) { + failure_start(file, line, "File %s can't be inspected?", path2); + failure_finish(NULL); + return (0); + } + return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber + && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh + && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow); +#else + struct stat st1, st2; + int r; + + assertion_count(file, line); + r = lstat(path1, &st1); + if (r != 0) { + failure_start(file, line, "File should exist: %s", path1); + failure_finish(NULL); + return (0); + } + r = lstat(path2, &st2); + if (r != 0) { + failure_start(file, line, "File should exist: %s", path2); + failure_finish(NULL); + return (0); + } + return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev); +#endif +} + +int +assertion_is_hardlink(const char *file, int line, + const char *path1, const char *path2) +{ + if (is_hardlink(file, line, path1, path2)) + return (1); + failure_start(file, line, + "Files %s and %s are not hardlinked", path1, path2); + failure_finish(NULL); + return (0); +} + +int +assertion_is_not_hardlink(const char *file, int line, + const char *path1, const char *path2) +{ + if (!is_hardlink(file, line, path1, path2)) + return (1); + failure_start(file, line, + "Files %s and %s should not be hardlinked", path1, path2); + failure_finish(NULL); + return (0); +} + +/* Verify a/b/mtime of 'pathname'. */ +/* If 'recent', verify that it's within last 10 seconds. */ +static int +assertion_file_time(const char *file, int line, + const char *pathname, long t, long nsec, char type, int recent) +{ + long long filet, filet_nsec; + int r; + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define EPOC_TIME (116444736000000000ULL) + FILETIME ftime, fbirthtime, fatime, fmtime; + ULARGE_INTEGER wintm; + HANDLE h; + ftime.dwLowDateTime = 0; + ftime.dwHighDateTime = 0; + + assertion_count(file, line); + h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + failure_start(file, line, "Can't access %s\n", pathname); + failure_finish(NULL); + return (0); + } + r = GetFileTime(h, &fbirthtime, &fatime, &fmtime); + switch (type) { + case 'a': ftime = fatime; break; + case 'b': ftime = fbirthtime; break; + case 'm': ftime = fmtime; break; + } + CloseHandle(h); + if (r == 0) { + failure_start(file, line, "Can't GetFileTime %s\n", pathname); + failure_finish(NULL); + return (0); + } + wintm.LowPart = ftime.dwLowDateTime; + wintm.HighPart = ftime.dwHighDateTime; + filet = (wintm.QuadPart - EPOC_TIME) / 10000000; + filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100; + nsec = (nsec / 100) * 100; /* Round the request */ +#else + struct stat st; + + assertion_count(file, line); + r = lstat(pathname, &st); + if (r != 0) { + failure_start(file, line, "Can't stat %s\n", pathname); + failure_finish(NULL); + return (0); + } + switch (type) { + case 'a': filet = st.st_atime; break; + case 'm': filet = st.st_mtime; break; + case 'b': filet = 0; break; + default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); + exit(1); + } +#if defined(__FreeBSD__) + switch (type) { + case 'a': filet_nsec = st.st_atimespec.tv_nsec; break; + case 'b': filet = st.st_birthtime; + filet_nsec = st.st_birthtimespec.tv_nsec; break; + case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break; + default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); + exit(1); + } + /* FreeBSD generally only stores to microsecond res, so round. */ + filet_nsec = (filet_nsec / 1000) * 1000; + nsec = (nsec / 1000) * 1000; +#else + filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */ + if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */ +#if defined(__HAIKU__) + if (type == 'a') return (1); /* Haiku doesn't have atime. */ +#endif +#endif +#endif + if (recent) { + /* Check that requested time is up-to-date. */ + time_t now = time(NULL); + if (filet < now - 10 || filet > now + 1) { + failure_start(file, line, + "File %s has %ctime %ld, %ld seconds ago\n", + pathname, type, filet, now - filet); + failure_finish(NULL); + return (0); + } + } else if (filet != t || filet_nsec != nsec) { + failure_start(file, line, + "File %s has %ctime %ld.%09ld, expected %ld.%09ld", + pathname, type, filet, filet_nsec, t, nsec); + failure_finish(NULL); + return (0); + } + return (1); +} + +/* Verify atime of 'pathname'. */ +int +assertion_file_atime(const char *file, int line, + const char *pathname, long t, long nsec) +{ + return assertion_file_time(file, line, pathname, t, nsec, 'a', 0); +} + +/* Verify atime of 'pathname' is up-to-date. */ +int +assertion_file_atime_recent(const char *file, int line, const char *pathname) +{ + return assertion_file_time(file, line, pathname, 0, 0, 'a', 1); +} + +/* Verify birthtime of 'pathname'. */ +int +assertion_file_birthtime(const char *file, int line, + const char *pathname, long t, long nsec) +{ + return assertion_file_time(file, line, pathname, t, nsec, 'b', 0); +} + +/* Verify birthtime of 'pathname' is up-to-date. */ +int +assertion_file_birthtime_recent(const char *file, int line, + const char *pathname) +{ + return assertion_file_time(file, line, pathname, 0, 0, 'b', 1); +} + +/* Verify mtime of 'pathname'. */ +int +assertion_file_mtime(const char *file, int line, + const char *pathname, long t, long nsec) +{ + return assertion_file_time(file, line, pathname, t, nsec, 'm', 0); +} + +/* Verify mtime of 'pathname' is up-to-date. */ +int +assertion_file_mtime_recent(const char *file, int line, const char *pathname) +{ + return assertion_file_time(file, line, pathname, 0, 0, 'm', 1); +} + +/* Verify number of links to 'pathname'. */ +int +assertion_file_nlinks(const char *file, int line, + const char *pathname, int nlinks) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + BY_HANDLE_FILE_INFORMATION bhfi; + int r; + + assertion_count(file, line); + r = my_GetFileInformationByName(pathname, &bhfi); + if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks) + return (1); + failure_start(file, line, "File %s has %d links, expected %d", + pathname, bhfi.nNumberOfLinks, nlinks); + failure_finish(NULL); + return (0); +#else + struct stat st; + int r; + + assertion_count(file, line); + r = lstat(pathname, &st); + if (r == 0 && st.st_nlink == nlinks) + return (1); + failure_start(file, line, "File %s has %d links, expected %d", + pathname, st.st_nlink, nlinks); + failure_finish(NULL); + return (0); +#endif +} + +/* Verify size of 'pathname'. */ +int +assertion_file_size(const char *file, int line, const char *pathname, long size) +{ + int64_t filesize; + int r; + + assertion_count(file, line); +#if defined(_WIN32) && !defined(__CYGWIN__) + { + BY_HANDLE_FILE_INFORMATION bhfi; + r = !my_GetFileInformationByName(pathname, &bhfi); + filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow; + } +#else + { + struct stat st; + r = lstat(pathname, &st); + filesize = st.st_size; + } +#endif + if (r == 0 && filesize == size) + return (1); + failure_start(file, line, "File %s has size %ld, expected %ld", + pathname, (long)filesize, (long)size); + failure_finish(NULL); + return (0); +} + +/* Assert that 'pathname' is a dir. If mode >= 0, verify that too. */ +int +assertion_is_dir(const char *file, int line, const char *pathname, int mode) +{ + struct stat st; + int r; + +#if defined(_WIN32) && !defined(__CYGWIN__) + (void)mode; /* UNUSED */ +#endif + assertion_count(file, line); + r = lstat(pathname, &st); + if (r != 0) { + failure_start(file, line, "Dir should exist: %s", pathname); + failure_finish(NULL); + return (0); + } + if (!S_ISDIR(st.st_mode)) { + failure_start(file, line, "%s is not a dir", pathname); + failure_finish(NULL); + return (0); + } +#if !defined(_WIN32) || defined(__CYGWIN__) + /* Windows doesn't handle permissions the same way as POSIX, + * so just ignore the mode tests. */ + /* TODO: Can we do better here? */ + if (mode >= 0 && mode != (st.st_mode & 07777)) { + failure_start(file, line, "Dir %s has wrong mode", pathname); + logprintf(" Expected: 0%3o\n", mode); + logprintf(" Found: 0%3o\n", st.st_mode & 07777); + failure_finish(NULL); + return (0); + } +#endif + return (1); +} + +/* Verify that 'pathname' is a regular file. If 'mode' is >= 0, + * verify that too. */ +int +assertion_is_reg(const char *file, int line, const char *pathname, int mode) +{ + struct stat st; + int r; + +#if defined(_WIN32) && !defined(__CYGWIN__) + (void)mode; /* UNUSED */ +#endif + assertion_count(file, line); + r = lstat(pathname, &st); + if (r != 0 || !S_ISREG(st.st_mode)) { + failure_start(file, line, "File should exist: %s", pathname); + failure_finish(NULL); + return (0); + } +#if !defined(_WIN32) || defined(__CYGWIN__) + /* Windows doesn't handle permissions the same way as POSIX, + * so just ignore the mode tests. */ + /* TODO: Can we do better here? */ + if (mode >= 0 && mode != (st.st_mode & 07777)) { + failure_start(file, line, "File %s has wrong mode", pathname); + logprintf(" Expected: 0%3o\n", mode); + logprintf(" Found: 0%3o\n", st.st_mode & 07777); + failure_finish(NULL); + return (0); + } +#endif + return (1); +} + +/* Check whether 'pathname' is a symbolic link. If 'contents' is + * non-NULL, verify that the symlink has those contents. */ +static int +is_symlink(const char *file, int line, + const char *pathname, const char *contents) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + (void)pathname; /* UNUSED */ + (void)contents; /* UNUSED */ + assertion_count(file, line); + /* Windows sort-of has real symlinks, but they're only usable + * by privileged users and are crippled even then, so there's + * really not much point in bothering with this. */ + return (0); +#else + char buff[300]; + struct stat st; + ssize_t linklen; + int r; + + assertion_count(file, line); + r = lstat(pathname, &st); + if (r != 0) { + failure_start(file, line, + "Symlink should exist: %s", pathname); + failure_finish(NULL); + return (0); + } + if (!S_ISLNK(st.st_mode)) + return (0); + if (contents == NULL) + return (1); + linklen = readlink(pathname, buff, sizeof(buff)); + if (linklen < 0) { + failure_start(file, line, "Can't read symlink %s", pathname); + failure_finish(NULL); + return (0); + } + buff[linklen] = '\0'; + if (strcmp(buff, contents) != 0) + return (0); + return (1); +#endif +} + +/* Assert that path is a symlink that (optionally) contains contents. */ +int +assertion_is_symlink(const char *file, int line, + const char *path, const char *contents) +{ + if (is_symlink(file, line, path, contents)) + return (1); + if (contents) + failure_start(file, line, "File %s is not a symlink to %s", + path, contents); + else + failure_start(file, line, "File %s is not a symlink", path); + failure_finish(NULL); + return (0); +} + + +/* Create a directory and report any errors. */ +int +assertion_make_dir(const char *file, int line, const char *dirname, int mode) +{ + assertion_count(file, line); +#if defined(_WIN32) && !defined(__CYGWIN__) + (void)mode; /* UNUSED */ + if (0 == _mkdir(dirname)) + return (1); +#else + if (0 == mkdir(dirname, mode)) + return (1); +#endif + failure_start(file, line, "Could not create directory %s", dirname); + failure_finish(NULL); + return(0); +} + +/* Create a file with the specified contents and report any failures. */ +int +assertion_make_file(const char *file, int line, + const char *path, int mode, const char *contents) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* TODO: Rework this to set file mode as well. */ + FILE *f; + (void)mode; /* UNUSED */ + assertion_count(file, line); + f = fopen(path, "wb"); + if (f == NULL) { + failure_start(file, line, "Could not create file %s", path); + failure_finish(NULL); + return (0); + } + if (contents != NULL) { + if (strlen(contents) + != fwrite(contents, 1, strlen(contents), f)) { + fclose(f); + failure_start(file, line, + "Could not write file %s", path); + failure_finish(NULL); + return (0); + } + } + fclose(f); + return (1); +#else + int fd; + assertion_count(file, line); + fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644); + if (fd < 0) { + failure_start(file, line, "Could not create %s", path); + failure_finish(NULL); + return (0); + } + if (contents != NULL) { + if ((ssize_t)strlen(contents) + != write(fd, contents, strlen(contents))) { + close(fd); + failure_start(file, line, "Could not write to %s", path); + failure_finish(NULL); + return (0); + } + } + close(fd); + return (1); +#endif +} + +/* Create a hardlink and report any failures. */ +int +assertion_make_hardlink(const char *file, int line, + const char *newpath, const char *linkto) +{ + int succeeded; + + assertion_count(file, line); +#if defined(_WIN32) && !defined(__CYGWIN__) + succeeded = my_CreateHardLinkA(newpath, linkto); +#elif HAVE_LINK + succeeded = !link(linkto, newpath); +#else + succeeded = 0; +#endif + if (succeeded) + return (1); + failure_start(file, line, "Could not create hardlink"); + logprintf(" New link: %s\n", newpath); + logprintf(" Old name: %s\n", linkto); + failure_finish(NULL); + return(0); +} + +/* Create a symlink and report any failures. */ +int +assertion_make_symlink(const char *file, int line, + const char *newpath, const char *linkto) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + int targetIsDir = 0; /* TODO: Fix this */ + assertion_count(file, line); + if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir)) + return (1); +#elif HAVE_SYMLINK + assertion_count(file, line); + if (0 == symlink(linkto, newpath)) + return (1); +#endif + failure_start(file, line, "Could not create symlink"); + logprintf(" New link: %s\n", newpath); + logprintf(" Old name: %s\n", linkto); + failure_finish(NULL); + return(0); +} + +/* Set umask, report failures. */ +int +assertion_umask(const char *file, int line, int mask) +{ + assertion_count(file, line); + (void)file; /* UNUSED */ + (void)line; /* UNUSED */ + umask(mask); + return (1); +} + +/* + * + * UTILITIES for use by tests. + * + */ + +/* + * Check whether platform supports symlinks. This is intended + * for tests to use in deciding whether to bother testing symlink + * support; if the platform doesn't support symlinks, there's no point + * in checking whether the program being tested can create them. + * + * Note that the first time this test is called, we actually go out to + * disk to create and verify a symlink. This is necessary because + * symlink support is actually a property of a particular filesystem + * and can thus vary between directories on a single system. After + * the first call, this returns the cached result from memory, so it's + * safe to call it as often as you wish. + */ +int +canSymlink(void) +{ + /* Remember the test result */ + static int value = 0, tested = 0; + if (tested) + return (value); + + ++tested; + assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a"); + /* Note: Cygwin has its own symlink() emulation that does not + * use the Win32 CreateSymbolicLink() function. */ +#if defined(_WIN32) && !defined(__CYGWIN__) + value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0) + && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0"); +#elif HAVE_SYMLINK + value = (0 == symlink("canSymlink.0", "canSymlink.1")) + && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0"); +#endif + return (value); +} + +/* + * Can this platform run the gzip program? + */ +/* Platform-dependent options for hiding the output of a subcommand. */ +#if defined(_WIN32) && !defined(__CYGWIN__) +static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */ +#else +static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */ +#endif +int +canGzip(void) +{ + static int tested = 0, value = 0; + if (!tested) { + tested = 1; + if (systemf("gzip -V %s", redirectArgs) == 0) + value = 1; + } + return (value); +} + +/* + * Can this platform run the gunzip program? + */ +int +canGunzip(void) +{ + static int tested = 0, value = 0; + if (!tested) { + tested = 1; + if (systemf("gunzip -V %s", redirectArgs) == 0) + value = 1; + } + return (value); +} + +/* + * Sleep as needed; useful for verifying disk timestamp changes by + * ensuring that the wall-clock time has actually changed before we + * go back to re-read something from disk. + */ +void +sleepUntilAfter(time_t t) +{ + while (t >= time(NULL)) +#if defined(_WIN32) && !defined(__CYGWIN__) + Sleep(500); +#else + sleep(1); +#endif +} + /* * Call standard system() call, but build up the command line using * sprintf() conventions. @@ -696,6 +1496,8 @@ systemf(const char *fmt, ...) va_start(ap, fmt); vsprintf(buff, fmt, ap); + if (verbosity > VERBOSITY_FULL) + logprintf("Cmd: %s\n", buff); r = system(buff); va_end(ap); return (r); @@ -714,143 +1516,48 @@ slurpfile(size_t * sizep, const char *fmt, ...) va_list ap; char *p; ssize_t bytes_read; - int fd; + FILE *f; int r; va_start(ap, fmt); vsprintf(filename, fmt, ap); va_end(ap); - fd = open(filename, O_RDONLY); - if (fd < 0) { + f = fopen(filename, "rb"); + if (f == NULL) { /* Note: No error; non-existent file is okay here. */ return (NULL); } - r = fstat(fd, &st); + r = fstat(fileno(f), &st); if (r != 0) { - fprintf(stderr, "Can't stat file %s\n", filename); - close(fd); + logprintf("Can't stat file %s\n", filename); + fclose(f); return (NULL); } - p = malloc(st.st_size + 1); + p = malloc((size_t)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); + logprintf("Can't allocate %ld bytes of memory to read file %s\n", + (long int)st.st_size, filename); + fclose(f); return (NULL); } - bytes_read = read(fd, p, st.st_size); + bytes_read = fread(p, 1, (size_t)st.st_size, f); if (bytes_read < st.st_size) { - fprintf(stderr, "Can't read file %s\n", filename); - close(fd); + logprintf("Can't read file %s\n", filename); + fclose(f); free(p); return (NULL); } p[st.st_size] = '\0'; if (sizep != NULL) *sizep = (size_t)st.st_size; - close(fd); + fclose(f); 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); - fflush(stdout); - } - - /* - * 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) { -#if defined(_WIN32) && !defined(__CYGWIN__) - systemf("rmdir /S /Q %s", tests[i].name); -#else - systemf("rm -rf %s", tests[i].name); -#endif - } - } - /* 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); -} - +/* Read a uuencoded file from the reference directory, decode, and + * write the result into the current directory. */ #define UUDECODE(c) (((c) - 0x20) & 0x3f) - void extract_reference_file(const char *name) { @@ -874,7 +1581,7 @@ extract_reference_file(const char *name) } /* Now, decode the rest and write it. */ /* Not a lot of error checking here; the input better be right. */ - out = fopen(name, "w"); + out = fopen(name, "wb"); while (fgets(buff, sizeof(buff), in) != NULL) { char *p = buff; int bytes; @@ -908,19 +1615,211 @@ extract_reference_file(const char *name) fclose(in); } +/* + * + * TEST management + * + */ + +/* + * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has + * a line like + * DEFINE_TEST(test_function) + * for each test. + */ + +/* Use "list.h" to declare all of the test functions. */ +#undef DEFINE_TEST +#define DEFINE_TEST(name) void name(void); +#include "list.h" + +/* Use "list.h" to create a list of all tests (functions and names). */ +#undef DEFINE_TEST +#define DEFINE_TEST(n) { n, #n, 0 }, +struct { void (*func)(void); const char *name; int failures; } tests[] = { + #include "list.h" +}; + +/* + * Summarize repeated failures in the just-completed test. + */ +static void +test_summarize(const char *filename, int failed) +{ + unsigned int i; + + switch (verbosity) { + case VERBOSITY_SUMMARY_ONLY: + printf(failed ? "E" : "."); + fflush(stdout); + break; + case VERBOSITY_PASSFAIL: + printf(failed ? "FAIL\n" : "ok\n"); + break; + } + + log_console = (verbosity == VERBOSITY_LIGHT_REPORT); + + for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { + if (failed_lines[i].count > 1 && !failed_lines[i].skip) + logprintf("%s:%d: Summary: Failed %d times\n", + filename, i, failed_lines[i].count); + } + /* Clear the failure history for the next file. */ + memset(failed_lines, 0, sizeof(failed_lines)); +} + +/* + * Actually run a single test, with appropriate setup and cleanup. + */ +static int +test_run(int i, const char *tmpdir) +{ + char logfilename[64]; + int failures_before = failures; + int oldumask; + + switch (verbosity) { + case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */ + break; + case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */ + printf("%3d: %-50s", i, tests[i].name); + fflush(stdout); + break; + default: /* Title of test, details will follow */ + printf("%3d: %s\n", i, tests[i].name); + } + + /* Chdir to the top-level work directory. */ + if (!assertChdir(tmpdir)) { + fprintf(stderr, + "ERROR: Can't chdir to top work dir %s\n", tmpdir); + exit(1); + } + /* Create a log file for this test. */ + sprintf(logfilename, "%s.log", tests[i].name); + logfile = fopen(logfilename, "w"); + fprintf(logfile, "%s\n\n", tests[i].name); + /* Chdir() to a work dir for this specific test. */ + if (!assertMakeDir(tests[i].name, 0755) + || !assertChdir(tests[i].name)) { + fprintf(stderr, + "ERROR: Can't chdir to work dir %s/%s\n", + tmpdir, tests[i].name); + exit(1); + } + /* Explicitly reset the locale before each test. */ + setlocale(LC_ALL, "C"); + /* Record the umask before we run the test. */ + umask(oldumask = umask(0)); + /* + * Run the actual test. + */ + (*tests[i].func)(); + /* + * Clean up and report afterwards. + */ + /* Restore umask */ + umask(oldumask); + /* Reset locale. */ + setlocale(LC_ALL, "C"); + /* Reset directory. */ + if (!assertChdir(tmpdir)) { + fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n", + tmpdir); + exit(1); + } + /* Report per-test summaries. */ + tests[i].failures = failures - failures_before; + test_summarize(test_filename, tests[i].failures); + /* Close the per-test log file. */ + fclose(logfile); + logfile = NULL; + /* If there were no failures, we can remove the work dir and logfile. */ + if (tests[i].failures == 0) { + if (!keep_temp_files && assertChdir(tmpdir)) { +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure not to leave empty directories. + * Sometimes a processing of closing files used by tests + * is not done, then rmdir will be failed and it will + * leave a empty test directory. So we should wait a few + * seconds and retry rmdir. */ + int r, t; + for (t = 0; t < 10; t++) { + if (t > 0) + Sleep(1000); + r = systemf("rmdir /S /Q %s", tests[i].name); + if (r == 0) + break; + } + systemf("del %s", logfilename); +#else + systemf("rm -rf %s", tests[i].name); + systemf("rm %s", logfilename); +#endif + } + } + /* Return appropriate status. */ + return (tests[i].failures); +} + +/* + * + * + * MAIN and support routines. + * + * + */ + +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); +} static char * -get_refdir(void) +get_refdir(const char *d) { char tried[512] = { '\0' }; char buff[128]; char *pwd, *p; + /* If a dir was specified, try that */ + if (d != NULL) { + pwd = NULL; + snprintf(buff, sizeof(buff), "%s", d); + p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); + if (p != NULL) goto success; + strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); + strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); + goto failure; + } + /* Get the current dir. */ pwd = getcwd(NULL, 0); while (pwd[strlen(pwd) - 1] == '\n') pwd[strlen(pwd) - 1] = '\0'; - printf("PWD: %s\n", pwd); /* Look for a known file. */ snprintf(buff, sizeof(buff), "%s", pwd); @@ -935,7 +1834,11 @@ get_refdir(void) strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); +#if defined(LIBRARY) + snprintf(buff, sizeof(buff), "%s/%s/test", pwd, LIBRARY); +#else snprintf(buff, sizeof(buff), "%s/%s/test", pwd, PROGRAM); +#endif p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); if (p != NULL) goto success; strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); @@ -955,11 +1858,12 @@ get_refdir(void) strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); } +failure: + printf("Unable to locate known reference file %s\n", KNOWNREF); + printf(" Checked following directories:\n%s\n", tried); #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) DebugBreak(); #endif - printf("Unable to locate known reference file %s\n", KNOWNREF); - printf(" Checked following directories:\n%s\n", tried); exit(1); success: @@ -968,27 +1872,27 @@ success: return strdup(buff); } -int main(int argc, char **argv) +int +main(int argc, char **argv) { static const int limit = sizeof(tests) / sizeof(tests[0]); - int i, tests_run = 0, tests_failed = 0, opt; + int i, tests_run = 0, tests_failed = 0, option; time_t now; char *refdir_alloc = NULL; -#if defined(_WIN32) && !defined(__CYGWIN__) - char *testprg; -#endif - const char *opt_arg, *progname, *p; + const char *progname; + const char *tmp, *option_arg, *p; char tmpdir[256]; char tmpdir_timestamp[256]; (void)argc; /* UNUSED */ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure open() function will be used with a binary mode. */ - /* on cygwin, we need something similar, but instead link against */ - /* a special startup object, binmode.o */ - _set_fmode(_O_BINARY); +#if defined(HAVE__CrtSetReportMode) + /* To stop to run the default invalid parameter handler. */ + _set_invalid_parameter_handler(invalid_parameter_handler); + /* Disable annoying assertion message box. */ + _CrtSetReportMode(_CRT_ASSERT, 0); #endif + /* * Name of this program, used to build root of our temp directory * tree. @@ -1003,9 +1907,20 @@ int main(int argc, char **argv) #ifdef PROGRAM /* Get the target program from environment, if available. */ - testprog = getenv(ENVBASE); + testprogfile = getenv(ENVBASE); #endif + if (getenv("TMPDIR") != NULL) + tmp = getenv("TMPDIR"); + else if (getenv("TMP") != NULL) + tmp = getenv("TMP"); + else if (getenv("TEMP") != NULL) + tmp = getenv("TEMP"); + else if (getenv("TEMPDIR") != NULL) + tmp = getenv("TEMPDIR"); + else + tmp = "/tmp"; + /* Allow -d to be controlled through the environment. */ if (getenv(ENVBASE "_DEBUG") != NULL) dump_on_failure = 1; @@ -1024,23 +1939,24 @@ int main(int argc, char **argv) p = *argv++; ++p; /* Skip '-' */ while (*p != '\0') { - opt = *p++; - opt_arg = NULL; + option = *p++; + option_arg = NULL; /* If 'opt' takes an argument, parse that. */ - if (opt == 'p' || opt == 'r') { + if (option == 'p' || option == 'r') { if (*p != '\0') - opt_arg = p; + option_arg = p; else if (*argv == NULL) { fprintf(stderr, "Option -%c requires argument.\n", - opt); + option); usage(progname); } else - opt_arg = *argv++; + option_arg = *argv++; p = ""; /* End of this option word. */ } - switch (opt) { + /* Now, handle the option. */ + switch (option) { case 'd': dump_on_failure = 1; break; @@ -1049,21 +1965,20 @@ int main(int argc, char **argv) break; case 'p': #ifdef PROGRAM - testprog = opt_arg; + testprogfile = option_arg; #else usage(progname); #endif break; case 'q': - quiet_flag++; + verbosity--; break; case 'r': - refdir = opt_arg; + refdir = option_arg; break; case 'v': - verbose = 1; + verbosity++; break; - case '?': default: usage(progname); } @@ -1074,20 +1989,26 @@ int main(int argc, char **argv) * Sanity-check that our options make sense. */ #ifdef PROGRAM - if (testprog == NULL) + if (testprogfile == NULL) usage(progname); -#endif + { + char *testprg; #if defined(_WIN32) && !defined(__CYGWIN__) - /* - * Command.exe cannot accept the command used '/' with drive - * name such as c:/xxx/command.exe when use '|' pipe handling. - */ - testprg = strdup(testprog); - for (i = 0; testprg[i] != '\0'; i++) { - if (testprg[i] == '/') - testprg[i] = '\\'; + /* Command.com sometimes rejects '/' separators. */ + testprg = strdup(testprogfile); + for (i = 0; testprg[i] != '\0'; i++) { + if (testprg[i] == '/') + testprg[i] = '\\'; + } + testprogfile = testprg; +#endif + /* Quote the name that gets put into shell command lines. */ + testprg = malloc(strlen(testprogfile) + 3); + strcpy(testprg, "\""); + strcat(testprg, testprogfile); + strcat(testprg, "\""); + testprog = testprg; } - testprog = testprg; #endif /* @@ -1096,32 +2017,37 @@ int main(int argc, char **argv) * to make it easier to track the results of multiple tests. */ now = time(NULL); - for (i = 0; i < 1000; i++) { + for (i = 0; ; 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) + sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname, + tmpdir_timestamp, i); + if (assertMakeDir(tmpdir,0755)) break; - if (errno == EEXIST) - continue; - fprintf(stderr, "ERROR: Unable to create temp directory %s\n", - tmpdir); - exit(1); + if (i >= 999) { + 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. + * reference files, try to find the reference files in + * the "usual places." */ - if (refdir == NULL) - refdir = refdir_alloc = get_refdir(); + refdir = refdir_alloc = get_refdir(refdir); /* * Banner with basic information. */ - if (!quiet_flag) { - printf("Running tests in: %s\n", tmpdir); + printf("\n"); + printf("If tests fail or crash, details will be in:\n"); + printf(" %s\n", tmpdir); + printf("\n"); + if (verbosity > VERBOSITY_SUMMARY_ONLY) { printf("Reference files will be read from: %s\n", refdir); #ifdef PROGRAM printf("Running tests on: %s\n", testprog); @@ -1129,6 +2055,9 @@ int main(int argc, char **argv) printf("Exercising: "); fflush(stdout); printf("%s\n", EXTRA_VERSION); + } else { + printf("Running "); + fflush(stdout); } /* @@ -1143,15 +2072,30 @@ int main(int argc, char **argv) } } else { while (*(argv) != NULL) { - i = atoi(*argv); - if (**argv < '0' || **argv > '9' || i < 0 || i >= limit) { - printf("*** INVALID Test %s\n", *argv); - usage(progname); + if (**argv >= '0' && **argv <= '9') { + i = atoi(*argv); + if (i < 0 || i >= limit) { + printf("*** INVALID Test %s\n", *argv); + free(refdir_alloc); + usage(progname); + /* usage() never returns */ + } } else { - if (test_run(i, tmpdir)) - tests_failed++; - tests_run++; + for (i = 0; i < limit; ++i) { + if (strcmp(*argv, tests[i].name) == 0) + break; + } + if (i >= limit) { + printf("*** INVALID Test ``%s''\n", + *argv); + free(refdir_alloc); + usage(progname); + /* usage() never returns */ + } } + if (test_run(i, tmpdir)) + tests_failed++; + tests_run++; argv++; } } @@ -1159,20 +2103,38 @@ int main(int argc, char **argv) /* * Report summary statistics. */ - if (!quiet_flag) { + if (verbosity > VERBOSITY_SUMMARY_ONLY) { 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); + printf("Totals:\n"); + printf(" Tests run: %8d\n", tests_run); + printf(" Tests failed: %8d\n", tests_failed); + printf(" Assertions checked:%8d\n", assertions); + printf(" Assertions failed: %8d\n", failures); + printf(" Skips reported: %8d\n", skips); + } + if (failures) { + printf("\n"); + printf("Failing tests:\n"); + for (i = 0; i < limit; ++i) { + if (tests[i].failures) + printf(" %d: %s (%d failures)\n", i, + tests[i].name, tests[i].failures); + } + printf("\n"); + printf("Details for failing tests: %s\n", tmpdir); + printf("\n"); + } else { + if (verbosity == VERBOSITY_SUMMARY_ONLY) + printf("\n"); + printf("%d tests passed, no failures\n", tests_run); } free(refdir_alloc); /* If the final tmpdir is empty, we can remove it. */ /* This should be the usual case when all tests succeed. */ + assertChdir(".."); rmdir(tmpdir); - return (tests_failed); + return (tests_failed ? 1 : 0); } diff --git a/usr.bin/cpio/test/test.h b/usr.bin/cpio/test/test.h index be28dd4..8b1352a 100644 --- a/usr.bin/cpio/test/test.h +++ b/usr.bin/cpio/test/test.h @@ -45,47 +45,84 @@ #error Oops: No config.h and no pre-built configuration in test.h. #endif -#if !defined(_WIN32) || defined(__CYGWIN__) +#include <sys/types.h> /* Windows requires this before sys/stat.h */ +#include <sys/stat.h> + +#ifdef USE_DMALLOC +#include <dmalloc.h> +#endif +#if HAVE_DIRENT_H #include <dirent.h> -#else -#include "../cpio_windows.h" #endif -#if defined(__CYGWIN__) -/* In cygwin-1.7.x, the .nlinks field of directories is - * deliberately inaccurate, because to populate it requires - * stat'ing every file in the directory, which is slow. - * So, as an optimization cygwin doesn't do that in newer - * releases; all correct applications on any platform should - * never rely on it being > 1, so this optimization doesn't - * impact the operation of correctly coded applications. - * Therefore, the cpio test should not check its accuracy - */ -# define NLINKS_INACCURATE_FOR_DIRS +#ifdef HAVE_DIRECT_H +#include <direct.h> +#define dirent direct #endif #include <errno.h> #include <fcntl.h> +#ifdef HAVE_IO_H +#include <io.h> +#endif #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/stat.h> -#if !defined(_WIN32) || defined(__CYGWIN__) +#include <time.h> +#ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#include <time.h> #include <wchar.h> - -#ifdef USE_DMALLOC -#include <dmalloc.h> +#ifdef HAVE_WINDOWS_H +#include <windows.h> #endif -/* No non-FreeBSD platform will have __FBSDID, so just define it here. */ -#ifdef __FreeBSD__ -#include <sys/cdefs.h> /* For __FBSDID */ +/* + * System-specific tweaks. We really want to minimize these + * as much as possible, since they make it harder to understand + * the mainline code. + */ + +/* Windows (including Visual Studio and MinGW but not Cygwin) */ +#if defined(_WIN32) && !defined(__CYGWIN__) +#include "../cpio_windows.h" +#if !defined(__BORLANDC__) +#define strdup _strdup +#endif +#define LOCALE_DE "deu" #else -#undef __FBSDID +#define LOCALE_DE "de_DE.UTF-8" +#endif + +/* Visual Studio */ +#ifdef _MSC_VER +#define snprintf sprintf_s +#endif + +/* Cygwin */ +#if defined(__CYGWIN__) +/* Cygwin-1.7.x is lazy about populating nlinks, so don't + * expect it to be accurate. */ +# define NLINKS_INACCURATE_FOR_DIRS +#endif + +#if defined(__HAIKU__) || defined(__QNXNTO__) +/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */ +#include <stdint.h> +#endif + +/* Get a real definition for __FBSDID if we can */ +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +/* If not, define it so as to avoid dangling semicolons. */ +#ifndef __FBSDID #define __FBSDID(a) struct _undefined_hack #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + /* * Redefine DEFINE_TEST for use in defining the test functions. */ @@ -93,40 +130,81 @@ #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) - +#define assert(e) assertion_assert(__FILE__, __LINE__, (e), #e, NULL) +/* chdir() and error if it fails */ +#define assertChdir(path) \ + assertion_chdir(__FILE__, __LINE__, path) /* 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) - +#define assertEqualInt(v1,v2) \ + assertion_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) + assertion_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) + assertion_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) + assertion_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 + assertion_setup(__FILE__, __LINE__);assertion_equal_file /* Assert that a file is empty; supports printf-style arguments. */ #define assertEmptyFile \ - test_setup(__FILE__, __LINE__);test_assert_empty_file + assertion_setup(__FILE__, __LINE__);assertion_empty_file +/* Assert that a file is not empty; supports printf-style arguments. */ +#define assertNonEmptyFile \ + assertion_setup(__FILE__, __LINE__);assertion_non_empty_file +#define assertFileAtime(pathname, sec, nsec) \ + assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec) +#define assertFileAtimeRecent(pathname) \ + assertion_file_atime_recent(__FILE__, __LINE__, pathname) +#define assertFileBirthtime(pathname, sec, nsec) \ + assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec) +#define assertFileBirthtimeRecent(pathname) \ + assertion_file_birthtime_recent(__FILE__, __LINE__, pathname) /* Assert that a file exists; supports printf-style arguments. */ #define assertFileExists \ - test_setup(__FILE__, __LINE__);test_assert_file_exists + assertion_setup(__FILE__, __LINE__);assertion_file_exists /* Assert that a file exists; supports printf-style arguments. */ #define assertFileNotExists \ - test_setup(__FILE__, __LINE__);test_assert_file_not_exists + assertion_setup(__FILE__, __LINE__);assertion_file_not_exists /* Assert that file contents match a string; supports printf-style arguments. */ #define assertFileContents \ - test_setup(__FILE__, __LINE__);test_assert_file_contents + assertion_setup(__FILE__, __LINE__);assertion_file_contents +#define assertFileMtime(pathname, sec, nsec) \ + assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec) +#define assertFileMtimeRecent(pathname) \ + assertion_file_mtime_recent(__FILE__, __LINE__, pathname) +#define assertFileNLinks(pathname, nlinks) \ + assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks) +#define assertFileSize(pathname, size) \ + assertion_file_size(__FILE__, __LINE__, pathname, size) #define assertTextFileContents \ - test_setup(__FILE__, __LINE__);test_assert_text_file_contents + assertion_setup(__FILE__, __LINE__);assertion_text_file_contents +#define assertIsDir(pathname, mode) \ + assertion_is_dir(__FILE__, __LINE__, pathname, mode) +#define assertIsHardlink(path1, path2) \ + assertion_is_hardlink(__FILE__, __LINE__, path1, path2) +#define assertIsNotHardlink(path1, path2) \ + assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2) +#define assertIsReg(pathname, mode) \ + assertion_is_reg(__FILE__, __LINE__, pathname, mode) +#define assertIsSymlink(pathname, contents) \ + assertion_is_symlink(__FILE__, __LINE__, pathname, contents) +/* Create a directory, report error if it fails. */ +#define assertMakeDir(dirname, mode) \ + assertion_make_dir(__FILE__, __LINE__, dirname, mode) +#define assertMakeFile(path, mode, contents) \ + assertion_make_file(__FILE__, __LINE__, path, mode, contents) +#define assertMakeHardlink(newfile, oldfile) \ + assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) +#define assertMakeSymlink(newfile, linkto) \ + assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) +#define assertUmask(mask) \ + assertion_umask(__FILE__, __LINE__, mask) /* * This would be simple with C99 variadic macros, but I don't want to @@ -135,27 +213,60 @@ * but effective. */ #define skipping \ - test_setup(__FILE__, __LINE__);test_skipping + assertion_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); +int assertion_assert(const char *, int, int, const char *, void *); +int assertion_chdir(const char *, int, const char *); +int assertion_empty_file(const char *, ...); +int assertion_equal_file(const char *, const char *, ...); +int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *); +int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *); +int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *); +int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); +int assertion_file_atime(const char *, int, const char *, long, long); +int assertion_file_atime_recent(const char *, int, const char *); +int assertion_file_birthtime(const char *, int, const char *, long, long); +int assertion_file_birthtime_recent(const char *, int, const char *); +int assertion_file_contents(const void *, int, const char *, ...); +int assertion_file_exists(const char *, ...); +int assertion_file_mtime(const char *, int, const char *, long, long); +int assertion_file_mtime_recent(const char *, int, const char *); +int assertion_file_nlinks(const char *, int, const char *, int); +int assertion_file_not_exists(const char *, ...); +int assertion_file_size(const char *, int, const char *, long); +int assertion_is_dir(const char *, int, const char *, int); +int assertion_is_hardlink(const char *, int, const char *, const char *); +int assertion_is_not_hardlink(const char *, int, const char *, const char *); +int assertion_is_reg(const char *, int, const char *, int); +int assertion_is_symlink(const char *, int, const char *, const char *); +int assertion_make_dir(const char *, int, const char *, int); +int assertion_make_file(const char *, int, const char *, int, const char *); +int assertion_make_hardlink(const char *, int, const char *newpath, const char *); +int assertion_make_symlink(const char *, int, const char *newpath, const char *); +int assertion_non_empty_file(const char *, ...); +int assertion_text_file_contents(const char *buff, const char *f); +int assertion_umask(const char *, int, int); +void assertion_setup(const char *, int); + void test_skipping(const char *fmt, ...); -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 *, ...); -int test_assert_text_file_contents(const char *buff, const char *f); -int test_assert_file_exists(const char *, ...); -int test_assert_file_not_exists(const char *, ...); /* Like sprintf, then system() */ int systemf(const char * fmt, ...); +/* Delay until time() returns a value after this. */ +void sleepUntilAfter(time_t); + +/* Return true if this platform can create symlinks. */ +int canSymlink(void); + +/* Return true if this platform can run the "gzip" program. */ +int canGzip(void); + +/* Return true if this platform can run the "gunzip" program. */ +int canGunzip(void); + /* Suck file into string allocated via malloc(). Call free() when done. */ /* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ char *slurpfile(size_t *, const char *fmt, ...); @@ -168,4 +279,7 @@ void extract_reference_file(const char *); */ /* Pathname of exe to be tested. */ +const char *testprogfile; +/* Name of exe to use in printf-formatted command strings. */ +/* On Windows, this includes leading/trailing quotes. */ const char *testprog; diff --git a/usr.bin/cpio/test/test_0.c b/usr.bin/cpio/test/test_0.c index d224daa..75a1437 100644 --- a/usr.bin/cpio/test/test_0.c +++ b/usr.bin/cpio/test/test_0.c @@ -39,11 +39,11 @@ DEFINE_TEST(test_0) { struct stat st; - failure("File %s does not exist?!", testprog); - if (!assertEqualInt(0, stat(testprog, &st))) + failure("File %s does not exist?!", testprogfile); + if (!assertEqualInt(0, stat(testprogfile, &st))) exit(1); - failure("%s is not executable?!", testprog); + failure("%s is not executable?!", testprogfile); if (!assert((st.st_mode & 0111) != 0)) exit(1); diff --git a/usr.bin/cpio/test/test_basic.c b/usr.bin/cpio/test/test_basic.c index a4eb60f..3a3fae8 100644 --- a/usr.bin/cpio/test/test_basic.c +++ b/usr.bin/cpio/test/test_basic.c @@ -26,106 +26,32 @@ __FBSDID("$FreeBSD$"); static void -verify_files(const char *target) +verify_files(const char *msg) { - struct stat st, st2; -#if !defined(_WIN32) || defined(__CYGWIN__) - char buff[128]; -#endif - 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)); -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Group members bits and others bits do not work. */ - assertEqualInt(0600, st.st_mode & 0700); -#else - assertEqualInt(0644, st.st_mode & 0777); -#endif - assertEqualInt(10, st.st_size); - failure("file %s/file should have 2 links", target); - assertEqualInt(2, st.st_nlink); - } + assertIsReg("file", 0644); + failure(msg); + assertFileSize("file", 10); + assertFileNLinks("file", 2); /* 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)); -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Group members bits and others bits do not work. */ - assertEqualInt(0600, st2.st_mode & 0700); -#else - assertEqualInt(0644, st2.st_mode & 0777); -#endif - 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); - } + assertIsHardlink("linkfile", "file"); /* Symlink */ - r = lstat("symlink", &st); - failure("Failed to stat file %s/symlink, errno=%d", target, errno); - assertEqualInt(r, 0); -#if !defined(_WIN32) || defined(__CYGWIN__) - 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"); - } - } -#endif + if (canSymlink()) + assertIsSymlink("symlink", "file"); /* Another file with 1 link and different permissions. */ - r = lstat("file2", &st); - failure("Failed to stat file %s/file2, errno=%d", target, errno); - assertEqualInt(r, 0); - if (r == 0) { - assert(S_ISREG(st.st_mode)); - failure("%s/file2: st.st_mode = %o", target, st.st_mode); -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Execution bit and group members bits and others - * bits do not work. */ - assertEqualInt(0600, st.st_mode & 0700); -#else - assertEqualInt(0777, st.st_mode & 0777); -#endif - assertEqualInt(10, st.st_size); - failure("file %s/file2 should have 1 link", target); - assertEqualInt(1, st.st_nlink); - } + assertIsReg("file2", 0777); + assertFileSize("file2", 10); + assertFileNLinks("file2", 1); /* dir */ - r = lstat("dir", &st); - if (r == 0) { - assertEqualInt(r, 0); - assert(S_ISDIR(st.st_mode)); - failure("%s/dir: st.st_mode = %o", target, st.st_mode); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualInt(0700, st.st_mode & 0700); -#else - assertEqualInt(0775, st.st_mode & 0777); -#endif - } + assertIsDir("dir", 0775); } static void @@ -136,7 +62,7 @@ basic_cpio(const char *target, { int r; - if (!assertEqualInt(0, mkdir(target, 0775))) + if (!assertMakeDir(target, 0775)) return; /* Use the cpio program to create an archive. */ @@ -145,7 +71,7 @@ basic_cpio(const char *target, failure("Error invoking %s -o %s", testprog, pack_options); assertEqualInt(r, 0); - chdir(target); + assertChdir(target); /* Verify stderr. */ failure("Expected: %s, options=%s", se, pack_options); @@ -163,9 +89,9 @@ basic_cpio(const char *target, failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target); assertTextFileContents(se, "unpack.err"); - verify_files(target); + verify_files(pack_options); - chdir(".."); + assertChdir(".."); } static void @@ -173,7 +99,7 @@ passthrough(const char *target) { int r; - if (!assertEqualInt(0, mkdir(target, 0775))) + if (!assertMakeDir(target, 0775)) return; /* @@ -184,77 +110,64 @@ passthrough(const char *target) failure("Error invoking %s -p", testprog); assertEqualInt(r, 0); - chdir(target); + assertChdir(target); /* Verify stderr. */ failure("Error invoking %s -p in dir %s", testprog, target); assertTextFileContents("1 block\n", "stderr"); - verify_files(target); - chdir(".."); + verify_files("passthrough"); + assertChdir(".."); } DEFINE_TEST(test_basic) { - int fd; - int filelist; - int oldumask; + FILE *filelist; + const char *msg; - oldumask = umask(0); + assertUmask(0); /* * Create an assortment of files on disk. */ - filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + filelist = fopen("filelist", "w"); /* 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); + assertMakeFile("file", 0644, "1234567890"); + fprintf(filelist, "file\n"); /* hardlink to above file. */ - assertEqualInt(0, link("file", "linkfile")); - write(filelist, "linkfile\n", 9); + assertMakeHardlink("linkfile", "file"); + fprintf(filelist, "linkfile\n"); /* Symlink to above file. */ - assertEqualInt(0, symlink("file", "symlink")); - write(filelist, "symlink\n", 8); + if (canSymlink()) { + assertMakeSymlink("symlink", "file"); + fprintf(filelist, "symlink\n"); + } /* Another file with different permissions. */ - fd = open("file2", O_CREAT | O_WRONLY, 0777); - assert(fd >= 0); - assertEqualInt(10, write(fd, "123456789", 10)); - close(fd); - write(filelist, "file2\n", 6); + assertMakeFile("file2", 0777, "1234567890"); + fprintf(filelist, "file2\n"); /* Directory. */ - assertEqualInt(0, mkdir("dir", 0775)); - write(filelist, "dir\n", 4); + assertMakeDir("dir", 0775); + fprintf(filelist, "dir\n"); /* All done. */ - close(filelist); + fclose(filelist); - umask(022); + assertUmask(022); /* Archive/dearchive with a variety of options. */ - basic_cpio("copy", "", "", "2 blocks\n"); - basic_cpio("copy_odc", "--format=odc", "", "2 blocks\n"); + msg = canSymlink() ? "2 blocks\n" : "1 block\n"; + basic_cpio("copy", "", "", msg); + basic_cpio("copy_odc", "--format=odc", "", msg); basic_cpio("copy_newc", "-H newc", "", "2 blocks\n"); - basic_cpio("copy_cpio", "-H odc", "", "2 blocks\n"); -#if defined(_WIN32) && !defined(__CYGWIN__) - /* - * On Windows, symbolic link does not work. - * Currentry copying file instead. therefore block size is - * different. - */ - basic_cpio("copy_ustar", "-H ustar", "", "10 blocks\n"); -#else - basic_cpio("copy_ustar", "-H ustar", "", "9 blocks\n"); -#endif + basic_cpio("copy_cpio", "-H odc", "", msg); + msg = canSymlink() ? "9 blocks\n" : "8 blocks\n"; + basic_cpio("copy_ustar", "-H ustar", "", msg); + /* Copy in one step using -p */ passthrough("passthrough"); - - umask(oldumask); } diff --git a/usr.bin/cpio/test/test_cmdline.c b/usr.bin/cpio/test/test_cmdline.c new file mode 100644 index 0000000..2dd7d65 --- /dev/null +++ b/usr.bin/cpio/test/test_cmdline.c @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 2003-2009 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 the command-line parsing. + */ + +DEFINE_TEST(test_cmdline) +{ + FILE *f; + + /* Create an empty file. */ + f = fopen("empty", "wb"); + assert(f != NULL); + fclose(f); + + failure("-Q is an invalid option on every cpio program I know of"); + assert(0 != systemf("%s -i -Q <empty >1.out 2>1.err", testprog)); + assertEmptyFile("1.out"); + + failure("-f requires an argument"); + assert(0 != systemf("%s -if <empty >2.out 2>2.err", testprog)); + assertEmptyFile("2.out"); + + failure("-f requires an argument"); + assert(0 != systemf("%s -i -f <empty >3.out 2>3.err", testprog)); + assertEmptyFile("3.out"); + + failure("--format requires an argument"); + assert(0 != systemf("%s -i --format <empty >4.out 2>4.err", testprog)); + assertEmptyFile("4.out"); + + failure("--badopt is an invalid option"); + assert(0 != systemf("%s -i --badop <empty >5.out 2>5.err", testprog)); + assertEmptyFile("5.out"); + + failure("--badopt is an invalid option"); + assert(0 != systemf("%s -i --badopt <empty >6.out 2>6.err", testprog)); + assertEmptyFile("6.out"); + + failure("--n is ambiguous"); + assert(0 != systemf("%s -i --n <empty >7.out 2>7.err", testprog)); + assertEmptyFile("7.out"); + + failure("--create forbids an argument"); + assert(0 != systemf("%s --create=arg <empty >8.out 2>8.err", testprog)); + assertEmptyFile("8.out"); + + failure("-i with empty input should succeed"); + assert(0 == systemf("%s -i <empty >9.out 2>9.err", testprog)); + assertEmptyFile("9.out"); + + failure("-o with empty input should succeed"); + assert(0 == systemf("%s -o <empty >10.out 2>10.err", testprog)); + + failure("-i -p is nonsense"); + assert(0 != systemf("%s -i -p <empty >11.out 2>11.err", testprog)); + assertEmptyFile("11.out"); + + failure("-p -i is nonsense"); + assert(0 != systemf("%s -p -i <empty >12.out 2>12.err", testprog)); + assertEmptyFile("12.out"); + + failure("-i -o is nonsense"); + assert(0 != systemf("%s -i -o <empty >13.out 2>13.err", testprog)); + assertEmptyFile("13.out"); + + failure("-o -i is nonsense"); + assert(0 != systemf("%s -o -i <empty >14.out 2>14.err", testprog)); + assertEmptyFile("14.out"); + + failure("-o -p is nonsense"); + assert(0 != systemf("%s -o -p <empty >15.out 2>15.err", testprog)); + assertEmptyFile("15.out"); + + failure("-p -o is nonsense"); + assert(0 != systemf("%s -p -o <empty >16.out 2>16.err", testprog)); + assertEmptyFile("16.out"); + + failure("-p with empty input should fail"); + assert(0 != systemf("%s -p <empty >17.out 2>17.err", testprog)); + assertEmptyFile("17.out"); +} diff --git a/usr.bin/cpio/test/test_format_newc.c b/usr.bin/cpio/test/test_format_newc.c index 816f074..eb87c31 100644 --- a/usr.bin/cpio/test/test_format_newc.c +++ b/usr.bin/cpio/test/test_format_newc.c @@ -25,6 +25,13 @@ #include "test.h" __FBSDID("$FreeBSD$"); +/* Number of bytes needed to pad 'n' to multiple of 'block', assuming + * that 'block' is a power of two. This trick can be more easily + * remembered as -n & (block - 1), but many compilers quite reasonably + * warn about "-n" when n is an unsigned value. (~(n) + 1) is the + * same thing, but written in a way that won't offend anyone. */ +#define PAD(n, block) ((~(n) + 1) & ((block) - 1)) + static int is_hex(const char *p, size_t l) { @@ -63,60 +70,67 @@ from_hex(const char *p, size_t l) DEFINE_TEST(test_format_newc) { - int fd, list; + FILE *list; int r; int devmajor, devminor, ino, gid; + int uid = -1; time_t t, t2, now; char *p, *e; size_t s, fs, ns; - mode_t oldmask; - oldmask = umask(0); + assertUmask(0); + +#if !defined(_WIN32) + uid = getuid(); +#endif /* * Create an assortment of files. * TODO: Extend this to cover more filetypes. */ - list = open("list", O_CREAT | O_WRONLY, 0644); + list = fopen("list", "w"); /* "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)); + assertMakeFile("file1", 0644, "1234567890"); + fprintf(list, "file1\n"); /* "hardlink" */ - assertEqualInt(0, link("file1", "hardlink")); - assertEqualInt(9, write(list, "hardlink\n", 9)); + assertMakeHardlink("hardlink", "file1"); + fprintf(list, "hardlink\n"); /* Another hardlink, but this one won't be archived. */ - assertEqualInt(0, link("file1", "hardlink2")); + assertMakeHardlink("hardlink2", "file1"); /* "symlink" */ - assertEqualInt(0, symlink("file1", "symlink")); - assertEqualInt(8, write(list, "symlink\n", 8)); + if (canSymlink()) { + assertMakeSymlink("symlink", "file1"); + fprintf(list, "symlink\n"); + } /* "dir" */ - assertEqualInt(0, mkdir("dir", 0775)); - assertEqualInt(4, write(list, "dir\n", 4)); + assertMakeDir("dir", 0775); + fprintf(list, "dir\n"); /* 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); + fclose(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. */ - assertTextFileContents("2 blocks\n", "newc.err"); + if (canSymlink()) { + assertTextFileContents("2 blocks\n", "newc.err"); + } else { + assertTextFileContents("1 block\n", "newc.err"); + } /* Verify that stdout is a well-formed cpio file in "newc" format. */ p = slurpfile(&s, "newc.out"); - assertEqualInt(s, 1024); + assertEqualInt(s, canSymlink() ? 1024 : 512); e = p; /* @@ -133,8 +147,10 @@ DEFINE_TEST(test_format_newc) assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */ #else assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */ -#endif - assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ +#endif + if (uid < 0) + uid = from_hex(e + 22, 8); + assertEqualInt(from_hex(e + 22, 8), uid); /* uid */ gid = from_hex(e + 30, 8); /* gid */ assertEqualMem(e + 38, "00000003", 8); /* nlink */ t = from_hex(e + 46, 8); /* mtime */ @@ -147,68 +163,60 @@ DEFINE_TEST(test_format_newc) " field should be zero"); assertEqualInt(0, from_hex(e + 54, 8)); /* File size */ fs = from_hex(e + 54, 8); - fs += 3 & -fs; + fs += PAD(fs, 4); devmajor = from_hex(e + 62, 8); /* devmajor */ devminor = from_hex(e + 70, 8); /* devminor */ assert(is_hex(e + 78, 8)); /* rdevmajor */ assert(is_hex(e + 86, 8)); /* rdevminor */ assertEqualMem(e + 94, "00000006", 8); /* Name size */ ns = from_hex(e + 94, 8); - ns += 3 & (-ns - 2); + ns += PAD(ns + 2, 4); 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 += 110 + fs + ns; - /* "symlink" pointing to "file1" */ - assert(is_hex(e, 110)); - assertEqualMem(e + 0, "070701", 6); /* Magic */ - assert(is_hex(e + 6, 8)); /* ino */ -#if !defined(_WIN32) || defined(__CYGWIN__) - /* On Windows, symbolic link and group members bits and - * others bits do not work. */ - assertEqualInt(0xa1ff, from_hex(e + 14, 8)); /* Mode */ -#endif - 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. */ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Symbolic link does not work. */ - assertEqualMem(e + 54, "0000000a", 8); /* File size */ -#else - assertEqualMem(e + 54, "00000005", 8); /* File size */ -#endif - fs = from_hex(e + 54, 8); - fs += 3 & -fs; - assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */ - assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */ - assert(is_hex(e + 78, 8)); /* rdevmajor */ - assert(is_hex(e + 86, 8)); /* rdevminor */ - assertEqualMem(e + 94, "00000008", 8); /* Name size */ - ns = from_hex(e + 94, 8); - ns += 3 & (-ns - 2); - assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ - assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */ -#if !defined(_WIN32) || defined(__CYGWIN__) - assertEqualMem(e + 110 + ns, "file1\0\0\0", 8); /* symlink target */ -#endif - e += 110 + fs + ns; + if (canSymlink()) { + /* "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), uid); /* 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 */ + fs = from_hex(e + 54, 8); + fs += PAD(fs, 4); + assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */ + assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */ + assert(is_hex(e + 78, 8)); /* rdevmajor */ + assert(is_hex(e + 86, 8)); /* rdevminor */ + assertEqualMem(e + 94, "00000008", 8); /* Name size */ + ns = from_hex(e + 94, 8); + ns += PAD(ns + 2, 4); + assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ + assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */ + assertEqualMem(e + 110 + ns, "file1\0\0\0", 8); /* symlink target */ + e += 110 + fs + ns; + } /* "dir" */ assert(is_hex(e, 110)); assertEqualMem(e + 0, "070701", 6); /* Magic */ assert(is_hex(e + 6, 8)); /* ino */ #if defined(_WIN32) && !defined(__CYGWIN__) - /* Group members bits and others bits do not work. */ + /* Group members bits and others bits do not work. */ assertEqualInt(0x41c0, from_hex(e + 14, 8) & 0xffc0); /* Mode */ #else - assertEqualInt(0x41fd, from_hex(e + 14, 8)); /* Mode */ + /* Mode: sgid bit sometimes propagates from parent dirs, ignore it. */ + assertEqualInt(040775, from_hex(e + 14, 8) & ~02000); #endif - assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ + assertEqualInt(from_hex(e + 22, 8), uid); /* uid */ assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */ #ifndef NLINKS_INACCURATE_FOR_DIRS assertEqualMem(e + 38, "00000002", 8); /* nlink */ @@ -218,14 +226,14 @@ DEFINE_TEST(test_format_newc) assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */ assertEqualMem(e + 54, "00000000", 8); /* File size */ fs = from_hex(e + 54, 8); - fs += 3 & -fs; + fs += PAD(fs, 4); assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */ assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */ assert(is_hex(e + 78, 8)); /* rdevmajor */ assert(is_hex(e + 86, 8)); /* rdevminor */ assertEqualMem(e + 94, "00000004", 8); /* Name size */ ns = from_hex(e + 94, 8); - ns += 3 & (-ns - 2); + ns += PAD(ns + 2, 4); assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ assertEqualMem(e + 110, "dir\0\0\0", 6); /* Name contents */ e += 110 + fs + ns; @@ -243,7 +251,7 @@ DEFINE_TEST(test_format_newc) #else assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */ #endif - assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ + assertEqualInt(from_hex(e + 22, 8), uid); /* uid */ assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */ assertEqualMem(e + 38, "00000003", 8); /* nlink */ t2 = from_hex(e + 46, 8); /* mtime */ @@ -251,17 +259,17 @@ DEFINE_TEST(test_format_newc) assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */ assertEqualInt(10, from_hex(e + 54, 8)); /* File size */ fs = from_hex(e + 54, 8); - fs += 3 & -fs; + fs += PAD(fs, 4); assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */ assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */ assert(is_hex(e + 78, 8)); /* rdevmajor */ assert(is_hex(e + 86, 8)); /* rdevminor */ assertEqualMem(e + 94, "00000009", 8); /* Name size */ ns = from_hex(e + 94, 8); - ns += 3 & (-ns - 2); + ns += PAD(ns + 2, 4); assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ assertEqualMem(e + 110, "hardlink\0\0", 10); /* Name contents */ - assertEqualMem(e + 110 + ns, "123456789\0\0\0", 12); /* File contents */ + assertEqualMem(e + 110 + ns, "1234567890\0\0", 12); /* File contents */ e += 110 + ns + fs; /* Last entry is end-of-archive marker. */ @@ -283,6 +291,4 @@ DEFINE_TEST(test_format_newc) 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 index 767719b..3d992c4 100644 --- a/usr.bin/cpio/test/test_gcpio_compat.c +++ b/usr.bin/cpio/test/test_gcpio_compat.c @@ -28,15 +28,11 @@ __FBSDID("$FreeBSD$"); static void unpack_test(const char *from, const char *options, const char *se) { - struct stat st, st2; -#if !defined(_WIN32) || defined(__CYGWIN__) - char buff[128]; -#endif int r; /* Create a work dir named after the file we're unpacking. */ - assertEqualInt(0, mkdir(from, 0775)); - chdir(from); + assertMakeDir(from, 0775); + assertChdir(from); /* * Use cpio to unpack the sample archive @@ -49,96 +45,64 @@ unpack_test(const char *from, const char *options, const char *se) assertEqualInt(r, 0); /* Verify that nothing went to stderr. */ - failure("Error invoking %s -i %s < %s", testprog, options, from); - assertTextFileContents(se, "unpack.err"); + if (canSymlink()) { + failure("Error invoking %s -i %s < %s", + testprog, options, from); + assertTextFileContents(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)); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualInt(0600, st.st_mode & 0700); -#else - assertEqualInt(0644, st.st_mode & 0777); -#endif - failure("file %s/file", from); - assertEqualInt(10, st.st_size); - failure("file %s/file", from); - assertEqualInt(2, st.st_nlink); - } + assertIsReg("file", 0644); + failure("%s", from); + assertFileSize("file", 10); + assertFileSize("linkfile", 10); + failure("%s", from); + assertFileNLinks("file", 2); /* 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)); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualInt(0600, st2.st_mode & 0700); -#else - assertEqualInt(0644, st2.st_mode & 0777); -#endif - 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); - } + failure("%s", from); + assertIsHardlink("linkfile", "file"); + assertFileSize("file", 10); + assertFileSize("linkfile", 10); /* Symlink */ - r = lstat("symlink", &st); - failure("Failed to stat file %s/symlink, errno=%d", from, errno); - assertEqualInt(r, 0); -#if !defined(_WIN32) || defined(__CYGWIN__) - 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"); - } - } -#endif + if (canSymlink()) + assertIsSymlink("symlink", "file"); /* dir */ - r = lstat("dir", &st); - if (r == 0) { - assertEqualInt(r, 0); - assert(S_ISDIR(st.st_mode)); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualInt(0700, st.st_mode & 0700); -#else - assertEqualInt(0775, st.st_mode & 0777); -#endif - } + assertIsDir("dir", 0775); - chdir(".."); + assertChdir(".."); } DEFINE_TEST(test_gcpio_compat) { - int oldumask; - - oldumask = umask(0); + assertUmask(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"); - /* gcpio-2.9 only reads 6 blocks here */ - unpack_test("test_gcpio_compat_ref.ustar", "", "7 blocks\n"); - - umask(oldumask); + if (canSymlink()) { + unpack_test("test_gcpio_compat_ref.bin", + "--no-preserve-owner", "1 block\n"); + unpack_test("test_gcpio_compat_ref.crc", + "--no-preserve-owner", "2 blocks\n"); + unpack_test("test_gcpio_compat_ref.newc", + "--no-preserve-owner", "2 blocks\n"); + /* gcpio-2.9 only reads 6 blocks here */ + unpack_test("test_gcpio_compat_ref.ustar", + "--no-preserve-owner", "7 blocks\n"); + } else { + unpack_test("test_gcpio_compat_ref_nosym.bin", + "--no-preserve-owner", "1 block\n"); + unpack_test("test_gcpio_compat_ref_nosym.crc", + "--no-preserve-owner", "2 blocks\n"); + unpack_test("test_gcpio_compat_ref_nosym.newc", + "--no-preserve-owner", "2 blocks\n"); + /* gcpio-2.9 only reads 6 blocks here */ + unpack_test("test_gcpio_compat_ref_nosym.ustar", + "--no-preserve-owner", "7 blocks\n"); + } } diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.bin.uu b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.bin.uu new file mode 100644 index 0000000..7a2a272 --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.bin.uu @@ -0,0 +1,17 @@ +$FreeBSD$ + +begin 644 test_gcpio_compat_ref_nosym.bin +MQW%4`-[Z_4'H`^@#`@`VNZU*NQX$``````!D:7(`QW%4`-SZI('H`^@#`@`G +MNZU*NQX%````"@!F:6QE```Q,C,T-38W.#D*QW%4`-SZI('H`^@#`@`GNZU* +MNQX)````"@!L:6YK9FEL90``,3(S-#4V-S@Y"L=Q``````````````$````` +M````"P``````5%)!24Q%4B$A(0`````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +1```````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.crc.uu b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.crc.uu new file mode 100644 index 0000000..0147df7 --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.crc.uu @@ -0,0 +1,17 @@ +$FreeBSD$ + +begin 644 test_gcpio_compat_ref_nosym.crc +M,#<P-S`R,#`U-D9!1$4P,#`P-#%&1#`P,#`P,T4X,#`P,#`S13@P,#`P,#`P +M,C1!040Q14)",#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4T,#`P,#`P0D(P,35" +M,#`S-C`P,#`P,#`T,#`P,#`P,#!D:7(````P-S`W,#(P,#4V1D%$0S`P,#`X +M,4$T,#`P,#`S13@P,#`P,#-%.#`P,#`P,#`R-$%!1#%%0D(P,#`P,#`P,#`P +M,#`P,#`P,#`P,#`P-30P,#`P,#!"0C`Q-4(P,#(W,#`P,#`P,#4P,#`P,#`P +M,&9I;&4``#`W,#<P,C`P-39&041#,#`P,#@Q030P,#`P,#-%.#`P,#`P,T4X +M,#`P,#`P,#(T04%$,45"0C`P,#`P,#!!,#`P,#`P,#`P,#`P,#`U-#`P,#`P +M,$)",#$U0C`P,C<P,#`P,#`P.3`P,#`P,44W;&EN:V9I;&4``#$R,S0U-C<X +M.0H``#`W,#<P,C`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P +M,#`P,#$P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P +M,#`P,#`P,#`P,#`P,#`P0C`P,#`P,#`P5%)!24Q%4B$A(0`````````````` +1```````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.newc.uu b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.newc.uu new file mode 100644 index 0000000..e2a4900 --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.newc.uu @@ -0,0 +1,17 @@ +$FreeBSD$ + +begin 644 test_gcpio_compat_ref_nosym.newc +M,#<P-S`Q,#`U-D9!1$4P,#`P-#%&1#`P,#`P,T4X,#`P,#`S13@P,#`P,#`P +M,C1!040Q14)",#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4T,#`P,#`P0D(P,35" +M,#`S-C`P,#`P,#`T,#`P,#`P,#!D:7(````P-S`W,#$P,#4V1D%$0S`P,#`X +M,4$T,#`P,#`S13@P,#`P,#-%.#`P,#`P,#`R-$%!1#%%0D(P,#`P,#`P,#`P +M,#`P,#`P,#`P,#`P-30P,#`P,#!"0C`Q-4(P,#(W,#`P,#`P,#4P,#`P,#`P +M,&9I;&4``#`W,#<P,3`P-39&041#,#`P,#@Q030P,#`P,#-%.#`P,#`P,T4X +M,#`P,#`P,#(T04%$,45"0C`P,#`P,#!!,#`P,#`P,#`P,#`P,#`U-#`P,#`P +M,$)",#$U0C`P,C<P,#`P,#`P.3`P,#`P,#`P;&EN:V9I;&4``#$R,S0U-C<X +M.0H``#`W,#<P,3`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P +M,#`P,#$P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P +M,#`P,#`P,#`P,#`P,#`P0C`P,#`P,#`P5%)!24Q%4B$A(0`````````````` +1```````````````````````` +` +end diff --git a/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.ustar.uu b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.ustar.uu new file mode 100644 index 0000000..b5cbd66 --- /dev/null +++ b/usr.bin/cpio/test/test_gcpio_compat_ref_nosym.ustar.uu @@ -0,0 +1,74 @@ +$FreeBSD$ + +begin 644 test_gcpio_compat_ref_nosym.ustar +M9&ER+P`````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````#`P,#`W-S4`,#`P,3<U,``P,#`Q-S4P`#`P,#`P,#`P,#`P +M`#$Q,C4S,C$W,C<S`#`P,3$S-3$`-0`````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````!U<W1A<@`P,'1I;0`` +M````````````````````````````````````=&EM```````````````````` +M```````````````````P,#`P,C<S`#8V,#`P-C8````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````!F:6QE```````````````````````````````` +M```````````````````````````````````````````````````````````` +M````````````````````````````````````,#`P,#8T-``P,#`Q-S4P`#`P +M,#$W-3``,#`P,#`P,#`P,3(`,3$R-3,R,3<R-S,`,#`Q,30R,P`P```````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````'5S=&%R`#`P=&EM``````````````````````````````````````!T +M:6T``````````````````````````````````````#`P,#`R-S,`-C8P,#`T +M-P`````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````````````````````````````````#$R,S0U-C<X.0H` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M````````;&EN:V9I;&4````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````````#`P,#`V-#0`,#`P,3<U,``P,#`Q-S4P`#`P,#`P +M,#`P,#`P`#$Q,C4S,C$W,C<S`#`P,3,Q,S<`,69I;&4````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````````````!U<W1A<@`P +M,'1I;0``````````````````````````````````````=&EM```````````` +M```````````````````````````P,#`P,C<S`#8V,#`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```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +,```````````````` +` +end diff --git a/usr.bin/cpio/test/test_option_B.c b/usr.bin/cpio/test/test_option_B_upper.c index 8083882..b040354 100644 --- a/usr.bin/cpio/test/test_option_B.c +++ b/usr.bin/cpio/test/test_option_B_upper.c @@ -26,29 +26,27 @@ __FBSDID("$FreeBSD$"); -DEFINE_TEST(test_option_B) +DEFINE_TEST(test_option_B_upper) { struct stat st; - int r, fd; + int r; /* * Create a file on disk. */ - fd = open("file", O_CREAT | O_WRONLY, 0644); - assert(fd >= 0); - close(fd); + assertMakeFile("file", 0644, NULL); /* 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"); + assertTextFileContents("1 block\n", "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"); + assertTextFileContents("1 block\n", "large.err"); assertEqualInt(0, stat("large.cpio", &st)); assertEqualInt(5120, st.st_size); } diff --git a/usr.bin/cpio/pathmatch.h b/usr.bin/cpio/test/test_option_C_upper.c index 3e82830..c8e63fd 100644 --- a/usr.bin/cpio/pathmatch.h +++ b/usr.bin/cpio/test/test_option_C_upper.c @@ -6,8 +6,7 @@ * 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 - * in this position and unchanged. + * 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. @@ -22,21 +21,42 @@ * 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$ */ +#include "test.h" +__FBSDID("$FreeBSD$"); + + +DEFINE_TEST(test_option_C_upper) +{ + int r; -#ifndef LAFE_PATHMATCH_H -#define LAFE_PATHMATCH_H + /* + * Create a file on disk. + */ + assertMakeFile("file", 0644, NULL); -/* Don't anchor at beginning unless the pattern starts with "^" */ -#define PATHMATCH_NO_ANCHOR_START 1 -/* Don't anchor at end unless the pattern ends with "$" */ -#define PATHMATCH_NO_ANCHOR_END 2 + /* Create an archive without -C; this should be 512 bytes. */ + r = systemf("echo file | %s -o > small.cpio 2>small.err", testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "small.err"); + assertFileSize("small.cpio", 512); -/* Note that "^" and "$" are not special unless you set the corresponding - * flag above. */ + /* Create an archive with -C 513; this should be 513 bytes. */ + r = systemf("echo file | %s -o -C 513 > 513.cpio 2>513.err", + testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "513.err"); + assertFileSize("513.cpio", 513); -int pathmatch(const char *p, const char *s, int flags); + /* Create an archive with -C 12345; this should be 12345 bytes. */ + r = systemf("echo file | %s -o -C12345 > 12345.cpio 2>12345.err", + testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "12345.err"); + assertFileSize("12345.cpio", 12345); -#endif + /* Create an archive with invalid -C request */ + assert(0 != systemf("echo file | %s -o -C > bad.cpio 2>bad.err", + testprog)); + assertEmptyFile("bad.cpio"); +} diff --git a/usr.bin/cpio/err.h b/usr.bin/cpio/test/test_option_J_upper.c index fe96c70..532aacf 100644 --- a/usr.bin/cpio/err.h +++ b/usr.bin/cpio/test/test_option_J_upper.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 Joerg Sonnenberger + * Copyright (c) 2003-2009 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,23 +21,36 @@ * 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$ */ +#include "test.h" +__FBSDID("$FreeBSD$"); -#ifndef LAFE_ERR_H -#define LAFE_ERR_H - -#if defined(__GNUC__) && (__GNUC__ > 2 || \ - (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) -#define __LA_DEAD __attribute__((__noreturn__)) -#else -#define __LA_DEAD -#endif - -extern const char *progname; +DEFINE_TEST(test_option_J_upper) +{ + char *p; + int r; + size_t s; -void warnc(int code, const char *fmt, ...); -void errc(int eval, int code, const char *fmt, ...) __LA_DEAD; + /* Create a file. */ + assertMakeFile("f", 0644, "a"); -#endif + /* Archive it with xz compression. */ + r = systemf("echo f | %s -o -J >archive.out 2>archive.err", + testprog); + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (r != 0) { + if (strstr(p, "compression not available") != NULL) { + skipping("This version of bsdcpio was compiled " + "without xz support"); + return; + } + failure("-J option is broken"); + assertEqualInt(r, 0); + return; + } + /* Check that the archive file has an xz signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "\3757zXZ", 5); +} diff --git a/usr.bin/cpio/test/test_option_L.c b/usr.bin/cpio/test/test_option_L_upper.c index 79e2adb..0acc100 100644 --- a/usr.bin/cpio/test/test_option_L.c +++ b/usr.bin/cpio/test/test_option_L_upper.c @@ -25,60 +25,77 @@ #include "test.h" __FBSDID("$FreeBSD$"); -DEFINE_TEST(test_option_L) +/* This is a little pointless, as Windows doesn't support symlinks + * (except for the seriously crippled CreateSymbolicLink API) so these + * tests won't run on Windows. */ +#if defined(_WIN32) && !defined(__CYGWIN__) +#define CAT "type" +#else +#define CAT "cat" +#endif + +DEFINE_TEST(test_option_L_upper) { - struct stat st; - int fd, filelist; + FILE *filelist; int r; - filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + if (!canSymlink()) { + skipping("Symlink tests"); + return; + } + + filelist = fopen("filelist", "w"); /* 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); + assertMakeFile("file", 0644, "1234567890"); + fprintf(filelist, "file\n"); /* Symlink to above file. */ - assertEqualInt(0, symlink("file", "symlink")); - write(filelist, "symlink\n", 8); + assertMakeSymlink("symlink", "file"); + fprintf(filelist, "symlink\n"); - close(filelist); + fclose(filelist); - r = systemf("cat filelist | %s -pd copy >copy.out 2>copy.err", testprog); + r = systemf(CAT " filelist | %s -pd copy >copy.out 2>copy.err", testprog); assertEqualInt(r, 0); - assertEqualInt(0, lstat("copy/symlink", &st)); + assertTextFileContents("1 block\n", "copy.err"); + failure("Regular -p without -L should preserve symlinks."); - assert(S_ISLNK(st.st_mode)); + assertIsSymlink("copy/symlink", NULL); - r = systemf("cat filelist | %s -pd -L copy-L >copy-L.out 2>copy-L.err", testprog); + r = systemf(CAT " filelist | %s -pd -L copy-L >copy-L.out 2>copy-L.err", testprog); assertEqualInt(r, 0); assertEmptyFile("copy-L.out"); - assertFileContents("1 block\n", 8, "copy-L.err"); - assertEqualInt(0, lstat("copy-L/symlink", &st)); + assertTextFileContents("1 block\n", "copy-L.err"); failure("-pdL should dereference symlinks and turn them into files."); - assert(!S_ISLNK(st.st_mode)); + assertIsReg("copy-L/symlink", -1); - r = systemf("cat filelist | %s -o >archive.out 2>archive.err", testprog); + r = systemf(CAT " filelist | %s -o >archive.out 2>archive.err", testprog); failure("Error invoking %s -o ", testprog); assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "archive.err"); - assertEqualInt(0, mkdir("unpack", 0755)); - r = systemf("cat archive.out | (cd unpack ; %s -i >unpack.out 2>unpack.err)", testprog); + assertMakeDir("unpack", 0755); + assertChdir("unpack"); + r = systemf(CAT " ../archive.out | %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)); + assertTextFileContents("1 block\n", "unpack.err"); + assertChdir(".."); + + assertIsSymlink("unpack/symlink", NULL); - r = systemf("cat filelist | %s -oL >archive-L.out 2>archive-L.err", testprog); + r = systemf(CAT " filelist | %s -oL >archive-L.out 2>archive-L.err", testprog); failure("Error invoking %s -oL", testprog); assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "archive-L.err"); - 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); + assertMakeDir("unpack-L", 0755); + assertChdir("unpack-L"); + r = systemf(CAT " ../archive-L.out | %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)); + assertTextFileContents("1 block\n", "unpack-L.err"); + assertChdir(".."); + assertIsReg("unpack-L/symlink", -1); } diff --git a/usr.bin/cpio/line_reader.h b/usr.bin/cpio/test/test_option_Z_upper.c index 4f5dd6a..936ce0c 100644 --- a/usr.bin/cpio/line_reader.h +++ b/usr.bin/cpio/test/test_option_Z_upper.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 Joerg Sonnenberger + * Copyright (c) 2003-2009 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,17 +21,36 @@ * 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$ */ +#include "test.h" +__FBSDID("$FreeBSD$"); -#ifndef LAFE_LINE_READER_H -#define LAFE_LINE_READER_H - -struct line_reader; +DEFINE_TEST(test_option_Z_upper) +{ + char *p; + int r; + size_t s; -struct line_reader *line_reader(const char *, int nullSeparator); -const char *line_reader_next(struct line_reader *); -void line_reader_free(struct line_reader *); + /* Create a file. */ + assertMakeFile("f", 0644, "a"); -#endif + /* Archive it with compress compression. */ + r = systemf("echo f | %s -oZ >archive.out 2>archive.err", + testprog); + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (r != 0) { + if (strstr(p, "compression not available") != NULL) { + skipping("This version of bsdcpio was compiled " + "without compress support"); + return; + } + failure("-Z option is broken"); + assertEqualInt(r, 0); + return; + } + /* Check that the archive file has a compress signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "\x1f\x9d", 2); +} diff --git a/usr.bin/cpio/test/test_option_a.c b/usr.bin/cpio/test/test_option_a.c index e769836..af4b48e 100644 --- a/usr.bin/cpio/test/test_option_a.c +++ b/usr.bin/cpio/test/test_option_a.c @@ -23,10 +23,10 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -#if defined(_WIN32) && !defined(__CYGWIN__) -#include <sys/utime.h> -#else +#if defined(HAVE_UTIME_H) #include <utime.h> +#elif defined(HAVE_SYS_UTIME_H) +#include <sys/utime.h> #endif __FBSDID("$FreeBSD$"); @@ -57,19 +57,15 @@ test_create(void) 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); + assertMakeFile(files[i].name, 0644, "a"); /* If utime() isn't supported on your platform, just * #ifdef this section out. Most of the test below is @@ -87,26 +83,21 @@ test_create(void) } /* 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); + sleepUntilAfter(files[numfiles - 1].atime_sec); } DEFINE_TEST(test_option_a) { struct stat st; int r; - int f; - char buff[64]; + char *p; /* 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)); + assert((p = slurpfile(NULL, "f0")) != NULL); + free(p); assertEqualInt(0, stat("f0", &st)); if (st.st_atime == files[0].atime_sec) { skipping("Cannot verify -a option\n" diff --git a/usr.bin/cpio/test/test_option_c.c b/usr.bin/cpio/test/test_option_c.c index 2f4e3bc..241bcf6 100644 --- a/usr.bin/cpio/test/test_option_c.c +++ b/usr.bin/cpio/test/test_option_c.c @@ -53,41 +53,44 @@ from_octal(const char *p, size_t l) DEFINE_TEST(test_option_c) { - int fd, filelist; + FILE *filelist; int r; + int uid = -1; int dev, ino, gid; time_t t, now; char *p, *e; size_t s; - mode_t oldmask; - oldmask = umask(0); + assertUmask(0); + +#if !defined(_WIN32) + uid = getuid(); +#endif /* * Create an assortment of files. * TODO: Extend this to cover more filetypes. */ - filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + filelist = fopen("filelist", "w"); /* "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)); + assertMakeFile("file", 0644, "1234567890"); + fprintf(filelist, "file\n"); /* "symlink" */ - assertEqualInt(0, symlink("file", "symlink")); - assertEqualInt(8, write(filelist, "symlink\n", 8)); + if (canSymlink()) { + assertMakeSymlink("symlink", "file"); + fprintf(filelist, "symlink\n"); + } /* "dir" */ - assertEqualInt(0, mkdir("dir", 0775)); + assertMakeDir("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)); + fprintf(filelist, "dir\n"); /* Use the cpio program to create an archive. */ - close(filelist); + fclose(filelist); r = systemf("%s -oc <filelist >basic.out 2>basic.err", testprog); /* Verify that nothing went to stderr. */ assertTextFileContents("1 block\n", "basic.err"); @@ -115,12 +118,14 @@ DEFINE_TEST(test_option_c) assert(is_octal(e + 12, 6)); /* ino */ ino = from_octal(e + 12, 6); #if defined(_WIN32) && !defined(__CYGWIN__) - /* Group members bits and others bits do not work. */ + /* Group members bits and others bits do not work. */ assertEqualMem(e + 18, "100666", 6); /* Mode */ #else assertEqualMem(e + 18, "100644", 6); /* Mode */ #endif - assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */ + if (uid < 0) + uid = from_octal(e + 24, 6); + assertEqualInt(from_octal(e + 24, 6), uid); /* uid */ assert(is_octal(e + 30, 6)); /* gid */ gid = from_octal(e + 30, 6); assertEqualMem(e + 36, "000001", 6); /* nlink */ @@ -133,46 +138,37 @@ DEFINE_TEST(test_option_c) 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 */ + assertEqualMem(e + 81, "1234567890", 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 */ + /* "symlink" pointing to "file" */ + if (canSymlink()) { + 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(ino != from_octal(e + 12, 6)); /* ino */ #if !defined(_WIN32) || defined(__CYGWIN__) - /* On Windows, symbolic link and group members bits and - * others bits do not work. */ - assertEqualMem(e + 18, "120777", 6); /* Mode */ -#endif - 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 */ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* On Windows, symbolic link does not work. */ - assertEqualMem(e + 65, "00000000012", 11); /* File size */ -#else - assertEqualMem(e + 65, "00000000004", 11); /* File size */ -#endif - assertEqualMem(e + 76, "symlink\0", 8); /* Name contents */ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* On Windows, symbolic link does not work. */ - assertEqualMem(e + 84, "123456789\0", 10); /* File contents. */ - e += 94; -#else - assertEqualMem(e + 84, "file", 4); /* Symlink target. */ - e += 88; + /* On Windows, symbolic link and group members bits and + * others bits do not work. */ + assertEqualMem(e + 18, "120777", 6); /* Mode */ #endif + assertEqualInt(from_octal(e + 24, 6), uid); /* 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" */ + /* "dir" */ assert(is_octal(e, 76)); assertEqualMem(e + 0, "070707", 6); /* Magic */ /* Dev should be same as first entry. */ @@ -182,12 +178,14 @@ DEFINE_TEST(test_option_c) assert(is_octal(e + 12, 6)); /* ino */ assert(dev != from_octal(e + 12, 6)); #if defined(_WIN32) && !defined(__CYGWIN__) - /* Group members bits and others bits do not work. */ + /* Group members bits and others bits do not work. */ assertEqualMem(e + 18, "040777", 6); /* Mode */ #else - assertEqualMem(e + 18, "040775", 6); /* Mode */ + /* Accept 042775 to accomodate systems where sgid bit propagates. */ + if (memcmp(e + 18, "042775", 6) != 0) + assertEqualMem(e + 18, "040775", 6); /* Mode */ #endif - assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */ + assertEqualInt(from_octal(e + 24, 6), uid); /* uid */ /* Gid should be same as first entry. */ assert(is_octal(e + 30, 6)); /* gid */ assertEqualInt(gid, from_octal(e + 30, 6)); @@ -220,6 +218,4 @@ DEFINE_TEST(test_option_c) 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 index cb422ae..9ff1453 100644 --- a/usr.bin/cpio/test/test_option_d.c +++ b/usr.bin/cpio/test/test_option_d.c @@ -28,41 +28,37 @@ __FBSDID("$FreeBSD$"); DEFINE_TEST(test_option_d) { - struct stat st; - int r, fd; + int r; /* * 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); + assertMakeDir("dir", 0755); + assertMakeFile("dir/file", 0644, NULL); /* Create an archive. */ r = systemf("echo dir/file | %s -o > archive.cpio 2>archive.err", testprog); assertEqualInt(r, 0); assertTextFileContents("1 block\n", "archive.err"); - assertEqualInt(0, stat("archive.cpio", &st)); - assertEqualInt(512, st.st_size); + assertFileSize("archive.cpio", 512); /* Dearchive without -d, this should fail. */ - assertEqualInt(0, mkdir("without-d", 0755)); - assertEqualInt(0, chdir("without-d")); + assertMakeDir("without-d", 0755); + assertChdir("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)); + assertFileNotExists("dir/file"); /* Dearchive with -d, this should succeed. */ - assertEqualInt(0, chdir("..")); - assertEqualInt(0, mkdir("with-d", 0755)); - assertEqualInt(0, chdir("with-d")); + assertChdir(".."); + assertMakeDir("with-d", 0755); + assertChdir("with-d"); r = systemf("%s -id < ../archive.cpio >out 2>err", testprog); assertEqualInt(r, 0); assertEmptyFile("out"); assertTextFileContents("1 block\n", "err"); /* And the file should be restored. */ - assertEqualInt(0, stat("dir/file", &st)); + assertFileExists("dir/file"); } diff --git a/usr.bin/cpio/test/test_option_f.c b/usr.bin/cpio/test/test_option_f.c index 54e07ac..784e085 100644 --- a/usr.bin/cpio/test/test_option_f.c +++ b/usr.bin/cpio/test/test_option_f.c @@ -33,44 +33,44 @@ unpack(const char *dirname, const char *option) { int r; - assertEqualInt(0, mkdir(dirname, 0755)); - assertEqualInt(0, chdir(dirname)); + assertMakeDir(dirname, 0755); + assertChdir(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("..")); + assertChdir(".."); } 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)); + unpack("t0", "--no-preserve-owner"); + assertFileExists("t0/a123"); + assertFileExists("t0/a234"); + assertFileExists("t0/b123"); + assertFileExists("t0/b234"); /* Don't extract 'a*' files. */ #if defined(_WIN32) && !defined(__CYGWIN__) /* Single quotes isn't used by command.exe. */ - unpack("t1", "-f a*"); + unpack("t1", "--no-preserve-owner -f a*"); #else - unpack("t1", "-f 'a*'"); + unpack("t1", "--no-preserve-owner -f 'a*'"); #endif - 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)); + assertFileNotExists("t1/a123"); + assertFileNotExists("t1/a234"); + assertFileExists("t1/b123"); + assertFileExists("t1/b234"); /* Don't extract 'b*' files. */ #if defined(_WIN32) && !defined(__CYGWIN__) /* Single quotes isn't used by command.exe. */ - unpack("t2", "-f b*"); + unpack("t2", "--no-preserve-owner -f b*"); #else - unpack("t2", "-f 'b*'"); + unpack("t2", "--no-preserve-owner -f 'b*'"); #endif - 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)); + assertFileExists("t2/a123"); + assertFileExists("t2/a234"); + assertFileNotExists("t2/b123"); + assertFileNotExists("t2/b234"); } diff --git a/usr.bin/cpio/test/test_option_help.c b/usr.bin/cpio/test/test_option_help.c index b9433a4..5623430 100644 --- a/usr.bin/cpio/test/test_option_help.c +++ b/usr.bin/cpio/test/test_option_help.c @@ -51,6 +51,7 @@ DEFINE_TEST(test_option_help) /* Exercise --help option. */ r = systemf("%s --help >help.stdout 2>help.stderr", testprog); + assertEqualInt(r, 0); failure("--help should generate nothing to stderr."); assertEmptyFile("help.stderr"); /* Help message should start with name of program. */ @@ -67,6 +68,7 @@ DEFINE_TEST(test_option_help) /* -h option should generate the same output. */ r = systemf("%s -h >h.stdout 2>h.stderr", testprog); + assertEqualInt(r, 0); failure("-h should generate nothing to stderr."); assertEmptyFile("h.stderr"); failure("stdout should be same for -h and --help"); @@ -74,6 +76,7 @@ DEFINE_TEST(test_option_help) /* -W help should be another synonym. */ r = systemf("%s -W help >Whelp.stdout 2>Whelp.stderr", testprog); + assertEqualInt(r, 0); failure("-W help should generate nothing to stderr."); assertEmptyFile("Whelp.stderr"); failure("stdout should be same for -W help and --help"); diff --git a/usr.bin/cpio/test/test_option_ell.c b/usr.bin/cpio/test/test_option_l.c index 36bb0ac..5c76e68 100644 --- a/usr.bin/cpio/test/test_option_ell.c +++ b/usr.bin/cpio/test/test_option_l.c @@ -25,26 +25,12 @@ #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) +DEFINE_TEST(test_option_l) { - 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)); + assertMakeFile("f", 0644, "a"); /* Copy the file to the "copy" dir. */ r = systemf("echo f | %s -pd copy >copy.out 2>copy.err", @@ -52,8 +38,7 @@ DEFINE_TEST(test_option_ell) 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); + assertIsNotHardlink("f", "copy/f"); /* Copy the file to the "link" dir with the -l option. */ r = systemf("echo f | %s -pld link >link.out 2>link.err", @@ -61,6 +46,5 @@ DEFINE_TEST(test_option_ell) 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); + assertIsHardlink("f", "link/f"); } diff --git a/usr.bin/cpio/err.c b/usr.bin/cpio/test/test_option_lzma.c index c74e097..c6e3353 100644 --- a/usr.bin/cpio/err.c +++ b/usr.bin/cpio/test/test_option_lzma.c @@ -6,8 +6,7 @@ * 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 - * in this position and unchanged. + * 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. @@ -23,52 +22,35 @@ * (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 "cpio_platform.h" +#include "test.h" __FBSDID("$FreeBSD$"); -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif -#include <stdio.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include "err.h" - -const char *progname; - -static void -vwarnc(int code, const char *fmt, va_list ap) -{ - fprintf(stderr, "%s: ", progname); - vfprintf(stderr, fmt, ap); - if (code != 0) - fprintf(stderr, ": %s", strerror(code)); - fprintf(stderr, "\n"); -} - -void -warnc(int code, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vwarnc(code, fmt, ap); - va_end(ap); -} - -void -errc(int eval, int code, const char *fmt, ...) +DEFINE_TEST(test_option_lzma) { - va_list ap; - - va_start(ap, fmt); - vwarnc(code, fmt, ap); - va_end(ap); - exit(eval); + char *p; + int r; + size_t s; + + /* Create a file. */ + assertMakeFile("f", 0644, "a"); + + /* Archive it with lzma compression. */ + r = systemf("echo f | %s -o --lzma >archive.out 2>archive.err", + testprog); + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (r != 0) { + if (strstr(p, "compression not available") != NULL) { + skipping("This version of bsdcpio was compiled " + "without lzma support"); + return; + } + failure("--lzma option is broken"); + assertEqualInt(r, 0); + return; + } + /* Check that the archive file has an lzma signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "\x5d\00\00", 3); } diff --git a/usr.bin/cpio/test/test_option_m.c b/usr.bin/cpio/test/test_option_m.c index 7f8e901..de880b2 100644 --- a/usr.bin/cpio/test/test_option_m.c +++ b/usr.bin/cpio/test/test_option_m.c @@ -28,9 +28,7 @@ __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 @@ -38,33 +36,28 @@ DEFINE_TEST(test_option_m) */ /* Restored without -m, the result should have a current mtime. */ - assertEqualInt(0, mkdir("without-m", 0755)); - assertEqualInt(0, chdir("without-m")); + assertMakeDir("without-m", 0755); + assertChdir("without-m"); extract_reference_file("test_option_m.cpio"); - r = systemf("%s -i < test_option_m.cpio >out 2>err", testprog); - now = time(NULL); + r = systemf("%s --no-preserve-owner -i < test_option_m.cpio >out 2>err", testprog); assertEqualInt(r, 0); assertEmptyFile("out"); assertTextFileContents("1 block\n", "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); + assertFileMtimeRecent("file"); /* With -m, it should have an mtime in 1970. */ - assertEqualInt(0, chdir("..")); - assertEqualInt(0, mkdir("with-m", 0755)); - assertEqualInt(0, chdir("with-m")); + assertChdir(".."); + assertMakeDir("with-m", 0755); + assertChdir("with-m"); extract_reference_file("test_option_m.cpio"); - r = systemf("%s -im < test_option_m.cpio >out 2>err", testprog); - now = time(NULL); + r = systemf("%s --no-preserve-owner -im < test_option_m.cpio >out 2>err", testprog); assertEqualInt(r, 0); assertEmptyFile("out"); assertTextFileContents("1 block\n", "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); + assertFileMtime("file", 1, 0); } diff --git a/usr.bin/cpio/test/test_option_t.c b/usr.bin/cpio/test/test_option_t.c index 1c9af19..4427bb3 100644 --- a/usr.bin/cpio/test/test_option_t.c +++ b/usr.bin/cpio/test/test_option_t.c @@ -71,12 +71,22 @@ DEFINE_TEST(test_option_t) testprog); assertEqualInt(r, 0); assertTextFileContents("1 block\n", "itnv.err"); - extract_reference_file("test_option_tnv.stdout"); - /* This does work because numeric IDs come from archive. */ - /* Unfortunately, the timestamp still gets localized, so - * we can't just compare against a fixed result. */ - /* TODO: Fix this. */ - /* assertEqualFile("itnv.out", "test_option_tnv.stdout"); */ + p = slurpfile(NULL, "itnv.out"); + /* Since -n uses numeric UID/GID, this part should be the + * same on every system. */ + assertEqualMem(p, "-rw-r--r-- 1 1000 1000 0 ",42); + /* Date varies depending on local timezone. */ + if (memcmp(p + 42, "Dec 31 1969", 12) == 0) { + /* East of Greenwich we get Dec 31, 1969. */ + } else { + /* West of Greenwich get Jan 1, 1970 */ + assertEqualMem(p + 42, "Jan ", 4); + /* Some systems format "Jan 01", some "Jan 1" */ + assert(p[46] == ' ' || p[46] == '0'); + assertEqualMem(p + 47, "1 1970 ", 8); + } + assertEqualMem(p + 54, " file", 5); + free(p); /* But "-n" without "-t" is an error. */ assert(0 != systemf("%s -in < test_option_t.cpio >in.out 2>in.err", diff --git a/usr.bin/cpio/test/test_option_u.c b/usr.bin/cpio/test/test_option_u.c index 7d2edff..08058aa 100644 --- a/usr.bin/cpio/test/test_option_u.c +++ b/usr.bin/cpio/test/test_option_u.c @@ -23,10 +23,10 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -#if defined(_WIN32) && !defined(__CYGWIN__) -#include <sys/utime.h> -#else +#if defined(HAVE_UTIME_H) #include <utime.h> +#elif defined(HAVE_SYS_UTIME_H) +#include <sys/utime.h> #endif __FBSDID("$FreeBSD$"); @@ -35,14 +35,10 @@ 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); + assertMakeFile("f", 0644, "a"); /* Copy the file to the "copy" dir. */ r = systemf("echo f | %s -pd copy >copy.out 2>copy.err", @@ -55,10 +51,7 @@ DEFINE_TEST(test_option_u) 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); + assertMakeFile("f", 0644, "b"); /* Set the mtime to the distant past. */ memset(×, 0, sizeof(times)); diff --git a/usr.bin/cpio/test/test_option_version.c b/usr.bin/cpio/test/test_option_version.c index 8a25248..7345da1 100644 --- a/usr.bin/cpio/test/test_option_version.c +++ b/usr.bin/cpio/test/test_option_version.c @@ -74,14 +74,14 @@ verify(const char *p, size_t 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. */ + /* All terminated by end-of-line: \r, \r\n, or \n */ assert(s >= 1); failure("Version: %s", p); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualMem(q, "\r\n", 2); -#else - assertEqualMem(q, "\n", 1); -#endif + if (*q == '\x0d') { + if (q[1] != '\0') + assertEqualMem(q, "\x0d\x0a", 2); + } else + assertEqualMem(q, "\x0a", 1); } diff --git a/usr.bin/cpio/test/test_option_y.c b/usr.bin/cpio/test/test_option_y.c index 5cefaed..8e81ee7 100644 --- a/usr.bin/cpio/test/test_option_y.c +++ b/usr.bin/cpio/test/test_option_y.c @@ -28,32 +28,30 @@ __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); + assertMakeFile("f", 0644, "a"); /* Archive it with bzip2 compression. */ r = systemf("echo f | %s -oy >archive.out 2>archive.err", testprog); - failure("-y (bzip) option seems to be broken"); - if (assertEqualInt(r, 0)) { - p = slurpfile(&s, "archive.err"); - p[s] = '\0'; - if (strstr(p, "bzip2 compression not supported") != NULL) { + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (r != 0) { + if (strstr(p, "compression not available") != NULL) { skipping("This version of bsdcpio was compiled " "without bzip2 support"); - } else { - assertTextFileContents("1 block\n", "archive.err"); - /* Check that the archive file has a bzip2 signature. */ - p = slurpfile(&s, "archive.out"); - assert(s > 2); - assertEqualMem(p, "BZh9", 4); + return; } + failure("-y option is broken"); + assertEqualInt(r, 0); + return; } + assertTextFileContents("1 block\n", "archive.err"); + /* 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 index 2057912..91d37ac 100644 --- a/usr.bin/cpio/test/test_option_z.c +++ b/usr.bin/cpio/test/test_option_z.c @@ -28,32 +28,29 @@ __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); + assertMakeFile("f", 0644, "a"); /* 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) { - p = slurpfile(&s, "archive.err"); - p[s] = '\0'; - if (strstr(p, "gzip compression not supported") != NULL) { + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (r != 0) { + if (strstr(p, "compression not available") != NULL) { skipping("This version of bsdcpio was compiled " "without gzip support"); - } else { - /* Check that the archive file has a gzip signature. */ - p = slurpfile(&s, "archive.out"); - assert(s > 2); - assertEqualMem(p, "\x1f\x8b\x08\x00", 4); + return; } + failure("-z option is broken"); + assertEqualInt(r, 0); + return; } + /* Check that the archive file has a gzip signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 4); + 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 index 06fabd9..d07724e 100644 --- a/usr.bin/cpio/test/test_owner_parse.c +++ b/usr.bin/cpio/test/test_owner_parse.c @@ -28,7 +28,12 @@ __FBSDID("$FreeBSD$"); #include "../cpio.h" #include "err.h" -#if defined(__CYGWIN__) +#if !defined(_WIN32) +#define ROOT "root" +static int root_uids[] = { 0 }; +/* Solaris 9 root has gid 1 (other) */ +static int root_gids[] = { 0, 1 }; +#elif defined(__CYGWIN__) /* On cygwin, the Administrator user most likely exists (unless * it has been renamed or is in a non-English localization), but * its primary group membership depends on how the user set up @@ -40,12 +45,9 @@ __FBSDID("$FreeBSD$"); #define ROOT "Administrator" static int root_uids[] = { 500 }; static int root_gids[] = { 513, 545, 544 }; -#else -#define ROOT "root" -static int root_uids[] = { 0 }; -static int root_gids[] = { 0 }; #endif +#if defined(ROOT) static int int_in_list(int i, int *l, size_t n) { @@ -55,54 +57,54 @@ int_in_list(int i, int *l, size_t n) failure("%d", i); return (0); } +#endif DEFINE_TEST(test_owner_parse) { -#if defined(_WIN32) && !defined(__CYGWIN__) - /* TODO: Does this need cygwin style handling of uid/gid ? */ - skipping("Windows cannot handle uid/gid as UNIX like system"); +#if !defined(ROOT) + skipping("No uid/gid configuration for this OS"); #else int uid, gid; - assertEqualInt(0, owner_parse(ROOT, &uid, &gid)); + assert(NULL == owner_parse(ROOT, &uid, &gid)); assert(int_in_list(uid, root_uids, sizeof(root_uids)/sizeof(root_uids[0]))); assertEqualInt(-1, gid); - assertEqualInt(0, owner_parse(ROOT ":", &uid, &gid)); + assert(NULL == owner_parse(ROOT ":", &uid, &gid)); assert(int_in_list(uid, root_uids, sizeof(root_uids)/sizeof(root_uids[0]))); assert(int_in_list(gid, root_gids, sizeof(root_gids)/sizeof(root_gids[0]))); - assertEqualInt(0, owner_parse(ROOT ".", &uid, &gid)); + assert(NULL == owner_parse(ROOT ".", &uid, &gid)); assert(int_in_list(uid, root_uids, sizeof(root_uids)/sizeof(root_uids[0]))); assert(int_in_list(gid, root_gids, sizeof(root_gids)/sizeof(root_gids[0]))); - assertEqualInt(0, owner_parse("111", &uid, &gid)); + assert(NULL == owner_parse("111", &uid, &gid)); assertEqualInt(111, uid); assertEqualInt(-1, gid); - assertEqualInt(0, owner_parse("112:", &uid, &gid)); + assert(NULL == owner_parse("112:", &uid, &gid)); assertEqualInt(112, uid); /* Can't assert gid, since we don't know gid for user #112. */ - assertEqualInt(0, owner_parse("113.", &uid, &gid)); + assert(NULL == owner_parse("113.", &uid, &gid)); assertEqualInt(113, uid); /* Can't assert gid, since we don't know gid for user #113. */ - assertEqualInt(0, owner_parse(":114", &uid, &gid)); + assert(NULL == owner_parse(":114", &uid, &gid)); assertEqualInt(-1, uid); assertEqualInt(114, gid); - assertEqualInt(0, owner_parse(".115", &uid, &gid)); + assert(NULL == owner_parse(".115", &uid, &gid)); assertEqualInt(-1, uid); assertEqualInt(115, gid); - assertEqualInt(0, owner_parse("116:117", &uid, &gid)); + assert(NULL == owner_parse("116:117", &uid, &gid)); assertEqualInt(116, uid); assertEqualInt(117, gid); @@ -112,19 +114,9 @@ DEFINE_TEST(test_owner_parse) * 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. - */ - - cpio_progname = "Ignore this message"; - assertEqualInt(1, owner_parse(":nonexistentgroup", &uid, &gid)); - assertEqualInt(1, owner_parse(ROOT ":nonexistentgroup", &uid, &gid)); - assertEqualInt(1, + assert(NULL != owner_parse(":nonexistentgroup", &uid, &gid)); + assert(NULL != owner_parse(ROOT ":nonexistentgroup", &uid, &gid)); + assert(NULL != owner_parse("nonexistentuser:nonexistentgroup", &uid, &gid)); #endif } diff --git a/usr.bin/cpio/test/test_passthrough_dotdot.c b/usr.bin/cpio/test/test_passthrough_dotdot.c index bcb5a6a..58d8234 100644 --- a/usr.bin/cpio/test/test_passthrough_dotdot.c +++ b/usr.bin/cpio/test/test_passthrough_dotdot.c @@ -31,33 +31,28 @@ __FBSDID("$FreeBSD$"); DEFINE_TEST(test_passthrough_dotdot) { - struct stat st; - int fd, r; - int filelist; - int oldumask; + int r; + FILE *filelist; - oldumask = umask(0); + assertUmask(0); /* * Create an assortment of files on disk. */ - filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + filelist = fopen("filelist", "w"); /* Directory. */ - assertEqualInt(0, mkdir("dir", 0755)); - assertEqualInt(0, chdir("dir")); + assertMakeDir("dir", 0755); + assertChdir("dir"); - write(filelist, ".\n", 2); + fprintf(filelist, ".\n"); /* File with 10 bytes content. */ - fd = open("file", O_CREAT | O_WRONLY, 0642); - assert(fd >= 0); - assertEqualInt(10, write(fd, "123456789", 10)); - close(fd); - write(filelist, "file\n", 5); + assertMakeFile("file", 0642, "1234567890"); + fprintf(filelist, "file\n"); /* All done. */ - close(filelist); + fclose(filelist); /* @@ -68,26 +63,14 @@ DEFINE_TEST(test_passthrough_dotdot) failure("Error invoking %s -pd ..", testprog); assertEqualInt(r, 0); - assertEqualInt(0, chdir("..")); + assertChdir(".."); /* Verify stderr and stdout. */ assertTextFileContents("../.\n../file\n1 block\n", "stderr"); assertEmptyFile("stdout"); /* Regular file. */ - r = lstat("file", &st); - failure("Failed to stat file, errno=%d", errno); - assertEqualInt(r, 0); - if (r == 0) { - assert(S_ISREG(st.st_mode)); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualInt(0600, st.st_mode & 0700); -#else - assertEqualInt(0642, st.st_mode & 0777); -#endif - assertEqualInt(10, st.st_size); - assertEqualInt(1, st.st_nlink); - } - - umask(oldumask); + assertIsReg("file", 0642); + assertFileSize("file", 10); + assertFileNLinks("file", 1); } diff --git a/usr.bin/cpio/test/test_passthrough_reverse.c b/usr.bin/cpio/test/test_passthrough_reverse.c index a7695ed..42df75a 100644 --- a/usr.bin/cpio/test/test_passthrough_reverse.c +++ b/usr.bin/cpio/test/test_passthrough_reverse.c @@ -36,33 +36,28 @@ __FBSDID("$FreeBSD$"); DEFINE_TEST(test_passthrough_reverse) { - struct stat st; - int fd, r; - int filelist; - int oldumask; + int r; + FILE *filelist; - oldumask = umask(0); + assertUmask(0); /* * Create an assortment of files on disk. */ - filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + filelist = fopen("filelist", "w"); /* Directory. */ - assertEqualInt(0, mkdir("dir", 0743)); + assertMakeDir("dir", 0743); /* File with 10 bytes content. */ - fd = open("dir/file", O_CREAT | O_WRONLY, 0644); - assert(fd >= 0); - assertEqualInt(10, write(fd, "123456789", 10)); - close(fd); - write(filelist, "dir/file\n", 9); + assertMakeFile("dir/file", 0644, "1234567890"); + fprintf(filelist, "dir/file\n"); /* Write dir last. */ - write(filelist, "dir\n", 4); + fprintf(filelist, "dir\n"); /* All done. */ - close(filelist); + fclose(filelist); /* @@ -72,7 +67,7 @@ DEFINE_TEST(test_passthrough_reverse) failure("Error invoking %s -pd out", testprog); assertEqualInt(r, 0); - assertEqualInt(0, chdir("out")); + assertChdir("out"); /* Verify stderr and stdout. */ assertTextFileContents("out/dir/file\nout/dir\n1 block\n", @@ -80,33 +75,11 @@ DEFINE_TEST(test_passthrough_reverse) assertEmptyFile("../stdout"); /* dir */ - r = lstat("dir", &st); - if (r == 0) { - assertEqualInt(r, 0); - assert(S_ISDIR(st.st_mode)); - failure("st.st_mode=0%o", st.st_mode); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualInt(0700, st.st_mode & 0700); -#else - assertEqualInt(0743, st.st_mode & 0777); -#endif - } + assertIsDir("dir", 0743); /* Regular file. */ - r = lstat("dir/file", &st); - failure("Failed to stat dir/file, errno=%d", errno); - assertEqualInt(r, 0); - if (r == 0) { - assert(S_ISREG(st.st_mode)); -#if defined(_WIN32) && !defined(__CYGWIN__) - assertEqualInt(0600, st.st_mode & 0700); -#else - assertEqualInt(0644, st.st_mode & 0777); -#endif - assertEqualInt(10, st.st_size); - assertEqualInt(1, st.st_nlink); - } - - umask(oldumask); + assertIsReg("dir/file", 0644); + assertFileSize("dir/file", 10); + assertFileNLinks("dir/file", 1); } diff --git a/usr.bin/cpio/test/test_pathmatch.c b/usr.bin/cpio/test/test_pathmatch.c index a596eda..177c2bc 100644 --- a/usr.bin/cpio/test/test_pathmatch.c +++ b/usr.bin/cpio/test/test_pathmatch.c @@ -25,7 +25,7 @@ #include "test.h" __FBSDID("$FreeBSD$"); -#include "../pathmatch.h" +#include "pathmatch.h" /* * Verify that the pattern matcher implements the wildcard logic specified @@ -45,126 +45,126 @@ __FBSDID("$FreeBSD$"); DEFINE_TEST(test_pathmatch) { - assertEqualInt(1, pathmatch("a/b/c", "a/b/c", 0)); - assertEqualInt(0, pathmatch("a/b/", "a/b/c", 0)); - assertEqualInt(0, pathmatch("a/b", "a/b/c", 0)); - assertEqualInt(0, pathmatch("a/b/c", "a/b/", 0)); - assertEqualInt(0, pathmatch("a/b/c", "a/b", 0)); + assertEqualInt(1, lafe_pathmatch("a/b/c", "a/b/c", 0)); + assertEqualInt(0, lafe_pathmatch("a/b/", "a/b/c", 0)); + assertEqualInt(0, lafe_pathmatch("a/b", "a/b/c", 0)); + assertEqualInt(0, lafe_pathmatch("a/b/c", "a/b/", 0)); + assertEqualInt(0, lafe_pathmatch("a/b/c", "a/b", 0)); /* Empty pattern only matches empty string. */ - assertEqualInt(1, pathmatch("","", 0)); - assertEqualInt(0, pathmatch("","a", 0)); - assertEqualInt(1, pathmatch("*","", 0)); - assertEqualInt(1, pathmatch("*","a", 0)); - assertEqualInt(1, pathmatch("*","abcd", 0)); + assertEqualInt(1, lafe_pathmatch("","", 0)); + assertEqualInt(0, lafe_pathmatch("","a", 0)); + assertEqualInt(1, lafe_pathmatch("*","", 0)); + assertEqualInt(1, lafe_pathmatch("*","a", 0)); + assertEqualInt(1, lafe_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)); + assertEqualInt(1, lafe_pathmatch("*","abcd/efgh/ijkl", 0)); + assertEqualInt(1, lafe_pathmatch("abcd*efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(1, lafe_pathmatch("abcd***efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(1, lafe_pathmatch("abcd***/efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(0, lafe_pathmatch("?", "", 0)); + assertEqualInt(0, lafe_pathmatch("?", "\0", 0)); + assertEqualInt(1, lafe_pathmatch("?", "a", 0)); + assertEqualInt(0, lafe_pathmatch("?", "ab", 0)); + assertEqualInt(1, lafe_pathmatch("?", ".", 0)); + assertEqualInt(1, lafe_pathmatch("?", "?", 0)); + assertEqualInt(1, lafe_pathmatch("a", "a", 0)); + assertEqualInt(0, lafe_pathmatch("a", "ab", 0)); + assertEqualInt(0, lafe_pathmatch("a", "ab", 0)); + assertEqualInt(1, lafe_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, lafe_pathmatch("a?c", "a/c", 0)); + assertEqualInt(1, lafe_pathmatch("a?*c*", "a/c", 0)); + assertEqualInt(1, lafe_pathmatch("*a*", "a/c", 0)); + assertEqualInt(1, lafe_pathmatch("*a*", "/a/c", 0)); + assertEqualInt(1, lafe_pathmatch("*a*", "defaaaaaaa", 0)); + assertEqualInt(0, lafe_pathmatch("a*", "defghi", 0)); + assertEqualInt(0, lafe_pathmatch("*a*", "defghi", 0)); /* Character classes */ - 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(0, pathmatch("abc[d-fh-k]", "abca", 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)); + assertEqualInt(1, lafe_pathmatch("abc[def", "abc[def", 0)); + assertEqualInt(0, lafe_pathmatch("abc[def]", "abc[def", 0)); + assertEqualInt(0, lafe_pathmatch("abc[def", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[def]", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[def]", "abce", 0)); + assertEqualInt(1, lafe_pathmatch("abc[def]", "abcf", 0)); + assertEqualInt(0, lafe_pathmatch("abc[def]", "abcg", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d*f]", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d*f]", "abc*", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d*f]", "abcdefghi", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d*", "abcdefghi", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d*", "abc[defghi", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-f]", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-f]", "abce", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-f]", "abcf", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d-f]", "abcg", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abca", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abce", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abcf", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abcg", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abch", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abci", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abcj", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abck", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abcl", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abc-", 0)); /* [] matches nothing, [!] is the same as ? */ - assertEqualInt(0, pathmatch("abc[]efg", "abcdefg", 0)); - assertEqualInt(0, pathmatch("abc[]efg", "abcqefg", 0)); - assertEqualInt(0, pathmatch("abc[]efg", "abcefg", 0)); - assertEqualInt(1, pathmatch("abc[!]efg", "abcdefg", 0)); - assertEqualInt(1, pathmatch("abc[!]efg", "abcqefg", 0)); - assertEqualInt(0, pathmatch("abc[!]efg", "abcefg", 0)); + assertEqualInt(0, lafe_pathmatch("abc[]efg", "abcdefg", 0)); + assertEqualInt(0, lafe_pathmatch("abc[]efg", "abcqefg", 0)); + assertEqualInt(0, lafe_pathmatch("abc[]efg", "abcefg", 0)); + assertEqualInt(1, lafe_pathmatch("abc[!]efg", "abcdefg", 0)); + assertEqualInt(1, lafe_pathmatch("abc[!]efg", "abcqefg", 0)); + assertEqualInt(0, lafe_pathmatch("abc[!]efg", "abcefg", 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)); + assertEqualInt(0, lafe_pathmatch("abc[d-fh-]", "abcl", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-]", "abch", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-fh-]", "abc-", 0)); + assertEqualInt(1, lafe_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)); + assertEqualInt(1, lafe_pathmatch("abc[\\]]", "abc]", 0)); + assertEqualInt(1, lafe_pathmatch("abc[\\]d]", "abc]", 0)); + assertEqualInt(1, lafe_pathmatch("abc[\\]d]", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d\\]]", "abc]", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d\\]]", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d]e]", "abcde]", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d\\]e]", "abc]", 0)); + assertEqualInt(0, lafe_pathmatch("abc[d\\]e]", "abcd]e", 0)); + assertEqualInt(0, lafe_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)); + assertEqualInt(1, lafe_pathmatch("abc[\\d-f]gh", "abcegh", 0)); + assertEqualInt(0, lafe_pathmatch("abc[\\d-f]gh", "abcggh", 0)); + assertEqualInt(0, lafe_pathmatch("abc[\\d-f]gh", "abc\\gh", 0)); + assertEqualInt(1, lafe_pathmatch("abc[d-\\f]gh", "abcegh", 0)); + assertEqualInt(1, lafe_pathmatch("abc[\\d-\\f]gh", "abcegh", 0)); + assertEqualInt(1, lafe_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)); + assertEqualInt(0, lafe_pathmatch("abc[d\\-f]gh", "abcegh", 0)); + assertEqualInt(1, lafe_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)); + assertEqualInt(0, lafe_pathmatch("abc[!d]", "abcd", 0)); + assertEqualInt(1, lafe_pathmatch("abc[!d]", "abce", 0)); + assertEqualInt(1, lafe_pathmatch("abc[!d]", "abcc", 0)); + assertEqualInt(0, lafe_pathmatch("abc[!d-z]", "abcq", 0)); + assertEqualInt(1, lafe_pathmatch("abc[!d-gi-z]", "abch", 0)); + assertEqualInt(1, lafe_pathmatch("abc[!fgijkl]", "abch", 0)); + assertEqualInt(0, lafe_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)); - assertEqualInt(1, pathmatch("abcd\\", "abcd\\", 0)); - assertEqualInt(0, pathmatch("abcd\\", "abcd\\[", 0)); - assertEqualInt(0, pathmatch("abcd\\", "abcde", 0)); - assertEqualInt(0, pathmatch("abcd\\[", "abcd\\", 0)); + assertEqualInt(0, lafe_pathmatch("abc\\[def]", "abc\\d", 0)); + assertEqualInt(1, lafe_pathmatch("abc\\[def]", "abc[def]", 0)); + assertEqualInt(0, lafe_pathmatch("abc\\\\[def]", "abc[def]", 0)); + assertEqualInt(0, lafe_pathmatch("abc\\\\[def]", "abc\\[def]", 0)); + assertEqualInt(1, lafe_pathmatch("abc\\\\[def]", "abc\\d", 0)); + assertEqualInt(1, lafe_pathmatch("abcd\\", "abcd\\", 0)); + assertEqualInt(0, lafe_pathmatch("abcd\\", "abcd\\[", 0)); + assertEqualInt(0, lafe_pathmatch("abcd\\", "abcde", 0)); + assertEqualInt(0, lafe_pathmatch("abcd\\[", "abcd\\", 0)); /* * Because '.' and '/' have special meanings, we can @@ -172,72 +172,72 @@ DEFINE_TEST(test_pathmatch) * differently. (But quoting a character with '\\' suppresses * special meanings!) */ - assertEqualInt(0, pathmatch("a/b/", "a/bc", 0)); - assertEqualInt(1, pathmatch("a/./b", "a/b", 0)); - assertEqualInt(0, pathmatch("a\\/./b", "a/b", 0)); - assertEqualInt(0, pathmatch("a/\\./b", "a/b", 0)); - assertEqualInt(0, pathmatch("a/.\\/b", "a/b", 0)); - assertEqualInt(0, pathmatch("a\\/\\.\\/b", "a/b", 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)); - assertEqualInt(1, pathmatch("./abc?def/", "abc/def/", 0)); + assertEqualInt(0, lafe_pathmatch("a/b/", "a/bc", 0)); + assertEqualInt(1, lafe_pathmatch("a/./b", "a/b", 0)); + assertEqualInt(0, lafe_pathmatch("a\\/./b", "a/b", 0)); + assertEqualInt(0, lafe_pathmatch("a/\\./b", "a/b", 0)); + assertEqualInt(0, lafe_pathmatch("a/.\\/b", "a/b", 0)); + assertEqualInt(0, lafe_pathmatch("a\\/\\.\\/b", "a/b", 0)); + assertEqualInt(1, lafe_pathmatch("./abc/./def/", "abc/def/", 0)); + assertEqualInt(1, lafe_pathmatch("abc/def", "./././abc/./def", 0)); + assertEqualInt(1, lafe_pathmatch("abc/def/././//", "./././abc/./def/", 0)); + assertEqualInt(1, lafe_pathmatch(".////abc/.//def", "./././abc/./def", 0)); + assertEqualInt(1, lafe_pathmatch("./abc?def/", "abc/def/", 0)); failure("\"?./\" is not the same as \"/./\""); - assertEqualInt(0, pathmatch("./abc?./def/", "abc/def/", 0)); + assertEqualInt(0, lafe_pathmatch("./abc?./def/", "abc/def/", 0)); failure("Trailing '/' should match no trailing '/'"); - assertEqualInt(1, pathmatch("./abc/./def/", "abc/def", 0)); + assertEqualInt(1, lafe_pathmatch("./abc/./def/", "abc/def", 0)); failure("Trailing '/./' is still the same directory."); - assertEqualInt(1, pathmatch("./abc/./def/./", "abc/def", 0)); + assertEqualInt(1, lafe_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)); + assertEqualInt(1, lafe_pathmatch("./abc/./def/.", "abc/def", 0)); + assertEqualInt(1, lafe_pathmatch("./abc/./def", "abc/def/", 0)); failure("Trailing '/./' is still the same directory."); - assertEqualInt(1, pathmatch("./abc/./def", "abc/def/./", 0)); + assertEqualInt(1, lafe_pathmatch("./abc/./def", "abc/def/./", 0)); failure("Trailing '/.' is still the same directory."); - assertEqualInt(1, pathmatch("./abc*/./def", "abc/def/.", 0)); + assertEqualInt(1, lafe_pathmatch("./abc*/./def", "abc/def/.", 0)); /* Matches not anchored at beginning. */ assertEqualInt(0, - pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + lafe_pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); assertEqualInt(1, - pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + lafe_pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_START)); assertEqualInt(0, - pathmatch("^bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + lafe_pathmatch("^bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); assertEqualInt(1, - pathmatch("b/c/d", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + lafe_pathmatch("b/c/d", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); assertEqualInt(0, - pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + lafe_pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); assertEqualInt(0, - pathmatch("^b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + lafe_pathmatch("^b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); /* Matches not anchored at end. */ assertEqualInt(0, - pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("abcd", "abcd/", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("abcd", "abcd/", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("abcd", "abcd/.", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("abcd", "abcd/.", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(0, - pathmatch("abc", "abcd", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("abc", "abcd", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("a/b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(0, - pathmatch("a/b/c$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("a/b/c$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("a/b/c$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("a/b/c/", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c/", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(0, - pathmatch("a/b/c/$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c/$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("a/b/c/$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c/$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(1, - pathmatch("a/b/c/$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("a/b/c/$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); assertEqualInt(0, - pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + lafe_pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); } |