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:
parent
cc7aa65fd4
commit
842030a811
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
DEFINE_TEST(test_0)
|
||||
DEFINE_TEST(test_basic)
|
||||
DEFINE_TEST(test_format_newc)
|
||||
DEFINE_TEST(test_gcpio_compat)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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(×, 0, sizeof(times));
|
||||
times.actime = 1;
|
||||
times.modtime = 3;
|
||||
assertEqualInt(0, utime(files[i].name, ×));
|
||||
|
||||
/* Record whatever atime the file ended up with. */
|
||||
/* If utime() is available, this should be 1, but there's
|
||||
* no harm in being careful. */
|
||||
assertEqualInt(0, stat(files[i].name, &st));
|
||||
files[i].atime_sec = st.st_atime;
|
||||
}
|
||||
|
||||
/* Wait until the atime on the last file is actually in the past. */
|
||||
/* If utime() is supported above, there's no sleep here which
|
||||
* makes the test faster. */
|
||||
while (files[numfiles - 1].atime_sec >= time(NULL))
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
DEFINE_TEST(test_option_a)
|
||||
{
|
||||
struct stat st;
|
||||
int r;
|
||||
int f;
|
||||
char buff[64];
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(".."));
|
||||
}
|
||||
|
|
|
@ -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(×, 0, sizeof(times));
|
||||
times.actime = 1;
|
||||
times.modtime = 3;
|
||||
assertEqualInt(0, utime("f", ×));
|
||||
|
||||
/* Copy the file to the "copy" dir. */
|
||||
r = systemf("echo f | %s -pd --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);
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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. */
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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. */
|
||||
}
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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.");
|
||||
|
|
Loading…
Reference in New Issue