Date: Fri, 17 Apr 2009 04:04:57 +0000 (UTC) From: Tim Kientzle <kientzle@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r191192 - in head/usr.bin/cpio: . test Message-ID: <200904170404.n3H44vIV007538@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kientzle Date: Fri Apr 17 04:04:57 2009 New Revision: 191192 URL: http://svn.freebsd.org/changeset/base/191192 Log: Merge from libarchive.googlecode.com: * Lots of new tests. * New -n / --numeric-uid-gid option * More sanity-checking of arguments * Various Windows portability improvements * Sync up version number to 2.7.0 Modified: head/usr.bin/cpio/Makefile head/usr.bin/cpio/bsdcpio.1 head/usr.bin/cpio/cmdline.c head/usr.bin/cpio/cpio.c head/usr.bin/cpio/cpio.h head/usr.bin/cpio/cpio_platform.h head/usr.bin/cpio/pathmatch.c head/usr.bin/cpio/pathmatch.h head/usr.bin/cpio/test/main.c head/usr.bin/cpio/test/test.h head/usr.bin/cpio/test/test_0.c head/usr.bin/cpio/test/test_basic.c head/usr.bin/cpio/test/test_format_newc.c head/usr.bin/cpio/test/test_gcpio_compat.c head/usr.bin/cpio/test/test_option_a.c head/usr.bin/cpio/test/test_option_c.c head/usr.bin/cpio/test/test_option_d.c head/usr.bin/cpio/test/test_option_f.c head/usr.bin/cpio/test/test_option_m.c head/usr.bin/cpio/test/test_option_t.c head/usr.bin/cpio/test/test_option_u.c head/usr.bin/cpio/test/test_option_version.c head/usr.bin/cpio/test/test_option_y.c head/usr.bin/cpio/test/test_option_z.c head/usr.bin/cpio/test/test_owner_parse.c head/usr.bin/cpio/test/test_passthrough_dotdot.c head/usr.bin/cpio/test/test_passthrough_reverse.c head/usr.bin/cpio/test/test_pathmatch.c Modified: head/usr.bin/cpio/Makefile ============================================================================== --- head/usr.bin/cpio/Makefile Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/Makefile Fri Apr 17 04:04:57 2009 (r191192) @@ -3,13 +3,13 @@ .include <bsd.own.mk> PROG= bsdcpio -BSDCPIO_VERSION_STRING=1.1.0 +BSDCPIO_VERSION_STRING=2.7.0 SRCS= cpio.c cmdline.c err.c matching.c pathmatch.c WARNS?= 6 DPADD= ${LIBARCHIVE} ${LIBZ} ${LIBBZ2} CFLAGS+= -DBSDCPIO_VERSION_STRING=\"${BSDCPIO_VERSION_STRING}\" CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\" -LDADD+= -larchive -lz -lbz2 +LDADD+= -larchive -lz -lbz2 -lmd -lcrypto .if ${MK_GNU_CPIO} != "yes" SYMLINKS=bsdcpio ${BINDIR}/cpio Modified: head/usr.bin/cpio/bsdcpio.1 ============================================================================== --- head/usr.bin/cpio/bsdcpio.1 Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/bsdcpio.1 Fri Apr 17 04:04:57 2009 (r191192) @@ -167,6 +167,15 @@ instead of copying. (i and p modes) Set file modification time on created files to match those in the source. +.It Fl n +(i mode, only with +.Fl t ) +Display numeric uid and gid. +By default, +.Nm +displays the user and group names when they are provided in the +archive, or looks up the user and group names in the system +password database. .It Fl O Ar file Write archive to .Ar file . Modified: head/usr.bin/cpio/cmdline.c ============================================================================== --- head/usr.bin/cpio/cmdline.c Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/cmdline.c Fri Apr 17 04:04:57 2009 (r191192) @@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$"); /* * Short options for cpio. Please keep this sorted. */ -static const char *short_options = "0AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz"; +static const char *short_options = "0AaBC:F:O:cdE:f:H:hijLlmnopR:rtuvW:yZz"; /* * Long options for cpio. Please keep this sorted. @@ -71,6 +71,7 @@ static const struct option { { "make-directories", 0, 'd' }, { "no-preserve-owner", 0, OPTION_NO_PRESERVE_OWNER }, { "null", 0, '0' }, + { "numeric-uid-gid", 0, 'n' }, { "owner", 1, 'R' }, { "pass-through", 0, 'p' }, { "preserve-modification-time", 0, 'm' }, Modified: head/usr.bin/cpio/cpio.c ============================================================================== --- head/usr.bin/cpio/cpio.c Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/cpio.c Fri Apr 17 04:04:57 2009 (r191192) @@ -32,9 +32,15 @@ __FBSDID("$FreeBSD$"); #include <archive.h> #include <archive_entry.h> +#ifdef HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif #ifdef HAVE_ERRNO_H #include <errno.h> #endif @@ -60,6 +66,12 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif #include "cpio.h" #include "matching.h" @@ -94,7 +106,7 @@ static void mode_in(struct cpio *); static void mode_list(struct cpio *); static void mode_out(struct cpio *); static void mode_pass(struct cpio *, const char *); -static void restore_time(struct cpio *, struct archive_entry *, +static int restore_time(struct cpio *, struct archive_entry *, const char *, int fd); static void usage(void); static void version(void); @@ -112,12 +124,22 @@ main(int argc, char *argv[]) memset(cpio, 0, sizeof(*cpio)); cpio->buff = buff; cpio->buff_size = sizeof(buff); +#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); +#endif /* Need cpio_progname before calling cpio_warnc. */ if (*argv == NULL) cpio_progname = "bsdcpio"; else { +#if defined(_WIN32) && !defined(__CYGWIN__) + cpio_progname = strrchr(*argv, '\\'); +#else cpio_progname = strrchr(*argv, '/'); +#endif if (cpio_progname != NULL) cpio_progname++; else @@ -132,8 +154,6 @@ main(int argc, char *argv[]) cpio->mode = '\0'; cpio->verbose = 0; cpio->compress = '\0'; - /* TODO: Implement old binary format in libarchive, use that here. */ - cpio->format = "odc"; /* Default format */ cpio->extract_flags = ARCHIVE_EXTRACT_NO_AUTODIR; cpio->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS; @@ -141,7 +161,11 @@ main(int argc, char *argv[]) cpio->extract_flags |= ARCHIVE_EXTRACT_PERM; cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; cpio->extract_flags |= ARCHIVE_EXTRACT_ACL; +#if defined(_WIN32) || defined(__CYGWIN__) + if (bsdcpio_is_privileged()) +#else if (geteuid() == 0) +#endif cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; cpio->bytes_per_block = 512; cpio->filename = NULL; @@ -190,6 +214,9 @@ main(int argc, char *argv[]) cpio->filename = cpio->optarg; break; case 'i': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -i and -%c", cpio->mode); cpio->mode = opt; break; case OPTION_INSECURE: @@ -205,6 +232,9 @@ main(int argc, char *argv[]) case 'm': /* POSIX 1997 */ cpio->extract_flags |= ARCHIVE_EXTRACT_TIME; break; + case 'n': /* GNU cpio */ + cpio->option_numeric_uid_gid = 1; + break; case OPTION_NO_PRESERVE_OWNER: /* GNU cpio */ cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; break; @@ -212,9 +242,15 @@ main(int argc, char *argv[]) cpio->filename = cpio->optarg; break; case 'o': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -o and -%c", cpio->mode); cpio->mode = opt; break; case 'p': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -p and -%c", cpio->mode); cpio->mode = opt; cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; break; @@ -254,23 +290,56 @@ main(int argc, char *argv[]) break; #endif case 'y': /* tar convention */ +#if HAVE_LIBBZ2 cpio->compress = opt; +#else + cpio_warnc(0, "bzip2 compression not supported by " + "this version of bsdcpio"); +#endif break; case 'Z': /* tar convention */ cpio->compress = opt; break; case 'z': /* tar convention */ +#if HAVE_LIBZ cpio->compress = opt; +#else + cpio_warnc(0, "gzip compression not supported by " + "this version of bsdcpio"); +#endif break; default: usage(); } } - /* TODO: Sanity-check args, error out on nonsensical combinations. */ + /* + * Sanity-check args, error out on nonsensical combinations. + */ + /* -t implies -i if no mode was specified. */ + if (cpio->option_list && cpio->mode == '\0') + cpio->mode = 'i'; + /* -t requires -i */ + if (cpio->option_list && cpio->mode != 'i') + cpio_errc(1, 0, "Option -t requires -i", cpio->mode); + /* -n requires -it */ + if (cpio->option_numeric_uid_gid && !cpio->option_list) + cpio_errc(1, 0, "Option -n requires -it"); + /* Can only specify format when writing */ + if (cpio->format != NULL && cpio->mode != 'o') + cpio_errc(1, 0, "Option --format requires -o"); + /* -l requires -p */ + if (cpio->option_link && cpio->mode != 'p') + cpio_errc(1, 0, "Option -l requires -p"); + /* TODO: Flag other nonsensical combinations. */ switch (cpio->mode) { case 'o': + /* TODO: Implement old binary format in libarchive, + use that here. */ + if (cpio->format == NULL) + cpio->format = "odc"; /* Default format */ + mode_out(cpio); break; case 'i': @@ -321,7 +390,12 @@ static const char *long_help_msg = "Common Options:\n" " -v Verbose\n" "Create: %p -o [options] < [list of files] > [archive]\n" - " -z, -y Compress archive with gzip/bzip2\n" +#ifdef HAVE_BZLIB_H + " -y Compress archive with bzip2\n" +#endif +#ifdef HAVE_ZLIB_H + " -z Compress archive with gzip\n" +#endif " --format {odc|newc|ustar} Select archive format\n" "List: %p -it < [archive]\n" "Extract: %p -i [options] < [archive]\n"; @@ -387,12 +461,16 @@ mode_out(struct cpio *cpio) if (cpio->archive == NULL) cpio_errc(1, 0, "Failed to allocate archive object"); switch (cpio->compress) { +#ifdef HAVE_BZLIB_H case 'j': case 'y': archive_write_set_compression_bzip2(cpio->archive); break; +#endif +#ifdef HAVE_ZLIB_H case 'z': archive_write_set_compression_gzip(cpio->archive); break; +#endif case 'Z': archive_write_set_compression_compress(cpio->archive); break; @@ -455,11 +533,15 @@ file_to_archive(struct cpio *cpio, const struct archive_entry *entry, *spare; size_t len; const char *p; +#if !defined(_WIN32) || defined(__CYGWIN__) int lnklen; +#endif int r; /* * Create an archive_entry describing the source file. + * + * XXX TODO: rework to use archive_read_disk_entry_from_file() */ entry = archive_entry_new(); if (entry == NULL) @@ -483,6 +565,7 @@ file_to_archive(struct cpio *cpio, const st.st_gid = cpio->uid_override; archive_entry_copy_stat(entry, &st); +#if !defined(_WIN32) || defined(__CYGWIN__) /* If its a symlink, pull the target. */ if (S_ISLNK(st.st_mode)) { lnklen = readlink(srcpath, cpio->buff, cpio->buff_size); @@ -495,6 +578,7 @@ file_to_archive(struct cpio *cpio, const cpio->buff[lnklen] = 0; archive_entry_set_symlink(entry, cpio->buff); } +#endif /* * Generate a destination path for this entry. @@ -625,7 +709,7 @@ entry_to_archive(struct cpio *cpio, stru if (r != ARCHIVE_OK) cpio_warnc(archive_errno(cpio->archive), "%s: %s", - destpath, + srcpath, archive_error_string(cpio->archive)); if (r == ARCHIVE_FATAL) @@ -647,7 +731,7 @@ entry_to_archive(struct cpio *cpio, stru } } - restore_time(cpio, entry, srcpath, fd); + fd = restore_time(cpio, entry, srcpath, fd); cleanup: if (cpio->verbose) @@ -657,7 +741,7 @@ cleanup: return (0); } -static void +static int restore_time(struct cpio *cpio, struct archive_entry *entry, const char *name, int fd) { @@ -667,17 +751,20 @@ restore_time(struct cpio *cpio, struct a (void)cpio; /* UNUSED */ (void)entry; /* UNUSED */ (void)name; /* UNUSED */ - (void)fd; /* UNUSED */ if (!warned) cpio_warnc(0, "Can't restore access times on this platform"); warned = 1; - return; + return (fd); +#else +#if defined(_WIN32) && !defined(__CYGWIN__) + struct __timeval times[2]; #else struct timeval times[2]; +#endif if (!cpio->option_atime_restore) - return; + return (fd); times[1].tv_sec = archive_entry_mtime(entry); times[1].tv_usec = archive_entry_mtime_nsec(entry) / 1000; @@ -687,8 +774,16 @@ restore_time(struct cpio *cpio, struct a #ifdef HAVE_FUTIMES if (fd >= 0 && futimes(fd, times) == 0) - return; + return (fd); #endif + /* + * Some platform cannot restore access times if the file descriptor + * is still opened. + */ + if (fd >= 0) { + close(fd); + fd = -1; + } #ifdef HAVE_LUTIMES if (lutimes(name, times) != 0) @@ -697,6 +792,7 @@ restore_time(struct cpio *cpio, struct a #endif cpio_warnc(errno, "Can't update time for %s", name); #endif + return (fd); } @@ -858,6 +954,7 @@ list_item_verbose(struct cpio *cpio, str { char size[32]; char date[32]; + char uids[16], gids[16]; const char *uname, *gname; FILE *out = stdout; const struct stat *st; @@ -870,15 +967,24 @@ list_item_verbose(struct cpio *cpio, str if (!now) time(&now); - /* Use uname if it's present, else uid. */ - uname = archive_entry_uname(entry); - if (uname == NULL) - uname = lookup_uname(cpio, archive_entry_uid(entry)); - - /* Use gname if it's present, else gid. */ - gname = archive_entry_gname(entry); - if (gname == NULL) - gname = lookup_gname(cpio, archive_entry_gid(entry)); + if (cpio->option_numeric_uid_gid) { + /* Format numeric uid/gid for display. */ + snprintf(uids, sizeof(uids), "%jd", + (intmax_t)archive_entry_uid(entry)); + uname = uids; + snprintf(gids, sizeof(gids), "%jd", + (intmax_t)archive_entry_gid(entry)); + gname = gids; + } else { + /* Use uname if it's present, else lookup name from uid. */ + uname = archive_entry_uname(entry); + if (uname == NULL) + uname = lookup_uname(cpio, archive_entry_uid(entry)); + /* Use gname if it's present, else lookup name from gid. */ + gname = archive_entry_gname(entry); + if (gname == NULL) + gname = lookup_gname(cpio, archive_entry_gid(entry)); + } /* Print device number or file size. */ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { @@ -892,10 +998,18 @@ list_item_verbose(struct cpio *cpio, str /* Format the time using 'ls -l' conventions. */ tim = (time_t)st->st_mtime; +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Windows' strftime function does not support %e format. */ + if (abs(tim - now) > (365/2)*86400) + fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y"; + else + fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M"; +#else if (abs(tim - now) > (365/2)*86400) fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y"; else fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M"; +#endif strftime(date, sizeof(date), fmt, localtime(&tim)); fprintf(out, "%s%3d %-8s %-8s %8s %12s %s", Modified: head/usr.bin/cpio/cpio.h ============================================================================== --- head/usr.bin/cpio/cpio.h Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/cpio.h Fri Apr 17 04:04:57 2009 (r191192) @@ -62,6 +62,7 @@ struct cpio { int option_follow_links; /* -L */ int option_link; /* -l */ int option_list; /* -t */ + int option_numeric_uid_gid; /* -n */ int option_rename; /* -r */ char *destdir; size_t pass_destpath_alloc; Modified: head/usr.bin/cpio/cpio_platform.h ============================================================================== --- head/usr.bin/cpio/cpio_platform.h Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/cpio_platform.h Fri Apr 17 04:04:57 2009 (r191192) @@ -39,7 +39,7 @@ #include PLATFORM_CONFIG_H #elif defined(HAVE_CONFIG_H) /* Most POSIX platforms use the 'configure' script to build config.h */ -#include "../config.h" +#include "config.h" #else /* Warn if cpio hasn't been (automatically or manually) configured. */ #error Oops: No config.h and no built-in configuration in cpio_platform.h. @@ -48,7 +48,7 @@ /* No non-FreeBSD platform will have __FBSDID, so just define it here. */ #ifdef __FreeBSD__ #include <sys/cdefs.h> /* For __FBSDID */ -#else +#elif !defined(__FBSDID) /* Just leaving this macro replacement empty leads to a dangling semicolon. */ #define __FBSDID(a) struct _undefined_hack #endif @@ -89,4 +89,10 @@ #define __LA_DEAD #endif +#if defined(__CYGWIN__) +#include "cpio_cygwin.h" +#elif defined(_WIN32) /* && !__CYGWIN__ */ +#include "cpio_windows.h" +#endif + #endif /* !CPIO_PLATFORM_H_INCLUDED */ Modified: head/usr.bin/cpio/pathmatch.c ============================================================================== --- head/usr.bin/cpio/pathmatch.c Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/pathmatch.c Fri Apr 17 04:04:57 2009 (r191192) @@ -101,11 +101,10 @@ pm_list(const char *start, const char *e */ static const char * pm_slashskip(const char *s) { - while (*s == '.' || *s == '/') { - if (s[0] != '/' && s[1] != '/') - break; + while ((*s == '/') + || (s[0] == '.' && s[1] == '/') + || (s[0] == '.' && s[1] == '\0')) ++s; - } return (s); } @@ -130,8 +129,6 @@ pm(const char *p, const char *s, int fla return (1); /* "dir" == "dir/" == "dir/." */ s = pm_slashskip(s); - if (s[0] == '.' && s[1] == '\0') - return (1); } return (*s == '\0'); break; @@ -176,19 +173,6 @@ pm(const char *p, const char *s, int fla if (*p != *s) return (0); break; - default: - if (*p == *s) - break; - if ((*s == '\0') && (*p == '/')) { - p = pm_slashskip(p); - if (*p == '\0') - return (1); - if (p[0] == '.' && p[1] == '\0') - return (1); - return (0); - } - return (0); - break; case '\\': /* Trailing '\\' matches itself. */ if (p[1] == '\0') { @@ -200,19 +184,34 @@ pm(const char *p, const char *s, int fla return (0); } break; - } - /* - * TODO: pattern of "\/\.\/" should not match plain "/", - * it should only match explicit "/./". - */ - if (*p == '/') + case '/': + if (*s != '/' && *s != '\0') + return (0); + /* Note: pattern "/\./" won't match "/"; + * pm_slashskip() correctly stops at backslash. */ p = pm_slashskip(p); - else - ++p; - if (*s == '/') s = pm_slashskip(s); - else - ++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; } } @@ -236,9 +235,9 @@ pathmatch(const char *p, const char *s, /* If start is unanchored, try to match start of each path element. */ if (flags & PATHMATCH_NO_ANCHOR_START) { - for ( ; p != NULL; p = strchr(p, '/')) { - if (*p == '/') - p++; + for ( ; s != NULL; s = strchr(s, '/')) { + if (*s == '/') + s++; if (pm(p, s, flags)) return (1); } Modified: head/usr.bin/cpio/pathmatch.h ============================================================================== --- head/usr.bin/cpio/pathmatch.h Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/pathmatch.h Fri Apr 17 04:04:57 2009 (r191192) @@ -29,9 +29,14 @@ #ifndef PATHMATCH_H #define PATHMATCH_H +/* 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 +/* Note that "^" and "$" are not special unless you set the corresponding + * flag above. */ + int pathmatch(const char *p, const char *s, int flags); #endif Modified: head/usr.bin/cpio/test/main.c ============================================================================== --- head/usr.bin/cpio/test/main.c Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/test/main.c Fri Apr 17 04:04:57 2009 (r191192) @@ -44,6 +44,7 @@ #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$"); /* @@ -80,7 +81,7 @@ static int skips = 0; static int assertions = 0; /* Directory where uuencoded reference files can be found. */ -static char *refdir; +static const char *refdir; /* * My own implementation of the standard assert() macro emits the @@ -324,10 +325,10 @@ test_assert_equal_string(const char *fil file, line); fprintf(stderr, " %s = ", e1); strdump(v1); - fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : strlen(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 : strlen(v2)); + fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : (int)strlen(v2)); report_failure(extra); return (0); } @@ -402,7 +403,7 @@ hexdump(const char *p, const char *ref, char sep; for(i=0; i < l; i+=16) { - fprintf(stderr, "%04x", i + offset); + fprintf(stderr, "%04x", (unsigned)(i + offset)); sep = ' '; for (j = 0; j < 16 && i + j < l; j++) { if (ref != NULL && p[i + j] != ref[i + j]) @@ -497,6 +498,7 @@ test_assert_empty_file(const char *f1fmt s = sizeof(buff) < st.st_size ? sizeof(buff) : st.st_size; s = read(fd, buff, s); hexdump(buff, NULL, s, 0); + close(fd); } report_failure(NULL); return (0); @@ -525,11 +527,16 @@ test_assert_equal_file(const char *f1, c n2 = read(fd2, buff2, sizeof(buff2)); if (n1 != n2) break; - if (n1 == 0 && n2 == 0) + if (n1 == 0 && n2 == 0) { + close(fd1); + close(fd2); return (1); + } if (memcmp(buff1, buff2, n1) != 0) break; } + close(fd1); + close(fd2); failures ++; if (!verbose && previous_failures(test_filename, test_line)) return (0); @@ -600,6 +607,7 @@ test_assert_file_contents(const void *bu fd = open(f, O_RDONLY); contents = malloc(s * 2 + 128); n = read(fd, contents, s * 2 + 128); + close(fd); if (n == s && memcmp(buff, contents, s) == 0) { free(contents); return (1); @@ -621,6 +629,60 @@ test_assert_file_contents(const void *bu return (0); } +/* assertTextFileContents() asserts the contents of a text file. */ +int +test_assert_text_file_contents(const char *buff, const char *f) +{ + char *contents; + const char *btxt, *ftxt; + int fd; + int n, s; + + fd = open(f, O_RDONLY); + s = strlen(buff); + contents = malloc(s * 2 + 128); + n = read(fd, contents, s * 2 + 128 -1); + if (n >= 0) + contents[n] = '\0'; + close(fd); + /* Compare texts. */ + btxt = buff; + ftxt = (const char *)contents; + while (*btxt != '\0' && *ftxt != '\0') { + if (*btxt == *ftxt) { + ++btxt; + ++ftxt; + continue; + } + if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') { + /* Pass over different new line characters. */ + ++btxt; + ftxt += 2; + continue; + } + break; + } + if (*btxt == '\0' && *ftxt == '\0') { + free(contents); + return (1); + } + failures ++; + if (!previous_failures(test_filename, test_line)) { + fprintf(stderr, "%s:%d: File contents don't match\n", + test_filename, test_line); + fprintf(stderr, " file=\"%s\"\n", f); + if (n > 0) + hexdump(contents, buff, n, 0); + else { + fprintf(stderr, " File empty, contents should be:\n"); + hexdump(buff, NULL, s, 0); + } + report_failure(test_extra); + } + free(contents); + return (0); +} + /* * Call standard system() call, but build up the command line using * sprintf() conventions. @@ -750,7 +812,11 @@ static int test_run(int i, const char *t /* 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. */ @@ -843,23 +909,94 @@ extract_reference_file(const char *name) } +static char * +get_refdir(void) +{ + char tried[512] = { '\0' }; + char buff[128]; + char *pwd, *p; + + /* 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); + 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); + + snprintf(buff, sizeof(buff), "%s/test", pwd); + 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); + + snprintf(buff, sizeof(buff), "%s/%s/test", pwd, PROGRAM); + 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); + + if (memcmp(pwd, "/usr/obj", 8) == 0) { + snprintf(buff, sizeof(buff), "%s", pwd + 8); + 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); + + snprintf(buff, sizeof(buff), "%s/test", pwd + 8); + 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); + } + +#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: + free(p); + free(pwd); + return strdup(buff); +} + int main(int argc, char **argv) { static const int limit = sizeof(tests) / sizeof(tests[0]); int i, tests_run = 0, tests_failed = 0, opt; time_t now; char *refdir_alloc = NULL; - char *progname, *p; +#if defined(_WIN32) && !defined(__CYGWIN__) + char *testprg; +#endif + const char *opt_arg, *progname, *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); +#endif /* * Name of this program, used to build root of our temp directory * tree. */ progname = p = argv[0]; while (*p != '\0') { - if (*p == '/') + /* Support \ or / dir separators for Windows compat. */ + if (*p == '/' || *p == '\\') progname = p + 1; ++p; } @@ -877,39 +1014,61 @@ int main(int argc, char **argv) refdir = getenv(ENVBASE "_TEST_FILES"); /* - * Parse options. + * Parse options, without using getopt(), which isn't available + * on all platforms. */ - while ((opt = getopt(argc, argv, "dkp:qr:v")) != -1) { - switch (opt) { - case 'd': - dump_on_failure = 1; - break; - case 'k': - keep_temp_files = 1; + ++argv; /* Skip program name */ + while (*argv != NULL) { + if (**argv != '-') break; - case 'p': + p = *argv++; + ++p; /* Skip '-' */ + while (*p != '\0') { + opt = *p++; + opt_arg = NULL; + /* If 'opt' takes an argument, parse that. */ + if (opt == 'p' || opt == 'r') { + if (*p != '\0') + opt_arg = p; + else if (*argv == NULL) { + fprintf(stderr, + "Option -%c requires argument.\n", + opt); + usage(progname); + } else + opt_arg = *argv++; + p = ""; /* End of this option word. */ + } + + switch (opt) { + case 'd': + dump_on_failure = 1; + break; + case 'k': + keep_temp_files = 1; + break; + case 'p': #ifdef PROGRAM - testprog = optarg; + testprog = opt_arg; #else - usage(progname); + usage(progname); #endif - break; - case 'q': - quiet_flag++; - break; - case 'r': - refdir = optarg; - break; - case 'v': - verbose = 1; - break; - case '?': - default: - usage(progname); + break; + case 'q': + quiet_flag++; + break; + case 'r': + refdir = opt_arg; + break; + case 'v': + verbose = 1; + break; + case '?': + default: + usage(progname); + } } } - argc -= optind; - argv += optind; /* * Sanity-check that our options make sense. @@ -918,6 +1077,18 @@ int main(int argc, char **argv) if (testprog == NULL) usage(progname); #endif +#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] = '\\'; + } + testprog = testprg; +#endif /* * Create a temp directory for the following tests. @@ -943,16 +1114,8 @@ int main(int argc, char **argv) * If the user didn't specify a directory for locating * reference files, use the current directory for that. */ - if (refdir == NULL) { - systemf("/bin/pwd > %s/refdir", tmpdir); - refdir = refdir_alloc = slurpfile(NULL, "%s/refdir", tmpdir); - p = refdir + strlen(refdir); - while (p[-1] == '\n') { - --p; - *p = '\0'; - } - systemf("rm %s/refdir", tmpdir); - } + if (refdir == NULL) + refdir = refdir_alloc = get_refdir(); /* * Banner with basic information. @@ -971,7 +1134,7 @@ int main(int argc, char **argv) /* * Run some or all of the individual tests. */ - if (argc == 0) { + if (*argv == NULL) { /* Default: Run all tests. */ for (i = 0; i < limit; i++) { if (test_run(i, tmpdir)) Modified: head/usr.bin/cpio/test/test.h ============================================================================== --- head/usr.bin/cpio/test/test.h Fri Apr 17 03:49:26 2009 (r191191) +++ head/usr.bin/cpio/test/test.h Fri Apr 17 04:04:57 2009 (r191192) @@ -33,28 +33,45 @@ */ #if defined(HAVE_CONFIG_H) /* Most POSIX platforms use the 'configure' script to build config.h */ -#include "../../config.h" +#include "config.h" #elif defined(__FreeBSD__) /* Building as part of FreeBSD system requires a pre-built config.h. */ -#include "../config_freebsd.h" -#elif defined(_WIN32) +#include "config_freebsd.h" +#elif defined(_WIN32) && !defined(__CYGWIN__) /* Win32 can't run the 'configure' script. */ -#include "../config_windows.h" +#include "config_windows.h" #else /* Warn if the library hasn't been (automatically or manually) configured. */ #error Oops: No config.h and no pre-built configuration in test.h. #endif +#if !defined(_WIN32) || defined(__CYGWIN__) *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200904170404.n3H44vIV007538>