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
This commit is contained in:
kientzle 2009-04-17 04:04:57 +00:00
parent 4e8cb50d8b
commit 5853643ce6
28 changed files with 788 additions and 153 deletions

View File

@ -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

View File

@ -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 .

View File

@ -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' },

View File

@ -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 char *srcpath)
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 char *srcpath)
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 char *srcpath)
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, struct archive_entry *entry)
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, struct archive_entry *entry)
}
}
restore_time(cpio, entry, srcpath, fd);
fd = restore_time(cpio, entry, srcpath, fd);
cleanup:
if (cpio->verbose)
@ -657,7 +741,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
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 archive_entry *entry,
(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 archive_entry *entry,
#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 archive_entry *entry,
#endif
cpio_warnc(errno, "Can't update time for %s", name);
#endif
return (fd);
}
@ -858,6 +954,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
{
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, struct archive_entry *entry)
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, struct archive_entry *entry)
/* 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",

View File

@ -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;

View File

@ -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 */

View File

@ -101,11 +101,10 @@ pm_list(const char *start, const char *end, const char c, int flags)
*/
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 flags)
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 flags)
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 flags)
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, int flags)
/* 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);
}

View File

@ -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

View File

@ -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 *file, int line,
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, size_t l, size_t offset)
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, const char *f2pattern, ...)
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 *buff, int s, const char *fpattern, ...)
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 *buff, int s, const char *fpattern, ...)
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 *tmpdir)
/* 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;
++argv; /* Skip program name */
while (*argv != NULL) {
if (**argv != '-')
break;
case 'k':
keep_temp_files = 1;
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))

View File

@ -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__)
#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
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#ifndef _WIN32
#if !defined(_WIN32) || defined(__CYGWIN__)
#include <unistd.h>
#endif
#include <time.h>
#include <wchar.h>
#ifdef USE_DMALLOC
@ -65,7 +82,8 @@
#ifdef __FreeBSD__
#include <sys/cdefs.h> /* For __FBSDID */
#else
#define __FBSDID(a) /* null */
#undef __FBSDID
#define __FBSDID(a) struct _undefined_hack
#endif
/*
@ -107,6 +125,8 @@
/* Assert that file contents match a string; supports printf-style arguments. */
#define assertFileContents \
test_setup(__FILE__, __LINE__);test_assert_file_contents
#define assertTextFileContents \
test_setup(__FILE__, __LINE__);test_assert_text_file_contents
/*
* This would be simple with C99 variadic macros, but I don't want to
@ -129,6 +149,7 @@ int test_assert_equal_string(const char *, int, const char *v1, const char *, co
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 *, ...);
@ -147,4 +168,4 @@ void extract_reference_file(const char *);
*/
/* Pathname of exe to be tested. */
char *testprog;
const char *testprog;

View File

@ -29,6 +29,11 @@ __FBSDID("$FreeBSD$");
* This first test does basic sanity checks on the environment. For
* most of these, we just exit on failure.
*/
#if !defined(_WIN32) || defined(__CYGWIN__)
#define DEV_NULL "/dev/null"
#else
#define DEV_NULL "NUL"
#endif
DEFINE_TEST(test_0)
{
@ -46,9 +51,9 @@ DEFINE_TEST(test_0)
* Try to succesfully run the program; this requires that
* we know some option that will succeed.
*/
if (0 == systemf("%s --version >/dev/null", testprog)) {
if (0 == systemf("%s --version >" DEV_NULL, testprog)) {
/* This worked. */
} else if (0 == systemf("%s -W version >/dev/null", testprog)) {
} else if (0 == systemf("%s -W version >" DEV_NULL, testprog)) {
/* This worked. */
} else {
failure("Unable to successfully run any of the following:\n"

View File

@ -29,7 +29,9 @@ static void
verify_files(const char *target)
{
struct stat st, st2;
#if !defined(_WIN32) || defined(__CYGWIN__)
char buff[128];
#endif
int r;
/*
@ -42,7 +44,12 @@ verify_files(const char *target)
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);
@ -54,7 +61,12 @@ verify_files(const char *target)
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);
@ -69,6 +81,7 @@ verify_files(const char *target)
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);
@ -80,6 +93,7 @@ verify_files(const char *target)
assertEqualString(buff, "file");
}
}
#endif
/* Another file with 1 link and different permissions. */
r = lstat("file2", &st);
@ -88,7 +102,13 @@ verify_files(const char *target)
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);
@ -100,7 +120,11 @@ verify_files(const char *target)
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
}
}
@ -125,7 +149,7 @@ basic_cpio(const char *target,
/* Verify stderr. */
failure("Expected: %s, options=%s", se, pack_options);
assertFileContents(se, strlen(se), "pack.err");
assertTextFileContents(se, "pack.err");
/*
* Use cpio to unpack the archive into another directory.
@ -137,7 +161,7 @@ basic_cpio(const char *target,
/* Verify stderr. */
failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target);
assertFileContents(se, strlen(se), "unpack.err");
assertTextFileContents(se, "unpack.err");
verify_files(target);
@ -165,7 +189,7 @@ passthrough(const char *target)
/* Verify stderr. */
failure("Error invoking %s -p in dir %s",
testprog, target);
assertFileContents("1 block\n", 8, "stderr");
assertTextFileContents("1 block\n", "stderr");
verify_files(target);
chdir("..");
@ -219,7 +243,16 @@ DEFINE_TEST(test_basic)
basic_cpio("copy_odc", "--format=odc", "", "2 blocks\n");
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
/* Copy in one step using -p */
passthrough("passthrough");

View File

@ -112,7 +112,7 @@ DEFINE_TEST(test_format_newc)
return;
/* Verify that nothing went to stderr. */
assertFileContents("2 blocks\n", 9, "newc.err");
assertTextFileContents("2 blocks\n", "newc.err");
/* Verify that stdout is a well-formed cpio file in "newc" format. */
p = slurpfile(&s, "newc.out");
@ -128,7 +128,12 @@ DEFINE_TEST(test_format_newc)
assert(is_hex(e, 110)); /* Entire header is octal digits. */
assertEqualMem(e + 0, "070701", 6); /* Magic */
ino = from_hex(e + 6, 8); /* ino */
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Group members bits and others bits do not work. */
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 */
gid = from_hex(e + 30, 8); /* gid */
assertEqualMem(e + 38, "00000003", 8); /* nlink */
@ -160,14 +165,23 @@ DEFINE_TEST(test_format_newc)
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 */
@ -179,17 +193,26 @@ DEFINE_TEST(test_format_newc)
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;
/* "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. */
assertEqualInt(0x41c0, from_hex(e + 14, 8) & 0xffc0); /* Mode */
#else
assertEqualInt(0x41fd, from_hex(e + 14, 8)); /* Mode */
#endif
assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
#ifndef NLINKS_INACCURATE_FOR_DIRS
assertEqualMem(e + 38, "00000002", 8); /* nlink */
#endif
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. */
@ -214,7 +237,12 @@ DEFINE_TEST(test_format_newc)
assertEqualMem(e + 0, "070701", 6); /* Magic */
failure("If these aren't the same, then the hardlink detection failed to match them.");
assertEqualInt(ino, from_hex(e + 6, 8)); /* ino */
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Group members bits and others bits do not work. */
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 */
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
assertEqualMem(e + 38, "00000003", 8); /* nlink */

View File

@ -25,12 +25,13 @@
#include "test.h"
__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. */
@ -49,7 +50,7 @@ unpack_test(const char *from, const char *options, const char *se)
/* Verify that nothing went to stderr. */
failure("Error invoking %s -i %s < %s", testprog, options, from);
assertFileContents(se, strlen(se), "unpack.err");
assertTextFileContents(se, "unpack.err");
/*
* Verify unpacked files.
@ -61,7 +62,11 @@ unpack_test(const char *from, const char *options, const char *se)
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);
@ -74,7 +79,11 @@ unpack_test(const char *from, const char *options, const char *se)
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);
@ -89,6 +98,7 @@ unpack_test(const char *from, const char *options, const char *se)
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);
@ -100,13 +110,18 @@ unpack_test(const char *from, const char *options, const char *se)
assertEqualString(buff, "file");
}
}
#endif
/* 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
}
chdir("..");

View File

@ -23,7 +23,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <sys/utime.h>
#else
#include <utime.h>
#endif
__FBSDID("$FreeBSD$");
static struct {
@ -118,7 +122,7 @@ DEFINE_TEST(test_option_a)
/* Copy the file without -a; should change the atime. */
r = systemf("echo %s | %s -pd copy-no-a > copy-no-a.out 2>copy-no-a.err", files[1].name, testprog);
assertEqualInt(r, 0);
assertFileContents("1 block\n", 8, "copy-no-a.err");
assertTextFileContents("1 block\n", "copy-no-a.err");
assertEmptyFile("copy-no-a.out");
assertEqualInt(0, stat(files[1].name, &st));
failure("Copying file without -a should have changed atime.");
@ -127,7 +131,7 @@ DEFINE_TEST(test_option_a)
/* Archive the file without -a; should change the atime. */
r = systemf("echo %s | %s -o > archive-no-a.out 2>archive-no-a.err", files[2].name, testprog);
assertEqualInt(r, 0);
assertFileContents("1 block\n", 8, "copy-no-a.err");
assertTextFileContents("1 block\n", "copy-no-a.err");
assertEqualInt(0, stat(files[2].name, &st));
failure("Archiving file without -a should have changed atime.");
assert(st.st_atime != files[2].atime_sec);
@ -142,7 +146,7 @@ DEFINE_TEST(test_option_a)
r = systemf("echo %s | %s -pad copy-a > copy-a.out 2>copy-a.err",
files[3].name, testprog);
assertEqualInt(r, 0);
assertFileContents("1 block\n", 8, "copy-a.err");
assertTextFileContents("1 block\n", "copy-a.err");
assertEmptyFile("copy-a.out");
assertEqualInt(0, stat(files[3].name, &st));
failure("Copying file with -a should not have changed atime.");
@ -152,7 +156,7 @@ DEFINE_TEST(test_option_a)
r = systemf("echo %s | %s -oa > archive-a.out 2>archive-a.err",
files[4].name, testprog);
assertEqualInt(r, 0);
assertFileContents("1 block\n", 8, "copy-a.err");
assertTextFileContents("1 block\n", "copy-a.err");
assertEqualInt(0, stat(files[4].name, &st));
failure("Archiving file with -a should not have changed atime.");
assertEqualInt(st.st_atime, files[4].atime_sec);

View File

@ -90,7 +90,7 @@ DEFINE_TEST(test_option_c)
close(filelist);
r = systemf("%s -oc <filelist >basic.out 2>basic.err", testprog);
/* Verify that nothing went to stderr. */
assertFileContents("1 block\n", 8, "basic.err");
assertTextFileContents("1 block\n", "basic.err");
/* Assert that the program finished. */
failure("%s -oc crashed", testprog);
@ -114,7 +114,12 @@ DEFINE_TEST(test_option_c)
dev = from_octal(e + 6, 6);
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. */
assertEqualMem(e + 18, "100666", 6); /* Mode */
#else
assertEqualMem(e + 18, "100644", 6); /* Mode */
#endif
assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */
assert(is_octal(e + 30, 6)); /* gid */
gid = from_octal(e + 30, 6);
@ -136,7 +141,11 @@ DEFINE_TEST(test_option_c)
assertEqualMem(e + 0, "070707", 6); /* Magic */
assertEqualInt(dev, from_octal(e + 6, 6)); /* dev */
assert(dev != 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 */
@ -147,10 +156,21 @@ DEFINE_TEST(test_option_c)
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;
#endif
/* Second entry is "dir" */
assert(is_octal(e, 76));
@ -161,12 +181,19 @@ DEFINE_TEST(test_option_c)
/* Ino must be different from first entry. */
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. */
assertEqualMem(e + 18, "040777", 6); /* Mode */
#else
assertEqualMem(e + 18, "040775", 6); /* Mode */
#endif
assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */
/* Gid should be same as first entry. */
assert(is_octal(e + 30, 6)); /* gid */
assertEqualInt(gid, from_octal(e + 30, 6));
#ifndef NLINKS_INACCURATE_FOR_DIRS
assertEqualMem(e + 36, "000002", 6); /* Nlink */
#endif
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. */

View File

@ -42,7 +42,7 @@ DEFINE_TEST(test_option_d)
/* Create an archive. */
r = systemf("echo dir/file | %s -o > archive.cpio 2>archive.err", testprog);
assertEqualInt(r, 0);
assertFileContents("1 block\n", 8, "archive.err");
assertTextFileContents("1 block\n", "archive.err");
assertEqualInt(0, stat("archive.cpio", &st));
assertEqualInt(512, st.st_size);
@ -62,7 +62,7 @@ DEFINE_TEST(test_option_d)
r = systemf("%s -id < ../archive.cpio >out 2>err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("out");
assertFileContents("1 block\n", 8, "err");
assertTextFileContents("1 block\n", "err");
/* And the file should be restored. */
assertEqualInt(0, stat("dir/file", &st));
}

View File

@ -51,14 +51,24 @@ DEFINE_TEST(test_option_f)
assertEqualInt(0, access("t0/b234", F_OK));
/* Don't extract 'a*' files. */
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Single quotes isn't used by command.exe. */
unpack("t1", "-f a*");
#else
unpack("t1", "-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));
/* Don't extract 'b*' files. */
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Single quotes isn't used by command.exe. */
unpack("t2", "-f b*");
#else
unpack("t2", "-f 'b*'");
#endif
assertEqualInt(0, access("t2/a123", F_OK));
assertEqualInt(0, access("t2/a234", F_OK));
assert(0 != access("t2/b123", F_OK));

View File

@ -45,7 +45,7 @@ DEFINE_TEST(test_option_m)
now = time(NULL);
assertEqualInt(r, 0);
assertEmptyFile("out");
assertFileContents("1 block\n", 8, "err");
assertTextFileContents("1 block\n", "err");
assertEqualInt(0, stat("file", &st));
/* Should have been created within the last few seconds. */
assert(st.st_mtime <= now);
@ -60,7 +60,7 @@ DEFINE_TEST(test_option_m)
now = time(NULL);
assertEqualInt(r, 0);
assertEmptyFile("out");
assertFileContents("1 block\n", 8, "err");
assertTextFileContents("1 block\n", "err");
assertEqualInt(0, stat("file", &st));
/*
* mtime in reference archive is '1' == 1 second after

View File

@ -28,20 +28,58 @@ __FBSDID("$FreeBSD$");
DEFINE_TEST(test_option_t)
{
char *p;
int r;
/* List reference archive, make sure the TOC is correct. */
extract_reference_file("test_option_t.cpio");
r = systemf("%s -it < test_option_t.cpio >t.out 2>t.err", testprog);
r = systemf("%s -it < test_option_t.cpio >it.out 2>it.err", testprog);
assertEqualInt(r, 0);
assertFileContents("1 block\n", 8, "t.err");
assertTextFileContents("1 block\n", "it.err");
extract_reference_file("test_option_t.stdout");
assertEqualFile("t.out", "test_option_t.stdout");
p = slurpfile(NULL, "test_option_t.stdout");
assertTextFileContents(p, "it.out");
free(p);
/* We accept plain "-t" as a synonym for "-it" */
r = systemf("%s -t < test_option_t.cpio >t.out 2>t.err", testprog);
assertEqualInt(r, 0);
assertTextFileContents("1 block\n", "t.err");
extract_reference_file("test_option_t.stdout");
p = slurpfile(NULL, "test_option_t.stdout");
assertTextFileContents(p, "t.out");
free(p);
/* But "-ot" is an error. */
assert(0 != systemf("%s -ot < test_option_t.cpio >ot.out 2>ot.err",
testprog));
assertEmptyFile("ot.out");
/* List reference archive verbosely, make sure the TOC is correct. */
r = systemf("%s -itv < test_option_t.cpio >tv.out 2>tv.err", testprog);
assertEqualInt(r, 0);
assertFileContents("1 block\n", 8, "tv.err");
assertTextFileContents("1 block\n", "tv.err");
extract_reference_file("test_option_tv.stdout");
assertEqualFile("tv.out", "test_option_tv.stdout");
/* This doesn't work because the usernames on different systems
* are different and cpio now looks up numeric UIDs on
* the local system. */
/* assertEqualFile("tv.out", "test_option_tv.stdout"); */
/* List reference archive with numeric IDs, verify TOC is correct. */
r = systemf("%s -itnv < test_option_t.cpio >itnv.out 2>itnv.err",
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"); */
/* But "-n" without "-t" is an error. */
assert(0 != systemf("%s -in < test_option_t.cpio >in.out 2>in.err",
testprog));
assertEmptyFile("in.out");
}

View File

@ -23,7 +23,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <sys/utime.h>
#else
#include <utime.h>
#endif
__FBSDID("$FreeBSD$");
DEFINE_TEST(test_option_u)

View File

@ -77,7 +77,11 @@ verify(const char *p, size_t s)
/* All terminated by a newline. */
assert(s >= 1);
failure("Version: %s", p);
#if defined(_WIN32) && !defined(__CYGWIN__)
assertEqualMem(q, "\r\n", 2);
#else
assertEqualMem(q, "\n", 1);
#endif
}

View File

@ -43,10 +43,17 @@ DEFINE_TEST(test_option_y)
testprog);
failure("-y (bzip) option seems to be broken");
if (assertEqualInt(r, 0)) {
assertFileContents("1 block\n", 8, "archive.err");
/* Check that the archive file has a bzip2 signature. */
p = slurpfile(&s, "archive.out");
assert(s > 2);
assertEqualMem(p, "BZh9", 4);
p = slurpfile(&s, "archive.err");
p[s] = '\0';
if (strstr(p, "bzip2 compression not supported") != 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);
}
}
}

View File

@ -44,9 +44,16 @@ DEFINE_TEST(test_option_z)
failure("-z option seems to be broken");
assertEqualInt(r, 0);
if (r == 0) {
/* Check that the archive file has a gzip signature. */
p = slurpfile(&s, "archive.out");
assert(s > 2);
assertEqualMem(p, "\x1f\x8b\x08\x00", 4);
p = slurpfile(&s, "archive.err");
p[s] = '\0';
if (strstr(p, "gzip compression not supported") != 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);
}
}
}

View File

@ -27,24 +27,67 @@ __FBSDID("$FreeBSD$");
#include "../cpio.h"
#if 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
* their /etc/passwd. Likely values are 513 (None), 545 (Users),
* or 544 (Administrators). Just check for one of those...
* TODO: Handle non-English localizations...e.g. French 'Administrateur'
* Use CreateWellKnownSID() and LookupAccountName()?
*/
#define ROOT "Administrator"
#define ROOT_UID 500
#define ROOT_GID1 513
#define ROOT_GID2 545
#define ROOT_GID3 544
#else
#define ROOT "root"
#define ROOT_UID 0
#define ROOT_GID 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");
#else
int uid, gid;
cpio_progname = "Ignore this message";
assertEqualInt(0, owner_parse("root", &uid, &gid));
assertEqualInt(0, uid);
assertEqualInt(0, owner_parse(ROOT, &uid, &gid));
assertEqualInt(ROOT_UID, uid);
assertEqualInt(-1, gid);
assertEqualInt(0, owner_parse("root:", &uid, &gid));
assertEqualInt(0, uid);
assertEqualInt(0, gid);
assertEqualInt(0, owner_parse(ROOT ":", &uid, &gid));
assertEqualInt(ROOT_UID, uid);
#if defined(__CYGWIN__)
{
int gidIsOneOf = (ROOT_GID1 == gid)
|| (ROOT_GID2 == gid)
|| (ROOT_GID3 == gid);
assertEqualInt(1, gidIsOneOf);
}
#else
assertEqualInt(ROOT_GID, gid);
#endif
assertEqualInt(0, owner_parse("root.", &uid, &gid));
assertEqualInt(0, uid);
assertEqualInt(0, gid);
assertEqualInt(0, owner_parse(ROOT ".", &uid, &gid));
assertEqualInt(ROOT_UID, uid);
#if defined(__CYGWIN__)
{
int gidIsOneOf = (ROOT_GID1 == gid)
|| (ROOT_GID2 == gid)
|| (ROOT_GID3 == gid);
assertEqualInt(1, gidIsOneOf);
}
#else
assertEqualInt(ROOT_GID, gid);
#endif
/*
* TODO: Lookup current user/group name, build strings and
@ -62,7 +105,8 @@ DEFINE_TEST(test_owner_parse)
*/
assertEqualInt(1, owner_parse(":nonexistentgroup", &uid, &gid));
assertEqualInt(1, owner_parse("root:nonexistentgroup", &uid, &gid));
assertEqualInt(1, owner_parse(ROOT ":nonexistentgroup", &uid, &gid));
assertEqualInt(1,
owner_parse("nonexistentuser:nonexistentgroup", &uid, &gid));
#endif
}

View File

@ -71,7 +71,7 @@ DEFINE_TEST(test_passthrough_dotdot)
assertEqualInt(0, chdir(".."));
/* Verify stderr and stdout. */
assertFileContents("../.\n../file\n1 block\n", 21, "stderr");
assertTextFileContents("../.\n../file\n1 block\n", "stderr");
assertEmptyFile("stdout");
/* Regular file. */
@ -80,7 +80,11 @@ DEFINE_TEST(test_passthrough_dotdot)
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);
}

View File

@ -75,7 +75,7 @@ DEFINE_TEST(test_passthrough_reverse)
assertEqualInt(0, chdir("out"));
/* Verify stderr and stdout. */
assertFileContents("out/dir/file\nout/dir\n1 block\n", 29,
assertTextFileContents("out/dir/file\nout/dir\n1 block\n",
"../stderr");
assertEmptyFile("../stdout");
@ -85,7 +85,11 @@ DEFINE_TEST(test_passthrough_reverse)
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
}
@ -95,7 +99,11 @@ DEFINE_TEST(test_passthrough_reverse)
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);
}

View File

@ -38,10 +38,22 @@ __FBSDID("$FreeBSD$");
*
* The specification in SUSv2 is a bit incomplete, I assume the following:
* Trailing '-' in [...] is not special.
*
* TODO: Figure out if there's a good way to extend this to handle
* Windows paths that use '\' as a path separator. <sigh>
*/
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));
/* 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));
@ -68,6 +80,8 @@ DEFINE_TEST(test_pathmatch)
assertEqualInt(1, pathmatch("*a*", "defaaaaaaa", 0));
assertEqualInt(0, pathmatch("a*", "defghi", 0));
assertEqualInt(0, 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));
@ -84,6 +98,7 @@ DEFINE_TEST(test_pathmatch)
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));
@ -95,6 +110,14 @@ DEFINE_TEST(test_pathmatch)
assertEqualInt(0, pathmatch("abc[d-fh-k]", "abcl", 0));
assertEqualInt(0, 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));
/* I assume: Trailing '-' is non-special. */
assertEqualInt(0, pathmatch("abc[d-fh-]", "abcl", 0));
assertEqualInt(1, pathmatch("abc[d-fh-]", "abch", 0));
@ -138,12 +161,23 @@ DEFINE_TEST(test_pathmatch)
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));
/*
* Because '.' and '/' have special meanings, we can
* identify many equivalent paths even if they're expressed
* differently.
* 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));
@ -162,4 +196,48 @@ DEFINE_TEST(test_pathmatch)
assertEqualInt(1, pathmatch("./abc/./def", "abc/def/./", 0));
failure("Trailing '/.' is still the same directory.");
assertEqualInt(1, pathmatch("./abc*/./def", "abc/def/.", 0));
/* Matches not anchored at beginning. */
assertEqualInt(0,
pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_START));
assertEqualInt(1,
pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_START));
assertEqualInt(0,
pathmatch("^bcd", "abcd", PATHMATCH_NO_ANCHOR_START));
assertEqualInt(1,
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));
assertEqualInt(0,
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));
assertEqualInt(1,
pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_END));
assertEqualInt(1,
pathmatch("abcd", "abcd/", PATHMATCH_NO_ANCHOR_END));
assertEqualInt(1,
pathmatch("abcd", "abcd/.", PATHMATCH_NO_ANCHOR_END));
assertEqualInt(0,
pathmatch("abc", "abcd", PATHMATCH_NO_ANCHOR_END));
assertEqualInt(1,
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));
assertEqualInt(1,
pathmatch("a/b/c$", "a/b/c", PATHMATCH_NO_ANCHOR_END));
assertEqualInt(1,
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));
assertEqualInt(0,
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));
assertEqualInt(1,
pathmatch("a/b/c/$", "a/b/c", PATHMATCH_NO_ANCHOR_END));
assertEqualInt(0,
pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END));
}