Import libarchive-2.5.1b.
This commit is contained in:
parent
5548060f79
commit
65a789b8e7
33 changed files with 1515 additions and 610 deletions
|
@ -1,4 +1,6 @@
|
|||
|
||||
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
|
||||
|
|
38
archivers/libarchive/files/configure
vendored
38
archivers/libarchive/files/configure
vendored
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.61 for libarchive 2.5.0b.
|
||||
# Generated by GNU Autoconf 2.61 for libarchive 2.5.1b.
|
||||
#
|
||||
# Report bugs to <kientzle@freebsd.org>.
|
||||
#
|
||||
|
@ -728,8 +728,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
|||
# Identity of this package.
|
||||
PACKAGE_NAME='libarchive'
|
||||
PACKAGE_TARNAME='libarchive'
|
||||
PACKAGE_VERSION='2.5.0b'
|
||||
PACKAGE_STRING='libarchive 2.5.0b'
|
||||
PACKAGE_VERSION='2.5.1b'
|
||||
PACKAGE_STRING='libarchive 2.5.1b'
|
||||
PACKAGE_BUGREPORT='kientzle@freebsd.org'
|
||||
|
||||
ac_unique_file="libarchive"
|
||||
|
@ -1408,7 +1408,7 @@ if test "$ac_init_help" = "long"; then
|
|||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures libarchive 2.5.0b to adapt to many kinds of systems.
|
||||
\`configure' configures libarchive 2.5.1b to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
|
@ -1478,7 +1478,7 @@ fi
|
|||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of libarchive 2.5.0b:";;
|
||||
short | recursive ) echo "Configuration of libarchive 2.5.1b:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
|
@ -1596,7 +1596,7 @@ fi
|
|||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
libarchive configure 2.5.0b
|
||||
libarchive configure 2.5.1b
|
||||
generated by GNU Autoconf 2.61
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
|
@ -1610,7 +1610,7 @@ cat >config.log <<_ACEOF
|
|||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by libarchive $as_me 2.5.0b, which was
|
||||
It was created by libarchive $as_me 2.5.1b, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
|
@ -2304,7 +2304,7 @@ fi
|
|||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='libarchive'
|
||||
VERSION='2.5.0b'
|
||||
VERSION='2.5.1b'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
|
@ -2455,21 +2455,21 @@ am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
|
|||
# platforms. At least on FreeBSD, libtool uses an overly complex
|
||||
# convention that attempts to solve problems that most people just
|
||||
# don't have and which just causes confusion for most end users.
|
||||
ARCHIVE_MAJOR=$(( 2005000 / 1000000 ))
|
||||
ARCHIVE_MINOR=$(( (2005000 / 1000) % 1000 ))
|
||||
ARCHIVE_REVISION=$(( 2005000 % 1000 ))
|
||||
ARCHIVE_MAJOR=$(( 2005001 / 1000000 ))
|
||||
ARCHIVE_MINOR=$(( (2005001 / 1000) % 1000 ))
|
||||
ARCHIVE_REVISION=$(( 2005001 % 1000 ))
|
||||
ARCHIVE_LIBTOOL_MAJOR=`echo $((${ARCHIVE_MAJOR} + ${ARCHIVE_MINOR}))`
|
||||
ARCHIVE_LIBTOOL_VERSION=$ARCHIVE_LIBTOOL_MAJOR:$ARCHIVE_REVISION:$ARCHIVE_MINOR
|
||||
|
||||
# Stick the version numbers into config.h
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define LIBARCHIVE_VERSION_STRING "2.5.0b"
|
||||
#define LIBARCHIVE_VERSION_STRING "2.5.1b"
|
||||
_ACEOF
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define LIBARCHIVE_VERSION_NUMBER "2005000"
|
||||
#define LIBARCHIVE_VERSION_NUMBER "2005001"
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
@ -2479,7 +2479,7 @@ _ACEOF
|
|||
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define BSDTAR_VERSION_STRING "2.5.0b"
|
||||
#define BSDTAR_VERSION_STRING "2.5.1b"
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
@ -2487,9 +2487,9 @@ _ACEOF
|
|||
# below, but the shell variable names apparently cannot be the same as
|
||||
# the m4 macro names above. Why? Ask autoconf.
|
||||
BSDCPIO_VERSION_STRING=0.9.9a
|
||||
BSDTAR_VERSION_STRING=2.5.0b
|
||||
LIBARCHIVE_VERSION_STRING=2.5.0b
|
||||
LIBARCHIVE_VERSION_NUMBER=2005000
|
||||
BSDTAR_VERSION_STRING=2.5.1b
|
||||
LIBARCHIVE_VERSION_STRING=2.5.1b
|
||||
LIBARCHIVE_VERSION_NUMBER=2005001
|
||||
|
||||
# Substitute the above version numbers into the various files below.
|
||||
# Yes, I believe this is the fourth time we define what are essentially
|
||||
|
@ -27783,7 +27783,7 @@ exec 6>&1
|
|||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by libarchive $as_me 2.5.0b, which was
|
||||
This file was extended by libarchive $as_me 2.5.1b, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
|
@ -27836,7 +27836,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
|||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
libarchive config.status 2.5.0b
|
||||
libarchive config.status 2.5.1b
|
||||
configured by $0, generated by GNU Autoconf 2.61,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front.
|
|||
dnl In particular, this allows the version macro to be used in AC_INIT
|
||||
|
||||
dnl These first two version numbers are updated automatically on each release.
|
||||
m4_define([LIBARCHIVE_VERSION_S],[2.5.0b])
|
||||
m4_define([LIBARCHIVE_VERSION_N],[2005000])
|
||||
m4_define([LIBARCHIVE_VERSION_S],[2.5.1b])
|
||||
m4_define([LIBARCHIVE_VERSION_N],[2005001])
|
||||
|
||||
dnl bsdtar versioning tracks libarchive
|
||||
m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S())
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -478,7 +478,8 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
|
|||
static int
|
||||
entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
|
||||
{
|
||||
const char *destpath, *srcpath;
|
||||
const char *destpath;
|
||||
char *srcpath;
|
||||
int fd = -1;
|
||||
ssize_t bytes_read;
|
||||
size_t len;
|
||||
|
@ -488,7 +489,12 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
|
|||
/*
|
||||
* Generate a target path for this entry.
|
||||
*/
|
||||
destpath = srcpath = archive_entry_pathname(entry);
|
||||
p = archive_entry_pathname(entry);
|
||||
srcpath = malloc(strlen(p) + 1);
|
||||
if (srcpath == NULL)
|
||||
cpio_errc(1, ENOMEM, "Can't allocate path buffer");
|
||||
strcpy(srcpath, p);
|
||||
destpath = srcpath;
|
||||
if (cpio->destdir) {
|
||||
len = strlen(cpio->destdir) + strlen(srcpath) + 8;
|
||||
if (len >= cpio->pass_destpath_alloc) {
|
||||
|
@ -511,8 +517,10 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
|
|||
}
|
||||
if (cpio->option_rename)
|
||||
destpath = cpio_rename(destpath);
|
||||
if (destpath == NULL)
|
||||
if (destpath == NULL) {
|
||||
free(srcpath);
|
||||
return (0);
|
||||
}
|
||||
archive_entry_copy_pathname(entry, destpath);
|
||||
|
||||
/* Print out the destination name to the user. */
|
||||
|
@ -526,12 +534,12 @@ 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);
|
||||
free(srcpath);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -563,8 +571,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,
|
||||
|
@ -587,6 +594,7 @@ cleanup:
|
|||
fprintf(stderr,"\n");
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
free(srcpath);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
@ -272,6 +272,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,
|
||||
|
@ -294,12 +318,37 @@ test_assert_equal_string(const char *file, int 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, "\n");
|
||||
fprintf(stderr, " %s = ", e2);
|
||||
strdump(v2);
|
||||
fprintf(stderr, "\n");
|
||||
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,7 +357,17 @@ 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);
|
||||
}
|
||||
|
@ -317,8 +376,12 @@ test_assert_equal_wstring(const char *file, int 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);
|
||||
}
|
||||
|
@ -587,7 +650,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"
|
||||
};
|
||||
|
@ -662,7 +725,7 @@ static void usage(const char *program)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
#define uudecode(c) (((c) - 0x20) & 0x3f)
|
||||
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
|
||||
|
||||
void
|
||||
extract_reference_file(const char *name)
|
||||
|
@ -695,23 +758,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;
|
||||
}
|
||||
|
|
|
@ -54,28 +54,30 @@ DEFINE_TEST(test_option_L)
|
|||
|
||||
r = systemf("cat filelist | %s -pd -L --quiet 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);
|
||||
failure("Error invoking %s -o --quiet", 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);
|
||||
failure("Error invoking %s -oL --quiet", 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));
|
||||
|
|
|
@ -56,6 +56,8 @@ 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");
|
||||
|
@ -63,24 +65,46 @@ DEFINE_TEST(test_option_a)
|
|||
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);
|
||||
|
||||
/* 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);
|
||||
/* Sanity check; verify that atimes really do get modified. */
|
||||
f = open("f0", O_RDONLY);
|
||||
assertEqualInt(1, read(f,buff, 1));
|
||||
assertEqualInt(0, close(f));
|
||||
assertEqualInt(0, stat("f0", &st));
|
||||
if (st.st_atime == 1) {
|
||||
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.
|
||||
*/
|
||||
|
||||
/* 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);
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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");
|
||||
|
|
|
@ -137,7 +137,7 @@ Each of the two 16 bit values are stored in machine-native byte order.
|
|||
.TP
|
||||
\fInamesize\fP
|
||||
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.
|
||||
.TP
|
||||
\fIfilesize\fP
|
||||
The size of the file.
|
||||
|
@ -149,8 +149,8 @@ above for a description of the storage of four-byte integers.
|
|||
The pathname immediately follows the fixed header.
|
||||
If the
|
||||
\fBnamesize\fP
|
||||
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.
|
||||
Hardlinked files are not given special treatment;
|
||||
the full file contents are included with each copy of the
|
||||
|
@ -187,7 +187,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
|
||||
|
@ -220,7 +220,7 @@ The string
|
|||
\fIcheck\fP
|
||||
This field is always set to zero by writers and ignored by readers.
|
||||
See the next section for more details.
|
||||
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
|
||||
|
|
|
@ -193,7 +193,7 @@ field with several new type values:
|
|||
.TP
|
||||
``0''
|
||||
Regular file.
|
||||
NULL should be treated as a synonym, for compatibility purposes.
|
||||
NUL should be treated as a synonym, for compatibility purposes.
|
||||
.TP
|
||||
``1''
|
||||
Hard link.
|
||||
|
@ -238,7 +238,7 @@ by readers.
|
|||
\fImagic\fP
|
||||
Contains the magic value
|
||||
``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.
|
||||
.TP
|
||||
\fIversion\fP
|
||||
|
@ -267,7 +267,7 @@ the prefix value and a
|
|||
\fI/\fP
|
||||
character to the regular name field to obtain the full pathname.
|
||||
Note that all unused bytes must be set to
|
||||
.BR NULL.
|
||||
.BR NUL.
|
||||
Field termination is specified slightly differently by POSIX
|
||||
than by previous implementations.
|
||||
The
|
||||
|
@ -276,14 +276,14 @@ The
|
|||
and
|
||||
\fIgname\fP
|
||||
fields must have a trailing
|
||||
.BR NULL.
|
||||
.BR NUL.
|
||||
The
|
||||
\fIpathname\fP,
|
||||
\fIlinkname\fP,
|
||||
and
|
||||
\fIprefix\fP
|
||||
fields must have a trailing
|
||||
.BR NULL
|
||||
.BR NUL
|
||||
unless they fill the entire field.
|
||||
(In particular, it is possible to store a 256-character pathname if it
|
||||
happens to have a
|
||||
|
@ -291,7 +291,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
|
||||
.BR NULL
|
||||
.BR NUL
|
||||
characters.
|
||||
Currently, most tar implementations comply with the ustar
|
||||
format, occasionally extending it by adding new fields to the
|
||||
|
|
|
@ -91,7 +91,7 @@ DESCRIPTION
|
|||
|
||||
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.
|
||||
|
||||
filesize
|
||||
The size of the file. Note that this archive format is limited
|
||||
|
@ -99,8 +99,8 @@ DESCRIPTION
|
|||
of the storage of four-byte integers.
|
||||
|
||||
The pathname immediately follows the fixed header. If the namesize is
|
||||
odd, an additional NULL byte is added after the pathname. The file data
|
||||
is then appended, padded with NULL bytes to an even length.
|
||||
odd, an additional NUL byte is added after the pathname. The file data
|
||||
is then appended, padded with NUL bytes to an even length.
|
||||
|
||||
Hardlinked files are not given special treatment; the full file contents
|
||||
are included with each copy of the file.
|
||||
|
@ -130,7 +130,7 @@ DESCRIPTION
|
|||
file body follow the fixed header. 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
|
||||
archive will be entirely ASCII, except for the NUL byte that terminates
|
||||
the name field.
|
||||
|
||||
New ASCII Format
|
||||
|
@ -163,11 +163,11 @@ DESCRIPTION
|
|||
check This field is always set to zero by writers and ignored by read-
|
||||
ers. See the next section for more details.
|
||||
|
||||
The pathname is followed by NULL 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 sup-
|
||||
ports only 4 gigabyte files (unlike the older ASCII format, which sup-
|
||||
ports 8 gigabyte files).
|
||||
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 older ASCII format, which supports 8 giga-
|
||||
byte files).
|
||||
|
||||
In this format, hardlinked files are handled by setting the filesize to
|
||||
zero for each entry except the last one that appears in the archive.
|
||||
|
|
|
@ -143,7 +143,7 @@ DESCRIPTION
|
|||
typeflag
|
||||
Type of entry. POSIX extended the earlier linkflag field with
|
||||
several new type values:
|
||||
``0'' Regular file. NULL should be treated as a synonym, for
|
||||
``0'' Regular file. NUL should be treated as a synonym, for
|
||||
compatibility purposes.
|
||||
``1'' Hard link.
|
||||
``2'' Symbolic link.
|
||||
|
@ -167,7 +167,7 @@ DESCRIPTION
|
|||
allocate directory space. For all other types, it should be set
|
||||
to zero by writers and ignored by readers.
|
||||
|
||||
magic Contains the magic value ``ustar'' followed by a NULL byte to
|
||||
magic Contains the magic value ``ustar'' 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.
|
||||
|
||||
|
@ -191,15 +191,15 @@ DESCRIPTION
|
|||
a / character to the regular name field to obtain the full path-
|
||||
name.
|
||||
|
||||
Note that all unused bytes must be set to NULL.
|
||||
Note that all unused bytes must be set to NUL.
|
||||
|
||||
Field termination is specified slightly differently by POSIX than by pre-
|
||||
vious implementations. The magic, uname, and gname fields must have a
|
||||
trailing NULL. The pathname, linkname, and prefix fields must have a
|
||||
trailing NULL unless they fill the entire field. (In particular, it is
|
||||
trailing NUL. The pathname, linkname, and prefix fields must have a
|
||||
trailing NUL unless they fill the entire field. (In particular, it is
|
||||
possible to store a 256-character pathname if it 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 NULL
|
||||
the front, and allows them to be terminated with either space or NUL
|
||||
characters.
|
||||
|
||||
Currently, most tar implementations comply with the ustar format, occa-
|
||||
|
|
|
@ -29,17 +29,48 @@
|
|||
#define ARCHIVE_H_INCLUDED
|
||||
|
||||
#include <sys/types.h> /* Linux requires this for off_t */
|
||||
@ARCHIVE_H_INCLUDE_INTTYPES_H@
|
||||
/* TODO: Conditionalize this include on platforms that don't support it. */
|
||||
#include <inttypes.h> /* int64_t, etc. */
|
||||
#include <stdio.h> /* For FILE * */
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> /* For ssize_t and size_t */
|
||||
|
||||
/* 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
|
||||
typedef long ssize_t;
|
||||
typedef unsigned int uid_t;
|
||||
typedef unsigned int gid_t;
|
||||
typedef unsigned short mode_t;
|
||||
#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
|
||||
|
@ -48,7 +79,9 @@ extern "C" {
|
|||
* 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).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -70,13 +103,13 @@ extern "C" {
|
|||
* #endif
|
||||
*/
|
||||
#define ARCHIVE_VERSION_NUMBER @LIBARCHIVE_VERSION_NUMBER@
|
||||
int archive_version_number(void);
|
||||
__LA_DECL int archive_version_number(void);
|
||||
|
||||
/*
|
||||
* Textual name/version of the library, useful for version displays.
|
||||
*/
|
||||
#define ARCHIVE_VERSION_STRING "libarchive @LIBARCHIVE_VERSION_STRING@"
|
||||
const char * archive_version_string(void);
|
||||
__LA_DECL const char * archive_version_string(void);
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 3000000
|
||||
/*
|
||||
|
@ -84,13 +117,13 @@ const char * archive_version_string(void);
|
|||
* the simpler definitions above.
|
||||
*/
|
||||
#define ARCHIVE_VERSION_STAMP ARCHIVE_VERSION_NUMBER
|
||||
int archive_version_stamp(void);
|
||||
__LA_DECL int archive_version_stamp(void);
|
||||
#define ARCHIVE_LIBRARY_VERSION ARCHIVE_VERSION_STRING
|
||||
const char * archive_version(void);
|
||||
__LA_DECL const char * archive_version(void);
|
||||
#define ARCHIVE_API_VERSION (ARCHIVE_VERSION_NUMBER / 1000000)
|
||||
int archive_api_version(void);
|
||||
__LA_DECL int archive_api_version(void);
|
||||
#define ARCHIVE_API_FEATURE ((ARCHIVE_VERSION_NUMBER / 1000) % 1000)
|
||||
int archive_api_feature(void);
|
||||
__LA_DECL int archive_api_feature(void);
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 3000000
|
||||
|
@ -140,18 +173,18 @@ struct archive_entry;
|
|||
*/
|
||||
|
||||
/* Returns pointer and size of next block of data from archive. */
|
||||
typedef ssize_t archive_read_callback(struct archive *, void *_client_data,
|
||||
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 ssize_t archive_skip_callback(struct archive *, void *_client_data,
|
||||
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 ssize_t archive_write_callback(struct archive *, void *_client_data,
|
||||
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);
|
||||
|
@ -219,7 +252,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
|
|||
* data for entries of interest.
|
||||
* 5) Call archive_read_finish to end processing.
|
||||
*/
|
||||
struct archive *archive_read_new(void);
|
||||
__LA_DECL struct archive *archive_read_new(void);
|
||||
|
||||
/*
|
||||
* The archive_read_support_XXX calls enable auto-detect for this
|
||||
|
@ -228,30 +261,30 @@ struct archive *archive_read_new(void);
|
|||
* support_compression_bzip2(). The "all" functions provide the
|
||||
* obvious shorthand.
|
||||
*/
|
||||
int archive_read_support_compression_all(struct archive *);
|
||||
int archive_read_support_compression_bzip2(struct archive *);
|
||||
int archive_read_support_compression_compress(struct archive *);
|
||||
int archive_read_support_compression_gzip(struct archive *);
|
||||
int archive_read_support_compression_none(struct archive *);
|
||||
int archive_read_support_compression_program(struct archive *,
|
||||
__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);
|
||||
|
||||
int archive_read_support_format_all(struct archive *);
|
||||
int archive_read_support_format_ar(struct archive *);
|
||||
int archive_read_support_format_cpio(struct archive *);
|
||||
int archive_read_support_format_empty(struct archive *);
|
||||
int archive_read_support_format_gnutar(struct archive *);
|
||||
int archive_read_support_format_iso9660(struct archive *);
|
||||
int archive_read_support_format_mtree(struct archive *);
|
||||
int archive_read_support_format_tar(struct archive *);
|
||||
int archive_read_support_format_zip(struct archive *);
|
||||
__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. */
|
||||
int archive_read_open(struct archive *, void *_client_data,
|
||||
__LA_DECL int archive_read_open(struct archive *, void *_client_data,
|
||||
archive_open_callback *, archive_read_callback *,
|
||||
archive_close_callback *);
|
||||
int archive_read_open2(struct archive *, void *_client_data,
|
||||
__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
|
||||
archive_open_callback *, archive_read_callback *,
|
||||
archive_skip_callback *, archive_close_callback *);
|
||||
|
||||
|
@ -261,43 +294,43 @@ int archive_read_open2(struct archive *, void *_client_data,
|
|||
* accept a block size handle tape blocking correctly.
|
||||
*/
|
||||
/* Use this if you know the filename. Note: NULL indicates stdin. */
|
||||
int archive_read_open_filename(struct archive *,
|
||||
__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(). */
|
||||
int archive_read_open_file(struct archive *,
|
||||
__LA_DECL int archive_read_open_file(struct archive *,
|
||||
const char *_filename, size_t _block_size);
|
||||
/* Read an archive that's stored in memory. */
|
||||
int archive_read_open_memory(struct archive *,
|
||||
__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. */
|
||||
int archive_read_open_memory2(struct archive *a, void *buff,
|
||||
__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. */
|
||||
int archive_read_open_fd(struct archive *, int _fd,
|
||||
__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. */
|
||||
int archive_read_open_FILE(struct archive *, FILE *_file);
|
||||
__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
|
||||
|
||||
/* Parses and returns next entry header. */
|
||||
int archive_read_next_header(struct archive *,
|
||||
__LA_DECL int archive_read_next_header(struct archive *,
|
||||
struct archive_entry **);
|
||||
|
||||
/*
|
||||
* Retrieve the byte offset in UNCOMPRESSED data where last-read
|
||||
* header started.
|
||||
*/
|
||||
int64_t archive_read_header_position(struct archive *);
|
||||
__LA_DECL int64_t archive_read_header_position(struct archive *);
|
||||
|
||||
/* Read data from the body of an entry. Similar to read(2). */
|
||||
ssize_t archive_read_data(struct archive *, void *, size_t);
|
||||
__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.
|
||||
*/
|
||||
int archive_read_data_block(struct archive *a,
|
||||
__LA_DECL int archive_read_data_block(struct archive *a,
|
||||
const void **buff, size_t *size, off_t *offset);
|
||||
|
||||
/*-
|
||||
|
@ -306,10 +339,10 @@ int archive_read_data_block(struct archive *a,
|
|||
* 'into_buffer': writes data into memory buffer that you provide
|
||||
* 'into_fd': writes data to specified filedes
|
||||
*/
|
||||
int archive_read_data_skip(struct archive *);
|
||||
int archive_read_data_into_buffer(struct archive *, void *buffer,
|
||||
ssize_t len);
|
||||
int archive_read_data_into_fd(struct archive *, int fd);
|
||||
__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
|
||||
|
@ -353,26 +386,26 @@ int archive_read_data_into_fd(struct archive *, int fd);
|
|||
/* Default: Overwrite files, even if one on disk is newer. */
|
||||
#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (2048)
|
||||
|
||||
int archive_read_extract(struct archive *, struct archive_entry *,
|
||||
__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
|
||||
int flags);
|
||||
void archive_read_extract_set_progress_callback(struct archive *,
|
||||
__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. */
|
||||
void archive_read_extract_set_skip_file(struct archive *,
|
||||
__LA_DECL void archive_read_extract_set_skip_file(struct archive *,
|
||||
dev_t, ino_t);
|
||||
|
||||
/* Close the file and release most resources. */
|
||||
int archive_read_close(struct archive *);
|
||||
__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
|
||||
int archive_read_finish(struct archive *);
|
||||
__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 */
|
||||
void archive_read_finish(struct archive *);
|
||||
__LA_DECL void archive_read_finish(struct archive *);
|
||||
#endif
|
||||
|
||||
/*-
|
||||
|
@ -390,75 +423,75 @@ void archive_read_finish(struct archive *);
|
|||
* 5) archive_write_close to close the output
|
||||
* 6) archive_write_finish to cleanup the writer and release resources
|
||||
*/
|
||||
struct archive *archive_write_new(void);
|
||||
int archive_write_set_bytes_per_block(struct archive *,
|
||||
__LA_DECL struct archive *archive_write_new(void);
|
||||
__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
|
||||
int bytes_per_block);
|
||||
int archive_write_get_bytes_per_block(struct archive *);
|
||||
__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
|
||||
/* XXX This is badly misnamed; suggestions appreciated. XXX */
|
||||
int archive_write_set_bytes_in_last_block(struct archive *,
|
||||
__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
|
||||
int bytes_in_last_block);
|
||||
int archive_write_get_bytes_in_last_block(struct archive *);
|
||||
__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. */
|
||||
int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
|
||||
__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
|
||||
|
||||
int archive_write_set_compression_bzip2(struct archive *);
|
||||
int archive_write_set_compression_compress(struct archive *);
|
||||
int archive_write_set_compression_gzip(struct archive *);
|
||||
int archive_write_set_compression_none(struct archive *);
|
||||
int archive_write_set_compression_program(struct archive *,
|
||||
__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. */
|
||||
int archive_write_set_format(struct archive *, int format_code);
|
||||
int archive_write_set_format_by_name(struct archive *,
|
||||
__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. */
|
||||
int archive_write_set_format_ar_bsd(struct archive *);
|
||||
int archive_write_set_format_ar_svr4(struct archive *);
|
||||
int archive_write_set_format_cpio(struct archive *);
|
||||
int archive_write_set_format_cpio_newc(struct archive *);
|
||||
__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 *); */
|
||||
int archive_write_set_format_pax(struct archive *);
|
||||
int archive_write_set_format_pax_restricted(struct archive *);
|
||||
int archive_write_set_format_shar(struct archive *);
|
||||
int archive_write_set_format_shar_dump(struct archive *);
|
||||
int archive_write_set_format_ustar(struct archive *);
|
||||
int archive_write_open(struct archive *, void *,
|
||||
__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 *);
|
||||
int archive_write_open_fd(struct archive *, int _fd);
|
||||
int archive_write_open_filename(struct archive *, const char *_file);
|
||||
__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() */
|
||||
int archive_write_open_file(struct archive *, const char *_file);
|
||||
int archive_write_open_FILE(struct archive *, FILE *);
|
||||
__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. */
|
||||
int archive_write_open_memory(struct archive *,
|
||||
__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.
|
||||
*/
|
||||
int archive_write_header(struct archive *,
|
||||
__LA_DECL int archive_write_header(struct archive *,
|
||||
struct archive_entry *);
|
||||
#if ARCHIVE_VERSION_NUMBER >= 2000000
|
||||
ssize_t archive_write_data(struct archive *, const void *, size_t);
|
||||
__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. */
|
||||
int archive_write_data(struct archive *, const void *, size_t);
|
||||
__LA_DECL int archive_write_data(struct archive *, const void *, size_t);
|
||||
#endif
|
||||
ssize_t archive_write_data_block(struct archive *, const void *, size_t, off_t);
|
||||
int archive_write_finish_entry(struct archive *);
|
||||
int archive_write_close(struct archive *);
|
||||
__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
|
||||
int archive_write_finish(struct archive *);
|
||||
__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. */
|
||||
void archive_write_finish(struct archive *);
|
||||
__LA_DECL void archive_write_finish(struct archive *);
|
||||
#endif
|
||||
|
||||
/*-
|
||||
|
@ -475,12 +508,12 @@ void archive_write_finish(struct archive *);
|
|||
* In particular, you can use this in conjunction with archive_read()
|
||||
* to pull entries out of an archive and create them on disk.
|
||||
*/
|
||||
struct archive *archive_write_disk_new(void);
|
||||
__LA_DECL struct archive *archive_write_disk_new(void);
|
||||
/* This file will not be overwritten. */
|
||||
int archive_write_disk_set_skip_file(struct archive *,
|
||||
__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. */
|
||||
int archive_write_disk_set_options(struct archive *,
|
||||
__LA_DECL int archive_write_disk_set_options(struct archive *,
|
||||
int flags);
|
||||
/*
|
||||
* The lookup functions are given uname/uid (or gname/gid) pairs and
|
||||
|
@ -499,42 +532,47 @@ int archive_write_disk_set_options(struct archive *,
|
|||
* particular, these match the specifications of POSIX "pax" and old
|
||||
* POSIX "tar".
|
||||
*/
|
||||
int archive_write_disk_set_standard_lookup(struct archive *);
|
||||
__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.
|
||||
*/
|
||||
int archive_write_disk_set_group_lookup(struct archive *,
|
||||
void *private_data,
|
||||
gid_t (*loookup)(void *, const char *gname, gid_t gid),
|
||||
void (*cleanup)(void *));
|
||||
int archive_write_disk_set_user_lookup(struct archive *,
|
||||
void *private_data,
|
||||
uid_t (*)(void *, const char *uname, uid_t uid),
|
||||
void (*cleanup)(void *));
|
||||
__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. */
|
||||
int64_t archive_position_compressed(struct archive *);
|
||||
__LA_DECL int64_t archive_position_compressed(struct archive *);
|
||||
/* Bytes written to compressor or read from decompressor. */
|
||||
int64_t archive_position_uncompressed(struct archive *);
|
||||
__LA_DECL int64_t archive_position_uncompressed(struct archive *);
|
||||
|
||||
const char *archive_compression_name(struct archive *);
|
||||
int archive_compression(struct archive *);
|
||||
int archive_errno(struct archive *);
|
||||
const char *archive_error_string(struct archive *);
|
||||
const char *archive_format_name(struct archive *);
|
||||
int archive_format(struct archive *);
|
||||
void archive_clear_error(struct archive *);
|
||||
void archive_set_error(struct archive *, int _err, const char *fmt, ...);
|
||||
void archive_copy_error(struct archive *dest, struct archive *src);
|
||||
__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 */
|
||||
|
|
|
@ -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,187 @@ 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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_utf8.s == NULL || aes->aes_utf8.length == 0) {
|
||||
if (aes->aes_wcs == NULL)
|
||||
return (NULL);
|
||||
if (archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
return (aes->aes_utf8.s);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return (aes->aes_mbs);
|
||||
/* If we already have an MBS form, return that immediately. */
|
||||
if (aes->aes_mbs.s != NULL && aes->aes_mbs.length != 0)
|
||||
return (aes->aes_mbs.s);
|
||||
/* If there's a WCS form, try converting with the native locale. */
|
||||
if (aes->aes_wcs != NULL
|
||||
&& archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL)
|
||||
return (aes->aes_mbs.s);
|
||||
/* 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_wcs != NULL)
|
||||
return (aes->aes_wcs);
|
||||
|
||||
if (aes->aes_mbs.s != NULL && aes->aes_mbs.length > 0) {
|
||||
/* 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)
|
||||
return (aes->aes_wcs = w);
|
||||
free(w);
|
||||
}
|
||||
return (aes->aes_wcs);
|
||||
|
||||
if (aes->aes_utf8.s != NULL && aes->aes_utf8.length > 0) {
|
||||
/* Try converting UTF8 to WCS. */
|
||||
aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
|
||||
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;
|
||||
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;
|
||||
}
|
||||
if (aes->aes_wcs_alloc) {
|
||||
free(aes->aes_wcs_alloc);
|
||||
aes->aes_wcs_alloc = 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 (aes->aes_wcs_alloc) {
|
||||
free(aes->aes_wcs_alloc);
|
||||
aes->aes_wcs_alloc = NULL;
|
||||
}
|
||||
aes->aes_mbs = NULL;
|
||||
aes->aes_wcs = wcs;
|
||||
}
|
||||
#endif
|
||||
/* Save the UTF8 string. */
|
||||
archive_strcpy(&(aes->aes_utf8), utf8);
|
||||
|
||||
static void
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* TODO: We should just do a UTF-8 to MBS conversion here.
|
||||
* That would be faster, use less space, and give the same
|
||||
* information. */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Try converting WCS to MBS, return false on failure. */
|
||||
if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL)
|
||||
return (0);
|
||||
|
||||
/* 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, 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;
|
||||
|
||||
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;
|
||||
}
|
||||
if (aes->aes_wcs_alloc) {
|
||||
free(aes->aes_wcs_alloc);
|
||||
aes->aes_wcs_alloc = 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 +366,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 +533,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));
|
||||
}
|
||||
|
||||
|
@ -603,12 +625,16 @@ archive_entry_size(struct archive_entry *entry)
|
|||
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 +677,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 +720,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 +737,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 +801,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 +811,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 +821,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 +876,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)
|
||||
{
|
||||
|
@ -866,18 +925,24 @@ 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 +970,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 +1815,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 +1859,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 +1933,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 and shared libraries on non-Windows. */
|
||||
# define __LA_DECL
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -97,50 +129,50 @@ 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 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 +181,53 @@ 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_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 +237,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 +286,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 +299,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 +320,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 +339,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 +356,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 +389,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 +431,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 */
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#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.
|
||||
|
@ -35,10 +37,9 @@
|
|||
*/
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct ae_acl {
|
||||
|
@ -141,6 +142,8 @@ 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;
|
||||
|
||||
struct ae_acl *acl_head;
|
||||
struct ae_acl *acl_p;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -496,34 +496,48 @@ 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)
|
||||
/* 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);
|
||||
archive_entry_set_pathname(entry_main,
|
||||
build_ustar_entry_name(ustar_entry_name,
|
||||
path, strlen(path), 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 {
|
||||
/* We have a narrow path; we first need to decide
|
||||
* if we can just put it in the ustar header. */
|
||||
suffix_start = path; /* Start with a zero-length prefix. */
|
||||
if (strlen(path) > 100) {
|
||||
/* Find largest suffix that will fit. */
|
||||
suffix_start = strchr(path + strlen(path) - 100 - 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 (has_non_ASCII(path_w) || suffix_start == NULL
|
||||
|| suffix_start - path > 155) {
|
||||
/* Path is either too long or has non-ASCII 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 +1229,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');
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -271,6 +271,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,
|
||||
|
@ -293,12 +317,37 @@ test_assert_equal_string(const char *file, int 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, "\n");
|
||||
fprintf(stderr, " %s = ", e2);
|
||||
strdump(v2);
|
||||
fprintf(stderr, "\n");
|
||||
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,7 +356,17 @@ 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);
|
||||
}
|
||||
|
@ -316,8 +375,12 @@ test_assert_equal_wstring(const char *file, int 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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -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. */
|
||||
|
@ -272,6 +272,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,
|
||||
|
@ -294,12 +318,37 @@ test_assert_equal_string(const char *file, int 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, "\n");
|
||||
fprintf(stderr, " %s = ", e2);
|
||||
strdump(v2);
|
||||
fprintf(stderr, "\n");
|
||||
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,7 +357,17 @@ 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);
|
||||
}
|
||||
|
@ -317,8 +376,12 @@ test_assert_equal_wstring(const char *file, int 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);
|
||||
}
|
||||
|
@ -587,7 +650,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"
|
||||
};
|
||||
|
@ -662,7 +725,7 @@ static void usage(const char *program)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
#define uudecode(c) (((c) - 0x20) & 0x3f)
|
||||
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
|
||||
|
||||
void
|
||||
extract_reference_file(const char *name)
|
||||
|
@ -695,23 +758,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;
|
||||
}
|
||||
|
|
|
@ -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,15 @@ verify_tree(int limit)
|
|||
p = de->d_name;
|
||||
switch(p[0]) {
|
||||
case 'l': case 'm':
|
||||
if (limit == LIMIT_USTAR)
|
||||
if (limit == LIMIT_USTAR) {
|
||||
failure("strlen(p) = %d", strlen(p));
|
||||
assert(strlen(p) <= 91);
|
||||
}
|
||||
case 'd': case 'f': case 's':
|
||||
if (limit == LIMIT_USTAR)
|
||||
if (limit == LIMIT_USTAR) {
|
||||
failure("strlen(p)=%d", strlen(p));
|
||||
assert(strlen(p) <= 100);
|
||||
}
|
||||
/* Our files have very particular filename patterns. */
|
||||
assert(p[1] == '_' && p[2] == 'a');
|
||||
assert(p[2] == 'a');
|
||||
|
@ -239,7 +255,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. */
|
||||
|
|
|
@ -1 +1 @@
|
|||
2005000b
|
||||
2005001b
|
||||
|
|
Loading…
Reference in a new issue