Import libarchive-2.5.3b:

- fix bugs in link resolver, mostly affecting bsdcpio [from NetBSD]
- fix bsdcpio -p for hardlinks
- correctness improvements for directory name handling with ustar format
- handle empty filenames correctly
- allow bsdtar -r and -T to be used together as well as --format with -r
and -u.
This commit is contained in:
joerg 2008-05-11 13:05:35 +00:00
parent cc7aa65fd4
commit 842030a811
58 changed files with 3291 additions and 687 deletions

42
dist/libarchive/NEWS vendored
View File

@ -1,9 +1,39 @@
Mar 14, 2008: libarchive 2.4.14 released. This is identical to 2.4.13
except it contains a one-line fix to the uname/gname problem
introduced by the Feb 25 UTF-8 fix. This bug makes libarchive
refuse to add a file to a pax archive if it has a valid gname
but not a valid uname. In some cases, it can also cause the
uname to be stored for the gname.
May 04, 2008: libarchive 2.5.3b released
* libarchive: Several fixes to link resolver to address bsdcpio crashes
* bsdcpio: -p hardlink handling fixes
* tar/pax: Ensure ustar dirnames end in '/'; be more careful about
measuring filenames when deciding what pathname fields to use
* libarchive: Mark which entry strings are set; be accurate about
distinguishing empty strings ("") from unset ones (NULL)
* tar: Don't crash reading entries with empty filenames
* libarchive_test, bsdtar_test, bsdcpio_test: Better detaults:
run all tests, delete temp dirs, summarize repeated failures
* -no-undefined to libtool for Cygwin
* libarchive_test: Skip large file tests on systems with 32-bit off_t
* iso9660: Don't bother trying to find the body of an empty file;
this works around strange behavior from some ISO9660 writers
* tar: allow -r -T to be used together
* tar: allow --format with -r or -u
* libarchive: Don't build archive.h
Mar 30, 2008: libarchive 2.5.1b released
Mar 15, 2008: libarchive 2.5.0b released
Mar 15, 2008: bsdcpio now seems to correctly write hardlinks into newc,
ustar, and old cpio archives. Just a little more testing before
bsdcpio 1.0 becomes a reality.
Mar 15, 2008: I think the new linkify() interface is finally handling
all known hardlink strategies.
Mar 15, 2008: Mtree read fixes from Joerg Sonnenberger.
Mar 15, 2008: Many new bsdtar and bsdcpio options from Joerg Sonnenberger.
Mar 15, 2008: test harnesses no longer require uudecode; they
now have built-in decoding logic that decodes the reference
files as they are needed.
Mar 14, 2008: libarchive 2.4.14 released; identical to 2.4.13 except for
a point fix for gname/uname mixup in pax format that was introduced
with the UTF-8 fixes.
Feb 26, 2008: libarchive 2.4.13 released
Feb 25, 2008: Handle path, linkname, gname, or uname that can't be converted

View File

@ -112,7 +112,7 @@ cpio_getopt(struct cpio *cpio)
opt = getopt_long(cpio->argc, cpio->argv, cpio_opts,
cpio_longopts, &option_index);
#else
opt = getopt(cpio->argc, cpio->argv, optstring);
opt = getopt(cpio->argc, cpio->argv, cpio_opts);
#endif
/* Support long options through -W longopt=value */

View File

@ -70,7 +70,7 @@ static void mode_pass(struct cpio *, const char *);
static void restore_time(struct cpio *, struct archive_entry *,
const char *, int fd);
static void usage(void);
static void version(FILE *);
static void version(void);
int
main(int argc, char *argv[])
@ -204,7 +204,7 @@ main(int argc, char *argv[])
cpio->verbose++;
break;
case OPTION_VERSION: /* GNU convention */
version(stdout);
version();
break;
#if 0
/*
@ -326,16 +326,16 @@ long_help(void)
} else
putchar(*p);
}
version(stdout);
version();
}
static void
version(FILE *out)
version(void)
{
fprintf(out,"bsdcpio %s -- %s\n",
fprintf(stdout,"bsdcpio %s -- %s\n",
BSDCPIO_VERSION_STRING,
archive_version());
exit(1);
exit(0);
}
static void
@ -412,7 +412,10 @@ static int
file_to_archive(struct cpio *cpio, const char *srcpath)
{
struct stat st;
const char *destpath;
struct archive_entry *entry, *spare;
size_t len;
const char *p;
int lnklen;
int r;
@ -422,7 +425,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
entry = archive_entry_new();
if (entry == NULL)
cpio_errc(1, 0, "Couldn't allocate entry");
archive_entry_set_pathname(entry, srcpath);
archive_entry_copy_sourcepath(entry, srcpath);
/* Get stat information. */
if (cpio->option_follow_links)
@ -455,40 +458,12 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
}
/*
* If we're trying to preserve hardlinks, match them here.
* Generate a destination path for this entry.
* "destination path" is the name to which it will be copied in
* pass mode or the name that will go into the archive in
* output mode.
*/
spare = NULL;
if (cpio->linkresolver != NULL
&& !S_ISDIR(st.st_mode)) {
archive_entry_linkify(cpio->linkresolver, &entry, &spare);
}
if (entry != NULL) {
r = entry_to_archive(cpio, entry);
archive_entry_free(entry);
}
if (spare != NULL) {
if (r == 0)
r = entry_to_archive(cpio, spare);
archive_entry_free(spare);
}
return (r);
}
static int
entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
{
const char *destpath, *srcpath;
int fd = -1;
ssize_t bytes_read;
size_t len;
const char *p;
int r;
/*
* Generate a target path for this entry.
*/
destpath = srcpath = archive_entry_pathname(entry);
destpath = srcpath;
if (cpio->destdir) {
len = strlen(cpio->destdir) + strlen(srcpath) + 8;
if (len >= cpio->pass_destpath_alloc) {
@ -515,6 +490,36 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
return (0);
archive_entry_copy_pathname(entry, destpath);
/*
* If we're trying to preserve hardlinks, match them here.
*/
spare = NULL;
if (cpio->linkresolver != NULL
&& !S_ISDIR(st.st_mode)) {
archive_entry_linkify(cpio->linkresolver, &entry, &spare);
}
if (entry != NULL) {
r = entry_to_archive(cpio, entry);
archive_entry_free(entry);
}
if (spare != NULL) {
if (r == 0)
r = entry_to_archive(cpio, spare);
archive_entry_free(spare);
}
return (r);
}
static int
entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
{
const char *destpath = archive_entry_pathname(entry);
const char *srcpath = archive_entry_sourcepath(entry);
int fd = -1;
ssize_t bytes_read;
int r;
/* Print out the destination name to the user. */
if (cpio->verbose)
fprintf(stderr,"%s", destpath);
@ -526,10 +531,9 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
/* Note: link(2) doesn't create parent directories. */
archive_entry_set_hardlink(entry, srcpath);
r = archive_write_header(cpio->archive, entry);
if (r == ARCHIVE_OK)
return (0);
cpio_warnc(archive_errno(cpio->archive),
archive_error_string(cpio->archive));
if (r != ARCHIVE_OK)
cpio_warnc(archive_errno(cpio->archive),
archive_error_string(cpio->archive));
if (r == ARCHIVE_FATAL)
exit(1);
return (0);
@ -563,8 +567,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
if (r == ARCHIVE_FATAL)
exit(1);
if (r >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) {
fd = open(srcpath, O_RDONLY);
if (r >= ARCHIVE_WARN && fd >= 0) {
bytes_read = read(fd, cpio->buff, cpio->buff_size);
while (bytes_read > 0) {
r = archive_write_data(cpio->archive,

View File

@ -1,3 +1,4 @@
DEFINE_TEST(test_0)
DEFINE_TEST(test_basic)
DEFINE_TEST(test_format_newc)
DEFINE_TEST(test_gcpio_compat)

View File

@ -39,7 +39,7 @@
*
* The next few lines are the only differences.
*/
#define PROGRAM "bsdcpio" /* Program being tested. */
#define PROGRAM "bsdcpio" /* Name of program being tested. */
#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */
#undef EXTRA_DUMP /* How to dump extra data */
/* How to generate extra version info. */
@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$");
* test functions.
*/
#undef DEFINE_TEST
#define DEFINE_TEST(name) void name(void);
#define DEFINE_TEST(name) void name(void);
#include "list.h"
/* Interix doesn't define these in a standard header. */
@ -64,10 +64,14 @@ extern char *optarg;
extern int optind;
#endif
/* Default is to crash and try to force a core dump on failure. */
static int dump_on_failure = 1;
/* Enable core dump on failure. */
static int dump_on_failure = 0;
/* Default is to remove temp dirs for successful tests. */
static int keep_temp_files = 0;
/* Default is to print some basic information about each test. */
static int quiet_flag = 0;
/* Default is to summarize repeated failures. */
static int verbose = 0;
/* Cumulative count of component failures. */
static int failures = 0;
/* Cumulative count of skipped component tests. */
@ -243,7 +247,7 @@ test_assert(const char *file, int line, int value, const char *condition, void *
return (value);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (value);
fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
fprintf(stderr, " Condition: %s\n", condition);
@ -262,7 +266,7 @@ test_assert_equal_int(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n",
file, line);
@ -272,6 +276,30 @@ test_assert_equal_int(const char *file, int line,
return (0);
}
static void strdump(const char *p)
{
if (p == NULL) {
fprintf(stderr, "(null)");
return;
}
fprintf(stderr, "\"");
while (*p != '\0') {
unsigned int c = 0xff & *p++;
switch (c) {
case '\a': fprintf(stderr, "\a"); break;
case '\b': fprintf(stderr, "\b"); break;
case '\n': fprintf(stderr, "\n"); break;
case '\r': fprintf(stderr, "\r"); break;
default:
if (c >= 32 && c < 127)
fprintf(stderr, "%c", c);
else
fprintf(stderr, "\\x%02X", c);
}
}
fprintf(stderr, "\"");
}
/* assertEqualString() displays the values of the two strings. */
int
test_assert_equal_string(const char *file, int line,
@ -290,16 +318,41 @@ test_assert_equal_string(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
file, line);
fprintf(stderr, " %s = \"%s\"\n", e1, v1);
fprintf(stderr, " %s = \"%s\"\n", e2, v2);
fprintf(stderr, " %s = ", e1);
strdump(v1);
fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : strlen(v1));
fprintf(stderr, " %s = ", e2);
strdump(v2);
fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : strlen(v2));
report_failure(extra);
return (0);
}
static void wcsdump(const wchar_t *w)
{
if (w == NULL) {
fprintf(stderr, "(null)");
return;
}
fprintf(stderr, "\"");
while (*w != L'\0') {
unsigned int c = *w++;
if (c >= 32 && c < 127)
fprintf(stderr, "%c", c);
else if (c < 256)
fprintf(stderr, "\\x%02X", c);
else if (c < 0x10000)
fprintf(stderr, "\\u%04X", c);
else
fprintf(stderr, "\\U%08X", c);
}
fprintf(stderr, "\"");
}
/* assertEqualWString() displays the values of the two strings. */
int
test_assert_equal_wstring(const char *file, int line,
@ -308,17 +361,31 @@ test_assert_equal_wstring(const char *file, int line,
void *extra)
{
++assertions;
if (wcscmp(v1, v2) == 0) {
if (v1 == NULL) {
if (v2 == NULL) {
msg[0] = '\0';
return (1);
}
} else if (v2 == NULL) {
if (v1 == NULL) {
msg[0] = '\0';
return (1);
}
} else if (wcscmp(v1, v2) == 0) {
msg[0] = '\0';
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n",
file, line);
fwprintf(stderr, L" %s = \"%ls\"\n", e1, v1);
fwprintf(stderr, L" %s = \"%ls\"\n", e2, v2);
fprintf(stderr, " %s = ", e1);
wcsdump(v1);
fprintf(stderr, "\n");
fprintf(stderr, " %s = ", e2);
wcsdump(v2);
fprintf(stderr, "\n");
report_failure(extra);
return (0);
}
@ -379,7 +446,7 @@ test_assert_equal_mem(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n",
file, line);
@ -411,12 +478,13 @@ test_assert_empty_file(const char *f1fmt, ...)
if (stat(f1, &st) != 0) {
fprintf(stderr, "%s:%d: Could not stat: %s\n", test_filename, test_line, f1);
report_failure(NULL);
return (0);
}
if (st.st_size == 0)
return (1);
failures ++;
if (previous_failures(test_filename, test_line))
if (!verbose && previous_failures(test_filename, test_line))
return (0);
fprintf(stderr, "%s:%d: File not empty: %s\n", test_filename, test_line, f1);
@ -463,7 +531,7 @@ test_assert_equal_file(const char *f1, const char *f2pattern, ...)
break;
}
failures ++;
if (previous_failures(test_filename, test_line))
if (!verbose && previous_failures(test_filename, test_line))
return (0);
fprintf(stderr, "%s:%d: Files are not identical\n",
test_filename, test_line);
@ -587,7 +655,7 @@ slurpfile(size_t * sizep, const char *fmt, ...)
* We reuse it here to define a list of all tests (functions and names).
*/
#undef DEFINE_TEST
#define DEFINE_TEST(n) { n, #n },
#define DEFINE_TEST(n) { n, #n },
struct { void (*func)(void); const char *name; } tests[] = {
#include "list.h"
};
@ -634,6 +702,12 @@ static int test_run(int i, const char *tmpdir)
(*tests[i].func)();
/* Summarize the results of this test. */
summarize();
/* If there were no failures, we can remove the work dir. */
if (failures == failures_before) {
if (!keep_temp_files && chdir(tmpdir) == 0) {
systemf("rm -rf %s", tests[i].name);
}
}
/* Return appropriate status. */
return (failures == failures_before ? 0 : 1);
}
@ -647,8 +721,9 @@ static void usage(const char *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(" -k Keep running after failures.\n");
printf(" Default: Core dump after any failure.\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");
@ -656,13 +731,14 @@ static void usage(const char *program)
printf(" -q Quiet.\n");
printf(" -r <dir> Path to dir containing reference files.\n");
printf(" Default: Current directory.\n");
printf(" -v Verbose.\n");
printf("Available tests:\n");
for (i = 0; i < limit; i++)
printf(" %d: %s\n", i, tests[i].name);
exit(1);
}
#define uudecode(c) (((c) - 0x20) & 0x3f)
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
void
extract_reference_file(const char *name)
@ -695,23 +771,23 @@ extract_reference_file(const char *name)
if (memcmp(buff, "end", 3) == 0)
break;
bytes = uudecode(*p++);
bytes = UUDECODE(*p++);
while (bytes > 0) {
int n = 0;
/* Write out 1-3 bytes from that. */
if (bytes > 0) {
n = uudecode(*p++) << 18;
n |= uudecode(*p++) << 12;
n = UUDECODE(*p++) << 18;
n |= UUDECODE(*p++) << 12;
fputc(n >> 16, out);
--bytes;
}
if (bytes > 0) {
n |= uudecode(*p++) << 6;
n |= UUDECODE(*p++) << 6;
fputc((n >> 8) & 0xFF, out);
--bytes;
}
if (bytes > 0) {
n |= uudecode(*p++);
n |= UUDECODE(*p++);
fputc(n & 0xFF, out);
--bytes;
}
@ -748,9 +824,9 @@ int main(int argc, char **argv)
testprog = getenv(ENVBASE);
#endif
/* Allow -k to be controlled through the environment. */
if (getenv(ENVBASE "_KEEP_GOING") != NULL)
dump_on_failure = 0;
/* Allow -d to be controlled through the environment. */
if (getenv(ENVBASE "_DEBUG") != NULL)
dump_on_failure = 1;
/* Get the directory holding test files from environment. */
refdir = getenv(ENVBASE "_TEST_FILES");
@ -758,10 +834,13 @@ int main(int argc, char **argv)
/*
* Parse options.
*/
while ((opt = getopt(argc, argv, "kp:qr:")) != -1) {
while ((opt = getopt(argc, argv, "dkp:qr:v")) != -1) {
switch (opt) {
case 'd':
dump_on_failure = 1;
break;
case 'k':
dump_on_failure = 0;
keep_temp_files = 1;
break;
case 'p':
#ifdef PROGRAM
@ -776,6 +855,9 @@ int main(int argc, char **argv)
case 'r':
refdir = optarg;
break;
case 'v':
verbose = 1;
break;
case '?':
default:
usage(progname);
@ -824,6 +906,7 @@ int main(int argc, char **argv)
--p;
*p = '\0';
}
systemf("rm %s/refdir", tmpdir);
}
/*
@ -879,5 +962,9 @@ int main(int argc, char **argv)
free(refdir_alloc);
/* If the final tmpdir is empty, we can remove it. */
/* This should be the usual case when all tests succeed. */
rmdir(tmpdir);
return (tests_failed);
}

62
dist/libarchive/cpio/test/test_0.c vendored Normal file
View File

@ -0,0 +1,62 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* This first test does basic sanity checks on the environment. For
* most of these, we just exit on failure.
*/
DEFINE_TEST(test_0)
{
struct stat st;
failure("File %s does not exist?!", testprog);
if (!assertEqualInt(0, stat(testprog, &st)))
exit(1);
failure("%s is not executable?!", testprog);
if (!assert((st.st_mode & 0111) != 0))
exit(1);
/*
* Try to succesfully run the program; this requires that
* we know some option that will succeed.
*/
if (0 == systemf("%s --version >/dev/null", testprog)) {
/* This worked. */
} else if (0 == systemf("%s -W version >/dev/null", testprog)) {
/* This worked. */
} else {
failure("Unable to successfully run any of the following:\n"
" * %s --version\n"
" * %s -W version\n",
testprog, testprog);
assert(0);
}
/* TODO: Ensure that our reference files are available. */
}

View File

@ -25,37 +25,13 @@
#include "test.h"
__FBSDID("$FreeBSD$");
static void
basic_cpio(const char *target, const char *pack_options, const char *unpack_options)
verify_files(const char *target)
{
struct stat st, st2;
char buff[128];
int r;
assertEqualInt(0, mkdir(target, 0775));
/* Use the cpio program to create an archive. */
r = systemf("%s -o --quiet %s < filelist >%s/archive 2>%s/pack.err", testprog, pack_options, target, target);
failure("Error invoking %s -o --quiet %s", testprog, pack_options);
assertEqualInt(r, 0);
chdir(target);
/* Verify that nothing went to stderr. */
assertEmptyFile("pack.err");
/*
* Use cpio to unpack the archive into another directory.
*/
r = systemf("%s -i --quiet %s< archive >unpack.out 2>unpack.err", testprog, unpack_options);
failure("Error invoking %s -i %s", testprog, unpack_options);
assertEqualInt(r, 0);
/* Verify stderr. */
failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target);
assertEmptyFile("unpack.err");
/*
* Verify unpacked files.
*/
@ -68,7 +44,7 @@ basic_cpio(const char *target, const char *pack_options, const char *unpack_opti
assert(S_ISREG(st.st_mode));
assertEqualInt(0644, st.st_mode & 0777);
assertEqualInt(10, st.st_size);
failure("file %s/file", target);
failure("file %s/file should have 2 links", target);
assertEqualInt(2, st.st_nlink);
}
@ -80,11 +56,12 @@ basic_cpio(const char *target, const char *pack_options, const char *unpack_opti
assert(S_ISREG(st2.st_mode));
assertEqualInt(0644, st2.st_mode & 0777);
assertEqualInt(10, st2.st_size);
failure("file %s/linkfile", target);
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 aren't really hardlinks", target, target);
failure("%s/linkfile and %s/file should be hardlinked",
target, target);
assertEqualInt(st.st_ino, st2.st_ino);
}
@ -111,7 +88,72 @@ basic_cpio(const char *target, const char *pack_options, const char *unpack_opti
assert(S_ISDIR(st.st_mode));
assertEqualInt(0775, st.st_mode & 0777);
}
}
static void
basic_cpio(const char *target,
const char *pack_options,
const char *unpack_options,
const char *se)
{
int r;
if (!assertEqualInt(0, mkdir(target, 0775)))
return;
/* Use the cpio program to create an archive. */
r = systemf("%s -o %s < filelist >%s/archive 2>%s/pack.err",
testprog, pack_options, target, target);
failure("Error invoking %s -o %s", testprog, pack_options);
assertEqualInt(r, 0);
chdir(target);
/* Verify stderr. */
failure("Expected: %s, options=%s", se, pack_options);
assertFileContents(se, strlen(se), "pack.err");
/*
* Use cpio to unpack the archive into another directory.
*/
r = systemf("%s -i %s< archive >unpack.out 2>unpack.err",
testprog, unpack_options);
failure("Error invoking %s -i %s", testprog, unpack_options);
assertEqualInt(r, 0);
/* Verify stderr. */
failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target);
assertFileContents(se, strlen(se), "unpack.err");
verify_files(target);
chdir("..");
}
static void
passthrough(const char *target)
{
int r;
if (!assertEqualInt(0, mkdir(target, 0775)))
return;
/*
* Use cpio passthrough mode to copy files to another directory.
*/
r = systemf("%s -p -W quiet %s <filelist >%s/stdout 2>%s/stderr",
testprog, target, target, target);
failure("Error invoking %s -p", testprog);
assertEqualInt(r, 0);
chdir(target);
/* Verify stderr. */
failure("Error invoking %s -p in dir %s",
testprog, target);
assertEmptyFile("stderr");
verify_files(target);
chdir("..");
}
@ -150,11 +192,13 @@ DEFINE_TEST(test_basic)
close(filelist);
/* Archive/dearchive with a variety of options. */
basic_cpio("copy", "", "");
basic_cpio("copy_odc", "--format=odc", "");
basic_cpio("copy_newc", "-H newc", "");
basic_cpio("copy_cpio", "-H odc", "");
basic_cpio("copy_ustar", "-H ustar", "");
basic_cpio("copy", "", "", "1 block\n");
basic_cpio("copy_odc", "--format=odc", "", "1 block\n");
basic_cpio("copy_newc", "-H newc", "", "2 blocks\n");
basic_cpio("copy_cpio", "-H odc", "", "1 block\n");
basic_cpio("copy_ustar", "-H ustar", "", "7 blocks\n");
/* Copy in one step using -p */
passthrough("passthrough");
umask(oldumask);
}

View File

@ -106,13 +106,13 @@ DEFINE_TEST(test_format_newc)
/* Use the cpio program to create an archive. */
close(list);
r = systemf("%s -o --format=newc --quiet <list >newc.out 2>newc.err",
r = systemf("%s -o --format=newc <list >newc.out 2>newc.err",
testprog);
if (!assertEqualInt(r, 0))
return;
/* Verify that nothing went to stderr. */
assertEmptyFile("newc.err");
assertFileContents("2 blocks\n", 9, "newc.err");
/* Verify that stdout is a well-formed cpio file in "newc" format. */
p = slurpfile(&s, "newc.out");

View File

@ -27,7 +27,7 @@ __FBSDID("$FreeBSD$");
static void
unpack_test(const char *from, const char *options)
unpack_test(const char *from, const char *options, const char *se)
{
struct stat st, st2;
char buff[128];
@ -41,14 +41,14 @@ unpack_test(const char *from, const char *options)
* Use cpio to unpack the sample archive
*/
extract_reference_file(from);
r = systemf("%s -i --quiet %s < %s >unpack.out 2>unpack.err",
r = systemf("%s -i %s < %s >unpack.out 2>unpack.err",
testprog, options, from);
failure("Error invoking %s -i --quiet %s < %s",
failure("Error invoking %s -i %s < %s",
testprog, options, from);
assertEqualInt(r, 0);
/* Verify that nothing went to stderr. */
assertEmptyFile("unpack.err");
assertFileContents(se, strlen(se), "unpack.err");
/*
* Verify unpacked files.
@ -118,10 +118,10 @@ DEFINE_TEST(test_gcpio_compat)
oldumask = umask(0);
/* Dearchive sample files with a variety of options. */
unpack_test("test_gcpio_compat_ref.bin", "");
unpack_test("test_gcpio_compat_ref.crc", "");
unpack_test("test_gcpio_compat_ref.newc", "");
unpack_test("test_gcpio_compat_ref.ustar", "");
unpack_test("test_gcpio_compat_ref.bin", "", "1 block\n");
unpack_test("test_gcpio_compat_ref.crc", "", "2 blocks\n");
unpack_test("test_gcpio_compat_ref.newc", "", "2 blocks\n");
unpack_test("test_gcpio_compat_ref.ustar", "", "7 blocks\n");
umask(oldumask);
}

View File

@ -39,16 +39,16 @@ DEFINE_TEST(test_option_B)
close(fd);
/* Create an archive without -B; this should be 512 bytes. */
r = systemf("echo file | %s -o --quiet > small.cpio 2>small.err", testprog);
r = systemf("echo file | %s -o > small.cpio 2>small.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("small.err");
assertFileContents("1 block\n", 8, "small.err");
assertEqualInt(0, stat("small.cpio", &st));
assertEqualInt(512, st.st_size);
/* Create an archive with -B; this should be 5120 bytes. */
r = systemf("echo file | %s -oB --quiet > large.cpio 2>large.err", testprog);
r = systemf("echo file | %s -oB > large.cpio 2>large.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("large.err");
assertFileContents("1 block\n", 8, "large.err");
assertEqualInt(0, stat("large.cpio", &st));
assertEqualInt(5120, st.st_size);
}

View File

@ -46,36 +46,38 @@ DEFINE_TEST(test_option_L)
close(filelist);
r = systemf("cat filelist | %s -pd --quiet 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));
failure("Regular -p without -L should preserve symlinks.");
assert(S_ISLNK(st.st_mode));
r = systemf("cat filelist | %s -pd -L --quiet 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");
assertEmptyFile("copy-L.err");
assertEqualInt(0, lstat("copy-L/symlink", &st));
failure("-pL should dereference symlinks and turn them into files.");
failure("-pdL should dereference symlinks and turn them into files.");
assert(!S_ISLNK(st.st_mode));
r = systemf("cat filelist | %s -o --quiet >archive.out 2>archive.err", testprog);
failure("Error invoking %s -o --quiet %s", testprog);
r = systemf("cat filelist | %s -o >archive.out 2>archive.err", testprog);
failure("Error invoking %s -o ", testprog);
assertEqualInt(r, 0);
assertEqualInt(0, mkdir("unpack", 0755));
r = systemf("cat archive.out | (cd unpack ; %s -i >unpack.out 2>unpack.err)", testprog);
failure("Error invoking %s -i %s", testprog);
failure("Error invoking %s -i", testprog);
assertEqualInt(r, 0);
assertEqualInt(0, lstat("unpack/symlink", &st));
assert(S_ISLNK(st.st_mode));
r = systemf("cat filelist | %s -oL --quiet >archive-L.out 2>archive-L.err", testprog);
failure("Error invoking %s -oL --quiet %s", testprog);
r = systemf("cat filelist | %s -oL >archive-L.out 2>archive-L.err", testprog);
failure("Error invoking %s -oL", testprog);
assertEqualInt(r, 0);
assertEqualInt(0, mkdir("unpack-L", 0755));
r = systemf("cat archive-L.out | (cd unpack-L ; %s -i >unpack-L.out 2>unpack-L.err)", testprog);
failure("Error invoking %s -i %s < archive-L.out", 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));

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2003-2008 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -23,82 +23,137 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
#include <utime.h>
__FBSDID("$FreeBSD$");
static struct {
const char *name;
time_t atime_sec;
} files[] = {
{ "f0", 0 },
{ "f1", 0 },
{ "f2", 0 },
{ "f3", 0 },
{ "f4", 0 },
{ "f5", 0 }
};
/*
* Create a file on disk and set the atime to a known value.
* Create a bunch of test files and record their atimes.
* For the atime preserve/change tests, the files must have
* atimes in the past. We can accomplish this by explicitly invoking
* utime() on platforms that support it or by simply sleeping
* for a second after creating the files. (Creating all of the files
* at once means we only need to sleep once.)
*/
static void
test_create(const char *filename)
test_create(void)
{
struct stat st;
struct utimbuf times;
static const int numfiles = sizeof(files) / sizeof(files[0]);
int i;
int fd;
struct timeval times[2];
fd = open(filename, 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));
memset(times, 0, sizeof(times));
times[0].tv_sec = 1; /* atime = 1.000000002 */
times[0].tv_usec = 2;
times[1].tv_sec = 3; /* mtime = 3.000000004 */
times[1].tv_usec = 4;
assertEqualInt(0, futimes(fd, times));
close(fd);
for (i = 0; i < numfiles; ++i) {
fd = open(files[i].name, O_CREAT | O_WRONLY, 0644);
assert(fd >= 0);
/*
* Note: Have to write at least one byte to the file.
* cpio doesn't bother reading the file if it's zero length,
* so the atime never gets changed in that case, which
* makes the tests below rather pointless.
*/
assertEqualInt(1, write(fd, "a", 1));
close(fd);
/* If utime() isn't supported on your platform, just
* #ifdef this section out. Most of the test below is
* still valid. */
memset(&times, 0, sizeof(times));
times.actime = 1;
times.modtime = 3;
assertEqualInt(0, utime(files[i].name, &times));
/* Record whatever atime the file ended up with. */
/* If utime() is available, this should be 1, but there's
* no harm in being careful. */
assertEqualInt(0, stat(files[i].name, &st));
files[i].atime_sec = st.st_atime;
}
/* Wait until the atime on the last file is actually in the past. */
/* If utime() is supported above, there's no sleep here which
* makes the test faster. */
while (files[numfiles - 1].atime_sec >= time(NULL))
sleep(1);
}
DEFINE_TEST(test_option_a)
{
struct stat st;
int r;
int f;
char buff[64];
/* Sanity check; verify that test_create really works. */
test_create("f0");
/* Create all of the test files. */
test_create();
/* Sanity check; verify that atimes really do get modified. */
f = open(files[0].name, O_RDONLY);
assertEqualInt(1, read(f,buff, 1));
assertEqualInt(0, close(f));
assertEqualInt(0, stat("f0", &st));
failure("test_create function is supposed to create a file with atime == 1; if this doesn't work, test_option_a is entirely invalid.");
assertEqualInt(st.st_atime, 1);
if (st.st_atime == files[0].atime_sec) {
skipping("Cannot verify -a option\n"
" Your system appears to not support atime.");
}
else
{
/*
* If this disk is mounted noatime, then we can't
* verify correct operation without -a.
*/
/* Copy the file without -a; should change the atime. */
test_create("f1");
r = systemf("echo f1 | %s -pd --quiet copy-no-a > copy-no-a.out 2>copy-no-a.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("copy-no-a.err");
assertEmptyFile("copy-no-a.out");
assertEqualInt(0, stat("f1", &st));
failure("Copying file without -a should have changed atime. Ignore this if your system does not record atimes.");
assert(st.st_atime != 1);
/* Copy the file without -a; should change the atime. */
r = systemf("echo %s | %s -pd copy-no-a > copy-no-a.out 2>copy-no-a.err", files[1].name, testprog);
assertEqualInt(r, 0);
assertEmptyFile("copy-no-a.err");
assertEmptyFile("copy-no-a.out");
assertEqualInt(0, stat(files[1].name, &st));
failure("Copying file without -a should have changed atime.");
assert(st.st_atime != files[1].atime_sec);
/* Archive the file without -a; should change the atime. */
test_create("f2");
r = systemf("echo f2 | %s -o --quiet > archive-no-a.out 2>archive-no-a.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("copy-no-a.err");
assertEqualInt(0, stat("f2", &st));
failure("Archiving file without -a should have changed atime. Ignore this if your system does not record atimes.");
assert(st.st_atime != 1);
/* Archive the file without -a; should change the atime. */
r = systemf("echo %s | %s -o > archive-no-a.out 2>archive-no-a.err", files[2].name, testprog);
assertEqualInt(r, 0);
assertEmptyFile("copy-no-a.err");
assertEqualInt(0, stat(files[2].name, &st));
failure("Archiving file without -a should have changed atime.");
assert(st.st_atime != files[2].atime_sec);
}
/*
* We can, of course, still verify that the atime is unchanged
* when using the -a option.
*/
/* Copy the file with -a; should not change the atime. */
test_create("f3");
r = systemf("echo f3 | %s -pad --quiet copy-a > copy-a.out 2>copy-a.err", testprog);
r = systemf("echo %s | %s -pad copy-a > copy-a.out 2>copy-a.err",
files[3].name, testprog);
assertEqualInt(r, 0);
assertEmptyFile("copy-a.err");
assertEmptyFile("copy-a.out");
assertEqualInt(0, stat("f3", &st));
assertEqualInt(0, stat(files[3].name, &st));
failure("Copying file with -a should not have changed atime.");
assertEqualInt(st.st_atime, 1);
assertEqualInt(st.st_atime, files[3].atime_sec);
/* Archive the file without -a; should change the atime. */
test_create("f4");
r = systemf("echo f4 | %s -oa --quiet > archive-a.out 2>archive-a.err", testprog);
/* Archive the file with -a; should not change the atime. */
r = systemf("echo %s | %s -oa > archive-a.out 2>archive-a.err",
files[4].name, testprog);
assertEqualInt(r, 0);
assertEmptyFile("copy-a.err");
assertEqualInt(0, stat("f4", &st));
assertEqualInt(0, stat(files[4].name, &st));
failure("Archiving file with -a should not have changed atime.");
assertEqualInt(st.st_atime, 1);
assertEqualInt(st.st_atime, files[4].atime_sec);
}

View File

@ -88,9 +88,9 @@ DEFINE_TEST(test_option_c)
/* Use the cpio program to create an archive. */
close(filelist);
r = systemf("%s -oc --quiet <filelist >basic.out 2>basic.err", testprog);
r = systemf("%s -oc <filelist >basic.out 2>basic.err", testprog);
/* Verify that nothing went to stderr. */
assertEmptyFile("basic.err");
assertFileContents("1 block\n", 8, "basic.err");
/* Assert that the program finished. */
failure("%s -oc crashed", testprog);

View File

@ -40,9 +40,9 @@ DEFINE_TEST(test_option_d)
close(fd);
/* Create an archive. */
r = systemf("echo dir/file | %s -o --quiet > archive.cpio 2>archive.err", testprog);
r = systemf("echo dir/file | %s -o > archive.cpio 2>archive.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("archive.err");
assertFileContents("1 block\n", 8, "archive.err");
assertEqualInt(0, stat("archive.cpio", &st));
assertEqualInt(512, st.st_size);
@ -59,10 +59,10 @@ DEFINE_TEST(test_option_d)
assertEqualInt(0, chdir(".."));
assertEqualInt(0, mkdir("with-d", 0755));
assertEqualInt(0, chdir("with-d"));
r = systemf("%s -id --quiet < ../archive.cpio >out 2>err", testprog);
r = systemf("%s -id < ../archive.cpio >out 2>err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("out");
assertEmptyFile("err");
assertFileContents("1 block\n", 8, "err");
/* And the file should be restored. */
assertEqualInt(0, stat("dir/file", &st));
}

View File

@ -47,7 +47,7 @@ DEFINE_TEST(test_option_ell)
assertEqualInt(0, stat("f", &st));
/* Copy the file to the "copy" dir. */
r = systemf("echo f | %s -pd --quiet copy >copy.out 2>copy.err",
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err",
testprog);
assertEqualInt(r, 0);
@ -56,7 +56,7 @@ DEFINE_TEST(test_option_ell)
assert(st2.st_ino != st.st_ino);
/* Copy the file to the "link" dir with the -l option. */
r = systemf("echo f | %s -pld --quiet link >link.out 2>link.err",
r = systemf("echo f | %s -pld link >link.out 2>link.err",
testprog);
assertEqualInt(r, 0);

View File

@ -36,7 +36,7 @@ unpack(const char *dirname, const char *option)
assertEqualInt(0, mkdir(dirname, 0755));
assertEqualInt(0, chdir(dirname));
extract_reference_file("test_option_f.cpio");
r = systemf("%s -i --quiet %s < test_option_f.cpio > copy-no-a.out 2>copy-no-a.err", testprog, option);
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(".."));
}

View File

@ -23,11 +23,12 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
#include <utime.h>
__FBSDID("$FreeBSD$");
DEFINE_TEST(test_option_u)
{
struct timeval times[2];
struct utimbuf times;
char *p;
size_t s;
int fd;
@ -40,7 +41,7 @@ DEFINE_TEST(test_option_u)
close(fd);
/* Copy the file to the "copy" dir. */
r = systemf("echo f | %s -pd --quiet copy >copy.out 2>copy.err",
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err",
testprog);
assertEqualInt(r, 0);
@ -56,15 +57,13 @@ DEFINE_TEST(test_option_u)
close(fd);
/* Set the mtime to the distant past. */
memset(times, 0, sizeof(times));
times[0].tv_sec = 1; /* atime = 1.000000002 */
times[0].tv_usec = 2;
times[1].tv_sec = 3; /* mtime = 3.000000004 */
times[1].tv_usec = 4;
assertEqualInt(0, utimes("f", times));
memset(&times, 0, sizeof(times));
times.actime = 1;
times.modtime = 3;
assertEqualInt(0, utime("f", &times));
/* Copy the file to the "copy" dir. */
r = systemf("echo f | %s -pd --quiet copy >copy.out 2>copy.err",
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err",
testprog);
assertEqualInt(r, 0);
@ -74,7 +73,7 @@ DEFINE_TEST(test_option_u)
assertEqualMem(p, "a", 1);
/* Copy the file to the "copy" dir with -u (force) */
r = systemf("echo f | %s -pud --quiet copy >copy.out 2>copy.err",
r = systemf("echo f | %s -pud copy >copy.out 2>copy.err",
testprog);
assertEqualInt(r, 0);

View File

@ -88,6 +88,14 @@ DEFINE_TEST(test_option_version)
size_t s;
r = systemf("%s --version >version.stdout 2>version.stderr", testprog);
if (r != 0)
r = systemf("%s -W version >version.stdout 2>version.stderr",
testprog);
failure("Unable to run either %s --version or %s -W version",
testprog, testprog);
if (!assert(r == 0))
return;
/* --version should generate nothing to stderr. */
assertEmptyFile("version.stderr");
/* Verify format of version message. */

580
dist/libarchive/libarchive/archive.h vendored Normal file
View File

@ -0,0 +1,580 @@
/*-
* 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.
*
* $FreeBSD: src/lib/libarchive/archive.h.in,v 1.49 2008/03/14 22:19:50 kientzle Exp $
*/
#ifndef ARCHIVE_H_INCLUDED
#define ARCHIVE_H_INCLUDED
#include <sys/types.h> /* Linux requires this for off_t */
/* TODO: Conditionalize this include on platforms that don't support it. */
#include <inttypes.h> /* int64_t, etc. */
#include <stdio.h> /* For FILE * */
/* Get appropriate definitions of standard POSIX-style types. */
/* These should match the types used in 'struct stat' */
#ifdef _WIN32
#define __LA_SSIZE_T long
#define __LA_UID_T unsigned int
#define __LA_GID_T unsigned int
#else
#include <unistd.h> /* ssize_t, uid_t, and gid_t */
#define __LA_SSIZE_T ssize_t
#define __LA_UID_T uid_t
#define __LA_GID_T gid_t
#endif
/*
* On Windows, define LIBARCHIVE_STATIC if you're building or using a
* .lib. The default here assumes you're building a DLL. Only
* libarchive source should ever define __LIBARCHIVE_BUILD.
*/
#if ((defined __WIN32__) || (defined _WIN32)) && (!defined LIBARCHIVE_STATIC)
# ifdef __LIBARCHIVE_BUILD
# ifdef __GNUC__
# define __LA_DECL __attribute__((dllexport)) extern
# else
# define __LA_DECL __declspec(dllexport)
# endif
# else
# ifdef __GNUC__
# define __LA_DECL __attribute__((dllimport)) extern
# else
# define __LA_DECL __declspec(dllimport)
# endif
# endif
#else
/* Static libraries or non-Windows needs no special declaration. */
# define __LA_DECL
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* The version number is provided as both a macro and a function.
* The macro identifies the installed header; the function identifies
* the library version (which may not be the same if you're using a
* dynamically-linked version of the library). Of course, if the
* header and library are very different, you should expect some
* strangeness. Don't do that.
*/
/*
* The version number is expressed as a single integer that makes it
* easy to compare versions at build time: for version a.b.c, the
* version number is printf("%d%03d%03d",a,b,c). For example, if you
* know your application requires version 2.12.108 or later, you can
* assert that ARCHIVE_VERSION >= 2012108.
*
* This single-number format was introduced with libarchive 1.9.0 in
* the libarchive 1.x family and libarchive 2.2.4 in the libarchive
* 2.x family. The following may be useful if you really want to do
* feature detection for earlier libarchive versions (which defined
* ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead):
*
* #ifndef ARCHIVE_VERSION_NUMBER
* #define ARCHIVE_VERSION_NUMBER \
* (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
* #endif
*/
#define ARCHIVE_VERSION_NUMBER 2005003
__LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
#define ARCHIVE_VERSION_STRING "libarchive 2.5.3b"
__LA_DECL const char * archive_version_string(void);
#if ARCHIVE_VERSION_NUMBER < 3000000
/*
* Deprecated; these are older names that will be removed in favor of
* the simpler definitions above.
*/
#define ARCHIVE_VERSION_STAMP ARCHIVE_VERSION_NUMBER
__LA_DECL int archive_version_stamp(void);
#define ARCHIVE_LIBRARY_VERSION ARCHIVE_VERSION_STRING
__LA_DECL const char * archive_version(void);
#define ARCHIVE_API_VERSION (ARCHIVE_VERSION_NUMBER / 1000000)
__LA_DECL int archive_api_version(void);
#define ARCHIVE_API_FEATURE ((ARCHIVE_VERSION_NUMBER / 1000) % 1000)
__LA_DECL int archive_api_feature(void);
#endif
#if ARCHIVE_VERSION_NUMBER < 3000000
/* This should never have been here in the first place. */
/* Legacy of old tar assumptions, will be removed in libarchive 3.0. */
#define ARCHIVE_BYTES_PER_RECORD 512
#define ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240
#endif
/* Declare our basic types. */
struct archive;
struct archive_entry;
/*
* Error codes: Use archive_errno() and archive_error_string()
* to retrieve details. Unless specified otherwise, all functions
* that return 'int' use these codes.
*/
#define ARCHIVE_EOF 1 /* Found end of archive. */
#define ARCHIVE_OK 0 /* Operation was successful. */
#define ARCHIVE_RETRY (-10) /* Retry might succeed. */
#define ARCHIVE_WARN (-20) /* Partial success. */
/* For example, if write_header "fails", then you can't push data. */
#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */
/* But if write_header is "fatal," then this archive is dead and useless. */
#define ARCHIVE_FATAL (-30) /* No more operations are possible. */
/*
* As far as possible, archive_errno returns standard platform errno codes.
* Of course, the details vary by platform, so the actual definitions
* here are stored in "archive_platform.h". The symbols are listed here
* for reference; as a rule, clients should not need to know the exact
* platform-dependent error code.
*/
/* Unrecognized or invalid file format. */
/* #define ARCHIVE_ERRNO_FILE_FORMAT */
/* Illegal usage of the library. */
/* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */
/* Unknown or unclassified error. */
/* #define ARCHIVE_ERRNO_MISC */
/*
* Callbacks are invoked to automatically read/skip/write/open/close the
* archive. You can provide your own for complex tasks (like breaking
* archives across multiple tapes) or use standard ones built into the
* library.
*/
/* Returns pointer and size of next block of data from archive. */
typedef __LA_SSIZE_T archive_read_callback(struct archive *, void *_client_data,
const void **_buffer);
/* Skips at most request bytes from archive and returns the skipped amount */
#if ARCHIVE_VERSION_NUMBER < 2000000
typedef __LA_SSIZE_T archive_skip_callback(struct archive *, void *_client_data,
size_t request);
#else
typedef off_t archive_skip_callback(struct archive *, void *_client_data,
off_t request);
#endif
/* Returns size actually written, zero on EOF, -1 on error. */
typedef __LA_SSIZE_T archive_write_callback(struct archive *, void *_client_data,
const void *_buffer, size_t _length);
typedef int archive_open_callback(struct archive *, void *_client_data);
typedef int archive_close_callback(struct archive *, void *_client_data);
/*
* Codes for archive_compression.
*/
#define ARCHIVE_COMPRESSION_NONE 0
#define ARCHIVE_COMPRESSION_GZIP 1
#define ARCHIVE_COMPRESSION_BZIP2 2
#define ARCHIVE_COMPRESSION_COMPRESS 3
#define ARCHIVE_COMPRESSION_PROGRAM 4
/*
* Codes returned by archive_format.
*
* Top 16 bits identifies the format family (e.g., "tar"); lower
* 16 bits indicate the variant. This is updated by read_next_header.
* Note that the lower 16 bits will often vary from entry to entry.
* In some cases, this variation occurs as libarchive learns more about
* the archive (for example, later entries might utilize extensions that
* weren't necessary earlier in the archive; in this case, libarchive
* will change the format code to indicate the extended format that
* was used). In other cases, it's because different tools have
* modified the archive and so different parts of the archive
* actually have slightly different formts. (Both tar and cpio store
* format codes in each entry, so it is quite possible for each
* entry to be in a different format.)
*/
#define ARCHIVE_FORMAT_BASE_MASK 0xff0000
#define ARCHIVE_FORMAT_CPIO 0x10000
#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1)
#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2)
#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3)
#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4)
#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5)
#define ARCHIVE_FORMAT_SHAR 0x20000
#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1)
#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2)
#define ARCHIVE_FORMAT_TAR 0x30000
#define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1)
#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2)
#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3)
#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4)
#define ARCHIVE_FORMAT_ISO9660 0x40000
#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1)
#define ARCHIVE_FORMAT_ZIP 0x50000
#define ARCHIVE_FORMAT_EMPTY 0x60000
#define ARCHIVE_FORMAT_AR 0x70000
#define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1)
#define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 2)
#define ARCHIVE_FORMAT_MTREE 0x80000
#define ARCHIVE_FORMAT_MTREE_V1 (ARCHIVE_FORMAT_MTREE | 1)
#define ARCHIVE_FORMAT_MTREE_V2 (ARCHIVE_FORMAT_MTREE | 2)
/*-
* Basic outline for reading an archive:
* 1) Ask archive_read_new for an archive reader object.
* 2) Update any global properties as appropriate.
* In particular, you'll certainly want to call appropriate
* archive_read_support_XXX functions.
* 3) Call archive_read_open_XXX to open the archive
* 4) Repeatedly call archive_read_next_header to get information about
* successive archive entries. Call archive_read_data to extract
* data for entries of interest.
* 5) Call archive_read_finish to end processing.
*/
__LA_DECL struct archive *archive_read_new(void);
/*
* The archive_read_support_XXX calls enable auto-detect for this
* archive handle. They also link in the necessary support code.
* For example, if you don't want bzlib linked in, don't invoke
* support_compression_bzip2(). The "all" functions provide the
* obvious shorthand.
*/
__LA_DECL int archive_read_support_compression_all(struct archive *);
__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
__LA_DECL int archive_read_support_compression_compress(struct archive *);
__LA_DECL int archive_read_support_compression_gzip(struct archive *);
__LA_DECL int archive_read_support_compression_none(struct archive *);
__LA_DECL int archive_read_support_compression_program(struct archive *,
const char *command);
__LA_DECL int archive_read_support_format_all(struct archive *);
__LA_DECL int archive_read_support_format_ar(struct archive *);
__LA_DECL int archive_read_support_format_cpio(struct archive *);
__LA_DECL int archive_read_support_format_empty(struct archive *);
__LA_DECL int archive_read_support_format_gnutar(struct archive *);
__LA_DECL int archive_read_support_format_iso9660(struct archive *);
__LA_DECL int archive_read_support_format_mtree(struct archive *);
__LA_DECL int archive_read_support_format_tar(struct archive *);
__LA_DECL int archive_read_support_format_zip(struct archive *);
/* Open the archive using callbacks for archive I/O. */
__LA_DECL int archive_read_open(struct archive *, void *_client_data,
archive_open_callback *, archive_read_callback *,
archive_close_callback *);
__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
archive_open_callback *, archive_read_callback *,
archive_skip_callback *, archive_close_callback *);
/*
* A variety of shortcuts that invoke archive_read_open() with
* canned callbacks suitable for common situations. The ones that
* accept a block size handle tape blocking correctly.
*/
/* Use this if you know the filename. Note: NULL indicates stdin. */
__LA_DECL int archive_read_open_filename(struct archive *,
const char *_filename, size_t _block_size);
/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
__LA_DECL int archive_read_open_file(struct archive *,
const char *_filename, size_t _block_size);
/* Read an archive that's stored in memory. */
__LA_DECL int archive_read_open_memory(struct archive *,
void * buff, size_t size);
/* A more involved version that is only used for internal testing. */
__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
size_t size, size_t read_size);
/* Read an archive that's already open, using the file descriptor. */
__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
size_t _block_size);
/* Read an archive that's already open, using a FILE *. */
/* Note: DO NOT use this with tape drives. */
__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
/* Parses and returns next entry header. */
__LA_DECL int archive_read_next_header(struct archive *,
struct archive_entry **);
/*
* Retrieve the byte offset in UNCOMPRESSED data where last-read
* header started.
*/
__LA_DECL int64_t archive_read_header_position(struct archive *);
/* Read data from the body of an entry. Similar to read(2). */
__LA_DECL __LA_SSIZE_T archive_read_data(struct archive *, void *, size_t);
/*
* A zero-copy version of archive_read_data that also exposes the file offset
* of each returned block. Note that the client has no way to specify
* the desired size of the block. The API does guarantee that offsets will
* be strictly increasing and that returned blocks will not overlap.
*/
__LA_DECL int archive_read_data_block(struct archive *a,
const void **buff, size_t *size, off_t *offset);
/*-
* Some convenience functions that are built on archive_read_data:
* 'skip': skips entire entry
* 'into_buffer': writes data into memory buffer that you provide
* 'into_fd': writes data to specified filedes
*/
__LA_DECL int archive_read_data_skip(struct archive *);
__LA_DECL int archive_read_data_into_buffer(struct archive *, void *buffer,
__LA_SSIZE_T len);
__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
/*-
* Convenience function to recreate the current entry (whose header
* has just been read) on disk.
*
* This does quite a bit more than just copy data to disk. It also:
* - Creates intermediate directories as required.
* - Manages directory permissions: non-writable directories will
* be initially created with write permission enabled; when the
* archive is closed, dir permissions are edited to the values specified
* in the archive.
* - Checks hardlinks: hardlinks will not be extracted unless the
* linked-to file was also extracted within the same session. (TODO)
*/
/* The "flags" argument selects optional behavior, 'OR' the flags you want. */
/* Default: Do not try to set owner/group. */
#define ARCHIVE_EXTRACT_OWNER (1)
/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */
#define ARCHIVE_EXTRACT_PERM (2)
/* Default: Do not restore mtime/atime. */
#define ARCHIVE_EXTRACT_TIME (4)
/* Default: Replace existing files. */
#define ARCHIVE_EXTRACT_NO_OVERWRITE (8)
/* Default: Try create first, unlink only if create fails with EEXIST. */
#define ARCHIVE_EXTRACT_UNLINK (16)
/* Default: Do not restore ACLs. */
#define ARCHIVE_EXTRACT_ACL (32)
/* Default: Do not restore fflags. */
#define ARCHIVE_EXTRACT_FFLAGS (64)
/* Default: Do not restore xattrs. */
#define ARCHIVE_EXTRACT_XATTR (128)
/* Default: Do not try to guard against extracts redirected by symlinks. */
/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */
#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (256)
/* Default: Do not reject entries with '..' as path elements. */
#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (512)
/* Default: Create parent directories as needed. */
#define ARCHIVE_EXTRACT_NO_AUTODIR (1024)
/* Default: Overwrite files, even if one on disk is newer. */
#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (2048)
__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
int flags);
__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
struct archive * /* dest */);
__LA_DECL void archive_read_extract_set_progress_callback(struct archive *,
void (*_progress_func)(void *), void *_user_data);
/* Record the dev/ino of a file that will not be written. This is
* generally set to the dev/ino of the archive being read. */
__LA_DECL void archive_read_extract_set_skip_file(struct archive *,
dev_t, ino_t);
/* Close the file and release most resources. */
__LA_DECL int archive_read_close(struct archive *);
/* Release all resources and destroy the object. */
/* Note that archive_read_finish will call archive_read_close for you. */
#if ARCHIVE_VERSION_NUMBER >= 2000000
__LA_DECL int archive_read_finish(struct archive *);
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
/* Erroneously declared to return void in libarchive 1.x */
__LA_DECL void archive_read_finish(struct archive *);
#endif
/*-
* To create an archive:
* 1) Ask archive_write_new for a archive writer object.
* 2) Set any global properties. In particular, you should set
* the compression and format to use.
* 3) Call archive_write_open to open the file (most people
* will use archive_write_open_file or archive_write_open_fd,
* which provide convenient canned I/O callbacks for you).
* 4) For each entry:
* - construct an appropriate struct archive_entry structure
* - archive_write_header to write the header
* - archive_write_data to write the entry data
* 5) archive_write_close to close the output
* 6) archive_write_finish to cleanup the writer and release resources
*/
__LA_DECL struct archive *archive_write_new(void);
__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
int bytes_per_block);
__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
/* XXX This is badly misnamed; suggestions appreciated. XXX */
__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
int bytes_in_last_block);
__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
/* The dev/ino of a file that won't be archived. This is used
* to avoid recursively adding an archive to itself. */
__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
__LA_DECL int archive_write_set_compression_compress(struct archive *);
__LA_DECL int archive_write_set_compression_gzip(struct archive *);
__LA_DECL int archive_write_set_compression_none(struct archive *);
__LA_DECL int archive_write_set_compression_program(struct archive *,
const char *cmd);
/* A convenience function to set the format based on the code or name. */
__LA_DECL int archive_write_set_format(struct archive *, int format_code);
__LA_DECL int archive_write_set_format_by_name(struct archive *,
const char *name);
/* To minimize link pollution, use one or more of the following. */
__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
__LA_DECL int archive_write_set_format_cpio(struct archive *);
__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
/* TODO: int archive_write_set_format_old_tar(struct archive *); */
__LA_DECL int archive_write_set_format_pax(struct archive *);
__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
__LA_DECL int archive_write_set_format_shar(struct archive *);
__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
__LA_DECL int archive_write_set_format_ustar(struct archive *);
__LA_DECL int archive_write_open(struct archive *, void *,
archive_open_callback *, archive_write_callback *,
archive_close_callback *);
__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
/* A deprecated synonym for archive_write_open_filename() */
__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
/* _buffSize is the size of the buffer, _used refers to a variable that
* will be updated after each write into the buffer. */
__LA_DECL int archive_write_open_memory(struct archive *,
void *_buffer, size_t _buffSize, size_t *_used);
/*
* Note that the library will truncate writes beyond the size provided
* to archive_write_header or pad if the provided data is short.
*/
__LA_DECL int archive_write_header(struct archive *,
struct archive_entry *);
#if ARCHIVE_VERSION_NUMBER >= 2000000
__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *, const void *, size_t);
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
/* This was erroneously declared to return "int" in libarchive 1.x. */
__LA_DECL int archive_write_data(struct archive *, const void *, size_t);
#endif
__LA_DECL __LA_SSIZE_T archive_write_data_block(struct archive *, const void *, size_t, off_t);
__LA_DECL int archive_write_finish_entry(struct archive *);
__LA_DECL int archive_write_close(struct archive *);
#if ARCHIVE_VERSION_NUMBER >= 2000000
__LA_DECL int archive_write_finish(struct archive *);
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
/* Return value was incorrect in libarchive 1.x. */
__LA_DECL void archive_write_finish(struct archive *);
#endif
/*-
* To create objects on disk:
* 1) Ask archive_write_disk_new for a new archive_write_disk object.
* 2) Set any global properties. In particular, you should set
* the compression and format to use.
* 3) For each entry:
* - construct an appropriate struct archive_entry structure
* - archive_write_header to create the file/dir/etc on disk
* - archive_write_data to write the entry data
* 4) archive_write_finish to cleanup the writer and release resources
*
* In particular, you can use this in conjunction with archive_read()
* to pull entries out of an archive and create them on disk.
*/
__LA_DECL struct archive *archive_write_disk_new(void);
/* This file will not be overwritten. */
__LA_DECL int archive_write_disk_set_skip_file(struct archive *,
dev_t, ino_t);
/* Set flags to control how the next item gets created. */
__LA_DECL int archive_write_disk_set_options(struct archive *,
int flags);
/*
* The lookup functions are given uname/uid (or gname/gid) pairs and
* return a uid (gid) suitable for this system. These are used for
* restoring ownership and for setting ACLs. The default functions
* are naive, they just return the uid/gid. These are small, so reasonable
* for applications that don't need to preserve ownership; they
* are probably also appropriate for applications that are doing
* same-system backup and restore.
*/
/*
* The "standard" lookup functions use common system calls to lookup
* the uname/gname, falling back to the uid/gid if the names can't be
* found. They cache lookups and are reasonably fast, but can be very
* large, so they are not used unless you ask for them. In
* particular, these match the specifications of POSIX "pax" and old
* POSIX "tar".
*/
__LA_DECL int archive_write_disk_set_standard_lookup(struct archive *);
/*
* If neither the default (naive) nor the standard (big) functions suit
* your needs, you can write your own and register them. Be sure to
* include a cleanup function if you have allocated private data.
*/
__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
void * /* private_data */,
__LA_GID_T (*)(void *, const char *, __LA_GID_T),
void (* /* cleanup */)(void *));
__LA_DECL int archive_write_disk_set_user_lookup(struct archive *,
void * /* private_data */,
__LA_UID_T (*)(void *, const char *, __LA_UID_T),
void (* /* cleanup */)(void *));
/*
* Accessor functions to read/set various information in
* the struct archive object:
*/
/* Bytes written after compression or read before decompression. */
__LA_DECL int64_t archive_position_compressed(struct archive *);
/* Bytes written to compressor or read from decompressor. */
__LA_DECL int64_t archive_position_uncompressed(struct archive *);
__LA_DECL const char *archive_compression_name(struct archive *);
__LA_DECL int archive_compression(struct archive *);
__LA_DECL int archive_errno(struct archive *);
__LA_DECL const char *archive_error_string(struct archive *);
__LA_DECL const char *archive_format_name(struct archive *);
__LA_DECL int archive_format(struct archive *);
__LA_DECL void archive_clear_error(struct archive *);
__LA_DECL void archive_set_error(struct archive *, int _err,
const char *fmt, ...);
__LA_DECL void archive_copy_error(struct archive *dest,
struct archive *src);
#ifdef __cplusplus
}
#endif
/* This is meaningless outside of this header. */
#undef __LA_DECL
#endif /* !ARCHIVE_H_INCLUDED */

View File

@ -48,6 +48,7 @@
.Nm archive_entry_copy_link ,
.Nm archive_entry_copy_link_w ,
.Nm archive_entry_copy_pathname_w ,
.Nm archive_entry_copy_sourcepath ,
.Nm archive_entry_copy_stat ,
.Nm archive_entry_copy_symlink ,
.Nm archive_entry_copy_symlink_w ,
@ -95,6 +96,7 @@
.Nm archive_entry_set_uid ,
.Nm archive_entry_set_uname ,
.Nm archive_entry_size ,
.Nm archive_entry_sourcepath ,
.Nm archive_entry_stat ,
.Nm archive_entry_symlink ,
.Nm archive_entry_uid ,
@ -167,6 +169,8 @@
.Ft void
.Fn archive_entry_copy_hardlink_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_sourcepath "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_copy_pathname_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_stat "struct archive_entry *" "const struct stat *"
@ -270,6 +274,8 @@
.Fn archive_entry_set_uname "struct archive_entry *" "const char *"
.Ft int64_t
.Fn archive_entry_size "struct archive_entry *"
.Ft const char *
.Fn archive_entry_sourcepath "struct archive_entry *"
.Ft const struct stat *
.Fn archive_entry_stat "struct archive_entry *"
.Ft const char *

View File

@ -91,15 +91,17 @@ static void aes_clean(struct aes *);
static void aes_copy(struct aes *dest, struct aes *src);
static const char * aes_get_mbs(struct aes *);
static const wchar_t * aes_get_wcs(struct aes *);
static void aes_set_mbs(struct aes *, const char *mbs);
static void aes_copy_mbs(struct aes *, const char *mbs);
static int aes_set_mbs(struct aes *, const char *mbs);
static int aes_copy_mbs(struct aes *, const char *mbs);
/* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */
static void aes_copy_wcs(struct aes *, const wchar_t *wcs);
static void aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t);
static int aes_copy_wcs(struct aes *, const wchar_t *wcs);
static int aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t);
static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
static const wchar_t *ae_wcstofflags(const wchar_t *stringp,
unsigned long *setp, unsigned long *clrp);
static const char *ae_strtofflags(const char *stringp,
unsigned long *setp, unsigned long *clrp);
static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
const wchar_t *wname, int perm, int id);
static void append_id_w(wchar_t **wp, int id);
@ -144,173 +146,216 @@ static size_t wcslen(const wchar_t *s)
#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
#endif
static void
aes_clean(struct aes *aes)
{
if (aes->aes_mbs_alloc) {
free(aes->aes_mbs_alloc);
aes->aes_mbs_alloc = NULL;
if (aes->aes_wcs) {
free((wchar_t *)(uintptr_t)aes->aes_wcs);
aes->aes_wcs = NULL;
}
if (aes->aes_wcs_alloc) {
free(aes->aes_wcs_alloc);
aes->aes_wcs_alloc = NULL;
}
memset(aes, 0, sizeof(*aes));
archive_string_free(&(aes->aes_mbs));
archive_string_free(&(aes->aes_utf8));
aes->aes_set = 0;
}
static void
aes_copy(struct aes *dest, struct aes *src)
{
*dest = *src;
if (src->aes_mbs != NULL) {
dest->aes_mbs_alloc = strdup(src->aes_mbs);
dest->aes_mbs = dest->aes_mbs_alloc;
if (dest->aes_mbs == NULL)
__archive_errx(1, "No memory for aes_copy()");
}
wchar_t *wp;
dest->aes_set = src->aes_set;
archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs));
archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8));
if (src->aes_wcs != NULL) {
dest->aes_wcs_alloc = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1)
wp = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1)
* sizeof(wchar_t));
dest->aes_wcs = dest->aes_wcs_alloc;
if (dest->aes_wcs == NULL)
if (wp == NULL)
__archive_errx(1, "No memory for aes_copy()");
wcscpy(dest->aes_wcs_alloc, src->aes_wcs);
wcscpy(wp, src->aes_wcs);
dest->aes_wcs = wp;
}
}
static const char *
aes_get_utf8(struct aes *aes)
{
if (aes->aes_set & AES_SET_UTF8)
return (aes->aes_utf8.s);
if ((aes->aes_set & AES_SET_WCS)
&& archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) != NULL) {
aes->aes_set |= AES_SET_UTF8;
return (aes->aes_utf8.s);
}
return (NULL);
}
static const char *
aes_get_mbs(struct aes *aes)
{
if (aes->aes_mbs == NULL && aes->aes_wcs == NULL)
return NULL;
if (aes->aes_mbs == NULL && aes->aes_wcs != NULL) {
/*
* XXX Need to estimate the number of byte in the
* multi-byte form. Assume that, on average, wcs
* chars encode to no more than 3 bytes. There must
* be a better way... XXX
*/
size_t mbs_length = wcslen(aes->aes_wcs) * 3 + 64;
aes->aes_mbs_alloc = (char *)malloc(mbs_length);
aes->aes_mbs = aes->aes_mbs_alloc;
if (aes->aes_mbs == NULL)
__archive_errx(1, "No memory for aes_get_mbs()");
wcstombs(aes->aes_mbs_alloc, aes->aes_wcs, mbs_length - 1);
aes->aes_mbs_alloc[mbs_length - 1] = 0;
/* If we already have an MBS form, return that immediately. */
if (aes->aes_set & AES_SET_MBS)
return (aes->aes_mbs.s);
/* If there's a WCS form, try converting with the native locale. */
if ((aes->aes_set & AES_SET_WCS)
&& archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) {
aes->aes_set |= AES_SET_MBS;
return (aes->aes_mbs.s);
}
return (aes->aes_mbs);
/* We'll use UTF-8 for MBS if all else fails. */
return (aes_get_utf8(aes));
}
static const wchar_t *
aes_get_wcs(struct aes *aes)
{
wchar_t *w;
int r;
if (aes->aes_wcs == NULL && aes->aes_mbs == NULL)
return NULL;
if (aes->aes_wcs == NULL && aes->aes_mbs != NULL) {
/* Return WCS form if we already have it. */
if (aes->aes_set & AES_SET_WCS)
return (aes->aes_wcs);
if (aes->aes_set & AES_SET_MBS) {
/* Try converting MBS to WCS using native locale. */
/*
* No single byte will be more than one wide character,
* so this length estimate will always be big enough.
*/
size_t wcs_length = strlen(aes->aes_mbs);
size_t wcs_length = aes->aes_mbs.length;
aes->aes_wcs_alloc
= (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t));
aes->aes_wcs = aes->aes_wcs_alloc;
if (aes->aes_wcs == NULL)
w = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t));
if (w == NULL)
__archive_errx(1, "No memory for aes_get_wcs()");
r = mbstowcs(aes->aes_wcs_alloc, aes->aes_mbs, wcs_length);
aes->aes_wcs_alloc[wcs_length] = 0;
if (r == -1) {
/* Conversion failed, don't lie to our clients. */
free(aes->aes_wcs_alloc);
aes->aes_wcs = aes->aes_wcs_alloc = NULL;
r = mbstowcs(w, aes->aes_mbs.s, wcs_length);
w[wcs_length] = 0;
if (r > 0) {
aes->aes_set |= AES_SET_WCS;
return (aes->aes_wcs = w);
}
free(w);
}
return (aes->aes_wcs);
if (aes->aes_set & AES_SET_UTF8) {
/* Try converting UTF8 to WCS. */
aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
aes->aes_set |= AES_SET_WCS;
return (aes->aes_wcs);
}
return (NULL);
}
static void
static int
aes_set_mbs(struct aes *aes, const char *mbs)
{
if (aes->aes_mbs_alloc) {
free(aes->aes_mbs_alloc);
aes->aes_mbs_alloc = NULL;
}
if (aes->aes_wcs_alloc) {
free(aes->aes_wcs_alloc);
aes->aes_wcs_alloc = NULL;
}
aes->aes_mbs = mbs;
aes->aes_wcs = NULL;
return (aes_copy_mbs(aes, mbs));
}
static void
static int
aes_copy_mbs(struct aes *aes, const char *mbs)
{
if (aes->aes_mbs_alloc) {
free(aes->aes_mbs_alloc);
aes->aes_mbs_alloc = NULL;
if (mbs == NULL) {
aes->aes_set = 0;
return (0);
}
if (aes->aes_wcs_alloc) {
free(aes->aes_wcs_alloc);
aes->aes_wcs_alloc = NULL;
aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
archive_strcpy(&(aes->aes_mbs), mbs);
archive_string_empty(&(aes->aes_utf8));
if (aes->aes_wcs) {
free((wchar_t *)(uintptr_t)aes->aes_wcs);
aes->aes_wcs = NULL;
}
aes->aes_mbs_alloc = (char *)malloc((strlen(mbs) + 1) * sizeof(char));
if (aes->aes_mbs_alloc == NULL)
__archive_errx(1, "No memory for aes_copy_mbs()");
strcpy(aes->aes_mbs_alloc, mbs);
aes->aes_mbs = aes->aes_mbs_alloc;
aes->aes_wcs = NULL;
return (0);
}
#if 0
static void
aes_set_wcs(struct aes *aes, const wchar_t *wcs)
/*
* The 'update' form tries to proactively update all forms of
* this string (WCS and MBS) and returns an error if any of
* them fail. This is used by the 'pax' handler, for instance,
* to detect and report character-conversion failures early while
* still allowing clients to get potentially useful values from
* the more tolerant lazy conversions. (get_mbs and get_wcs will
* strive to give the user something useful, so you can get hopefully
* usable values even if some of the character conversions are failing.)
*/
static int
aes_update_utf8(struct aes *aes, const char *utf8)
{
if (aes->aes_mbs_alloc) {
free(aes->aes_mbs_alloc);
aes->aes_mbs_alloc = NULL;
if (utf8 == NULL) {
aes->aes_set = 0;
return (1); /* Succeeded in clearing everything. */
}
if (aes->aes_wcs_alloc) {
free(aes->aes_wcs_alloc);
aes->aes_wcs_alloc = NULL;
}
aes->aes_mbs = NULL;
aes->aes_wcs = wcs;
}
#endif
static void
/* Save the UTF8 string. */
archive_strcpy(&(aes->aes_utf8), utf8);
/* Empty the mbs and wcs strings. */
archive_string_empty(&(aes->aes_mbs));
if (aes->aes_wcs) {
free((wchar_t *)(uintptr_t)aes->aes_wcs);
aes->aes_wcs = NULL;
}
aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */
/* TODO: We should just do a direct UTF-8 to MBS conversion
* here. That would be faster, use less space, and give the
* same information. (If a UTF-8 to MBS conversion succeeds,
* then UTF-8->WCS and Unicode->MBS conversions will both
* succeed.) */
/* Try converting UTF8 to WCS, return false on failure. */
aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
if (aes->aes_wcs == NULL)
return (0);
aes->aes_set = AES_SET_UTF8 | AES_SET_WCS; /* Both UTF8 and WCS set. */
/* Try converting WCS to MBS, return false on failure. */
if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL)
return (0);
aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS;
/* All conversions succeeded. */
return (1);
}
static int
aes_copy_wcs(struct aes *aes, const wchar_t *wcs)
{
aes_copy_wcs_len(aes, wcs, wcslen(wcs));
return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs));
}
static void
static int
aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len)
{
if (aes->aes_mbs_alloc) {
free(aes->aes_mbs_alloc);
aes->aes_mbs_alloc = NULL;
wchar_t *w;
if (wcs == NULL) {
aes->aes_set = 0;
return (0);
}
if (aes->aes_wcs_alloc) {
free(aes->aes_wcs_alloc);
aes->aes_wcs_alloc = NULL;
aes->aes_set = AES_SET_WCS; /* Only WCS form set. */
archive_string_empty(&(aes->aes_mbs));
archive_string_empty(&(aes->aes_utf8));
if (aes->aes_wcs) {
free((wchar_t *)(uintptr_t)aes->aes_wcs);
aes->aes_wcs = NULL;
}
aes->aes_mbs = NULL;
aes->aes_wcs_alloc = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
if (aes->aes_wcs_alloc == NULL)
w = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
if (w == NULL)
__archive_errx(1, "No memory for aes_copy_wcs()");
wmemcpy(aes->aes_wcs_alloc, wcs, len);
aes->aes_wcs_alloc[len] = L'\0';
aes->aes_wcs = aes->aes_wcs_alloc;
wmemcpy(w, wcs, len);
w[len] = L'\0';
aes->aes_wcs = w;
return (0);
}
/****************************************************************************
*
* Public Interface
*
****************************************************************************/
struct archive_entry *
archive_entry_clear(struct archive_entry *entry)
{
@ -350,6 +395,8 @@ archive_entry_clone(struct archive_entry *entry)
aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
aes_copy(&entry2->ae_pathname, &entry->ae_pathname);
aes_copy(&entry2->ae_symlink, &entry->ae_symlink);
entry2->ae_hardlinkset = entry->ae_hardlinkset;
entry2->ae_symlinkset = entry->ae_symlinkset;
aes_copy(&entry2->ae_uname, &entry->ae_uname);
/* Copy ACL data over. */
@ -515,12 +562,16 @@ archive_entry_gname_w(struct archive_entry *entry)
const char *
archive_entry_hardlink(struct archive_entry *entry)
{
if (!entry->ae_hardlinkset)
return (NULL);
return (aes_get_mbs(&entry->ae_hardlink));
}
const wchar_t *
archive_entry_hardlink_w(struct archive_entry *entry)
{
if (!entry->ae_hardlinkset)
return (NULL);
return (aes_get_wcs(&entry->ae_hardlink));
}
@ -600,15 +651,25 @@ archive_entry_size(struct archive_entry *entry)
return (entry->ae_stat.aest_size);
}
const char *
archive_entry_sourcepath(struct archive_entry *entry)
{
return (aes_get_mbs(&entry->ae_sourcepath));
}
const char *
archive_entry_symlink(struct archive_entry *entry)
{
if (!entry->ae_symlinkset)
return (NULL);
return (aes_get_mbs(&entry->ae_symlink));
}
const wchar_t *
archive_entry_symlink_w(struct archive_entry *entry)
{
if (!entry->ae_symlinkset)
return (NULL);
return (aes_get_wcs(&entry->ae_symlink));
}
@ -651,6 +712,15 @@ archive_entry_set_fflags(struct archive_entry *entry,
entry->ae_fflags_clear = clear;
}
const char *
archive_entry_copy_fflags_text(struct archive_entry *entry,
const char *flags)
{
aes_copy_mbs(&entry->ae_fflags_text, flags);
return (ae_strtofflags(flags,
&entry->ae_fflags_set, &entry->ae_fflags_clear));
}
const wchar_t *
archive_entry_copy_fflags_text_w(struct archive_entry *entry,
const wchar_t *flags)
@ -685,6 +755,12 @@ archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
aes_copy_wcs(&entry->ae_gname, name);
}
int
archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
{
return (aes_update_utf8(&entry->ae_gname, name));
}
void
archive_entry_set_ino(struct archive_entry *entry, unsigned long ino)
{
@ -696,18 +772,24 @@ void
archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
{
aes_set_mbs(&entry->ae_hardlink, target);
if (target != NULL)
entry->ae_hardlinkset = 1;
}
void
archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
{
aes_copy_mbs(&entry->ae_hardlink, target);
if (target != NULL)
entry->ae_hardlinkset = 1;
}
void
archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
{
aes_copy_wcs(&entry->ae_hardlink, target);
if (target != NULL)
entry->ae_hardlinkset = 1;
}
void
@ -754,8 +836,7 @@ archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
void
archive_entry_set_link(struct archive_entry *entry, const char *target)
{
if (entry->ae_symlink.aes_mbs != NULL ||
entry->ae_symlink.aes_wcs != NULL)
if (entry->ae_symlinkset)
aes_set_mbs(&entry->ae_symlink, target);
else
aes_set_mbs(&entry->ae_hardlink, target);
@ -765,8 +846,7 @@ archive_entry_set_link(struct archive_entry *entry, const char *target)
void
archive_entry_copy_link(struct archive_entry *entry, const char *target)
{
if (entry->ae_symlink.aes_mbs != NULL ||
entry->ae_symlink.aes_wcs != NULL)
if (entry->ae_symlinkset)
aes_copy_mbs(&entry->ae_symlink, target);
else
aes_copy_mbs(&entry->ae_hardlink, target);
@ -776,13 +856,21 @@ archive_entry_copy_link(struct archive_entry *entry, const char *target)
void
archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)
{
if (entry->ae_symlink.aes_mbs != NULL ||
entry->ae_symlink.aes_wcs != NULL)
if (entry->ae_symlinkset)
aes_copy_wcs(&entry->ae_symlink, target);
else
aes_copy_wcs(&entry->ae_hardlink, target);
}
int
archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
{
if (entry->ae_symlinkset)
return (aes_update_utf8(&entry->ae_symlink, target));
else
return (aes_update_utf8(&entry->ae_hardlink, target));
}
void
archive_entry_set_mode(struct archive_entry *entry, mode_t m)
{
@ -823,6 +911,12 @@ archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
aes_copy_wcs(&entry->ae_pathname, name);
}
int
archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)
{
return (aes_update_utf8(&entry->ae_pathname, name));
}
void
archive_entry_set_perm(struct archive_entry *entry, mode_t p)
{
@ -862,22 +956,34 @@ archive_entry_set_size(struct archive_entry *entry, int64_t s)
entry->ae_stat.aest_size = s;
}
void
archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)
{
aes_set_mbs(&entry->ae_sourcepath, path);
}
void
archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
{
aes_set_mbs(&entry->ae_symlink, linkname);
if (linkname != NULL)
entry->ae_symlinkset = 1;
}
void
archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
{
aes_copy_mbs(&entry->ae_symlink, linkname);
if (linkname != NULL)
entry->ae_symlinkset = 1;
}
void
archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
{
aes_copy_wcs(&entry->ae_symlink, linkname);
if (linkname != NULL)
entry->ae_symlinkset = 1;
}
void
@ -905,6 +1011,12 @@ archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
aes_copy_wcs(&entry->ae_uname, name);
}
int
archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
{
return (aes_update_utf8(&entry->ae_uname, name));
}
/*
* ACL management. The following would, of course, be a lot simpler
* if: 1) the last draft of POSIX.1e were a really thorough and
@ -1744,7 +1856,7 @@ static struct flag {
* Convert file flags to a comma-separated string. If no flags
* are set, return the empty string.
*/
char *
static char *
ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
{
char *string, *dp;
@ -1788,6 +1900,70 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
return (string);
}
/*
* strtofflags --
* Take string of arguments and return file flags. This
* version works a little differently than strtofflags(3).
* In particular, it always tests every token, skipping any
* unrecognized tokens. It returns a pointer to the first
* unrecognized token, or NULL if every token was recognized.
* This version is also const-correct and does not modify the
* provided string.
*/
static const char *
ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
{
const char *start, *end;
struct flag *flag;
unsigned long set, clear;
const char *failed;
set = clear = 0;
start = s;
failed = NULL;
/* Find start of first token. */
while (*start == '\t' || *start == ' ' || *start == ',')
start++;
while (*start != '\0') {
/* Locate end of token. */
end = start;
while (*end != '\0' && *end != '\t' &&
*end != ' ' && *end != ',')
end++;
for (flag = flags; flag->wname != NULL; flag++) {
if (memcmp(start, flag->wname, end - start) == 0) {
/* Matched "noXXXX", so reverse the sense. */
clear |= flag->set;
set |= flag->clear;
break;
} else if (memcmp(start, flag->wname + 2, end - start)
== 0) {
/* Matched "XXXX", so don't reverse. */
set |= flag->set;
clear |= flag->clear;
break;
}
}
/* Ignore unknown flag names. */
if (flag->wname == NULL && failed == NULL)
failed = start;
/* Find start of next token. */
start = end;
while (*start == '\t' || *start == ' ' || *start == ',')
start++;
}
if (setp)
*setp = set;
if (clrp)
*clrp = clear;
/* Return location of first failure. */
return (failed);
}
/*
* wcstofflags --
* Take string of arguments and return file flags. This
@ -1798,7 +1974,7 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
* This version is also const-correct and does not modify the
* provided string.
*/
const wchar_t *
static const wchar_t *
ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
{
const wchar_t *start, *end;

View File

@ -31,14 +31,46 @@
#include <sys/types.h>
#include <stddef.h> /* for wchar_t */
#include <time.h>
#ifndef _WIN32
#include <unistd.h>
/* Get appropriate definitions of standard POSIX-style types. */
/* These should match the types used in 'struct stat' */
#ifdef _WIN32
#define __LA_UID_T unsigned int
#define __LA_GID_T unsigned int
#define __LA_INO_T unsigned int
#define __LA_DEV_T unsigned int
#define __LA_MODE_T unsigned short
#else
typedef unsigned int uid_t;
typedef unsigned int gid_t;
typedef unsigned int ino_t;
typedef unsigned int dev_t;
typedef unsigned short mode_t;
#include <unistd.h>
#define __LA_UID_T uid_t
#define __LA_GID_T gid_t
#define __LA_INO_T ino_t
#define __LA_DEV_T dev_t
#define __LA_MODE_T mode_t
#endif
/*
* On Windows, define LIBARCHIVE_STATIC if you're building or using a
* .lib. The default here assumes you're building a DLL. Only
* libarchive source should ever define __LIBARCHIVE_BUILD.
*/
#if ((defined __WIN32__) || (defined _WIN32)) && (!defined LIBARCHIVE_STATIC)
# ifdef __LIBARCHIVE_BUILD
# ifdef __GNUC__
# define __LA_DECL __attribute__((dllexport)) extern
# else
# define __LA_DECL __declspec(dllexport)
# endif
# else
# ifdef __GNUC__
# define __LA_DECL __attribute__((dllimport)) extern
# else
# define __LA_DECL __declspec(dllimport)
# endif
# endif
#else
/* Static libraries on all platforms and shared libraries on non-Windows. */
# define __LA_DECL
#endif
#ifdef __cplusplus
@ -48,7 +80,7 @@ extern "C" {
/*
* Description of an archive entry.
*
* Basically, a "struct stat" with a few text fields added in.
* You can think of this as "struct stat" with some text fields added in.
*
* TODO: Add "comment", "charset", and possibly other entries that are
* supported by "pax interchange" format. However, GNU, ustar, cpio,
@ -97,50 +129,51 @@ struct archive_entry;
* Basic object manipulation
*/
struct archive_entry *archive_entry_clear(struct archive_entry *);
__LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *);
/* The 'clone' function does a deep copy; all of the strings are copied too. */
struct archive_entry *archive_entry_clone(struct archive_entry *);
void archive_entry_free(struct archive_entry *);
struct archive_entry *archive_entry_new(void);
__LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *);
__LA_DECL void archive_entry_free(struct archive_entry *);
__LA_DECL struct archive_entry *archive_entry_new(void);
/*
* Retrieve fields from an archive_entry.
*/
time_t archive_entry_atime(struct archive_entry *);
long archive_entry_atime_nsec(struct archive_entry *);
time_t archive_entry_ctime(struct archive_entry *);
long archive_entry_ctime_nsec(struct archive_entry *);
dev_t archive_entry_dev(struct archive_entry *);
dev_t archive_entry_devmajor(struct archive_entry *);
dev_t archive_entry_devminor(struct archive_entry *);
mode_t archive_entry_filetype(struct archive_entry *);
void archive_entry_fflags(struct archive_entry *,
__LA_DECL time_t archive_entry_atime(struct archive_entry *);
__LA_DECL long archive_entry_atime_nsec(struct archive_entry *);
__LA_DECL time_t archive_entry_ctime(struct archive_entry *);
__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *);
__LA_DECL dev_t archive_entry_dev(struct archive_entry *);
__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *);
__LA_DECL dev_t archive_entry_devminor(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *);
__LA_DECL void archive_entry_fflags(struct archive_entry *,
unsigned long * /* set */,
unsigned long * /* clear */);
const char *archive_entry_fflags_text(struct archive_entry *);
gid_t archive_entry_gid(struct archive_entry *);
const char *archive_entry_gname(struct archive_entry *);
const wchar_t *archive_entry_gname_w(struct archive_entry *);
const char *archive_entry_hardlink(struct archive_entry *);
const wchar_t *archive_entry_hardlink_w(struct archive_entry *);
ino_t archive_entry_ino(struct archive_entry *);
mode_t archive_entry_mode(struct archive_entry *);
time_t archive_entry_mtime(struct archive_entry *);
long archive_entry_mtime_nsec(struct archive_entry *);
unsigned int archive_entry_nlink(struct archive_entry *);
const char *archive_entry_pathname(struct archive_entry *);
const wchar_t *archive_entry_pathname_w(struct archive_entry *);
dev_t archive_entry_rdev(struct archive_entry *);
dev_t archive_entry_rdevmajor(struct archive_entry *);
dev_t archive_entry_rdevminor(struct archive_entry *);
int64_t archive_entry_size(struct archive_entry *);
const char *archive_entry_strmode(struct archive_entry *);
const char *archive_entry_symlink(struct archive_entry *);
const wchar_t *archive_entry_symlink_w(struct archive_entry *);
uid_t archive_entry_uid(struct archive_entry *);
const char *archive_entry_uname(struct archive_entry *);
const wchar_t *archive_entry_uname_w(struct archive_entry *);
__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *);
__LA_DECL __LA_GID_T archive_entry_gid(struct archive_entry *);
__LA_DECL const char *archive_entry_gname(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *);
__LA_DECL const char *archive_entry_hardlink(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *);
__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *);
__LA_DECL time_t archive_entry_mtime(struct archive_entry *);
__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *);
__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *);
__LA_DECL const char *archive_entry_pathname(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdev(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *);
__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *);
__LA_DECL int64_t archive_entry_size(struct archive_entry *);
__LA_DECL const char *archive_entry_strmode(struct archive_entry *);
__LA_DECL const char *archive_entry_symlink(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *);
__LA_DECL __LA_UID_T archive_entry_uid(struct archive_entry *);
__LA_DECL const char *archive_entry_uname(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);
/*
* Set fields in an archive_entry.
@ -149,48 +182,54 @@ const wchar_t *archive_entry_uname_w(struct archive_entry *);
* In contrast, 'copy' functions do copy the object pointed to.
*/
void archive_entry_set_atime(struct archive_entry *, time_t, long);
void archive_entry_set_ctime(struct archive_entry *, time_t, long);
void archive_entry_set_dev(struct archive_entry *, dev_t);
void archive_entry_set_devmajor(struct archive_entry *, dev_t);
void archive_entry_set_devminor(struct archive_entry *, dev_t);
void archive_entry_set_filetype(struct archive_entry *, unsigned int);
void archive_entry_set_fflags(struct archive_entry *,
__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int);
__LA_DECL void archive_entry_set_fflags(struct archive_entry *,
unsigned long /* set */, unsigned long /* clear */);
/* Returns pointer to start of first invalid token, or NULL if none. */
/* Note that all recognized tokens are processed, regardless. */
const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,
const char *);
__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
const wchar_t *);
void archive_entry_set_gid(struct archive_entry *, gid_t);
void archive_entry_set_gname(struct archive_entry *, const char *);
void archive_entry_copy_gname(struct archive_entry *, const char *);
void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
void archive_entry_set_hardlink(struct archive_entry *, const char *);
void archive_entry_copy_hardlink(struct archive_entry *, const char *);
void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
void archive_entry_set_ino(struct archive_entry *, unsigned long);
void archive_entry_set_link(struct archive_entry *, const char *);
void archive_entry_copy_link(struct archive_entry *, const char *);
void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
void archive_entry_set_mode(struct archive_entry *, mode_t);
void archive_entry_set_mtime(struct archive_entry *, time_t, long);
void archive_entry_set_nlink(struct archive_entry *, unsigned int);
void archive_entry_set_pathname(struct archive_entry *, const char *);
void archive_entry_copy_pathname(struct archive_entry *, const char *);
void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
void archive_entry_set_perm(struct archive_entry *, mode_t);
void archive_entry_set_rdev(struct archive_entry *, dev_t);
void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
void archive_entry_set_rdevminor(struct archive_entry *, dev_t);
void archive_entry_set_size(struct archive_entry *, int64_t);
void archive_entry_set_symlink(struct archive_entry *, const char *);
void archive_entry_copy_symlink(struct archive_entry *, const char *);
void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
void archive_entry_set_uid(struct archive_entry *, uid_t);
void archive_entry_set_uname(struct archive_entry *, const char *);
void archive_entry_copy_uname(struct archive_entry *, const char *);
void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
__LA_DECL void archive_entry_set_gid(struct archive_entry *, __LA_GID_T);
__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
__LA_DECL void archive_entry_set_ino(struct archive_entry *, unsigned long);
__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T);
__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int);
__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);
__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_size(struct archive_entry *, int64_t);
__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
__LA_DECL void archive_entry_set_uid(struct archive_entry *, __LA_UID_T);
__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *);
/*
* Routines to bulk copy fields to/from a platform-native "struct
* stat." Libarchive used to just store a struct stat inside of each
@ -200,8 +239,8 @@ void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
*
* TODO: On Linux, provide both stat32 and stat64 versions of these functions.
*/
const struct stat *archive_entry_stat(struct archive_entry *);
void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *);
__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
/*
* ACL routines. This used to simply store and return text-format ACL
@ -249,11 +288,11 @@ void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
* POSIX.1e) is useful for handling archive formats that combine
* default and access information in a single ACL list.
*/
void archive_entry_acl_clear(struct archive_entry *);
void archive_entry_acl_add_entry(struct archive_entry *,
__LA_DECL void archive_entry_acl_clear(struct archive_entry *);
__LA_DECL void archive_entry_acl_add_entry(struct archive_entry *,
int /* type */, int /* permset */, int /* tag */,
int /* qual */, const char * /* name */);
void archive_entry_acl_add_entry_w(struct archive_entry *,
__LA_DECL void archive_entry_acl_add_entry_w(struct archive_entry *,
int /* type */, int /* permset */, int /* tag */,
int /* qual */, const wchar_t * /* name */);
@ -262,11 +301,11 @@ void archive_entry_acl_add_entry_w(struct archive_entry *,
* "next" entry. The want_type parameter allows you to request only
* access entries or only default entries.
*/
int archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
int archive_entry_acl_next(struct archive_entry *, int /* want_type */,
__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */,
int * /* type */, int * /* permset */, int * /* tag */,
int * /* qual */, const char ** /* name */);
int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */,
__LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */,
int * /* type */, int * /* permset */, int * /* tag */,
int * /* qual */, const wchar_t ** /* name */);
@ -283,11 +322,11 @@ int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */,
*/
#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
int /* flags */);
/* Return a count of entries matching 'want_type' */
int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
/*
* Private ACL parser. This is private because it handles some
@ -302,15 +341,15 @@ int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
* TODO: Move this declaration out of the public header and into
* a private header. Warnings above are silly.
*/
int __archive_entry_acl_parse_w(struct archive_entry *,
__LA_DECL int __archive_entry_acl_parse_w(struct archive_entry *,
const wchar_t *, int /* type */);
/*
* extended attributes
*/
void archive_entry_xattr_clear(struct archive_entry *);
void archive_entry_xattr_add_entry(struct archive_entry *,
__LA_DECL void archive_entry_xattr_clear(struct archive_entry *);
__LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *,
const char * /* name */, const void * /* value */,
size_t /* size */);
@ -319,9 +358,9 @@ void archive_entry_xattr_add_entry(struct archive_entry *,
* "next" entry.
*/
int archive_entry_xattr_count(struct archive_entry *);
int archive_entry_xattr_reset(struct archive_entry *);
int archive_entry_xattr_next(struct archive_entry *,
__LA_DECL int archive_entry_xattr_count(struct archive_entry *);
__LA_DECL int archive_entry_xattr_reset(struct archive_entry *);
__LA_DECL int archive_entry_xattr_next(struct archive_entry *,
const char ** /* name */, const void ** /* value */, size_t *);
/*
@ -352,7 +391,7 @@ int archive_entry_xattr_next(struct archive_entry *,
* Note that archive_entry_size() is reset to zero if the file
* body should not be written to the archive. Pay attention!
*/
struct archive_entry_linkresolver;
__LA_DECL struct archive_entry_linkresolver;
/*
* There are three different strategies for marking hardlinks.
@ -394,15 +433,18 @@ struct archive_entry_linkresolver;
* correctly extract an arbitrary link.
*/
struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);
void archive_entry_linkresolver_set_strategy(
__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);
__LA_DECL void archive_entry_linkresolver_set_strategy(
struct archive_entry_linkresolver *, int /* format_code */);
void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
void archive_entry_linkify(struct archive_entry_linkresolver *,
__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,
struct archive_entry **, struct archive_entry **);
#ifdef __cplusplus
}
#endif
/* This is meaningless outside of this header. */
#undef __LA_DECL
#endif /* !ARCHIVE_ENTRY_H_INCLUDED */

View File

@ -22,23 +22,31 @@
* (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: src/lib/libarchive/archive_entry_private.h,v 1.2 2007/12/30 04:58:21 kientzle Exp $
* $FreeBSD: src/lib/libarchive/archive_entry_private.h,v 1.3 2008/03/31 06:24:39 kientzle Exp $
*/
#ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
#include "archive_string.h"
/*
* Handle wide character (i.e., Unicode) and non-wide character
* strings transparently.
*
*/
struct aes {
const char *aes_mbs;
char *aes_mbs_alloc;
struct archive_string aes_mbs;
struct archive_string aes_utf8;
const wchar_t *aes_wcs;
wchar_t *aes_wcs_alloc;
/* Bitmap of which of the above are valid. Because we're lazy
* about malloc-ing and reusing the underlying storage, we
* can't rely on NULL pointers to indicate whether a string
* has been set. */
int aes_set;
#define AES_SET_MBS 1
#define AES_SET_UTF8 2
#define AES_SET_WCS 4
};
struct ae_acl {
@ -128,8 +136,6 @@ struct archive_entry {
dev_t aest_rdevminor;
} ae_stat;
/*
* Use aes here so that we get transparent mbs<->wcs conversions.
*/
@ -141,16 +147,24 @@ struct archive_entry {
struct aes ae_pathname; /* Name of entry */
struct aes ae_symlink; /* symlink contents */
struct aes ae_uname; /* Name of owner */
unsigned char ae_hardlinkset;
unsigned char ae_symlinkset;
/* Not used within libarchive; useful for some clients. */
struct aes ae_sourcepath; /* Path this entry is sourced from. */
/* ACL support. */
struct ae_acl *acl_head;
struct ae_acl *acl_p;
int acl_state; /* See acl_next for details. */
wchar_t *acl_text_w;
/* extattr support. */
struct ae_xattr *xattr_head;
struct ae_xattr *xattr_p;
char strmode[11];
/* Miscellaneous. */
char strmode[12];
};

View File

@ -36,6 +36,9 @@
#ifndef ARCHIVE_PLATFORM_H_INCLUDED
#define ARCHIVE_PLATFORM_H_INCLUDED
/* archive.h and archive_entry.h require this. */
#define __LIBARCHIVE_BUILD 1
#ifdef _WIN32
#include "config_windows.h"
#include "archive_windows.h"

View File

@ -56,6 +56,7 @@
.\" #endif
.Nm archive_read_data_into_fd ,
.Nm archive_read_extract ,
.Nm archive_read_extract2 ,
.Nm archive_read_extract_set_progress_callback ,
.Nm archive_read_close ,
.Nm archive_read_finish
@ -145,6 +146,12 @@
.Fa "struct archive_entry *"
.Fa "int flags"
.Fc
.Ft int
.Fo archive_read_extract2
.Fa "struct archive *src"
.Fa "struct archive_entry *"
.Fa "struct archive *dest"
.Fc
.Ft void
.Fo archive_read_extract_set_progress_callback
.Fa "struct archive *"
@ -314,6 +321,22 @@ The
.Va flags
argument is passed unmodified to
.Xr archive_write_disk_set_options 3 .
.It Fn archive_read_extract2
This is another version of
.Fn archive_read_extract
that allows you to provide your own restore object.
In particular, this allows you to override the standard lookup functions
using
.Xr archive_write_disk_set_group_lookup 3 ,
and
.Xr archive_write_disk_set_user_lookup 3 .
Note that
.Fn archive_read_extract2
does not accept a
.Va flags
argument; you should use
.Fn archive_write_disk_set_options
to set the restore options yourself.
.It Fn archive_read_extract_set_progress_callback
Sets a pointer to a user-defined callback that can be used
for updating progress displays during extraction.

View File

@ -82,34 +82,40 @@ get_extract(struct archive_read *a)
int
archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
{
struct archive_read *a = (struct archive_read *)_a;
struct extract *extract;
int r, r2;
extract = get_extract(a);
extract = get_extract((struct archive_read *)_a);
if (extract == NULL)
return (ARCHIVE_FATAL);
archive_write_disk_set_options(extract->ad, flags);
return (archive_read_extract2(_a, entry, extract->ad));
}
int
archive_read_extract2(struct archive *_a, struct archive_entry *entry,
struct archive *ad)
{
struct archive_read *a = (struct archive_read *)_a;
int r, r2;
/* Set up for this particular entry. */
extract = a->extract;
archive_write_disk_set_options(a->extract->ad, flags);
archive_write_disk_set_skip_file(a->extract->ad,
archive_write_disk_set_skip_file(ad,
a->skip_file_dev, a->skip_file_ino);
r = archive_write_header(a->extract->ad, entry);
r = archive_write_header(ad, entry);
if (r < ARCHIVE_WARN)
r = ARCHIVE_WARN;
if (r != ARCHIVE_OK)
/* If _write_header failed, copy the error. */
archive_copy_error(&a->archive, extract->ad);
archive_copy_error(&a->archive, ad);
else
/* Otherwise, pour data into the entry. */
r = copy_data(_a, a->extract->ad);
r2 = archive_write_finish_entry(a->extract->ad);
r = copy_data(_a, ad);
r2 = archive_write_finish_entry(ad);
if (r2 < ARCHIVE_WARN)
r2 = ARCHIVE_WARN;
/* Use the first message. */
if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
archive_copy_error(&a->archive, extract->ad);
archive_copy_error(&a->archive, ad);
/* Use the worst error return. */
if (r2 < r)
r = r2;

View File

@ -908,6 +908,11 @@ fprintf(stderr, " *** Discarding CE data.\n");
file->ce_size = 0;
}
/* Don't waste time seeking for zero-length bodies. */
if (file->size == 0) {
file->offset = iso9660->current_position;
}
/* If CE exists, find and read it now. */
if (file->ce_offset > 0)
offset = file->ce_offset;

View File

@ -145,6 +145,8 @@ struct sparse_block {
struct tar {
struct archive_string acl_text;
struct archive_string entry_pathname;
/* For "GNU.sparse.name" and other similar path extensions. */
struct archive_string entry_pathname_override;
struct archive_string entry_linkpath;
struct archive_string entry_uname;
struct archive_string entry_gname;
@ -272,6 +274,7 @@ archive_read_format_tar_cleanup(struct archive_read *a)
gnu_clear_sparse_list(tar);
archive_string_free(&tar->acl_text);
archive_string_free(&tar->entry_pathname);
archive_string_free(&tar->entry_pathname_override);
archive_string_free(&tar->entry_linkpath);
archive_string_free(&tar->entry_uname);
archive_string_free(&tar->entry_gname);
@ -1174,7 +1177,6 @@ pax_header(struct archive_read *a, struct tar *tar,
size_t attr_length, l, line_length;
char *line, *p;
char *key, *value;
wchar_t *wp;
int err, err2;
attr_length = strlen(attr);
@ -1182,6 +1184,7 @@ pax_header(struct archive_read *a, struct tar *tar,
archive_string_empty(&(tar->entry_gname));
archive_string_empty(&(tar->entry_linkpath));
archive_string_empty(&(tar->entry_pathname));
archive_string_empty(&(tar->entry_pathname_override));
archive_string_empty(&(tar->entry_uname));
err = ARCHIVE_OK;
while (attr_length > 0) {
@ -1257,13 +1260,13 @@ pax_header(struct archive_read *a, struct tar *tar,
if (tar->pax_hdrcharset_binary)
archive_entry_copy_gname(entry, value);
else {
wp = utf8_decode(tar, value, strlen(value));
if (wp == NULL) {
archive_entry_copy_gname(entry, value);
if (err > ARCHIVE_WARN)
err = ARCHIVE_WARN;
} else
archive_entry_copy_gname_w(entry, wp);
if (!archive_entry_update_gname_utf8(entry, value)) {
err = ARCHIVE_WARN;
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Gname in pax header can't "
"be converted to current locale.");
}
}
}
if (archive_strlen(&(tar->entry_linkpath)) > 0) {
@ -1271,27 +1274,40 @@ pax_header(struct archive_read *a, struct tar *tar,
if (tar->pax_hdrcharset_binary)
archive_entry_copy_link(entry, value);
else {
wp = utf8_decode(tar, value, strlen(value));
if (wp == NULL) {
archive_entry_copy_link(entry, value);
if (err > ARCHIVE_WARN)
err = ARCHIVE_WARN;
} else
archive_entry_copy_link_w(entry, wp);
if (!archive_entry_update_link_utf8(entry, value)) {
err = ARCHIVE_WARN;
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Linkname in pax header can't "
"be converted to current locale.");
}
}
}
if (archive_strlen(&(tar->entry_pathname)) > 0) {
/*
* Some extensions (such as the GNU sparse file extensions)
* deliberately store a synthetic name under the regular 'path'
* attribute and the real file name under a different attribute.
* Since we're supposed to not care about the order, we
* have no choice but to store all of the various filenames
* we find and figure it all out afterwards. This is the
* figuring out part.
*/
value = NULL;
if (archive_strlen(&(tar->entry_pathname_override)) > 0)
value = tar->entry_pathname_override.s;
else if (archive_strlen(&(tar->entry_pathname)) > 0)
value = tar->entry_pathname.s;
if (value != NULL) {
if (tar->pax_hdrcharset_binary)
archive_entry_copy_pathname(entry, value);
else {
wp = utf8_decode(tar, value, strlen(value));
if (wp == NULL) {
archive_entry_copy_pathname(entry, value);
if (err > ARCHIVE_WARN)
err = ARCHIVE_WARN;
} else
archive_entry_copy_pathname_w(entry, wp);
if (!archive_entry_update_pathname_utf8(entry, value)) {
err = ARCHIVE_WARN;
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Pathname in pax header can't be "
"converted to current locale.");
}
}
}
if (archive_strlen(&(tar->entry_uname)) > 0) {
@ -1299,13 +1315,13 @@ pax_header(struct archive_read *a, struct tar *tar,
if (tar->pax_hdrcharset_binary)
archive_entry_copy_uname(entry, value);
else {
wp = utf8_decode(tar, value, strlen(value));
if (wp == NULL) {
archive_entry_copy_uname(entry, value);
if (err > ARCHIVE_WARN)
err = ARCHIVE_WARN;
} else
archive_entry_copy_uname_w(entry, wp);
if (!archive_entry_update_uname_utf8(entry, value)) {
err = ARCHIVE_WARN;
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Uname in pax header can't "
"be converted to current locale.");
}
}
}
return (err);
@ -1415,11 +1431,13 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
tar->sparse_gnu_pending = 1;
}
if (strcmp(key, "GNU.sparse.name") == 0) {
wp = utf8_decode(tar, value, strlen(value));
if (wp != NULL)
archive_entry_copy_pathname_w(entry, wp);
else
archive_entry_copy_pathname(entry, value);
/*
* The real filename; when storing sparse
* files, GNU tar puts a synthesized name into
* the regular 'path' attribute in an attempt
* to limit confusion. ;-)
*/
archive_strcpy(&(tar->entry_pathname_override), value);
}
if (strcmp(key, "GNU.sparse.realsize") == 0) {
tar->realsize = tar_atol10(value, strlen(value));
@ -1455,9 +1473,7 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
archive_entry_set_rdevminor(entry,
tar_atol10(value, strlen(value)));
} else if (strcmp(key, "SCHILY.fflags")==0) {
wp = utf8_decode(tar, value, strlen(value));
/* TODO: if (wp == NULL) */
archive_entry_copy_fflags_text_w(entry, wp);
archive_entry_copy_fflags_text(entry, value);
} else if (strcmp(key, "SCHILY.dev")==0) {
archive_entry_set_dev(entry,
tar_atol10(value, strlen(value)));

View File

@ -37,6 +37,9 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_string.c,v 1.11 2007/07/15 19:13:
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_WCHAR_H
#include <wchar.h>
#endif
#include "archive_private.h"
#include "archive_string.h"
@ -55,11 +58,15 @@ __archive_string_append(struct archive_string *as, const char *p, size_t s)
void
__archive_string_copy(struct archive_string *dest, struct archive_string *src)
{
if (__archive_string_ensure(dest, src->length + 1) == NULL)
__archive_errx(1, "Out of memory");
memcpy(dest->s, src->s, src->length);
dest->length = src->length;
dest->s[dest->length] = 0;
if (src->length == 0)
dest->length = 0;
else {
if (__archive_string_ensure(dest, src->length + 1) == NULL)
__archive_errx(1, "Out of memory");
memcpy(dest->s, src->s, src->length);
dest->length = src->length;
dest->s[dest->length] = 0;
}
}
void
@ -67,21 +74,52 @@ __archive_string_free(struct archive_string *as)
{
as->length = 0;
as->buffer_length = 0;
if (as->s != NULL)
if (as->s != NULL) {
free(as->s);
as->s = NULL;
}
}
/* Returns NULL on any allocation failure. */
struct archive_string *
__archive_string_ensure(struct archive_string *as, size_t s)
{
/* If buffer is already big enough, don't reallocate. */
if (as->s && (s <= as->buffer_length))
return (as);
/*
* Growing the buffer at least exponentially ensures that
* append operations are always linear in the number of
* characters appended. Using a smaller growth rate for
* larger buffers reduces memory waste somewhat at the cost of
* a larger constant factor.
*/
if (as->buffer_length < 32)
/* Start with a minimum 32-character buffer. */
as->buffer_length = 32;
while (as->buffer_length < s)
else if (as->buffer_length < 8192)
/* Buffers under 8k are doubled for speed. */
as->buffer_length *= 2;
else {
/* Buffers 8k and over grow by at least 25% each time. */
size_t old_length = as->buffer_length;
as->buffer_length = (as->buffer_length * 5) / 4;
/* Be safe: If size wraps, release buffer and return NULL. */
if (as->buffer_length < old_length) {
free(as->s);
as->s = NULL;
return (NULL);
}
}
/*
* The computation above is a lower limit to how much we'll
* grow the buffer. In any case, we have to grow it enough to
* hold the request.
*/
if (as->buffer_length < s)
as->buffer_length = s;
/* Now we can reallocate the buffer. */
as->s = (char *)realloc(as->s, as->buffer_length);
if (as->s == NULL)
return (NULL);
@ -124,3 +162,206 @@ __archive_strappend_int(struct archive_string *as, int d, int base)
__archive_strappend_char(as, digits[d % base]);
return (as);
}
/*
* Home-grown wcrtomb for UTF-8.
*/
static size_t
my_wcrtomb_utf8(char *p, wchar_t wc, mbstate_t *s)
{
(void)s; /* UNUSED */
if (p == NULL)
return (0);
if (wc <= 0x7f) {
p[0] = (char)wc;
return (1);
}
if (wc <= 0x7ff) {
p[0] = 0xc0 | ((wc >> 6) & 0x1f);
p[1] = 0x80 | (wc & 0x3f);
return (2);
}
if (wc <= 0xffff) {
p[0] = 0xe0 | ((wc >> 12) & 0x0f);
p[1] = 0x80 | ((wc >> 6) & 0x3f);
p[2] = 0x80 | (wc & 0x3f);
return (3);
}
if (wc <= 0x1fffff) {
p[0] = 0xf0 | ((wc >> 18) & 0x07);
p[1] = 0x80 | ((wc >> 12) & 0x3f);
p[2] = 0x80 | ((wc >> 6) & 0x3f);
p[3] = 0x80 | (wc & 0x3f);
return (4);
}
/* Unicode has no codes larger than 0x1fffff. */
/*
* Awkward point: UTF-8 <-> wchar_t conversions
* can actually fail.
*/
return ((size_t)-1);
}
static int
my_wcstombs(struct archive_string *as, const wchar_t *w,
size_t (*func)(char *, wchar_t, mbstate_t *))
{
size_t n;
char *p;
mbstate_t shift_state;
char buff[256];
/*
* Convert one wide char at a time into 'buff', whenever that
* fills, append it to the string.
*/
p = buff;
wcrtomb(NULL, L'\0', &shift_state);
while (*w != L'\0') {
/* Flush the buffer when we have <=16 bytes free. */
/* (No encoding has a single character >16 bytes.) */
if ((size_t)(p - buff) >= (size_t)(sizeof(buff) - 16)) {
*p = '\0';
archive_strcat(as, buff);
p = buff;
}
n = (*func)(p, *w++, &shift_state);
if (n == (size_t)-1)
return (-1);
p += n;
}
*p = '\0';
archive_strcat(as, buff);
return (0);
}
/*
* Translates a wide character string into UTF-8 and appends
* to the archive_string. Note: returns NULL if conversion fails.
*/
struct archive_string *
__archive_strappend_w_utf8(struct archive_string *as, const wchar_t *w)
{
if (my_wcstombs(as, w, my_wcrtomb_utf8))
return (NULL);
return (as);
}
/*
* Translates a wide character string into current locale character set
* and appends to the archive_string. Note: returns NULL if conversion
* fails.
*
* TODO: use my_wcrtomb_utf8 if !HAVE_WCRTOMB (add configure logic first!)
*/
struct archive_string *
__archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w)
{
if (my_wcstombs(as, w, wcrtomb))
return (NULL);
return (as);
}
/*
* Home-grown mbrtowc for UTF-8. Some systems lack UTF-8
* (or even lack mbrtowc()) and we need UTF-8 support for pax
* format. So please don't replace this with a call to the
* standard mbrtowc() function!
*/
static size_t
my_mbrtowc_utf8(wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
{
int ch;
/*
* This argument is here to make the prototype identical to the
* standard mbrtowc(), so I can build generic string processors
* that just accept a pointer to a suitable mbrtowc() function.
*/
(void)ps; /* UNUSED */
/* Standard behavior: a NULL value for 's' just resets shift state. */
if (s == NULL)
return (0);
/* If length argument is zero, don't look at the first character. */
if (n <= 0)
return ((size_t)-2);
/*
* Decode 1-4 bytes depending on the value of the first byte.
*/
ch = (unsigned char)*s;
if (ch == 0) {
return (0); /* Standard: return 0 for end-of-string. */
}
if ((ch & 0x80) == 0) {
*pwc = ch & 0x7f;
return (1);
}
if ((ch & 0xe0) == 0xc0) {
if (n < 2)
return ((size_t)-2);
if ((s[1] & 0xc0) != 0x80) return (size_t)-1;
*pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
return (2);
}
if ((ch & 0xf0) == 0xe0) {
if (n < 3)
return ((size_t)-2);
if ((s[1] & 0xc0) != 0x80) return (size_t)-1;
if ((s[2] & 0xc0) != 0x80) return (size_t)-1;
*pwc = ((ch & 0x0f) << 12)
| ((s[1] & 0x3f) << 6)
| (s[2] & 0x3f);
return (3);
}
if ((ch & 0xf8) == 0xf0) {
if (n < 4)
return ((size_t)-2);
if ((s[1] & 0xc0) != 0x80) return (size_t)-1;
if ((s[2] & 0xc0) != 0x80) return (size_t)-1;
if ((s[3] & 0xc0) != 0x80) return (size_t)-1;
*pwc = ((ch & 0x07) << 18)
| ((s[1] & 0x3f) << 12)
| ((s[2] & 0x3f) << 6)
| (s[3] & 0x3f);
return (4);
}
/* Invalid first byte. */
return ((size_t)-1);
}
/*
* Return a wide-character string by converting this archive_string
* from UTF-8.
*/
wchar_t *
__archive_string_utf8_w(struct archive_string *as)
{
wchar_t *ws, *dest;
const char *src;
size_t n;
int err;
ws = (wchar_t *)malloc((as->length + 1) * sizeof(wchar_t));
if (ws == NULL)
__archive_errx(1, "Out of memory");
err = 0;
dest = ws;
src = as->s;
while (*src != '\0') {
n = my_mbrtowc_utf8(dest, src, 8, NULL);
if (n == 0)
break;
if (n == (size_t)-1 || n == (size_t)-2) {
free(ws);
return (NULL);
}
dest++;
src += n;
}
*dest++ = L'\0';
return (ws);
}

View File

@ -33,6 +33,9 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_WCHAR_H
#include <wchar.h>
#endif
/*
* Basic resizable/reusable string support a la Java's "StringBuffer."
@ -60,16 +63,22 @@ struct archive_string *
__archive_strappend_char(struct archive_string *, char);
#define archive_strappend_char __archive_strappend_char
/* Append a char to an archive_string using UTF8. */
struct archive_string *
__archive_strappend_char_UTF8(struct archive_string *, int);
#define archive_strappend_char_UTF8 __archive_strappend_char_UTF8
/* Append an integer in the specified base (2 <= base <= 16). */
struct archive_string *
__archive_strappend_int(struct archive_string *as, int d, int base);
#define archive_strappend_int __archive_strappend_int
/* Convert a wide-char string to UTF-8 and append the result. */
struct archive_string *
__archive_strappend_w_utf8(struct archive_string *, const wchar_t *);
#define archive_strappend_w_utf8 __archive_strappend_w_utf8
/* Convert a wide-char string to current locale and append the result. */
/* Returns NULL if conversion fails. */
struct archive_string *
__archive_strappend_w_mbs(struct archive_string *, const wchar_t *);
#define archive_strappend_w_mbs __archive_strappend_w_mbs
/* Basic append operation. */
struct archive_string *
__archive_string_append(struct archive_string *as, const char *p, size_t s);
@ -95,7 +104,7 @@ __archive_strncat(struct archive_string *, const char *, size_t);
/* Copy a C string to an archive_string, resizing as necessary. */
#define archive_strcpy(as,p) \
((as)->length = 0, __archive_string_append((as), (p), strlen(p)))
((as)->length = 0, __archive_string_append((as), (p), p == NULL ? 0 : strlen(p)))
/* Copy a C string to an archive_string with limit, resizing as necessary. */
#define archive_strncpy(as,p,l) \
@ -119,4 +128,9 @@ void __archive_string_vsprintf(struct archive_string *, const char *,
void __archive_string_sprintf(struct archive_string *, const char *, ...);
#define archive_string_sprintf __archive_string_sprintf
/* Allocates a fresh buffer and converts as (assumed to be UTF-8) into it.
* Returns NULL if conversion failed in any way. */
wchar_t *__archive_string_utf8_w(struct archive_string *as);
#endif

View File

@ -386,7 +386,7 @@ archive_write_pax_header(struct archive_write *a,
const char *p;
char *t;
const wchar_t *wp;
const char *suffix_start;
const char *suffix;
int need_extension, r, ret;
struct pax *pax;
const char *hdrcharset = NULL;
@ -496,34 +496,73 @@ archive_write_pax_header(struct archive_write *a,
if (hdrcharset != NULL)
add_pax_attr(&(pax->pax_header), "hdrcharset", hdrcharset);
/*
* Determining whether or not the name is too big is ugly
* because of the rules for dividing names between 'name' and
* 'prefix' fields. Here, I pick out the longest possible
* suffix, then test whether the remaining prefix is too long.
*/
if (strlen(path) <= 100) /* Short enough for just 'name' field */
suffix_start = path; /* Record a zero-length prefix */
else
/* Find the largest suffix that fits in 'name' field. */
suffix_start = strchr(path + strlen(path) - 100 - 1, '/');
/*
* If name is too long, or has non-ASCII characters, add
* 'path' to pax extended attrs. (Note that an unconvertible
* name must have non-ASCII characters.)
*/
if (suffix_start == NULL || suffix_start - path > 155
|| path_w == NULL || has_non_ASCII(path_w)) {
if (path_w == NULL || hdrcharset != NULL)
if (path == NULL) {
/* We don't have a narrow version, so we have to store
* the wide version. */
add_pax_attr_w(&(pax->pax_header), "path", path_w);
archive_entry_set_pathname(entry_main, "@WidePath");
need_extension = 1;
} else if (has_non_ASCII(path_w)) {
/* We have non-ASCII characters. */
if (path_w == NULL || hdrcharset != NULL) {
/* Can't do UTF-8, so store it raw. */
add_pax_attr(&(pax->pax_header), "path", path);
else
add_pax_attr_w(&(pax->pax_header), "path", path_w);
} else {
/* Store UTF-8 */
add_pax_attr_w(&(pax->pax_header),
"path", path_w);
}
archive_entry_set_pathname(entry_main,
build_ustar_entry_name(ustar_entry_name,
path, strlen(path), NULL));
need_extension = 1;
} else {
/* We have an all-ASCII path; we'd like to just store
* it in the ustar header if it will fit. Yes, this
* duplicates some of the logic in
* write_set_format_ustar.c
*/
if (strlen(path) <= 100) {
/* Fits in the old 100-char tar name field. */
} else {
/* Find largest suffix that will fit. */
/* Note: strlen() > 100, so strlen() - 100 - 1 >= 0 */
suffix = strchr(path + strlen(path) - 100 - 1, '/');
/* Don't attempt an empty prefix. */
if (suffix == path)
suffix = strchr(suffix + 1, '/');
/* We can put it in the ustar header if it's
* all ASCII and it's either <= 100 characters
* or can be split at a '/' into a prefix <=
* 155 chars and a suffix <= 100 chars. (Note
* the strchr() above will return NULL exactly
* when the path can't be split.)
*/
if (suffix == NULL /* Suffix > 100 chars. */
|| suffix[1] == '\0' /* empty suffix */
|| suffix - path > 155) /* Prefix > 155 chars */
{
if (path_w == NULL || hdrcharset != NULL) {
/* Can't do UTF-8, so store it raw. */
add_pax_attr(&(pax->pax_header),
"path", path);
} else {
/* Store UTF-8 */
add_pax_attr_w(&(pax->pax_header),
"path", path_w);
}
archive_entry_set_pathname(entry_main,
build_ustar_entry_name(ustar_entry_name,
path, strlen(path), NULL));
need_extension = 1;
}
}
}
if (linkpath != NULL) {
@ -1215,6 +1254,8 @@ archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
static int
has_non_ASCII(const wchar_t *wp)
{
if (wp == NULL)
return (1);
while (*wp != L'\0' && *wp < 128)
wp++;
return (*wp != L'\0');

View File

@ -206,7 +206,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
!(archive_entry_filetype(entry) == AE_IFREG))
archive_entry_set_size(entry, 0);
if (AE_IFDIR == archive_entry_mode(entry)) {
if (AE_IFDIR == archive_entry_filetype(entry)) {
const char *p;
char *t;
/*
@ -282,24 +282,30 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
/* Store in two pieces, splitting at a '/'. */
p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/');
/*
* If the separator we found is the first '/', find
* the next one. (This is a pathological case that
* occurs for paths of exactly 101 bytes that start with
* '/'; it occurs because the separating '/' is not
* stored explicitly and the reconstruction assumes that
* an empty prefix means there is no '/' separator.)
* Look for the next '/' if we chose the first character
* as the separator. (ustar format doesn't permit
* an empty prefix.)
*/
if (p == pp)
p = strchr(p + 1, '/');
/*
* If there is no path separator, or the prefix or
* remaining name are too large, return an error.
*/
/* Fail if the name won't fit. */
if (!p) {
/* No separator. */
archive_set_error(&a->archive, ENAMETOOLONG,
"Pathname too long");
ret = ARCHIVE_WARN;
} else if (p[1] == '\0') {
/*
* The only feasible separator is a final '/';
* this would result in a non-empty prefix and
* an empty name, which POSIX doesn't
* explicity forbid, but it just feels wrong.
*/
archive_set_error(&a->archive, ENAMETOOLONG,
"Pathname too long");
ret = ARCHIVE_WARN;
} else if (p > pp + USTAR_prefix_size) {
/* Prefix is too long. */
archive_set_error(&a->archive, ENAMETOOLONG,
"Pathname too long");
ret = ARCHIVE_WARN;

View File

@ -149,7 +149,7 @@ followed by the least-significant 16 bits.
Each of the two 16 bit values are stored in machine-native byte order.
.It Va namesize
The number of bytes in the pathname that follows the header.
This count includes the trailing NULL byte.
This count includes the trailing NUL byte.
.It Va filesize
The size of the file.
Note that this archive format is limited to
@ -162,8 +162,8 @@ above for a description of the storage of four-byte integers.
The pathname immediately follows the fixed header.
If the
.Cm namesize
is odd, an additional NULL byte is added after the pathname.
The file data is then appended, padded with NULL
is odd, an additional NUL byte is added after the pathname.
The file data is then appended, padded with NUL
bytes to an even length.
.Pp
Hardlinked files are not given special treatment;
@ -202,7 +202,7 @@ Unlike the old binary format, there is no additional padding
after the pathname or file contents.
If the files being archived are themselves entirely ASCII, then
the resulting archive will be entirely ASCII, except for the
NULL byte that terminates the name field.
NUL byte that terminates the name field.
.Ss New ASCII Format
The "new" ASCII format uses 8-byte hexadecimal fields for
all numbers and separates device numbers into separate fields
@ -237,7 +237,7 @@ This field is always set to zero by writers and ignored by readers.
See the next section for more details.
.El
.Pp
The pathname is followed by NULL bytes so that the total size
The pathname is followed by NUL bytes so that the total size
of the fixed header plus pathname is a multiple of four.
Likewise, the file data is padded to a multiple of four bytes.
Note that this format supports only 4 gigabyte files (unlike the
@ -322,4 +322,4 @@ by SCO under their
license.
The character format was adopted as part of
.St -p1003.1-88 .
XXX when did "newc" appear? Who invented it? When did HP come out with their variant? When did Sun introduce ACLs and extended attributes? XXX
XXX when did "newc" appear? Who invented it? When did HP come out with their variant? When did Sun introduce ACLs and extended attributes? XXX

View File

@ -221,7 +221,7 @@ field with several new type values:
.Bl -tag -width indent -compact
.It Dq 0
Regular file.
NULL should be treated as a synonym, for compatibility purposes.
NUL should be treated as a synonym, for compatibility purposes.
.It Dq 1
Hard link.
.It Dq 2
@ -258,7 +258,7 @@ by readers.
.It Va magic
Contains the magic value
.Dq ustar
followed by a NULL byte to indicate that this is a POSIX standard archive.
followed by a NUL byte to indicate that this is a POSIX standard archive.
Full compliance requires the uname and gname fields be properly set.
.It Va version
Version.
@ -285,7 +285,7 @@ character to the regular name field to obtain the full pathname.
.El
.Pp
Note that all unused bytes must be set to
.Dv NULL .
.Dv NUL .
.Pp
Field termination is specified slightly differently by POSIX
than by previous implementations.
@ -295,14 +295,14 @@ The
and
.Va gname
fields must have a trailing
.Dv NULL .
.Dv NUL .
The
.Va pathname ,
.Va linkname ,
and
.Va prefix
fields must have a trailing
.Dv NULL
.Dv NUL
unless they fill the entire field.
(In particular, it is possible to store a 256-character pathname if it
happens to have a
@ -310,7 +310,7 @@ happens to have a
as the 156th character.)
POSIX requires numeric fields to be zero-padded in the front, and allows
them to be terminated with either space or
.Dv NULL
.Dv NUL
characters.
.Pp
Currently, most tar implementations comply with the ustar

View File

@ -9,7 +9,9 @@ DEFINE_TEST(test_empty_write)
DEFINE_TEST(test_entry)
DEFINE_TEST(test_entry_strmode)
DEFINE_TEST(test_link_resolver)
DEFINE_TEST(test_pax_filename_encoding)
DEFINE_TEST(test_pax_filename_encoding_1)
DEFINE_TEST(test_pax_filename_encoding_2)
DEFINE_TEST(test_pax_filename_encoding_3)
DEFINE_TEST(test_read_compress_program)
DEFINE_TEST(test_read_data_large)
DEFINE_TEST(test_read_extract)
@ -29,6 +31,7 @@ DEFINE_TEST(test_read_format_isorr_bz2)
DEFINE_TEST(test_read_format_mtree)
DEFINE_TEST(test_read_format_pax_bz2)
DEFINE_TEST(test_read_format_tar)
DEFINE_TEST(test_read_format_tar_empty_filename)
DEFINE_TEST(test_read_format_tbz)
DEFINE_TEST(test_read_format_tgz)
DEFINE_TEST(test_read_format_tz)
@ -39,6 +42,7 @@ DEFINE_TEST(test_read_position)
DEFINE_TEST(test_read_truncated)
DEFINE_TEST(test_tar_filenames)
DEFINE_TEST(test_tar_large)
DEFINE_TEST(test_ustar_filenames)
DEFINE_TEST(test_write_compress)
DEFINE_TEST(test_write_compress_program)
DEFINE_TEST(test_write_disk)
@ -53,4 +57,5 @@ DEFINE_TEST(test_write_format_cpio_odc)
DEFINE_TEST(test_write_format_shar_empty)
DEFINE_TEST(test_write_format_tar)
DEFINE_TEST(test_write_format_tar_empty)
DEFINE_TEST(test_write_format_tar_ustar)
DEFINE_TEST(test_write_open_memory)

View File

@ -63,10 +63,14 @@ extern char *optarg;
extern int optind;
#endif
/* Default is to crash and try to force a core dump on failure. */
static int dump_on_failure = 1;
/* Enable core dump on failure. */
static int dump_on_failure = 0;
/* Default is to remove temp dirs for successful tests. */
static int keep_temp_files = 0;
/* Default is to print some basic information about each test. */
static int quiet_flag = 0;
/* Default is to summarize repeated failures. */
static int verbose = 0;
/* Cumulative count of component failures. */
static int failures = 0;
/* Cumulative count of skipped component tests. */
@ -242,7 +246,7 @@ test_assert(const char *file, int line, int value, const char *condition, void *
return (value);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (value);
fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
fprintf(stderr, " Condition: %s\n", condition);
@ -261,7 +265,7 @@ test_assert_equal_int(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n",
file, line);
@ -271,6 +275,30 @@ test_assert_equal_int(const char *file, int line,
return (0);
}
static void strdump(const char *p)
{
if (p == NULL) {
fprintf(stderr, "(null)");
return;
}
fprintf(stderr, "\"");
while (*p != '\0') {
unsigned int c = 0xff & *p++;
switch (c) {
case '\a': fprintf(stderr, "\a"); break;
case '\b': fprintf(stderr, "\b"); break;
case '\n': fprintf(stderr, "\n"); break;
case '\r': fprintf(stderr, "\r"); break;
default:
if (c >= 32 && c < 127)
fprintf(stderr, "%c", c);
else
fprintf(stderr, "\\x%02X", c);
}
}
fprintf(stderr, "\"");
}
/* assertEqualString() displays the values of the two strings. */
int
test_assert_equal_string(const char *file, int line,
@ -289,16 +317,41 @@ test_assert_equal_string(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
file, line);
fprintf(stderr, " %s = \"%s\"\n", e1, v1);
fprintf(stderr, " %s = \"%s\"\n", e2, v2);
fprintf(stderr, " %s = ", e1);
strdump(v1);
fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : strlen(v1));
fprintf(stderr, " %s = ", e2);
strdump(v2);
fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : strlen(v2));
report_failure(extra);
return (0);
}
static void wcsdump(const wchar_t *w)
{
if (w == NULL) {
fprintf(stderr, "(null)");
return;
}
fprintf(stderr, "\"");
while (*w != L'\0') {
unsigned int c = *w++;
if (c >= 32 && c < 127)
fprintf(stderr, "%c", c);
else if (c < 256)
fprintf(stderr, "\\x%02X", c);
else if (c < 0x10000)
fprintf(stderr, "\\u%04X", c);
else
fprintf(stderr, "\\U%08X", c);
}
fprintf(stderr, "\"");
}
/* assertEqualWString() displays the values of the two strings. */
int
test_assert_equal_wstring(const char *file, int line,
@ -307,17 +360,31 @@ test_assert_equal_wstring(const char *file, int line,
void *extra)
{
++assertions;
if (wcscmp(v1, v2) == 0) {
if (v1 == NULL) {
if (v2 == NULL) {
msg[0] = '\0';
return (1);
}
} else if (v2 == NULL) {
if (v1 == NULL) {
msg[0] = '\0';
return (1);
}
} else if (wcscmp(v1, v2) == 0) {
msg[0] = '\0';
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n",
file, line);
fwprintf(stderr, L" %s = \"%ls\"\n", e1, v1);
fwprintf(stderr, L" %s = \"%ls\"\n", e2, v2);
fprintf(stderr, " %s = ", e1);
wcsdump(v1);
fprintf(stderr, "\n");
fprintf(stderr, " %s = ", e2);
wcsdump(v2);
fprintf(stderr, "\n");
report_failure(extra);
return (0);
}
@ -378,7 +445,7 @@ test_assert_equal_mem(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n",
file, line);
@ -410,12 +477,13 @@ test_assert_empty_file(const char *f1fmt, ...)
if (stat(f1, &st) != 0) {
fprintf(stderr, "%s:%d: Could not stat: %s\n", test_filename, test_line, f1);
report_failure(NULL);
return (0);
}
if (st.st_size == 0)
return (1);
failures ++;
if (previous_failures(test_filename, test_line))
if (!verbose && previous_failures(test_filename, test_line))
return (0);
fprintf(stderr, "%s:%d: File not empty: %s\n", test_filename, test_line, f1);
@ -462,7 +530,7 @@ test_assert_equal_file(const char *f1, const char *f2pattern, ...)
break;
}
failures ++;
if (previous_failures(test_filename, test_line))
if (!verbose && previous_failures(test_filename, test_line))
return (0);
fprintf(stderr, "%s:%d: Files are not identical\n",
test_filename, test_line);
@ -633,6 +701,12 @@ static int test_run(int i, const char *tmpdir)
(*tests[i].func)();
/* Summarize the results of this test. */
summarize();
/* If there were no failures, we can remove the work dir. */
if (failures == failures_before) {
if (!keep_temp_files && chdir(tmpdir) == 0) {
systemf("rm -rf %s", tests[i].name);
}
}
/* Return appropriate status. */
return (failures == failures_before ? 0 : 1);
}
@ -646,8 +720,9 @@ static void usage(const char *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(" -k Keep running after failures.\n");
printf(" Default: Core dump after any failure.\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");
@ -655,6 +730,7 @@ static void usage(const char *program)
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);
@ -747,9 +823,9 @@ int main(int argc, char **argv)
testprog = getenv(ENVBASE);
#endif
/* Allow -k to be controlled through the environment. */
if (getenv(ENVBASE "_KEEP_GOING") != NULL)
dump_on_failure = 0;
/* Allow -d to be controlled through the environment. */
if (getenv(ENVBASE "_DEBUG") != NULL)
dump_on_failure = 1;
/* Get the directory holding test files from environment. */
refdir = getenv(ENVBASE "_TEST_FILES");
@ -757,10 +833,13 @@ int main(int argc, char **argv)
/*
* Parse options.
*/
while ((opt = getopt(argc, argv, "kp:qr:")) != -1) {
while ((opt = getopt(argc, argv, "dkp:qr:v")) != -1) {
switch (opt) {
case 'd':
dump_on_failure = 1;
break;
case 'k':
dump_on_failure = 0;
keep_temp_files = 1;
break;
case 'p':
#ifdef PROGRAM
@ -775,6 +854,9 @@ int main(int argc, char **argv)
case 'r':
refdir = optarg;
break;
case 'v':
verbose = 1;
break;
case '?':
default:
usage(progname);
@ -823,6 +905,7 @@ int main(int argc, char **argv)
--p;
*p = '\0';
}
systemf("rm %s/refdir", tmpdir);
}
/*
@ -878,5 +961,9 @@ int main(int argc, char **argv)
free(refdir_alloc);
/* If the final tmpdir is empty, we can remove it. */
/* This should be the usual case when all tests succeed. */
rmdir(tmpdir);
return (tests_failed);
}

View File

@ -332,14 +332,10 @@ acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const cha
return (1);
if (qual != acl->qual)
return (0);
if (name == NULL) {
if (acl->name == NULL || acl->name[0] == '\0')
return (1);
}
if (acl->name == NULL) {
if (name[0] == '\0')
return (1);
}
if (name == NULL)
return (acl->name == NULL || acl->name[0] == '\0');
if (acl->name == NULL)
return (name == NULL || name[0] == '\0');
return (0 == strcmp(name, acl->name));
}

View File

@ -28,7 +28,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_archive_api_feature.c,v 1.4 200
DEFINE_TEST(test_archive_api_feature)
{
char buff[128];
char *p;
const char *p;
/* This is the (hopefully) final versioning API. */
assertEqualInt(ARCHIVE_VERSION_NUMBER, archive_version_number());

View File

@ -52,6 +52,8 @@ DEFINE_TEST(test_entry)
const void *xval; /* For xattr tests. */
size_t xsize; /* For xattr tests. */
int c;
wchar_t wc;
long l;
assert((e = archive_entry_new()) != NULL);
@ -146,7 +148,7 @@ DEFINE_TEST(test_entry)
archive_entry_copy_link_w(e, L"link3");
assertEqualString(archive_entry_hardlink(e), NULL);
assertEqualString(archive_entry_symlink(e), "link3");
/* Arbitrarily override hardlink if both hardlink and symlink set. */
/* Arbitrarily override symlink if both hardlink and symlink set. */
archive_entry_set_hardlink(e, "hardlink");
archive_entry_set_symlink(e, "symlink");
archive_entry_set_link(e, "link");
@ -726,8 +728,10 @@ DEFINE_TEST(test_entry)
/*
* Exercise the character-conversion logic, if we can.
*/
failure("Can't exercise charset-conversion logic.");
if (assert(NULL != setlocale(LC_ALL, "de_DE.UTF-8"))) {
if (NULL == setlocale(LC_ALL, "de_DE.UTF-8")) {
skipping("Can't exercise charset-conversion logic without"
" a suitable locale.");
} else {
/* A filename that cannot be converted to wide characters. */
archive_entry_copy_pathname(e, "abc\314\214mno\374xyz");
failure("Converting invalid chars to Unicode should fail.");
@ -756,6 +760,26 @@ DEFINE_TEST(test_entry)
assert(NULL == archive_entry_symlink_w(e));
}
l = 0x12345678L;
wc = (wchar_t)l; /* Wide character too big for UTF-8. */
if (NULL == setlocale(LC_ALL, "C") || (long)wc != l) {
skipping("Testing charset conversion failure requires 32-bit wchar_t and support for \"C\" locale.");
} else {
/*
* Build the string L"xxx\U12345678yyy\u5678zzz" without
* using C99 \u#### syntax, which isn't uniformly
* supported. (GCC 3.4.6, for instance, defaults to
* "c89 plus GNU extensions.")
*/
wcscpy(wbuff, L"xxxAyyyBzzz");
wbuff[3] = 0x12345678;
wbuff[7] = 0x5678;
/* A wide filename that cannot be converted to narrow. */
archive_entry_copy_pathname_w(e, wbuff);
failure("Converting wide characters from Unicode should fail.");
assertEqualString(NULL, archive_entry_pathname(e));
}
/* Release the experimental entry. */
archive_entry_free(e);
}

View File

@ -34,24 +34,20 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_pax_filename_encoding.c,v 1.1 2
* stored and restored correctly, regardless of the encodings.
*/
DEFINE_TEST(test_pax_filename_encoding)
/*
* Read a manually-created archive that has filenames that are
* stored in binary instead of UTF-8 and verify that we get
* the right filename returned and that we get a warning only
* if the header isn't marked as binary.
*/
DEFINE_TEST(test_pax_filename_encoding_1)
{
static const char testname[] = "test_pax_filename_encoding.tar.gz";
char buff[65536];
/*
* \314\214 is a valid 2-byte UTF-8 sequence.
* \374 is invalid in UTF-8.
*/
char filename[] = "abc\314\214mno\374xyz";
char longname[] = "abc\314\214mno\374xyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
;
size_t used;
struct archive *a;
struct archive_entry *entry;
@ -69,8 +65,7 @@ DEFINE_TEST(test_pax_filename_encoding)
* in it, but the header is not marked as hdrcharset=BINARY, so that
* requires a warning.
*/
failure("An invalid UTF8 pathname in a pax archive should be read\n"
" without conversion but with a warning");
failure("Invalid UTF8 in a pax archive pathname should cause a warning");
assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
assertEqualString(filename, archive_entry_pathname(entry));
/*
@ -82,15 +77,39 @@ DEFINE_TEST(test_pax_filename_encoding)
assertEqualInt(ARCHIVE_OK, archive_read_next_header(a, &entry));
assertEqualString(filename, archive_entry_pathname(entry));
archive_read_finish(a);
}
/*
* Set the locale and write a pathname containing invalid characters.
* This should work; the underlying implementation should automatically
* fall back to storing the pathname in binary.
*/
DEFINE_TEST(test_pax_filename_encoding_2)
{
char filename[] = "abc\314\214mno\374xyz";
struct archive *a;
struct archive_entry *entry;
char buff[65536];
char longname[] = "abc\314\214mno\374xyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
"/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
;
size_t used;
/*
* We need a starting locale which has invalid sequences.
* de_DE.UTF-8 seems to be commonly supported.
*/
/* If it doesn't exist, just warn and return. */
failure("We need a suitable locale for the encoding tests.");
if (!assert(NULL != setlocale(LC_ALL, "de_DE.UTF-8")))
if (NULL == setlocale(LC_ALL, "de_DE.UTF-8")) {
skipping("invalid encoding tests require a suitable locale;"
" de_DE.UTF-8 not available on this system");
return;
}
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, 0, archive_write_set_format_pax(a));
@ -159,3 +178,120 @@ DEFINE_TEST(test_pax_filename_encoding)
assertEqualInt(0, archive_read_finish(a));
}
/*
* Create an entry starting from a wide-character Unicode pathname,
* read it back into "C" locale, which doesn't support the name.
* TODO: Figure out the "right" behavior here.
*/
DEFINE_TEST(test_pax_filename_encoding_3)
{
wchar_t badname[] = L"xxxAyyyBzzz";
const char badname_utf8[] = "xxx\xE1\x88\xB4yyy\xE5\x99\xB8zzz";
struct archive *a;
struct archive_entry *entry;
char buff[65536];
size_t used;
badname[3] = 0x1234;
badname[7] = 0x5678;
/* If it doesn't exist, just warn and return. */
if (NULL == setlocale(LC_ALL, "C")) {
skipping("Can't set \"C\" locale, so can't exercise "
"certain character-conversion failures");
return;
}
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, 0, archive_write_set_format_pax(a));
assertEqualIntA(a, 0, archive_write_set_compression_none(a));
assertEqualIntA(a, 0, archive_write_set_bytes_per_block(a, 0));
assertEqualInt(0,
archive_write_open_memory(a, buff, sizeof(buff), &used));
assert((entry = archive_entry_new()) != NULL);
/* Set pathname to non-convertible wide value. */
archive_entry_copy_pathname_w(entry, badname);
archive_entry_set_filetype(entry, AE_IFREG);
assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
archive_entry_free(entry);
assert((entry = archive_entry_new()) != NULL);
archive_entry_copy_pathname_w(entry, L"abc");
/* Set gname to non-convertible wide value. */
archive_entry_copy_gname_w(entry, badname);
archive_entry_set_filetype(entry, AE_IFREG);
assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
archive_entry_free(entry);
assert((entry = archive_entry_new()) != NULL);
archive_entry_copy_pathname_w(entry, L"abc");
/* Set uname to non-convertible wide value. */
archive_entry_copy_uname_w(entry, badname);
archive_entry_set_filetype(entry, AE_IFREG);
assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
archive_entry_free(entry);
assert((entry = archive_entry_new()) != NULL);
archive_entry_copy_pathname_w(entry, L"abc");
/* Set hardlink to non-convertible wide value. */
archive_entry_copy_hardlink_w(entry, badname);
archive_entry_set_filetype(entry, AE_IFREG);
assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
archive_entry_free(entry);
assert((entry = archive_entry_new()) != NULL);
archive_entry_copy_pathname_w(entry, L"abc");
/* Set symlink to non-convertible wide value. */
archive_entry_copy_symlink_w(entry, badname);
archive_entry_set_filetype(entry, AE_IFLNK);
assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
archive_entry_free(entry);
assertEqualInt(0, archive_write_close(a));
assertEqualInt(0, archive_write_finish(a));
/*
* Now read the entries back.
*/
assert((a = archive_read_new()) != NULL);
assertEqualInt(0, archive_read_support_format_tar(a));
assertEqualInt(0, archive_read_open_memory(a, buff, used));
failure("A non-convertible pathname should cause a warning.");
assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
assertEqualWString(badname, archive_entry_pathname_w(entry));
failure("If native locale can't convert, we should get UTF-8 back.");
assertEqualString(badname_utf8, archive_entry_pathname(entry));
failure("A non-convertible gname should cause a warning.");
assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
assertEqualWString(badname, archive_entry_gname_w(entry));
failure("If native locale can't convert, we should get UTF-8 back.");
assertEqualString(badname_utf8, archive_entry_gname(entry));
failure("A non-convertible uname should cause a warning.");
assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
assertEqualWString(badname, archive_entry_uname_w(entry));
failure("If native locale can't convert, we should get UTF-8 back.");
assertEqualString(badname_utf8, archive_entry_uname(entry));
failure("A non-convertible hardlink should cause a warning.");
assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
assertEqualWString(badname, archive_entry_hardlink_w(entry));
failure("If native locale can't convert, we should get UTF-8 back.");
assertEqualString(badname_utf8, archive_entry_hardlink(entry));
failure("A non-convertible symlink should cause a warning.");
assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
assertEqualWString(badname, archive_entry_symlink_w(entry));
assertEqualWString(NULL, archive_entry_hardlink_w(entry));
failure("If native locale can't convert, we should get UTF-8 back.");
assertEqualString(badname_utf8, archive_entry_symlink(entry));
assertEqualInt(ARCHIVE_EOF, archive_read_next_header(a, &entry));
assertEqualInt(0, archive_read_close(a));
assertEqualInt(0, archive_read_finish(a));
}

View File

@ -0,0 +1,66 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* Tar entries with empty filenames are unusual, but shouldn't crash us.
*/
DEFINE_TEST(test_read_format_tar_empty_filename)
{
char name[] = "test_read_format_tar_empty_filename.tar";
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
extract_reference_file(name);
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));
/* Read first entry. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("", archive_entry_pathname(ae));
assertEqualInt(1208628157, archive_entry_mtime(ae));
assertEqualInt(1000, archive_entry_uid(ae));
assertEqualString("tim", archive_entry_uname(ae));
assertEqualInt(0, archive_entry_gid(ae));
assertEqualString("wheel", archive_entry_gname(ae));
assertEqualInt(040775, archive_entry_mode(ae));
/* Verify the end-of-archive. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
/* Verify that the format detection worked. */
assertEqualInt(archive_compression(a), ARCHIVE_COMPRESSION_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
assertEqualInt(ARCHIVE_OK, archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,38 @@
begin 644 test_compat_tar_1.tar
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M`````````````#`P,#<W-2``,#`Q-S4P(``P,#`P,#`@`#`P,#`P,#`P,#`P
M(#$Q,#`R-#,Q-C<U(#`Q,3`P,0`@-0``````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````````````````````````!U<W1A<@`P,'1I;0``
M````````````````````````````````````=VAE96P`````````````````
M```````````````````P,#`P,#`@`#`P,#`P,"``````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
&````````
`
end

View File

@ -40,19 +40,22 @@ test_filename(const char *prefix, int dlen, int flen)
struct archive_entry *ae;
struct archive *a;
size_t used;
size_t prefix_length = 0;
unsigned i = 0;
char *p;
int i;
p = filename;
if (prefix) {
strcpy(filename, prefix);
i = prefix_length = strlen(prefix);
p += strlen(p);
}
for (; i < prefix_length + dlen; i++)
filename[i] = 'a';
filename[i++] = '/';
for (; i < prefix_length + dlen + flen + 1; i++)
filename[i] = 'b';
filename[i++] = '\0';
if (dlen > 0) {
for (i = 0; i < dlen; i++)
*p++ = 'a';
*p++ = '/';
}
for (i = 0; i < flen; i++)
*p++ = 'b';
*p = '\0';
strcpy(dirname, filename);
@ -160,15 +163,22 @@ DEFINE_TEST(test_tar_filenames)
int dlen, flen;
/* Repeat the following for a variety of dir/file lengths. */
for (dlen = 40; dlen < 60; dlen++) {
for (flen = 40; flen < 60; flen++) {
for (dlen = 45; dlen < 55; dlen++) {
for (flen = 45; flen < 55; flen++) {
test_filename(NULL, dlen, flen);
test_filename("/", dlen, flen);
}
}
for (dlen = 0; dlen < 140; dlen += 10) {
for (flen = 98; flen < 102; flen++) {
test_filename(NULL, dlen, flen);
test_filename("/", dlen, flen);
}
}
for (dlen = 140; dlen < 160; dlen++) {
for (flen = 90; flen < 110; flen++) {
for (flen = 95; flen < 105; flen++) {
test_filename(NULL, dlen, flen);
test_filename("/", dlen, flen);
}

View File

@ -242,6 +242,11 @@ DEFINE_TEST(test_tar_large)
archive_entry_copy_pathname(ae, namebuff);
archive_entry_set_mode(ae, S_IFREG | 0755);
filesize = tests[i];
if (filesize < 0) {
skipping("32-bit off_t doesn't permit testing of very large files.");
return;
}
archive_entry_set_size(ae, filesize);
assertA(0 == archive_write_header(a, ae));

View File

@ -0,0 +1,183 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* Exercise various lengths of filenames in ustar archives.
*/
static void
test_filename(const char *prefix, int dlen, int flen)
{
char buff[8192];
char filename[400];
char dirname[400];
struct archive_entry *ae;
struct archive *a;
size_t used;
int separator = 0;
int i = 0;
if (prefix != NULL) {
strcpy(filename, prefix);
i = strlen(prefix);
}
if (dlen > 0) {
for (; i < dlen; i++)
filename[i] = 'a';
filename[i++] = '/';
separator = 1;
}
for (; i < dlen + flen + separator; i++)
filename[i] = 'b';
filename[i++] = '\0';
strcpy(dirname, filename);
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_set_compression_none(a));
assertA(0 == archive_write_set_bytes_per_block(a,0));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/*
* Write a file to it.
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, filename);
archive_entry_set_mode(ae, S_IFREG | 0755);
failure("dlen=%d, flen=%d", dlen, flen);
if (flen > 100) {
assertEqualIntA(a, ARCHIVE_WARN, archive_write_header(a, ae));
} else {
assertEqualIntA(a, 0, archive_write_header(a, ae));
}
archive_entry_free(ae);
/*
* Write a dir to it (without trailing '/').
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, dirname);
archive_entry_set_mode(ae, S_IFDIR | 0755);
failure("dlen=%d, flen=%d", dlen, flen);
if (flen >= 100) {
assertEqualIntA(a, ARCHIVE_WARN, archive_write_header(a, ae));
} else {
assertEqualIntA(a, 0, archive_write_header(a, ae));
}
archive_entry_free(ae);
/* Tar adds a '/' to directory names. */
strcat(dirname, "/");
/*
* Write a dir to it (with trailing '/').
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, dirname);
archive_entry_set_mode(ae, S_IFDIR | 0755);
failure("dlen=%d, flen=%d", dlen, flen);
if (flen >= 100) {
assertEqualIntA(a, ARCHIVE_WARN, archive_write_header(a, ae));
} else {
assertEqualIntA(a, 0, archive_write_header(a, ae));
}
archive_entry_free(ae);
/* Close out the archive. */
assertA(0 == archive_write_close(a));
assertA(0 == archive_write_finish(a));
/*
* Now, read the data back.
*/
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, used));
if (flen <= 100) {
/* Read the file and check the filename. */
assertA(0 == archive_read_next_header(a, &ae));
failure("dlen=%d, flen=%d", dlen, flen);
assertEqualString(filename, archive_entry_pathname(ae));
assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
}
/*
* Read the two dirs and check the names.
*
* Both dirs should read back with the same name, since
* tar should add a trailing '/' to any dir that doesn't
* already have one.
*/
if (flen <= 99) {
assertA(0 == archive_read_next_header(a, &ae));
assert((S_IFDIR | 0755) == archive_entry_mode(ae));
failure("dlen=%d, flen=%d", dlen, flen);
assertEqualString(dirname, archive_entry_pathname(ae));
}
if (flen <= 99) {
assertA(0 == archive_read_next_header(a, &ae));
assert((S_IFDIR | 0755) == archive_entry_mode(ae));
assertEqualString(dirname, archive_entry_pathname(ae));
}
/* Verify the end of the archive. */
failure("This fails if entries were written that should not have been written. dlen=%d, flen=%d", dlen, flen);
assertEqualInt(1, archive_read_next_header(a, &ae));
assert(0 == archive_read_close(a));
assert(0 == archive_read_finish(a));
}
DEFINE_TEST(test_ustar_filenames)
{
int dlen, flen;
/* Try a bunch of different file/dir lengths that add up
* to just a little less or a little more than 100 bytes.
* This exercises the code that splits paths between ustar
* filename and prefix fields.
*/
for (dlen = 5; dlen < 70; dlen += 5) {
for (flen = 100 - dlen - 5; flen < 100 - dlen + 5; flen++) {
test_filename(NULL, dlen, flen);
test_filename("/", dlen, flen);
}
}
/* Probe the 100-char limit for paths with no '/'. */
for (flen = 90; flen < 110; flen++) {
test_filename(NULL, 0, flen);
test_filename("/", dlen, flen);
}
/* XXXX TODO Probe the 100-char limit with a dir prefix. */
/* XXXX TODO Probe the 255-char total limit. */
}

View File

@ -30,7 +30,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_write_format_ar.c,v 1.6 2008/03
char buff[4096];
char buff2[64];
static unsigned char strtab[] = "abcdefghijklmn.o/\nggghhhjjjrrrttt.o/\niiijjjdddsssppp.o/\n";
static char strtab[] = "abcdefghijklmn.o/\nggghhhjjjrrrttt.o/\niiijjjdddsssppp.o/\n";
DEFINE_TEST(test_write_format_ar)
{

View File

@ -0,0 +1,342 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static int
is_null(const char *p, size_t l)
{
while (l > 0) {
if (*p != '\0')
return (0);
--l;
++p;
}
return (1);
}
/* Verify the contents, then erase them to NUL bytes. */
/* Tar requires all "unused" bytes be set to NUL; this allows us
* to easily verify that by invoking is_null() over the entire header
* after verifying each field. */
#define myAssertEqualMem(a,b,s) assertEqualMem(a, b, s); memset(a, 0, s)
/*
* Detailed verification that 'ustar' archives are written with
* the correct format.
*/
DEFINE_TEST(test_write_format_tar_ustar)
{
struct archive *a;
struct archive_entry *entry;
char *buff, *e;
size_t buffsize = 100000;
size_t used;
int i;
char f99[100];
char f100[101];
char f256[257];
for (i = 0; i < 99; ++i)
f99[i] = 'a' + i % 26;
f99[99] = '\0';
for (i = 0; i < 100; ++i)
f100[i] = 'A' + i % 26;
f100[100] = '\0';
for (i = 0; i < 256; ++i)
f256[i] = 'A' + i % 26;
f256[155] = '/';
f256[256] = '\0';
buff = malloc(buffsize);
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, 0, archive_write_set_format_ustar(a));
assertEqualIntA(a, 0, archive_write_set_compression_none(a));
assertEqualIntA(a, 0, archive_write_open_memory(a, buff, buffsize, &used));
/*
* Add various files to it.
* TODO: Extend this to cover more filetypes.
*/
/* "file" with 10 bytes of content */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_mtime(entry, 1, 10);
archive_entry_set_pathname(entry, "file");
archive_entry_set_mode(entry, S_IFREG | 0664);
archive_entry_set_size(entry, 10);
archive_entry_set_uid(entry, 80);
archive_entry_set_gid(entry, 90);
archive_entry_set_dev(entry, 12);
archive_entry_set_ino(entry, 89);
archive_entry_set_nlink(entry, 2);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
assertEqualIntA(a, 10, archive_write_data(a, "1234567890", 10));
/* Hardlink to "file" with 10 bytes of content */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_mtime(entry, 1, 10);
archive_entry_set_pathname(entry, "linkfile");
archive_entry_set_mode(entry, S_IFREG | 0664);
/* TODO: Put this back and fix the bug. */
/* archive_entry_set_size(entry, 10); */
archive_entry_set_uid(entry, 80);
archive_entry_set_gid(entry, 90);
archive_entry_set_dev(entry, 12);
archive_entry_set_ino(entry, 89);
archive_entry_set_nlink(entry, 2);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
/* Write of data to dir should fail == zero bytes get written. */
assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10));
/* "dir" */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_mtime(entry, 2, 20);
archive_entry_set_pathname(entry, "dir");
archive_entry_set_mode(entry, S_IFDIR | 0775);
archive_entry_set_size(entry, 10);
archive_entry_set_nlink(entry, 2);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
/* Write of data to dir should fail == zero bytes get written. */
assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10));
/* "symlink" pointing to "file" */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_mtime(entry, 3, 30);
archive_entry_set_pathname(entry, "symlink");
archive_entry_set_mode(entry, S_IFLNK | 0664);
archive_entry_set_symlink(entry,"file");
archive_entry_set_size(entry, 0);
archive_entry_set_uid(entry, 88);
archive_entry_set_gid(entry, 98);
archive_entry_set_dev(entry, 12);
archive_entry_set_ino(entry, 90);
archive_entry_set_nlink(entry, 1);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
/* Write of data to symlink should fail == zero bytes get written. */
assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10));
/* file with 99-char filename. */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_mtime(entry, 1, 10);
archive_entry_set_pathname(entry, f99);
archive_entry_set_mode(entry, S_IFREG | 0664);
archive_entry_set_size(entry, 0);
archive_entry_set_uid(entry, 82);
archive_entry_set_gid(entry, 93);
archive_entry_set_dev(entry, 102);
archive_entry_set_ino(entry, 7);
archive_entry_set_nlink(entry, 1);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
/* file with 100-char filename. */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_mtime(entry, 1, 10);
archive_entry_set_pathname(entry, f100);
archive_entry_set_mode(entry, S_IFREG | 0664);
archive_entry_set_size(entry, 0);
archive_entry_set_uid(entry, 82);
archive_entry_set_gid(entry, 93);
archive_entry_set_dev(entry, 102);
archive_entry_set_ino(entry, 7);
archive_entry_set_nlink(entry, 1);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
/* file with 256-char filename. */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_mtime(entry, 1, 10);
archive_entry_set_pathname(entry, f256);
archive_entry_set_mode(entry, S_IFREG | 0664);
archive_entry_set_size(entry, 0);
archive_entry_set_uid(entry, 82);
archive_entry_set_gid(entry, 93);
archive_entry_set_dev(entry, 102);
archive_entry_set_ino(entry, 7);
archive_entry_set_nlink(entry, 1);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
assert(0 == archive_write_finish(a));
/*
* Verify the archive format.
*/
e = buff;
/* "file" */
myAssertEqualMem(e + 0, "file", 5); /* Filename */
myAssertEqualMem(e + 100, "000664 ", 8); /* mode */
myAssertEqualMem(e + 108, "000120 ", 8); /* uid */
myAssertEqualMem(e + 116, "000132 ", 8); /* gid */
myAssertEqualMem(e + 124, "00000000012 ", 12); /* size */
myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */
myAssertEqualMem(e + 148, "010034\0 ", 8); /* checksum */
myAssertEqualMem(e + 156, "0", 1); /* linkflag */
myAssertEqualMem(e + 157, "", 1); /* linkname */
myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */
myAssertEqualMem(e + 265, "", 1); /* uname */
myAssertEqualMem(e + 297, "", 1); /* gname */
myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */
myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */
myAssertEqualMem(e + 345, "", 1); /* prefix */
assert(is_null(e + 0, 512));
myAssertEqualMem(e + 512, "1234567890", 10);
assert(is_null(e + 512, 512));
e += 1024;
/* hardlink to "file" */
myAssertEqualMem(e + 0, "linkfile", 9); /* Filename */
myAssertEqualMem(e + 100, "000664 ", 8); /* mode */
myAssertEqualMem(e + 108, "000120 ", 8); /* uid */
myAssertEqualMem(e + 116, "000132 ", 8); /* gid */
myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */
myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */
myAssertEqualMem(e + 148, "010707\0 ", 8); /* checksum */
myAssertEqualMem(e + 156, "0", 1); /* linkflag */
myAssertEqualMem(e + 157, "", 1); /* linkname */
myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */
myAssertEqualMem(e + 265, "", 1); /* uname */
myAssertEqualMem(e + 297, "", 1); /* gname */
myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */
myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */
myAssertEqualMem(e + 345, "", 1); /* prefix */
assert(is_null(e + 0, 512));
e += 512;
/* "dir" */
myAssertEqualMem(e + 0, "dir/", 4); /* Filename */
myAssertEqualMem(e + 100, "000775 ", 8); /* mode */
myAssertEqualMem(e + 108, "000000 ", 8); /* uid */
myAssertEqualMem(e + 116, "000000 ", 8); /* gid */
myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */
myAssertEqualMem(e + 136, "00000000002 ", 12); /* mtime */
myAssertEqualMem(e + 148, "007747\0 ", 8); /* checksum */
myAssertEqualMem(e + 156, "5", 1); /* typeflag */
myAssertEqualMem(e + 157, "", 1); /* linkname */
myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */
myAssertEqualMem(e + 265, "", 1); /* uname */
myAssertEqualMem(e + 297, "", 1); /* gname */
myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */
myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */
myAssertEqualMem(e + 345, "", 1); /* prefix */
assert(is_null(e + 0, 512));
e += 512;
/* "symlink" pointing to "file" */
myAssertEqualMem(e + 0, "symlink", 8); /* Filename */
myAssertEqualMem(e + 100, "000664 ", 8); /* mode */
myAssertEqualMem(e + 108, "000130 ", 8); /* uid */
myAssertEqualMem(e + 116, "000142 ", 8); /* gid */
myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */
myAssertEqualMem(e + 136, "00000000003 ", 12); /* mtime */
myAssertEqualMem(e + 148, "011446\0 ", 8); /* checksum */
myAssertEqualMem(e + 156, "2", 1); /* linkflag */
myAssertEqualMem(e + 157, "file", 5); /* linkname */
myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */
myAssertEqualMem(e + 265, "", 1); /* uname */
myAssertEqualMem(e + 297, "", 1); /* gname */
myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */
myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */
myAssertEqualMem(e + 345, "", 1); /* prefix */
assert(is_null(e + 0, 512));
e += 512;
/* File with 99-char filename */
myAssertEqualMem(e + 0, f99, 100); /* Filename */
myAssertEqualMem(e + 100, "000664 ", 8); /* mode */
myAssertEqualMem(e + 108, "000122 ", 8); /* uid */
myAssertEqualMem(e + 116, "000135 ", 8); /* gid */
myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */
myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */
myAssertEqualMem(e + 148, "034242\0 ", 8); /* checksum */
myAssertEqualMem(e + 156, "0", 1); /* linkflag */
myAssertEqualMem(e + 157, "", 1); /* linkname */
myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */
myAssertEqualMem(e + 265, "", 1); /* uname */
myAssertEqualMem(e + 297, "", 1); /* gname */
myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */
myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */
myAssertEqualMem(e + 345, "", 1); /* prefix */
assert(is_null(e + 0, 512));
e += 512;
/* File with 100-char filename */
myAssertEqualMem(e + 0, f100, 100); /* Filename */
myAssertEqualMem(e + 100, "000664 ", 8); /* mode */
myAssertEqualMem(e + 108, "000122 ", 8); /* uid */
myAssertEqualMem(e + 116, "000135 ", 8); /* gid */
myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */
myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */
myAssertEqualMem(e + 148, "026230\0 ", 8); /* checksum */
myAssertEqualMem(e + 156, "0", 1); /* linkflag */
myAssertEqualMem(e + 157, "", 1); /* linkname */
myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */
myAssertEqualMem(e + 265, "", 1); /* uname */
myAssertEqualMem(e + 297, "", 1); /* gname */
myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */
myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */
myAssertEqualMem(e + 345, "", 1); /* prefix */
assert(is_null(e + 0, 512));
e += 512;
/* File with 256-char filename */
myAssertEqualMem(e + 0, f256 + 156, 100); /* Filename */
myAssertEqualMem(e + 100, "000664 ", 8); /* mode */
myAssertEqualMem(e + 108, "000122 ", 8); /* uid */
myAssertEqualMem(e + 116, "000135 ", 8); /* gid */
myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */
myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */
myAssertEqualMem(e + 148, "055570\0 ", 8); /* checksum */
myAssertEqualMem(e + 156, "0", 1); /* linkflag */
myAssertEqualMem(e + 157, "", 1); /* linkname */
myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */
myAssertEqualMem(e + 265, "", 1); /* uname */
myAssertEqualMem(e + 297, "", 1); /* gname */
myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */
myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */
myAssertEqualMem(e + 345, f256, 155); /* prefix */
assert(is_null(e + 0, 512));
e += 512;
/* TODO: Verify other types of entries. */
/* Last entry is end-of-archive marker. */
assert(is_null(e, 1024));
e += 1024;
assertEqualInt(used, e - buff);
free(buff);
}

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.40 2008/03/15 03:25:26 kientzle Exp $
.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.41 2008/05/02 05:40:05 kientzle Exp $
.\"
.Dd April 13, 2004
.Dt BSDTAR 1
@ -159,7 +159,7 @@ specified pattern.
Note that exclusions take precedence over patterns or filenames
specified on the command line.
.It Fl -format Ar format ( Fl W Cm format Ns = Ns Ar format )
(c mode only)
(c, r, u mode only)
Use the specified format for the created archive.
Supported formats include
.Dq cpio ,
@ -170,6 +170,8 @@ and
Other formats may also be supported; see
.Xr libarchive-formats 5
for more information about currently-supported formats.
In r and u modes, when extending an existing archive, the format specified
here must be compatible with the format of the existing archive on disk.
.It Fl f Ar file
Read the archive from or write the archive to the specified file.
The filename can be
@ -272,6 +274,10 @@ This is often used to read filenames output by the
.Fl print0
option to
.Xr find 1 .
.It Fl -numeric-owner
(x mode only)
Ignore symbolic user and group names when restoring archives to disk,
only numeric uid and gid values will be obeyed.
.It Fl O
(x, t modes only)
In extract (-x) mode, files will be written to standard out rather than
@ -279,7 +285,7 @@ being extracted to disk.
In list (-t) mode, the file listing will be written to stderr rather than
the usual stdout.
.It Fl o
(x mode only)
(x mode)
Use the user and group of the user running the program rather
than those specified in the archive.
Note that this has no significance unless
@ -288,6 +294,10 @@ is specified, and the program is being run by the root user.
In this case, the file modes and flags from
the archive will be restored, but ACLs or owner information in
the archive will be discarded.
.Pp
(c, r, u mode)
A synonym for
.Fl -format Ar ustar
.It Fl -one-file-system ( Fl W Cm one-file-system )
(c, r, and u modes)
Do not cross mount points.

View File

@ -24,7 +24,7 @@
*/
#include "bsdtar_platform.h"
__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.86 2008/03/15 05:08:21 kientzle Exp $");
__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.88 2008/05/02 05:40:05 kientzle Exp $");
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
@ -150,6 +150,7 @@ enum {
OPTION_NO_SAME_OWNER,
OPTION_NO_SAME_PERMISSIONS,
OPTION_NULL,
OPTION_NUMERIC_OWNER,
OPTION_ONE_FILE_SYSTEM,
OPTION_POSIX,
OPTION_STRIP_COMPONENTS,
@ -205,6 +206,7 @@ static const struct option tar_longopts[] = {
{ "no-same-owner", no_argument, NULL, OPTION_NO_SAME_OWNER },
{ "no-same-permissions",no_argument, NULL, OPTION_NO_SAME_PERMISSIONS },
{ "null", no_argument, NULL, OPTION_NULL },
{ "numeric-owner", no_argument, NULL, OPTION_NUMERIC_OWNER },
{ "one-file-system", no_argument, NULL, OPTION_ONE_FILE_SYSTEM },
{ "posix", no_argument, NULL, OPTION_POSIX },
{ "preserve-permissions", no_argument, NULL, 'p' },
@ -455,6 +457,9 @@ main(int argc, char **argv)
case OPTION_NULL: /* GNU tar */
bsdtar->option_null++;
break;
case OPTION_NUMERIC_OWNER: /* GNU tar */
bsdtar->option_numeric_owner++;
break;
case 'O': /* GNU tar */
bsdtar->option_stdout = 1;
break;
@ -638,7 +643,7 @@ main(int argc, char **argv)
only_mode(bsdtar, buff, "cxt");
}
if (bsdtar->create_format != NULL)
only_mode(bsdtar, "--format", "c");
only_mode(bsdtar, "--format", "cru");
if (bsdtar->symlink_mode != '\0') {
strcpy(buff, "-?");
buff[1] = bsdtar->symlink_mode;
@ -788,7 +793,7 @@ version(void)
printf("bsdtar %s - %s\n",
BSDTAR_VERSION_STRING,
archive_version());
exit(1);
exit(0);
}
static const char *long_help_msg =

View File

@ -65,6 +65,7 @@ struct bsdtar {
char option_no_owner; /* -o */
char option_no_subdirs; /* -n */
char option_null; /* --null */
char option_numeric_owner; /* --numeric-owner */
char option_stdout; /* -O */
char option_totals; /* --totals */
char option_unlink_first; /* -U */

View File

@ -24,7 +24,7 @@
*/
#include "bsdtar_platform.h"
__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.11 2007/03/11 10:36:42 kientzle Exp $");
__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.12 2008/03/18 06:18:49 kientzle Exp $");
#ifdef HAVE_ERRNO_H
#include <errno.h>
@ -157,7 +157,7 @@ excluded(struct bsdtar *bsdtar, const char *pathname)
*/
if (match->matches == 0) {
match->matches++;
matching->inclusions_unmatched_count++;
matching->inclusions_unmatched_count--;
return (0);
}
/*

View File

@ -150,6 +150,11 @@ read_archive(struct bsdtar *bsdtar, char mode)
if (r == ARCHIVE_FATAL)
break;
if (bsdtar->option_numeric_owner) {
archive_entry_set_uname(entry, NULL);
archive_entry_set_gname(entry, NULL);
}
/*
* Exclude entries that are too old.
*/

View File

@ -39,7 +39,7 @@
*
* The next few lines are the only differences.
*/
#define PROGRAM "bsdtar" /* Name of program we're testing. */
#define PROGRAM "bsdtar" /* Name of program being tested. */
#define ENVBASE "BSDTAR" /* Prefix for environment variables. */
#undef EXTRA_DUMP /* How to dump extra data */
/* How to generate extra version info. */
@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$");
* test functions.
*/
#undef DEFINE_TEST
#define DEFINE_TEST(name) void name(void);
#define DEFINE_TEST(name) void name(void);
#include "list.h"
/* Interix doesn't define these in a standard header. */
@ -64,10 +64,14 @@ extern char *optarg;
extern int optind;
#endif
/* Default is to crash and try to force a core dump on failure. */
static int dump_on_failure = 1;
/* Enable core dump on failure. */
static int dump_on_failure = 0;
/* Default is to remove temp dirs for successful tests. */
static int keep_temp_files = 0;
/* Default is to print some basic information about each test. */
static int quiet_flag = 0;
/* Default is to summarize repeated failures. */
static int verbose = 0;
/* Cumulative count of component failures. */
static int failures = 0;
/* Cumulative count of skipped component tests. */
@ -243,7 +247,7 @@ test_assert(const char *file, int line, int value, const char *condition, void *
return (value);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (value);
fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
fprintf(stderr, " Condition: %s\n", condition);
@ -262,7 +266,7 @@ test_assert_equal_int(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n",
file, line);
@ -272,6 +276,30 @@ test_assert_equal_int(const char *file, int line,
return (0);
}
static void strdump(const char *p)
{
if (p == NULL) {
fprintf(stderr, "(null)");
return;
}
fprintf(stderr, "\"");
while (*p != '\0') {
unsigned int c = 0xff & *p++;
switch (c) {
case '\a': fprintf(stderr, "\a"); break;
case '\b': fprintf(stderr, "\b"); break;
case '\n': fprintf(stderr, "\n"); break;
case '\r': fprintf(stderr, "\r"); break;
default:
if (c >= 32 && c < 127)
fprintf(stderr, "%c", c);
else
fprintf(stderr, "\\x%02X", c);
}
}
fprintf(stderr, "\"");
}
/* assertEqualString() displays the values of the two strings. */
int
test_assert_equal_string(const char *file, int line,
@ -290,16 +318,41 @@ test_assert_equal_string(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
file, line);
fprintf(stderr, " %s = \"%s\"\n", e1, v1);
fprintf(stderr, " %s = \"%s\"\n", e2, v2);
fprintf(stderr, " %s = ", e1);
strdump(v1);
fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : strlen(v1));
fprintf(stderr, " %s = ", e2);
strdump(v2);
fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : strlen(v2));
report_failure(extra);
return (0);
}
static void wcsdump(const wchar_t *w)
{
if (w == NULL) {
fprintf(stderr, "(null)");
return;
}
fprintf(stderr, "\"");
while (*w != L'\0') {
unsigned int c = *w++;
if (c >= 32 && c < 127)
fprintf(stderr, "%c", c);
else if (c < 256)
fprintf(stderr, "\\x%02X", c);
else if (c < 0x10000)
fprintf(stderr, "\\u%04X", c);
else
fprintf(stderr, "\\U%08X", c);
}
fprintf(stderr, "\"");
}
/* assertEqualWString() displays the values of the two strings. */
int
test_assert_equal_wstring(const char *file, int line,
@ -308,17 +361,31 @@ test_assert_equal_wstring(const char *file, int line,
void *extra)
{
++assertions;
if (wcscmp(v1, v2) == 0) {
if (v1 == NULL) {
if (v2 == NULL) {
msg[0] = '\0';
return (1);
}
} else if (v2 == NULL) {
if (v1 == NULL) {
msg[0] = '\0';
return (1);
}
} else if (wcscmp(v1, v2) == 0) {
msg[0] = '\0';
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n",
file, line);
fwprintf(stderr, L" %s = \"%ls\"\n", e1, v1);
fwprintf(stderr, L" %s = \"%ls\"\n", e2, v2);
fprintf(stderr, " %s = ", e1);
wcsdump(v1);
fprintf(stderr, "\n");
fprintf(stderr, " %s = ", e2);
wcsdump(v2);
fprintf(stderr, "\n");
report_failure(extra);
return (0);
}
@ -379,7 +446,7 @@ test_assert_equal_mem(const char *file, int line,
return (1);
}
failures ++;
if (previous_failures(file, line))
if (!verbose && previous_failures(file, line))
return (0);
fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n",
file, line);
@ -411,12 +478,13 @@ test_assert_empty_file(const char *f1fmt, ...)
if (stat(f1, &st) != 0) {
fprintf(stderr, "%s:%d: Could not stat: %s\n", test_filename, test_line, f1);
report_failure(NULL);
return (0);
}
if (st.st_size == 0)
return (1);
failures ++;
if (previous_failures(test_filename, test_line))
if (!verbose && previous_failures(test_filename, test_line))
return (0);
fprintf(stderr, "%s:%d: File not empty: %s\n", test_filename, test_line, f1);
@ -463,7 +531,7 @@ test_assert_equal_file(const char *f1, const char *f2pattern, ...)
break;
}
failures ++;
if (previous_failures(test_filename, test_line))
if (!verbose && previous_failures(test_filename, test_line))
return (0);
fprintf(stderr, "%s:%d: Files are not identical\n",
test_filename, test_line);
@ -473,6 +541,48 @@ test_assert_equal_file(const char *f1, const char *f2pattern, ...)
return (0);
}
int
test_assert_file_exists(const char *fpattern, ...)
{
char f[1024];
va_list ap;
va_start(ap, fpattern);
vsprintf(f, fpattern, ap);
va_end(ap);
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);
}
return (0);
}
int
test_assert_file_not_exists(const char *fpattern, ...)
{
char f[1024];
va_list ap;
va_start(ap, fpattern);
vsprintf(f, fpattern, ap);
va_end(ap);
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);
}
return (0);
}
/* assertFileContents() asserts the contents of a file. */
int
test_assert_file_contents(const void *buff, int s, const char *fpattern, ...)
@ -587,7 +697,7 @@ slurpfile(size_t * sizep, const char *fmt, ...)
* We reuse it here to define a list of all tests (functions and names).
*/
#undef DEFINE_TEST
#define DEFINE_TEST(n) { n, #n },
#define DEFINE_TEST(n) { n, #n },
struct { void (*func)(void); const char *name; } tests[] = {
#include "list.h"
};
@ -634,6 +744,12 @@ static int test_run(int i, const char *tmpdir)
(*tests[i].func)();
/* Summarize the results of this test. */
summarize();
/* If there were no failures, we can remove the work dir. */
if (failures == failures_before) {
if (!keep_temp_files && chdir(tmpdir) == 0) {
systemf("rm -rf %s", tests[i].name);
}
}
/* Return appropriate status. */
return (failures == failures_before ? 0 : 1);
}
@ -647,8 +763,9 @@ static void usage(const char *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(" -k Keep running after failures.\n");
printf(" Default: Core dump after any failure.\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");
@ -656,13 +773,14 @@ static void usage(const char *program)
printf(" -q Quiet.\n");
printf(" -r <dir> Path to dir containing reference files.\n");
printf(" Default: Current directory.\n");
printf(" -v Verbose.\n");
printf("Available tests:\n");
for (i = 0; i < limit; i++)
printf(" %d: %s\n", i, tests[i].name);
exit(1);
}
#define uudecode(c) (((c) - 0x20) & 0x3f)
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
void
extract_reference_file(const char *name)
@ -695,23 +813,23 @@ extract_reference_file(const char *name)
if (memcmp(buff, "end", 3) == 0)
break;
bytes = uudecode(*p++);
bytes = UUDECODE(*p++);
while (bytes > 0) {
int n = 0;
/* Write out 1-3 bytes from that. */
if (bytes > 0) {
n = uudecode(*p++) << 18;
n |= uudecode(*p++) << 12;
n = UUDECODE(*p++) << 18;
n |= UUDECODE(*p++) << 12;
fputc(n >> 16, out);
--bytes;
}
if (bytes > 0) {
n |= uudecode(*p++) << 6;
n |= UUDECODE(*p++) << 6;
fputc((n >> 8) & 0xFF, out);
--bytes;
}
if (bytes > 0) {
n |= uudecode(*p++);
n |= UUDECODE(*p++);
fputc(n & 0xFF, out);
--bytes;
}
@ -748,9 +866,9 @@ int main(int argc, char **argv)
testprog = getenv(ENVBASE);
#endif
/* Allow -k to be controlled through the environment. */
if (getenv(ENVBASE "_KEEP_GOING") != NULL)
dump_on_failure = 0;
/* Allow -d to be controlled through the environment. */
if (getenv(ENVBASE "_DEBUG") != NULL)
dump_on_failure = 1;
/* Get the directory holding test files from environment. */
refdir = getenv(ENVBASE "_TEST_FILES");
@ -758,10 +876,13 @@ int main(int argc, char **argv)
/*
* Parse options.
*/
while ((opt = getopt(argc, argv, "kp:qr:")) != -1) {
while ((opt = getopt(argc, argv, "dkp:qr:v")) != -1) {
switch (opt) {
case 'd':
dump_on_failure = 1;
break;
case 'k':
dump_on_failure = 0;
keep_temp_files = 1;
break;
case 'p':
#ifdef PROGRAM
@ -776,6 +897,9 @@ int main(int argc, char **argv)
case 'r':
refdir = optarg;
break;
case 'v':
verbose = 1;
break;
case '?':
default:
usage(progname);
@ -824,6 +948,7 @@ int main(int argc, char **argv)
--p;
*p = '\0';
}
systemf("rm %s/refdir", tmpdir);
}
/*
@ -879,5 +1004,9 @@ int main(int argc, char **argv)
free(refdir_alloc);
/* If the final tmpdir is empty, we can remove it. */
/* This should be the usual case when all tests succeed. */
rmdir(tmpdir);
return (tests_failed);
}

View File

@ -102,6 +102,12 @@
/* Assert that a file is empty; supports printf-style arguments. */
#define assertEmptyFile \
test_setup(__FILE__, __LINE__);test_assert_empty_file
/* Assert that a file exists; supports printf-style arguments. */
#define assertFileExists \
test_setup(__FILE__, __LINE__);test_assert_file_exists
/* Assert that a file exists; supports printf-style arguments. */
#define assertFileNotExists \
test_setup(__FILE__, __LINE__);test_assert_file_not_exists
/*
* This would be simple with C99 variadic macros, but I don't want to
@ -124,6 +130,8 @@ 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_file_exists(const char *, ...);
int test_assert_file_not_exists(const char *, ...);
/* Like sprintf, then system() */
int systemf(const char * fmt, ...);
@ -141,4 +149,3 @@ void extract_reference_file(const char *);
/* Pathname of exe to be tested. */
char *testprog;

62
dist/libarchive/tar/test/test_0.c vendored Normal file
View File

@ -0,0 +1,62 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* This first test does basic sanity checks on the environment. For
* most of these, we just exit on failure.
*/
DEFINE_TEST(test_0)
{
struct stat st;
failure("File %s does not exist?!", testprog);
if (!assertEqualInt(0, stat(testprog, &st)))
exit(1);
failure("%s is not executable?!", testprog);
if (!assert((st.st_mode & 0111) != 0))
exit(1);
/*
* Try to succesfully run the program; this requires that
* we know some option that will succeed.
*/
if (0 == systemf("%s --version >/dev/null", testprog)) {
/* This worked. */
} else if (0 == systemf("%s -W version >/dev/null", testprog)) {
/* This worked. */
} else {
failure("Unable to successfully run any of the following:\n"
" * %s --version\n"
" * %s -W version\n",
testprog, testprog);
assert(0);
}
/* TODO: Ensure that our reference files are available. */
}

View File

@ -76,8 +76,8 @@ static void
verify_tree(int limit)
{
struct stat st, st2;
char buff[260];
char buff2[260];
char filename[260];
char contents[260];
int i, r;
int fd;
int len;
@ -88,23 +88,25 @@ verify_tree(int limit)
/* Generate the names we know should be there and verify them. */
for (i = 0; i < 200; i++) {
/* Verify a file named "f_abcdef..." */
buff[0] = 'f';
buff[1] = '_';
buff[i + 2] = 'a' + (i % 26);
buff[i + 3] = '\0';
if (limit != LIMIT_USTAR || strlen(buff) <= 100) {
fd = open(buff, O_RDONLY);
filename[0] = 'f';
filename[1] = '_';
filename[i + 2] = 'a' + (i % 26);
filename[i + 3] = '\0';
if (limit != LIMIT_USTAR || strlen(filename) <= 100) {
fd = open(filename, O_RDONLY);
failure("Couldn't open \"%s\": %s",
buff, strerror(errno));
assert(fd >= 0);
len = read(fd, buff2, i + 10);
close(fd);
assertEqualInt(len, i + 3);
/* Verify contents of 'buff2' */
buff2[len] = '\0';
assertEqualString(buff, buff2);
/* stat() file and get dev/ino for next check */
assertEqualInt(0, lstat(buff, &st));
filename, strerror(errno));
if (assert(fd >= 0)) {
len = read(fd, contents, i + 10);
close(fd);
assertEqualInt(len, i + 3);
/* Verify contents of 'contents' */
contents[len] = '\0';
failure("Each test file contains its own name");
assertEqualString(filename, contents);
/* stat() file and get dev/ino for next check */
assertEqualInt(0, lstat(filename, &st));
}
}
/*
@ -112,18 +114,18 @@ verify_tree(int limit)
* "original/" as part of the name, so the link
* names here can't exceed 91 chars.
*/
if (limit != LIMIT_USTAR || strlen(buff) <= 91) {
if (limit != LIMIT_USTAR || strlen(filename) <= 91) {
/* Verify hardlink "l_abcdef..." */
buff[0] = 'l';
assertEqualInt(0, (r = lstat(buff, &st2)));
filename[0] = 'l';
assertEqualInt(0, (r = lstat(filename, &st2)));
if (r == 0) {
assertEqualInt(st2.st_dev, st.st_dev);
assertEqualInt(st2.st_ino, st.st_ino);
}
/* Verify hardlink "m_abcdef..." */
buff[0] = 'm';
assertEqualInt(0, (r = lstat(buff, &st2)));
filename[0] = 'm';
assertEqualInt(0, (r = lstat(filename, &st2)));
if (r == 0) {
assertEqualInt(st2.st_dev, st.st_dev);
assertEqualInt(st2.st_ino, st.st_ino);
@ -135,26 +137,36 @@ verify_tree(int limit)
* so the limit here is 100 characters.
*/
/* Verify symlink "s_abcdef..." */
buff[0] = 's';
if (limit != LIMIT_USTAR || strlen(buff) <= 100) {
filename[0] = 's';
if (limit != LIMIT_USTAR || strlen(filename) <= 100) {
/* This is a symlink. */
assertEqualInt(0, lstat(buff, &st2));
assert(S_ISLNK(st2.st_mode));
/* This is a symlink to the file above. */
assertEqualInt(0, stat(buff, &st2));
assertEqualInt(st2.st_dev, st.st_dev);
assertEqualInt(st2.st_ino, st.st_ino);
failure("Couldn't stat %s (length %d)",
filename, strlen(filename));
if (assertEqualInt(0, lstat(filename, &st2))) {
assert(S_ISLNK(st2.st_mode));
/* This is a symlink to the file above. */
failure("Couldn't stat %s", filename);
if (assertEqualInt(0, stat(filename, &st2))) {
assertEqualInt(st2.st_dev, st.st_dev);
assertEqualInt(st2.st_ino, st.st_ino);
}
}
}
/* Verify dir "d_abcdef...". */
buff[0] = 'd';
if (limit != LIMIT_USTAR || strlen(buff) <= 100) {
filename[0] = 'd';
if (limit != LIMIT_USTAR || strlen(filename) < 100) {
/* This is a dir. */
assertEqualInt(0, lstat(buff, &st2));
assert(S_ISDIR(st2.st_mode));
/* TODO: opendir/readdir this directory and
* make sure it's empty.
*/
failure("Couldn't stat %s (length %d)",
filename, strlen(filename));
if (assertEqualInt(0, lstat(filename, &st2))) {
if (assert(S_ISDIR(st2.st_mode))) {
/* TODO: opendir/readdir this
* directory and make sure
* it's empty.
*/
}
}
}
}
@ -164,11 +176,20 @@ verify_tree(int limit)
p = de->d_name;
switch(p[0]) {
case 'l': case 'm':
if (limit == LIMIT_USTAR)
assert(strlen(p) <= 91);
case 'd': case 'f': case 's':
if (limit == LIMIT_USTAR)
assert(strlen(p) <= 100);
if (limit == LIMIT_USTAR) {
failure("strlen(p) = %d", strlen(p));
assert(strlen(p) < 92);
}
case 'd':
if (limit == LIMIT_USTAR) {
failure("strlen(p)=%d", strlen(p));
assert(strlen(p) < 100);
}
case 'f': case 's':
if (limit == LIMIT_USTAR) {
failure("strlen(p)=%d", strlen(p));
assert(strlen(p) < 101);
}
/* Our files have very particular filename patterns. */
assert(p[1] == '_' && p[2] == 'a');
assert(p[2] == 'a');
@ -239,7 +260,7 @@ copy_ustar(void)
*/
r = systemf("%s cf archive --format=ustar -C .. original >pack.out 2>pack.err",
testprog);
failure("Error invoking \"%s cf\"", testprog);
failure("Error invoking \"%s cf archive --format=ustar\"", testprog);
assertEqualInt(r, 0);
/* Verify that nothing went to stdout. */

View File

@ -37,6 +37,14 @@ DEFINE_TEST(test_version)
r = systemf("%s --version >version.stdout 2>version.stderr", testprog);
if (r != 0)
r = systemf("%s -W version >version.stdout 2>version.stderr",
testprog);
failure("Unable to run either %s --version or %s -W version",
testprog, testprog);
if (!assert(r == 0))
return;
/* --version should generate nothing to stdout. */
assertEmptyFile("version.stderr");
/* Verify format of version message. */

View File

@ -24,7 +24,7 @@
*/
#include "bsdtar_platform.h"
__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.65 2008/03/15 02:41:44 kientzle Exp $");
__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.66 2008/05/02 05:14:58 kientzle Exp $");
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@ -1534,7 +1534,7 @@ test_for_append(struct bsdtar *bsdtar)
{
struct stat s;
if (*bsdtar->argv == NULL)
if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL)
bsdtar_errc(bsdtar, 1, 0, "no files or directories specified");
if (bsdtar->filename == NULL)
bsdtar_errc(bsdtar, 1, 0, "Cannot append to stdout.");