diff options
Diffstat (limited to 'contrib/libarchive')
141 files changed, 10196 insertions, 4178 deletions
diff --git a/contrib/libarchive/NEWS b/contrib/libarchive/NEWS index e9811b5..5c28068 100644 --- a/contrib/libarchive/NEWS +++ b/contrib/libarchive/NEWS @@ -1,14 +1,10 @@ -Jan 10, 2012: Issue 223: Skip atime tests if atime not supported -Jan 09, 2012: Issue 222: Errors saving sparse files to pax archives -Jan 09, 2012: Issue 221: allow archive_*_free(NULL) -Dec 31, 2011: Issue 212: configure script on Solaris -Dec 30, 2011: Issue 218: empty contents extracting Zip files with bsdcpio -Dec 30, 2011: Issue 217: fix compile warning -Dec 30, 2011: Issue 216: truncated filenames in listings -Dec 28, 2011: Issue 210: memory leak on Windows -Dec 28, 2011: Issue 206: fix hardlink tests on Windows 2000 -Dec 27, 2011: Issue 208: Don't hang when using external compression - program on Windows +Mar 27, 2012: libarchive 3.0.4 released + +Feb 05, 2012: libarchive development now hosted at GitHub. + http://libarchive.github.com/ +Feb 05, 2012: libarchive's issue tracker remains at Google Code. + http://code.google.com/p/libarchive/issues/list +Feb 05, 2012: libarchive's mailing lists remain at Google Groups. Dec 24, 2011: libarchive 3.0.2 released Dec 23, 2011: Various fixes merged from FreeBSD diff --git a/contrib/libarchive/README b/contrib/libarchive/README index 6923838..4ffc3b7 100644 --- a/contrib/libarchive/README +++ b/contrib/libarchive/README @@ -1,9 +1,14 @@ README for libarchive bundle. Questions? Issues? - * http://libarchive.googlecode.com/ is the home for ongoing - libarchive development, including issue tracker, additional - documentation, and links to the libarchive mailing lists. + * http://libarchive.github.com/ is the home for ongoing + libarchive development, including documentation, and + links to the libarchive mailing lists. + * To report an issue, use the issue tracker at + http://code.google.com/p/libarchive/issues/list + * To submit an enhancement to libarchive, please submit + a pull request via GitHub. + https://github.com/libarchive/libarchive/pulls This distribution bundle includes the following components: * libarchive: a library for reading and writing streaming archives @@ -66,6 +71,7 @@ Currently, the library automatically detects and reads the following fomats: * ZIP archives (with uncompressed or "deflate" compressed entries) * GNU and BSD 'ar' archives * 'mtree' format + * 7-Zip archives * Microsoft CAB format * LHA and LZH archives * RAR archives @@ -92,6 +98,7 @@ The library can create archives in any of the following formats: * GNU and BSD 'ar' archives * 'mtree' format * ISO9660 format + * 7-Zip archives * XAR archives When creating archives, the result can be filtered with any of the following: diff --git a/contrib/libarchive/cpio/bsdcpio.1 b/contrib/libarchive/cpio/bsdcpio.1 index 1355130..5611b20 100644 --- a/contrib/libarchive/cpio/bsdcpio.1 +++ b/contrib/libarchive/cpio/bsdcpio.1 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 21, 2007 +.Dd December 24, 2011 .Dt CPIO 1 .Os .Sh NAME diff --git a/contrib/libarchive/cpio/cmdline.c b/contrib/libarchive/cpio/cmdline.c index a9cb33c..7f12896 100644 --- a/contrib/libarchive/cpio/cmdline.c +++ b/contrib/libarchive/cpio/cmdline.c @@ -346,6 +346,7 @@ owner_parse(const char *spec, int *uid, int *gid) snprintf(errbuff, sizeof(errbuff), "Couldn't lookup user ``%s''", user); errbuff[sizeof(errbuff) - 1] = '\0'; + free(user); return (errbuff); } } diff --git a/contrib/libarchive/cpio/cpio.c b/contrib/libarchive/cpio/cpio.c index 3e74461..fb814a2 100644 --- a/contrib/libarchive/cpio/cpio.c +++ b/contrib/libarchive/cpio/cpio.c @@ -82,7 +82,6 @@ __FBSDID("$FreeBSD$"); #include "cpio.h" #include "err.h" #include "line_reader.h" -#include "matching.h" /* Fixed size of uname/gname caches. */ #define name_cache_size 101 @@ -190,6 +189,10 @@ main(int argc, char *argv[]) cpio->bytes_per_block = 512; cpio->filename = NULL; + cpio->matching = archive_match_new(); + if (cpio->matching == NULL) + lafe_errc(1, 0, "Out of memory"); + while ((opt = cpio_getopt(cpio)) != -1) { switch (opt) { case '0': /* GNU convention: --null, -0 */ @@ -216,14 +219,20 @@ main(int argc, char *argv[]) cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR; break; case 'E': /* NetBSD/OpenBSD */ - lafe_include_from_file(&cpio->matching, - cpio->argument, cpio->option_null); + if (archive_match_include_pattern_from_file( + cpio->matching, cpio->argument, + cpio->option_null) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(cpio->matching)); break; case 'F': /* NetBSD/OpenBSD/GNU cpio */ cpio->filename = cpio->argument; break; case 'f': /* POSIX 1997 */ - lafe_exclude(&cpio->matching, cpio->argument); + if (archive_match_exclude_pattern(cpio->matching, + cpio->argument) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(cpio->matching)); break; case 'H': /* GNU cpio (also --format) */ cpio->format = cpio->argument; @@ -369,9 +378,6 @@ main(int argc, char *argv[]) /* -v overrides -V */ if (cpio->dot && cpio->verbose) cpio->dot = 0; - /* -v overrides -V */ - if (cpio->dot && cpio->verbose) - cpio->dot = 0; /* TODO: Flag other nonsensical combinations. */ switch (cpio->mode) { @@ -385,7 +391,10 @@ main(int argc, char *argv[]) break; case 'i': while (*cpio->argv != NULL) { - lafe_include(&cpio->matching, *cpio->argv); + if (archive_match_include_pattern(cpio->matching, + *cpio->argv) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(cpio->matching)); --cpio->argc; ++cpio->argv; } @@ -405,6 +414,7 @@ main(int argc, char *argv[]) "Must specify at least one of -i, -o, or -p"); } + archive_match_free(cpio->matching); free_cache(cpio->gname_cache); free_cache(cpio->uname_cache); return (cpio->return_value); @@ -909,7 +919,7 @@ mode_in(struct cpio *cpio) lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); } - if (lafe_excluded(cpio->matching, archive_entry_pathname(entry))) + if (archive_match_path_excluded(cpio->matching, entry)) continue; if (cpio->option_rename) { destpath = cpio_rename(archive_entry_pathname(entry)); @@ -1011,7 +1021,7 @@ mode_list(struct cpio *cpio) lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); } - if (lafe_excluded(cpio->matching, archive_entry_pathname(entry))) + if (archive_match_path_excluded(cpio->matching, entry)) continue; if (cpio->verbose) list_item_verbose(cpio, entry); @@ -1306,7 +1316,8 @@ lookup_uname_helper(struct cpio *cpio, const char **name, id_t id) if (pwent == NULL) { *name = NULL; if (errno != 0 && errno != ENOENT) - lafe_warnc(errno, "getpwuid(%d) failed", id); + lafe_warnc(errno, "getpwuid(%s) failed", + cpio_i64toa((int64_t)id)); return (errno); } @@ -1333,7 +1344,8 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id) if (grent == NULL) { *name = NULL; if (errno != 0) - lafe_warnc(errno, "getgrgid(%d) failed", id); + lafe_warnc(errno, "getgrgid(%s) failed", + cpio_i64toa((int64_t)id)); return (errno); } diff --git a/contrib/libarchive/cpio/cpio.h b/contrib/libarchive/cpio/cpio.h index 7c56d3c..0859100 100644 --- a/contrib/libarchive/cpio/cpio.h +++ b/contrib/libarchive/cpio/cpio.h @@ -31,8 +31,6 @@ #include "cpio_platform.h" #include <stdio.h> -#include "matching.h" - /* * The internal state for the "cpio" program. * @@ -88,7 +86,7 @@ struct cpio { struct name_cache *gname_cache; /* Work data. */ - struct lafe_matching *matching; + struct archive *matching; char *buff; size_t buff_size; }; diff --git a/contrib/libarchive/cpio/test/main.c b/contrib/libarchive/cpio/test/main.c index d4ed99c..1e4997c 100644 --- a/contrib/libarchive/cpio/test/main.c +++ b/contrib/libarchive/cpio/test/main.c @@ -24,6 +24,9 @@ */ #include "test.h" +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -31,6 +34,16 @@ #ifdef HAVE_ICONV_H #include <iconv.h> #endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include <linux/ext2_fs.h> /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ +#endif #include <limits.h> #include <locale.h> #ifdef HAVE_SIGNAL_H @@ -116,7 +129,14 @@ __FBSDID("$FreeBSD$"); #endif #if defined(_WIN32) && !defined(__CYGWIN__) -void *GetFunctionKernel32(const char *name) +static void *GetFunctionKernel32(const char *); +static int my_CreateSymbolicLinkA(const char *, const char *, int); +static int my_CreateHardLinkA(const char *, const char *); +static int my_GetFileInformationByName(const char *, + BY_HANDLE_FILE_INFORMATION *); + +static void * +GetFunctionKernel32(const char *name) { static HINSTANCE lib; static int set; @@ -155,7 +175,7 @@ my_CreateHardLinkA(const char *linkname, const char *target) return f == NULL ? 0 : (*f)(linkname, target, NULL); } -int +static int my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) { HANDLE h; @@ -1507,7 +1527,7 @@ assertion_make_dir(const char *file, int line, const char *dirname, int mode) /* Create a file with the specified contents and report any failures. */ int assertion_make_file(const char *file, int line, - const char *path, int mode, const char *contents) + const char *path, int mode, int csize, const void *contents) { #if defined(_WIN32) && !defined(__CYGWIN__) /* TODO: Rework this to set file mode as well. */ @@ -1521,8 +1541,13 @@ assertion_make_file(const char *file, int line, return (0); } if (contents != NULL) { - if (strlen(contents) - != fwrite(contents, 1, strlen(contents), f)) { + size_t wsize; + + if (csize < 0) + wsize = strlen(contents); + else + wsize = (size_t)csize; + if (wsize != fwrite(contents, 1, wsize, f)) { fclose(f); failure_start(file, line, "Could not write file %s", path); @@ -1542,10 +1567,16 @@ assertion_make_file(const char *file, int line, return (0); } if (contents != NULL) { - if ((ssize_t)strlen(contents) - != write(fd, contents, strlen(contents))) { + ssize_t wsize; + + if (csize < 0) + wsize = (ssize_t)strlen(contents); + else + wsize = (ssize_t)csize; + if (wsize != write(fd, contents, wsize)) { close(fd); - failure_start(file, line, "Could not write to %s", path); + failure_start(file, line, + "Could not write to %s", path); failure_finish(NULL); return (0); } @@ -1716,6 +1747,52 @@ assertion_utimes(const char *file, int line, #endif /* defined(_WIN32) && !defined(__CYGWIN__) */ } +/* Set nodump, report failures. */ +int +assertion_nodump(const char *file, int line, const char *pathname) +{ +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + int r; + + assertion_count(file, line); + r = chflags(pathname, UF_NODUMP); + if (r < 0) { + failure_start(file, line, "Can't set nodump %s\n", pathname); + failure_finish(NULL); + return (0); + } +#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ + && defined(EXT2_NODUMP_FL) + int fd, r, flags; + + assertion_count(file, line); + fd = open(pathname, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + failure_start(file, line, "Can't open %s\n", pathname); + failure_finish(NULL); + return (0); + } + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) { + failure_start(file, line, "Can't get flags %s\n", pathname); + failure_finish(NULL); + return (0); + } + flags |= EXT2_NODUMP_FL; + r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + if (r < 0) { + failure_start(file, line, "Can't set nodump %s\n", pathname); + failure_finish(NULL); + return (0); + } + close(fd); +#else + (void)pathname; /* UNUSED */ + assertion_count(file, line); +#endif + return (1); +} + /* * * UTILITIES for use by tests. @@ -1744,7 +1821,7 @@ canSymlink(void) return (value); ++tested; - assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a"); + assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); /* Note: Cygwin has its own symlink() emulation that does not * use the Win32 CreateSymbolicLink() function. */ #if defined(_WIN32) && !defined(__CYGWIN__) @@ -1794,6 +1871,70 @@ canGunzip(void) } /* + * Can this filesystem handle nodump flags. + */ +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + +int +canNodump(void) +{ + const char *path = "cannodumptest"; + struct stat sb; + + assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); + if (chflags(path, UF_NODUMP) < 0) + return (0); + if (stat(path, &sb) < 0) + return (0); + if (sb.st_flags & UF_NODUMP) + return (1); + return (0); +} + +#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ + && defined(EXT2_NODUMP_FL) + +int +canNodump(void) +{ + const char *path = "cannodumptest"; + int fd, r, flags; + + assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return (0); + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) + return (0); + flags |= EXT2_NODUMP_FL; + r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + if (r < 0) + return (0); + close(fd); + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return (0); + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) + return (0); + close(fd); + if (flags & EXT2_NODUMP_FL) + return (1); + return (0); +} + +#else + +int +canNodump() +{ + return (0); +} + +#endif + +/* * Sleep as needed; useful for verifying disk timestamp changes by * ensuring that the wall-clock time has actually changed before we * go back to re-read something from disk. @@ -2236,17 +2377,77 @@ success: return strdup(buff); } +static int +get_test_set(int *test_set, int limit, const char *test) +{ + int start, end; + int idx = 0; + + if (test == NULL) { + /* Default: Run all tests. */ + for (;idx < limit; idx++) + test_set[idx] = idx; + return (limit); + } + if (*test >= '0' && *test <= '9') { + const char *vp = test; + start = 0; + while (*vp >= '0' && *vp <= '9') { + start *= 10; + start += *vp - '0'; + ++vp; + } + if (*vp == '\0') { + end = start; + } else if (*vp == '-') { + ++vp; + if (*vp == '\0') { + end = limit - 1; + } else { + end = 0; + while (*vp >= '0' && *vp <= '9') { + end *= 10; + end += *vp - '0'; + ++vp; + } + } + } else + return (-1); + if (start < 0 || end >= limit || start > end) + return (-1); + while (start <= end) + test_set[idx++] = start++; + } else { + size_t len = strlen(test); + for (start = 0; start < limit; ++start) { + const char *name = tests[start].name; + const char *p; + + while ((p = strchr(name, test[0])) != NULL) { + if (strncmp(p, test, len) == 0) { + test_set[idx++] = start; + break; + } else + name = p + 1; + } + + } + } + return ((idx == 0)?-1:idx); +} + int main(int argc, char **argv) { static const int limit = sizeof(tests) / sizeof(tests[0]); - int i = 0, j = 0, start, end, tests_run = 0, tests_failed = 0, option; + int test_set[sizeof(tests) / sizeof(tests[0])]; + int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; time_t now; char *refdir_alloc = NULL; const char *progname; char **saved_argv; const char *tmp, *option_arg, *p; - char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL; + char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; char tmpdir_timestamp[256]; (void)argc; /* UNUSED */ @@ -2332,6 +2533,19 @@ main(int argc, char **argv) if (getenv(ENVBASE "_DEBUG") != NULL) dump_on_failure = 1; + /* Allow -v to be controlled through the environment. */ + if (getenv("_VERBOSITY_LEVEL") != NULL) + { + vlevel = getenv("_VERBOSITY_LEVEL"); + verbosity = atoi(vlevel); + if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) + { + /* Unsupported verbosity levels are silently ignored */ + vlevel = NULL; + verbosity = VERBOSITY_PASSFAIL; + } + } + /* Get the directory holding test files from environment. */ refdir = getenv(ENVBASE "_TEST_FILES"); @@ -2379,7 +2593,8 @@ main(int argc, char **argv) #endif break; case 'q': - verbosity--; + if (!vlevel) + verbosity--; break; case 'r': refdir = option_arg; @@ -2388,7 +2603,8 @@ main(int argc, char **argv) until_failure++; break; case 'v': - verbosity++; + if (!vlevel) + verbosity++; break; default: fprintf(stderr, "Unrecognized option '%c'\n", @@ -2501,78 +2717,27 @@ main(int argc, char **argv) saved_argv = argv; do { argv = saved_argv; - if (*argv == NULL) { - /* Default: Run all tests. */ - for (i = 0; i < limit; i++) { + do { + int test_num; + + test_num = get_test_set(test_set, limit, *argv); + if (test_num < 0) { + printf("*** INVALID Test %s\n", *argv); + free(refdir_alloc); + usage(progname); + return (1); + } + for (i = 0; i < test_num; i++) { tests_run++; - if (test_run(i, tmpdir)) { + if (test_run(test_set[i], tmpdir)) { tests_failed++; if (until_failure) goto finish; } } - } else { - while (*(argv) != NULL) { - if (**argv >= '0' && **argv <= '9') { - char *vp = *argv; - start = 0; - while (*vp >= '0' && *vp <= '9') { - start *= 10; - start += *vp - '0'; - ++vp; - } - if (*vp == '\0') { - end = start; - } else if (*vp == '-') { - ++vp; - if (*vp == '\0') { - end = limit - 1; - } else { - end = 0; - while (*vp >= '0' && *vp <= '9') { - end *= 10; - end += *vp - '0'; - ++vp; - } - } - } else { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - usage(progname); - return (1); - } - if (start < 0 || end >= limit || start > end) { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - usage(progname); - return (1); - } - } else { - for (start = 0; start < limit; ++start) { - if (strcmp(*argv, tests[start].name) == 0) - break; - } - end = start; - if (start >= limit) { - printf("*** INVALID Test ``%s''\n", - *argv); - free(refdir_alloc); - usage(progname); - /* usage() never returns */ - } - } - while (start <= end) { - tests_run++; - if (test_run(start, tmpdir)) { - tests_failed++; - if (until_failure) - goto finish; - } - ++start; - } + if (*argv != NULL) argv++; - } - } + } while (*argv != NULL); } while (until_failure); finish: diff --git a/contrib/libarchive/cpio/test/test.h b/contrib/libarchive/cpio/test/test.h index fdecb3e..b9e7030 100644 --- a/contrib/libarchive/cpio/test/test.h +++ b/contrib/libarchive/cpio/test/test.h @@ -194,11 +194,15 @@ #define assertMakeDir(dirname, mode) \ assertion_make_dir(__FILE__, __LINE__, dirname, mode) #define assertMakeFile(path, mode, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, contents) + assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) +#define assertMakeBinFile(path, mode, csize, contents) \ + assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) #define assertMakeHardlink(newfile, oldfile) \ assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) #define assertMakeSymlink(newfile, linkto) \ assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) +#define assertNodump(path) \ + assertion_nodump(__FILE__, __LINE__, path) #define assertUmask(mask) \ assertion_umask(__FILE__, __LINE__, mask) #define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ @@ -241,9 +245,10 @@ int assertion_is_not_hardlink(const char *, int, const char *, const char *); int assertion_is_reg(const char *, int, const char *, int); int assertion_is_symlink(const char *, int, const char *, const char *); int assertion_make_dir(const char *, int, const char *, int); -int assertion_make_file(const char *, int, const char *, int, const char *); +int assertion_make_file(const char *, int, const char *, int, int, const void *); int assertion_make_hardlink(const char *, int, const char *newpath, const char *); int assertion_make_symlink(const char *, int, const char *newpath, const char *); +int assertion_nodump(const char *, int, const char *); int assertion_non_empty_file(const char *, int, const char *); int assertion_text_file_contents(const char *, int, const char *buff, const char *f); int assertion_umask(const char *, int, int); @@ -267,6 +272,9 @@ int canGzip(void); /* Return true if this platform can run the "gunzip" program. */ int canGunzip(void); +/* Return true if this filesystem can handle nodump flags. */ +int canNodump(void); + /* Return true if the file has large i-node number(>0xffffffff). */ int is_LargeInode(const char *); diff --git a/contrib/libarchive/cpio/test/test_pathmatch.c b/contrib/libarchive/cpio/test/test_pathmatch.c deleted file mode 100644 index 177c2bc..0000000 --- a/contrib/libarchive/cpio/test/test_pathmatch.c +++ /dev/null @@ -1,243 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "test.h" -__FBSDID("$FreeBSD$"); - -#include "pathmatch.h" - -/* - * Verify that the pattern matcher implements the wildcard logic specified - * in SUSv2 for the cpio command. This is essentially the - * shell glob syntax: - * * - matches any sequence of chars, including '/' - * ? - matches any single char, including '/' - * [...] - matches any of a set of chars, '-' specifies a range, - * initial '!' is undefined - * - * The specification in SUSv2 is a bit incomplete, I assume the following: - * Trailing '-' in [...] is not special. - * - * TODO: Figure out if there's a good way to extend this to handle - * Windows paths that use '\' as a path separator. <sigh> - */ - -DEFINE_TEST(test_pathmatch) -{ - assertEqualInt(1, lafe_pathmatch("a/b/c", "a/b/c", 0)); - assertEqualInt(0, lafe_pathmatch("a/b/", "a/b/c", 0)); - assertEqualInt(0, lafe_pathmatch("a/b", "a/b/c", 0)); - assertEqualInt(0, lafe_pathmatch("a/b/c", "a/b/", 0)); - assertEqualInt(0, lafe_pathmatch("a/b/c", "a/b", 0)); - - /* Empty pattern only matches empty string. */ - assertEqualInt(1, lafe_pathmatch("","", 0)); - assertEqualInt(0, lafe_pathmatch("","a", 0)); - assertEqualInt(1, lafe_pathmatch("*","", 0)); - assertEqualInt(1, lafe_pathmatch("*","a", 0)); - assertEqualInt(1, lafe_pathmatch("*","abcd", 0)); - /* SUSv2: * matches / */ - assertEqualInt(1, lafe_pathmatch("*","abcd/efgh/ijkl", 0)); - assertEqualInt(1, lafe_pathmatch("abcd*efgh/ijkl","abcd/efgh/ijkl", 0)); - assertEqualInt(1, lafe_pathmatch("abcd***efgh/ijkl","abcd/efgh/ijkl", 0)); - assertEqualInt(1, lafe_pathmatch("abcd***/efgh/ijkl","abcd/efgh/ijkl", 0)); - assertEqualInt(0, lafe_pathmatch("?", "", 0)); - assertEqualInt(0, lafe_pathmatch("?", "\0", 0)); - assertEqualInt(1, lafe_pathmatch("?", "a", 0)); - assertEqualInt(0, lafe_pathmatch("?", "ab", 0)); - assertEqualInt(1, lafe_pathmatch("?", ".", 0)); - assertEqualInt(1, lafe_pathmatch("?", "?", 0)); - assertEqualInt(1, lafe_pathmatch("a", "a", 0)); - assertEqualInt(0, lafe_pathmatch("a", "ab", 0)); - assertEqualInt(0, lafe_pathmatch("a", "ab", 0)); - assertEqualInt(1, lafe_pathmatch("a?c", "abc", 0)); - /* SUSv2: ? matches / */ - assertEqualInt(1, lafe_pathmatch("a?c", "a/c", 0)); - assertEqualInt(1, lafe_pathmatch("a?*c*", "a/c", 0)); - assertEqualInt(1, lafe_pathmatch("*a*", "a/c", 0)); - assertEqualInt(1, lafe_pathmatch("*a*", "/a/c", 0)); - assertEqualInt(1, lafe_pathmatch("*a*", "defaaaaaaa", 0)); - assertEqualInt(0, lafe_pathmatch("a*", "defghi", 0)); - assertEqualInt(0, lafe_pathmatch("*a*", "defghi", 0)); - - /* Character classes */ - assertEqualInt(1, lafe_pathmatch("abc[def", "abc[def", 0)); - assertEqualInt(0, lafe_pathmatch("abc[def]", "abc[def", 0)); - assertEqualInt(0, lafe_pathmatch("abc[def", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[def]", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[def]", "abce", 0)); - assertEqualInt(1, lafe_pathmatch("abc[def]", "abcf", 0)); - assertEqualInt(0, lafe_pathmatch("abc[def]", "abcg", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d*f]", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d*f]", "abc*", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d*f]", "abcdefghi", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d*", "abcdefghi", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d*", "abc[defghi", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-f]", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-f]", "abce", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-f]", "abcf", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d-f]", "abcg", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abca", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abce", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abcf", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abcg", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abch", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abci", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abcj", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-k]", "abck", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abcl", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d-fh-k]", "abc-", 0)); - - /* [] matches nothing, [!] is the same as ? */ - assertEqualInt(0, lafe_pathmatch("abc[]efg", "abcdefg", 0)); - assertEqualInt(0, lafe_pathmatch("abc[]efg", "abcqefg", 0)); - assertEqualInt(0, lafe_pathmatch("abc[]efg", "abcefg", 0)); - assertEqualInt(1, lafe_pathmatch("abc[!]efg", "abcdefg", 0)); - assertEqualInt(1, lafe_pathmatch("abc[!]efg", "abcqefg", 0)); - assertEqualInt(0, lafe_pathmatch("abc[!]efg", "abcefg", 0)); - - /* I assume: Trailing '-' is non-special. */ - assertEqualInt(0, lafe_pathmatch("abc[d-fh-]", "abcl", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-]", "abch", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-]", "abc-", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-fh-]", "abc-", 0)); - - /* ']' can be backslash-quoted within a character class. */ - assertEqualInt(1, lafe_pathmatch("abc[\\]]", "abc]", 0)); - assertEqualInt(1, lafe_pathmatch("abc[\\]d]", "abc]", 0)); - assertEqualInt(1, lafe_pathmatch("abc[\\]d]", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d\\]]", "abc]", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d\\]]", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d]e]", "abcde]", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d\\]e]", "abc]", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d\\]e]", "abcd]e", 0)); - assertEqualInt(0, lafe_pathmatch("abc[d]e]", "abc]", 0)); - - /* backslash-quoted chars can appear as either end of a range. */ - assertEqualInt(1, lafe_pathmatch("abc[\\d-f]gh", "abcegh", 0)); - assertEqualInt(0, lafe_pathmatch("abc[\\d-f]gh", "abcggh", 0)); - assertEqualInt(0, lafe_pathmatch("abc[\\d-f]gh", "abc\\gh", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d-\\f]gh", "abcegh", 0)); - assertEqualInt(1, lafe_pathmatch("abc[\\d-\\f]gh", "abcegh", 0)); - assertEqualInt(1, lafe_pathmatch("abc[\\d-\\f]gh", "abcegh", 0)); - /* backslash-quoted '-' isn't special. */ - assertEqualInt(0, lafe_pathmatch("abc[d\\-f]gh", "abcegh", 0)); - assertEqualInt(1, lafe_pathmatch("abc[d\\-f]gh", "abc-gh", 0)); - - /* Leading '!' negates a character class. */ - assertEqualInt(0, lafe_pathmatch("abc[!d]", "abcd", 0)); - assertEqualInt(1, lafe_pathmatch("abc[!d]", "abce", 0)); - assertEqualInt(1, lafe_pathmatch("abc[!d]", "abcc", 0)); - assertEqualInt(0, lafe_pathmatch("abc[!d-z]", "abcq", 0)); - assertEqualInt(1, lafe_pathmatch("abc[!d-gi-z]", "abch", 0)); - assertEqualInt(1, lafe_pathmatch("abc[!fgijkl]", "abch", 0)); - assertEqualInt(0, lafe_pathmatch("abc[!fghijkl]", "abch", 0)); - - /* Backslash quotes next character. */ - assertEqualInt(0, lafe_pathmatch("abc\\[def]", "abc\\d", 0)); - assertEqualInt(1, lafe_pathmatch("abc\\[def]", "abc[def]", 0)); - assertEqualInt(0, lafe_pathmatch("abc\\\\[def]", "abc[def]", 0)); - assertEqualInt(0, lafe_pathmatch("abc\\\\[def]", "abc\\[def]", 0)); - assertEqualInt(1, lafe_pathmatch("abc\\\\[def]", "abc\\d", 0)); - assertEqualInt(1, lafe_pathmatch("abcd\\", "abcd\\", 0)); - assertEqualInt(0, lafe_pathmatch("abcd\\", "abcd\\[", 0)); - assertEqualInt(0, lafe_pathmatch("abcd\\", "abcde", 0)); - assertEqualInt(0, lafe_pathmatch("abcd\\[", "abcd\\", 0)); - - /* - * Because '.' and '/' have special meanings, we can - * identify many equivalent paths even if they're expressed - * differently. (But quoting a character with '\\' suppresses - * special meanings!) - */ - assertEqualInt(0, lafe_pathmatch("a/b/", "a/bc", 0)); - assertEqualInt(1, lafe_pathmatch("a/./b", "a/b", 0)); - assertEqualInt(0, lafe_pathmatch("a\\/./b", "a/b", 0)); - assertEqualInt(0, lafe_pathmatch("a/\\./b", "a/b", 0)); - assertEqualInt(0, lafe_pathmatch("a/.\\/b", "a/b", 0)); - assertEqualInt(0, lafe_pathmatch("a\\/\\.\\/b", "a/b", 0)); - assertEqualInt(1, lafe_pathmatch("./abc/./def/", "abc/def/", 0)); - assertEqualInt(1, lafe_pathmatch("abc/def", "./././abc/./def", 0)); - assertEqualInt(1, lafe_pathmatch("abc/def/././//", "./././abc/./def/", 0)); - assertEqualInt(1, lafe_pathmatch(".////abc/.//def", "./././abc/./def", 0)); - assertEqualInt(1, lafe_pathmatch("./abc?def/", "abc/def/", 0)); - failure("\"?./\" is not the same as \"/./\""); - assertEqualInt(0, lafe_pathmatch("./abc?./def/", "abc/def/", 0)); - failure("Trailing '/' should match no trailing '/'"); - assertEqualInt(1, lafe_pathmatch("./abc/./def/", "abc/def", 0)); - failure("Trailing '/./' is still the same directory."); - assertEqualInt(1, lafe_pathmatch("./abc/./def/./", "abc/def", 0)); - failure("Trailing '/.' is still the same directory."); - assertEqualInt(1, lafe_pathmatch("./abc/./def/.", "abc/def", 0)); - assertEqualInt(1, lafe_pathmatch("./abc/./def", "abc/def/", 0)); - failure("Trailing '/./' is still the same directory."); - assertEqualInt(1, lafe_pathmatch("./abc/./def", "abc/def/./", 0)); - failure("Trailing '/.' is still the same directory."); - assertEqualInt(1, lafe_pathmatch("./abc*/./def", "abc/def/.", 0)); - - /* Matches not anchored at beginning. */ - assertEqualInt(0, - lafe_pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); - assertEqualInt(1, - lafe_pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_START)); - assertEqualInt(0, - lafe_pathmatch("^bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); - assertEqualInt(1, - lafe_pathmatch("b/c/d", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); - assertEqualInt(0, - lafe_pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); - assertEqualInt(0, - lafe_pathmatch("^b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); - - /* Matches not anchored at end. */ - assertEqualInt(0, - lafe_pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("abcd", "abcd/", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("abcd", "abcd/.", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(0, - lafe_pathmatch("abc", "abcd", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("a/b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(0, - lafe_pathmatch("a/b/c$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("a/b/c$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("a/b/c$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("a/b/c/", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(0, - lafe_pathmatch("a/b/c/$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("a/b/c/$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(1, - lafe_pathmatch("a/b/c/$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); - assertEqualInt(0, - lafe_pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); -} diff --git a/contrib/libarchive/libarchive/archive.h b/contrib/libarchive/libarchive/archive.h index 8a85377..9fc69d2 100644 --- a/contrib/libarchive/libarchive/archive.h +++ b/contrib/libarchive/libarchive/archive.h @@ -56,23 +56,14 @@ # else # define __LA_SSIZE_T long # endif -# if defined(__BORLANDC__) -# define __LA_UID_T uid_t -# define __LA_GID_T gid_t -# else -# define __LA_UID_T short -# define __LA_GID_T short -# endif #else -# include <unistd.h> /* ssize_t, uid_t, and gid_t */ +# include <unistd.h> /* ssize_t */ # if defined(_SCO_DS) # define __LA_INT64_T long long # else # define __LA_INT64_T int64_t # endif # define __LA_SSIZE_T ssize_t -# define __LA_UID_T uid_t -# define __LA_GID_T gid_t #endif /* @@ -127,13 +118,13 @@ extern "C" { * assert that ARCHIVE_VERSION_NUMBER >= 2012108. */ /* Note: Compiler will complain if this does not match archive_entry.h! */ -#define ARCHIVE_VERSION_NUMBER 3000003 +#define ARCHIVE_VERSION_NUMBER 3000004 __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_STRING "libarchive 3.0.3" +#define ARCHIVE_VERSION_STRING "libarchive 3.0.4" __LA_DECL const char * archive_version_string(void); /* Declare our basic types. */ @@ -567,6 +558,8 @@ __LA_DECL int archive_write_set_compression_program(struct archive *, __LA_DECL int archive_write_set_compression_xz(struct archive *); #endif +/* A convenience function to set the filter based on the code. */ +__LA_DECL int archive_write_add_filter(struct archive *, int filter_code); __LA_DECL int archive_write_add_filter_bzip2(struct archive *); __LA_DECL int archive_write_add_filter_compress(struct archive *); __LA_DECL int archive_write_add_filter_gzip(struct archive *); @@ -758,11 +751,42 @@ __LA_DECL int archive_read_disk_open_w(struct archive *, const wchar_t *); * traversal. */ __LA_DECL int archive_read_disk_descend(struct archive *); +__LA_DECL int archive_read_disk_can_descend(struct archive *); __LA_DECL int archive_read_disk_current_filesystem(struct archive *); __LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *); __LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *); /* Request that the access time of the entry visited by travesal be restored. */ __LA_DECL int archive_read_disk_set_atime_restored(struct archive *); +/* + * Set behavior. The "flags" argument selects optional behavior. + */ +/* Request that the access time of the entry visited by travesal be restored. + * This is the same as archive_read_disk_set_atime_restored. */ +#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001) +/* Default: Do not skip an entry which has nodump flags. */ +#define ARCHIVE_READDISK_HONOR_NODUMP (0x0002) +/* Default: Skip a mac resource fork file whose prefix is "._" because of + * using copyfile. */ +#define ARCHIVE_READDISK_MAC_COPYFILE (0x0004) +/* Default: Do not traverse mount points. */ +#define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008) + +__LA_DECL int archive_read_disk_set_behavior(struct archive *, + int flags); + +/* + * Set archive_match object that will be used in archive_read_disk to + * know whether an entry should be skipped. The callback function + * _excluded_func will be invoked when an entry is skipped by the result + * of archive_match. + */ +__LA_DECL int archive_read_disk_set_matching(struct archive *, + struct archive *_matching, void (*_excluded_func) + (struct archive *, void *, struct archive_entry *), + void *_client_data); +__LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *, + int (*_metadata_filter_func)(struct archive *, void *, + struct archive_entry *), void *_client_data); /* * Accessor functions to read/set various information in @@ -802,14 +826,116 @@ __LA_DECL void archive_copy_error(struct archive *dest, struct archive *src); __LA_DECL int archive_file_count(struct archive *); +/* + * ARCHIVE_MATCH API + */ +__LA_DECL struct archive *archive_match_new(void); +__LA_DECL int archive_match_free(struct archive *); + +/* + * Test if archive_entry is excluded. + * This is a convenience function. This is the same as calling all + * archive_match_path_excluded, archive_match_time_excluded + * and archive_match_owner_excluded. + */ +__LA_DECL int archive_match_excluded(struct archive *, + struct archive_entry *); + +/* + * Test if pathname is excluded. The conditions are set by following functions. + */ +__LA_DECL int archive_match_path_excluded(struct archive *, + struct archive_entry *); +/* Add exclusion pathname pattern. */ +__LA_DECL int archive_match_exclude_pattern(struct archive *, const char *); +__LA_DECL int archive_match_exclude_pattern_w(struct archive *, + const wchar_t *); +/* Add exclusion pathname pattern from file. */ +__LA_DECL int archive_match_exclude_pattern_from_file(struct archive *, + const char *, int _nullSeparator); +__LA_DECL int archive_match_exclude_pattern_from_file_w(struct archive *, + const wchar_t *, int _nullSeparator); +/* Add inclusion pathname pattern. */ +__LA_DECL int archive_match_include_pattern(struct archive *, const char *); +__LA_DECL int archive_match_include_pattern_w(struct archive *, + const wchar_t *); +/* Add inclusion pathname pattern from file. */ +__LA_DECL int archive_match_include_pattern_from_file(struct archive *, + const char *, int _nullSeparator); +__LA_DECL int archive_match_include_pattern_from_file_w(struct archive *, + const wchar_t *, int _nullSeparator); +/* + * How to get statistic information for inclusion patterns. + */ +/* Return the amount number of unmatched inclusion patterns. */ +__LA_DECL int archive_match_path_unmatched_inclusions(struct archive *); +/* Return the pattern of unmatched inclusion with ARCHIVE_OK. + * Return ARCHIVE_EOF if there is no inclusion pattern. */ +__LA_DECL int archive_match_path_unmatched_inclusions_next( + struct archive *, const char **); +__LA_DECL int archive_match_path_unmatched_inclusions_next_w( + struct archive *, const wchar_t **); + +/* + * Test if a file is excluded by its time stamp. + * The conditions are set by following functions. + */ +__LA_DECL int archive_match_time_excluded(struct archive *, + struct archive_entry *); + +/* + * Flags to tell a matching type of time stamps. These are used for + * following functinos. + */ +/* Time flag: mtime to be tested. */ +#define ARCHIVE_MATCH_MTIME (0x0100) +/* Time flag: ctime to be tested. */ +#define ARCHIVE_MATCH_CTIME (0x0200) +/* Comparison flag: Match the time if it is newer than. */ +#define ARCHIVE_MATCH_NEWER (0x0001) +/* Comparison flag: Match the time if it is older than. */ +#define ARCHIVE_MATCH_OLDER (0x0002) +/* Comparison flag: Match the time if it is equal to. */ +#define ARCHIVE_MATCH_EQUAL (0x0010) +/* Set inclusion time. */ +__LA_DECL int archive_match_include_time(struct archive *, int _flag, + time_t _sec, long _nsec); +/* Set inclusion time by a date string. */ +__LA_DECL int archive_match_include_date(struct archive *, int _flag, + const char *_datestr); +__LA_DECL int archive_match_include_date_w(struct archive *, int _flag, + const wchar_t *_datestr); +/* Set inclusion time by a particluar file. */ +__LA_DECL int archive_match_include_file_time(struct archive *, + int _flag, const char *_pathname); +__LA_DECL int archive_match_include_file_time_w(struct archive *, + int _flag, const wchar_t *_pathname); +/* Add exclusion entry. */ +__LA_DECL int archive_match_exclude_entry(struct archive *, + int _flag, struct archive_entry *); + +/* + * Test if a file is excluded by its uid ,gid, uname or gname. + * The conditions are set by following functions. + */ +__LA_DECL int archive_match_owner_excluded(struct archive *, + struct archive_entry *); +/* Add inclusion uid, gid, uname and gname. */ +__LA_DECL int archive_match_include_uid(struct archive *, __LA_INT64_T); +__LA_DECL int archive_match_include_gid(struct archive *, __LA_INT64_T); +__LA_DECL int archive_match_include_uname(struct archive *, const char *); +__LA_DECL int archive_match_include_uname_w(struct archive *, + const wchar_t *); +__LA_DECL int archive_match_include_gname(struct archive *, const char *); +__LA_DECL int archive_match_include_gname_w(struct archive *, + const wchar_t *); + #ifdef __cplusplus } #endif /* These are meaningless outside of this header. */ #undef __LA_DECL -#undef __LA_GID_T -#undef __LA_UID_T /* These need to remain defined because they're used in the * callback type definitions. XXX Fix this. This is ugly. XXX */ diff --git a/contrib/libarchive/libarchive/archive_acl.c b/contrib/libarchive/libarchive/archive_acl.c index fbf0298..bf4b610 100644 --- a/contrib/libarchive/libarchive/archive_acl.c +++ b/contrib/libarchive/libarchive/archive_acl.c @@ -422,8 +422,11 @@ archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int *permset = acl->acl_p->permset; *tag = acl->acl_p->tag; *id = acl->acl_p->id; - if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) + if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) { + if (errno == ENOMEM) + return (ARCHIVE_FATAL); *name = NULL; + } acl->acl_p = acl->acl_p->next; return (ARCHIVE_OK); } @@ -441,7 +444,7 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags) const wchar_t *prefix; wchar_t separator; struct archive_acl_entry *ap; - int id; + int id, r; wchar_t *wp; if (acl->acl_text_w != NULL) { @@ -461,9 +464,11 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags) length += 8; /* "default:" */ length += 5; /* tag name */ length += 1; /* colon */ - if (archive_mstring_get_wcs(a, &ap->name, &wname) == 0 && - wname != NULL) + r = archive_mstring_get_wcs(a, &ap->name, &wname); + if (r == 0 && wname != NULL) length += wcslen(wname); + else if (r < 0 && errno == ENOMEM) + return (NULL); else length += sizeof(uid_t) * 3 + 1; length ++; /* colon */ @@ -487,7 +492,7 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags) /* Now, allocate the string and actually populate it. */ wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t)); if (wp == NULL) - __archive_errx(1, "No memory to generate the text version of the ACL"); + return (NULL); count = 0; if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL, @@ -502,16 +507,19 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags) ap = acl->acl_head; while (ap != NULL) { - if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 && - archive_mstring_get_wcs(a, &ap->name, &wname) == 0) { - *wp++ = separator; - if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) - id = ap->id; - else - id = -1; - append_entry_w(&wp, NULL, ap->tag, wname, - ap->permset, id); - count++; + if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + r = archive_mstring_get_wcs(a, &ap->name, &wname); + if (r == 0) { + *wp++ = separator; + if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) + id = ap->id; + else + id = -1; + append_entry_w(&wp, NULL, ap->tag, wname, + ap->permset, id); + count++; + } else if (r < 0 && errno == ENOMEM) + return (NULL); } ap = ap->next; } @@ -526,17 +534,20 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags) ap = acl->acl_head; count = 0; while (ap != NULL) { - if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 && - archive_mstring_get_wcs(a, &ap->name, &wname) == 0) { - if (count > 0) - *wp++ = separator; - if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) - id = ap->id; - else - id = -1; - append_entry_w(&wp, prefix, ap->tag, - wname, ap->permset, id); - count ++; + if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { + r = archive_mstring_get_wcs(a, &ap->name, &wname); + if (r == 0) { + if (count > 0) + *wp++ = separator; + if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) + id = ap->id; + else + id = -1; + append_entry_w(&wp, prefix, ap->tag, + wname, ap->permset, id); + count ++; + } else if (r < 0 && errno == ENOMEM) + return (NULL); } ap = ap->next; } @@ -675,7 +686,7 @@ archive_acl_text_l(struct archive_acl *acl, int flags, /* Now, allocate the string and actually populate it. */ p = acl->acl_text = (char *)malloc(length); if (p == NULL) - __archive_errx(1, "No memory to generate the text version of the ACL"); + return (-1); count = 0; if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL, diff --git a/contrib/libarchive/libarchive/archive_check_magic.c b/contrib/libarchive/libarchive/archive_check_magic.c index 93c7a4f..10e8c3a 100644 --- a/contrib/libarchive/libarchive/archive_check_magic.c +++ b/contrib/libarchive/libarchive/archive_check_magic.c @@ -94,6 +94,7 @@ archive_handle_type_name(unsigned m) case ARCHIVE_READ_MAGIC: return ("archive_read"); case ARCHIVE_WRITE_DISK_MAGIC: return ("archive_write_disk"); case ARCHIVE_READ_DISK_MAGIC: return ("archive_read_disk"); + case ARCHIVE_MATCH_MAGIC: return ("archive_match"); default: return NULL; } } diff --git a/contrib/libarchive/libarchive/archive_endian.h b/contrib/libarchive/libarchive/archive_endian.h index 9d01365..7bdeb62 100644 --- a/contrib/libarchive/libarchive/archive_endian.h +++ b/contrib/libarchive/libarchive/archive_endian.h @@ -126,8 +126,8 @@ archive_be64enc(void *pp, uint64_t u) { unsigned char *p = (unsigned char *)pp; - archive_be32enc(p, u >> 32); - archive_be32enc(p + 4, u & 0xffffffff); + archive_be32enc(p, (uint32_t)(u >> 32)); + archive_be32enc(p + 4, (uint32_t)(u & 0xffffffff)); } static inline void @@ -155,8 +155,8 @@ archive_le64enc(void *pp, uint64_t u) { unsigned char *p = (unsigned char *)pp; - archive_le32enc(p, u & 0xffffffff); - archive_le32enc(p + 4, u >> 32); + archive_le32enc(p, (uint32_t)(u & 0xffffffff)); + archive_le32enc(p + 4, (uint32_t)(u >> 32)); } #endif diff --git a/contrib/libarchive/libarchive/archive_entry.3 b/contrib/libarchive/libarchive/archive_entry.3 index 5214945..f77f385 100644 --- a/contrib/libarchive/libarchive/archive_entry.3 +++ b/contrib/libarchive/libarchive/archive_entry.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Feburary 22, 2010 +.Dd Feburary 2, 2012 .Dt ARCHIVE_ENTRY 3 .Os .Sh NAME @@ -34,6 +34,8 @@ .Nm archive_entry_free , .Nm archive_entry_new , .Nd functions for managing archive entry descriptions +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive_entry.h .Ft "struct archive_entry *" diff --git a/contrib/libarchive/libarchive/archive_entry.c b/contrib/libarchive/libarchive/archive_entry.c index f723a4d..5a028d6 100644 --- a/contrib/libarchive/libarchive/archive_entry.c +++ b/contrib/libarchive/libarchive/archive_entry.c @@ -375,8 +375,11 @@ archive_entry_fflags_text(struct archive_entry *entry) char *p; if (archive_mstring_get_mbs(entry->archive, - &entry->ae_fflags_text, &f) == 0 && f != NULL) - return (f); + &entry->ae_fflags_text, &f) == 0) { + if (f != NULL) + return (f); + } else if (errno == ENOMEM) + __archive_errx(1, "No memory"); if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0) return (NULL); @@ -390,6 +393,8 @@ archive_entry_fflags_text(struct archive_entry *entry) if (archive_mstring_get_mbs(entry->archive, &entry->ae_fflags_text, &f) == 0) return (f); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -405,6 +410,8 @@ archive_entry_gname(struct archive_entry *entry) const char *p; if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -414,6 +421,8 @@ archive_entry_gname_w(struct archive_entry *entry) const wchar_t *p; if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -428,9 +437,13 @@ const char * archive_entry_hardlink(struct archive_entry *entry) { const char *p; - if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_mbs( + if ((entry->ae_set & AE_SET_HARDLINK) == 0) + return (NULL); + if (archive_mstring_get_mbs( entry->archive, &entry->ae_hardlink, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -438,9 +451,13 @@ const wchar_t * archive_entry_hardlink_w(struct archive_entry *entry) { const wchar_t *p; - if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_wcs( + if ((entry->ae_set & AE_SET_HARDLINK) == 0) + return (NULL); + if (archive_mstring_get_wcs( entry->archive, &entry->ae_hardlink, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -511,6 +528,8 @@ archive_entry_pathname(struct archive_entry *entry) if (archive_mstring_get_mbs( entry->archive, &entry->ae_pathname, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -521,6 +540,8 @@ archive_entry_pathname_w(struct archive_entry *entry) if (archive_mstring_get_wcs( entry->archive, &entry->ae_pathname, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -584,6 +605,8 @@ archive_entry_sourcepath(struct archive_entry *entry) if (archive_mstring_get_mbs( entry->archive, &entry->ae_sourcepath, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -601,9 +624,13 @@ const char * archive_entry_symlink(struct archive_entry *entry) { const char *p; - if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_mbs( + if ((entry->ae_set & AE_SET_SYMLINK) == 0) + return (NULL); + if (archive_mstring_get_mbs( entry->archive, &entry->ae_symlink, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -611,9 +638,13 @@ const wchar_t * archive_entry_symlink_w(struct archive_entry *entry) { const wchar_t *p; - if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_wcs( + if ((entry->ae_set & AE_SET_SYMLINK) == 0) + return (NULL); + if (archive_mstring_get_wcs( entry->archive, &entry->ae_symlink, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -641,6 +672,8 @@ archive_entry_uname(struct archive_entry *entry) const char *p; if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -650,6 +683,8 @@ archive_entry_uname_w(struct archive_entry *entry) const wchar_t *p; if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0) return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); } @@ -730,6 +765,8 @@ archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) if (archive_mstring_update_utf8(entry->archive, &entry->ae_gname, name) == 0) return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (0); } @@ -796,6 +833,8 @@ archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *targ if (archive_mstring_update_utf8(entry->archive, &entry->ae_hardlink, target) == 0) return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (0); } @@ -932,7 +971,11 @@ archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) else r = archive_mstring_update_utf8(entry->archive, &entry->ae_hardlink, target); - return ((r == 0)? 1: 0); + if (r == 0) + return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (0); } int @@ -1005,6 +1048,8 @@ archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name if (archive_mstring_update_utf8(entry->archive, &entry->ae_pathname, name) == 0) return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (0); } @@ -1115,6 +1160,8 @@ archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkn if (archive_mstring_update_utf8(entry->archive, &entry->ae_symlink, linkname) == 0) return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (0); } @@ -1164,6 +1211,8 @@ archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) if (archive_mstring_update_utf8(entry->archive, &entry->ae_uname, name) == 0) return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (0); } @@ -1269,7 +1318,12 @@ int archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, int *permset, int *tag, int *id, const char **name) { - return archive_acl_next(entry->archive, &entry->acl, want_type, type, permset, tag, id, name); + int r; + r = archive_acl_next(entry->archive, &entry->acl, want_type, type, + permset, tag, id, name); + if (r == ARCHIVE_FATAL && errno == ENOMEM) + __archive_errx(1, "No memory"); + return (r); } /* @@ -1279,7 +1333,11 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, const wchar_t * archive_entry_acl_text_w(struct archive_entry *entry, int flags) { - return archive_acl_text_w(entry->archive, &entry->acl, flags); + const wchar_t *r; + r = archive_acl_text_w(entry->archive, &entry->acl, flags); + if (r == NULL && errno == ENOMEM) + __archive_errx(1, "No memory"); + return (r); } const char * @@ -1288,7 +1346,7 @@ archive_entry_acl_text(struct archive_entry *entry, int flags) const char *p; if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0 && errno == ENOMEM) - return (NULL); + __archive_errx(1, "No memory"); return (p); } diff --git a/contrib/libarchive/libarchive/archive_entry.h b/contrib/libarchive/libarchive/archive_entry.h index 50b0d85..1ee3f73 100644 --- a/contrib/libarchive/libarchive/archive_entry.h +++ b/contrib/libarchive/libarchive/archive_entry.h @@ -29,7 +29,7 @@ #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3000003 +#define ARCHIVE_VERSION_NUMBER 3000004 /* * Note: archive_entry.h is for use outside of libarchive; the @@ -47,21 +47,9 @@ #include <windows.h> #endif -/* Get appropriate definitions of standard POSIX-style types. */ -/* These should match the types used in 'struct stat' */ +/* Get a suitable 64-bit integer type. */ #if defined(_WIN32) && !defined(__CYGWIN__) -#define __LA_INT64_T __int64 -# if defined(__BORLANDC__) -# define __LA_UID_T uid_t /* Remove in libarchive 3.2 */ -# define __LA_GID_T gid_t /* Remove in libarchive 3.2 */ -# define __LA_DEV_T dev_t -# define __LA_MODE_T mode_t -# else -# define __LA_UID_T short /* Remove in libarchive 3.2 */ -# define __LA_GID_T short /* Remove in libarchive 3.2 */ -# define __LA_DEV_T unsigned int -# define __LA_MODE_T unsigned short -# endif +# define __LA_INT64_T __int64 #else #include <unistd.h> # if defined(_SCO_DS) @@ -69,17 +57,17 @@ # else # define __LA_INT64_T int64_t # endif -# define __LA_UID_T uid_t /* Remove in libarchive 3.2 */ -# define __LA_GID_T gid_t /* Remove in libarchive 3.2 */ -# define __LA_DEV_T dev_t -# define __LA_MODE_T mode_t #endif -/* - * Remove this for libarchive 3.2, since ino_t is no longer used. - */ -#define __LA_INO_T ino_t - +/* Get a suitable definition for mode_t */ +#if ARCHIVE_VERSION_NUMBER >= 3999000 +/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */ +# define __LA_MODE_T int +#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) +# define __LA_MODE_T unsigned short +#else +# define __LA_MODE_T mode_t +#endif /* * On Windows, define LIBARCHIVE_STATIC if you're building or using a @@ -149,14 +137,18 @@ struct archive_entry; * portable values to platform-native values when entries are read from * or written to disk. */ -#define AE_IFMT 0170000 -#define AE_IFREG 0100000 -#define AE_IFLNK 0120000 -#define AE_IFSOCK 0140000 -#define AE_IFCHR 0020000 -#define AE_IFBLK 0060000 -#define AE_IFDIR 0040000 -#define AE_IFIFO 0010000 +/* + * In libarchive 4.0, we can drop the casts here. + * They're needed to work around Borland C's broken mode_t. + */ +#define AE_IFMT ((__LA_MODE_T)0170000) +#define AE_IFREG ((__LA_MODE_T)0100000) +#define AE_IFLNK ((__LA_MODE_T)0120000) +#define AE_IFSOCK ((__LA_MODE_T)0140000) +#define AE_IFCHR ((__LA_MODE_T)0020000) +#define AE_IFBLK ((__LA_MODE_T)0060000) +#define AE_IFDIR ((__LA_MODE_T)0040000) +#define AE_IFIFO ((__LA_MODE_T)0010000) /* * Basic object manipulation @@ -321,7 +313,10 @@ __LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char * manipulate archives on systems different than the ones they were * created on. * - * TODO: On Linux, provide both stat32 and stat64 versions of these functions. + * TODO: On Linux and other LFS systems, provide both stat32 and + * stat64 versions of these functions and all of the macro glue so + * that archive_entry_stat is magically defined to + * archive_entry_stat32 or archive_entry_stat64 as appropriate. */ __LA_DECL const struct stat *archive_entry_stat(struct archive_entry *); __LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *); diff --git a/contrib/libarchive/libarchive/archive_entry_acl.3 b/contrib/libarchive/libarchive/archive_entry_acl.3 index 8c4f0cd..f5c3377 100644 --- a/contrib/libarchive/libarchive/archive_entry_acl.3 +++ b/contrib/libarchive/libarchive/archive_entry_acl.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 21, 2010 +.Dd February 2, 2012 .Dt ARCHIVE_ENTRY_ACL 3 .Os .Sh NAME @@ -35,6 +35,8 @@ .Nm archive_entry_acl_reset , .Nm archive_entry_acl_text_w .Nd functions for manipulating Access Control Lists in archive entry descriptions +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive_entry.h .Ft void diff --git a/contrib/libarchive/libarchive/archive_entry_link_resolver.c b/contrib/libarchive/libarchive/archive_entry_link_resolver.c index 9ec0b65..5d6780d 100644 --- a/contrib/libarchive/libarchive/archive_entry_link_resolver.c +++ b/contrib/libarchive/libarchive/archive_entry_link_resolver.c @@ -362,7 +362,7 @@ insert_entry(struct archive_entry_linkresolver *res, if (res->number_entries > res->number_buckets * 2) grow_hash(res); - hash = archive_entry_dev(entry) ^ archive_entry_ino64(entry); + hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry)); bucket = hash & (res->number_buckets - 1); /* If we could allocate the entry, record it. */ diff --git a/contrib/libarchive/libarchive/archive_entry_linkify.3 b/contrib/libarchive/libarchive/archive_entry_linkify.3 index a34b095..8c19fdd 100644 --- a/contrib/libarchive/libarchive/archive_entry_linkify.3 +++ b/contrib/libarchive/libarchive/archive_entry_linkify.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 20, 2010 +.Dd February 2, 2012 .Dt ARCHIVE_ENTRY_LINKIFY 3 .Os .Sh NAME @@ -33,7 +33,7 @@ .Nm archive_entry_linkify .Nd hardlink resolver functions .Sh LIBRARY -.Lb libarchive +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive_entry.h .Ft struct archive_entry_linkresolver * diff --git a/contrib/libarchive/libarchive/archive_entry_paths.3 b/contrib/libarchive/libarchive/archive_entry_paths.3 index 621f6551..51c8b8c 100644 --- a/contrib/libarchive/libarchive/archive_entry_paths.3 +++ b/contrib/libarchive/libarchive/archive_entry_paths.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 22, 2010 +.Dd February 2, 2012 .Dt ARCHIVE_ENTRY_PATHS 3 .Os .Sh NAME @@ -51,6 +51,8 @@ .Nm archive_entry_copy_symlink_w , .Nm archve_entry_update_symlink_utf8 .Nd functions for manipulating path names in archive entry descriptions +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive_entry.h .Ft const char * diff --git a/contrib/libarchive/libarchive/archive_entry_perms.3 b/contrib/libarchive/libarchive/archive_entry_perms.3 index 164af97..5b7b5d9 100644 --- a/contrib/libarchive/libarchive/archive_entry_perms.3 +++ b/contrib/libarchive/libarchive/archive_entry_perms.3 @@ -23,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 22, 2010 +.Dd February 2, 2012 .Dt ARCHIVE_ENTRY_PERMS 3 .Os .Sh NAME @@ -52,6 +52,8 @@ .Nm archive_entry_copy_fflags_text , .Nm archive_entry_copy_fflags_text_w .Nd functions for manipulating ownership and permissions in archive entry descriptions +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive_entry.h .Ft gid_t diff --git a/contrib/libarchive/libarchive/archive_entry_stat.3 b/contrib/libarchive/libarchive/archive_entry_stat.3 index 36a7efb..84a4ea1 100644 --- a/contrib/libarchive/libarchive/archive_entry_stat.3 +++ b/contrib/libarchive/libarchive/archive_entry_stat.3 @@ -22,8 +22,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 12, 2008 -.Dt ARCHIVE_ENTRY 3 +.Dd February 2, 2012 +.Dt ARCHIVE_ENTRY_STAT 3 .Os .Sh NAME .Nm archive_entry_stat , @@ -56,6 +56,8 @@ .Nm archive_entry_rdevminor , .Nm archive_entry_set_rdevminor , .Nd accessor functions for manipulating archive entry descriptions +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive_entry.h .Ft const struct stat * diff --git a/contrib/libarchive/libarchive/archive_entry_stat.c b/contrib/libarchive/libarchive/archive_entry_stat.c index 2edc5d2..8ae5c87 100644 --- a/contrib/libarchive/libarchive/archive_entry_stat.c +++ b/contrib/libarchive/libarchive/archive_entry_stat.c @@ -70,12 +70,12 @@ archive_entry_stat(struct archive_entry *entry) st->st_ctime = archive_entry_ctime(entry); st->st_mtime = archive_entry_mtime(entry); st->st_dev = archive_entry_dev(entry); - st->st_gid = archive_entry_gid(entry); - st->st_uid = archive_entry_uid(entry); - st->st_ino = archive_entry_ino64(entry); + st->st_gid = (gid_t)archive_entry_gid(entry); + st->st_uid = (uid_t)archive_entry_uid(entry); + st->st_ino = (ino_t)archive_entry_ino64(entry); st->st_nlink = archive_entry_nlink(entry); st->st_rdev = archive_entry_rdev(entry); - st->st_size = archive_entry_size(entry); + st->st_size = (off_t)archive_entry_size(entry); st->st_mode = archive_entry_mode(entry); /* diff --git a/contrib/libarchive/libarchive/archive_entry_time.3 b/contrib/libarchive/libarchive/archive_entry_time.3 index 85a8209..17c658a 100644 --- a/contrib/libarchive/libarchive/archive_entry_time.3 +++ b/contrib/libarchive/libarchive/archive_entry_time.3 @@ -23,9 +23,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $ +.\" $FreeBSD$ .\" -.Dd February 21, 2010 +.Dd February 2, 2012 .Dt ARCHIVE_ENTRY_TIME 3 .Os .Sh NAME @@ -50,6 +50,8 @@ .Nm archive_entry_set_mtime , .Nm archive_entry_unset_mtime , .Nd functions for manipulating times in archive entry descriptions +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive_entry.h .Ft time_t diff --git a/contrib/libarchive/tar/getdate.c b/contrib/libarchive/libarchive/archive_getdate.c index 0e15d9c..f8b5a28 100644 --- a/contrib/libarchive/tar/getdate.c +++ b/contrib/libarchive/libarchive/archive_getdate.c @@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$"); #include <time.h> /* This file defines a single public function. */ -time_t get_date(time_t now, char *); +time_t __archive_get_date(time_t now, char *); /* Basic time units. */ #define EPOCH 1970 @@ -894,7 +894,7 @@ difftm (struct tm *a, struct tm *b) * TODO: tokens[] array should be dynamically sized. */ time_t -get_date(time_t now, char *p) +__archive_get_date(time_t now, char *p) { struct token tokens[256]; struct gdstate _gds; diff --git a/contrib/libarchive/libarchive/archive_match.c b/contrib/libarchive/libarchive/archive_match.c new file mode 100644 index 0000000..6b533e6 --- /dev/null +++ b/contrib/libarchive/libarchive/archive_match.c @@ -0,0 +1,1836 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_entry.h" +#include "archive_pathmatch.h" +#include "archive_rb.h" +#include "archive_string.h" + +struct match { + struct match *next; + int matches; + struct archive_mstring pattern; +}; + +struct match_list { + struct match *first; + struct match **last; + int count; + int unmatched_count; + struct match *unmatched_next; + int unmatched_eof; +}; + +struct match_file { + struct archive_rb_node node; + struct match_file *next; + struct archive_mstring pathname; + int flag; + time_t mtime_sec; + long mtime_nsec; + time_t ctime_sec; + long ctime_nsec; +}; + +struct entry_list { + struct match_file *first; + struct match_file **last; + int count; +}; + +struct id_array { + size_t size;/* Allocated size */ + size_t count; + int64_t *ids; +}; + +#define PATTERN_IS_SET 1 +#define TIME_IS_SET 2 +#define ID_IS_SET 4 + +struct archive_match { + struct archive archive; + + /* exclusion/inclusion set flag. */ + int setflag; + + /* + * Matching filename patterns. + */ + struct match_list exclusions; + struct match_list inclusions; + + /* + * Matching time stamps. + */ + time_t now; + int newer_mtime_filter; + time_t newer_mtime_sec; + long newer_mtime_nsec; + int newer_ctime_filter; + time_t newer_ctime_sec; + long newer_ctime_nsec; + int older_mtime_filter; + time_t older_mtime_sec; + long older_mtime_nsec; + int older_ctime_filter; + time_t older_ctime_sec; + long older_ctime_nsec; + /* + * Matching time stamps with its filename. + */ + struct archive_rb_tree exclusion_tree; + struct entry_list exclusion_entry_list; + + /* + * Matching file owners. + */ + struct id_array inclusion_uids; + struct id_array inclusion_gids; + struct match_list inclusion_unames; + struct match_list inclusion_gnames; +}; + +static int add_pattern_from_file(struct archive_match *, + struct match_list *, int, const void *, int); +static int add_entry(struct archive_match *, int, + struct archive_entry *); +static int add_owner_id(struct archive_match *, struct id_array *, + int64_t); +static int add_owner_name(struct archive_match *, struct match_list *, + int, const void *); +static int add_pattern_mbs(struct archive_match *, struct match_list *, + const char *); +static int add_pattern_wcs(struct archive_match *, struct match_list *, + const wchar_t *); +static int cmp_key_mbs(const struct archive_rb_node *, const void *); +static int cmp_key_wcs(const struct archive_rb_node *, const void *); +static int cmp_node_mbs(const struct archive_rb_node *, + const struct archive_rb_node *); +static int cmp_node_wcs(const struct archive_rb_node *, + const struct archive_rb_node *); +static void entry_list_add(struct entry_list *, struct match_file *); +static void entry_list_free(struct entry_list *); +static void entry_list_init(struct entry_list *); +static int error_nomem(struct archive_match *); +static void match_list_add(struct match_list *, struct match *); +static void match_list_free(struct match_list *); +static void match_list_init(struct match_list *); +static int match_list_unmatched_inclusions_next(struct archive_match *, + struct match_list *, int, const void **); +static int match_owner_id(struct id_array *, int64_t); +#if !defined(_WIN32) || defined(__CYGWIN__) +static int match_owner_name_mbs(struct archive_match *, + struct match_list *, const char *); +#else +static int match_owner_name_wcs(struct archive_match *, + struct match_list *, const wchar_t *); +#endif +static int match_path_exclusion(struct archive_match *, + struct match *, int, const void *); +static int match_path_inclusion(struct archive_match *, + struct match *, int, const void *); +static int owner_excluded(struct archive_match *, + struct archive_entry *); +static int path_excluded(struct archive_match *, int, const void *); +static int set_timefilter(struct archive_match *, int, time_t, long, + time_t, long); +static int set_timefilter_pathname_mbs(struct archive_match *, + int, const char *); +static int set_timefilter_pathname_wcs(struct archive_match *, + int, const wchar_t *); +static int set_timefilter_date(struct archive_match *, int, const char *); +static int set_timefilter_date_w(struct archive_match *, int, + const wchar_t *); +static int time_excluded(struct archive_match *, + struct archive_entry *); +static int validate_time_flag(struct archive *, int, const char *); + +time_t __archive_get_date(time_t now, const char *); +#define get_date __archive_get_date + +static const struct archive_rb_tree_ops rb_ops_mbs = { + cmp_node_mbs, cmp_key_mbs +}; + +static const struct archive_rb_tree_ops rb_ops_wcs = { + cmp_node_wcs, cmp_key_wcs +}; + +/* + * The matching logic here needs to be re-thought. I started out to + * try to mimic gtar's matching logic, but it's not entirely + * consistent. In particular 'tar -t' and 'tar -x' interpret patterns + * on the command line as anchored, but --exclude doesn't. + */ + +static int +error_nomem(struct archive_match *a) +{ + archive_set_error(&(a->archive), ENOMEM, "No memory"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); +} + +/* + * Create an ARCHIVE_MATCH object. + */ +struct archive * +archive_match_new(void) +{ + struct archive_match *a; + + a = (struct archive_match *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_MATCH_MAGIC; + a->archive.state = ARCHIVE_STATE_NEW; + match_list_init(&(a->inclusions)); + match_list_init(&(a->exclusions)); + __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); + entry_list_init(&(a->exclusion_entry_list)); + match_list_init(&(a->inclusion_unames)); + match_list_init(&(a->inclusion_gnames)); + time(&a->now); + return (&(a->archive)); +} + +/* + * Free an ARCHIVE_MATCH object. + */ +int +archive_match_free(struct archive *_a) +{ + struct archive_match *a; + + if (_a == NULL) + return (ARCHIVE_OK); + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free"); + a = (struct archive_match *)_a; + match_list_free(&(a->inclusions)); + match_list_free(&(a->exclusions)); + entry_list_free(&(a->exclusion_entry_list)); + free(a->inclusion_uids.ids); + free(a->inclusion_gids.ids); + match_list_free(&(a->inclusion_unames)); + match_list_free(&(a->inclusion_gnames)); + free(a); + return (ARCHIVE_OK); +} + +/* + * Convenience function to perform all exclusion tests. + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_excluded(struct archive *_a, struct archive_entry *entry) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_excluded_ae"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + r = 0; + if (a->setflag & PATTERN_IS_SET) { +#if defined(_WIN32) && !defined(__CYGWIN__) + r = path_excluded(a, 0, archive_entry_pathname_w(entry)); +#else + r = path_excluded(a, 1, archive_entry_pathname(entry)); +#endif + if (r != 0) + return (r); + } + + if (a->setflag & TIME_IS_SET) { + r = time_excluded(a, entry); + if (r != 0) + return (r); + } + + if (a->setflag & ID_IS_SET) + r = owner_excluded(a, entry); + return (r); +} + +/* + * Utility functions to manage exclusion/inclusion patterns + */ + +int +archive_match_exclude_pattern(struct archive *_a, const char *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == '\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_exclude_pattern_from_file(struct archive *_a, + const char *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->exclusions), 1, pathname, + nullSeparator); +} + +int +archive_match_exclude_pattern_from_file_w(struct archive *_a, + const wchar_t *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->exclusions), 0, pathname, + nullSeparator); +} + +int +archive_match_include_pattern(struct archive *_a, const char *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == '\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern_w"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_include_pattern_from_file(struct archive *_a, + const char *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->inclusions), 1, pathname, + nullSeparator); +} + +int +archive_match_include_pattern_from_file_w(struct archive *_a, + const wchar_t *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->inclusions), 0, pathname, + nullSeparator); +} + +/* + * Test functions for pathname patterns. + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_path_excluded(struct archive *_a, + struct archive_entry *entry) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_path_excluded"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + /* If we don't have exclusion/inclusion pattern set at all, + * the entry is always not excluded. */ + if ((a->setflag & PATTERN_IS_SET) == 0) + return (0); +#if defined(_WIN32) && !defined(__CYGWIN__) + return (path_excluded(a, 0, archive_entry_pathname_w(entry))); +#else + return (path_excluded(a, 1, archive_entry_pathname(entry))); +#endif +} + +/* + * Utilty functions to get statistic information for inclusion patterns. + */ +int +archive_match_path_unmatched_inclusions(struct archive *_a) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions"); + a = (struct archive_match *)_a; + + return (a->inclusions.unmatched_count); +} + +int +archive_match_path_unmatched_inclusions_next(struct archive *_a, + const char **_p) +{ + struct archive_match *a; + const void *v; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next"); + a = (struct archive_match *)_a; + + r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v); + *_p = (const char *)v; + return (r); +} + +int +archive_match_path_unmatched_inclusions_next_w(struct archive *_a, + const wchar_t **_p) +{ + struct archive_match *a; + const void *v; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w"); + a = (struct archive_match *)_a; + + r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v); + *_p = (const wchar_t *)v; + return (r); +} + +/* + * Add inclusion/exclusion patterns. + */ +static int +add_pattern_mbs(struct archive_match *a, struct match_list *list, + const char *pattern) +{ + struct match *match; + size_t len; + + match = calloc(1, sizeof(*match)); + if (match == NULL) + return (error_nomem(a)); + /* Both "foo/" and "foo" should match "foo/bar". */ + len = strlen(pattern); + if (len && pattern[len - 1] == '/') + --len; + archive_mstring_copy_mbs_len(&(match->pattern), pattern, len); + match_list_add(list, match); + a->setflag |= PATTERN_IS_SET; + return (ARCHIVE_OK); +} + +static int +add_pattern_wcs(struct archive_match *a, struct match_list *list, + const wchar_t *pattern) +{ + struct match *match; + size_t len; + + match = calloc(1, sizeof(*match)); + if (match == NULL) + return (error_nomem(a)); + /* Both "foo/" and "foo" should match "foo/bar". */ + len = wcslen(pattern); + if (len && pattern[len - 1] == L'/') + --len; + archive_mstring_copy_wcs_len(&(match->pattern), pattern, len); + match_list_add(list, match); + a->setflag |= PATTERN_IS_SET; + return (ARCHIVE_OK); +} + +static int +add_pattern_from_file(struct archive_match *a, struct match_list *mlist, + int mbs, const void *pathname, int nullSeparator) +{ + struct archive *ar; + struct archive_entry *ae; + struct archive_string as; + const void *buff; + size_t size; + int64_t offset; + int r; + + ar = archive_read_new(); + if (ar == NULL) { + archive_set_error(&(a->archive), ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + r = archive_read_support_format_raw(ar); + if (r != ARCHIVE_OK) { + archive_copy_error(&(a->archive), ar); + archive_read_free(ar); + return (r); + } + if (mbs) + r = archive_read_open_filename(ar, pathname, 512*20); + else + r = archive_read_open_filename_w(ar, pathname, 512*20); + if (r != ARCHIVE_OK) { + archive_copy_error(&(a->archive), ar); + archive_read_free(ar); + return (r); + } + r = archive_read_next_header(ar, &ae); + if (r != ARCHIVE_OK) { + archive_copy_error(&(a->archive), ar); + archive_read_free(ar); + return (r); + } + + archive_string_init(&as); + + while ((r = archive_read_data_block(ar, &buff, &size, &offset)) + == ARCHIVE_OK) { + const char *b = (const char *)buff; + + while (size) { + const char *s = (const char *)b; + size_t length = 0; + int found_separator = 0; + + while (length < size) { + if (nullSeparator) { + if (*b == '\0') { + found_separator = 1; + break; + } + } else { + if (*b == 0x0d || *b == 0x0a) { + found_separator = 1; + break; + } + } + b++; + length++; + } + if (!found_separator) { + archive_strncat(&as, s, length); + /* Read next data block. */ + break; + } + b++; + size -= length + 1; + archive_strncat(&as, s, length); + + /* If the line is not empty, add the pattern. */ + if (archive_strlen(&as) > 0) { + /* Add pattern. */ + r = add_pattern_mbs(a, mlist, as.s); + if (r != ARCHIVE_OK) { + archive_read_free(ar); + archive_string_free(&as); + return (r); + } + archive_string_empty(&as); + } + } + } + + /* If something error happend, report it immediately. */ + if (r < ARCHIVE_OK) { + archive_copy_error(&(a->archive), ar); + archive_read_free(ar); + archive_string_free(&as); + return (r); + } + + /* If the line is not empty, add the pattern. */ + if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { + /* Add pattern. */ + r = add_pattern_mbs(a, mlist, as.s); + if (r != ARCHIVE_OK) { + archive_read_free(ar); + archive_string_free(&as); + return (r); + } + } + archive_read_free(ar); + archive_string_free(&as); + return (ARCHIVE_OK); +} + +/* + * Test if pathname is excluded by inclusion/exclusion patterns. + */ +static int +path_excluded(struct archive_match *a, int mbs, const void *pathname) +{ + struct match *match; + struct match *matched; + int r; + + if (a == NULL) + return (0); + + /* Mark off any unmatched inclusions. */ + /* In particular, if a filename does appear in the archive and + * is explicitly included and excluded, then we don't report + * it as missing even though we don't extract it. + */ + matched = NULL; + for (match = a->inclusions.first; match != NULL; + match = match->next){ + if (match->matches == 0 && + (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { + if (r < 0) + return (r); + a->inclusions.unmatched_count--; + match->matches++; + matched = match; + } + } + + /* Exclusions take priority */ + for (match = a->exclusions.first; match != NULL; + match = match->next){ + r = match_path_exclusion(a, match, mbs, pathname); + if (r) + return (r); + } + + /* It's not excluded and we found an inclusion above, so it's + * included. */ + if (matched != NULL) + return (0); + + + /* We didn't find an unmatched inclusion, check the remaining ones. */ + for (match = a->inclusions.first; match != NULL; + match = match->next){ + /* We looked at previously-unmatched inclusions already. */ + if (match->matches > 0 && + (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { + if (r < 0) + return (r); + match->matches++; + return (0); + } + } + + /* If there were inclusions, default is to exclude. */ + if (a->inclusions.first != NULL) + return (1); + + /* No explicit inclusions, default is to match. */ + return (0); +} + +/* + * This is a little odd, but it matches the default behavior of + * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' + * + */ +static int +match_path_exclusion(struct archive_match *a, struct match *m, + int mbs, const void *pn) +{ + int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END; + int r; + + if (mbs) { + const char *p; + r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch(p, (const char *)pn, flag)); + } else { + const wchar_t *p; + r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch_w(p, (const wchar_t *)pn, + flag)); + } + if (errno == ENOMEM) + return (error_nomem(a)); + return (0); +} + +/* + * Again, mimic gtar: inclusions are always anchored (have to match + * the beginning of the path) even though exclusions are not anchored. + */ +static int +match_path_inclusion(struct archive_match *a, struct match *m, + int mbs, const void *pn) +{ + int flag = PATHMATCH_NO_ANCHOR_END; + int r; + + if (mbs) { + const char *p; + r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch(p, (const char *)pn, flag)); + } else { + const wchar_t *p; + r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch_w(p, (const wchar_t *)pn, + flag)); + } + if (errno == ENOMEM) + return (error_nomem(a)); + return (0); +} + +static void +match_list_init(struct match_list *list) +{ + list->first = NULL; + list->last = &(list->first); + list->count = 0; +} + +static void +match_list_free(struct match_list *list) +{ + struct match *p, *q; + + for (p = list->first; p != NULL; ) { + q = p; + p = p->next; + archive_mstring_clean(&(q->pattern)); + free(q); + } +} + +static void +match_list_add(struct match_list *list, struct match *m) +{ + *list->last = m; + list->last = &(m->next); + list->count++; + list->unmatched_count++; +} + +static int +match_list_unmatched_inclusions_next(struct archive_match *a, + struct match_list *list, int mbs, const void **vp) +{ + struct match *m; + + *vp = NULL; + if (list->unmatched_eof) { + list->unmatched_eof = 0; + return (ARCHIVE_EOF); + } + if (list->unmatched_next == NULL) { + if (list->unmatched_count == 0) + return (ARCHIVE_EOF); + list->unmatched_next = list->first; + } + + for (m = list->unmatched_next; m != NULL; m = m->next) { + int r; + + if (m->matches) + continue; + if (mbs) { + const char *p; + r = archive_mstring_get_mbs(&(a->archive), + &(m->pattern), &p); + if (r < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p == NULL) + p = ""; + *vp = p; + } else { + const wchar_t *p; + r = archive_mstring_get_wcs(&(a->archive), + &(m->pattern), &p); + if (r < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p == NULL) + p = L""; + *vp = p; + } + list->unmatched_next = m->next; + if (list->unmatched_next == NULL) + /* To return EOF next time. */ + list->unmatched_eof = 1; + return (ARCHIVE_OK); + } + list->unmatched_next = NULL; + return (ARCHIVE_EOF); +} + +/* + * Utility functions to manage inclusion timestamps. + */ +int +archive_match_include_time(struct archive *_a, int flag, time_t sec, + long nsec) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_time"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter((struct archive_match *)_a, flag, + sec, nsec, sec, nsec); +} + +int +archive_match_include_date(struct archive *_a, int flag, + const char *datestr) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_date"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter_date((struct archive_match *)_a, flag, datestr); +} + +int +archive_match_include_date_w(struct archive *_a, int flag, + const wchar_t *datestr) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_date_w"); + if (r != ARCHIVE_OK) + return (r); + + return set_timefilter_date_w((struct archive_match *)_a, flag, datestr); +} + +int +archive_match_include_file_time(struct archive *_a, int flag, + const char *pathname) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_file_time"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter_pathname_mbs((struct archive_match *)_a, + flag, pathname); +} + +int +archive_match_include_file_time_w(struct archive *_a, int flag, + const wchar_t *pathname) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_file_time_w"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter_pathname_wcs((struct archive_match *)_a, + flag, pathname); +} + +int +archive_match_exclude_entry(struct archive *_a, int flag, + struct archive_entry *entry) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_time_include_entry"); + a = (struct archive_match *)_a; + + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + r = validate_time_flag(_a, flag, "archive_match_exclude_entry"); + if (r != ARCHIVE_OK) + return (r); + return (add_entry(a, flag, entry)); +} + +/* + * Test function for time stamps. + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_time_excluded(struct archive *_a, + struct archive_entry *entry) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + /* If we don't have inclusion time set at all, the entry is always + * not excluded. */ + if ((a->setflag & TIME_IS_SET) == 0) + return (0); + return (time_excluded(a, entry)); +} + +static int +validate_time_flag(struct archive *_a, int flag, const char *_fn) +{ + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, _fn); + + /* Check a type of time. */ + if (flag & + ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) { + archive_set_error(_a, EINVAL, "Invalid time flag"); + return (ARCHIVE_FAILED); + } + if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) { + archive_set_error(_a, EINVAL, "No time flag"); + return (ARCHIVE_FAILED); + } + + /* Check a type of comparison. */ + if (flag & + ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER + | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) { + archive_set_error(_a, EINVAL, "Invalid comparison flag"); + return (ARCHIVE_FAILED); + } + if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER + | ARCHIVE_MATCH_EQUAL)) == 0) { + archive_set_error(_a, EINVAL, "No comparison flag"); + return (ARCHIVE_FAILED); + } + + return (ARCHIVE_OK); +} + +#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\ + ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL) +static int +set_timefilter(struct archive_match *a, int timetype, + time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec) +{ + if (timetype & ARCHIVE_MATCH_MTIME) { + if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { + a->newer_mtime_filter = timetype; + a->newer_mtime_sec = mtime_sec; + a->newer_mtime_nsec = mtime_nsec; + a->setflag |= TIME_IS_SET; + } + if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { + a->older_mtime_filter = timetype; + a->older_mtime_sec = mtime_sec; + a->older_mtime_nsec = mtime_nsec; + a->setflag |= TIME_IS_SET; + } + } + if (timetype & ARCHIVE_MATCH_CTIME) { + if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { + a->newer_ctime_filter = timetype; + a->newer_ctime_sec = ctime_sec; + a->newer_ctime_nsec = ctime_nsec; + a->setflag |= TIME_IS_SET; + } + if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { + a->older_ctime_filter = timetype; + a->older_ctime_sec = ctime_sec; + a->older_ctime_nsec = ctime_nsec; + a->setflag |= TIME_IS_SET; + } + } + return (ARCHIVE_OK); +} + +static int +set_timefilter_date(struct archive_match *a, int timetype, const char *datestr) +{ + time_t t; + + if (datestr == NULL || *datestr == '\0') { + archive_set_error(&(a->archive), EINVAL, "date is empty"); + return (ARCHIVE_FAILED); + } + t = get_date(a->now, datestr); + if (t == (time_t)-1) { + archive_set_error(&(a->archive), EINVAL, "invalid date string"); + return (ARCHIVE_FAILED); + } + return set_timefilter(a, timetype, t, 0, t, 0); +} + +static int +set_timefilter_date_w(struct archive_match *a, int timetype, + const wchar_t *datestr) +{ + struct archive_string as; + time_t t; + + if (datestr == NULL || *datestr == L'\0') { + archive_set_error(&(a->archive), EINVAL, "date is empty"); + return (ARCHIVE_FAILED); + } + + archive_string_init(&as); + if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { + archive_string_free(&as); + if (errno == ENOMEM) + return (error_nomem(a)); + archive_set_error(&(a->archive), -1, + "Failed to convert WCS to MBS"); + return (ARCHIVE_FAILED); + } + t = get_date(a->now, as.s); + archive_string_free(&as); + if (t == (time_t)-1) { + archive_set_error(&(a->archive), EINVAL, "invalid date string"); + return (ARCHIVE_FAILED); + } + return set_timefilter(a, timetype, t, 0, t, 0); +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) +static int +set_timefilter_find_data(struct archive_match *a, int timetype, + DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, + DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) +{ + ULARGE_INTEGER utc; + time_t ctime_sec, mtime_sec; + long ctime_ns, mtime_ns; + + utc.HighPart = ftCreationTime_dwHighDateTime; + utc.LowPart = ftCreationTime_dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + ctime_sec = (time_t)(utc.QuadPart / 10000000); + ctime_ns = (long)(utc.QuadPart % 10000000) * 100; + } else { + ctime_sec = 0; + ctime_ns = 0; + } + utc.HighPart = ftLastWriteTime_dwHighDateTime; + utc.LowPart = ftLastWriteTime_dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + mtime_sec = (time_t)(utc.QuadPart / 10000000); + mtime_ns = (long)(utc.QuadPart % 10000000) * 100; + } else { + mtime_sec = 0; + mtime_ns = 0; + } + return set_timefilter(a, timetype, + mtime_sec, mtime_ns, ctime_sec, ctime_ns); +} + +static int +set_timefilter_pathname_mbs(struct archive_match *a, int timetype, + const char *path) +{ + /* NOTE: stat() on Windows cannot handle nano seconds. */ + HANDLE h; + WIN32_FIND_DATA d; + + if (path == NULL || *path == '\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + h = FindFirstFileA(path, &d); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + archive_set_error(&(a->archive), errno, + "Failed to FindFirstFileA"); + return (ARCHIVE_FAILED); + } + FindClose(h); + return set_timefilter_find_data(a, timetype, + d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, + d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); +} + +static int +set_timefilter_pathname_wcs(struct archive_match *a, int timetype, + const wchar_t *path) +{ + HANDLE h; + WIN32_FIND_DATAW d; + + if (path == NULL || *path == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + h = FindFirstFileW(path, &d); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + archive_set_error(&(a->archive), errno, + "Failed to FindFirstFile"); + return (ARCHIVE_FAILED); + } + FindClose(h); + return set_timefilter_find_data(a, timetype, + d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, + d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); +} + +#else /* _WIN32 && !__CYGWIN__ */ + +static int +set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st) +{ + struct archive_entry *ae; + time_t ctime_sec, mtime_sec; + long ctime_ns, mtime_ns; + + ae = archive_entry_new(); + if (ae == NULL) + return (error_nomem(a)); + archive_entry_copy_stat(ae, st); + ctime_sec = archive_entry_ctime(ae); + ctime_ns = archive_entry_ctime_nsec(ae); + mtime_sec = archive_entry_mtime(ae); + mtime_ns = archive_entry_mtime_nsec(ae); + archive_entry_free(ae); + return set_timefilter(a, timetype, mtime_sec, mtime_ns, + ctime_sec, ctime_ns); +} + +static int +set_timefilter_pathname_mbs(struct archive_match *a, int timetype, + const char *path) +{ + struct stat st; + + if (path == NULL || *path == '\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + if (stat(path, &st) != 0) { + archive_set_error(&(a->archive), errno, "Failed to stat()"); + return (ARCHIVE_FAILED); + } + return (set_timefilter_stat(a, timetype, &st)); +} + +static int +set_timefilter_pathname_wcs(struct archive_match *a, int timetype, + const wchar_t *path) +{ + struct archive_string as; + int r; + + if (path == NULL || *path == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + + /* Convert WCS filename to MBS filename. */ + archive_string_init(&as); + if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { + archive_string_free(&as); + if (errno == ENOMEM) + return (error_nomem(a)); + archive_set_error(&(a->archive), -1, + "Failed to convert WCS to MBS"); + return (ARCHIVE_FAILED); + } + + r = set_timefilter_pathname_mbs(a, timetype, as.s); + archive_string_free(&as); + + return (r); +} +#endif /* _WIN32 && !__CYGWIN__ */ + +/* + * Call back funtions for archive_rb. + */ +static int +cmp_node_mbs(const struct archive_rb_node *n1, + const struct archive_rb_node *n2) +{ + struct match_file *f1 = (struct match_file *)(uintptr_t)n1; + struct match_file *f2 = (struct match_file *)(uintptr_t)n2; + const char *p1, *p2; + + archive_mstring_get_mbs(NULL, &(f1->pathname), &p1); + archive_mstring_get_mbs(NULL, &(f2->pathname), &p2); + if (p1 == NULL) + return (1); + if (p2 == NULL) + return (-1); + return (strcmp(p1, p2)); +} + +static int +cmp_key_mbs(const struct archive_rb_node *n, const void *key) +{ + struct match_file *f = (struct match_file *)(uintptr_t)n; + const char *p; + + archive_mstring_get_mbs(NULL, &(f->pathname), &p); + if (p == NULL) + return (-1); + return (strcmp(p, (const char *)key)); +} + +static int +cmp_node_wcs(const struct archive_rb_node *n1, + const struct archive_rb_node *n2) +{ + struct match_file *f1 = (struct match_file *)(uintptr_t)n1; + struct match_file *f2 = (struct match_file *)(uintptr_t)n2; + const wchar_t *p1, *p2; + + archive_mstring_get_wcs(NULL, &(f1->pathname), &p1); + archive_mstring_get_wcs(NULL, &(f2->pathname), &p2); + if (p1 == NULL) + return (1); + if (p2 == NULL) + return (-1); + return (wcscmp(p1, p2)); +} + +static int +cmp_key_wcs(const struct archive_rb_node *n, const void *key) +{ + struct match_file *f = (struct match_file *)(uintptr_t)n; + const wchar_t *p; + + archive_mstring_get_wcs(NULL, &(f->pathname), &p); + if (p == NULL) + return (-1); + return (wcscmp(p, (const wchar_t *)key)); +} + +static void +entry_list_init(struct entry_list *list) +{ + list->first = NULL; + list->last = &(list->first); + list->count = 0; +} + +static void +entry_list_free(struct entry_list *list) +{ + struct match_file *p, *q; + + for (p = list->first; p != NULL; ) { + q = p; + p = p->next; + archive_mstring_clean(&(q->pathname)); + free(q); + } +} + +static void +entry_list_add(struct entry_list *list, struct match_file *file) +{ + *list->last = file; + list->last = &(file->next); + list->count++; +} + +static int +add_entry(struct archive_match *a, int flag, + struct archive_entry *entry) +{ + struct match_file *f; + const void *pathname; + int r; + + f = calloc(1, sizeof(*f)); + if (f == NULL) + return (error_nomem(a)); + +#if defined(_WIN32) && !defined(__CYGWIN__) + pathname = archive_entry_pathname_w(entry); + if (pathname == NULL) { + free(f); + archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); + return (ARCHIVE_FAILED); + } + archive_mstring_copy_wcs(&(f->pathname), pathname); + a->exclusion_tree.rbt_ops = &rb_ops_wcs; +#else + pathname = archive_entry_pathname(entry); + if (pathname == NULL) { + free(f); + archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); + return (ARCHIVE_FAILED); + } + archive_mstring_copy_mbs(&(f->pathname), pathname); + a->exclusion_tree.rbt_ops = &rb_ops_mbs; +#endif + f->flag = flag; + f->mtime_sec = archive_entry_mtime(entry); + f->mtime_nsec = archive_entry_mtime_nsec(entry); + f->ctime_sec = archive_entry_ctime(entry); + f->ctime_nsec = archive_entry_ctime_nsec(entry); + r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node)); + if (!r) { + struct match_file *f2; + + /* Get the duplicated file. */ + f2 = (struct match_file *)__archive_rb_tree_find_node( + &(a->exclusion_tree), pathname); + + /* + * We always overwrite comparison condision. + * If you do not want to overwrite it, you should not + * call archive_match_exclude_entry(). We cannot know + * what behavior you really expect since overwriting + * condition might be different with the flag. + */ + if (f2 != NULL) { + f2->flag = f->flag; + f2->mtime_sec = f->mtime_sec; + f2->mtime_nsec = f->mtime_nsec; + f2->ctime_sec = f->ctime_sec; + f2->ctime_nsec = f->ctime_nsec; + } + /* Release the duplicated file. */ + archive_mstring_clean(&(f->pathname)); + free(f); + return (ARCHIVE_OK); + } + entry_list_add(&(a->exclusion_entry_list), f); + a->setflag |= TIME_IS_SET; + return (ARCHIVE_OK); +} + +/* + * Test if entry is excluded by its timestamp. + */ +static int +time_excluded(struct archive_match *a, struct archive_entry *entry) +{ + struct match_file *f; + const void *pathname; + time_t sec; + long nsec; + + /* + * If this file/dir is excluded by a time comparison, skip it. + */ + if (a->newer_ctime_filter) { + /* If ctime is not set, use mtime instead. */ + if (archive_entry_ctime_is_set(entry)) + sec = archive_entry_ctime(entry); + else + sec = archive_entry_mtime(entry); + if (sec < a->newer_ctime_sec) + return (1); /* Too old, skip it. */ + if (sec == a->newer_ctime_sec) { + if (archive_entry_ctime_is_set(entry)) + nsec = archive_entry_ctime_nsec(entry); + else + nsec = archive_entry_mtime_nsec(entry); + if (nsec < a->newer_ctime_nsec) + return (1); /* Too old, skip it. */ + if (nsec == a->newer_ctime_nsec && + (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Equal, skip it. */ + } + } + if (a->older_ctime_filter) { + /* If ctime is not set, use mtime instead. */ + if (archive_entry_ctime_is_set(entry)) + sec = archive_entry_ctime(entry); + else + sec = archive_entry_mtime(entry); + if (sec > a->older_ctime_sec) + return (1); /* Too new, skip it. */ + if (sec == a->older_ctime_sec) { + if (archive_entry_ctime_is_set(entry)) + nsec = archive_entry_ctime_nsec(entry); + else + nsec = archive_entry_mtime_nsec(entry); + if (nsec > a->older_ctime_nsec) + return (1); /* Too new, skip it. */ + if (nsec == a->older_ctime_nsec && + (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Eeual, skip it. */ + } + } + if (a->newer_mtime_filter) { + sec = archive_entry_mtime(entry); + if (sec < a->newer_mtime_sec) + return (1); /* Too old, skip it. */ + if (sec == a->newer_mtime_sec) { + nsec = archive_entry_mtime_nsec(entry); + if (nsec < a->newer_mtime_nsec) + return (1); /* Too old, skip it. */ + if (nsec == a->newer_mtime_nsec && + (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Equal, skip it. */ + } + } + if (a->older_mtime_filter) { + sec = archive_entry_mtime(entry); + if (sec > a->older_mtime_sec) + return (1); /* Too new, skip it. */ + nsec = archive_entry_mtime_nsec(entry); + if (sec == a->older_mtime_sec) { + if (nsec > a->older_mtime_nsec) + return (1); /* Too new, skip it. */ + if (nsec == a->older_mtime_nsec && + (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Equal, skip it. */ + } + } + + /* If there is no excluson list, include the file. */ + if (a->exclusion_entry_list.count == 0) + return (0); + +#if defined(_WIN32) && !defined(__CYGWIN__) + pathname = archive_entry_pathname_w(entry); + a->exclusion_tree.rbt_ops = &rb_ops_wcs; +#else + pathname = archive_entry_pathname(entry); + a->exclusion_tree.rbt_ops = &rb_ops_mbs; +#endif + if (pathname == NULL) + return (0); + + f = (struct match_file *)__archive_rb_tree_find_node( + &(a->exclusion_tree), pathname); + /* If the file wasn't rejected, include it. */ + if (f == NULL) + return (0); + + if (f->flag & ARCHIVE_MATCH_CTIME) { + sec = archive_entry_ctime(entry); + if (f->ctime_sec > sec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->ctime_sec < sec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else { + nsec = archive_entry_ctime_nsec(entry); + if (f->ctime_nsec > nsec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->ctime_nsec < nsec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else if (f->flag & ARCHIVE_MATCH_EQUAL) + return (1); + } + } + if (f->flag & ARCHIVE_MATCH_MTIME) { + sec = archive_entry_mtime(entry); + if (f->mtime_sec > sec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->mtime_sec < sec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else { + nsec = archive_entry_mtime_nsec(entry); + if (f->mtime_nsec > nsec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->mtime_nsec < nsec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else if (f->flag & ARCHIVE_MATCH_EQUAL) + return (1); + } + } + return (0); +} + +/* + * Utility functions to manage inclusion owners + */ + +int +archive_match_include_uid(struct archive *_a, int64_t uid) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_uid"); + a = (struct archive_match *)_a; + return (add_owner_id(a, &(a->inclusion_uids), uid)); +} + +int +archive_match_include_gid(struct archive *_a, int64_t gid) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_gid"); + a = (struct archive_match *)_a; + return (add_owner_id(a, &(a->inclusion_gids), gid)); +} + +int +archive_match_include_uname(struct archive *_a, const char *uname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_uname"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_unames), 1, uname)); +} + +int +archive_match_include_uname_w(struct archive *_a, const wchar_t *uname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_uname_w"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_unames), 0, uname)); +} + +int +archive_match_include_gname(struct archive *_a, const char *gname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_gname"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_gnames), 1, gname)); +} + +int +archive_match_include_gname_w(struct archive *_a, const wchar_t *gname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_gname_w"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_gnames), 0, gname)); +} + +/* + * Test function for owner(uid, gid, uname, gname). + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_owner_excluded(struct archive *_a, + struct archive_entry *entry) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + /* If we don't have inclusion id set at all, the entry is always + * not excluded. */ + if ((a->setflag & ID_IS_SET) == 0) + return (0); + return (owner_excluded(a, entry)); +} + +static int +add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) +{ + unsigned i; + + if (ids->count + 1 >= ids->size) { + if (ids->size == 0) + ids->size = 8; + else + ids->size *= 2; + ids->ids = realloc(ids->ids, sizeof(*ids->ids) * ids->size); + if (ids->ids == NULL) + return (error_nomem(a)); + } + + /* Find an insert point. */ + for (i = 0; i < ids->count; i++) { + if (ids->ids[i] >= id) + break; + } + + /* Add oowner id. */ + if (i == ids->count) + ids->ids[ids->count++] = id; + else if (ids->ids[i] != id) { + memmove(&(ids->ids[i+1]), &(ids->ids[i]), + (ids->count - i) * sizeof(ids->ids[0])); + ids->ids[i] = id; + ids->count++; + } + a->setflag |= ID_IS_SET; + return (ARCHIVE_OK); +} + +static int +match_owner_id(struct id_array *ids, int64_t id) +{ + unsigned b, m, t; + + t = 0; + b = ids->count; + while (t < b) { + m = (t + b)>>1; + if (ids->ids[m] == id) + return (1); + if (ids->ids[m] < id) + t = m + 1; + else + b = m; + } + return (0); +} + +static int +add_owner_name(struct archive_match *a, struct match_list *list, + int mbs, const void *name) +{ + struct match *match; + + match = calloc(1, sizeof(*match)); + if (match == NULL) + return (error_nomem(a)); + if (mbs) + archive_mstring_copy_mbs(&(match->pattern), name); + else + archive_mstring_copy_wcs(&(match->pattern), name); + match_list_add(list, match); + a->setflag |= ID_IS_SET; + return (ARCHIVE_OK); +} + +#if !defined(_WIN32) || defined(__CYGWIN__) +static int +match_owner_name_mbs(struct archive_match *a, struct match_list *list, + const char *name) +{ + struct match *m; + const char *p; + + if (name == NULL || *name == '\0') + return (0); + for (m = list->first; m; m = m->next) { + if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p) + < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p != NULL && strcmp(p, name) == 0) { + m->matches++; + return (1); + } + } + return (0); +} +#else +static int +match_owner_name_wcs(struct archive_match *a, struct match_list *list, + const wchar_t *name) +{ + struct match *m; + const wchar_t *p; + + if (name == NULL || *name == L'\0') + return (0); + for (m = list->first; m; m = m->next) { + if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p) + < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p != NULL && wcscmp(p, name) == 0) { + m->matches++; + return (1); + } + } + return (0); +} +#endif + +/* + * Test if entry is excluded by uid, gid, uname or gname. + */ +static int +owner_excluded(struct archive_match *a, struct archive_entry *entry) +{ + int r; + + if (a->inclusion_uids.count) { + if (!match_owner_id(&(a->inclusion_uids), + archive_entry_uid(entry))) + return (1); + } + + if (a->inclusion_gids.count) { + if (!match_owner_id(&(a->inclusion_gids), + archive_entry_gid(entry))) + return (1); + } + + if (a->inclusion_unames.count) { +#if defined(_WIN32) && !defined(__CYGWIN__) + r = match_owner_name_wcs(a, &(a->inclusion_unames), + archive_entry_uname_w(entry)); +#else + r = match_owner_name_mbs(a, &(a->inclusion_unames), + archive_entry_uname(entry)); +#endif + if (!r) + return (1); + else if (r < 0) + return (r); + } + + if (a->inclusion_gnames.count) { +#if defined(_WIN32) && !defined(__CYGWIN__) + r = match_owner_name_wcs(a, &(a->inclusion_gnames), + archive_entry_gname_w(entry)); +#else + r = match_owner_name_mbs(a, &(a->inclusion_gnames), + archive_entry_gname(entry)); +#endif + if (!r) + return (1); + else if (r < 0) + return (r); + } + return (0); +} + diff --git a/contrib/libarchive/libarchive_fe/pathmatch.c b/contrib/libarchive/libarchive/archive_pathmatch.c index ff8a105..505252a 100644 --- a/contrib/libarchive/libarchive_fe/pathmatch.c +++ b/contrib/libarchive/libarchive/archive_pathmatch.c @@ -24,14 +24,17 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "lafe_platform.h" +#include "archive_platform.h" __FBSDID("$FreeBSD$"); #ifdef HAVE_STRING_H #include <string.h> #endif +#ifdef HAVE_WCHAR_H +#include <wchar.h> +#endif -#include "pathmatch.h" +#include "archive_pathmatch.h" /* * Check whether a character 'c' is matched by a list specification [...]: @@ -96,6 +99,53 @@ pm_list(const char *start, const char *end, const char c, int flags) return (nomatch); } +static int +pm_list_w(const wchar_t *start, const wchar_t *end, const wchar_t c, int flags) +{ + const wchar_t *p = start; + wchar_t rangeStart = L'\0', nextRangeStart; + int match = 1, nomatch = 0; + + /* This will be used soon... */ + (void)flags; /* UNUSED */ + + /* If this is a negated class, return success for nomatch. */ + if ((*p == L'!' || *p == L'^') && p < end) { + match = 0; + nomatch = 1; + ++p; + } + + while (p < end) { + nextRangeStart = L'\0'; + switch (*p) { + case L'-': + /* Trailing or initial '-' is not special. */ + if ((rangeStart == L'\0') || (p == end - 1)) { + if (*p == c) + return (match); + } else { + wchar_t rangeEnd = *++p; + if (rangeEnd == L'\\') + rangeEnd = *++p; + if ((rangeStart <= c) && (c <= rangeEnd)) + return (match); + } + break; + case L'\\': + ++p; + /* Fall through */ + default: + if (*p == c) + return (match); + nextRangeStart = *p; /* Possible start of range. */ + } + rangeStart = nextRangeStart; + ++p; + } + return (nomatch); +} + /* * If s is pointing to "./", ".//", "./././" or the like, skip it. */ @@ -108,6 +158,15 @@ pm_slashskip(const char *s) { return (s); } +static const wchar_t * +pm_slashskip_w(const wchar_t *s) { + while ((*s == L'/') + || (s[0] == L'.' && s[1] == L'/') + || (s[0] == L'.' && s[1] == L'\0')) + ++s; + return (s); +} + static int pm(const char *p, const char *s, int flags) { @@ -144,7 +203,7 @@ pm(const char *p, const char *s, int flags) if (*p == '\0') return (1); while (*s) { - if (lafe_pathmatch(p, s, flags)) + if (archive_pathmatch(p, s, flags)) return (1); ++s; } @@ -213,9 +272,114 @@ pm(const char *p, const char *s, int flags) } } +static int +pm_w(const wchar_t *p, const wchar_t *s, int flags) +{ + const wchar_t *end; + + /* + * Ignore leading './', './/', '././', etc. + */ + if (s[0] == L'.' && s[1] == L'/') + s = pm_slashskip_w(s + 1); + if (p[0] == L'.' && p[1] == L'/') + p = pm_slashskip_w(p + 1); + + for (;;) { + switch (*p) { + case L'\0': + if (s[0] == L'/') { + if (flags & PATHMATCH_NO_ANCHOR_END) + return (1); + /* "dir" == "dir/" == "dir/." */ + s = pm_slashskip_w(s); + } + return (*s == L'\0'); + case L'?': + /* ? always succeeds, unless we hit end of 's' */ + if (*s == L'\0') + return (0); + break; + case L'*': + /* "*" == "**" == "***" ... */ + while (*p == L'*') + ++p; + /* Trailing '*' always succeeds. */ + if (*p == L'\0') + return (1); + while (*s) { + if (archive_pathmatch_w(p, s, flags)) + return (1); + ++s; + } + return (0); + case L'[': + /* + * Find the end of the [...] character class, + * ignoring \] that might occur within the class. + */ + end = p + 1; + while (*end != L'\0' && *end != L']') { + if (*end == L'\\' && end[1] != L'\0') + ++end; + ++end; + } + if (*end == L']') { + /* We found [...], try to match it. */ + if (!pm_list_w(p + 1, end, *s, flags)) + return (0); + p = end; /* Jump to trailing ']' char. */ + break; + } else + /* No final ']', so just match '['. */ + if (*p != *s) + return (0); + break; + case L'\\': + /* Trailing '\\' matches itself. */ + if (p[1] == L'\0') { + if (*s != L'\\') + return (0); + } else { + ++p; + if (*p != *s) + return (0); + } + break; + case L'/': + if (*s != L'/' && *s != L'\0') + return (0); + /* Note: pattern "/\./" won't match "/"; + * pm_slashskip() correctly stops at backslash. */ + p = pm_slashskip_w(p); + s = pm_slashskip_w(s); + if (*p == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)) + return (1); + --p; /* Counteract the increment below. */ + --s; + break; + case L'$': + /* '$' is special only at end of pattern and only + * if PATHMATCH_NO_ANCHOR_END is specified. */ + if (p[1] == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ + /* "dir" == "dir/" == "dir/." */ + return (*pm_slashskip_w(s) == L'\0'); + } + /* Otherwise, '$' is not special. */ + /* FALL THROUGH */ + default: + if (*p != *s) + return (0); + break; + } + ++p; + ++s; + } +} + /* Main entry point. */ int -lafe_pathmatch(const char *p, const char *s, int flags) +__archive_pathmatch(const char *p, const char *s, int flags) { /* Empty pattern only matches the empty string. */ if (p == NULL || *p == '\0') @@ -253,3 +417,43 @@ lafe_pathmatch(const char *p, const char *s, int flags) /* Default: Match from beginning. */ return (pm(p, s, flags)); } + +int +__archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags) +{ + /* Empty pattern only matches the empty string. */ + if (p == NULL || *p == L'\0') + return (s == NULL || *s == L'\0'); + + /* Leading '^' anchors the start of the pattern. */ + if (*p == L'^') { + ++p; + flags &= ~PATHMATCH_NO_ANCHOR_START; + } + + if (*p == L'/' && *s != L'/') + return (0); + + /* Certain patterns and file names anchor implicitly. */ + if (*p == L'*' || *p == L'/' || *p == L'/') { + while (*p == L'/') + ++p; + while (*s == L'/') + ++s; + return (pm_w(p, s, flags)); + } + + /* If start is unanchored, try to match start of each path element. */ + if (flags & PATHMATCH_NO_ANCHOR_START) { + for ( ; s != NULL; s = wcschr(s, L'/')) { + if (*s == L'/') + s++; + if (pm_w(p, s, flags)) + return (1); + } + return (0); + } + + /* Default: Match from beginning. */ + return (pm_w(p, s, flags)); +} diff --git a/contrib/libarchive/libarchive_fe/pathmatch.h b/contrib/libarchive/libarchive/archive_pathmatch.h index a92f3ae..e690177 100644 --- a/contrib/libarchive/libarchive_fe/pathmatch.h +++ b/contrib/libarchive/libarchive/archive_pathmatch.h @@ -26,8 +26,14 @@ * $FreeBSD$ */ -#ifndef LAFE_PATHMATCH_H -#define LAFE_PATHMATCH_H +#ifndef __LIBARCHIVE_BUILD +#ifndef __LIBARCHIVE_TEST +#error This header is only to be used internally to libarchive. +#endif +#endif + +#ifndef ARCHIVE_PATHMATCH_H +#define ARCHIVE_PATHMATCH_H /* Don't anchor at beginning unless the pattern starts with "^" */ #define PATHMATCH_NO_ANCHOR_START 1 @@ -37,6 +43,10 @@ /* Note that "^" and "$" are not special unless you set the corresponding * flag above. */ -int lafe_pathmatch(const char *p, const char *s, int flags); +int __archive_pathmatch(const char *p, const char *s, int flags); +int __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags); + +#define archive_pathmatch(p, s, f) __archive_pathmatch(p, s, f) +#define archive_pathmatch_w(p, s, f) __archive_pathmatch_w(p, s, f) #endif diff --git a/contrib/libarchive/libarchive/archive_ppmd7.c b/contrib/libarchive/libarchive/archive_ppmd7.c index b2e8c3a..13a2581 100644 --- a/contrib/libarchive/libarchive/archive_ppmd7.c +++ b/contrib/libarchive/libarchive/archive_ppmd7.c @@ -415,7 +415,7 @@ static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); } - do + while (numPs != 0) { /* Create Child */ CTX_PTR c1; /* = AllocContext(p); */ @@ -435,7 +435,6 @@ static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) SetSuccessor(ps[--numPs], REF(c1)); c = c1; } - while (numPs != 0); return c; } @@ -778,7 +777,7 @@ static void Range_Normalize(CPpmd7z_RangeDec *p) if(p->Range >= p->Bottom) break; else - p->Range = -p->Low & (p->Bottom - 1); + p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1); } p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); p->Range <<= 8; diff --git a/contrib/libarchive/libarchive/archive_private.h b/contrib/libarchive/libarchive/archive_private.h index eb4f122..86f2c2b 100644 --- a/contrib/libarchive/libarchive/archive_private.h +++ b/contrib/libarchive/libarchive/archive_private.h @@ -50,6 +50,7 @@ #define ARCHIVE_READ_MAGIC (0xdeb0c5U) #define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U) #define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U) +#define ARCHIVE_MATCH_MAGIC (0xcad11c9U) #define ARCHIVE_STATE_NEW 1U #define ARCHIVE_STATE_HEADER 2U diff --git a/contrib/libarchive/libarchive/archive_read.3 b/contrib/libarchive/libarchive/archive_read.3 index f0ab30d..a29cc1e 100644 --- a/contrib/libarchive/libarchive/archive_read.3 +++ b/contrib/libarchive/libarchive/archive_read.3 @@ -24,12 +24,14 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ 3 .Os .Sh NAME .Nm archive_read .Nd functions for reading streaming archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Sh DESCRIPTION diff --git a/contrib/libarchive/libarchive/archive_read.c b/contrib/libarchive/libarchive/archive_read.c index cd5ac20..d108ad6 100644 --- a/contrib/libarchive/libarchive/archive_read.c +++ b/contrib/libarchive/libarchive/archive_read.c @@ -201,7 +201,6 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request) request -= get; total += get; } - return total; } else if (self->archive->client.seeker != NULL && request > 64 * 1024) { /* If the client provided a seeker but not a skipper, @@ -638,8 +637,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s) len = s; } else if (a->read_data_output_offset < a->read_data_offset) { - len = a->read_data_offset - - a->read_data_output_offset; + len = (size_t)(a->read_data_offset - + a->read_data_output_offset); } else len = 0; @@ -1231,7 +1230,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request) /* Use up the copy buffer first. */ if (filter->avail > 0) { - min = minimum(request, (int64_t)filter->avail); + min = (size_t)minimum(request, (int64_t)filter->avail); filter->next += min; filter->avail -= min; request -= min; @@ -1241,7 +1240,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request) /* Then use up the client buffer. */ if (filter->client_avail > 0) { - min = minimum(request, (int64_t)filter->client_avail); + min = (size_t)minimum(request, (int64_t)filter->client_avail); filter->client_next += min; filter->client_avail -= min; request -= min; @@ -1283,7 +1282,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request) if (bytes_read >= request) { filter->client_next = ((const char *)filter->client_buff) + request; - filter->client_avail = bytes_read - request; + filter->client_avail = (size_t)(bytes_read - request); filter->client_total = bytes_read; total_bytes_skipped += request; filter->position += request; diff --git a/contrib/libarchive/libarchive/archive_read_data.3 b/contrib/libarchive/libarchive/archive_read_data.3 index 78d0497..bf0578c 100644 --- a/contrib/libarchive/libarchive/archive_read_data.3 +++ b/contrib/libarchive/libarchive/archive_read_data.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 22, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_DATA 3 .Os .Sh NAME @@ -33,6 +33,8 @@ .Nm archive_read_data_skip , .Nm archive_read_data_into_fd .Nd functions for reading streaming archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft ssize_t diff --git a/contrib/libarchive/libarchive/archive_read_disk.3 b/contrib/libarchive/libarchive/archive_read_disk.3 index b26d3ed..525dc59 100644 --- a/contrib/libarchive/libarchive/archive_read_disk.3 +++ b/contrib/libarchive/libarchive/archive_read_disk.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 10, 2009 +.Dd February 2, 2012 .Dt ARCHIVE_READ_DISK 3 .Os .Sh NAME @@ -42,6 +42,8 @@ .Nm archive_read_finish , .Nm archive_read_free .Nd functions for reading objects from disk +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft struct archive * diff --git a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c index e9df514..9ce38d9 100644 --- a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c +++ b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 2003-2009 Tim Kientzle - * Copyright (c) 2010 Michihiro NAKAJIMA + * Copyright (c) 2010-2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,6 +73,9 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_LIMITS_H #include <limits.h> #endif +#ifdef HAVE_LINUX_TYPES_H +#include <linux/types.h> +#endif #ifdef HAVE_LINUX_FIEMAP_H #include <linux/fiemap.h> #endif @@ -112,13 +115,13 @@ __FBSDID("$FreeBSD$"); #endif static int setup_acls_posix1e(struct archive_read_disk *, - struct archive_entry *, int fd); + struct archive_entry *, int *fd); static int setup_mac_metadata(struct archive_read_disk *, - struct archive_entry *, int fd); + struct archive_entry *, int *fd); static int setup_xattrs(struct archive_read_disk *, - struct archive_entry *, int fd); + struct archive_entry *, int *fd); static int setup_sparse(struct archive_read_disk *, - struct archive_entry *, int fd); + struct archive_entry *, int *fd); int archive_read_disk_entry_from_file(struct archive *_a, @@ -165,16 +168,15 @@ archive_read_disk_entry_from_file(struct archive *_a, st = &s; } archive_entry_copy_stat(entry, st); + /* Lookup uname/gname */ + name = archive_read_disk_uname(_a, archive_entry_uid(entry)); + if (name != NULL) + archive_entry_copy_uname(entry, name); + name = archive_read_disk_gname(_a, archive_entry_gid(entry)); + if (name != NULL) + archive_entry_copy_gname(entry, name); } - /* Lookup uname/gname */ - name = archive_read_disk_uname(_a, archive_entry_uid(entry)); - if (name != NULL) - archive_entry_copy_uname(entry, name); - name = archive_read_disk_gname(_a, archive_entry_gid(entry)); - if (name != NULL) - archive_entry_copy_gname(entry, name); - #ifdef HAVE_STRUCT_STAT_ST_FLAGS /* On FreeBSD, we get flags for free with the stat. */ /* TODO: Does this belong in copy_stat()? */ @@ -187,8 +189,13 @@ archive_read_disk_entry_from_file(struct archive *_a, * this is an extra step, it has a nice side-effect: We get an * open file descriptor which we can use in the subsequent lookups. */ if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) { - if (fd < 0) - fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + if (a->tree != NULL) + fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK); + else + fd = open(path, O_RDONLY | O_NONBLOCK); + } if (fd >= 0) { unsigned long stflags; r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags); @@ -210,13 +217,21 @@ archive_read_disk_entry_from_file(struct archive *_a, "Couldn't read link data"); return (ARCHIVE_FAILED); } + if (a->tree != NULL) { #ifdef HAVE_READLINKAT - if (a->entry_wd_fd >= 0) - lnklen = readlinkat(a->entry_wd_fd, path, - linkbuffer, linkbuffer_len); - else + lnklen = readlinkat(a->tree_current_dir_fd(a->tree), + path, linkbuffer, linkbuffer_len); +#else + if (a->tree_enter_working_dir(a->tree) != 0) { + archive_set_error(&a->archive, errno, + "Couldn't read link data"); + free(linkbuffer); + return (ARCHIVE_FAILED); + } + lnklen = readlink(path, linkbuffer, linkbuffer_len); #endif /* HAVE_READLINKAT */ - lnklen = readlink(path, linkbuffer, linkbuffer_len); + } else + lnklen = readlink(path, linkbuffer, linkbuffer_len); if (lnklen < 0) { archive_set_error(&a->archive, errno, "Couldn't read link data"); @@ -229,14 +244,16 @@ archive_read_disk_entry_from_file(struct archive *_a, } #endif /* HAVE_READLINK || HAVE_READLINKAT */ - r = setup_acls_posix1e(a, entry, fd); - r1 = setup_xattrs(a, entry, fd); - if (r1 < r) - r = r1; - r1 = setup_mac_metadata(a, entry, fd); + r = setup_acls_posix1e(a, entry, &fd); + r1 = setup_xattrs(a, entry, &fd); if (r1 < r) r = r1; - r1 = setup_sparse(a, entry, fd); + if (a->enable_copyfile) { + r1 = setup_mac_metadata(a, entry, &fd); + if (r1 < r) + r = r1; + } + r1 = setup_sparse(a, entry, &fd); if (r1 < r) r = r1; @@ -262,7 +279,7 @@ archive_read_disk_entry_from_file(struct archive *_a, */ static int setup_mac_metadata(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { int tempfd = -1; int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR; @@ -272,6 +289,7 @@ setup_mac_metadata(struct archive_read_disk *a, int have_attrs; const char *name, *tempdir, *tempfile = NULL; + (void)fd; /* UNUSED */ name = archive_entry_sourcepath(entry); if (name == NULL) name = archive_entry_pathname(entry); @@ -281,6 +299,14 @@ setup_mac_metadata(struct archive_read_disk *a, return (ARCHIVE_WARN); } + if (a->tree != NULL) { + if (a->tree_enter_working_dir(a->tree) != 0) { + archive_set_error(&a->archive, errno, + "Couldn't change dir"); + return (ARCHIVE_FAILED); + } + } + /* Short-circuit if there's nothing to do. */ have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK); if (have_attrs == -1) { @@ -351,7 +377,7 @@ cleanup: */ static int setup_mac_metadata(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { (void)a; /* UNUSED */ (void)entry; /* UNUSED */ @@ -367,7 +393,7 @@ static void setup_acl_posix1e(struct archive_read_disk *a, static int setup_acls_posix1e(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { const char *accpath; acl_t acl; @@ -378,9 +404,20 @@ setup_acls_posix1e(struct archive_read_disk *a, archive_entry_acl_clear(entry); + if (*fd < 0 && a->tree != NULL && + (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)){ + *fd = a->open_on_current_dir(a->tree, accpath, + O_RDONLY | O_NONBLOCK); + if (*fd < 0) { + archive_set_error(&a->archive, errno, + "Couldn't access %s", accpath); + return (ARCHIVE_FAILED); + } + } + /* Retrieve access ACL from file. */ - if (fd >= 0) - acl = acl_get_fd(fd); + if (*fd >= 0) + acl = acl_get_fd(*fd); #if HAVE_ACL_GET_LINK_NP else if (!a->follow_symlinks) acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS); @@ -474,7 +511,7 @@ setup_acl_posix1e(struct archive_read_disk *a, #else static int setup_acls_posix1e(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { (void)a; /* UNUSED */ (void)entry; /* UNUSED */ @@ -568,7 +605,7 @@ setup_xattr(struct archive_read_disk *a, static int setup_xattrs(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { char *list, *p; const char *path; @@ -578,16 +615,30 @@ setup_xattrs(struct archive_read_disk *a, if (path == NULL) path = archive_entry_pathname(entry); + if (*fd < 0 && a->tree != NULL) { + if (a->follow_symlinks || + archive_entry_filetype(entry) != AE_IFLNK) + *fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK); + if (*fd < 0) { + if (a->tree_enter_working_dir(a->tree) != 0) { + archive_set_error(&a->archive, errno, + "Couldn't access %s", path); + return (ARCHIVE_FAILED); + } + } + } + #if HAVE_FLISTXATTR - if (fd >= 0) - list_size = flistxattr(fd, NULL, 0); + if (*fd >= 0) + list_size = flistxattr(*fd, NULL, 0); else if (!a->follow_symlinks) list_size = llistxattr(path, NULL, 0); else list_size = listxattr(path, NULL, 0); #elif HAVE_FLISTEA - if (fd >= 0) - list_size = flistea(fd, NULL, 0); + if (*fd >= 0) + list_size = flistea(*fd, NULL, 0); else if (!a->follow_symlinks) list_size = llistea(path, NULL, 0); else @@ -611,15 +662,15 @@ setup_xattrs(struct archive_read_disk *a, } #if HAVE_FLISTXATTR - if (fd >= 0) - list_size = flistxattr(fd, list, list_size); + if (*fd >= 0) + list_size = flistxattr(*fd, list, list_size); else if (!a->follow_symlinks) list_size = llistxattr(path, list, list_size); else list_size = listxattr(path, list, list_size); #elif HAVE_FLISTEA - if (fd >= 0) - list_size = flistea(fd, list, list_size); + if (*fd >= 0) + list_size = flistea(*fd, list, list_size); else if (!a->follow_symlinks) list_size = llistea(path, list, list_size); else @@ -637,7 +688,7 @@ setup_xattrs(struct archive_read_disk *a, if (strncmp(p, "system.", 7) == 0 || strncmp(p, "xfsroot.", 8) == 0) continue; - setup_xattr(a, entry, p, fd); + setup_xattr(a, entry, p, *fd); } free(list); @@ -698,6 +749,7 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, size = extattr_get_file(accpath, namespace, name, value, size); if (size == -1) { + free(value); archive_set_error(&a->archive, errno, "Couldn't read extended attribute"); return (ARCHIVE_WARN); @@ -711,7 +763,7 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, static int setup_xattrs(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { char buff[512]; char *list, *p; @@ -723,8 +775,22 @@ setup_xattrs(struct archive_read_disk *a, if (path == NULL) path = archive_entry_pathname(entry); - if (fd >= 0) - list_size = extattr_list_fd(fd, namespace, NULL, 0); + if (*fd < 0 && a->tree != NULL) { + if (a->follow_symlinks || + archive_entry_filetype(entry) != AE_IFLNK) + *fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK); + if (*fd < 0) { + if (a->tree_enter_working_dir(a->tree) != 0) { + archive_set_error(&a->archive, errno, + "Couldn't access %s", path); + return (ARCHIVE_FAILED); + } + } + } + + if (*fd >= 0) + list_size = extattr_list_fd(*fd, namespace, NULL, 0); else if (!a->follow_symlinks) list_size = extattr_list_link(path, namespace, NULL, 0); else @@ -746,8 +812,8 @@ setup_xattrs(struct archive_read_disk *a, return (ARCHIVE_FATAL); } - if (fd >= 0) - list_size = extattr_list_fd(fd, namespace, list, list_size); + if (*fd >= 0) + list_size = extattr_list_fd(*fd, namespace, list, list_size); else if (!a->follow_symlinks) list_size = extattr_list_link(path, namespace, list, list_size); else @@ -769,7 +835,7 @@ setup_xattrs(struct archive_read_disk *a, name = buff + strlen(buff); memcpy(name, p + 1, len); name[len] = '\0'; - setup_xattr(a, entry, namespace, name, buff, fd); + setup_xattr(a, entry, namespace, name, buff, *fd); p += 1 + len; } @@ -784,7 +850,7 @@ setup_xattrs(struct archive_read_disk *a, */ static int setup_xattrs(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { (void)a; /* UNUSED */ (void)entry; /* UNUSED */ @@ -813,14 +879,13 @@ setup_xattrs(struct archive_read_disk *a, static int setup_sparse(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { char buff[4096]; struct fiemap *fm; struct fiemap_extent *fe; int64_t size; int count, do_fiemap; - int initial_fd = fd; int exit_sts = ARCHIVE_OK; if (archive_entry_filetype(entry) != AE_IFREG @@ -828,14 +893,18 @@ setup_sparse(struct archive_read_disk *a, || archive_entry_hardlink(entry) != NULL) return (ARCHIVE_OK); - if (fd < 0) { + if (*fd < 0) { const char *path; path = archive_entry_sourcepath(entry); if (path == NULL) path = archive_entry_pathname(entry); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) { + if (a->tree != NULL) + *fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK); + else + *fd = open(path, O_RDONLY | O_NONBLOCK); + if (*fd < 0) { archive_set_error(&a->archive, errno, "Can't open `%s'", path); return (ARCHIVE_FAILED); @@ -853,18 +922,11 @@ setup_sparse(struct archive_read_disk *a, for (;;) { int i, r; - r = ioctl(fd, FS_IOC_FIEMAP, fm); + r = ioctl(*fd, FS_IOC_FIEMAP, fm); if (r < 0) { - /* When errno is ENOTTY, it is better we should - * return ARCHIVE_OK because an earlier version - *(<2.6.28) cannot perfom FS_IOC_FIEMAP. - * We should also check if errno is EOPNOTSUPP, - * it means "Operation not supported". */ - if (errno != ENOTTY && errno != EOPNOTSUPP) { - archive_set_error(&a->archive, errno, - "FIEMAP failed"); - exit_sts = ARCHIVE_FAILED; - } + /* When something error happens, it is better we + * should return ARCHIVE_OK because an earlier + * version(<2.6.28) cannot perfom FS_IOC_FIEMAP. */ goto exit_setup_sparse; } if (fm->fm_mapped_extents == 0) @@ -896,8 +958,6 @@ setup_sparse(struct archive_read_disk *a, break; } exit_setup_sparse: - if (initial_fd != fd) - close(fd); return (exit_sts); } @@ -909,10 +969,9 @@ exit_setup_sparse: static int setup_sparse(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { int64_t size; - int initial_fd = fd; off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */ off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */ int exit_sts = ARCHIVE_OK; @@ -923,22 +982,38 @@ setup_sparse(struct archive_read_disk *a, return (ARCHIVE_OK); /* Does filesystem support the reporting of hole ? */ - if (fd >= 0) { - if (fpathconf(fd, _PC_MIN_HOLE_SIZE) <= 0) + if (*fd < 0 && a->tree != NULL) { + const char *path; + + path = archive_entry_sourcepath(entry); + if (path == NULL) + path = archive_entry_pathname(entry); + *fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK); + if (*fd < 0) { + archive_set_error(&a->archive, errno, + "Can't open `%s'", path); + return (ARCHIVE_FAILED); + } + } + + if (*fd >= 0) { + if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0) return (ARCHIVE_OK); - initial_off = lseek(fd, 0, SEEK_CUR); + initial_off = lseek(*fd, 0, SEEK_CUR); if (initial_off != 0) - lseek(fd, 0, SEEK_SET); + lseek(*fd, 0, SEEK_SET); } else { const char *path; path = archive_entry_sourcepath(entry); if (path == NULL) path = archive_entry_pathname(entry); + if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0) return (ARCHIVE_OK); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) { + *fd = open(path, O_RDONLY | O_NONBLOCK); + if (*fd < 0) { archive_set_error(&a->archive, errno, "Can't open `%s'", path); return (ARCHIVE_FAILED); @@ -949,7 +1024,7 @@ setup_sparse(struct archive_read_disk *a, off_s = 0; size = archive_entry_size(entry); while (off_s < size) { - off_s = lseek(fd, off_s, SEEK_DATA); + off_s = lseek(*fd, off_s, SEEK_DATA); if (off_s == (off_t)-1) { if (errno == ENXIO) break;/* no more hole */ @@ -958,10 +1033,10 @@ setup_sparse(struct archive_read_disk *a, exit_sts = ARCHIVE_FAILED; goto exit_setup_sparse; } - off_e = lseek(fd, off_s, SEEK_HOLE); - if (off_s == (off_t)-1) { + off_e = lseek(*fd, off_s, SEEK_HOLE); + if (off_e == (off_t)-1) { if (errno == ENXIO) { - off_e = lseek(fd, 0, SEEK_END); + off_e = lseek(*fd, 0, SEEK_END); if (off_e != (off_t)-1) break;/* no more data */ } @@ -977,10 +1052,7 @@ setup_sparse(struct archive_read_disk *a, off_s = off_e; } exit_setup_sparse: - if (initial_fd != fd) - close(fd); - else - lseek(fd, initial_off, SEEK_SET); + lseek(*fd, initial_off, SEEK_SET); return (exit_sts); } @@ -991,7 +1063,7 @@ exit_setup_sparse: */ static int setup_sparse(struct archive_read_disk *a, - struct archive_entry *entry, int fd) + struct archive_entry *entry, int *fd) { (void)a; /* UNUSED */ (void)entry; /* UNUSED */ diff --git a/contrib/libarchive/libarchive/archive_read_disk_posix.c b/contrib/libarchive/libarchive/archive_read_disk_posix.c index cf8f311..4623901 100644 --- a/contrib/libarchive/libarchive/archive_read_disk_posix.c +++ b/contrib/libarchive/libarchive/archive_read_disk_posix.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 2003-2009 Tim Kientzle - * Copyright (c) 2010,2011 Michihiro NAKAJIMA + * Copyright (c) 2010-2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,6 +52,19 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_LINUX_MAGIC_H #include <linux/magic.h> #endif +#ifdef HAVE_LINUX_FS_H +#include <linux/fs.h> +#endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include <linux/ext2_fs.h> /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ +#endif #ifdef HAVE_DIRECT_H #include <direct.h> #endif @@ -76,6 +89,9 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif #include "archive.h" #include "archive_string.h" @@ -222,6 +238,7 @@ struct tree { char symlink_mode; struct filesystem *current_filesystem; struct filesystem *filesystem_table; + int initial_filesystem_id; int current_filesystem_id; int max_filesystem_id; int allocated_filesytem; @@ -240,6 +257,7 @@ struct tree { #define onWorkingDir 64 /* We are on the working dir where we are * reading directory entry at this time. */ #define needsRestoreTimes 128 +#define onInitialDir 256 /* We are on the initial dir. */ static int tree_dir_next_posix(struct tree *t); @@ -342,6 +360,7 @@ static const char *trivial_lookup_uname(void *, int64_t uid); static int setup_sparse(struct archive_read_disk *, struct archive_entry *); static int close_and_restore_time(int fd, struct tree *, struct restore_time *); +static int open_on_current_dir(struct tree *, const char *, int); static struct archive_vtable * @@ -430,16 +449,19 @@ archive_read_disk_new(void) { struct archive_read_disk *a; - a = (struct archive_read_disk *)malloc(sizeof(*a)); + a = (struct archive_read_disk *)calloc(1, sizeof(*a)); if (a == NULL) return (NULL); - memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_READ_DISK_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; a->archive.vtable = archive_read_disk_vtable(); a->lookup_uname = trivial_lookup_uname; a->lookup_gname = trivial_lookup_gname; - a->entry_wd_fd = -1; + a->enable_copyfile = 1; + a->traverse_mount_points = 1; + a->open_on_current_dir = open_on_current_dir; + a->tree_current_dir_fd = tree_current_dir_fd; + a->tree_enter_working_dir = tree_enter_working_dir; return (&a->archive); } @@ -555,6 +577,37 @@ archive_read_disk_set_atime_restored(struct archive *_a) #endif } +int +archive_read_disk_set_behavior(struct archive *_a, int flags) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + int r = ARCHIVE_OK; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump"); + + if (flags & ARCHIVE_READDISK_RESTORE_ATIME) + r = archive_read_disk_set_atime_restored(_a); + else { + a->restore_time = 0; + if (a->tree != NULL) + a->tree->flags &= ~needsRestoreTimes; + } + if (flags & ARCHIVE_READDISK_HONOR_NODUMP) + a->honor_nodump = 1; + else + a->honor_nodump = 0; + if (flags & ARCHIVE_READDISK_MAC_COPYFILE) + a->enable_copyfile = 1; + else + a->enable_copyfile = 0; + if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) + a->traverse_mount_points = 0; + else + a->traverse_mount_points = 1; + return (r); +} + /* * Trivial implementations of gname/uname lookup functions. * These are normally overridden by the client, but these stub @@ -685,13 +738,8 @@ _archive_read_data_block(struct archive *_a, const void **buff, flags |= O_NOATIME; do { #endif -#ifdef HAVE_OPENAT - t->entry_fd = openat(tree_current_dir_fd(t), + t->entry_fd = open_on_current_dir(t, tree_current_access_path(t), flags); -#else - tree_enter_working_dir(t); - t->entry_fd = open(tree_current_access_path(t), flags); -#endif #if defined(O_NOATIME) /* * When we did open the file with O_NOATIME flag, @@ -802,29 +850,17 @@ abort_read_data: } static int -_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) +next_entry(struct archive_read_disk *a, struct tree *t, + struct archive_entry *entry) { - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t; const struct stat *st; /* info to use for this entry */ const struct stat *lst;/* lstat() information */ - int descend, fd = -1, r; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_next_header2"); + const char *name; + int descend, r; - t = a->tree; - if (t->entry_fd >= 0) { - close_and_restore_time(t->entry_fd, t, &t->restore_time); - t->entry_fd = -1; - } -#if !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)) - /* Restore working directory. */ - tree_enter_working_dir(t); -#endif st = NULL; lst = NULL; + t->descend = 0; do { switch (tree_next(t)) { case TREE_ERROR_FATAL: @@ -859,6 +895,38 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry) } } while (lst == NULL); +#ifdef __APPLE__ + if (a->enable_copyfile) { + /* If we're using copyfile(), ignore "._XXX" files. */ + const char *bname = strrchr(tree_current_path(t), '/'); + if (bname == NULL) + bname = tree_current_path(t); + else + ++bname; + if (bname[0] == '.' && bname[1] == '_') + return (ARCHIVE_RETRY); + } +#endif + + archive_entry_copy_pathname(entry, tree_current_path(t)); + /* + * Perform path matching. + */ + if (a->matching) { + r = archive_match_path_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Faild : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + /* * Distinguish 'L'/'P'/'H' symlink following. */ @@ -897,13 +965,44 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry) tree_enter_initial_dir(t); return (ARCHIVE_FATAL); } + if (t->initial_filesystem_id == -1) + t->initial_filesystem_id = t->current_filesystem_id; + if (!a->traverse_mount_points) { + if (t->initial_filesystem_id != t->current_filesystem_id) + return (ARCHIVE_RETRY); + } t->descend = descend; - archive_entry_set_pathname(entry, tree_current_path(t)); - archive_entry_copy_sourcepath(entry, tree_current_access_path(t)); + /* + * Honor nodump flag. + * If the file is marked with nodump flag, do not return this entry. + */ + if (a->honor_nodump) { +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + if (st->st_flags & UF_NODUMP) + return (ARCHIVE_RETRY); +#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\ + defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) + if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) { + unsigned long stflags; + + t->entry_fd = open_on_current_dir(t, + tree_current_access_path(t), O_RDONLY | O_NONBLOCK); + if (t->entry_fd >= 0) { + r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS, + &stflags); + if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0) + return (ARCHIVE_RETRY); + } + } +#endif + } + archive_entry_copy_stat(entry, st); - /* Save the times to be restored. */ + /* Save the times to be restored. This must be in before + * calling archive_read_disk_descend() or any chance of it, + * especially, invokng a callback. */ t->restore_time.mtime = archive_entry_mtime(entry); t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry); t->restore_time.atime = archive_entry_atime(entry); @@ -911,39 +1010,102 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry) t->restore_time.filetype = archive_entry_filetype(entry); t->restore_time.noatime = t->current_filesystem->noatime; -#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) /* - * Open the current file to freely gather its metadata anywhere in - * working directory. - * Note: A symbolic link file cannot be opened with O_NOFOLLOW. + * Perform time matching. */ - if (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK) - fd = openat(tree_current_dir_fd(t), tree_current_access_path(t), - O_RDONLY | O_NONBLOCK); - /* Restore working directory if openat() operation failed or - * the file is a symbolic link. */ - if (fd < 0) - tree_enter_working_dir(t); + if (a->matching) { + r = archive_match_time_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Faild : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } - /* The current direcotry fd is needed at - * archive_read_disk_entry_from_file() function to read link data - * with readlinkat(). */ - a->entry_wd_fd = tree_current_dir_fd(t); -#endif + /* Lookup uname/gname */ + name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry)); + if (name != NULL) + archive_entry_copy_uname(entry, name); + name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry)); + if (name != NULL) + archive_entry_copy_gname(entry, name); + + /* + * Perform owner matching. + */ + if (a->matching) { + r = archive_match_owner_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Faild : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + + /* + * Invoke a meta data filter callback. + */ + if (a->metadata_filter_func) { + if (!a->metadata_filter_func(&(a->archive), + a->metadata_filter_data, entry)) + return (ARCHIVE_RETRY); + } /* * Populate the archive_entry with metadata from the disk. */ - r = archive_read_disk_entry_from_file(&(a->archive), entry, fd, st); + archive_entry_copy_sourcepath(entry, tree_current_access_path(t)); + r = archive_read_disk_entry_from_file(&(a->archive), entry, + t->entry_fd, st); - /* Close the file descriptor used for reding the current file - * metadata at archive_read_disk_entry_from_file(). */ - if (fd >= 0) - close(fd); + return (r); +} + +static int +_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t; + int r; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_next_header2"); + + t = a->tree; + if (t->entry_fd >= 0) { + close_and_restore_time(t->entry_fd, t, &t->restore_time); + t->entry_fd = -1; + } + + for (;;) { + r = next_entry(a, t, entry); + if (t->entry_fd >= 0) { + close(t->entry_fd); + t->entry_fd = -1; + } + + if (r == ARCHIVE_RETRY) { + archive_entry_clear(entry); + continue; + } + break; + } /* Return to the initial directory. */ tree_enter_initial_dir(t); - archive_entry_copy_sourcepath(entry, tree_current_path(t)); /* * EOF and FATAL are persistent at this layer. By @@ -956,6 +1118,8 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry) break; case ARCHIVE_OK: case ARCHIVE_WARN: + /* Overwrite the sourcepath based on the initial directory. */ + archive_entry_copy_sourcepath(entry, tree_current_path(t)); t->entry_total = 0; if (archive_entry_filetype(entry) == AE_IFREG) { t->nlink = archive_entry_nlink(entry); @@ -1018,6 +1182,48 @@ setup_sparse(struct archive_read_disk *a, struct archive_entry *entry) return (ARCHIVE_OK); } +int +archive_read_disk_set_matching(struct archive *_a, struct archive *_ma, + void (*_excluded_func)(struct archive *, void *, struct archive_entry *), + void *_client_data) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_matching"); + a->matching = _ma; + a->excluded_cb_func = _excluded_func; + a->excluded_cb_data = _client_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_metadata_filter_callback(struct archive *_a, + int (*_metadata_filter_func)(struct archive *, void *, + struct archive_entry *), void *_client_data) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, + "archive_read_disk_set_metadata_filter_callback"); + + a->metadata_filter_func = _metadata_filter_func; + a->metadata_filter_data = _client_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_can_descend(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t = a->tree; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_disk_can_descend"); + + return (t->visit_type == TREE_REGULAR && t->descend); +} + /* * Called by the client to mark the directory just returned from * tree_next() as needing to be visited. @@ -1028,14 +1234,12 @@ archive_read_disk_descend(struct archive *_a) struct archive_read_disk *a = (struct archive_read_disk *)_a; struct tree *t = a->tree; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_disk_descend"); - if (t->visit_type != TREE_REGULAR || !t->descend) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Ignored the request descending the current object"); - return (ARCHIVE_WARN); - } + if (t->visit_type != TREE_REGULAR || !t->descend) + return (ARCHIVE_OK); if (tree_current_is_physical_dir(t)) { tree_push(t, t->basename, t->current_filesystem_id, @@ -1079,8 +1283,12 @@ archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) archive_string_init(&path); if (archive_string_append_from_wcs(&path, pathname, wcslen(pathname)) != 0) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Can't convert a path to a char string"); + if (errno == ENOMEM) + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can't convert a path to a char string"); a->archive.state = ARCHIVE_STATE_FATAL; ret = ARCHIVE_FATAL; } else @@ -1268,7 +1476,7 @@ setup_current_filesystem(struct archive_read_disk *a) t->current_filesystem->synthetic = -1; t->current_filesystem->remote = -1; if (tree_current_is_symblic_link_target(t)) { -#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) +#if defined(HAVE_OPENAT) /* * Get file system statistics on any directory * where current is. @@ -1285,6 +1493,10 @@ setup_current_filesystem(struct archive_read_disk *a) xr = get_xfer_size(t, fd, NULL); close(fd); #else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } r = statfs(tree_current_access_path(t), &sfs); if (r == 0) xr = get_xfer_size(t, -1, tree_current_access_path(t)); @@ -1334,9 +1546,13 @@ setup_current_filesystem(struct archive_read_disk *a) t->current_filesystem->name_max = sfs.f_namemax; #else /* Mac OS X does not have f_namemax in struct statfs. */ - if (tree_current_is_symblic_link_target(t)) + if (tree_current_is_symblic_link_target(t)) { + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); - else + } else nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); if (nm == -1) t->current_filesystem->name_max = NAME_MAX; @@ -1360,6 +1576,10 @@ setup_current_filesystem(struct archive_read_disk *a) int r, xr = 0; t->current_filesystem->synthetic = -1; + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } if (tree_current_is_symblic_link_target(t)) { r = statvfs(tree_current_access_path(t), &sfs); if (r == 0) @@ -1384,17 +1604,24 @@ setup_current_filesystem(struct archive_read_disk *a) * for pathconf() function. */ t->current_filesystem->xfer_align = sfs.f_frsize; t->current_filesystem->max_xfer_size = -1; +#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE) t->current_filesystem->min_xfer_size = sfs.f_iosize; t->current_filesystem->incr_xfer_size = sfs.f_iosize; +#else + t->current_filesystem->min_xfer_size = sfs.f_bsize; + t->current_filesystem->incr_xfer_size = sfs.f_bsize; +#endif } if (sfs.f_flag & ST_LOCAL) t->current_filesystem->remote = 0; else t->current_filesystem->remote = 1; +#if defined(ST_NOATIME) if (sfs.f_flag & ST_NOATIME) t->current_filesystem->noatime = 1; else +#endif t->current_filesystem->noatime = 0; /* Set maximum filename length. */ @@ -1427,7 +1654,7 @@ setup_current_filesystem(struct archive_read_disk *a) int r, vr = 0, xr = 0; if (tree_current_is_symblic_link_target(t)) { -#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) +#if defined(HAVE_OPENAT) /* * Get file system statistics on any directory * where current is. @@ -1445,6 +1672,10 @@ setup_current_filesystem(struct archive_read_disk *a) xr = get_xfer_size(t, fd, NULL); close(fd); #else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } vr = statvfs(tree_current_access_path(t), &svfs); r = statfs(tree_current_access_path(t), &sfs); if (r == 0) @@ -1456,9 +1687,11 @@ setup_current_filesystem(struct archive_read_disk *a) r = fstatfs(tree_current_dir_fd(t), &sfs); if (r == 0) xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); -#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) -#error "Unexpected case. Please tell us about this error." #else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } vr = statvfs(".", &svfs); r = statfs(".", &sfs); if (r == 0) @@ -1529,7 +1762,7 @@ setup_current_filesystem(struct archive_read_disk *a) t->current_filesystem->synthetic = -1;/* Not supported */ t->current_filesystem->remote = -1;/* Not supported */ if (tree_current_is_symblic_link_target(t)) { -#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) +#if defined(HAVE_OPENAT) /* * Get file system statistics on any directory * where current is. @@ -1546,6 +1779,10 @@ setup_current_filesystem(struct archive_read_disk *a) xr = get_xfer_size(t, fd, NULL); close(fd); #else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } r = statvfs(tree_current_access_path(t), &sfs); if (r == 0) xr = get_xfer_size(t, -1, tree_current_access_path(t)); @@ -1555,9 +1792,11 @@ setup_current_filesystem(struct archive_read_disk *a) r = fstatvfs(tree_current_dir_fd(t), &sfs); if (r == 0) xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); -#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) -#error "Unexpected case. Please tell us about this error." #else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } r = statvfs(".", &sfs); if (r == 0) xr = get_xfer_size(t, -1, "."); @@ -1615,9 +1854,13 @@ setup_current_filesystem(struct archive_read_disk *a) #if defined(HAVE_READDIR_R) /* Set maximum filename length. */ # if defined(_PC_NAME_MAX) - if (tree_current_is_symblic_link_target(t)) + if (tree_current_is_symblic_link_target(t)) { + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); - else + } else nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); if (nm == -1) # endif /* _PC_NAME_MAX */ @@ -1697,6 +1940,18 @@ close_and_restore_time(int fd, struct tree *t, struct restore_time *rt) return (0); } +static int +open_on_current_dir(struct tree *t, const char *path, int flags) +{ +#ifdef HAVE_OPENAT + return (openat(tree_current_dir_fd(t), path, flags)); +#else + if (tree_enter_working_dir(t) != 0) + return (-1); + return (open(path, flags)); +#endif +} + /* * Add a directory path to the current stack. */ @@ -1778,6 +2033,7 @@ static struct tree * tree_reopen(struct tree *t, const char *path, int restore_time) { t->flags = (restore_time)?needsRestoreTimes:0; + t->flags |= onInitialDir; t->visit_type = 0; t->tree_errno = 0; t->dirname_length = 0; @@ -1790,6 +2046,7 @@ tree_reopen(struct tree *t, const char *path, int restore_time) t->entry_fd = -1; t->entry_eof = 0; t->entry_remaining_bytes = 0; + t->initial_filesystem_id = -1; /* First item is set up a lot like a symlink traversal. */ tree_push(t, path, 0, 0, 0, NULL); @@ -1803,12 +2060,14 @@ tree_reopen(struct tree *t, const char *path, int restore_time) static int tree_descent(struct tree *t) { - int r = 0; + int flag, new_fd, r = 0; -#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) - int new_fd; t->dirname_length = archive_strlen(&t->path); - new_fd = openat(t->working_dir_fd, t->stack->name.s, O_RDONLY); + flag = O_RDONLY; +#if defined(O_DIRECTORY) + flag |= O_DIRECTORY; +#endif + new_fd = open_on_current_dir(t, t->stack->name.s, flag); if (new_fd < 0) { t->tree_errno = errno; r = TREE_ERROR_DIR; @@ -1822,30 +2081,10 @@ tree_descent(struct tree *t) t->maxOpenCount = t->openCount; } else close(t->working_dir_fd); + /* Renew the current working directory. */ t->working_dir_fd = new_fd; + t->flags &= ~onWorkingDir; } -#else - /* If it is a link, set up fd for the ascent. */ - if (t->stack->flags & isDirLink) - t->stack->symlink_parent_fd = t->working_dir_fd; - else { - close(t->working_dir_fd); - t->openCount--; - } - t->working_dir_fd = -1; - t->dirname_length = archive_strlen(&t->path); - if (chdir(t->stack->name.s) != 0) - { - t->tree_errno = errno; - r = TREE_ERROR_DIR; - } else { - t->depth++; - t->working_dir_fd = open(".", O_RDONLY); - t->openCount++; - if (t->openCount > t->maxOpenCount) - t->maxOpenCount = t->openCount; - } -#endif return (r); } @@ -1856,37 +2095,21 @@ static int tree_ascend(struct tree *t) { struct tree_entry *te; - int r = 0, prev_dir_fd; + int new_fd, r = 0, prev_dir_fd; te = t->stack; prev_dir_fd = t->working_dir_fd; -#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR) if (te->flags & isDirLink) - t->working_dir_fd = te->symlink_parent_fd; - else { - int new_fd = openat(t->working_dir_fd, "..", O_RDONLY); - if (new_fd < 0) { - t->tree_errno = errno; - r = TREE_ERROR_FATAL; - } else - t->working_dir_fd = new_fd; - } -#else - if (te->flags & isDirLink) { - if (fchdir(te->symlink_parent_fd) != 0) { - t->tree_errno = errno; - r = TREE_ERROR_FATAL; - } else - t->working_dir_fd = te->symlink_parent_fd; + new_fd = te->symlink_parent_fd; + else + new_fd = open_on_current_dir(t, "..", O_RDONLY); + if (new_fd < 0) { + t->tree_errno = errno; + r = TREE_ERROR_FATAL; } else { - if (chdir("..") != 0) { - t->tree_errno = errno; - r = TREE_ERROR_FATAL; - } else - t->working_dir_fd = open(".", O_RDONLY); - } -#endif - if (r == 0) { + /* Renew the current working directory. */ + t->working_dir_fd = new_fd; + t->flags &= ~onWorkingDir; /* Current directory has been changed, we should * close an fd of previous working directory. */ close_and_restore_time(prev_dir_fd, t, &te->restore_time); @@ -1907,10 +2130,12 @@ tree_enter_initial_dir(struct tree *t) { int r = 0; - if (t->flags & onWorkingDir) { + if ((t->flags & onInitialDir) == 0) { r = fchdir(t->initial_dir_fd); - if (r == 0) + if (r == 0) { t->flags &= ~onWorkingDir; + t->flags |= onInitialDir; + } } return (r); } @@ -1930,8 +2155,10 @@ tree_enter_working_dir(struct tree *t) */ if (t->depth > 0 && (t->flags & onWorkingDir) == 0) { r = fchdir(t->working_dir_fd); - if (r == 0) + if (r == 0) { + t->flags &= ~onInitialDir; t->flags |= onWorkingDir; + } } return (r); } @@ -2040,7 +2267,8 @@ tree_dir_next_posix(struct tree *t) #if defined(HAVE_FDOPENDIR) if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) { #else - if ((t->d = opendir(".")) == NULL) { + if (tree_enter_working_dir(t) != 0 || + (t->d = opendir(".")) == NULL) { #endif r = tree_ascend(t); /* Undo "chdir" */ tree_pop(t); @@ -2111,6 +2339,8 @@ tree_current_stat(struct tree *t) if (fstatat(tree_current_dir_fd(t), tree_current_access_path(t), &t->st, 0) != 0) #else + if (tree_enter_working_dir(t) != 0) + return NULL; if (stat(tree_current_access_path(t), &t->st) != 0) #endif return NULL; @@ -2131,6 +2361,8 @@ tree_current_lstat(struct tree *t) tree_current_access_path(t), &t->lst, AT_SYMLINK_NOFOLLOW) != 0) #else + if (tree_enter_working_dir(t) != 0) + return NULL; if (lstat(tree_current_access_path(t), &t->lst) != 0) #endif return NULL; @@ -2152,7 +2384,10 @@ tree_current_is_dir(struct tree *t) */ if (t->flags & hasLstat) { /* If lstat() says it's a dir, it must be a dir. */ - if (S_ISDIR(tree_current_lstat(t)->st_mode)) + st = tree_current_lstat(t); + if (st == NULL) + return 0; + if (S_ISDIR(st->st_mode)) return 1; /* Not a dir; might be a link to a dir. */ /* If it's not a link, then it's not a link to a dir. */ @@ -2186,9 +2421,13 @@ tree_current_is_physical_dir(struct tree *t) * If stat() says it isn't a dir, then it's not a dir. * If stat() data is cached, this check is free, so do it first. */ - if ((t->flags & hasStat) - && (!S_ISDIR(tree_current_stat(t)->st_mode))) - return 0; + if (t->flags & hasStat) { + st = tree_current_stat(t); + if (st == NULL) + return (0); + if (!S_ISDIR(st->st_mode)) + return (0); + } /* * Either stat() said it was a dir (in which case, we have @@ -2232,7 +2471,7 @@ tree_current_is_symblic_link_target(struct tree *t) lst = tree_current_lstat(t); st = tree_current_stat(t); - return (st != NULL && + return (st != NULL && lst != NULL && (int64_t)st->st_dev == t->current_filesystem->dev && st->st_dev != lst->st_dev); } diff --git a/contrib/libarchive/libarchive/archive_read_disk_private.h b/contrib/libarchive/libarchive/archive_read_disk_private.h index 445e88f..bba8a0a 100644 --- a/contrib/libarchive/libarchive/archive_read_disk_private.h +++ b/contrib/libarchive/libarchive/archive_read_disk_private.h @@ -34,6 +34,7 @@ #define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED struct tree; +struct archive_entry; struct archive_read_disk { struct archive archive; @@ -55,10 +56,18 @@ struct archive_read_disk { /* Directory traversals. */ struct tree *tree; + int (*open_on_current_dir)(struct tree*, const char *, int); + int (*tree_current_dir_fd)(struct tree*); + int (*tree_enter_working_dir)(struct tree*); /* Set 1 if users request to restore atime . */ int restore_time; - int entry_wd_fd; + /* Set 1 if users request to honor nodump flag . */ + int honor_nodump; + /* Set 1 if users request to enable mac copyfile. */ + int enable_copyfile; + /* Set 1 if users request to traverse mount points. */ + int traverse_mount_points; const char * (*lookup_gname)(void *private, int64_t gid); void (*cleanup_gname)(void *private); @@ -66,6 +75,18 @@ struct archive_read_disk { const char * (*lookup_uname)(void *private, int64_t uid); void (*cleanup_uname)(void *private); void *lookup_uname_data; + + int (*metadata_filter_func)(struct archive *, void *, + struct archive_entry *); + void *metadata_filter_data; + + /* ARCHIVE_MATCH object. */ + struct archive *matching; + /* Callback function, this will be invoked when ARCHIVE_MATCH + * archive_match_*_excluded_ae return true. */ + void (*excluded_cb_func)(struct archive *, void *, + struct archive_entry *); + void *excluded_cb_data; }; #endif diff --git a/contrib/libarchive/libarchive/archive_read_extract.3 b/contrib/libarchive/libarchive/archive_read_extract.3 index 882c6e1..6ec0ced 100644 --- a/contrib/libarchive/libarchive/archive_read_extract.3 +++ b/contrib/libarchive/libarchive/archive_read_extract.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 22, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_EXTRACT 3 .Os .Sh NAME @@ -32,6 +32,8 @@ .Nm archive_read_extract2 , .Nm archive_read_extract_set_progress_callback .Nd functions for reading streaming archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_read_filter.3 b/contrib/libarchive/libarchive/archive_read_filter.3 index 1cfa215..8761127 100644 --- a/contrib/libarchive/libarchive/archive_read_filter.3 +++ b/contrib/libarchive/libarchive/archive_read_filter.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 19, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_FILTER 3 .Os .Sh NAME @@ -39,6 +39,8 @@ .Nm archive_read_support_filter_program_signature .Nd functions for reading streaming archives .\" +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_read_format.3 b/contrib/libarchive/libarchive/archive_read_format.3 index e707e05..53b9a7e 100644 --- a/contrib/libarchive/libarchive/archive_read_format.3 +++ b/contrib/libarchive/libarchive/archive_read_format.3 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $ +.\" $FreeBSD$ .\" -.Dd March 19, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_FORMAT 3 .Os .Sh NAME @@ -45,6 +45,8 @@ .Nm archive_read_support_format_zip .Nd functions for reading streaming archives .\" +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_read_free.3 b/contrib/libarchive/libarchive/archive_read_free.3 index f5f2515..5b21822 100644 --- a/contrib/libarchive/libarchive/archive_read_free.3 +++ b/contrib/libarchive/libarchive/archive_read_free.3 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $ +.\" $FreeBSD$ .\" -.Dd March 20, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_FREE 3 .Os .Sh NAME @@ -32,6 +32,8 @@ .Nm archive_read_finish , .Nm archive_read_free .Nd functions for reading streaming archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_read_header.3 b/contrib/libarchive/libarchive/archive_read_header.3 index 999e963..480a666 100644 --- a/contrib/libarchive/libarchive/archive_read_header.3 +++ b/contrib/libarchive/libarchive/archive_read_header.3 @@ -24,13 +24,15 @@ .\" .\" $FreeBSD$ .\" -.Dd March 22, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_HEADER 3 .Os .Sh NAME .Nm archive_read_next_header , .Nm archive_read_next_header2 .Nd functions for reading streaming archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_read_new.3 b/contrib/libarchive/libarchive/archive_read_new.3 index e04406a..0c9d1a7 100644 --- a/contrib/libarchive/libarchive/archive_read_new.3 +++ b/contrib/libarchive/libarchive/archive_read_new.3 @@ -22,14 +22,16 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $ +.\" $FreeBSD$ .\" -.Dd March 20, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_NEW 3 .Os .Sh NAME .Nm archive_read_new .Nd functions for reading streaming archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft struct archive * diff --git a/contrib/libarchive/libarchive/archive_read_open.3 b/contrib/libarchive/libarchive/archive_read_open.3 index 09c0575..30a740b 100644 --- a/contrib/libarchive/libarchive/archive_read_open.3 +++ b/contrib/libarchive/libarchive/archive_read_open.3 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $ +.\" $FreeBSD$ .\" -.Dd March 19, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_READ_OPEN 3 .Os .Sh NAME @@ -35,6 +35,8 @@ .Nm archive_read_open_filename , .Nm archive_read_open_memory , .Nd functions for reading streaming archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_read_open_fd.c b/contrib/libarchive/libarchive/archive_read_open_fd.c index ada21c2..d8f112f 100644 --- a/contrib/libarchive/libarchive/archive_read_open_fd.c +++ b/contrib/libarchive/libarchive/archive_read_open_fd.c @@ -129,8 +129,8 @@ static int64_t file_skip(struct archive *a, void *client_data, int64_t request) { struct read_fd_data *mine = (struct read_fd_data *)client_data; - off_t skip = (off_t)request; - off_t old_offset, new_offset; + int64_t skip = request; + int64_t old_offset, new_offset; int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */ if (!mine->use_lseek) diff --git a/contrib/libarchive/libarchive/archive_read_open_filename.c b/contrib/libarchive/libarchive/archive_read_open_filename.c index 8af0b20..0727070 100644 --- a/contrib/libarchive/libarchive/archive_read_open_filename.c +++ b/contrib/libarchive/libarchive/archive_read_open_filename.c @@ -130,9 +130,13 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename, archive_string_init(&fn); if (archive_string_append_from_wcs(&fn, wfilename, wcslen(wfilename)) != 0) { - archive_set_error(a, EINVAL, - "Failed to convert a wide-character filename to" - " a multi-byte filename"); + if (errno == ENOMEM) + archive_set_error(a, errno, + "Can't allocate memory"); + else + archive_set_error(a, EINVAL, + "Failed to convert a wide-character" + " filename to a multi-byte filename"); archive_string_free(&fn); return (ARCHIVE_FATAL); } @@ -450,7 +454,7 @@ static int64_t file_seek(struct archive *a, void *client_data, int64_t request, int whence) { struct read_file_data *mine = (struct read_file_data *)client_data; - off_t r; + int64_t r; /* We use off_t here because lseek() is declared that way. */ /* See above for notes about when off_t is less than 64 bits. */ diff --git a/contrib/libarchive/libarchive/archive_read_private.h b/contrib/libarchive/libarchive/archive_read_private.h index 2938d64..77aca36 100644 --- a/contrib/libarchive/libarchive/archive_read_private.h +++ b/contrib/libarchive/libarchive/archive_read_private.h @@ -134,8 +134,8 @@ struct archive_read { /* Dev/ino of the archive being read/written. */ int skip_file_set; - dev_t skip_file_dev; - ino_t skip_file_ino; + int64_t skip_file_dev; + int64_t skip_file_ino; /* * Used by archive_read_data() to track blocks and copy diff --git a/contrib/libarchive/libarchive/archive_read_set_options.3 b/contrib/libarchive/libarchive/archive_read_set_options.3 index 81efb08..6fe9f90 100644 --- a/contrib/libarchive/libarchive/archive_read_set_options.3 +++ b/contrib/libarchive/libarchive/archive_read_set_options.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 13, 2009 +.Dd February 2, 2012 .Dt ARCHIVE_READ_OPTIONS 3 .Os .Sh NAME @@ -34,6 +34,8 @@ .Nm archive_read_set_options .Nd functions controlling options for reading archives .\" +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .Ft int .Fo archive_read_set_filter_option diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c b/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c index 7dbfc0e..1b3e124 100644 --- a/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c +++ b/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c @@ -188,7 +188,7 @@ rpm_filter_read(struct archive_read_filter *self, const void **buff) if (rpm->total_in + avail_in < RPM_LEAD_SIZE) used += avail_in; else { - n = RPM_LEAD_SIZE - rpm->total_in; + n = (size_t)(RPM_LEAD_SIZE - rpm->total_in); used += n; b += n; rpm->state = ST_HEADER; diff --git a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c index c1bcd6a..39a46ed 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c @@ -580,7 +580,7 @@ archive_read_format_7zip_read_header(struct archive_read *a, free_Header(&header); if (r != ARCHIVE_OK) return (r); - zip->entries_remaining = zip->numFiles; + zip->entries_remaining = (size_t)zip->numFiles; zip->entry = zip->entries; } else { ++zip->entry; @@ -653,19 +653,24 @@ archive_read_format_7zip_read_header(struct archive_read *a, */ while (zip->entry_bytes_remaining > 0) { const void *buff; + unsigned char *mem; size_t size; int64_t offset; r = archive_read_format_7zip_read_data(a, &buff, &size, &offset); - if (r < ARCHIVE_WARN) + if (r < ARCHIVE_WARN) { + free(symname); return (r); - symname = realloc(symname, symsize + size + 1); - if (symname == NULL) { + } + mem = realloc(symname, symsize + size + 1); + if (mem == NULL) { + free(symname); archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Symname"); return (ARCHIVE_FATAL); } + symname = mem; memcpy(symname+symsize, buff, size); symsize += size; } @@ -715,7 +720,8 @@ archive_read_format_7zip_read_data(struct archive_read *a, return (ARCHIVE_EOF); } - bytes = read_stream(a, buff, zip->entry_bytes_remaining, 0); + bytes = read_stream(a, buff, + (size_t)zip->entry_bytes_remaining, 0); if (bytes < 0) return ((int)bytes); if (bytes == 0) { @@ -773,7 +779,7 @@ archive_read_format_7zip_read_data_skip(struct archive_read *a) * If the length is at the beginning, we can skip the * compressed data much more quickly. */ - bytes_skipped = skip_stream(a, zip->entry_bytes_remaining); + bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining); if (bytes_skipped < 0) return (ARCHIVE_FATAL); zip->entry_bytes_remaining = 0; @@ -1053,7 +1059,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, ff = &filters[fi]; #endif r = lzma_properties_decode(&filters[fi], NULL, - coder1->properties, coder1->propertiesSize); + coder1->properties, (size_t)coder1->propertiesSize); if (r != LZMA_OK) { set_error(a, r); return (ARCHIVE_FAILED); @@ -1441,8 +1447,8 @@ decompress(struct archive_read *a, struct _7zip *zip, } while (zip->ppstream.avail_out && (zip->ppstream.avail_in || flush_bytes)); - t_avail_in = zip->ppstream.avail_in; - t_avail_out = zip->ppstream.avail_out; + t_avail_in = (size_t)zip->ppstream.avail_in; + t_avail_out = (size_t)zip->ppstream.avail_out; break; } default: @@ -1505,6 +1511,10 @@ free_decompression(struct archive_read *a, struct _7zip *zip) { int r = ARCHIVE_OK; +#if !defined(HAVE_ZLIB_H) &&\ + !(defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)) + (void)a;/* UNUSED */ +#endif #ifdef HAVE_LZMA_H if (zip->lzstream_valid) lzma_end(&(zip->lzstream)); @@ -1671,8 +1681,8 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi) return (0); if (*p != kSize) return (-1); - pi->sizes = calloc(pi->numPackStreams, sizeof(uint64_t)); - pi->positions = calloc(pi->numPackStreams, sizeof(uint64_t)); + pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t)); + pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t)); if (pi->sizes == NULL || pi->positions == NULL) return (-1); @@ -1689,9 +1699,9 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi) if (*p == kEnd) { /* PackStreamDigests[num] are not present. */ pi->digest.defineds = - calloc(pi->numPackStreams, sizeof(*pi->digest.defineds)); + calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds)); pi->digest.digests = - calloc(pi->numPackStreams, sizeof(*pi->digest.digests)); + calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests)); if (pi->digest.defineds == NULL || pi->digest.digests == NULL) return (-1); return (0); @@ -1700,7 +1710,7 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi) if (*p != kSize) return (-1); - if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0) + if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0) return (-1); /* @@ -1749,7 +1759,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f) /* Too many coders. */ return (-1); - f->coders = calloc(f->numCoders, sizeof(*f->coders)); + f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders)); if (f->coders == NULL) return (-1); for (i = 0; i< f->numCoders; i++) { @@ -1801,14 +1811,14 @@ read_Folder(struct archive_read *a, struct _7z_folder *f) a, &(f->coders[i].propertiesSize)) < 0) return (-1); if ((p = header_bytes( - a, f->coders[i].propertiesSize)) == NULL) + a, (size_t)f->coders[i].propertiesSize)) == NULL) return (-1); f->coders[i].properties = - malloc(f->coders[i].propertiesSize); + malloc((size_t)f->coders[i].propertiesSize); if (f->coders[i].properties == NULL) return (-1); memcpy(f->coders[i].properties, p, - f->coders[i].propertiesSize); + (size_t)f->coders[i].propertiesSize); } numInStreamsTotal += f->coders[i].numInStreams; @@ -1822,9 +1832,13 @@ read_Folder(struct archive_read *a, struct _7z_folder *f) f->numBindPairs = numOutStreamsTotal - 1; if (zip->header_bytes_remaining < f->numBindPairs) return (-1); - f->bindPairs = calloc(f->numBindPairs, sizeof(*f->bindPairs)); - if (f->bindPairs == NULL) - return (-1); + if (f->numBindPairs > 0) { + f->bindPairs = + calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs)); + if (f->bindPairs == NULL) + return (-1); + } else + f->bindPairs = NULL; for (i = 0; i < f->numBindPairs; i++) { if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0) return (-1); @@ -1838,7 +1852,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f) f->numPackedStreams = numInStreamsTotal - f->numBindPairs; f->packedStreams = - calloc(f->numPackedStreams, sizeof(*f->packedStreams)); + calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams)); if (f->packedStreams == NULL) return (-1); if (f->numPackedStreams == 1) { @@ -1910,7 +1924,8 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci) goto failed; switch (*p) { case 0: - ci->folders = calloc(ci->numFolders, sizeof(*ci->folders)); + ci->folders = + calloc((size_t)ci->numFolders, sizeof(*ci->folders)); if (ci->folders == NULL) return (-1); for (i = 0; i < ci->numFolders; i++) { @@ -1936,7 +1951,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci) unsigned j; folder->unPackSize = - calloc(folder->numOutStreams, sizeof(*folder->unPackSize)); + calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize)); if (folder->unPackSize == NULL) goto failed; for (j = 0; j < folder->numOutStreams; j++) { @@ -1954,7 +1969,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci) return (0); if (*p != kCRC) goto failed; - if (read_Digests(a, &digest, ci->numFolders) < 0) + if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0) goto failed; for (i = 0; i < ci->numFolders; i++) { ci->folders[i].digest_defined = digest.defineds[i]; @@ -1978,8 +1993,8 @@ failed: static uint64_t folder_uncompressed_size(struct _7z_folder *f) { - int n = f->numOutStreams; - unsigned pairs = f->numBindPairs; + int n = (int)f->numOutStreams; + unsigned pairs = (unsigned)f->numBindPairs; while (--n >= 0) { unsigned i; @@ -2028,7 +2043,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss, return (-1); if (1000000 < f[i].numUnpackStreams) return (-1); - unpack_streams += f[i].numUnpackStreams; + unpack_streams += (size_t)f[i].numUnpackStreams; } if ((p = header_bytes(a, 1)) == NULL) return (-1); @@ -2082,7 +2097,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss, numDigests = 0; for (i = 0; i < numFolders; i++) { if (f[i].numUnpackStreams != 1 || !f[i].digest_defined) - numDigests += f[i].numUnpackStreams; + numDigests += (uint32_t)f[i].numUnpackStreams; } if (type == kCRC) { @@ -2180,7 +2195,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si) f = si->ci.folders; for (i = 0; i < si->ci.numFolders; i++) { f[i].packIndex = packIndex; - packIndex += f[i].numPackedStreams; + packIndex += (uint32_t)f[i].numPackedStreams; if (packIndex > si->pi.numPackStreams) return (-1); } @@ -2190,7 +2205,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si) if (*p == kSubStreamsInfo) { if (read_SubStreamsInfo(a, &(si->ss), - si->ci.folders, si->ci.numFolders) < 0) + si->ci.folders, (size_t)si->ci.numFolders) < 0) return (-1); if ((p = header_bytes(a, 1)) == NULL) return (-1); @@ -2278,7 +2293,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, if (1000000 < zip->numFiles) return (-1); - zip->entries = calloc(zip->numFiles, sizeof(*zip->entries)); + zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries)); if (zip->entries == NULL) return (-1); entries = zip->entries; @@ -2303,12 +2318,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, switch (type) { case kEmptyStream: - h->emptyStreamBools = calloc(zip->numFiles, + h->emptyStreamBools = calloc((size_t)zip->numFiles, sizeof(*h->emptyStreamBools)); if (h->emptyStreamBools == NULL) return (-1); if (read_Bools( - a, h->emptyStreamBools, zip->numFiles) < 0) + a, h->emptyStreamBools, (size_t)zip->numFiles) < 0) return (-1); empty_streams = 0; for (i = 0; i < zip->numFiles; i++) { @@ -2317,6 +2332,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, } break; case kEmptyFile: + if (empty_streams <= 0) { + /* Unexcepted sequence. Skip this. */ + if (header_bytes(a, ll) == NULL) + return (-1); + break; + } h->emptyFileBools = calloc(empty_streams, sizeof(*h->emptyFileBools)); if (h->emptyFileBools == NULL) @@ -2325,6 +2346,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, return (-1); break; case kAnti: + if (empty_streams <= 0) { + /* Unexcepted sequence. Skip this. */ + if (header_bytes(a, ll) == NULL) + return (-1); + break; + } h->antiBools = calloc(empty_streams, sizeof(*h->antiBools)); if (h->antiBools == NULL) @@ -2403,15 +2430,15 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, if ((p = header_bytes(a, 2)) == NULL) return (-1); allAreDefined = *p; - h->attrBools = calloc(zip->numFiles, + h->attrBools = calloc((size_t)zip->numFiles, sizeof(*h->attrBools)); if (h->attrBools == NULL) return (-1); if (allAreDefined) - memset(h->attrBools, 1, zip->numFiles); + memset(h->attrBools, 1, (size_t)zip->numFiles); else { if (read_Bools(a, h->attrBools, - zip->numFiles) < 0) + (size_t)zip->numFiles) < 0) return (-1); } for (i = 0; i < zip->numFiles; i++) { @@ -2445,7 +2472,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, if ((size_t)sindex >= si->ss.unpack_streams) return (-1); if (entries[i].mode == 0) - entries[i].mode = AE_IFREG | 0777; + entries[i].mode = AE_IFREG | 0666; if (si->ss.digestsDefined[sindex]) entries[i].flg |= CRC32_IS_SET; entries[i].ssIndex = sindex; @@ -2465,7 +2492,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, if (dir) entries[i].mode = AE_IFDIR | 0777; else - entries[i].mode = AE_IFREG | 0777; + entries[i].mode = AE_IFREG | 0666; } else if (dir && (entries[i].mode & AE_IFMT) != AE_IFDIR) { entries[i].mode &= ~AE_IFMT; @@ -2541,7 +2568,7 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type) int allAreDefined; unsigned i; - timeBools = calloc(zip->numFiles, sizeof(*timeBools)); + timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools)); if (timeBools == NULL) return (-1); @@ -2550,9 +2577,9 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type) goto failed; allAreDefined = *p; if (allAreDefined) - memset(timeBools, 1, zip->numFiles); + memset(timeBools, 1, (size_t)zip->numFiles); else { - if (read_Bools(a, timeBools, zip->numFiles) < 0) + if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0) goto failed; } @@ -2563,7 +2590,7 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type) if (parse_7zip_uint64(a, &(h->dataIndex)) < 0) goto failed; if (1000000 < h->dataIndex) - return (-1); + goto failed; } for (i = 0; i < zip->numFiles; i++) { @@ -2897,10 +2924,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum) return (ARCHIVE_FATAL); } if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining) - bytes_avail = zip->pack_stream_inbytes_remaining; + bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining; zip->pack_stream_inbytes_remaining -= bytes_avail; if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining) - bytes_avail = zip->folder_outbytes_remaining; + bytes_avail = (ssize_t)zip->folder_outbytes_remaining; zip->folder_outbytes_remaining -= bytes_avail; zip->uncompressed_buffer_bytes_remaining = bytes_avail; return (ARCHIVE_OK); @@ -2965,7 +2992,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum) size_t bytes_in, bytes_out; const void *buff_in; unsigned char *buff_out; - int eof; + int end_of_data; /* * Note: '1' here is a performance optimization. @@ -2987,23 +3014,23 @@ extract_pack_stream(struct archive_read *a, size_t minimum) - zip->uncompressed_buffer_bytes_remaining; bytes_in = bytes_avail; if (bytes_in > zip->pack_stream_inbytes_remaining) - bytes_in = zip->pack_stream_inbytes_remaining; + bytes_in = (size_t)zip->pack_stream_inbytes_remaining; /* Drive decompression. */ r = decompress(a, zip, buff_out, &bytes_out, buff_in, &bytes_in); switch (r) { case ARCHIVE_OK: - eof = 0; + end_of_data = 0; break; case ARCHIVE_EOF: - eof = 1; + end_of_data = 1; break; default: return (ARCHIVE_FATAL); } zip->pack_stream_inbytes_remaining -= bytes_in; if (bytes_out > zip->folder_outbytes_remaining) - bytes_out = zip->folder_outbytes_remaining; + bytes_out = (size_t)zip->folder_outbytes_remaining; zip->folder_outbytes_remaining -= bytes_out; zip->uncompressed_buffer_bytes_remaining += bytes_out; zip->pack_stream_bytes_unconsumed = bytes_in; @@ -3021,7 +3048,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum) if (zip->pack_stream_inbytes_remaining == 0 && zip->folder_outbytes_remaining == 0) break; - if (eof || (bytes_in == 0 && bytes_out == 0)) { + if (end_of_data || (bytes_in == 0 && bytes_out == 0)) { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive"); return (ARCHIVE_FATAL); @@ -3160,7 +3187,8 @@ read_stream(struct archive_read *a, const void **buff, size_t size, return (ARCHIVE_FATAL); } } - skipped = get_uncompressed_data(a, buff, skip_bytes, 0); + skipped = get_uncompressed_data( + a, buff, (size_t)skip_bytes, 0); if (skipped < 0) return (skipped); skip_bytes -= skipped; @@ -3292,13 +3320,13 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder, } coder2 = &(fc[3]); zip->main_stream_bytes_remaining = - folder->unPackSize[2]; + (size_t)folder->unPackSize[2]; } else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 && zip->pack_stream_remaining == 4 && folder->numInStreams == 5 && folder->numOutStreams == 2) { /* Source type 0 made by 7z */ zip->main_stream_bytes_remaining = - folder->unPackSize[0]; + (size_t)folder->unPackSize[0]; } else { /* We got an unexpected form. */ archive_set_error(&(a->archive), @@ -3311,7 +3339,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder, if ((r = seek_pack(a)) < 0) return (r); zip->pack_stream_bytes_unconsumed = - zip->pack_stream_inbytes_remaining; + (size_t)zip->pack_stream_inbytes_remaining; read_consume(a); /* Read following three sub streams. */ @@ -3333,7 +3361,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder, /* Allocate memory for the decorded data of a sub * stream. */ - b[i] = malloc(zip->folder_outbytes_remaining); + b[i] = malloc((size_t)zip->folder_outbytes_remaining); if (b[i] == NULL) { archive_set_error(&a->archive, ENOMEM, "No memory for 7-Zip decompression"); @@ -3428,7 +3456,7 @@ skip_stream(struct archive_read *a, size_t skip_bytes) "Truncated 7-Zip file body"); return (ARCHIVE_FATAL); } - bytes -= skipped_bytes; + bytes -= (size_t)skipped_bytes; if (zip->pack_stream_bytes_unconsumed) read_consume(a); } diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cab.c b/contrib/libarchive/libarchive/archive_read_support_format_cab.c index 0bc7c99..aa0152a 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_cab.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_cab.c @@ -292,6 +292,8 @@ struct cab { char end_of_archive; char end_of_entry; char end_of_entry_cleanup; + char read_data_invoked; + int64_t bytes_skipped; unsigned char *uncompressed_buffer; size_t uncompressed_buffer_size; @@ -798,7 +800,7 @@ cab_read_header(struct archive_read *a) file->offset = archive_le32dec(p + CFFILE_uoffFolderStart); file->folder = archive_le16dec(p + CFFILE_iFolder); file->mtime = cab_dos_time(p + CFFILE_date_time); - file->attr = archive_le16dec(p + CFFILE_attribs); + file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs); __archive_read_consume(a, 16); cab->cab_offset += 16; @@ -988,7 +990,7 @@ archive_read_format_cab_read_header(struct archive_read *a, if (file->attr & ATTR_RDONLY) archive_entry_set_mode(entry, AE_IFREG | 0555); else - archive_entry_set_mode(entry, AE_IFREG | 0777); + archive_entry_set_mode(entry, AE_IFREG | 0666); archive_entry_set_mtime(entry, file->mtime, 0); cab->entry_bytes_remaining = file->uncompressed_size; @@ -1026,9 +1028,22 @@ archive_read_format_cab_read_data(struct archive_read *a, default: break; } + if (cab->read_data_invoked == 0) { + if (cab->bytes_skipped) { + if (cab->entry_cfdata == NULL) { + r = cab_next_cfdata(a); + if (r < 0) + return (r); + } + if (cab_consume_cfdata(a, cab->bytes_skipped) < 0) + return (ARCHIVE_FATAL); + cab->bytes_skipped = 0; + } + cab->read_data_invoked = 1; + } if (cab->entry_unconsumed) { /* Consume as much as the compressor actually used. */ - r = cab_consume_cfdata(a, cab->entry_unconsumed); + r = (int)cab_consume_cfdata(a, cab->entry_unconsumed); cab->entry_unconsumed = 0; if (r < 0) return (r); @@ -1358,46 +1373,25 @@ cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail) struct cab *cab = (struct cab *)(a->format->data); struct cfdata *cfdata; const void *d; - int64_t skipped_bytes; cfdata = cab->entry_cfdata; - if (cfdata->uncompressed_avail == 0 && - cfdata->read_offset > 0) { - /* we've already skipped some bytes before really read. */ - skipped_bytes = cfdata->read_offset; - cfdata->read_offset = 0; - cfdata->uncompressed_bytes_remaining += skipped_bytes; - } else - skipped_bytes = 0; - do { - /* - * Note: '1' here is a performance optimization. - * Recall that the decompression layer returns a count of - * available bytes; asking for more than that forces the - * decompressor to combine reads by copying data. - */ - d = __archive_read_ahead(a, 1, avail); - if (*avail <= 0) { - *avail = truncated_error(a); - return (NULL); - } - if (*avail > cfdata->uncompressed_bytes_remaining) - *avail = cfdata->uncompressed_bytes_remaining; - cfdata->uncompressed_avail = cfdata->uncompressed_size; - cfdata->unconsumed = *avail; - cfdata->sum_ptr = d; - if (skipped_bytes > 0) { - skipped_bytes = - cab_minimum_consume_cfdata(a, skipped_bytes); - if (skipped_bytes < 0) { - *avail = ARCHIVE_FATAL; - return (NULL); - } - continue; - } - } while (0); - + /* + * Note: '1' here is a performance optimization. + * Recall that the decompression layer returns a count of + * available bytes; asking for more than that forces the + * decompressor to combine reads by copying data. + */ + d = __archive_read_ahead(a, 1, avail); + if (*avail <= 0) { + *avail = truncated_error(a); + return (NULL); + } + if (*avail > cfdata->uncompressed_bytes_remaining) + *avail = cfdata->uncompressed_bytes_remaining; + cfdata->uncompressed_avail = cfdata->uncompressed_size; + cfdata->unconsumed = *avail; + cfdata->sum_ptr = d; return (d); } @@ -1543,7 +1537,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail) return (NULL); } } - uavail = cab->stream.total_out; + uavail = (uint16_t)cab->stream.total_out; if (uavail < cfdata->uncompressed_size) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -1721,7 +1715,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail) } } - uavail = cab->xstrm.total_out; + uavail = (uint16_t)cab->xstrm.total_out; /* * Make sure a read pointer advances to next CFDATA. */ @@ -1793,9 +1787,8 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) rbytes -= cbytes; if (cfdata->uncompressed_avail == 0 && - (cab->entry_cffolder->comptype == COMPTYPE_NONE || - cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT || - cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) { + (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT || + cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) { /* We have not read any data yet. */ if (cbytes == cfdata->uncompressed_bytes_remaining) { /* Skip whole current CFDATA. */ @@ -1821,8 +1814,8 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) } continue; } - cfdata->read_offset += cbytes; - cfdata->uncompressed_bytes_remaining -= cbytes; + cfdata->read_offset += (uint16_t)cbytes; + cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes; break; } else if (cbytes == 0) { err = cab_next_cfdata(a); @@ -1846,7 +1839,7 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) if (avail <= 0) return (ARCHIVE_FATAL); if (avail > cbytes) - avail = cbytes; + avail = (ssize_t)cbytes; if (cab_minimum_consume_cfdata(a, avail) < 0) return (ARCHIVE_FATAL); cbytes -= avail; @@ -1875,8 +1868,8 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) else cbytes = cfdata->unconsumed; rbytes -= cbytes; - cfdata->read_offset += cbytes; - cfdata->uncompressed_bytes_remaining -= cbytes; + cfdata->read_offset += (uint16_t)cbytes; + cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes; cfdata->unconsumed -= cbytes; } else { cbytes = cfdata->uncompressed_avail - cfdata->read_offset; @@ -1884,8 +1877,8 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) if (consumed_bytes < cbytes) cbytes = consumed_bytes; rbytes -= cbytes; - cfdata->read_offset += cbytes; - cfdata->uncompressed_bytes_remaining -= cbytes; + cfdata->read_offset += (uint16_t)cbytes; + cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes; } if (cfdata->unconsumed) { @@ -1896,12 +1889,12 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) } if (cbytes) { /* Compute the sum. */ - cab_checksum_update(a, cbytes); + cab_checksum_update(a, (size_t)cbytes); /* Consume as much as the compressor actually used. */ __archive_read_consume(a, cbytes); cab->cab_offset += cbytes; - cfdata->compressed_bytes_remaining -= cbytes; + cfdata->compressed_bytes_remaining -= (uint16_t)cbytes; if (cfdata->compressed_bytes_remaining == 0) { err = cab_checksum_finish(a); if (err < 0) @@ -1945,7 +1938,7 @@ cab_read_data(struct archive_read *a, const void **buff, return (bytes_avail); } if (bytes_avail > cab->entry_bytes_remaining) - bytes_avail = cab->entry_bytes_remaining; + bytes_avail = (ssize_t)cab->entry_bytes_remaining; *size = bytes_avail; *offset = cab->entry_offset; @@ -1954,6 +1947,11 @@ cab_read_data(struct archive_read *a, const void **buff, if (cab->entry_bytes_remaining == 0) cab->end_of_entry = 1; cab->entry_unconsumed = bytes_avail; + if (cab->entry_cffolder->comptype == COMPTYPE_NONE) { + /* Don't consume more than current entry used. */ + if (cab->entry_cfdata->unconsumed > cab->entry_unconsumed) + cab->entry_cfdata->unconsumed = cab->entry_unconsumed; + } return (ARCHIVE_OK); } @@ -1969,9 +1967,17 @@ archive_read_format_cab_read_data_skip(struct archive_read *a) if (cab->end_of_archive) return (ARCHIVE_EOF); + if (!cab->read_data_invoked) { + cab->bytes_skipped += cab->entry_bytes_remaining; + cab->entry_bytes_remaining = 0; + /* This entry is finished and done. */ + cab->end_of_entry_cleanup = cab->end_of_entry = 1; + return (ARCHIVE_OK); + } + if (cab->entry_unconsumed) { /* Consume as much as the compressor actually used. */ - r = cab_consume_cfdata(a, cab->entry_unconsumed); + r = (int)cab_consume_cfdata(a, cab->entry_unconsumed); cab->entry_unconsumed = 0; if (r < 0) return (r); @@ -1993,6 +1999,11 @@ archive_read_format_cab_read_data_skip(struct archive_read *a) if (bytes_skipped < 0) return (ARCHIVE_FATAL); + /* If the compression type is none(uncompressed), we've already + * consumed data as much as the current entry size. */ + if (cab->entry_cffolder->comptype == COMPTYPE_NONE) + cab->entry_cfdata->unconsumed = 0; + /* This entry is finished and done. */ cab->end_of_entry_cleanup = cab->end_of_entry = 1; return (ARCHIVE_OK); @@ -2227,7 +2238,9 @@ lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset) /* Notify how many bits we consumed. */ #define lzx_br_consume(br, n) ((br)->cache_avail -= (n)) -#define lzx_br_consume_unalined_bits(br) ((br)->cache_avail &= ~0x0f) +#define lzx_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~0x0f) + +#define lzx_br_is_unaligned(br) ((br)->cache_avail & 0x0f) static const uint32_t cache_masks[] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, @@ -2354,24 +2367,25 @@ lzx_cleanup_bitstream(struct lzx_stream *strm) #define ST_RD_TRANSLATION_SIZE 1 #define ST_RD_BLOCK_TYPE 2 #define ST_RD_BLOCK_SIZE 3 -#define ST_RD_R0 4 -#define ST_RD_R1 5 -#define ST_RD_R2 6 -#define ST_COPY_UNCOMP1 7 -#define ST_COPY_UNCOMP2 8 -#define ST_RD_ALIGNED_OFFSET 9 -#define ST_RD_VERBATIM 10 -#define ST_RD_PRE_MAIN_TREE_256 11 -#define ST_MAIN_TREE_256 12 -#define ST_RD_PRE_MAIN_TREE_REM 13 -#define ST_MAIN_TREE_REM 14 -#define ST_RD_PRE_LENGTH_TREE 15 -#define ST_LENGTH_TREE 16 -#define ST_MAIN 17 -#define ST_LENGTH 18 -#define ST_OFFSET 19 -#define ST_REAL_POS 20 -#define ST_COPY 21 +#define ST_RD_ALIGNMENT 4 +#define ST_RD_R0 5 +#define ST_RD_R1 6 +#define ST_RD_R2 7 +#define ST_COPY_UNCOMP1 8 +#define ST_COPY_UNCOMP2 9 +#define ST_RD_ALIGNED_OFFSET 10 +#define ST_RD_VERBATIM 11 +#define ST_RD_PRE_MAIN_TREE_256 12 +#define ST_MAIN_TREE_256 13 +#define ST_RD_PRE_MAIN_TREE_REM 14 +#define ST_MAIN_TREE_REM 15 +#define ST_RD_PRE_LENGTH_TREE 16 +#define ST_LENGTH_TREE 17 +#define ST_MAIN 18 +#define ST_LENGTH 19 +#define ST_OFFSET 20 +#define ST_REAL_POS 21 +#define ST_COPY 22 static int lzx_decode(struct lzx_stream *strm, int last) @@ -2475,15 +2489,25 @@ lzx_read_blocks(struct lzx_stream *strm, int last) ds->state = ST_RD_ALIGNED_OFFSET; break; } + /* FALL THROUGH */ + case ST_RD_ALIGNMENT: /* * Handle an Uncompressed Block. */ /* Skip padding to align following field on * 16-bit boundary. */ - if (br->cache_avail == 32 || br->cache_avail == 16) - lzx_br_consume(br, 16); - else - lzx_br_consume_unalined_bits(br); + if (lzx_br_is_unaligned(br)) + lzx_br_consume_unaligned_bits(br); + else { + if (lzx_br_read_ahead(strm, br, 16)) + lzx_br_consume(br, 16); + else { + ds->state = ST_RD_ALIGNMENT; + if (last) + goto failed; + return (ARCHIVE_OK); + } + } /* Preparation to read repeated offsets R0,R1 and R2. */ ds->rbytes_avail = 0; ds->state = ST_RD_R0; @@ -2508,8 +2532,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last) lzx_br_consume(br, 16); archive_le16enc(ds->rbytes, u16); ds->rbytes_avail = 2; - } else - ds->rbytes_avail = 0; + } if (ds->rbytes_avail < 4 && ds->br.have_odd) { ds->rbytes[ds->rbytes_avail++] = ds->br.odd; @@ -2525,6 +2548,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last) *strm->next_in++; strm->avail_in--; } + ds->rbytes_avail = 0; if (ds->state == ST_RD_R0) { ds->r0 = archive_le32dec(ds->rbytes); if (ds->r0 < 0) @@ -2549,8 +2573,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last) * Copy bytes form next_in to next_out directly. */ while (ds->block_bytes_avail) { - unsigned char *d; - int l,ll; + int l; if (strm->avail_out <= 0) /* Output buffer is empty. */ @@ -2568,17 +2591,16 @@ lzx_read_blocks(struct lzx_stream *strm, int last) l = (int)strm->avail_out; if (l > strm->avail_in) l = (int)strm->avail_in; - ll = l; - d = &(ds->w_buff[ds->w_pos]); - while (--l >= 0) { - *strm->next_out++ = *strm->next_in; - *d++ = *strm->next_in++; - } - strm->avail_out -= ll; - strm->total_out += ll; - strm->avail_in -= ll; - ds->w_pos = (ds->w_pos + ll) & ds->w_mask; - ds->block_bytes_avail -= ll; + memcpy(strm->next_out, strm->next_in, l); + memcpy(&(ds->w_buff[ds->w_pos]), + strm->next_in, l); + strm->next_in += l; + strm->avail_in -= l; + strm->next_out += l; + strm->avail_out -= l; + strm->total_out += l; + ds->w_pos = (ds->w_pos + l) & ds->w_mask; + ds->block_bytes_avail -= l; } /* FALL THROUGH */ case ST_COPY_UNCOMP2: diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c index 556ef66..b839cd7 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c @@ -398,11 +398,12 @@ archive_read_format_cpio_read_header(struct archive_read *a, /* If this is a symlink, read the link contents. */ if (archive_entry_filetype(entry) == AE_IFLNK) { - h = __archive_read_ahead(a, cpio->entry_bytes_remaining, NULL); + h = __archive_read_ahead(a, + (size_t)cpio->entry_bytes_remaining, NULL); if (h == NULL) return (ARCHIVE_FATAL); if (archive_entry_copy_symlink_l(entry, (const char *)h, - cpio->entry_bytes_remaining, sconv) != 0) { + (size_t)cpio->entry_bytes_remaining, sconv) != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Linkname"); @@ -458,7 +459,7 @@ archive_read_format_cpio_read_data(struct archive_read *a, if (bytes_read <= 0) return (ARCHIVE_FATAL); if (bytes_read > cpio->entry_bytes_remaining) - bytes_read = cpio->entry_bytes_remaining; + bytes_read = (ssize_t)cpio->entry_bytes_remaining; *size = bytes_read; cpio->entry_bytes_unconsumed = bytes_read; *offset = cpio->entry_offset; @@ -603,17 +604,23 @@ header_newc(struct archive_read *a, struct cpio *cpio, /* TODO: Abort here? */ } - archive_entry_set_devmajor(entry, atol16(header + newc_devmajor_offset, newc_devmajor_size)); - archive_entry_set_devminor(entry, atol16(header + newc_devminor_offset, newc_devminor_size)); + archive_entry_set_devmajor(entry, + (dev_t)atol16(header + newc_devmajor_offset, newc_devmajor_size)); + archive_entry_set_devminor(entry, + (dev_t)atol16(header + newc_devminor_offset, newc_devminor_size)); archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size)); - archive_entry_set_mode(entry, atol16(header + newc_mode_offset, newc_mode_size)); + archive_entry_set_mode(entry, + (mode_t)atol16(header + newc_mode_offset, newc_mode_size)); archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size)); archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size)); - archive_entry_set_nlink(entry, atol16(header + newc_nlink_offset, newc_nlink_size)); - archive_entry_set_rdevmajor(entry, atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size)); - archive_entry_set_rdevminor(entry, atol16(header + newc_rdevminor_offset, newc_rdevminor_size)); + archive_entry_set_nlink(entry, + (unsigned int)atol16(header + newc_nlink_offset, newc_nlink_size)); + archive_entry_set_rdevmajor(entry, + (dev_t)atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size)); + archive_entry_set_rdevminor(entry, + (dev_t)atol16(header + newc_rdevminor_offset, newc_rdevminor_size)); archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0); - *namelength = atol16(header + newc_namesize_offset, newc_namesize_size); + *namelength = (size_t)atol16(header + newc_namesize_offset, newc_namesize_size); /* Pad name to 2 more than a multiple of 4. */ *name_pad = (2 - *namelength) & 3; @@ -767,15 +774,19 @@ header_odc(struct archive_read *a, struct cpio *cpio, /* Parse out octal fields. */ header = (const char *)h; - archive_entry_set_dev(entry, atol8(header + odc_dev_offset, odc_dev_size)); + archive_entry_set_dev(entry, + (dev_t)atol8(header + odc_dev_offset, odc_dev_size)); archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size)); - archive_entry_set_mode(entry, atol8(header + odc_mode_offset, odc_mode_size)); + archive_entry_set_mode(entry, + (mode_t)atol8(header + odc_mode_offset, odc_mode_size)); archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size)); archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size)); - archive_entry_set_nlink(entry, atol8(header + odc_nlink_offset, odc_nlink_size)); - archive_entry_set_rdev(entry, atol8(header + odc_rdev_offset, odc_rdev_size)); + archive_entry_set_nlink(entry, + (unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size)); + archive_entry_set_rdev(entry, + (dev_t)atol8(header + odc_rdev_offset, odc_rdev_size)); archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0); - *namelength = atol8(header + odc_namesize_offset, odc_namesize_size); + *namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size); *name_pad = 0; /* No padding of filename. */ /* @@ -816,15 +827,19 @@ header_afiol(struct archive_read *a, struct cpio *cpio, /* Parse out octal fields. */ header = (const char *)h; - archive_entry_set_dev(entry, atol16(header + afiol_dev_offset, afiol_dev_size)); + archive_entry_set_dev(entry, + (dev_t)atol16(header + afiol_dev_offset, afiol_dev_size)); archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size)); - archive_entry_set_mode(entry, atol8(header + afiol_mode_offset, afiol_mode_size)); + archive_entry_set_mode(entry, + (mode_t)atol8(header + afiol_mode_offset, afiol_mode_size)); archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size)); archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size)); - archive_entry_set_nlink(entry, atol16(header + afiol_nlink_offset, afiol_nlink_size)); - archive_entry_set_rdev(entry, atol16(header + afiol_rdev_offset, afiol_rdev_size)); + archive_entry_set_nlink(entry, + (unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size)); + archive_entry_set_rdev(entry, + (dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size)); archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0); - *namelength = atol16(header + afiol_namesize_offset, afiol_namesize_size); + *namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size); *name_pad = 0; /* No padding of filename. */ cpio->entry_bytes_remaining = diff --git a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c index c7a4d74..8c9b080 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c @@ -975,8 +975,8 @@ read_children(struct archive_read *a, struct file_info *parent) iso9660->current_position = parent->offset; } - step = ((parent->size + iso9660->logical_block_size -1) / - iso9660->logical_block_size) * iso9660->logical_block_size; + step = (size_t)(((parent->size + iso9660->logical_block_size -1) / + iso9660->logical_block_size) * iso9660->logical_block_size); b = __archive_read_ahead(a, step, NULL); if (b == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -1397,7 +1397,7 @@ zisofs_read_data(struct archive_read *a, return (ARCHIVE_FATAL); } if (bytes_read > iso9660->entry_bytes_remaining) - bytes_read = iso9660->entry_bytes_remaining; + bytes_read = (ssize_t)iso9660->entry_bytes_remaining; avail = bytes_read; uncompressed_size = 0; @@ -1405,9 +1405,9 @@ zisofs_read_data(struct archive_read *a, size_t ceil, xsize; /* Allocate block pointers buffer. */ - ceil = (zisofs->pz_uncompressed_size + - (1LL << zisofs->pz_log2_bs) - 1) - >> zisofs->pz_log2_bs; + ceil = (size_t)((zisofs->pz_uncompressed_size + + (((int64_t)1) << zisofs->pz_log2_bs) - 1) + >> zisofs->pz_log2_bs); xsize = (ceil + 1) * 4; if (zisofs->block_pointers_alloc < xsize) { size_t alloc; @@ -1671,7 +1671,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a, if (*buff == NULL) return (ARCHIVE_FATAL); if (bytes_read > iso9660->entry_bytes_remaining) - bytes_read = iso9660->entry_bytes_remaining; + bytes_read = (ssize_t)iso9660->entry_bytes_remaining; *size = bytes_read; *offset = iso9660->entry_sparse_offset; iso9660->entry_sparse_offset += bytes_read; @@ -2277,7 +2277,7 @@ register_CE(struct archive_read *a, int32_t location, archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } - p = malloc(new_size * sizeof(p[0])); + p = calloc(new_size, sizeof(p[0])); if (p == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); @@ -2527,9 +2527,6 @@ parse_rockridge_SL1(struct file_info *file, const unsigned char *data, if (!file->symlink_continues || file->symlink.length < 1) archive_string_empty(&file->symlink); - else if (!file->symlink_continues && - file->symlink.s[file->symlink.length - 1] != '/') - separator = "/"; file->symlink_continues = 0; /* @@ -3099,6 +3096,8 @@ isodate7(const unsigned char *v) { struct tm tm; int offset; + time_t t; + memset(&tm, 0, sizeof(tm)); tm.tm_year = v[0]; tm.tm_mon = v[1] - 1; @@ -3112,7 +3111,10 @@ isodate7(const unsigned char *v) tm.tm_hour -= offset / 4; tm.tm_min -= (offset % 4) * 15; } - return (time_from_tm(&tm)); + t = time_from_tm(&tm); + if (t == (time_t)-1) + return ((time_t)0); + return (t); } static time_t @@ -3120,6 +3122,8 @@ isodate17(const unsigned char *v) { struct tm tm; int offset; + time_t t; + memset(&tm, 0, sizeof(tm)); tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100 + (v[2] - '0') * 10 + (v[3] - '0') @@ -3135,7 +3139,10 @@ isodate17(const unsigned char *v) tm.tm_hour -= offset / 4; tm.tm_min -= (offset % 4) * 15; } - return (time_from_tm(&tm)); + t = time_from_tm(&tm); + if (t == (time_t)-1) + return ((time_t)0); + return (t); } static time_t @@ -3149,7 +3156,8 @@ time_from_tm(struct tm *t) #else /* Else use direct calculation using POSIX assumptions. */ /* First, fix up tm_yday based on the year/month/day. */ - mktime(t); + if (mktime(t) == (time_t)-1) + return ((time_t)-1); /* Then we can compute timegm() from first principles. */ return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600 + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000 diff --git a/contrib/libarchive/libarchive/archive_read_support_format_lha.c b/contrib/libarchive/libarchive/archive_read_support_format_lha.c index ace3b3a..a92b072 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_lha.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_lha.c @@ -951,7 +951,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha) /* Read extended headers */ err2 = lha_read_file_extended_header(a, lha, NULL, 2, - lha->compsize + 2, &extdsize); + (size_t)(lha->compsize + 2), &extdsize); if (err2 < ARCHIVE_WARN) return (err2); if (err2 < err) @@ -1446,7 +1446,7 @@ lha_read_data_none(struct archive_read *a, const void **buff, return (ARCHIVE_FATAL); } if (bytes_avail > lha->entry_bytes_remaining) - bytes_avail = lha->entry_bytes_remaining; + bytes_avail = (ssize_t)lha->entry_bytes_remaining; lha->entry_crc_calculated = lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail); *size = bytes_avail; @@ -1529,7 +1529,7 @@ lha_read_data_lzh(struct archive_read *a, const void **buff, return (ARCHIVE_FATAL); } if (bytes_avail > lha->entry_bytes_remaining) - bytes_avail = lha->entry_bytes_remaining; + bytes_avail = (ssize_t)lha->entry_bytes_remaining; lha->strm.avail_in = bytes_avail; lha->strm.total_in = 0; @@ -1575,7 +1575,7 @@ static int archive_read_format_lha_read_data_skip(struct archive_read *a) { struct lha *lha; - off_t bytes_skipped; + int64_t bytes_skipped; lha = (struct lha *)(a->format->data); @@ -2016,7 +2016,7 @@ lzh_copy_from_window(struct lzh_stream *strm, struct lzh_dec *ds) if (ds->w_pos - ds->copy_pos <= strm->avail_out) copy_bytes = ds->w_pos - ds->copy_pos; else - copy_bytes = strm->avail_out; + copy_bytes = (size_t)strm->avail_out; memcpy(strm->next_out, ds->w_buff + ds->copy_pos, copy_bytes); ds->copy_pos += copy_bytes; @@ -2024,7 +2024,7 @@ lzh_copy_from_window(struct lzh_stream *strm, struct lzh_dec *ds) if (ds->w_remaining <= strm->avail_out) copy_bytes = ds->w_remaining; else - copy_bytes = strm->avail_out; + copy_bytes = (size_t)strm->avail_out; memcpy(strm->next_out, ds->w_buff + ds->w_size - ds->w_remaining, copy_bytes); ds->w_remaining -= copy_bytes; diff --git a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c index 316bad6..ffe456f 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c @@ -1183,7 +1183,7 @@ parse_device(struct archive *a, struct archive_entry *entry, char *val) comma1 = strchr(val, ','); if (comma1 == NULL) { - archive_entry_set_dev(entry, mtree_atol10(&val)); + archive_entry_set_dev(entry, (dev_t)mtree_atol10(&val)); return (ARCHIVE_OK); } ++comma1; @@ -1194,8 +1194,8 @@ parse_device(struct archive *a, struct archive_entry *entry, char *val) return (ARCHIVE_WARN); } ++comma2; - archive_entry_set_rdevmajor(entry, mtree_atol(&comma1)); - archive_entry_set_rdevminor(entry, mtree_atol(&comma2)); + archive_entry_set_rdevmajor(entry, (dev_t)mtree_atol(&comma1)); + archive_entry_set_rdevminor(entry, (dev_t)mtree_atol(&comma2)); return (ARCHIVE_OK); } @@ -1280,7 +1280,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, if (val[0] >= '0' && val[0] <= '9') { *parsed_kws |= MTREE_HAS_PERM; archive_entry_set_perm(entry, - mtree_atol8(&val)); + (mode_t)mtree_atol8(&val)); } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -1292,7 +1292,8 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, case 'n': if (strcmp(key, "nlink") == 0) { *parsed_kws |= MTREE_HAS_NLINK; - archive_entry_set_nlink(entry, mtree_atol10(&val)); + archive_entry_set_nlink(entry, + (unsigned int)mtree_atol10(&val)); break; } case 'r': @@ -1434,7 +1435,7 @@ read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offs *buff = mtree->buff; *offset = mtree->offset; if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset) - bytes_to_read = mtree->cur_size - mtree->offset; + bytes_to_read = (size_t)(mtree->cur_size - mtree->offset); else bytes_to_read = mtree->buffsize; bytes_read = read(mtree->fd, mtree->buff, bytes_to_read); diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar.c b/contrib/libarchive/libarchive/archive_read_support_format_rar.c index d2a893e..1e5c5fa 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_rar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_rar.c @@ -453,7 +453,7 @@ rar_br_fillup(struct archive_read *a, struct rar_br *br) if (br->next_in == NULL) return (0); if (br->avail_in > rar->bytes_remaining) - br->avail_in = rar->bytes_remaining; + br->avail_in = (ssize_t)rar->bytes_remaining; if (br->avail_in == 0) return (0); } @@ -481,7 +481,7 @@ rar_br_preparation(struct archive_read *a, struct rar_br *br) return (ARCHIVE_FATAL); } if (br->avail_in > rar->bytes_remaining) - br->avail_in = rar->bytes_remaining; + br->avail_in = (ssize_t)rar->bytes_remaining; if (br->cache_avail == 0) (void)rar_br_fillup(a, br); } @@ -522,7 +522,7 @@ lzss_size(struct lzss *lzss) static inline int lzss_offset_for_position(struct lzss *lzss, int64_t pos) { - return pos & lzss->mask; + return (int)(pos & lzss->mask); } static inline unsigned char * @@ -1084,11 +1084,11 @@ read_header(struct archive_read *a, struct archive_entry *entry, return (ARCHIVE_FATAL); } - if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL) + if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) return (ARCHIVE_FATAL); /* File Header CRC check. */ - crc32_val = crc32(crc32_val, h, header_size - 7); + crc32_val = crc32(crc32_val, h, (unsigned)(header_size - 7)); if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Header CRC error"); @@ -1131,9 +1131,6 @@ read_header(struct archive_read *a, struct archive_entry *entry, rar->unp_size = archive_le32dec(file_header.unp_size); } - /* TODO: Need to use CRC check for these kind of cases. - * For now, check if sizes are not < 0. - */ if (rar->packed_size < 0 || rar->unp_size < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -1148,7 +1145,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, size_t distance = p - (const char *)h; header_size += rar->packed_size; /* Make sure we have the extended data. */ - if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL) + if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) return (ARCHIVE_FATAL); p = h; endp = p + header_size - 7; @@ -1161,13 +1158,17 @@ read_header(struct archive_read *a, struct archive_entry *entry, "Invalid filename size"); return (ARCHIVE_FATAL); } - if (rar->filename_allocated < filename_size+2) { - rar->filename = realloc(rar->filename, filename_size+2); - if (rar->filename == NULL) { + if (rar->filename_allocated < filename_size * 2 + 2) { + char *newptr; + size_t newsize = filename_size * 2 + 2; + newptr = realloc(rar->filename, newsize); + if (newptr == NULL) { archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory."); return (ARCHIVE_FATAL); } + rar->filename = newptr; + rar->filename_allocated = newsize; } filename = rar->filename; memcpy(filename, p, filename_size); @@ -1176,15 +1177,17 @@ read_header(struct archive_read *a, struct archive_entry *entry, { if (filename_size != strlen(filename)) { - unsigned char highbyte, flagbits, flagbyte, length, offset; + unsigned char highbyte, flagbits, flagbyte, offset; + unsigned fn_end; end = filename_size; + fn_end = filename_size * 2; filename_size = 0; offset = strlen(filename) + 1; highbyte = *(p + offset++); flagbits = 0; flagbyte = 0; - while (offset < end && filename_size < end) + while (offset < end && filename_size < fn_end) { if (!flagbits) { @@ -1210,19 +1213,26 @@ read_header(struct archive_read *a, struct archive_entry *entry, break; case 3: { - length = *(p + offset++); - while (length) - { - if (filename_size >= end) - break; - filename[filename_size++] = *(p + offset); + char extra, high; + uint8_t length = *(p + offset++); + + if (length & 0x80) { + extra = *(p + offset++); + high = (char)highbyte; + } else + extra = high = 0; + length = (length & 0x7f) + 2; + while (length && filename_size < fn_end) { + unsigned cp = filename_size >> 1; + filename[filename_size++] = high; + filename[filename_size++] = p[cp] + extra; length--; } } break; } } - if (filename_size >= end) { + if (filename_size > fn_end) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid filename"); return (ARCHIVE_FATAL); @@ -1322,7 +1332,8 @@ read_header(struct archive_read *a, struct archive_entry *entry, rar->bytes_remaining = rar->packed_size; rar->bytes_uncopied = rar->bytes_unconsumed = 0; - rar->lzss.position = rar->dictionary_size = rar->offset = 0; + rar->lzss.position = rar->offset = 0; + rar->dictionary_size = 0; rar->offset_outgoing = 0; rar->br.cache_avail = 0; rar->br.avail_in = 0; @@ -1477,11 +1488,12 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry, int ret = (ARCHIVE_OK); rar = (struct rar *)(a->format->data); - if ((h = __archive_read_ahead(a, rar->packed_size, NULL)) == NULL) + if ((h = __archive_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL) return (ARCHIVE_FATAL); p = h; - if (archive_entry_copy_symlink_l(entry, p, rar->packed_size, sconv)) + if (archive_entry_copy_symlink_l(entry, + p, (size_t)rar->packed_size, sconv)) { if (errno == ENOMEM) { @@ -1528,7 +1540,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size, return (ARCHIVE_FATAL); } if (bytes_avail > rar->bytes_remaining) - bytes_avail = rar->bytes_remaining; + bytes_avail = (ssize_t)rar->bytes_remaining; *size = bytes_avail; *offset = rar->offset; @@ -1587,7 +1599,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset)) bs = rar->unp_buffer_size - rar->unp_offset; else - bs = rar->bytes_uncopied; + bs = (size_t)rar->bytes_uncopied; ret = copy_from_lzss_window(a, buff, rar->offset, bs); if (ret != ARCHIVE_OK) return (ret); @@ -1715,7 +1727,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset)) bs = rar->unp_buffer_size - rar->unp_offset; else - bs = rar->bytes_uncopied; + bs = (size_t)rar->bytes_uncopied; ret = copy_from_lzss_window(a, buff, rar->offset, bs); if (ret != ARCHIVE_OK) return (ret); @@ -1978,7 +1990,7 @@ parse_codes(struct archive_read *a) if (rar->unp_size >= DICTIONARY_MAX_SIZE) rar->dictionary_size = DICTIONARY_MAX_SIZE; else - rar->dictionary_size = rar_fls(rar->unp_size) << 1; + rar->dictionary_size = rar_fls((unsigned int)rar->unp_size) << 1; rar->lzss.window = (unsigned char *)realloc(rar->lzss.window, rar->dictionary_size); if (rar->lzss.window == NULL) { diff --git a/contrib/libarchive/libarchive/archive_read_support_format_tar.c b/contrib/libarchive/libarchive/archive_read_support_format_tar.c index 9a943cb..867d208 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_tar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_tar.c @@ -527,56 +527,57 @@ archive_read_format_tar_read_data(struct archive_read *a, tar = (struct tar *)(a->format->data); -skip_hole: - /* Remove exhausted entries from sparse list. */ - while (tar->sparse_list != NULL && - tar->sparse_list->remaining == 0) { - p = tar->sparse_list; - tar->sparse_list = p->next; - free(p); - } + for (;;) { + /* Remove exhausted entries from sparse list. */ + while (tar->sparse_list != NULL && + tar->sparse_list->remaining == 0) { + p = tar->sparse_list; + tar->sparse_list = p->next; + free(p); + } - if (tar->entry_bytes_unconsumed) { - __archive_read_consume(a, tar->entry_bytes_unconsumed); - tar->entry_bytes_unconsumed = 0; - } + if (tar->entry_bytes_unconsumed) { + __archive_read_consume(a, tar->entry_bytes_unconsumed); + tar->entry_bytes_unconsumed = 0; + } - /* If we're at end of file, return EOF. */ - if (tar->sparse_list == NULL || tar->entry_bytes_remaining == 0) { - if (__archive_read_consume(a, tar->entry_padding) < 0) - return (ARCHIVE_FATAL); - tar->entry_padding = 0; - *buff = NULL; - *size = 0; - *offset = tar->realsize; - return (ARCHIVE_EOF); - } + /* If we're at end of file, return EOF. */ + if (tar->sparse_list == NULL || + tar->entry_bytes_remaining == 0) { + if (__archive_read_consume(a, tar->entry_padding) < 0) + return (ARCHIVE_FATAL); + tar->entry_padding = 0; + *buff = NULL; + *size = 0; + *offset = tar->realsize; + return (ARCHIVE_EOF); + } - *buff = __archive_read_ahead(a, 1, &bytes_read); - if (bytes_read < 0) - return (ARCHIVE_FATAL); - if (*buff == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Truncated tar archive"); - return (ARCHIVE_FATAL); + *buff = __archive_read_ahead(a, 1, &bytes_read); + if (bytes_read < 0) + return (ARCHIVE_FATAL); + if (*buff == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Truncated tar archive"); + return (ARCHIVE_FATAL); + } + if (bytes_read > tar->entry_bytes_remaining) + bytes_read = (ssize_t)tar->entry_bytes_remaining; + /* Don't read more than is available in the + * current sparse block. */ + if (tar->sparse_list->remaining < bytes_read) + bytes_read = (ssize_t)tar->sparse_list->remaining; + *size = bytes_read; + *offset = tar->sparse_list->offset; + tar->sparse_list->remaining -= bytes_read; + tar->sparse_list->offset += bytes_read; + tar->entry_bytes_remaining -= bytes_read; + tar->entry_bytes_unconsumed = bytes_read; + + if (!tar->sparse_list->hole) + return (ARCHIVE_OK); + /* Current is hole data and skip this. */ } - if (bytes_read > tar->entry_bytes_remaining) - bytes_read = tar->entry_bytes_remaining; - /* Don't read more than is available in the - * current sparse block. */ - if (tar->sparse_list->remaining < bytes_read) - bytes_read = tar->sparse_list->remaining; - *size = bytes_read; - *offset = tar->sparse_list->offset; - tar->sparse_list->remaining -= bytes_read; - tar->sparse_list->offset += bytes_read; - tar->entry_bytes_remaining -= bytes_read; - tar->entry_bytes_unconsumed = bytes_read; - - if (tar->sparse_list->hole) - goto skip_hole; - - return (ARCHIVE_OK); } static int @@ -786,7 +787,7 @@ checksum(struct archive_read *a, const void *h) * Test the checksum. Note that POSIX specifies _unsigned_ * bytes for this calculation. */ - sum = tar_atol(header->checksum, sizeof(header->checksum)); + sum = (int)tar_atol(header->checksum, sizeof(header->checksum)); check = 0; for (i = 0; i < 148; i++) check += (unsigned char)bytes[i]; @@ -847,7 +848,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, * more to make sure that we don't overrun acl_text later. */ header = (const struct archive_entry_header_ustar *)h; - size = tar_atol(header->size, sizeof(header->size)); + size = (size_t)tar_atol(header->size, sizeof(header->size)); err = read_body_to_string(a, tar, &(tar->acl_text), h, unconsumed); if (err != ARCHIVE_OK) return (err); @@ -1021,7 +1022,7 @@ read_body_to_string(struct archive_read *a, struct tar *tar, } /* Fail if we can't make our buffer big enough. */ - if (archive_string_ensure(as, size+1) == NULL) { + if (archive_string_ensure(as, (size_t)size+1) == NULL) { archive_set_error(&a->archive, ENOMEM, "No memory"); return (ARCHIVE_FATAL); @@ -1030,15 +1031,15 @@ read_body_to_string(struct archive_read *a, struct tar *tar, tar_flush_unconsumed(a, unconsumed); /* Read the body into the string. */ - *unconsumed = (size + 511) & ~ 511; + *unconsumed = (size_t)((size + 511) & ~ 511); src = __archive_read_ahead(a, *unconsumed, NULL); if (src == NULL) { *unconsumed = 0; return (ARCHIVE_FATAL); } - memcpy(as->s, src, size); + memcpy(as->s, src, (size_t)size); as->s[size] = '\0'; - as->length = size; + as->length = (size_t)size; return (ARCHIVE_OK); } @@ -1068,7 +1069,8 @@ header_common(struct archive_read *a, struct tar *tar, archive_string_empty(&(tar->entry_linkpath)); /* Parse out the numeric fields (all are octal) */ - archive_entry_set_mode(entry, tar_atol(header->mode, sizeof(header->mode))); + archive_entry_set_mode(entry, + (mode_t)tar_atol(header->mode, sizeof(header->mode))); archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid))); archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid))); tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size)); @@ -1310,13 +1312,13 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, * Q: Is the above idea really possible? Even * when there are GNU or pax extension entries? */ - data = __archive_read_ahead(a, size, NULL); + data = __archive_read_ahead(a, (size_t)size, NULL); if (data == NULL) { *unconsumed = 0; return (ARCHIVE_FATAL); } - archive_entry_copy_mac_metadata(entry, data, size); - *unconsumed = (size + 511) & ~ 511; + archive_entry_copy_mac_metadata(entry, data, (size_t)size); + *unconsumed = (size_t)((size + 511) & ~ 511); tar_flush_unconsumed(a, unconsumed); return (tar_read_header(a, tar, entry, unconsumed)); } @@ -1424,9 +1426,9 @@ header_ustar(struct archive_read *a, struct tar *tar, /* Parse out device numbers only for char and block specials. */ if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { - archive_entry_set_rdevmajor(entry, + archive_entry_set_rdevmajor(entry, (dev_t) tar_atol(header->rdevmajor, sizeof(header->rdevmajor))); - archive_entry_set_rdevminor(entry, + archive_entry_set_rdevminor(entry, (dev_t) tar_atol(header->rdevminor, sizeof(header->rdevminor))); } @@ -1663,6 +1665,11 @@ pax_attribute(struct archive_read *a, struct tar *tar, long n; int err = ARCHIVE_OK, r; +#ifndef __FreeBSD__ + if (value == NULL) + value = ""; /* Disable compiler warning; do not pass + * NULL pointer to strlen(). */ +#endif switch (key[0]) { case 'G': /* GNU "0.0" sparse pax format. */ @@ -1709,11 +1716,11 @@ pax_attribute(struct archive_read *a, struct tar *tar, /* GNU "1.0" sparse pax format */ if (strcmp(key, "GNU.sparse.major") == 0) { - tar->sparse_gnu_major = tar_atol10(value, strlen(value)); + tar->sparse_gnu_major = (int)tar_atol10(value, strlen(value)); tar->sparse_gnu_pending = 1; } if (strcmp(key, "GNU.sparse.minor") == 0) { - tar->sparse_gnu_minor = tar_atol10(value, strlen(value)); + tar->sparse_gnu_minor = (int)tar_atol10(value, strlen(value)); tar->sparse_gnu_pending = 1; } if (strcmp(key, "GNU.sparse.name") == 0) { @@ -1796,20 +1803,20 @@ pax_attribute(struct archive_read *a, struct tar *tar, } } else if (strcmp(key, "SCHILY.devmajor") == 0) { archive_entry_set_rdevmajor(entry, - tar_atol10(value, strlen(value))); + (dev_t)tar_atol10(value, strlen(value))); } else if (strcmp(key, "SCHILY.devminor") == 0) { archive_entry_set_rdevminor(entry, - tar_atol10(value, strlen(value))); + (dev_t)tar_atol10(value, strlen(value))); } else if (strcmp(key, "SCHILY.fflags") == 0) { archive_entry_copy_fflags_text(entry, value); } else if (strcmp(key, "SCHILY.dev") == 0) { archive_entry_set_dev(entry, - tar_atol10(value, strlen(value))); + (dev_t)tar_atol10(value, strlen(value))); } else if (strcmp(key, "SCHILY.ino") == 0) { archive_entry_set_ino(entry, tar_atol10(value, strlen(value))); } else if (strcmp(key, "SCHILY.nlink") == 0) { - archive_entry_set_nlink(entry, + archive_entry_set_nlink(entry, (unsigned) tar_atol10(value, strlen(value))); } else if (strcmp(key, "SCHILY.realsize") == 0) { tar->realsize = tar_atol10(value, strlen(value)); @@ -2018,9 +2025,9 @@ header_gnutar(struct archive_read *a, struct tar *tar, /* Parse out device numbers only for char and block specials */ if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { - archive_entry_set_rdevmajor(entry, + archive_entry_set_rdevmajor(entry, (dev_t) tar_atol(header->rdevmajor, sizeof(header->rdevmajor))); - archive_entry_set_rdevminor(entry, + archive_entry_set_rdevminor(entry, (dev_t) tar_atol(header->rdevminor, sizeof(header->rdevminor))); } else archive_entry_set_rdev(entry, 0); @@ -2255,7 +2262,8 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar, * don't require this, but they should. */ do { - bytes_read = readline(a, tar, &p, tar_min(*remaining, 100), unconsumed); + bytes_read = readline(a, tar, &p, + (ssize_t)tar_min(*remaining, 100), unconsumed); if (bytes_read <= 0) return (ARCHIVE_FATAL); *remaining -= bytes_read; @@ -2296,7 +2304,7 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) remaining = tar->entry_bytes_remaining; /* Parse entries. */ - entries = gnu_sparse_10_atol(a, tar, &remaining, unconsumed); + entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed); if (entries < 0) return (ARCHIVE_FATAL); /* Parse the individual entries. */ @@ -2314,11 +2322,11 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) } /* Skip rest of block... */ tar_flush_unconsumed(a, unconsumed); - bytes_read = tar->entry_bytes_remaining - remaining; + bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining); to_skip = 0x1ff & -bytes_read; if (to_skip != __archive_read_consume(a, to_skip)) return (ARCHIVE_FATAL); - return (bytes_read + to_skip); + return ((ssize_t)(bytes_read + to_skip)); } /* diff --git a/contrib/libarchive/libarchive/archive_read_support_format_xar.c b/contrib/libarchive/libarchive/archive_read_support_format_xar.c index 92569bb..733011c 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_xar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_xar.c @@ -183,9 +183,9 @@ struct xar_file { time_t mtime; time_t atime; struct archive_string uname; - uid_t uid; + int64_t uid; struct archive_string gname; - gid_t gid; + int64_t gid; mode_t mode; dev_t dev; dev_t devmajor; @@ -602,7 +602,8 @@ read_toc(struct archive_read *a) r = move_reading_point(a, xar->toc_chksum_offset); if (r != ARCHIVE_OK) return (r); - b = __archive_read_ahead(a, xar->toc_chksum_size, &bytes); + b = __archive_read_ahead(a, + (size_t)xar->toc_chksum_size, &bytes); if (bytes < 0) return ((int)bytes); if ((uint64_t)bytes < xar->toc_chksum_size) { @@ -611,7 +612,8 @@ read_toc(struct archive_read *a) "Truncated archive file"); return (ARCHIVE_FATAL); } - r = checksum_final(a, b, xar->toc_chksum_size, NULL, 0); + r = checksum_final(a, b, + (size_t)xar->toc_chksum_size, NULL, 0); __archive_read_consume(a, xar->toc_chksum_size); xar->offset += xar->toc_chksum_size; if (r != ARCHIVE_OK) @@ -2065,7 +2067,7 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list) xar->file->hdnext = xar->hdlink_orgs; xar->hdlink_orgs = xar->file; } else { - xar->file->link = atol10(attr->value, + xar->file->link = (unsigned)atol10(attr->value, strlen(attr->value)); if (xar->file->link > 0) if (add_link(a, xar, xar->file) != ARCHIVE_OK) { @@ -2761,7 +2763,7 @@ xml_data(void *userData, const char *s, int len) xar->file->has |= HAS_MODE; xar->file->mode = (xar->file->mode & AE_IFMT) | - (atol8(s, len) & ~AE_IFMT); + ((mode_t)(atol8(s, len)) & ~AE_IFMT); break; case FILE_GROUP: xar->file->has |= HAS_GID; @@ -3076,12 +3078,15 @@ xml2_xmlattr_setup(struct archive_read *a, attr->name = strdup( (const char *)xmlTextReaderConstLocalName(reader)); if (attr->name == NULL) { + free(attr); archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } attr->value = strdup( (const char *)xmlTextReaderConstValue(reader)); if (attr->value == NULL) { + free(attr->name); + free(attr); archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } diff --git a/contrib/libarchive/libarchive/archive_read_support_format_zip.c b/contrib/libarchive/libarchive/archive_read_support_format_zip.c index 60811be..015b8ac 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_zip.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_zip.c @@ -38,17 +38,19 @@ __FBSDID("$FreeBSD$"); #endif #include "archive.h" +#include "archive_endian.h" #include "archive_entry.h" #include "archive_entry_locale.h" #include "archive_private.h" +#include "archive_rb.h" #include "archive_read_private.h" -#include "archive_endian.h" #ifndef HAVE_ZLIB_H #include "archive_crc32.h" #endif struct zip_entry { + struct archive_rb_node node; int64_t local_header_offset; int64_t compressed_size; int64_t uncompressed_size; @@ -71,11 +73,13 @@ struct zip { size_t central_directory_size; size_t central_directory_entries; char have_central_directory; + int64_t offset; /* List of entries (seekable Zip only) */ size_t entries_remaining; struct zip_entry *zip_entries; struct zip_entry *entry; + struct archive_rb_tree tree; size_t unconsumed; @@ -275,13 +279,37 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid) } static int +cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2) +{ + const struct zip_entry *e1 = (const struct zip_entry *)n1; + const struct zip_entry *e2 = (const struct zip_entry *)n2; + + return ((int)(e2->local_header_offset - e1->local_header_offset)); +} + +static int +cmp_key(const struct archive_rb_node *n, const void *key) +{ + /* This function won't be called */ + (void)n; /* UNUSED */ + (void)key; /* UNUSED */ + return 1; +} + +static int slurp_central_directory(struct archive_read *a, struct zip *zip) { unsigned i; + static const struct archive_rb_tree_ops rb_ops = { + &cmp_node, &cmp_key + }; __archive_read_seek(a, zip->central_directory_offset, SEEK_SET); + zip->offset = zip->central_directory_offset; + __archive_rb_tree_init(&zip->tree, &rb_ops); - zip->zip_entries = calloc(zip->central_directory_entries, sizeof(struct zip_entry)); + zip->zip_entries = calloc(zip->central_directory_entries, + sizeof(struct zip_entry)); for (i = 0; i < zip->central_directory_entries; ++i) { struct zip_entry *zip_entry = &zip->zip_entries[i]; size_t filename_length, extra_length, comment_length; @@ -300,7 +328,7 @@ slurp_central_directory(struct archive_read *a, struct zip *zip) zip_entry->system = p[5]; /* version_required = archive_le16dec(p + 6); */ zip_entry->flags = archive_le16dec(p + 8); - zip_entry->compression = archive_le16dec(p + 10); + zip_entry->compression = (char)archive_le16dec(p + 10); zip_entry->mtime = zip_time(p + 12); zip_entry->crc32 = archive_le32dec(p + 16); zip_entry->compressed_size = archive_le32dec(p + 20); @@ -320,6 +348,8 @@ slurp_central_directory(struct archive_read *a, struct zip *zip) if (zip_entry->system == 3) { zip_entry->mode = external_attributes >> 16; } + /* Register an entry to RB tree to sort it by file offset. */ + __archive_rb_tree_insert_node(&zip->tree, &zip_entry->node); /* We don't read the filename until we get to the local file header. Reading it here would speed up @@ -333,19 +363,27 @@ slurp_central_directory(struct archive_read *a, struct zip *zip) 46 + filename_length + extra_length + comment_length); } - /* TODO: Sort zip entries by file offset so that we - can optimize get_next_header() to use skip instead of - seek. */ - return ARCHIVE_OK; } +static int64_t +zip_read_consume(struct archive_read *a, int64_t bytes) +{ + struct zip *zip = (struct zip *)a->format->data; + int64_t skip; + + skip = __archive_read_consume(a, bytes); + if (skip > 0) + zip->offset += skip; + return (skip); +} + static int archive_read_format_zip_seekable_read_header(struct archive_read *a, struct archive_entry *entry) { struct zip *zip = (struct zip *)a->format->data; - int r; + int r, ret = ARCHIVE_OK; a->archive.archive_format = ARCHIVE_FORMAT_ZIP; if (a->archive.archive_format_name == NULL) @@ -356,26 +394,33 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a, zip->entries_remaining = zip->central_directory_entries; if (r != ARCHIVE_OK) return r; - zip->entry = zip->zip_entries; - } else { - ++zip->entry; + /* Get first entry whose local header offset is lower than + * other entries in the archive file. */ + zip->entry = + (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree); + } else if (zip->entry != NULL) { + /* Get next entry in local header offset order. */ + zip->entry = (struct zip_entry *)__archive_rb_tree_iterate( + &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT); } - if (zip->entries_remaining <= 0) + if (zip->entries_remaining <= 0 || zip->entry == NULL) return ARCHIVE_EOF; --zip->entries_remaining; - /* TODO: If entries are sorted by offset within the file, we - should be able to skip here instead of seeking. Skipping is - typically faster (easier for I/O layer to optimize). */ - __archive_read_seek(a, zip->entry->local_header_offset, SEEK_SET); + if (zip->offset != zip->entry->local_header_offset) { + __archive_read_seek(a, zip->entry->local_header_offset, + SEEK_SET); + zip->offset = zip->entry->local_header_offset; + } zip->unconsumed = 0; r = zip_read_local_file_header(a, entry, zip); if (r != ARCHIVE_OK) return r; if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) { const void *p; - size_t linkname_length = archive_entry_size(entry); + struct archive_string_conv *sconv; + size_t linkname_length = (size_t)archive_entry_size(entry); archive_entry_set_size(entry, 0); p = __archive_read_ahead(a, linkname_length, NULL); @@ -385,17 +430,40 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a, return ARCHIVE_FATAL; } + sconv = zip->sconv; + if (sconv == NULL && (zip->entry->flags & ZIP_UTF8_NAME)) + sconv = zip->sconv_utf8; + if (sconv == NULL) + sconv = zip->sconv_default; if (archive_entry_copy_symlink_l(entry, p, linkname_length, - NULL) != 0) { - /* NOTE: If the last argument is NULL, this will - * fail only by memeory allocation failure. */ - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Symlink"); - return (ARCHIVE_FATAL); + sconv) != 0) { + if (errno != ENOMEM && sconv == zip->sconv_utf8 && + (zip->entry->flags & ZIP_UTF8_NAME)) + archive_entry_copy_symlink_l(entry, p, + linkname_length, NULL); + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Symlink"); + return (ARCHIVE_FATAL); + } + /* + * Since there is no character-set regulation for + * symlink name, do not report the conversion error + * in an automatic conversion. + */ + if (sconv != zip->sconv_utf8 || + (zip->entry->flags & ZIP_UTF8_NAME) == 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Symlink cannot be converted " + "from %s to current locale.", + archive_string_conversion_charset_name( + sconv)); + ret = ARCHIVE_WARN; + } } - /* TODO: handle character-set issues? */ } - return ARCHIVE_OK; + return (ret); } static int @@ -489,7 +557,7 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a, memset(zip->entry, 0, sizeof(struct zip_entry)); /* Search ahead for the next local file header. */ - __archive_read_consume(a, zip->unconsumed); + zip_read_consume(a, zip->unconsumed); zip->unconsumed = 0; for (;;) { int64_t skipped = 0; @@ -509,7 +577,7 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a, if (p[2] == '\003' && p[3] == '\004') { /* Regular file entry. */ - __archive_read_consume(a, skipped); + zip_read_consume(a, skipped); return zip_read_local_file_header(a, entry, zip); } @@ -520,7 +588,7 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a, ++p; ++skipped; } - __archive_read_consume(a, skipped); + zip_read_consume(a, skipped); } } @@ -569,7 +637,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, version = p[4]; zip_entry->system = p[5]; zip_entry->flags = archive_le16dec(p + 6); - zip_entry->compression = archive_le16dec(p + 8); + zip_entry->compression = (char)archive_le16dec(p + 8); zip_entry->mtime = zip_time(p + 10); local_crc32 = archive_le32dec(p + 14); compressed_size = archive_le32dec(p + 18); @@ -577,7 +645,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, filename_length = archive_le16dec(p + 26); extra_length = archive_le16dec(p + 28); - __archive_read_consume(a, 30); + zip_read_consume(a, 30); if (zip->have_central_directory) { /* If we read the central dir entry, we must have size information @@ -647,7 +715,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, archive_string_conversion_charset_name(sconv)); ret = ARCHIVE_WARN; } - __archive_read_consume(a, filename_length); + zip_read_consume(a, filename_length); if (zip_entry->mode == 0) { /* Especially in streaming mode, we can end up @@ -659,14 +727,14 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, if (len > 0 && wp[len - 1] == L'/') zip_entry->mode = AE_IFDIR | 0777; else - zip_entry->mode = AE_IFREG | 0777; + zip_entry->mode = AE_IFREG | 0666; } else { cp = archive_entry_pathname(entry); len = (cp != NULL)?strlen(cp):0; if (len > 0 && cp[len - 1] == '/') zip_entry->mode = AE_IFDIR | 0777; else - zip_entry->mode = AE_IFREG | 0777; + zip_entry->mode = AE_IFREG | 0666; } } @@ -677,7 +745,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, return (ARCHIVE_FATAL); } process_extra(h, extra_length, zip_entry); - __archive_read_consume(a, extra_length); + zip_read_consume(a, extra_length); /* Populate some additional entry fields: */ archive_entry_set_mode(entry, zip_entry->mode); @@ -774,7 +842,7 @@ archive_read_format_zip_read_data(struct archive_read *a, return (ARCHIVE_FAILED); } - __archive_read_consume(a, zip->unconsumed); + zip_read_consume(a, zip->unconsumed); zip->unconsumed = 0; switch(zip->entry->compression) { @@ -926,7 +994,7 @@ zip_read_data_none(struct archive_read *a, const void **_buff, return (ARCHIVE_FATAL); } if (bytes_avail > zip->entry_bytes_remaining) - bytes_avail = zip->entry_bytes_remaining; + bytes_avail = (ssize_t)zip->entry_bytes_remaining; } *size = bytes_avail; zip->entry_bytes_remaining -= bytes_avail; @@ -990,7 +1058,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, compressed_buff = __archive_read_ahead(a, 1, &bytes_avail); if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END) && bytes_avail > zip->entry_bytes_remaining) { - bytes_avail = zip->entry_bytes_remaining; + bytes_avail = (ssize_t)zip->entry_bytes_remaining; } if (bytes_avail <= 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -1030,7 +1098,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, /* Consume as much as the compressor actually used. */ bytes_avail = zip->stream.total_in; - __archive_read_consume(a, bytes_avail); + zip_read_consume(a, bytes_avail); zip->entry_bytes_remaining -= bytes_avail; zip->entry_compressed_bytes_read += bytes_avail; @@ -1070,14 +1138,11 @@ archive_read_format_zip_read_data_skip(struct archive_read *a) /* If we've already read to end of data, we're done. */ if (zip->end_of_entry) return (ARCHIVE_OK); - /* If we're seeking, we're done. */ - if (zip->have_central_directory) - return (ARCHIVE_OK); /* So we know we're streaming... */ if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)) { /* We know the compressed length, so we can just skip. */ - int64_t bytes_skipped = __archive_read_consume(a, + int64_t bytes_skipped = zip_read_consume(a, zip->entry_bytes_remaining + zip->unconsumed); if (bytes_skipped < 0) return (ARCHIVE_FATAL); @@ -1100,11 +1165,11 @@ archive_read_format_zip_read_data_skip(struct archive_read *a) if (r != ARCHIVE_OK) return (r); } - break; + return ARCHIVE_OK; #endif default: /* Uncompressed or unknown. */ /* Scan for a PK\007\010 signature. */ - __archive_read_consume(a, zip->unconsumed); + zip_read_consume(a, zip->unconsumed); zip->unconsumed = 0; for (;;) { const char *p, *buff; @@ -1122,14 +1187,13 @@ archive_read_format_zip_read_data_skip(struct archive_read *a) else if (p[3] == '\007') { p += 1; } else if (p[3] == '\010' && p[2] == '\007' && p[1] == 'K' && p[0] == 'P') { - __archive_read_consume(a, p - buff + 16); + zip_read_consume(a, p - buff + 16); return ARCHIVE_OK; } else { p += 4; } } - __archive_read_consume(a, p - buff); + zip_read_consume(a, p - buff); } } - return ARCHIVE_OK; } static int diff --git a/contrib/libarchive/libarchive/archive_string.c b/contrib/libarchive/libarchive/archive_string.c index b5563df..9d27390 100644 --- a/contrib/libarchive/libarchive/archive_string.c +++ b/contrib/libarchive/libarchive/archive_string.c @@ -61,9 +61,6 @@ __FBSDID("$FreeBSD$"); #include <windows.h> #include <locale.h> #endif -#if defined(__APPLE__) -#include <CoreServices/CoreServices.h> -#endif #include "archive_endian.h" #include "archive_private.h" @@ -115,11 +112,6 @@ struct archive_string_conv { #endif /* A temporary buffer for normalization. */ struct archive_string utftmp; -#if defined(__APPLE__) - UnicodeToTextInfo uniInfo; - struct archive_string utf16nfc; - struct archive_string utf16nfd; -#endif int (*converter[2])(struct archive_string *, const void *, size_t, struct archive_string_conv *); int nconverter; @@ -164,29 +156,29 @@ static int archive_string_append_from_wcs_in_codepage(struct archive_string *, static int is_big_endian(void); static int strncat_in_codepage(struct archive_string *, const void *, size_t, struct archive_string_conv *); -static int win_strncat_from_utf16be(struct archive_string *, const void *, size_t, - struct archive_string_conv *); -static int win_strncat_from_utf16le(struct archive_string *, const void *, size_t, - struct archive_string_conv *); -static int win_strncat_to_utf16be(struct archive_string *, const void *, size_t, - struct archive_string_conv *); -static int win_strncat_to_utf16le(struct archive_string *, const void *, size_t, - struct archive_string_conv *); -#endif -static int best_effort_strncat_from_utf16be(struct archive_string *, const void *, +static int win_strncat_from_utf16be(struct archive_string *, const void *, size_t, struct archive_string_conv *); -static int best_effort_strncat_from_utf16le(struct archive_string *, const void *, +static int win_strncat_from_utf16le(struct archive_string *, const void *, size_t, struct archive_string_conv *); -static int best_effort_strncat_to_utf16be(struct archive_string *, const void *, +static int win_strncat_to_utf16be(struct archive_string *, const void *, size_t, struct archive_string_conv *); -static int best_effort_strncat_to_utf16le(struct archive_string *, const void *, +static int win_strncat_to_utf16le(struct archive_string *, const void *, size_t, struct archive_string_conv *); +#endif +static int best_effort_strncat_from_utf16be(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int best_effort_strncat_from_utf16le(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int best_effort_strncat_to_utf16be(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int best_effort_strncat_to_utf16le(struct archive_string *, + const void *, size_t, struct archive_string_conv *); #if defined(HAVE_ICONV) static int iconv_strncat_in_locale(struct archive_string *, const void *, size_t, struct archive_string_conv *); #endif -static int best_effort_strncat_in_locale(struct archive_string *, const void *, - size_t, struct archive_string_conv *); +static int best_effort_strncat_in_locale(struct archive_string *, + const void *, size_t, struct archive_string_conv *); static int _utf8_to_unicode(uint32_t *, const char *, size_t); static int utf8_to_unicode(uint32_t *, const char *, size_t); static inline uint32_t combine_surrogate_pair(uint32_t, uint32_t); @@ -201,10 +193,8 @@ static int strncat_from_utf8_to_utf8(struct archive_string *, const void *, size_t, struct archive_string_conv *); static int archive_string_normalize_C(struct archive_string *, const void *, size_t, struct archive_string_conv *); -#if defined(__APPLE__) static int archive_string_normalize_D(struct archive_string *, const void *, size_t, struct archive_string_conv *); -#endif static int archive_string_append_unicode(struct archive_string *, const void *, size_t, struct archive_string_conv *); @@ -238,7 +228,8 @@ archive_string_concat(struct archive_string *dest, struct archive_string *src) } void -archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src) +archive_wstring_concat(struct archive_wstring *dest, + struct archive_wstring *src) { if (archive_wstring_append(dest, src->s, src->length) == NULL) __archive_errx(1, "Out of memory"); @@ -443,10 +434,7 @@ int archive_wstring_append_from_mbs(struct archive_wstring *dest, const char *p, size_t len) { - int r = archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL); - if (r != 0 && errno == ENOMEM) - __archive_errx(1, "No memory"); - return (r); + return archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL); } static int @@ -479,7 +467,8 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, *ws++ = (wchar_t)*mp++; count++; } - } else if (sc != NULL && (sc->flag & SCONV_NORMALIZATION_C)) { + } else if (sc != NULL && + (sc->flag & (SCONV_NORMALIZATION_C | SCONV_NORMALIZATION_D))) { /* * Normalize UTF-8 and UTF-16BE and convert it directly * to UTF-16 as wchar_t. @@ -495,18 +484,23 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, if (sc->flag & SCONV_FROM_UTF16) { /* * UTF-16BE/LE NFD ===> UTF-16 NFC + * UTF-16BE/LE NFC ===> UTF-16 NFD */ count = utf16nbytes(s, length); } else { /* * UTF-8 NFD ===> UTF-16 NFC + * UTF-8 NFC ===> UTF-16 NFD */ count = mbsnbytes(s, length); } u16.s = (char *)dest->s; u16.length = dest->length << 1;; u16.buffer_length = dest->buffer_length; - ret = archive_string_normalize_C(&u16, s, count, sc); + if (sc->flag & SCONV_NORMALIZATION_C) + ret = archive_string_normalize_C(&u16, s, count, sc); + else + ret = archive_string_normalize_D(&u16, s, count, sc); dest->s = (wchar_t *)u16.s; dest->length = u16.length >> 1; dest->buffer_length = u16.buffer_length; @@ -519,7 +513,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, if (NULL == archive_wstring_ensure(dest, dest->length + count + 1)) return (-1); - wmemcpy(dest->s + dest->length, (wchar_t *)s, count); + wmemcpy(dest->s + dest->length, (const wchar_t *)s, count); if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) { uint16_t *u16 = (uint16_t *)(dest->s + dest->length); int b; @@ -537,6 +531,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, } } else { DWORD mbflag; + size_t buffsize; if (sc == NULL) mbflag = 0; @@ -548,83 +543,30 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, } else mbflag = MB_PRECOMPOSED; - if (length == 0) { - /* - * We do not need to convert any characters but make - * sure `dest' has a valid buffer(no NULL pointer). - */ - if (NULL == archive_wstring_ensure(dest, - dest->length + 1)) + buffsize = dest->length + length + 1; + do { + /* Allocate memory for WCS. */ + if (NULL == archive_wstring_ensure(dest, buffsize)) return (-1); - dest->s[dest->length] = L'\0'; - return (0); - } - - /* - * Count how many bytes are needed for WCS. - */ - count = MultiByteToWideChar(from_cp, - mbflag, s, length, NULL, 0); - if (count == 0) { - if (dest->s == NULL) { - if (NULL == archive_wstring_ensure(dest, - dest->length + 1)) - return (-1); + /* Convert MBS to WCS. */ + count = MultiByteToWideChar(from_cp, + mbflag, s, length, dest->s + dest->length, + (dest->buffer_length >> 1) -1); + if (count == 0 && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + /* Expand the WCS buffer. */ + buffsize = dest->buffer_length << 1; + continue; } - dest->s[dest->length] = L'\0'; - return (-1); - } - /* Allocate memory for WCS. */ - if (NULL == archive_wstring_ensure(dest, - dest->length + count + 1)) - return (-1); - /* Convert MBS to WCS. */ - count = MultiByteToWideChar(from_cp, - mbflag, s, length, dest->s + dest->length, count); - if (count == 0) - ret = -1; + if (count == 0 && length != 0) + ret = -1; + } while (0); } dest->length += count; dest->s[dest->length] = L'\0'; return (ret); } -#elif defined(HAVE_MBSNRTOWCS) - -/* - * Convert MBS to WCS. - * Note: returns -1 if conversion fails. - */ -int -archive_wstring_append_from_mbs(struct archive_wstring *dest, - const char *p, size_t len) -{ - size_t r; - /* - * No single byte will be more than one wide character, - * so this length estimate will always be big enough. - */ - size_t wcs_length = len; - size_t mbs_length = len; - const char *mbs = p; - wchar_t *wcs; - mbstate_t shift_state; - - memset(&shift_state, 0, sizeof(shift_state)); - if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1)) - __archive_errx(1, - "No memory for archive_wstring_append_from_mbs()"); - wcs = dest->s + dest->length; - r = mbsnrtowcs(wcs, &mbs, mbs_length, wcs_length, &shift_state); - if (r != (size_t)-1) { - dest->length += r; - dest->s[dest->length] = L'\0'; - return (0); - } - dest->s[dest->length] = L'\0'; - return (-1); -} - #else /* @@ -636,6 +578,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, const char *p, size_t len) { size_t r; + int ret_val = 0; /* * No single byte will be more than one wide character, * so this length estimate will always be big enough. @@ -650,23 +593,36 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, memset(&shift_state, 0, sizeof(shift_state)); #endif if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1)) - __archive_errx(1, - "No memory for archive_wstring_append_from_mbs()"); + return (-1); wcs = dest->s + dest->length; /* * We cannot use mbsrtowcs/mbstowcs here because those may convert * extra MBS when strlen(p) > len and one wide character consis of * multi bytes. */ - while (wcs_length > 0 && *mbs && mbs_length > 0) { + while (*mbs && mbs_length > 0) { + if (wcs_length == 0) { + dest->length = wcs - dest->s; + dest->s[dest->length] = L'\0'; + wcs_length = mbs_length; + if (NULL == archive_wstring_ensure(dest, + dest->length + wcs_length + 1)) + return (-1); + wcs = dest->s + dest->length; + } #if HAVE_MBRTOWC r = mbrtowc(wcs, mbs, wcs_length, &shift_state); #else r = mbtowc(wcs, mbs, wcs_length); #endif if (r == (size_t)-1 || r == (size_t)-2) { - dest->s[dest->length] = L'\0'; - return (-1); + ret_val = -1; + if (errno == EILSEQ) { + ++mbs; + --mbs_length; + continue; + } else + break; } if (r == 0 || r > mbs_length) break; @@ -677,7 +633,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, } dest->length = wcs - dest->s; dest->s[dest->length] = L'\0'; - return (0); + return (ret_val); } #endif @@ -697,10 +653,7 @@ int archive_string_append_from_wcs(struct archive_string *as, const wchar_t *w, size_t len) { - int r = archive_string_append_from_wcs_in_codepage(as, w, len, NULL); - if (r != 0 && errno == ENOMEM) - __archive_errx(1, "No memory"); - return (r); + return archive_string_append_from_wcs_in_codepage(as, w, len, NULL); } static int @@ -792,73 +745,6 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as, return (defchar_used?-1:ret); } -#elif defined(HAVE_WCSNRTOMBS) - -/* - * Translates a wide character string into current locale character set - * and appends to the archive_string. Note: returns -1 if conversion - * fails. - */ -int -archive_string_append_from_wcs(struct archive_string *as, - const wchar_t *w, size_t len) -{ - mbstate_t shift_state; - size_t r, ndest, nwc; - char *dest; - const wchar_t *wp, *wpp; - int ret_val = 0; - - wp = w; - nwc = len; - ndest = len * 2; - /* Initialize the shift state. */ - memset(&shift_state, 0, sizeof(shift_state)); - while (nwc > 0) { - /* Allocate buffer for MBS. */ - if (archive_string_ensure(as, as->length + ndest + 1) == NULL) - __archive_errx(1, "Out of memory"); - - dest = as->s + as->length; - wpp = wp; - r = wcsnrtombs(dest, &wp, nwc, - as->buffer_length - as->length -1, - &shift_state); - if (r == (size_t)-1) { - if (errno == EILSEQ) { - /* Retry conversion just for safe WCS. */ - size_t xwc = wp - wpp; - wp = wpp; - r = wcsnrtombs(dest, &wp, xwc, - as->buffer_length - as->length -1, - &shift_state); - if (r == (size_t)-1) - /* This would not happen. */ - return (-1); - as->length += r; - nwc -= wp - wpp; - /* Skip an illegal wide char. */ - as->s[as->length++] = '?'; - wp++; - nwc--; - ret_val = -1; - continue; - } else { - ret_val = -1; - break; - } - } - as->length += r; - if (wp == NULL || (wp - wpp) >= (int64_t)nwc) - break; - /* Get a remaining WCS lenth. */ - nwc -= wp - wpp; - } - /* All wide characters are translated to MBS. */ - as->s[as->length] = '\0'; - return (ret_val); -} - #elif defined(HAVE_WCTOMB) || defined(HAVE_WCRTOMB) /* @@ -893,7 +779,7 @@ archive_string_append_from_wcs(struct archive_string *as, * as->s is still NULL. */ if (archive_string_ensure(as, as->length + len + 1) == NULL) - __archive_errx(1, "Out of memory"); + return (-1); p = as->s + as->length; end = as->s + as->buffer_length - MB_CUR_MAX -1; @@ -904,7 +790,7 @@ archive_string_append_from_wcs(struct archive_string *as, /* Re-allocate buffer for MBS. */ if (archive_string_ensure(as, as->length + len * 2 + 1) == NULL) - __archive_errx(1, "Out of memory"); + return (-1); p = as->s + as->length; end = as->s + as->buffer_length - MB_CUR_MAX -1; } @@ -946,6 +832,7 @@ archive_string_append_from_wcs(struct archive_string *as, (void)as;/* UNUSED */ (void)w;/* UNUSED */ (void)len;/* UNUSED */ + errno = ENOSYS; return (-1); } @@ -987,27 +874,6 @@ add_sconv_object(struct archive *a, struct archive_string_conv *sc) *psc = sc; } -#if defined(__APPLE__) - -static int -createUniInfo(struct archive_string_conv *sconv) -{ - UnicodeMapping map; - OSStatus err; - - map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeNoSubset, kUnicode16BitFormat); - map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeHFSPlusDecompVariant, kUnicode16BitFormat); - map.mappingVersion = kUnicodeUseLatestMapping; - - sconv->uniInfo = NULL; - err = CreateUnicodeToTextInfo(&map, &(sconv->uniInfo)); - return ((err == noErr)? 0: -1); -} - -#endif /* __APPLE__ */ - static void add_converter(struct archive_string_conv *sc, int (*converter) (struct archive_string *, const void *, size_t, @@ -1066,9 +932,11 @@ setup_converter(struct archive_string_conv *sc) if (sc->flag & SCONV_BEST_EFFORT) { if (sc->flag & SCONV_TO_UTF16BE) - add_converter(sc, best_effort_strncat_to_utf16be); + add_converter(sc, + best_effort_strncat_to_utf16be); else - add_converter(sc, best_effort_strncat_to_utf16le); + add_converter(sc, + best_effort_strncat_to_utf16le); } else /* Make sure we have no converter. */ sc->nconverter = 0; @@ -1082,12 +950,9 @@ setup_converter(struct archive_string_conv *sc) /* * At least we should normalize a UTF-16BE string. */ -#if defined(__APPLE__) if (sc->flag & SCONV_NORMALIZATION_D) add_converter(sc,archive_string_normalize_D); - else -#endif - if (sc->flag & SCONV_NORMALIZATION_C) + else if (sc->flag & SCONV_NORMALIZATION_C) add_converter(sc, archive_string_normalize_C); if (sc->flag & SCONV_TO_UTF8) { @@ -1135,12 +1000,9 @@ setup_converter(struct archive_string_conv *sc) /* * At least we should normalize a UTF-8 string. */ -#if defined(__APPLE__) if (sc->flag & SCONV_NORMALIZATION_D) add_converter(sc,archive_string_normalize_D); - else -#endif - if (sc->flag & SCONV_NORMALIZATION_C) + else if (sc->flag & SCONV_NORMALIZATION_C) add_converter(sc, archive_string_normalize_C); /* @@ -1174,6 +1036,16 @@ setup_converter(struct archive_string_conv *sc) #if HAVE_ICONV if (sc->cd != (iconv_t)-1) { add_converter(sc, iconv_strncat_in_locale); + /* + * iconv generally does not support UTF-8-MAC and so + * we have to the output of iconv from NFC to NFD if + * need. + */ + if ((sc->flag & SCONV_FROM_CHARSET) && + (sc->flag & SCONV_TO_UTF8)) { + if (sc->flag & SCONV_NORMALIZATION_D) + add_converter(sc, archive_string_normalize_D); + } return; } #endif @@ -1253,10 +1125,6 @@ create_sconv_object(const char *fc, const char *tc, return (NULL); } archive_string_init(&sc->utftmp); -#if defined(__APPLE__) - archive_string_init(&sc->utf16nfc); - archive_string_init(&sc->utf16nfd); -#endif if (flag & SCONV_TO_CHARSET) { /* @@ -1335,13 +1203,35 @@ create_sconv_object(const char *fc, const char *tc, if ((flag & SCONV_FROM_CHARSET) && (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8))) { #if defined(__APPLE__) - if (flag & SCONV_TO_UTF8) { - if (createUniInfo(sc) == 0) - flag |= SCONV_NORMALIZATION_D; - } else + if (flag & SCONV_TO_UTF8) + flag |= SCONV_NORMALIZATION_D; + else #endif flag |= SCONV_NORMALIZATION_C; } +#if defined(__APPLE__) + /* + * In case writing an archive file, make sure that a filename + * going to be passed to iconv is a Unicode NFC string since + * a filename in HFS Plus filesystem is a Unicode NFD one and + * iconv cannot handle it with "UTF-8" charset. It is simpler + * than a use of "UTF-8-MAC" charset. + */ + if ((flag & SCONV_TO_CHARSET) && + (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && + !(flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8))) + flag |= SCONV_NORMALIZATION_C; + /* + * In case reading an archive file. make sure that a filename + * will be passed to users is a Unicode NFD string in order to + * correctly compare the filename with other one which comes + * from HFS Plus filesystem. + */ + if ((flag & SCONV_FROM_CHARSET) && + !(flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && + (flag & SCONV_TO_UTF8)) + flag |= SCONV_NORMALIZATION_D; +#endif #if defined(HAVE_ICONV) sc->cd_w = (iconv_t)-1; @@ -1353,46 +1243,6 @@ create_sconv_object(const char *fc, const char *tc, (flag & SCONV_WIN_CP)) { /* This case we won't use iconv. */ sc->cd = (iconv_t)-1; -#if defined(__APPLE__) - } else if ((flag & SCONV_FROM_CHARSET) && (flag & SCONV_TO_UTF8)) { - /* - * In case reading an archive file. - * Translate non-Unicode filenames in an archive file to - * UTF-8-MAC filenames. - */ - sc->cd = iconv_open("UTF-8-MAC", fc); - if (sc->cd == (iconv_t)-1) { - if ((sc->flag & SCONV_BEST_EFFORT) && - strcmp(fc, "CP932") == 0) { - sc->cd = iconv_open("UTF-8-MAC", "SJIS"); - if (sc->cd == (iconv_t)-1) { - sc->cd = iconv_open(tc, fc); - if (sc->cd == (iconv_t)-1) - sc->cd = iconv_open(tc, "SJIS"); - } - } else - sc->cd = iconv_open(tc, fc); - } - } else if ((flag & SCONV_TO_CHARSET) && (flag & SCONV_FROM_UTF8)) { - /* - * In case writing an archive file. - * Translate UTF-8-MAC filenames in HFS Plus to non-Unicode - * filenames. - */ - sc->cd = iconv_open(tc, "UTF-8-MAC"); - if (sc->cd == (iconv_t)-1) { - if ((sc->flag & SCONV_BEST_EFFORT) && - strcmp(tc, "CP932") == 0) { - sc->cd = iconv_open("SJIS", "UTF-8-MAC"); - if (sc->cd == (iconv_t)-1) { - sc->cd = iconv_open(tc, fc); - if (sc->cd == (iconv_t)-1) - sc->cd = iconv_open("SJIS", fc); - } - } else - sc->cd = iconv_open(tc, fc); - } -#endif } else { sc->cd = iconv_open(tc, fc); if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) { @@ -1428,7 +1278,7 @@ create_sconv_object(const char *fc, const char *tc, sc->flag = flag; /* - * Setup converters. + * Set up converters. */ setup_converter(sc); @@ -1450,12 +1300,6 @@ free_sconv_object(struct archive_string_conv *sc) if (sc->cd_w != (iconv_t)-1) iconv_close(sc->cd_w); #endif -#if defined(__APPLE__) - archive_string_free(&sc->utf16nfc); - archive_string_free(&sc->utf16nfd); - if (sc->uniInfo != NULL) - DisposeUnicodeToTextInfo(&(sc->uniInfo)); -#endif free(sc); } @@ -1995,11 +1839,37 @@ archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt) #else if ((sc->flag & SCONV_UTF8_LIBARCHIVE_2) == 0) { sc->flag |= SCONV_UTF8_LIBARCHIVE_2; - /* Re-setup string converters. */ + /* Set up string converters. */ setup_converter(sc); } #endif break; + case SCONV_SET_OPT_NORMALIZATION_C: + if ((sc->flag & SCONV_NORMALIZATION_C) == 0) { + sc->flag |= SCONV_NORMALIZATION_C; + sc->flag &= ~SCONV_NORMALIZATION_D; + /* Set up string converters. */ + setup_converter(sc); + } + break; + case SCONV_SET_OPT_NORMALIZATION_D: +#if defined(HAVE_ICONV) + /* + * If iconv will take the string, do not change the + * setting of the normalization. + */ + if (!(sc->flag & SCONV_WIN_CP) && + (sc->flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && + !(sc->flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8))) + break; +#endif + if ((sc->flag & SCONV_NORMALIZATION_D) == 0) { + sc->flag |= SCONV_NORMALIZATION_D; + sc->flag &= ~SCONV_NORMALIZATION_C; + /* Set up string converters. */ + setup_converter(sc); + } + break; default: break; } @@ -2009,8 +1879,8 @@ archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt) * * Copy one archive_string to another in locale conversion. * - * archive_strncpy_in_locale(); - * archive_strcpy_in_locale(); + * archive_strncat_l(); + * archive_strncpy_l(); * */ @@ -2056,15 +1926,15 @@ utf16nbytes(const void *_p, size_t n) } int -archive_strncpy_in_locale(struct archive_string *as, const void *_p, size_t n, +archive_strncpy_l(struct archive_string *as, const void *_p, size_t n, struct archive_string_conv *sc) { as->length = 0; - return (archive_strncat_in_locale(as, _p, n, sc)); + return (archive_strncat_l(as, _p, n, sc)); } int -archive_strncat_in_locale(struct archive_string *as, const void *_p, size_t n, +archive_strncat_l(struct archive_string *as, const void *_p, size_t n, struct archive_string_conv *sc) { const void *s; @@ -2291,7 +2161,6 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc) const char *p = (const char *)_p; size_t r; - (void)sc; /* UNUSED */ #if HAVE_MBRTOWC mbstate_t shift_state; @@ -2315,6 +2184,7 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc) p += r; n -= r; } + (void)sc; /* UNUSED */ return (0); /* All Okey. */ } @@ -2773,8 +2643,8 @@ unicode_to_utf16le(char *p, size_t remaining, uint32_t uc) * If any surrogate pair are found, it would be canonicalized. */ static int -strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p, size_t len, - struct archive_string_conv *sc) +strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p, + size_t len, struct archive_string_conv *sc) { const char *s; char *p, *endp; @@ -3320,119 +3190,222 @@ archive_string_normalize_C(struct archive_string *as, const void *_p, return (ret); } -#if defined(__APPLE__) - -/* - * Normalize UTF-8 characters to Form D and copy the result. - */ static int -archive_string_normalize_D(struct archive_string *as, const void *_p, - size_t len, struct archive_string_conv *sc) +get_nfd(uint32_t *cp1, uint32_t *cp2, uint32_t uc) { - const UniChar *inp; - char *outp; - size_t newsize; - ByteCount inCount, outCount; - ByteCount inAvail, outAvail; - OSStatus err; - int ret, saved_flag; + int t, b; /* - * Convert the current string to UTF-16LE for normalization. - * The character-set of the current string must be UTF-16BE or - * UTF-8. + * These are not converted to NFD on Mac OS. */ - archive_string_empty(&(sc->utf16nfc)); - saved_flag = sc->flag;/* save a flag. */ - sc->flag &= ~(SCONV_TO_UTF16BE | SCONV_TO_UTF8); - sc->flag |= SCONV_TO_UTF16LE; - ret = archive_string_append_unicode(&(sc->utf16nfc), _p, len, sc); - sc->flag = saved_flag;/* restore the saved flag */ - if (archive_strlen(&(sc->utf16nfc)) == 0) { - if (archive_string_ensure(as, as->length + 1) == NULL) - return (-1); - return (ret); - } - + if ((uc >= 0x2000 && uc <= 0x2FFF) || + (uc >= 0xF900 && uc <= 0xFAFF) || + (uc >= 0x2F800 && uc <= 0x2FAFF)) + return (0); /* - * Normalize an NFC string to be an NFD(HFS Plus version). + * Those code points are not converted to NFD on Mac OS. + * I do not know the reason because it is undocumented. + * NFC NFD + * 1109A ==> 11099 110BA + * 1109C ==> 1109B 110BA + * 110AB ==> 110A5 110BA */ - newsize = sc->utf16nfc.length + 2; - if (archive_string_ensure(&(sc->utf16nfd), newsize) == NULL) - return (-1); + if (uc == 0x1109A || uc == 0x1109C || uc == 0x110AB) + return (0); - inp = (UniChar *)sc->utf16nfc.s; - inAvail = archive_strlen(&(sc->utf16nfc)); - sc->utf16nfd.length = 0; - outp = sc->utf16nfd.s; - outAvail = sc->utf16nfd.buffer_length -2; + t = 0; + b = sizeof(u_decomposition_table)/sizeof(u_decomposition_table[0]) -1; + while (b >= t) { + int m = (t + b) / 2; + if (u_decomposition_table[m].nfc < uc) + t = m + 1; + else if (u_decomposition_table[m].nfc > uc) + b = m - 1; + else { + *cp1 = u_decomposition_table[m].cp1; + *cp2 = u_decomposition_table[m].cp2; + return (1); + } + } + return (0); +} - do { - /* Reinitialize all state information. */ - if (ResetUnicodeToTextInfo(sc->uniInfo) != noErr) - goto return_no_changed_data; - - inCount = outCount = 0; - err = ConvertFromUnicodeToText(sc->uniInfo, - inAvail, inp, - kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, - outAvail, &inCount, &outCount, outp); - - if (err == noErr) { - sc->utf16nfd.length = outCount; - sc->utf16nfd.s[sc->utf16nfd.length] = 0; - sc->utf16nfd.s[sc->utf16nfd.length+1] = 0; - } else if (err == kTECOutputBufferFullStatus) { - newsize = inAvail - inCount; - if (newsize > inAvail) - newsize = inAvail; - newsize += sc->utf16nfd.buffer_length + 2; - if (archive_string_ensure(&(sc->utf16nfd), newsize) - == NULL) - return (-1); - outp = sc->utf16nfd.s; - outAvail = sc->utf16nfd.buffer_length -2; - } else - goto return_no_changed_data; - } while (err == kTECOutputBufferFullStatus); +#define REPLACE_UC_WITH(cp) do { \ + uc = cp; \ + ucptr = NULL; \ +} while (0) - /* - * If there is a next-step conversion, we should convert - * a UTF-16LE(NFD) string back to the original Unicode type. - */ - saved_flag = sc->flag;/* save a flag. */ - if (!(sc->flag & - (SCONV_TO_UTF16BE | SCONV_TO_UTF16LE | SCONV_TO_UTF8))) { +/* + * Normalize UTF-8 characters to Form D and copy the result. + */ +static int +archive_string_normalize_D(struct archive_string *as, const void *_p, + size_t len, struct archive_string_conv *sc) +{ + const char *s = (const char *)_p; + char *p, *endp; + uint32_t uc, uc2; + size_t w; + int always_replace, n, n2, ret = 0, spair, ts, tm; + int (*parse)(uint32_t *, const char *, size_t); + size_t (*unparse)(char *, size_t, uint32_t); + + always_replace = 1; + ts = 1;/* text size. */ + if (sc->flag & SCONV_TO_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + if (sc->flag & SCONV_FROM_UTF16BE) + always_replace = 0; + } else if (sc->flag & SCONV_TO_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + if (sc->flag & SCONV_FROM_UTF16LE) + always_replace = 0; + } else if (sc->flag & SCONV_TO_UTF8) { + unparse = unicode_to_utf8; + if (sc->flag & SCONV_FROM_UTF8) + always_replace = 0; + } else { /* * This case is going to be converted to another * character-set through iconv. */ - if (sc->flag & SCONV_FROM_UTF16BE) - sc->flag |= SCONV_TO_UTF16BE; - else if (sc->flag & SCONV_FROM_UTF16LE) - sc->flag |= SCONV_TO_UTF16LE; + always_replace = 0; + if (sc->flag & SCONV_FROM_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + } else if (sc->flag & SCONV_FROM_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + } else { + unparse = unicode_to_utf8; + } + } + + if (sc->flag & SCONV_FROM_UTF16BE) { + parse = utf16be_to_unicode; + tm = 1; + spair = 4;/* surrogate pair size in UTF-16. */ + } else if (sc->flag & SCONV_FROM_UTF16LE) { + parse = utf16le_to_unicode; + tm = 1; + spair = 4;/* surrogate pair size in UTF-16. */ + } else { + parse = cesu8_to_unicode; + tm = ts; + spair = 6;/* surrogate pair size in UTF-8. */ + } + + if (archive_string_ensure(as, as->length + len * tm + ts) == NULL) + return (-1); + + p = as->s + as->length; + endp = as->s + as->buffer_length - ts; + while ((n = parse(&uc, s, len)) != 0) { + const char *ucptr; + uint32_t cp1, cp2; + int SIndex; + struct { + uint32_t uc; + int ccc; + } fdc[FDC_MAX]; + int fdi, fdj; + int ccc; + +check_first_code: + if (n < 0) { + /* Use a replaced unicode character. */ + UNPARSE(p, endp, uc); + s += n*-1; + len -= n*-1; + ret = -1; + continue; + } else if (n == spair || always_replace) + /* uc is converted from a surrogate pair. + * this should be treated as a changed code. */ + ucptr = NULL; else - sc->flag |= SCONV_TO_UTF8; + ucptr = s; + s += n; + len -= n; + + /* Hangul Decomposition. */ + if ((SIndex = uc - HC_SBASE) >= 0 && SIndex < HC_SCOUNT) { + int L = HC_LBASE + SIndex / HC_NCOUNT; + int V = HC_VBASE + (SIndex % HC_NCOUNT) / HC_TCOUNT; + int T = HC_TBASE + SIndex % HC_TCOUNT; + + REPLACE_UC_WITH(L); + WRITE_UC(); + REPLACE_UC_WITH(V); + WRITE_UC(); + if (T != HC_TBASE) { + REPLACE_UC_WITH(T); + WRITE_UC(); + } + continue; + } + if (IS_DECOMPOSABLE_BLOCK(uc) && CCC(uc) != 0) { + WRITE_UC(); + continue; + } + + fdi = 0; + while (get_nfd(&cp1, &cp2, uc) && fdi < FDC_MAX) { + int k; + + for (k = fdi; k > 0; k--) + fdc[k] = fdc[k-1]; + fdc[0].ccc = CCC(cp2); + fdc[0].uc = cp2; + fdi++; + REPLACE_UC_WITH(cp1); + } + + /* Read following code points. */ + while ((n2 = parse(&uc2, s, len)) > 0 && + (ccc = CCC(uc2)) != 0 && fdi < FDC_MAX) { + int j, k; + + s += n2; + len -= n2; + for (j = 0; j < fdi; j++) { + if (fdc[j].ccc > ccc) + break; + } + if (j < fdi) { + for (k = fdi; k > j; k--) + fdc[k] = fdc[k-1]; + fdc[j].ccc = ccc; + fdc[j].uc = uc2; + } else { + fdc[fdi].ccc = ccc; + fdc[fdi].uc = uc2; + } + fdi++; + } + + WRITE_UC(); + for (fdj = 0; fdj < fdi; fdj++) { + REPLACE_UC_WITH(fdc[fdj].uc); + WRITE_UC(); + } + + if (n2 == 0) + break; + REPLACE_UC_WITH(uc2); + n = n2; + ucptr = s; + goto check_first_code; } - sc->flag &= ~(SCONV_FROM_UTF16BE | SCONV_FROM_UTF8); - sc->flag |= SCONV_FROM_UTF16LE; - if (archive_string_append_unicode(as, sc->utf16nfd.s, - sc->utf16nfd.length, sc) != 0) - ret = -1; - sc->flag = saved_flag;/* restore the saved flag */ + as->length = p - as->s; + as->s[as->length] = '\0'; + if (ts == 2) + as->s[as->length+1] = '\0'; return (ret); - -return_no_changed_data: - /* - * Something conversion error happened, so we return a no normalized - * string with an error. - */ - (void)archive_string_append_unicode(as, _p, len, sc); - return (-1); } -#endif /* __APPLE__ */ - /* * libarchive 2.x made incorrect UTF-8 strings in the wrong assumption * that WCS is Unicode. It is true for several platforms but some are false. @@ -3629,15 +3602,15 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes, } static int -win_strncat_from_utf16be(struct archive_string *as, const void *_p, size_t bytes, - struct archive_string_conv *sc) +win_strncat_from_utf16be(struct archive_string *as, const void *_p, + size_t bytes, struct archive_string_conv *sc) { return (win_strncat_from_utf16(as, _p, bytes, sc, 1)); } static int -win_strncat_from_utf16le(struct archive_string *as, const void *_p, size_t bytes, - struct archive_string_conv *sc) +win_strncat_from_utf16le(struct archive_string *as, const void *_p, + size_t bytes, struct archive_string_conv *sc) { return (win_strncat_from_utf16(as, _p, bytes, sc, 0)); } @@ -3655,8 +3628,8 @@ is_big_endian(void) * Return -1 if conversion failes. */ static int -win_strncat_to_utf16(struct archive_string *as16, const void *_p, size_t length, - struct archive_string_conv *sc, int bigendian) +win_strncat_to_utf16(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc, int bigendian) { const char *s = (const char *)_p; char *u16; @@ -3732,15 +3705,15 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p, size_t length, } static int -win_strncat_to_utf16be(struct archive_string *as16, const void *_p, size_t length, - struct archive_string_conv *sc) +win_strncat_to_utf16be(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc) { return (win_strncat_to_utf16(as16, _p, length, sc, 1)); } static int -win_strncat_to_utf16le(struct archive_string *as16, const void *_p, size_t length, - struct archive_string_conv *sc) +win_strncat_to_utf16le(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc) { return (win_strncat_to_utf16(as16, _p, length, sc, 0)); } @@ -3914,7 +3887,7 @@ archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes, sc = archive_string_conversion_to_charset(a, "UTF-8", 1); if (sc == NULL) return (-1);/* Couldn't allocate memory for sc. */ - r = archive_strncpy_in_locale(&(aes->aes_mbs), aes->aes_mbs.s, + r = archive_strncpy_l(&(aes->aes_mbs), aes->aes_mbs.s, aes->aes_mbs.length, sc); if (a == NULL) free_sconv_object(sc); @@ -4043,7 +4016,7 @@ archive_mstring_get_mbs_l(struct archive_mstring *aes, *length = aes->aes_mbs.length; return (0); } - ret = archive_strncpy_in_locale(&(aes->aes_mbs_in_locale), + ret = archive_strncpy_l(&(aes->aes_mbs_in_locale), aes->aes_mbs.s, aes->aes_mbs.length, sc); *p = aes->aes_mbs_in_locale.s; if (length != NULL) @@ -4084,7 +4057,8 @@ archive_mstring_copy_mbs_len(struct archive_mstring *aes, const char *mbs, int archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs) { - return archive_mstring_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs)); + return archive_mstring_copy_wcs_len(aes, wcs, + wcs == NULL ? 0 : wcslen(wcs)); } int @@ -4143,7 +4117,7 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes, * Translate multi-bytes from some character-set to UTF-8. */ sc->cd = sc->cd_w; - r = archive_strncpy_in_locale(&(aes->aes_utf8), mbs, len, sc); + r = archive_strncpy_l(&(aes->aes_utf8), mbs, len, sc); sc->cd = cd; if (r != 0) { aes->aes_set = 0; @@ -4175,7 +4149,7 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes, aes->aes_set = 0; } #else - r = archive_strncpy_in_locale(&(aes->aes_mbs), mbs, len, sc); + r = archive_strncpy_l(&(aes->aes_mbs), mbs, len, sc); if (r == 0) aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ else @@ -4219,7 +4193,7 @@ archive_mstring_update_utf8(struct archive *a, struct archive_mstring *aes, sc = archive_string_conversion_from_charset(a, "UTF-8", 1); if (sc == NULL) return (-1);/* Couldn't allocate memory for sc. */ - r = archive_strcpy_in_locale(&(aes->aes_mbs), utf8, sc); + r = archive_strcpy_l(&(aes->aes_mbs), utf8, sc); if (a == NULL) free_sconv_object(sc); if (r != 0) diff --git a/contrib/libarchive/libarchive/archive_string.h b/contrib/libarchive/libarchive/archive_string.h index 33064cd..accd5a6 100644 --- a/contrib/libarchive/libarchive/archive_string.h +++ b/contrib/libarchive/libarchive/archive_string.h @@ -110,18 +110,20 @@ archive_string_conversion_charset_name(struct archive_string_conv *); void archive_string_conversion_set_opt(struct archive_string_conv *, int); #define SCONV_SET_OPT_UTF8_LIBARCHIVE2X 1 +#define SCONV_SET_OPT_NORMALIZATION_C 2 +#define SCONV_SET_OPT_NORMALIZATION_D 4 /* Copy one archive_string to another in locale conversion. * Return -1 if conversion failes. */ int -archive_strncpy_in_locale(struct archive_string *, const void *, size_t, +archive_strncpy_l(struct archive_string *, const void *, size_t, struct archive_string_conv *); /* Copy one archive_string to another in locale conversion. * Return -1 if conversion failes. */ int -archive_strncat_in_locale(struct archive_string *, const void *, size_t, +archive_strncat_l(struct archive_string *, const void *, size_t, struct archive_string_conv *); @@ -162,8 +164,8 @@ archive_wstrcat(struct archive_wstring *, const wchar_t *); archive_strncpy((as), (p), ((p) == NULL ? 0 : strlen(p))) #define archive_wstrcpy(as,p) \ archive_wstrncpy((as), (p), ((p) == NULL ? 0 : wcslen(p))) -#define archive_strcpy_in_locale(as,p,lo) \ - archive_strncpy_in_locale((as), (p), ((p) == NULL ? 0 : strlen(p)), (lo)) +#define archive_strcpy_l(as,p,lo) \ + archive_strncpy_l((as), (p), ((p) == NULL ? 0 : strlen(p)), (lo)) /* Copy a C string to an archive_string with limit, resizing as necessary. */ #define archive_strncpy(as,p,l) \ diff --git a/contrib/libarchive/libarchive/archive_string_composition.h b/contrib/libarchive/libarchive/archive_string_composition.h index cc4bf46..be41e33 100644 --- a/contrib/libarchive/libarchive/archive_string_composition.h +++ b/contrib/libarchive/libarchive/archive_string_composition.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2011 libarchive Project + * Copyright (c) 2011-2012 libarchive Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ /* * ATTENTION! * This file is generated by build/utils/gen_archive_string_composition_h.sh - * from http://unicode.org/Public/UNIDATA/UnicodeData.txt + * from http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt * * See also http://unicode.org/report/tr15/ */ @@ -1348,4 +1348,945 @@ static const unsigned char ccc_index[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,37,38,}; +struct unicode_decomposition_table { + uint32_t nfc; + uint32_t cp1; + uint32_t cp2; +}; + +static const struct unicode_decomposition_table u_decomposition_table[] = { + { 0x000C0 , 0x00041 , 0x00300 }, + { 0x000C1 , 0x00041 , 0x00301 }, + { 0x000C2 , 0x00041 , 0x00302 }, + { 0x000C3 , 0x00041 , 0x00303 }, + { 0x000C4 , 0x00041 , 0x00308 }, + { 0x000C5 , 0x00041 , 0x0030A }, + { 0x000C7 , 0x00043 , 0x00327 }, + { 0x000C8 , 0x00045 , 0x00300 }, + { 0x000C9 , 0x00045 , 0x00301 }, + { 0x000CA , 0x00045 , 0x00302 }, + { 0x000CB , 0x00045 , 0x00308 }, + { 0x000CC , 0x00049 , 0x00300 }, + { 0x000CD , 0x00049 , 0x00301 }, + { 0x000CE , 0x00049 , 0x00302 }, + { 0x000CF , 0x00049 , 0x00308 }, + { 0x000D1 , 0x0004E , 0x00303 }, + { 0x000D2 , 0x0004F , 0x00300 }, + { 0x000D3 , 0x0004F , 0x00301 }, + { 0x000D4 , 0x0004F , 0x00302 }, + { 0x000D5 , 0x0004F , 0x00303 }, + { 0x000D6 , 0x0004F , 0x00308 }, + { 0x000D9 , 0x00055 , 0x00300 }, + { 0x000DA , 0x00055 , 0x00301 }, + { 0x000DB , 0x00055 , 0x00302 }, + { 0x000DC , 0x00055 , 0x00308 }, + { 0x000DD , 0x00059 , 0x00301 }, + { 0x000E0 , 0x00061 , 0x00300 }, + { 0x000E1 , 0x00061 , 0x00301 }, + { 0x000E2 , 0x00061 , 0x00302 }, + { 0x000E3 , 0x00061 , 0x00303 }, + { 0x000E4 , 0x00061 , 0x00308 }, + { 0x000E5 , 0x00061 , 0x0030A }, + { 0x000E7 , 0x00063 , 0x00327 }, + { 0x000E8 , 0x00065 , 0x00300 }, + { 0x000E9 , 0x00065 , 0x00301 }, + { 0x000EA , 0x00065 , 0x00302 }, + { 0x000EB , 0x00065 , 0x00308 }, + { 0x000EC , 0x00069 , 0x00300 }, + { 0x000ED , 0x00069 , 0x00301 }, + { 0x000EE , 0x00069 , 0x00302 }, + { 0x000EF , 0x00069 , 0x00308 }, + { 0x000F1 , 0x0006E , 0x00303 }, + { 0x000F2 , 0x0006F , 0x00300 }, + { 0x000F3 , 0x0006F , 0x00301 }, + { 0x000F4 , 0x0006F , 0x00302 }, + { 0x000F5 , 0x0006F , 0x00303 }, + { 0x000F6 , 0x0006F , 0x00308 }, + { 0x000F9 , 0x00075 , 0x00300 }, + { 0x000FA , 0x00075 , 0x00301 }, + { 0x000FB , 0x00075 , 0x00302 }, + { 0x000FC , 0x00075 , 0x00308 }, + { 0x000FD , 0x00079 , 0x00301 }, + { 0x000FF , 0x00079 , 0x00308 }, + { 0x00100 , 0x00041 , 0x00304 }, + { 0x00101 , 0x00061 , 0x00304 }, + { 0x00102 , 0x00041 , 0x00306 }, + { 0x00103 , 0x00061 , 0x00306 }, + { 0x00104 , 0x00041 , 0x00328 }, + { 0x00105 , 0x00061 , 0x00328 }, + { 0x00106 , 0x00043 , 0x00301 }, + { 0x00107 , 0x00063 , 0x00301 }, + { 0x00108 , 0x00043 , 0x00302 }, + { 0x00109 , 0x00063 , 0x00302 }, + { 0x0010A , 0x00043 , 0x00307 }, + { 0x0010B , 0x00063 , 0x00307 }, + { 0x0010C , 0x00043 , 0x0030C }, + { 0x0010D , 0x00063 , 0x0030C }, + { 0x0010E , 0x00044 , 0x0030C }, + { 0x0010F , 0x00064 , 0x0030C }, + { 0x00112 , 0x00045 , 0x00304 }, + { 0x00113 , 0x00065 , 0x00304 }, + { 0x00114 , 0x00045 , 0x00306 }, + { 0x00115 , 0x00065 , 0x00306 }, + { 0x00116 , 0x00045 , 0x00307 }, + { 0x00117 , 0x00065 , 0x00307 }, + { 0x00118 , 0x00045 , 0x00328 }, + { 0x00119 , 0x00065 , 0x00328 }, + { 0x0011A , 0x00045 , 0x0030C }, + { 0x0011B , 0x00065 , 0x0030C }, + { 0x0011C , 0x00047 , 0x00302 }, + { 0x0011D , 0x00067 , 0x00302 }, + { 0x0011E , 0x00047 , 0x00306 }, + { 0x0011F , 0x00067 , 0x00306 }, + { 0x00120 , 0x00047 , 0x00307 }, + { 0x00121 , 0x00067 , 0x00307 }, + { 0x00122 , 0x00047 , 0x00327 }, + { 0x00123 , 0x00067 , 0x00327 }, + { 0x00124 , 0x00048 , 0x00302 }, + { 0x00125 , 0x00068 , 0x00302 }, + { 0x00128 , 0x00049 , 0x00303 }, + { 0x00129 , 0x00069 , 0x00303 }, + { 0x0012A , 0x00049 , 0x00304 }, + { 0x0012B , 0x00069 , 0x00304 }, + { 0x0012C , 0x00049 , 0x00306 }, + { 0x0012D , 0x00069 , 0x00306 }, + { 0x0012E , 0x00049 , 0x00328 }, + { 0x0012F , 0x00069 , 0x00328 }, + { 0x00130 , 0x00049 , 0x00307 }, + { 0x00134 , 0x0004A , 0x00302 }, + { 0x00135 , 0x0006A , 0x00302 }, + { 0x00136 , 0x0004B , 0x00327 }, + { 0x00137 , 0x0006B , 0x00327 }, + { 0x00139 , 0x0004C , 0x00301 }, + { 0x0013A , 0x0006C , 0x00301 }, + { 0x0013B , 0x0004C , 0x00327 }, + { 0x0013C , 0x0006C , 0x00327 }, + { 0x0013D , 0x0004C , 0x0030C }, + { 0x0013E , 0x0006C , 0x0030C }, + { 0x00143 , 0x0004E , 0x00301 }, + { 0x00144 , 0x0006E , 0x00301 }, + { 0x00145 , 0x0004E , 0x00327 }, + { 0x00146 , 0x0006E , 0x00327 }, + { 0x00147 , 0x0004E , 0x0030C }, + { 0x00148 , 0x0006E , 0x0030C }, + { 0x0014C , 0x0004F , 0x00304 }, + { 0x0014D , 0x0006F , 0x00304 }, + { 0x0014E , 0x0004F , 0x00306 }, + { 0x0014F , 0x0006F , 0x00306 }, + { 0x00150 , 0x0004F , 0x0030B }, + { 0x00151 , 0x0006F , 0x0030B }, + { 0x00154 , 0x00052 , 0x00301 }, + { 0x00155 , 0x00072 , 0x00301 }, + { 0x00156 , 0x00052 , 0x00327 }, + { 0x00157 , 0x00072 , 0x00327 }, + { 0x00158 , 0x00052 , 0x0030C }, + { 0x00159 , 0x00072 , 0x0030C }, + { 0x0015A , 0x00053 , 0x00301 }, + { 0x0015B , 0x00073 , 0x00301 }, + { 0x0015C , 0x00053 , 0x00302 }, + { 0x0015D , 0x00073 , 0x00302 }, + { 0x0015E , 0x00053 , 0x00327 }, + { 0x0015F , 0x00073 , 0x00327 }, + { 0x00160 , 0x00053 , 0x0030C }, + { 0x00161 , 0x00073 , 0x0030C }, + { 0x00162 , 0x00054 , 0x00327 }, + { 0x00163 , 0x00074 , 0x00327 }, + { 0x00164 , 0x00054 , 0x0030C }, + { 0x00165 , 0x00074 , 0x0030C }, + { 0x00168 , 0x00055 , 0x00303 }, + { 0x00169 , 0x00075 , 0x00303 }, + { 0x0016A , 0x00055 , 0x00304 }, + { 0x0016B , 0x00075 , 0x00304 }, + { 0x0016C , 0x00055 , 0x00306 }, + { 0x0016D , 0x00075 , 0x00306 }, + { 0x0016E , 0x00055 , 0x0030A }, + { 0x0016F , 0x00075 , 0x0030A }, + { 0x00170 , 0x00055 , 0x0030B }, + { 0x00171 , 0x00075 , 0x0030B }, + { 0x00172 , 0x00055 , 0x00328 }, + { 0x00173 , 0x00075 , 0x00328 }, + { 0x00174 , 0x00057 , 0x00302 }, + { 0x00175 , 0x00077 , 0x00302 }, + { 0x00176 , 0x00059 , 0x00302 }, + { 0x00177 , 0x00079 , 0x00302 }, + { 0x00178 , 0x00059 , 0x00308 }, + { 0x00179 , 0x0005A , 0x00301 }, + { 0x0017A , 0x0007A , 0x00301 }, + { 0x0017B , 0x0005A , 0x00307 }, + { 0x0017C , 0x0007A , 0x00307 }, + { 0x0017D , 0x0005A , 0x0030C }, + { 0x0017E , 0x0007A , 0x0030C }, + { 0x001A0 , 0x0004F , 0x0031B }, + { 0x001A1 , 0x0006F , 0x0031B }, + { 0x001AF , 0x00055 , 0x0031B }, + { 0x001B0 , 0x00075 , 0x0031B }, + { 0x001CD , 0x00041 , 0x0030C }, + { 0x001CE , 0x00061 , 0x0030C }, + { 0x001CF , 0x00049 , 0x0030C }, + { 0x001D0 , 0x00069 , 0x0030C }, + { 0x001D1 , 0x0004F , 0x0030C }, + { 0x001D2 , 0x0006F , 0x0030C }, + { 0x001D3 , 0x00055 , 0x0030C }, + { 0x001D4 , 0x00075 , 0x0030C }, + { 0x001D5 , 0x000DC , 0x00304 }, + { 0x001D6 , 0x000FC , 0x00304 }, + { 0x001D7 , 0x000DC , 0x00301 }, + { 0x001D8 , 0x000FC , 0x00301 }, + { 0x001D9 , 0x000DC , 0x0030C }, + { 0x001DA , 0x000FC , 0x0030C }, + { 0x001DB , 0x000DC , 0x00300 }, + { 0x001DC , 0x000FC , 0x00300 }, + { 0x001DE , 0x000C4 , 0x00304 }, + { 0x001DF , 0x000E4 , 0x00304 }, + { 0x001E0 , 0x00226 , 0x00304 }, + { 0x001E1 , 0x00227 , 0x00304 }, + { 0x001E2 , 0x000C6 , 0x00304 }, + { 0x001E3 , 0x000E6 , 0x00304 }, + { 0x001E6 , 0x00047 , 0x0030C }, + { 0x001E7 , 0x00067 , 0x0030C }, + { 0x001E8 , 0x0004B , 0x0030C }, + { 0x001E9 , 0x0006B , 0x0030C }, + { 0x001EA , 0x0004F , 0x00328 }, + { 0x001EB , 0x0006F , 0x00328 }, + { 0x001EC , 0x001EA , 0x00304 }, + { 0x001ED , 0x001EB , 0x00304 }, + { 0x001EE , 0x001B7 , 0x0030C }, + { 0x001EF , 0x00292 , 0x0030C }, + { 0x001F0 , 0x0006A , 0x0030C }, + { 0x001F4 , 0x00047 , 0x00301 }, + { 0x001F5 , 0x00067 , 0x00301 }, + { 0x001F8 , 0x0004E , 0x00300 }, + { 0x001F9 , 0x0006E , 0x00300 }, + { 0x001FA , 0x000C5 , 0x00301 }, + { 0x001FB , 0x000E5 , 0x00301 }, + { 0x001FC , 0x000C6 , 0x00301 }, + { 0x001FD , 0x000E6 , 0x00301 }, + { 0x001FE , 0x000D8 , 0x00301 }, + { 0x001FF , 0x000F8 , 0x00301 }, + { 0x00200 , 0x00041 , 0x0030F }, + { 0x00201 , 0x00061 , 0x0030F }, + { 0x00202 , 0x00041 , 0x00311 }, + { 0x00203 , 0x00061 , 0x00311 }, + { 0x00204 , 0x00045 , 0x0030F }, + { 0x00205 , 0x00065 , 0x0030F }, + { 0x00206 , 0x00045 , 0x00311 }, + { 0x00207 , 0x00065 , 0x00311 }, + { 0x00208 , 0x00049 , 0x0030F }, + { 0x00209 , 0x00069 , 0x0030F }, + { 0x0020A , 0x00049 , 0x00311 }, + { 0x0020B , 0x00069 , 0x00311 }, + { 0x0020C , 0x0004F , 0x0030F }, + { 0x0020D , 0x0006F , 0x0030F }, + { 0x0020E , 0x0004F , 0x00311 }, + { 0x0020F , 0x0006F , 0x00311 }, + { 0x00210 , 0x00052 , 0x0030F }, + { 0x00211 , 0x00072 , 0x0030F }, + { 0x00212 , 0x00052 , 0x00311 }, + { 0x00213 , 0x00072 , 0x00311 }, + { 0x00214 , 0x00055 , 0x0030F }, + { 0x00215 , 0x00075 , 0x0030F }, + { 0x00216 , 0x00055 , 0x00311 }, + { 0x00217 , 0x00075 , 0x00311 }, + { 0x00218 , 0x00053 , 0x00326 }, + { 0x00219 , 0x00073 , 0x00326 }, + { 0x0021A , 0x00054 , 0x00326 }, + { 0x0021B , 0x00074 , 0x00326 }, + { 0x0021E , 0x00048 , 0x0030C }, + { 0x0021F , 0x00068 , 0x0030C }, + { 0x00226 , 0x00041 , 0x00307 }, + { 0x00227 , 0x00061 , 0x00307 }, + { 0x00228 , 0x00045 , 0x00327 }, + { 0x00229 , 0x00065 , 0x00327 }, + { 0x0022A , 0x000D6 , 0x00304 }, + { 0x0022B , 0x000F6 , 0x00304 }, + { 0x0022C , 0x000D5 , 0x00304 }, + { 0x0022D , 0x000F5 , 0x00304 }, + { 0x0022E , 0x0004F , 0x00307 }, + { 0x0022F , 0x0006F , 0x00307 }, + { 0x00230 , 0x0022E , 0x00304 }, + { 0x00231 , 0x0022F , 0x00304 }, + { 0x00232 , 0x00059 , 0x00304 }, + { 0x00233 , 0x00079 , 0x00304 }, + { 0x00385 , 0x000A8 , 0x00301 }, + { 0x00386 , 0x00391 , 0x00301 }, + { 0x00388 , 0x00395 , 0x00301 }, + { 0x00389 , 0x00397 , 0x00301 }, + { 0x0038A , 0x00399 , 0x00301 }, + { 0x0038C , 0x0039F , 0x00301 }, + { 0x0038E , 0x003A5 , 0x00301 }, + { 0x0038F , 0x003A9 , 0x00301 }, + { 0x00390 , 0x003CA , 0x00301 }, + { 0x003AA , 0x00399 , 0x00308 }, + { 0x003AB , 0x003A5 , 0x00308 }, + { 0x003AC , 0x003B1 , 0x00301 }, + { 0x003AD , 0x003B5 , 0x00301 }, + { 0x003AE , 0x003B7 , 0x00301 }, + { 0x003AF , 0x003B9 , 0x00301 }, + { 0x003B0 , 0x003CB , 0x00301 }, + { 0x003CA , 0x003B9 , 0x00308 }, + { 0x003CB , 0x003C5 , 0x00308 }, + { 0x003CC , 0x003BF , 0x00301 }, + { 0x003CD , 0x003C5 , 0x00301 }, + { 0x003CE , 0x003C9 , 0x00301 }, + { 0x003D3 , 0x003D2 , 0x00301 }, + { 0x003D4 , 0x003D2 , 0x00308 }, + { 0x00400 , 0x00415 , 0x00300 }, + { 0x00401 , 0x00415 , 0x00308 }, + { 0x00403 , 0x00413 , 0x00301 }, + { 0x00407 , 0x00406 , 0x00308 }, + { 0x0040C , 0x0041A , 0x00301 }, + { 0x0040D , 0x00418 , 0x00300 }, + { 0x0040E , 0x00423 , 0x00306 }, + { 0x00419 , 0x00418 , 0x00306 }, + { 0x00439 , 0x00438 , 0x00306 }, + { 0x00450 , 0x00435 , 0x00300 }, + { 0x00451 , 0x00435 , 0x00308 }, + { 0x00453 , 0x00433 , 0x00301 }, + { 0x00457 , 0x00456 , 0x00308 }, + { 0x0045C , 0x0043A , 0x00301 }, + { 0x0045D , 0x00438 , 0x00300 }, + { 0x0045E , 0x00443 , 0x00306 }, + { 0x00476 , 0x00474 , 0x0030F }, + { 0x00477 , 0x00475 , 0x0030F }, + { 0x004C1 , 0x00416 , 0x00306 }, + { 0x004C2 , 0x00436 , 0x00306 }, + { 0x004D0 , 0x00410 , 0x00306 }, + { 0x004D1 , 0x00430 , 0x00306 }, + { 0x004D2 , 0x00410 , 0x00308 }, + { 0x004D3 , 0x00430 , 0x00308 }, + { 0x004D6 , 0x00415 , 0x00306 }, + { 0x004D7 , 0x00435 , 0x00306 }, + { 0x004DA , 0x004D8 , 0x00308 }, + { 0x004DB , 0x004D9 , 0x00308 }, + { 0x004DC , 0x00416 , 0x00308 }, + { 0x004DD , 0x00436 , 0x00308 }, + { 0x004DE , 0x00417 , 0x00308 }, + { 0x004DF , 0x00437 , 0x00308 }, + { 0x004E2 , 0x00418 , 0x00304 }, + { 0x004E3 , 0x00438 , 0x00304 }, + { 0x004E4 , 0x00418 , 0x00308 }, + { 0x004E5 , 0x00438 , 0x00308 }, + { 0x004E6 , 0x0041E , 0x00308 }, + { 0x004E7 , 0x0043E , 0x00308 }, + { 0x004EA , 0x004E8 , 0x00308 }, + { 0x004EB , 0x004E9 , 0x00308 }, + { 0x004EC , 0x0042D , 0x00308 }, + { 0x004ED , 0x0044D , 0x00308 }, + { 0x004EE , 0x00423 , 0x00304 }, + { 0x004EF , 0x00443 , 0x00304 }, + { 0x004F0 , 0x00423 , 0x00308 }, + { 0x004F1 , 0x00443 , 0x00308 }, + { 0x004F2 , 0x00423 , 0x0030B }, + { 0x004F3 , 0x00443 , 0x0030B }, + { 0x004F4 , 0x00427 , 0x00308 }, + { 0x004F5 , 0x00447 , 0x00308 }, + { 0x004F8 , 0x0042B , 0x00308 }, + { 0x004F9 , 0x0044B , 0x00308 }, + { 0x00622 , 0x00627 , 0x00653 }, + { 0x00623 , 0x00627 , 0x00654 }, + { 0x00624 , 0x00648 , 0x00654 }, + { 0x00625 , 0x00627 , 0x00655 }, + { 0x00626 , 0x0064A , 0x00654 }, + { 0x006C0 , 0x006D5 , 0x00654 }, + { 0x006C2 , 0x006C1 , 0x00654 }, + { 0x006D3 , 0x006D2 , 0x00654 }, + { 0x00929 , 0x00928 , 0x0093C }, + { 0x00931 , 0x00930 , 0x0093C }, + { 0x00934 , 0x00933 , 0x0093C }, + { 0x009CB , 0x009C7 , 0x009BE }, + { 0x009CC , 0x009C7 , 0x009D7 }, + { 0x00B48 , 0x00B47 , 0x00B56 }, + { 0x00B4B , 0x00B47 , 0x00B3E }, + { 0x00B4C , 0x00B47 , 0x00B57 }, + { 0x00B94 , 0x00B92 , 0x00BD7 }, + { 0x00BCA , 0x00BC6 , 0x00BBE }, + { 0x00BCB , 0x00BC7 , 0x00BBE }, + { 0x00BCC , 0x00BC6 , 0x00BD7 }, + { 0x00C48 , 0x00C46 , 0x00C56 }, + { 0x00CC0 , 0x00CBF , 0x00CD5 }, + { 0x00CC7 , 0x00CC6 , 0x00CD5 }, + { 0x00CC8 , 0x00CC6 , 0x00CD6 }, + { 0x00CCA , 0x00CC6 , 0x00CC2 }, + { 0x00CCB , 0x00CCA , 0x00CD5 }, + { 0x00D4A , 0x00D46 , 0x00D3E }, + { 0x00D4B , 0x00D47 , 0x00D3E }, + { 0x00D4C , 0x00D46 , 0x00D57 }, + { 0x00DDA , 0x00DD9 , 0x00DCA }, + { 0x00DDC , 0x00DD9 , 0x00DCF }, + { 0x00DDD , 0x00DDC , 0x00DCA }, + { 0x00DDE , 0x00DD9 , 0x00DDF }, + { 0x01026 , 0x01025 , 0x0102E }, + { 0x01B06 , 0x01B05 , 0x01B35 }, + { 0x01B08 , 0x01B07 , 0x01B35 }, + { 0x01B0A , 0x01B09 , 0x01B35 }, + { 0x01B0C , 0x01B0B , 0x01B35 }, + { 0x01B0E , 0x01B0D , 0x01B35 }, + { 0x01B12 , 0x01B11 , 0x01B35 }, + { 0x01B3B , 0x01B3A , 0x01B35 }, + { 0x01B3D , 0x01B3C , 0x01B35 }, + { 0x01B40 , 0x01B3E , 0x01B35 }, + { 0x01B41 , 0x01B3F , 0x01B35 }, + { 0x01B43 , 0x01B42 , 0x01B35 }, + { 0x01E00 , 0x00041 , 0x00325 }, + { 0x01E01 , 0x00061 , 0x00325 }, + { 0x01E02 , 0x00042 , 0x00307 }, + { 0x01E03 , 0x00062 , 0x00307 }, + { 0x01E04 , 0x00042 , 0x00323 }, + { 0x01E05 , 0x00062 , 0x00323 }, + { 0x01E06 , 0x00042 , 0x00331 }, + { 0x01E07 , 0x00062 , 0x00331 }, + { 0x01E08 , 0x000C7 , 0x00301 }, + { 0x01E09 , 0x000E7 , 0x00301 }, + { 0x01E0A , 0x00044 , 0x00307 }, + { 0x01E0B , 0x00064 , 0x00307 }, + { 0x01E0C , 0x00044 , 0x00323 }, + { 0x01E0D , 0x00064 , 0x00323 }, + { 0x01E0E , 0x00044 , 0x00331 }, + { 0x01E0F , 0x00064 , 0x00331 }, + { 0x01E10 , 0x00044 , 0x00327 }, + { 0x01E11 , 0x00064 , 0x00327 }, + { 0x01E12 , 0x00044 , 0x0032D }, + { 0x01E13 , 0x00064 , 0x0032D }, + { 0x01E14 , 0x00112 , 0x00300 }, + { 0x01E15 , 0x00113 , 0x00300 }, + { 0x01E16 , 0x00112 , 0x00301 }, + { 0x01E17 , 0x00113 , 0x00301 }, + { 0x01E18 , 0x00045 , 0x0032D }, + { 0x01E19 , 0x00065 , 0x0032D }, + { 0x01E1A , 0x00045 , 0x00330 }, + { 0x01E1B , 0x00065 , 0x00330 }, + { 0x01E1C , 0x00228 , 0x00306 }, + { 0x01E1D , 0x00229 , 0x00306 }, + { 0x01E1E , 0x00046 , 0x00307 }, + { 0x01E1F , 0x00066 , 0x00307 }, + { 0x01E20 , 0x00047 , 0x00304 }, + { 0x01E21 , 0x00067 , 0x00304 }, + { 0x01E22 , 0x00048 , 0x00307 }, + { 0x01E23 , 0x00068 , 0x00307 }, + { 0x01E24 , 0x00048 , 0x00323 }, + { 0x01E25 , 0x00068 , 0x00323 }, + { 0x01E26 , 0x00048 , 0x00308 }, + { 0x01E27 , 0x00068 , 0x00308 }, + { 0x01E28 , 0x00048 , 0x00327 }, + { 0x01E29 , 0x00068 , 0x00327 }, + { 0x01E2A , 0x00048 , 0x0032E }, + { 0x01E2B , 0x00068 , 0x0032E }, + { 0x01E2C , 0x00049 , 0x00330 }, + { 0x01E2D , 0x00069 , 0x00330 }, + { 0x01E2E , 0x000CF , 0x00301 }, + { 0x01E2F , 0x000EF , 0x00301 }, + { 0x01E30 , 0x0004B , 0x00301 }, + { 0x01E31 , 0x0006B , 0x00301 }, + { 0x01E32 , 0x0004B , 0x00323 }, + { 0x01E33 , 0x0006B , 0x00323 }, + { 0x01E34 , 0x0004B , 0x00331 }, + { 0x01E35 , 0x0006B , 0x00331 }, + { 0x01E36 , 0x0004C , 0x00323 }, + { 0x01E37 , 0x0006C , 0x00323 }, + { 0x01E38 , 0x01E36 , 0x00304 }, + { 0x01E39 , 0x01E37 , 0x00304 }, + { 0x01E3A , 0x0004C , 0x00331 }, + { 0x01E3B , 0x0006C , 0x00331 }, + { 0x01E3C , 0x0004C , 0x0032D }, + { 0x01E3D , 0x0006C , 0x0032D }, + { 0x01E3E , 0x0004D , 0x00301 }, + { 0x01E3F , 0x0006D , 0x00301 }, + { 0x01E40 , 0x0004D , 0x00307 }, + { 0x01E41 , 0x0006D , 0x00307 }, + { 0x01E42 , 0x0004D , 0x00323 }, + { 0x01E43 , 0x0006D , 0x00323 }, + { 0x01E44 , 0x0004E , 0x00307 }, + { 0x01E45 , 0x0006E , 0x00307 }, + { 0x01E46 , 0x0004E , 0x00323 }, + { 0x01E47 , 0x0006E , 0x00323 }, + { 0x01E48 , 0x0004E , 0x00331 }, + { 0x01E49 , 0x0006E , 0x00331 }, + { 0x01E4A , 0x0004E , 0x0032D }, + { 0x01E4B , 0x0006E , 0x0032D }, + { 0x01E4C , 0x000D5 , 0x00301 }, + { 0x01E4D , 0x000F5 , 0x00301 }, + { 0x01E4E , 0x000D5 , 0x00308 }, + { 0x01E4F , 0x000F5 , 0x00308 }, + { 0x01E50 , 0x0014C , 0x00300 }, + { 0x01E51 , 0x0014D , 0x00300 }, + { 0x01E52 , 0x0014C , 0x00301 }, + { 0x01E53 , 0x0014D , 0x00301 }, + { 0x01E54 , 0x00050 , 0x00301 }, + { 0x01E55 , 0x00070 , 0x00301 }, + { 0x01E56 , 0x00050 , 0x00307 }, + { 0x01E57 , 0x00070 , 0x00307 }, + { 0x01E58 , 0x00052 , 0x00307 }, + { 0x01E59 , 0x00072 , 0x00307 }, + { 0x01E5A , 0x00052 , 0x00323 }, + { 0x01E5B , 0x00072 , 0x00323 }, + { 0x01E5C , 0x01E5A , 0x00304 }, + { 0x01E5D , 0x01E5B , 0x00304 }, + { 0x01E5E , 0x00052 , 0x00331 }, + { 0x01E5F , 0x00072 , 0x00331 }, + { 0x01E60 , 0x00053 , 0x00307 }, + { 0x01E61 , 0x00073 , 0x00307 }, + { 0x01E62 , 0x00053 , 0x00323 }, + { 0x01E63 , 0x00073 , 0x00323 }, + { 0x01E64 , 0x0015A , 0x00307 }, + { 0x01E65 , 0x0015B , 0x00307 }, + { 0x01E66 , 0x00160 , 0x00307 }, + { 0x01E67 , 0x00161 , 0x00307 }, + { 0x01E68 , 0x01E62 , 0x00307 }, + { 0x01E69 , 0x01E63 , 0x00307 }, + { 0x01E6A , 0x00054 , 0x00307 }, + { 0x01E6B , 0x00074 , 0x00307 }, + { 0x01E6C , 0x00054 , 0x00323 }, + { 0x01E6D , 0x00074 , 0x00323 }, + { 0x01E6E , 0x00054 , 0x00331 }, + { 0x01E6F , 0x00074 , 0x00331 }, + { 0x01E70 , 0x00054 , 0x0032D }, + { 0x01E71 , 0x00074 , 0x0032D }, + { 0x01E72 , 0x00055 , 0x00324 }, + { 0x01E73 , 0x00075 , 0x00324 }, + { 0x01E74 , 0x00055 , 0x00330 }, + { 0x01E75 , 0x00075 , 0x00330 }, + { 0x01E76 , 0x00055 , 0x0032D }, + { 0x01E77 , 0x00075 , 0x0032D }, + { 0x01E78 , 0x00168 , 0x00301 }, + { 0x01E79 , 0x00169 , 0x00301 }, + { 0x01E7A , 0x0016A , 0x00308 }, + { 0x01E7B , 0x0016B , 0x00308 }, + { 0x01E7C , 0x00056 , 0x00303 }, + { 0x01E7D , 0x00076 , 0x00303 }, + { 0x01E7E , 0x00056 , 0x00323 }, + { 0x01E7F , 0x00076 , 0x00323 }, + { 0x01E80 , 0x00057 , 0x00300 }, + { 0x01E81 , 0x00077 , 0x00300 }, + { 0x01E82 , 0x00057 , 0x00301 }, + { 0x01E83 , 0x00077 , 0x00301 }, + { 0x01E84 , 0x00057 , 0x00308 }, + { 0x01E85 , 0x00077 , 0x00308 }, + { 0x01E86 , 0x00057 , 0x00307 }, + { 0x01E87 , 0x00077 , 0x00307 }, + { 0x01E88 , 0x00057 , 0x00323 }, + { 0x01E89 , 0x00077 , 0x00323 }, + { 0x01E8A , 0x00058 , 0x00307 }, + { 0x01E8B , 0x00078 , 0x00307 }, + { 0x01E8C , 0x00058 , 0x00308 }, + { 0x01E8D , 0x00078 , 0x00308 }, + { 0x01E8E , 0x00059 , 0x00307 }, + { 0x01E8F , 0x00079 , 0x00307 }, + { 0x01E90 , 0x0005A , 0x00302 }, + { 0x01E91 , 0x0007A , 0x00302 }, + { 0x01E92 , 0x0005A , 0x00323 }, + { 0x01E93 , 0x0007A , 0x00323 }, + { 0x01E94 , 0x0005A , 0x00331 }, + { 0x01E95 , 0x0007A , 0x00331 }, + { 0x01E96 , 0x00068 , 0x00331 }, + { 0x01E97 , 0x00074 , 0x00308 }, + { 0x01E98 , 0x00077 , 0x0030A }, + { 0x01E99 , 0x00079 , 0x0030A }, + { 0x01E9B , 0x0017F , 0x00307 }, + { 0x01EA0 , 0x00041 , 0x00323 }, + { 0x01EA1 , 0x00061 , 0x00323 }, + { 0x01EA2 , 0x00041 , 0x00309 }, + { 0x01EA3 , 0x00061 , 0x00309 }, + { 0x01EA4 , 0x000C2 , 0x00301 }, + { 0x01EA5 , 0x000E2 , 0x00301 }, + { 0x01EA6 , 0x000C2 , 0x00300 }, + { 0x01EA7 , 0x000E2 , 0x00300 }, + { 0x01EA8 , 0x000C2 , 0x00309 }, + { 0x01EA9 , 0x000E2 , 0x00309 }, + { 0x01EAA , 0x000C2 , 0x00303 }, + { 0x01EAB , 0x000E2 , 0x00303 }, + { 0x01EAC , 0x01EA0 , 0x00302 }, + { 0x01EAD , 0x01EA1 , 0x00302 }, + { 0x01EAE , 0x00102 , 0x00301 }, + { 0x01EAF , 0x00103 , 0x00301 }, + { 0x01EB0 , 0x00102 , 0x00300 }, + { 0x01EB1 , 0x00103 , 0x00300 }, + { 0x01EB2 , 0x00102 , 0x00309 }, + { 0x01EB3 , 0x00103 , 0x00309 }, + { 0x01EB4 , 0x00102 , 0x00303 }, + { 0x01EB5 , 0x00103 , 0x00303 }, + { 0x01EB6 , 0x01EA0 , 0x00306 }, + { 0x01EB7 , 0x01EA1 , 0x00306 }, + { 0x01EB8 , 0x00045 , 0x00323 }, + { 0x01EB9 , 0x00065 , 0x00323 }, + { 0x01EBA , 0x00045 , 0x00309 }, + { 0x01EBB , 0x00065 , 0x00309 }, + { 0x01EBC , 0x00045 , 0x00303 }, + { 0x01EBD , 0x00065 , 0x00303 }, + { 0x01EBE , 0x000CA , 0x00301 }, + { 0x01EBF , 0x000EA , 0x00301 }, + { 0x01EC0 , 0x000CA , 0x00300 }, + { 0x01EC1 , 0x000EA , 0x00300 }, + { 0x01EC2 , 0x000CA , 0x00309 }, + { 0x01EC3 , 0x000EA , 0x00309 }, + { 0x01EC4 , 0x000CA , 0x00303 }, + { 0x01EC5 , 0x000EA , 0x00303 }, + { 0x01EC6 , 0x01EB8 , 0x00302 }, + { 0x01EC7 , 0x01EB9 , 0x00302 }, + { 0x01EC8 , 0x00049 , 0x00309 }, + { 0x01EC9 , 0x00069 , 0x00309 }, + { 0x01ECA , 0x00049 , 0x00323 }, + { 0x01ECB , 0x00069 , 0x00323 }, + { 0x01ECC , 0x0004F , 0x00323 }, + { 0x01ECD , 0x0006F , 0x00323 }, + { 0x01ECE , 0x0004F , 0x00309 }, + { 0x01ECF , 0x0006F , 0x00309 }, + { 0x01ED0 , 0x000D4 , 0x00301 }, + { 0x01ED1 , 0x000F4 , 0x00301 }, + { 0x01ED2 , 0x000D4 , 0x00300 }, + { 0x01ED3 , 0x000F4 , 0x00300 }, + { 0x01ED4 , 0x000D4 , 0x00309 }, + { 0x01ED5 , 0x000F4 , 0x00309 }, + { 0x01ED6 , 0x000D4 , 0x00303 }, + { 0x01ED7 , 0x000F4 , 0x00303 }, + { 0x01ED8 , 0x01ECC , 0x00302 }, + { 0x01ED9 , 0x01ECD , 0x00302 }, + { 0x01EDA , 0x001A0 , 0x00301 }, + { 0x01EDB , 0x001A1 , 0x00301 }, + { 0x01EDC , 0x001A0 , 0x00300 }, + { 0x01EDD , 0x001A1 , 0x00300 }, + { 0x01EDE , 0x001A0 , 0x00309 }, + { 0x01EDF , 0x001A1 , 0x00309 }, + { 0x01EE0 , 0x001A0 , 0x00303 }, + { 0x01EE1 , 0x001A1 , 0x00303 }, + { 0x01EE2 , 0x001A0 , 0x00323 }, + { 0x01EE3 , 0x001A1 , 0x00323 }, + { 0x01EE4 , 0x00055 , 0x00323 }, + { 0x01EE5 , 0x00075 , 0x00323 }, + { 0x01EE6 , 0x00055 , 0x00309 }, + { 0x01EE7 , 0x00075 , 0x00309 }, + { 0x01EE8 , 0x001AF , 0x00301 }, + { 0x01EE9 , 0x001B0 , 0x00301 }, + { 0x01EEA , 0x001AF , 0x00300 }, + { 0x01EEB , 0x001B0 , 0x00300 }, + { 0x01EEC , 0x001AF , 0x00309 }, + { 0x01EED , 0x001B0 , 0x00309 }, + { 0x01EEE , 0x001AF , 0x00303 }, + { 0x01EEF , 0x001B0 , 0x00303 }, + { 0x01EF0 , 0x001AF , 0x00323 }, + { 0x01EF1 , 0x001B0 , 0x00323 }, + { 0x01EF2 , 0x00059 , 0x00300 }, + { 0x01EF3 , 0x00079 , 0x00300 }, + { 0x01EF4 , 0x00059 , 0x00323 }, + { 0x01EF5 , 0x00079 , 0x00323 }, + { 0x01EF6 , 0x00059 , 0x00309 }, + { 0x01EF7 , 0x00079 , 0x00309 }, + { 0x01EF8 , 0x00059 , 0x00303 }, + { 0x01EF9 , 0x00079 , 0x00303 }, + { 0x01F00 , 0x003B1 , 0x00313 }, + { 0x01F01 , 0x003B1 , 0x00314 }, + { 0x01F02 , 0x01F00 , 0x00300 }, + { 0x01F03 , 0x01F01 , 0x00300 }, + { 0x01F04 , 0x01F00 , 0x00301 }, + { 0x01F05 , 0x01F01 , 0x00301 }, + { 0x01F06 , 0x01F00 , 0x00342 }, + { 0x01F07 , 0x01F01 , 0x00342 }, + { 0x01F08 , 0x00391 , 0x00313 }, + { 0x01F09 , 0x00391 , 0x00314 }, + { 0x01F0A , 0x01F08 , 0x00300 }, + { 0x01F0B , 0x01F09 , 0x00300 }, + { 0x01F0C , 0x01F08 , 0x00301 }, + { 0x01F0D , 0x01F09 , 0x00301 }, + { 0x01F0E , 0x01F08 , 0x00342 }, + { 0x01F0F , 0x01F09 , 0x00342 }, + { 0x01F10 , 0x003B5 , 0x00313 }, + { 0x01F11 , 0x003B5 , 0x00314 }, + { 0x01F12 , 0x01F10 , 0x00300 }, + { 0x01F13 , 0x01F11 , 0x00300 }, + { 0x01F14 , 0x01F10 , 0x00301 }, + { 0x01F15 , 0x01F11 , 0x00301 }, + { 0x01F18 , 0x00395 , 0x00313 }, + { 0x01F19 , 0x00395 , 0x00314 }, + { 0x01F1A , 0x01F18 , 0x00300 }, + { 0x01F1B , 0x01F19 , 0x00300 }, + { 0x01F1C , 0x01F18 , 0x00301 }, + { 0x01F1D , 0x01F19 , 0x00301 }, + { 0x01F20 , 0x003B7 , 0x00313 }, + { 0x01F21 , 0x003B7 , 0x00314 }, + { 0x01F22 , 0x01F20 , 0x00300 }, + { 0x01F23 , 0x01F21 , 0x00300 }, + { 0x01F24 , 0x01F20 , 0x00301 }, + { 0x01F25 , 0x01F21 , 0x00301 }, + { 0x01F26 , 0x01F20 , 0x00342 }, + { 0x01F27 , 0x01F21 , 0x00342 }, + { 0x01F28 , 0x00397 , 0x00313 }, + { 0x01F29 , 0x00397 , 0x00314 }, + { 0x01F2A , 0x01F28 , 0x00300 }, + { 0x01F2B , 0x01F29 , 0x00300 }, + { 0x01F2C , 0x01F28 , 0x00301 }, + { 0x01F2D , 0x01F29 , 0x00301 }, + { 0x01F2E , 0x01F28 , 0x00342 }, + { 0x01F2F , 0x01F29 , 0x00342 }, + { 0x01F30 , 0x003B9 , 0x00313 }, + { 0x01F31 , 0x003B9 , 0x00314 }, + { 0x01F32 , 0x01F30 , 0x00300 }, + { 0x01F33 , 0x01F31 , 0x00300 }, + { 0x01F34 , 0x01F30 , 0x00301 }, + { 0x01F35 , 0x01F31 , 0x00301 }, + { 0x01F36 , 0x01F30 , 0x00342 }, + { 0x01F37 , 0x01F31 , 0x00342 }, + { 0x01F38 , 0x00399 , 0x00313 }, + { 0x01F39 , 0x00399 , 0x00314 }, + { 0x01F3A , 0x01F38 , 0x00300 }, + { 0x01F3B , 0x01F39 , 0x00300 }, + { 0x01F3C , 0x01F38 , 0x00301 }, + { 0x01F3D , 0x01F39 , 0x00301 }, + { 0x01F3E , 0x01F38 , 0x00342 }, + { 0x01F3F , 0x01F39 , 0x00342 }, + { 0x01F40 , 0x003BF , 0x00313 }, + { 0x01F41 , 0x003BF , 0x00314 }, + { 0x01F42 , 0x01F40 , 0x00300 }, + { 0x01F43 , 0x01F41 , 0x00300 }, + { 0x01F44 , 0x01F40 , 0x00301 }, + { 0x01F45 , 0x01F41 , 0x00301 }, + { 0x01F48 , 0x0039F , 0x00313 }, + { 0x01F49 , 0x0039F , 0x00314 }, + { 0x01F4A , 0x01F48 , 0x00300 }, + { 0x01F4B , 0x01F49 , 0x00300 }, + { 0x01F4C , 0x01F48 , 0x00301 }, + { 0x01F4D , 0x01F49 , 0x00301 }, + { 0x01F50 , 0x003C5 , 0x00313 }, + { 0x01F51 , 0x003C5 , 0x00314 }, + { 0x01F52 , 0x01F50 , 0x00300 }, + { 0x01F53 , 0x01F51 , 0x00300 }, + { 0x01F54 , 0x01F50 , 0x00301 }, + { 0x01F55 , 0x01F51 , 0x00301 }, + { 0x01F56 , 0x01F50 , 0x00342 }, + { 0x01F57 , 0x01F51 , 0x00342 }, + { 0x01F59 , 0x003A5 , 0x00314 }, + { 0x01F5B , 0x01F59 , 0x00300 }, + { 0x01F5D , 0x01F59 , 0x00301 }, + { 0x01F5F , 0x01F59 , 0x00342 }, + { 0x01F60 , 0x003C9 , 0x00313 }, + { 0x01F61 , 0x003C9 , 0x00314 }, + { 0x01F62 , 0x01F60 , 0x00300 }, + { 0x01F63 , 0x01F61 , 0x00300 }, + { 0x01F64 , 0x01F60 , 0x00301 }, + { 0x01F65 , 0x01F61 , 0x00301 }, + { 0x01F66 , 0x01F60 , 0x00342 }, + { 0x01F67 , 0x01F61 , 0x00342 }, + { 0x01F68 , 0x003A9 , 0x00313 }, + { 0x01F69 , 0x003A9 , 0x00314 }, + { 0x01F6A , 0x01F68 , 0x00300 }, + { 0x01F6B , 0x01F69 , 0x00300 }, + { 0x01F6C , 0x01F68 , 0x00301 }, + { 0x01F6D , 0x01F69 , 0x00301 }, + { 0x01F6E , 0x01F68 , 0x00342 }, + { 0x01F6F , 0x01F69 , 0x00342 }, + { 0x01F70 , 0x003B1 , 0x00300 }, + { 0x01F72 , 0x003B5 , 0x00300 }, + { 0x01F74 , 0x003B7 , 0x00300 }, + { 0x01F76 , 0x003B9 , 0x00300 }, + { 0x01F78 , 0x003BF , 0x00300 }, + { 0x01F7A , 0x003C5 , 0x00300 }, + { 0x01F7C , 0x003C9 , 0x00300 }, + { 0x01F80 , 0x01F00 , 0x00345 }, + { 0x01F81 , 0x01F01 , 0x00345 }, + { 0x01F82 , 0x01F02 , 0x00345 }, + { 0x01F83 , 0x01F03 , 0x00345 }, + { 0x01F84 , 0x01F04 , 0x00345 }, + { 0x01F85 , 0x01F05 , 0x00345 }, + { 0x01F86 , 0x01F06 , 0x00345 }, + { 0x01F87 , 0x01F07 , 0x00345 }, + { 0x01F88 , 0x01F08 , 0x00345 }, + { 0x01F89 , 0x01F09 , 0x00345 }, + { 0x01F8A , 0x01F0A , 0x00345 }, + { 0x01F8B , 0x01F0B , 0x00345 }, + { 0x01F8C , 0x01F0C , 0x00345 }, + { 0x01F8D , 0x01F0D , 0x00345 }, + { 0x01F8E , 0x01F0E , 0x00345 }, + { 0x01F8F , 0x01F0F , 0x00345 }, + { 0x01F90 , 0x01F20 , 0x00345 }, + { 0x01F91 , 0x01F21 , 0x00345 }, + { 0x01F92 , 0x01F22 , 0x00345 }, + { 0x01F93 , 0x01F23 , 0x00345 }, + { 0x01F94 , 0x01F24 , 0x00345 }, + { 0x01F95 , 0x01F25 , 0x00345 }, + { 0x01F96 , 0x01F26 , 0x00345 }, + { 0x01F97 , 0x01F27 , 0x00345 }, + { 0x01F98 , 0x01F28 , 0x00345 }, + { 0x01F99 , 0x01F29 , 0x00345 }, + { 0x01F9A , 0x01F2A , 0x00345 }, + { 0x01F9B , 0x01F2B , 0x00345 }, + { 0x01F9C , 0x01F2C , 0x00345 }, + { 0x01F9D , 0x01F2D , 0x00345 }, + { 0x01F9E , 0x01F2E , 0x00345 }, + { 0x01F9F , 0x01F2F , 0x00345 }, + { 0x01FA0 , 0x01F60 , 0x00345 }, + { 0x01FA1 , 0x01F61 , 0x00345 }, + { 0x01FA2 , 0x01F62 , 0x00345 }, + { 0x01FA3 , 0x01F63 , 0x00345 }, + { 0x01FA4 , 0x01F64 , 0x00345 }, + { 0x01FA5 , 0x01F65 , 0x00345 }, + { 0x01FA6 , 0x01F66 , 0x00345 }, + { 0x01FA7 , 0x01F67 , 0x00345 }, + { 0x01FA8 , 0x01F68 , 0x00345 }, + { 0x01FA9 , 0x01F69 , 0x00345 }, + { 0x01FAA , 0x01F6A , 0x00345 }, + { 0x01FAB , 0x01F6B , 0x00345 }, + { 0x01FAC , 0x01F6C , 0x00345 }, + { 0x01FAD , 0x01F6D , 0x00345 }, + { 0x01FAE , 0x01F6E , 0x00345 }, + { 0x01FAF , 0x01F6F , 0x00345 }, + { 0x01FB0 , 0x003B1 , 0x00306 }, + { 0x01FB1 , 0x003B1 , 0x00304 }, + { 0x01FB2 , 0x01F70 , 0x00345 }, + { 0x01FB3 , 0x003B1 , 0x00345 }, + { 0x01FB4 , 0x003AC , 0x00345 }, + { 0x01FB6 , 0x003B1 , 0x00342 }, + { 0x01FB7 , 0x01FB6 , 0x00345 }, + { 0x01FB8 , 0x00391 , 0x00306 }, + { 0x01FB9 , 0x00391 , 0x00304 }, + { 0x01FBA , 0x00391 , 0x00300 }, + { 0x01FBC , 0x00391 , 0x00345 }, + { 0x01FC1 , 0x000A8 , 0x00342 }, + { 0x01FC2 , 0x01F74 , 0x00345 }, + { 0x01FC3 , 0x003B7 , 0x00345 }, + { 0x01FC4 , 0x003AE , 0x00345 }, + { 0x01FC6 , 0x003B7 , 0x00342 }, + { 0x01FC7 , 0x01FC6 , 0x00345 }, + { 0x01FC8 , 0x00395 , 0x00300 }, + { 0x01FCA , 0x00397 , 0x00300 }, + { 0x01FCC , 0x00397 , 0x00345 }, + { 0x01FCD , 0x01FBF , 0x00300 }, + { 0x01FCE , 0x01FBF , 0x00301 }, + { 0x01FCF , 0x01FBF , 0x00342 }, + { 0x01FD0 , 0x003B9 , 0x00306 }, + { 0x01FD1 , 0x003B9 , 0x00304 }, + { 0x01FD2 , 0x003CA , 0x00300 }, + { 0x01FD6 , 0x003B9 , 0x00342 }, + { 0x01FD7 , 0x003CA , 0x00342 }, + { 0x01FD8 , 0x00399 , 0x00306 }, + { 0x01FD9 , 0x00399 , 0x00304 }, + { 0x01FDA , 0x00399 , 0x00300 }, + { 0x01FDD , 0x01FFE , 0x00300 }, + { 0x01FDE , 0x01FFE , 0x00301 }, + { 0x01FDF , 0x01FFE , 0x00342 }, + { 0x01FE0 , 0x003C5 , 0x00306 }, + { 0x01FE1 , 0x003C5 , 0x00304 }, + { 0x01FE2 , 0x003CB , 0x00300 }, + { 0x01FE4 , 0x003C1 , 0x00313 }, + { 0x01FE5 , 0x003C1 , 0x00314 }, + { 0x01FE6 , 0x003C5 , 0x00342 }, + { 0x01FE7 , 0x003CB , 0x00342 }, + { 0x01FE8 , 0x003A5 , 0x00306 }, + { 0x01FE9 , 0x003A5 , 0x00304 }, + { 0x01FEA , 0x003A5 , 0x00300 }, + { 0x01FEC , 0x003A1 , 0x00314 }, + { 0x01FED , 0x000A8 , 0x00300 }, + { 0x01FF2 , 0x01F7C , 0x00345 }, + { 0x01FF3 , 0x003C9 , 0x00345 }, + { 0x01FF4 , 0x003CE , 0x00345 }, + { 0x01FF6 , 0x003C9 , 0x00342 }, + { 0x01FF7 , 0x01FF6 , 0x00345 }, + { 0x01FF8 , 0x0039F , 0x00300 }, + { 0x01FFA , 0x003A9 , 0x00300 }, + { 0x01FFC , 0x003A9 , 0x00345 }, + { 0x0219A , 0x02190 , 0x00338 }, + { 0x0219B , 0x02192 , 0x00338 }, + { 0x021AE , 0x02194 , 0x00338 }, + { 0x021CD , 0x021D0 , 0x00338 }, + { 0x021CE , 0x021D4 , 0x00338 }, + { 0x021CF , 0x021D2 , 0x00338 }, + { 0x02204 , 0x02203 , 0x00338 }, + { 0x02209 , 0x02208 , 0x00338 }, + { 0x0220C , 0x0220B , 0x00338 }, + { 0x02224 , 0x02223 , 0x00338 }, + { 0x02226 , 0x02225 , 0x00338 }, + { 0x02241 , 0x0223C , 0x00338 }, + { 0x02244 , 0x02243 , 0x00338 }, + { 0x02247 , 0x02245 , 0x00338 }, + { 0x02249 , 0x02248 , 0x00338 }, + { 0x02260 , 0x0003D , 0x00338 }, + { 0x02262 , 0x02261 , 0x00338 }, + { 0x0226D , 0x0224D , 0x00338 }, + { 0x0226E , 0x0003C , 0x00338 }, + { 0x0226F , 0x0003E , 0x00338 }, + { 0x02270 , 0x02264 , 0x00338 }, + { 0x02271 , 0x02265 , 0x00338 }, + { 0x02274 , 0x02272 , 0x00338 }, + { 0x02275 , 0x02273 , 0x00338 }, + { 0x02278 , 0x02276 , 0x00338 }, + { 0x02279 , 0x02277 , 0x00338 }, + { 0x02280 , 0x0227A , 0x00338 }, + { 0x02281 , 0x0227B , 0x00338 }, + { 0x02284 , 0x02282 , 0x00338 }, + { 0x02285 , 0x02283 , 0x00338 }, + { 0x02288 , 0x02286 , 0x00338 }, + { 0x02289 , 0x02287 , 0x00338 }, + { 0x022AC , 0x022A2 , 0x00338 }, + { 0x022AD , 0x022A8 , 0x00338 }, + { 0x022AE , 0x022A9 , 0x00338 }, + { 0x022AF , 0x022AB , 0x00338 }, + { 0x022E0 , 0x0227C , 0x00338 }, + { 0x022E1 , 0x0227D , 0x00338 }, + { 0x022E2 , 0x02291 , 0x00338 }, + { 0x022E3 , 0x02292 , 0x00338 }, + { 0x022EA , 0x022B2 , 0x00338 }, + { 0x022EB , 0x022B3 , 0x00338 }, + { 0x022EC , 0x022B4 , 0x00338 }, + { 0x022ED , 0x022B5 , 0x00338 }, + { 0x0304C , 0x0304B , 0x03099 }, + { 0x0304E , 0x0304D , 0x03099 }, + { 0x03050 , 0x0304F , 0x03099 }, + { 0x03052 , 0x03051 , 0x03099 }, + { 0x03054 , 0x03053 , 0x03099 }, + { 0x03056 , 0x03055 , 0x03099 }, + { 0x03058 , 0x03057 , 0x03099 }, + { 0x0305A , 0x03059 , 0x03099 }, + { 0x0305C , 0x0305B , 0x03099 }, + { 0x0305E , 0x0305D , 0x03099 }, + { 0x03060 , 0x0305F , 0x03099 }, + { 0x03062 , 0x03061 , 0x03099 }, + { 0x03065 , 0x03064 , 0x03099 }, + { 0x03067 , 0x03066 , 0x03099 }, + { 0x03069 , 0x03068 , 0x03099 }, + { 0x03070 , 0x0306F , 0x03099 }, + { 0x03071 , 0x0306F , 0x0309A }, + { 0x03073 , 0x03072 , 0x03099 }, + { 0x03074 , 0x03072 , 0x0309A }, + { 0x03076 , 0x03075 , 0x03099 }, + { 0x03077 , 0x03075 , 0x0309A }, + { 0x03079 , 0x03078 , 0x03099 }, + { 0x0307A , 0x03078 , 0x0309A }, + { 0x0307C , 0x0307B , 0x03099 }, + { 0x0307D , 0x0307B , 0x0309A }, + { 0x03094 , 0x03046 , 0x03099 }, + { 0x0309E , 0x0309D , 0x03099 }, + { 0x030AC , 0x030AB , 0x03099 }, + { 0x030AE , 0x030AD , 0x03099 }, + { 0x030B0 , 0x030AF , 0x03099 }, + { 0x030B2 , 0x030B1 , 0x03099 }, + { 0x030B4 , 0x030B3 , 0x03099 }, + { 0x030B6 , 0x030B5 , 0x03099 }, + { 0x030B8 , 0x030B7 , 0x03099 }, + { 0x030BA , 0x030B9 , 0x03099 }, + { 0x030BC , 0x030BB , 0x03099 }, + { 0x030BE , 0x030BD , 0x03099 }, + { 0x030C0 , 0x030BF , 0x03099 }, + { 0x030C2 , 0x030C1 , 0x03099 }, + { 0x030C5 , 0x030C4 , 0x03099 }, + { 0x030C7 , 0x030C6 , 0x03099 }, + { 0x030C9 , 0x030C8 , 0x03099 }, + { 0x030D0 , 0x030CF , 0x03099 }, + { 0x030D1 , 0x030CF , 0x0309A }, + { 0x030D3 , 0x030D2 , 0x03099 }, + { 0x030D4 , 0x030D2 , 0x0309A }, + { 0x030D6 , 0x030D5 , 0x03099 }, + { 0x030D7 , 0x030D5 , 0x0309A }, + { 0x030D9 , 0x030D8 , 0x03099 }, + { 0x030DA , 0x030D8 , 0x0309A }, + { 0x030DC , 0x030DB , 0x03099 }, + { 0x030DD , 0x030DB , 0x0309A }, + { 0x030F4 , 0x030A6 , 0x03099 }, + { 0x030F7 , 0x030EF , 0x03099 }, + { 0x030F8 , 0x030F0 , 0x03099 }, + { 0x030F9 , 0x030F1 , 0x03099 }, + { 0x030FA , 0x030F2 , 0x03099 }, + { 0x030FE , 0x030FD , 0x03099 }, + { 0x1109A , 0x11099 , 0x110BA }, + { 0x1109C , 0x1109B , 0x110BA }, + { 0x110AB , 0x110A5 , 0x110BA }, +}; + #endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */ + diff --git a/contrib/libarchive/libarchive/archive_string_sprintf.c b/contrib/libarchive/libarchive/archive_string_sprintf.c index f177d86..8dc1487 100644 --- a/contrib/libarchive/libarchive/archive_string_sprintf.c +++ b/contrib/libarchive/libarchive/archive_string_sprintf.c @@ -38,7 +38,9 @@ __FBSDID("$FreeBSD$"); * here. This is only used to format error messages, so doesn't * require any floating-point support or field-width handling. */ - +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif #include <stdio.h> #include "archive_string.h" @@ -129,7 +131,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, break; case 'c': s = va_arg(ap, int); - archive_strappend_char(as, s); + archive_strappend_char(as, (char)s); break; case 'd': switch(long_flag) { @@ -146,7 +148,9 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, pw = va_arg(ap, wchar_t *); if (pw == NULL) pw = L"(null)"; - archive_string_append_from_wcs(as, pw, wcslen(pw)); + if (archive_string_append_from_wcs(as, pw, + wcslen(pw)) != 0 && errno == ENOMEM) + __archive_errx(1, "Out of memory"); break; default: p2 = va_arg(ap, char *); @@ -160,7 +164,9 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, pw = va_arg(ap, wchar_t *); if (pw == NULL) pw = L"(null)"; - archive_string_append_from_wcs(as, pw, wcslen(pw)); + if (archive_string_append_from_wcs(as, pw, + wcslen(pw)) != 0 && errno == ENOMEM) + __archive_errx(1, "Out of memory"); break; case 'o': case 'u': case 'x': case 'X': /* Common handling for unsigned integer formats. */ diff --git a/contrib/libarchive/libarchive/archive_util.3 b/contrib/libarchive/libarchive/archive_util.3 index fd48f6f..99ab842 100644 --- a/contrib/libarchive/libarchive/archive_util.3 +++ b/contrib/libarchive/libarchive/archive_util.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 8, 2005 +.Dd February 2, 2012 .Dt ARCHIVE_UTIL 3 .Os .Sh NAME @@ -43,6 +43,8 @@ .Nm archive_position , .Nm archive_set_error .Nd libarchive utility functions +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft void diff --git a/contrib/libarchive/libarchive/archive_util.c b/contrib/libarchive/libarchive/archive_util.c index 7c45d7e..cdd151e 100644 --- a/contrib/libarchive/libarchive/archive_util.c +++ b/contrib/libarchive/libarchive/archive_util.c @@ -243,8 +243,9 @@ __archive_mktemp(const char *tmpdir) archive_wstrcpy(&temp_name, tmp); free(tmp); } else { - archive_wstring_append_from_mbs(&temp_name, tmpdir, - strlen(tmpdir)); + if (archive_wstring_append_from_mbs(&temp_name, tmpdir, + strlen(tmpdir)) < 0) + goto exit_tmpfile; if (temp_name.s[temp_name.length-1] != L'/') archive_wstrappend_wchar(&temp_name, L'/'); } diff --git a/contrib/libarchive/libarchive/archive_write.3 b/contrib/libarchive/libarchive/archive_write.3 index 2055665..228bc2c 100644 --- a/contrib/libarchive/libarchive/archive_write.3 +++ b/contrib/libarchive/libarchive/archive_write.3 @@ -24,12 +24,14 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE 3 .Os .Sh NAME .Nm archive_write .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Sh DESCRIPTION diff --git a/contrib/libarchive/libarchive/archive_write.c b/contrib/libarchive/libarchive/archive_write.c index cca06ad..5b5db52 100644 --- a/contrib/libarchive/libarchive/archive_write.c +++ b/contrib/libarchive/libarchive/archive_write.c @@ -380,7 +380,7 @@ archive_write_client_write(struct archive_write_filter *f, } } - while ((size_t)remaining > state->buffer_size) { + while ((size_t)remaining >= state->buffer_size) { /* Write out full blocks directly to client. */ bytes_written = (a->client_writer)(&a->archive, a->client_data, buff, state->buffer_size); @@ -623,7 +623,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry) if (a->skip_file_set && archive_entry_dev_is_set(entry) && archive_entry_ino_is_set(entry) && - archive_entry_dev(entry) == a->skip_file_dev && + archive_entry_dev(entry) == (dev_t)a->skip_file_dev && archive_entry_ino64(entry) == a->skip_file_ino) { archive_set_error(&a->archive, 0, "Can't add archive to itself"); diff --git a/contrib/libarchive/libarchive_fe/matching.h b/contrib/libarchive/libarchive/archive_write_add_filter.c index f4edebd..915290a 100644 --- a/contrib/libarchive/libarchive_fe/matching.h +++ b/contrib/libarchive/libarchive/archive_write_add_filter.c @@ -1,13 +1,12 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2012 Ondrej Holy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. @@ -22,25 +21,46 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ */ -#ifndef MATCHING_H -#define MATCHING_H +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); -struct lafe_matching; +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif -int lafe_exclude(struct lafe_matching **matching, const char *pattern); -int lafe_exclude_from_file(struct lafe_matching **matching, - const char *pathname); -int lafe_include(struct lafe_matching **matching, const char *pattern); -int lafe_include_from_file(struct lafe_matching **matching, - const char *pathname, int nullSeparator); +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif -int lafe_excluded(struct lafe_matching *, const char *pathname); -void lafe_cleanup_exclusions(struct lafe_matching **); -int lafe_unmatched_inclusions(struct lafe_matching *); -int lafe_unmatched_inclusions_warn(struct lafe_matching *, const char *msg); +#include "archive.h" +#include "archive_private.h" -#endif +/* A table that maps filter codes to functions. */ +static +struct { int code; int (*setter)(struct archive *); } codes[] = +{ + { ARCHIVE_FILTER_NONE, archive_write_add_filter_none }, + { ARCHIVE_FILTER_GZIP, archive_write_add_filter_gzip }, + { ARCHIVE_FILTER_BZIP2, archive_write_add_filter_bzip2 }, + { ARCHIVE_FILTER_COMPRESS, archive_write_add_filter_compress }, + { ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma }, + { ARCHIVE_FILTER_XZ, archive_write_add_filter_xz }, + { ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip }, + { -1, NULL } +}; + +int +archive_write_add_filter(struct archive *a, int code) +{ + int i; + + for (i = 0; codes[i].code != -1; i++) { + if (code == codes[i].code) + return ((codes[i].setter)(a)); + } + + archive_set_error(a, EINVAL, "No such filter"); + return (ARCHIVE_FATAL); +} diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c b/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c index ef1fcf4..2b48959 100644 --- a/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c +++ b/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c @@ -133,10 +133,18 @@ archive_compressor_bzip2_open(struct archive_write_filter *f) if (ret != 0) return (ret); - /* TODO: Find a better way to size this. (Maybe look at the */ - /* block size expected by the following filter?) */ if (data->compressed == NULL) { - data->compressed_buffer_size = 65536; + size_t bs = 65536, bpb; + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of the of bytes + * per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + data->compressed_buffer_size = bs; data->compressed = (char *)malloc(data->compressed_buffer_size); if (data->compressed == NULL) { diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_compress.c b/contrib/libarchive/libarchive/archive_write_add_filter_compress.c index 465ff0e..4923316 100644 --- a/contrib/libarchive/libarchive/archive_write_add_filter_compress.c +++ b/contrib/libarchive/libarchive/archive_write_add_filter_compress.c @@ -148,6 +148,7 @@ archive_compressor_compress_open(struct archive_write_filter *f) { int ret; struct private_data *state; + size_t bs = 65536, bpb; f->code = ARCHIVE_COMPRESSION_COMPRESS; f->name = "compress"; @@ -163,7 +164,16 @@ archive_compressor_compress_open(struct archive_write_filter *f) return (ARCHIVE_FATAL); } - state->compressed_buffer_size = 65536; + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of the of bytes + * per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + state->compressed_buffer_size = bs; state->compressed = malloc(state->compressed_buffer_size); if (state->compressed == NULL) { @@ -386,12 +396,12 @@ archive_compressor_compress_write(struct archive_write_filter *f, state->checkpoint = state->in_count + CHECK_GAP; - if (state->in_count <= 0x007fffff) - ratio = state->in_count * 256 / state->out_count; - else if ((ratio = state->out_count / 256) == 0) + if (state->in_count <= 0x007fffff && state->out_count != 0) + ratio = (int)(state->in_count * 256 / state->out_count); + else if ((ratio = (int)(state->out_count / 256)) == 0) ratio = 0x7fffffff; else - ratio = state->in_count / ratio; + ratio = (int)(state->in_count / ratio); if (ratio > state->compress_ratio) state->compress_ratio = ratio; diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c b/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c index d761540..b156477 100644 --- a/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c +++ b/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c @@ -135,7 +135,17 @@ archive_compressor_gzip_open(struct archive_write_filter *f) return (ret); if (data->compressed == NULL) { - data->compressed_buffer_size = 65536; + size_t bs = 65536, bpb; + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of the of bytes + * per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + data->compressed_buffer_size = bs; data->compressed = (unsigned char *)malloc(data->compressed_buffer_size); if (data->compressed == NULL) { @@ -155,10 +165,10 @@ archive_compressor_gzip_open(struct archive_write_filter *f) data->compressed[1] = 0x8b; data->compressed[2] = 0x08; /* "Deflate" compression */ data->compressed[3] = 0; /* No options */ - data->compressed[4] = (t)&0xff; /* Timestamp */ - data->compressed[5] = (t>>8)&0xff; - data->compressed[6] = (t>>16)&0xff; - data->compressed[7] = (t>>24)&0xff; + data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */ + data->compressed[5] = (uint8_t)(t>>8)&0xff; + data->compressed[6] = (uint8_t)(t>>16)&0xff; + data->compressed[7] = (uint8_t)(t>>24)&0xff; data->compressed[8] = 0; /* No deflate options */ data->compressed[9] = 3; /* OS=Unix */ data->stream.next_out += 10; @@ -270,14 +280,14 @@ archive_compressor_gzip_close(struct archive_write_filter *f) } if (ret == ARCHIVE_OK) { /* Build and write out 8-byte trailer. */ - trailer[0] = (data->crc)&0xff; - trailer[1] = (data->crc >> 8)&0xff; - trailer[2] = (data->crc >> 16)&0xff; - trailer[3] = (data->crc >> 24)&0xff; - trailer[4] = (data->total_in)&0xff; - trailer[5] = (data->total_in >> 8)&0xff; - trailer[6] = (data->total_in >> 16)&0xff; - trailer[7] = (data->total_in >> 24)&0xff; + trailer[0] = (uint8_t)(data->crc)&0xff; + trailer[1] = (uint8_t)(data->crc >> 8)&0xff; + trailer[2] = (uint8_t)(data->crc >> 16)&0xff; + trailer[3] = (uint8_t)(data->crc >> 24)&0xff; + trailer[4] = (uint8_t)(data->total_in)&0xff; + trailer[5] = (uint8_t)(data->total_in >> 8)&0xff; + trailer[6] = (uint8_t)(data->total_in >> 16)&0xff; + trailer[7] = (uint8_t)(data->total_in >> 24)&0xff; ret = __archive_write_filter(f->next_filter, trailer, 8); } diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_program.c b/contrib/libarchive/libarchive/archive_write_add_filter_program.c index 3dcc9df..d7d38f7 100644 --- a/contrib/libarchive/libarchive/archive_write_add_filter_program.c +++ b/contrib/libarchive/libarchive/archive_write_add_filter_program.c @@ -171,60 +171,62 @@ child_write(struct archive_write_filter *f, const char *buf, size_t buf_len) if (buf_len == 0) return (-1); -restart_write: - do { - ret = write(data->child_stdin, buf, buf_len); - } while (ret == -1 && errno == EINTR); - - if (ret > 0) - return (ret); - if (ret == 0) { - close(data->child_stdin); - data->child_stdin = -1; - fcntl(data->child_stdout, F_SETFL, 0); - return (0); - } - if (ret == -1 && errno != EAGAIN) - return (-1); - - if (data->child_stdout == -1) { - fcntl(data->child_stdin, F_SETFL, 0); - __archive_check_child(data->child_stdin, data->child_stdout); - goto restart_write; - } + for (;;) { + do { + ret = write(data->child_stdin, buf, buf_len); + } while (ret == -1 && errno == EINTR); + + if (ret > 0) + return (ret); + if (ret == 0) { + close(data->child_stdin); + data->child_stdin = -1; + fcntl(data->child_stdout, F_SETFL, 0); + return (0); + } + if (ret == -1 && errno != EAGAIN) + return (-1); + + if (data->child_stdout == -1) { + fcntl(data->child_stdin, F_SETFL, 0); + __archive_check_child(data->child_stdin, + data->child_stdout); + continue; + } - do { - ret = read(data->child_stdout, - data->child_buf + data->child_buf_avail, - data->child_buf_len - data->child_buf_avail); - } while (ret == -1 && errno == EINTR); + do { + ret = read(data->child_stdout, + data->child_buf + data->child_buf_avail, + data->child_buf_len - data->child_buf_avail); + } while (ret == -1 && errno == EINTR); - if (ret == 0 || (ret == -1 && errno == EPIPE)) { - close(data->child_stdout); - data->child_stdout = -1; - fcntl(data->child_stdin, F_SETFL, 0); - goto restart_write; - } - if (ret == -1 && errno == EAGAIN) { - __archive_check_child(data->child_stdin, data->child_stdout); - goto restart_write; - } - if (ret == -1) - return (-1); + if (ret == 0 || (ret == -1 && errno == EPIPE)) { + close(data->child_stdout); + data->child_stdout = -1; + fcntl(data->child_stdin, F_SETFL, 0); + continue; + } + if (ret == -1 && errno == EAGAIN) { + __archive_check_child(data->child_stdin, + data->child_stdout); + continue; + } + if (ret == -1) + return (-1); - data->child_buf_avail += ret; + data->child_buf_avail += ret; - ret = __archive_write_filter(f->next_filter, - data->child_buf, data->child_buf_avail); - if (ret <= 0) - return (-1); + ret = __archive_write_filter(f->next_filter, + data->child_buf, data->child_buf_avail); + if (ret <= 0) + return (-1); - if ((size_t)ret < data->child_buf_avail) { - memmove(data->child_buf, data->child_buf + ret, - data->child_buf_avail - ret); + if ((size_t)ret < data->child_buf_avail) { + memmove(data->child_buf, data->child_buf + ret, + data->child_buf_avail - ret); + } + data->child_buf_avail -= ret; } - data->child_buf_avail -= ret; - goto restart_write; } /* diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_xz.c b/contrib/libarchive/libarchive/archive_write_add_filter_xz.c index c6a9677..834d596 100644 --- a/contrib/libarchive/libarchive/archive_write_add_filter_xz.c +++ b/contrib/libarchive/libarchive/archive_write_add_filter_xz.c @@ -298,7 +298,17 @@ archive_compressor_xz_open(struct archive_write_filter *f) return (ret); if (data->compressed == NULL) { - data->compressed_buffer_size = 65536; + size_t bs = 65536, bpb; + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of the of bytes + * per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + data->compressed_buffer_size = bs; data->compressed = (unsigned char *)malloc(data->compressed_buffer_size); if (data->compressed == NULL) { diff --git a/contrib/libarchive/libarchive/archive_write_blocksize.3 b/contrib/libarchive/libarchive/archive_write_blocksize.3 index 96c7538..afd84ea 100644 --- a/contrib/libarchive/libarchive/archive_write_blocksize.3 +++ b/contrib/libarchive/libarchive/archive_write_blocksize.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_BLOCKSIZE 3 .Os .Sh NAME @@ -33,6 +33,8 @@ .Nm archive_write_get_bytes_in_last_block , .Nm archive_write_set_bytes_in_last_block .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_write_data.3 b/contrib/libarchive/libarchive/archive_write_data.3 index fc399bc..cfd5cd5 100644 --- a/contrib/libarchive/libarchive/archive_write_data.3 +++ b/contrib/libarchive/libarchive/archive_write_data.3 @@ -22,14 +22,16 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $ +.\" $FreeBSD$ .\" -.Dd March 23, 2011 -.Dt ARCHIVE_WRITE 3 +.Dd February 2, 2012 +.Dt ARCHIVE_WRITE_DATA 3 .Os .Sh NAME .Nm archive_write_data .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft ssize_t diff --git a/contrib/libarchive/libarchive/archive_write_disk.3 b/contrib/libarchive/libarchive/archive_write_disk.3 index 8128ed3..fa925cc 100644 --- a/contrib/libarchive/libarchive/archive_write_disk.3 +++ b/contrib/libarchive/libarchive/archive_write_disk.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 5, 2008 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_DISK 3 .Os .Sh NAME @@ -42,6 +42,8 @@ .Nm archive_write_finish .Nm archive_write_free .Nd functions for creating objects on disk +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft struct archive * diff --git a/contrib/libarchive/libarchive/archive_write_disk_posix.c b/contrib/libarchive/libarchive/archive_write_disk_posix.c index 752ce89..d79b0f6 100644 --- a/contrib/libarchive/libarchive/archive_write_disk_posix.c +++ b/contrib/libarchive/libarchive/archive_write_disk_posix.c @@ -188,8 +188,8 @@ struct archive_write_disk { struct fixup_entry *current_fixup; int64_t user_uid; int skip_file_set; - dev_t skip_file_dev; - ino_t skip_file_ino; + int64_t skip_file_dev; + int64_t skip_file_ino; time_t start_time; int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); @@ -1143,9 +1143,10 @@ restore_entry(struct archive_write_disk *a) /* If it's our archive, we're done. */ if (a->skip_file_set && - a->st.st_dev == a->skip_file_dev && - a->st.st_ino == a->skip_file_ino) { - archive_set_error(&a->archive, 0, "Refusing to overwrite archive"); + a->st.st_dev == (dev_t)a->skip_file_dev && + a->st.st_ino == (ino_t)a->skip_file_ino) { + archive_set_error(&a->archive, 0, + "Refusing to overwrite archive"); return (ARCHIVE_FAILED); } @@ -1163,7 +1164,7 @@ restore_entry(struct archive_write_disk *a) /* A dir is in the way of a non-dir, rmdir it. */ if (rmdir(a->name) != 0) { archive_set_error(&a->archive, errno, - "Can't remove already-existing dir"); + "Can't replace existing directory with non-directory"); return (ARCHIVE_FAILED); } /* Try again. */ @@ -2529,7 +2530,7 @@ set_mac_metadata(struct archive_write_disk *a, const char *pathname, } written = write(fd, metadata, metadata_size); close(fd); - if (written != metadata_size + if ((size_t)written != metadata_size || copyfile(tmp.s, pathname, 0, COPYFILE_UNPACK | COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR)) { @@ -2584,7 +2585,7 @@ set_acl(struct archive_write_disk *a, int fd, const char *name, acl_t acl; acl_entry_t acl_entry; acl_permset_t acl_permset; - int ret; + int ret, r; int ae_type, ae_permset, ae_tag, ae_id; uid_t ae_uid; gid_t ae_gid; @@ -2596,9 +2597,9 @@ set_acl(struct archive_write_disk *a, int fd, const char *name, if (entries == 0) return (ARCHIVE_OK); acl = acl_init(entries); - while (archive_acl_next(&a->archive, abstract_acl, + while ((r = archive_acl_next(&a->archive, abstract_acl, ae_requested_type, &ae_type, &ae_permset, &ae_tag, &ae_id, - &ae_name) == ARCHIVE_OK) { + &ae_name)) == ARCHIVE_OK) { acl_create_entry(&acl, &acl_entry); switch (ae_tag) { @@ -2640,6 +2641,12 @@ set_acl(struct archive_write_disk *a, int fd, const char *name, if (ae_permset & ARCHIVE_ENTRY_ACL_READ) acl_add_perm(acl_permset, ACL_READ); } + if (r == ARCHIVE_FATAL) { + acl_free(acl); + archive_set_error(&a->archive, errno, + "Failed to archive_acl_next"); + return (r); + } /* Try restoring the ACL through 'fd' if we can. */ #if HAVE_ACL_SET_FD diff --git a/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c b/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c index a6b5bf6..7fc42c8 100644 --- a/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c +++ b/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c @@ -122,6 +122,7 @@ lookup_gid(void *private_data, const char *gname, int64_t gid) char _buffer[128]; size_t bufsize = 128; char *buffer = _buffer; + char *allocated = NULL; struct group grent, *result; int r; @@ -133,16 +134,15 @@ lookup_gid(void *private_data, const char *gname, int64_t gid) if (r != ERANGE) break; bufsize *= 2; - if (buffer != _buffer) - free(buffer); - buffer = malloc(bufsize); - if (buffer == NULL) + free(allocated); + allocated = malloc(bufsize); + if (allocated == NULL) break; + buffer = allocated; } if (result != NULL) gid = result->gr_gid; - if (buffer != _buffer) - free(buffer); + free(allocated); } # else /* HAVE_GETGRNAM_R */ { @@ -158,7 +158,7 @@ lookup_gid(void *private_data, const char *gname, int64_t gid) #else #error No way to perform gid lookups on this platform #endif - b->id = gid; + b->id = (gid_t)gid; return (gid); } @@ -192,6 +192,7 @@ lookup_uid(void *private_data, const char *uname, int64_t uid) char _buffer[128]; size_t bufsize = 128; char *buffer = _buffer; + char *allocated = NULL; struct passwd pwent, *result; int r; @@ -203,16 +204,15 @@ lookup_uid(void *private_data, const char *uname, int64_t uid) if (r != ERANGE) break; bufsize *= 2; - if (buffer != _buffer) - free(buffer); - buffer = malloc(bufsize); - if (buffer == NULL) + free(allocated); + allocated = malloc(bufsize); + if (allocated == NULL) break; + buffer = allocated; } if (result != NULL) uid = result->pw_uid; - if (buffer != _buffer) - free(buffer); + free(allocated); } # else /* HAVE_GETPWNAM_R */ { @@ -228,7 +228,7 @@ lookup_uid(void *private_data, const char *uname, int64_t uid) #else #error No way to look up uids on this platform #endif - b->id = uid; + b->id = (uid_t)uid; return (uid); } diff --git a/contrib/libarchive/libarchive/archive_write_filter.3 b/contrib/libarchive/libarchive/archive_write_filter.3 index 00438d4..3ca248b 100644 --- a/contrib/libarchive/libarchive/archive_write_filter.3 +++ b/contrib/libarchive/libarchive/archive_write_filter.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_FILTER 3 .Os .Sh NAME @@ -36,6 +36,8 @@ .Nm archive_write_add_filter_none , .Nm archive_write_add_filter_program , .Nm archive_write_add_filter_xz +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_write_finish_entry.3 b/contrib/libarchive/libarchive/archive_write_finish_entry.3 index 3add601..d881c80 100644 --- a/contrib/libarchive/libarchive/archive_write_finish_entry.3 +++ b/contrib/libarchive/libarchive/archive_write_finish_entry.3 @@ -22,14 +22,16 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $ +.\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_FINISH_ENTRY 3 .Os .Sh NAME .Nm archive_write_finish_entry .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_write_format.3 b/contrib/libarchive/libarchive/archive_write_format.3 index e12e7d8..dad2f7d 100644 --- a/contrib/libarchive/libarchive/archive_write_format.3 +++ b/contrib/libarchive/libarchive/archive_write_format.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_FORMAT 3 .Os .Sh NAME @@ -35,6 +35,8 @@ .Nm archive_write_set_format_shar_dump , .Nm archive_write_set_format_ustar .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_write_free.3 b/contrib/libarchive/libarchive/archive_write_free.3 index 27efe18..ac01dd4 100644 --- a/contrib/libarchive/libarchive/archive_write_free.3 +++ b/contrib/libarchive/libarchive/archive_write_free.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_FREE 3 .Os .Sh NAME @@ -32,6 +32,8 @@ .Nm archive_write_finish , .Nm archive_write_free .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_write_header.3 b/contrib/libarchive/libarchive/archive_write_header.3 index 423b38e..4de58f3 100644 --- a/contrib/libarchive/libarchive/archive_write_header.3 +++ b/contrib/libarchive/libarchive/archive_write_header.3 @@ -24,12 +24,14 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_HEADER 3 .Os .Sh NAME .Nm archive_write_header .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_write_new.3 b/contrib/libarchive/libarchive/archive_write_new.3 index d626ccb..f05d269 100644 --- a/contrib/libarchive/libarchive/archive_write_new.3 +++ b/contrib/libarchive/libarchive/archive_write_new.3 @@ -24,12 +24,14 @@ .\" .\" $FreeBSD$ .\" -.Dd March 23, 2011 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_NEW 3 .Os .Sh NAME .Nm archive_write_new .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft struct archive * diff --git a/contrib/libarchive/libarchive/archive_write_open.3 b/contrib/libarchive/libarchive/archive_write_open.3 index 0d12cb3..4037248 100644 --- a/contrib/libarchive/libarchive/archive_write_open.3 +++ b/contrib/libarchive/libarchive/archive_write_open.3 @@ -22,10 +22,10 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $ +.\" $FreeBSD$ .\" -.Dd March 23, 2011 -.Dt ARCHIVE_WRITE 3 +.Dd February 2, 2012 +.Dt ARCHIVE_WRITE_OPEN 3 .Os .Sh NAME .Nm archive_write_open , @@ -34,6 +34,8 @@ .Nm archive_write_open_filename , .Nm archive_write_open_memory .Nd functions for creating archives +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .In archive.h .Ft int diff --git a/contrib/libarchive/libarchive/archive_write_open_filename.c b/contrib/libarchive/libarchive/archive_write_open_filename.c index 4bd7b43..6635bfb 100644 --- a/contrib/libarchive/libarchive/archive_write_open_filename.c +++ b/contrib/libarchive/libarchive/archive_write_open_filename.c @@ -54,16 +54,13 @@ __FBSDID("$FreeBSD$"); struct write_file_data { int fd; - char mbs_filename; - union { - char m[1]; - wchar_t w[1]; - } filename; /* Must be last! */ + struct archive_mstring filename; }; static int file_close(struct archive *, void *); static int file_open(struct archive *, void *); static ssize_t file_write(struct archive *, void *, const void *buff, size_t); +static int open_filename(struct archive *, int, const void *); int archive_write_open_file(struct archive *a, const char *filename) @@ -74,76 +71,69 @@ archive_write_open_file(struct archive *a, const char *filename) int archive_write_open_filename(struct archive *a, const char *filename) { - struct write_file_data *mine; if (filename == NULL || filename[0] == '\0') return (archive_write_open_fd(a, 1)); - mine = (struct write_file_data *)malloc(sizeof(*mine) + strlen(filename)); - if (mine == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - strcpy(mine->filename.m, filename); - mine->mbs_filename = 1; - mine->fd = -1; - return (archive_write_open(a, mine, - file_open, file_write, file_close)); + return (open_filename(a, 1, filename)); } int archive_write_open_filename_w(struct archive *a, const wchar_t *filename) { -#if defined(_WIN32) && !defined(__CYGWIN__) - struct write_file_data *mine; if (filename == NULL || filename[0] == L'\0') return (archive_write_open_fd(a, 1)); - mine = malloc(sizeof(*mine) + wcslen(filename) * sizeof(wchar_t)); + return (open_filename(a, 0, filename)); +} + +static int +open_filename(struct archive *a, int mbs_fn, const void *filename) +{ + struct write_file_data *mine; + int r; + + mine = (struct write_file_data *)calloc(1, sizeof(*mine)); if (mine == NULL) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } - wcscpy(mine->filename.w, filename); - mine->mbs_filename = 0; + if (mbs_fn) + r = archive_mstring_copy_mbs(&mine->filename, filename); + else + r = archive_mstring_copy_wcs(&mine->filename, filename); + if (r < 0) { + if (errno == ENOMEM) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + if (mbs_fn) + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Can't convert '%s' to WCS", + (const char *)filename); + else + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Can't convert '%S' to MBS", + (const wchar_t *)filename); + return (ARCHIVE_FAILED); + } mine->fd = -1; return (archive_write_open(a, mine, file_open, file_write, file_close)); -#else - /* - * POSIX system does not support a wchar_t interface for - * open() system call, so we have to translate a wchar_t - * filename to multi-byte one and use it. - */ - struct archive_string fn; - int r; - - if (filename == NULL || filename[0] == L'\0') - return (archive_write_open_fd(a, 1)); - - archive_string_init(&fn); - if (archive_string_append_from_wcs(&fn, filename, - wcslen(filename)) != 0) { - archive_set_error(a, EINVAL, - "Failed to convert a wide-character filename to" - " a multi-byte filename"); - archive_string_free(&fn); - return (ARCHIVE_FATAL); - } - r = archive_write_open_filename(a, fn.s); - archive_string_free(&fn); - return (r); -#endif } - static int file_open(struct archive *a, void *client_data) { int flags; struct write_file_data *mine; struct stat st; +#if defined(_WIN32) && !defined(__CYGWIN__) + wchar_t *fullpath; +#endif + const wchar_t *wcs; + const char *mbs; mine = (struct write_file_data *)client_data; flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; @@ -151,46 +141,51 @@ file_open(struct archive *a, void *client_data) /* * Open the file. */ - if (mine->mbs_filename) { - mine->fd = open(mine->filename.m, flags, 0666); - if (mine->fd < 0) { - archive_set_error(a, errno, "Failed to open '%s'", - mine->filename.m); - return (ARCHIVE_FATAL); - } - - if (fstat(mine->fd, &st) != 0) { - archive_set_error(a, errno, "Couldn't stat '%s'", - mine->filename.m); - return (ARCHIVE_FATAL); - } - } else { + mbs = NULL; wcs = NULL; #if defined(_WIN32) && !defined(__CYGWIN__) - mine->fd = _wopen(mine->filename.w, flags, 0666); - if (mine->fd < 0 && errno == ENOENT) { - wchar_t *fullpath; - fullpath = __la_win_permissive_name_w(mine->filename.w); - if (fullpath != NULL) { - mine->fd = _wopen(fullpath, flags, 0666); - free(fullpath); - } - } - if (mine->fd < 0) { - archive_set_error(a, errno, "Failed to open '%S'", - mine->filename.w); - return (ARCHIVE_FATAL); - } - - if (fstat(mine->fd, &st) != 0) { - archive_set_error(a, errno, "Couldn't stat '%S'", - mine->filename.w); - return (ARCHIVE_FATAL); + if (archive_mstring_get_wcs(a, &mine->filename, &wcs) != 0) { + if (errno == ENOMEM) + archive_set_error(a, errno, "No memory"); + else { + archive_mstring_get_mbs(a, &mine->filename, &mbs); + archive_set_error(a, errno, + "Can't convert '%s' to WCS", mbs); } + return (ARCHIVE_FATAL); + } + fullpath = __la_win_permissive_name_w(wcs); + if (fullpath != NULL) { + mine->fd = _wopen(fullpath, flags, 0666); + free(fullpath); + } else + mine->fd = _wopen(wcs, flags, 0666); #else - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Unexpedted operation in archive_write_open_filename"); + if (archive_mstring_get_mbs(a, &mine->filename, &mbs) != 0) { + if (errno == ENOMEM) + archive_set_error(a, errno, "No memory"); + else { + archive_mstring_get_wcs(a, &mine->filename, &wcs); + archive_set_error(a, errno, + "Can't convert '%S' to MBS", wcs); + } return (ARCHIVE_FATAL); + } + mine->fd = open(mbs, flags, 0666); #endif + if (mine->fd < 0) { + if (mbs != NULL) + archive_set_error(a, errno, "Failed to open '%s'", mbs); + else + archive_set_error(a, errno, "Failed to open '%S'", wcs); + return (ARCHIVE_FATAL); + } + + if (fstat(mine->fd, &st) != 0) { + if (mbs != NULL) + archive_set_error(a, errno, "Couldn't stat '%s'", mbs); + else + archive_set_error(a, errno, "Couldn't stat '%S'", wcs); + return (ARCHIVE_FATAL); } /* @@ -218,7 +213,8 @@ file_open(struct archive *a, void *client_data) } static ssize_t -file_write(struct archive *a, void *client_data, const void *buff, size_t length) +file_write(struct archive *a, void *client_data, const void *buff, + size_t length) { struct write_file_data *mine; ssize_t bytesWritten; @@ -243,6 +239,7 @@ file_close(struct archive *a, void *client_data) (void)a; /* UNUSED */ close(mine->fd); + archive_mstring_clean(&mine->filename); free(mine); return (ARCHIVE_OK); } diff --git a/contrib/libarchive/libarchive/archive_write_private.h b/contrib/libarchive/libarchive/archive_write_private.h index c979810..f34e8eb 100644 --- a/contrib/libarchive/libarchive/archive_write_private.h +++ b/contrib/libarchive/libarchive/archive_write_private.h @@ -72,7 +72,7 @@ struct archive_write { /* Dev/ino of the archive being written. */ int skip_file_set; - dev_t skip_file_dev; + int64_t skip_file_dev; int64_t skip_file_ino; /* Utility: Pointer to a block of nulls. */ diff --git a/contrib/libarchive/libarchive/archive_write_set_format_7zip.c b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c index f4dbe30..7e1240a 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_7zip.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c @@ -199,7 +199,7 @@ struct _7zip { /* * Compressed data buffer. */ - unsigned char wbuff[1024 * 64]; + unsigned char wbuff[512 * 20 * 6]; size_t wbuff_remaining; /* @@ -498,7 +498,7 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry) if (archive_entry_filetype(entry) == AE_IFLNK) { ssize_t bytes; const void *p = (const void *)archive_entry_symlink(entry); - bytes = compress_out(a, p, file->size, ARCHIVE_Z_RUN); + bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN); if (bytes < 0) return ((int)bytes); zip->entry_crc32 = crc32(zip->entry_crc32, p, bytes); @@ -580,11 +580,11 @@ compress_out(struct archive_write *a, const void *buff, size_t s, } while (zip->stream.avail_in); if (run == ARCHIVE_Z_FINISH) { uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out; - if (write_to_temp(a, zip->wbuff, bytes) != ARCHIVE_OK) + if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK) return (ARCHIVE_FATAL); if ((zip->crc32flg & ENCODED_CRC32) && bytes) zip->encoded_crc32 = crc32(zip->encoded_crc32, - zip->wbuff, bytes); + zip->wbuff, (unsigned)bytes); } return (s); @@ -599,7 +599,7 @@ _7z_write_data(struct archive_write *a, const void *buff, size_t s) zip = (struct _7zip *)a->format_data; if (s > zip->entry_bytes_remaining) - s = zip->entry_bytes_remaining; + s = (size_t)zip->entry_bytes_remaining; if (s == 0 || zip->cur_file == NULL) return (0); bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN); @@ -622,7 +622,7 @@ _7z_finish_entry(struct archive_write *a) return (ARCHIVE_OK); while (zip->entry_bytes_remaining > 0) { - s = zip->entry_bytes_remaining; + s = (size_t)zip->entry_bytes_remaining; if (s > a->null_length) s = a->null_length; r = _7z_write_data(a, a->nulls, s); @@ -1151,7 +1151,7 @@ make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti) struct _7zip *zip = (struct _7zip *)a->format_data; struct file *file; int r; - uint8_t mask, byte; + uint8_t b, mask; /* * Make Time Bools. @@ -1188,23 +1188,23 @@ make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti) if (r < 0) return (r); - byte = 0; + b = 0; mask = 0x80; file = zip->file_list.first; for (;file != NULL; file = file->next) { if (file->flg & flg) - byte |= mask; + b |= mask; mask >>= 1; if (mask == 0) { - r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN); + r = compress_out(a, &b, 1, ARCHIVE_Z_RUN); if (r < 0) return (r); mask = 0x80; - byte = 0; + b = 0; } } if (mask != 0x80) { - r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN); + r = compress_out(a, &b, 1, ARCHIVE_Z_RUN); if (r < 0) return (r); } @@ -1240,7 +1240,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size, struct _7zip *zip = (struct _7zip *)a->format_data; struct file *file; int r; - uint8_t mask, byte; + uint8_t b, mask; /* * Make FilesInfo. @@ -1288,23 +1288,23 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size, if (r < 0) return (r); - byte = 0; + b = 0; mask = 0x80; file = zip->file_list.first; for (;file != NULL; file = file->next) { if (file->size == 0) - byte |= mask; + b |= mask; mask >>= 1; if (mask == 0) { - r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN); + r = compress_out(a, &b, 1, ARCHIVE_Z_RUN); if (r < 0) return (r); mask = 0x80; - byte = 0; + b = 0; } } if (mask != 0x80) { - r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN); + r = compress_out(a, &b, 1, ARCHIVE_Z_RUN); if (r < 0) return (r); } @@ -1321,25 +1321,25 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size, if (r < 0) return (r); - byte = 0; + b = 0; mask = 0x80; file = zip->file_list.first; for (;file != NULL; file = file->next) { if (file->size) continue; if (!file->dir) - byte |= mask; + b |= mask; mask >>= 1; if (mask == 0) { - r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN); + r = compress_out(a, &b, 1, ARCHIVE_Z_RUN); if (r < 0) return (r); mask = 0x80; - byte = 0; + b = 0; } } if (mask != 0x80) { - r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN); + r = compress_out(a, &b, 1, ARCHIVE_Z_RUN); if (r < 0) return (r); } @@ -1492,6 +1492,7 @@ file_new(struct archive_write *a, struct archive_entry *entry, if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) { if (errno == ENOMEM) { + free(file); archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for UTF-16LE"); return (ARCHIVE_FATAL); @@ -1503,6 +1504,7 @@ file_new(struct archive_write *a, struct archive_entry *entry, } file->utf16name = malloc(u16len + 2); if (file->utf16name == NULL) { + free(file); archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Name"); return (ARCHIVE_FATAL); @@ -1676,10 +1678,10 @@ compression_init_encoder_deflate(struct archive *a, * a non-const pointer. */ strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in; strm->avail_in = lastrm->avail_in; - strm->total_in = lastrm->total_in; + strm->total_in = (uLong)lastrm->total_in; strm->next_out = lastrm->next_out; strm->avail_out = lastrm->avail_out; - strm->total_out = lastrm->total_out; + strm->total_out = (uLong)lastrm->total_out; if (deflateInit2(strm, level, Z_DEFLATED, (withheader)?15:-15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { @@ -1709,10 +1711,10 @@ compression_code_deflate(struct archive *a, * a non-const pointer. */ strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in; strm->avail_in = lastrm->avail_in; - strm->total_in = lastrm->total_in; + strm->total_in = (uLong)lastrm->total_in; strm->next_out = lastrm->next_out; strm->avail_out = lastrm->avail_out; - strm->total_out = lastrm->total_out; + strm->total_out = (uLong)lastrm->total_out; r = deflate(strm, (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH); lastrm->next_in = strm->next_in; @@ -1914,6 +1916,7 @@ compression_init_encoder_lzma(struct archive *a, if (level > 6) level = 6; if (lzma_lzma_preset(&lzma_opt, level)) { + free(strm); lastrm->real_stream = NULL; archive_set_error(a, ENOMEM, "Internal error initializing compression library"); diff --git a/contrib/libarchive/libarchive/archive_write_set_format_ar.c b/contrib/libarchive/libarchive/archive_write_set_format_ar.c index 550d691..d39d7d0 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_ar.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_ar.c @@ -366,7 +366,7 @@ archive_write_ar_data(struct archive_write *a, const void *buff, size_t s) ar = (struct ar_w *)a->format_data; if (s > ar->entry_bytes_remaining) - s = ar->entry_bytes_remaining; + s = (size_t)ar->entry_bytes_remaining; if (ar->is_strtab > 0) { if (ar->has_strtab > 0) { diff --git a/contrib/libarchive/libarchive/archive_write_set_format_cpio.c b/contrib/libarchive/libarchive/archive_write_set_format_cpio.c index 87f1d71..d69c6a6 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_cpio.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_cpio.c @@ -189,7 +189,7 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) /* Don't store a mapping if we don't need to. */ if (archive_entry_nlink(entry) < 2) { - return ++cpio->ino_next; + return (int)(++cpio->ino_next); } /* Look up old ino; if we have it, this is a hardlink @@ -200,7 +200,7 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) } /* Assign a new index number. */ - ino_new = ++cpio->ino_next; + ino_new = (int)(++cpio->ino_next); /* Ensure space for the new mapping. */ if (cpio->ino_list_size <= cpio->ino_list_next) { @@ -421,7 +421,7 @@ archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s) cpio = (struct cpio *)a->format_data; if (s > cpio->entry_bytes_remaining) - s = cpio->entry_bytes_remaining; + s = (size_t)cpio->entry_bytes_remaining; ret = __archive_write_output(a, buff, s); cpio->entry_bytes_remaining -= s; @@ -457,7 +457,7 @@ format_octal_recursive(int64_t v, char *p, int s) if (s == 0) return (v); v = format_octal_recursive(v, p+1, s-1); - *p = '0' + (v & 7); + *p = '0' + ((char)v & 7); return (v >> 3); } @@ -495,5 +495,6 @@ archive_write_cpio_finish_entry(struct archive_write *a) struct cpio *cpio; cpio = (struct cpio *)a->format_data; - return (__archive_write_nulls(a, cpio->entry_bytes_remaining)); + return (__archive_write_nulls(a, + (size_t)cpio->entry_bytes_remaining)); } diff --git a/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c b/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c index 55959c0..df0173e 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c @@ -350,7 +350,7 @@ write_header(struct archive_write *a, struct archive_entry *entry) } cpio->entry_bytes_remaining = archive_entry_size(entry); - cpio->padding = PAD4(cpio->entry_bytes_remaining); + cpio->padding = (int)PAD4(cpio->entry_bytes_remaining); /* Write the symlink now. */ if (p != NULL && *p != '\0') { @@ -380,7 +380,7 @@ archive_write_newc_data(struct archive_write *a, const void *buff, size_t s) cpio = (struct cpio *)a->format_data; if (s > cpio->entry_bytes_remaining) - s = cpio->entry_bytes_remaining; + s = (size_t)cpio->entry_bytes_remaining; ret = __archive_write_output(a, buff, s); cpio->entry_bytes_remaining -= s; @@ -453,5 +453,6 @@ archive_write_newc_finish_entry(struct archive_write *a) struct cpio *cpio; cpio = (struct cpio *)a->format_data; - return (__archive_write_nulls(a, cpio->entry_bytes_remaining + cpio->padding)); + return (__archive_write_nulls(a, + (size_t)cpio->entry_bytes_remaining + cpio->padding)); } diff --git a/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c index 5fac49c..13942c1 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c @@ -247,8 +247,8 @@ archive_write_gnutar_finish_entry(struct archive_write *a) int ret; gnutar = (struct gnutar *)a->format_data; - ret = __archive_write_nulls(a, - gnutar->entry_bytes_remaining + gnutar->entry_padding); + ret = __archive_write_nulls(a, (size_t) + (gnutar->entry_bytes_remaining + gnutar->entry_padding)); gnutar->entry_bytes_remaining = gnutar->entry_padding = 0; return (ret); } @@ -261,7 +261,7 @@ archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s) gnutar = (struct gnutar *)a->format_data; if (s > gnutar->entry_bytes_remaining) - s = gnutar->entry_bytes_remaining; + s = (size_t)gnutar->entry_bytes_remaining; ret = __archive_write_output(a, buff, s); gnutar->entry_bytes_remaining -= s; if (ret != ARCHIVE_OK) diff --git a/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c b/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c index 90c2157..483de90 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c @@ -1698,7 +1698,7 @@ wb_write_padding_to_temp(struct archive_write *a, int64_t csize) size_t ns; int ret; - ns = csize % LOGICAL_BLOCK_SIZE; + ns = (size_t)(csize % LOGICAL_BLOCK_SIZE); if (ns != 0) ret = write_null(a, LOGICAL_BLOCK_SIZE - ns); else @@ -1725,8 +1725,8 @@ write_iso9660_data(struct archive_write *a, const void *buff, size_t s) struct content *con; size_t ts; - ts = MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE - - iso9660->cur_file->cur_content->size; + ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE - + iso9660->cur_file->cur_content->size); if (iso9660->zisofs.detect_magic) zisofs_detect_magic(a, buff, ts); @@ -1746,9 +1746,9 @@ write_iso9660_data(struct archive_write *a, const void *buff, size_t s) return (ARCHIVE_FATAL); /* Compute the logical block number. */ - iso9660->cur_file->cur_content->blocks = - (iso9660->cur_file->cur_content->size - + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS; + iso9660->cur_file->cur_content->blocks = (int) + ((iso9660->cur_file->cur_content->size + + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS); /* * Make next extent. @@ -1796,7 +1796,7 @@ iso9660_write_data(struct archive_write *a, const void *buff, size_t s) if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG) return (0); if (s > iso9660->bytes_remaining) - s = iso9660->bytes_remaining; + s = (size_t)iso9660->bytes_remaining; if (s == 0) return (0); @@ -1838,9 +1838,9 @@ iso9660_finish_entry(struct archive_write *a) return (ARCHIVE_FATAL); /* Compute the logical block number. */ - iso9660->cur_file->cur_content->blocks = - (iso9660->cur_file->cur_content->size - + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS; + iso9660->cur_file->cur_content->blocks = (int) + ((iso9660->cur_file->cur_content->size + + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS); /* Add the current file to data file list. */ isofile_add_data_file(iso9660, iso9660->cur_file); @@ -2244,7 +2244,7 @@ set_str_utf16be(struct archive_write *a, unsigned char *p, const char *s, onepad = 0; if (vdc == VDC_UCS2) { struct iso9660 *iso9660 = a->format_data; - if (archive_strncpy_in_locale(&iso9660->utf16be, s, strlen(s), + if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s), iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for UTF-16BE"); @@ -2547,7 +2547,7 @@ set_date_time(unsigned char *p, time_t t) set_digit(p+10, 2, tm.tm_min); set_digit(p+12, 2, tm.tm_sec); set_digit(p+14, 2, 0); - set_num_712(p+16, get_gmoffset(&tm)/(60*15)); + set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15))); } static void @@ -2569,7 +2569,7 @@ set_time_915(unsigned char *p, time_t t) set_num_711(p+3, tm.tm_hour); set_num_711(p+4, tm.tm_min); set_num_711(p+5, tm.tm_sec); - set_num_712(p+6, get_gmoffset(&tm)/(60*15)); + set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15))); } @@ -2941,8 +2941,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len, bp = extra_next_record(&ctl, length); if (bp != NULL) { mode_t mode; - uid_t uid; - gid_t gid; + int64_t uid; + int64_t gid; mode = archive_entry_mode(file->entry); uid = archive_entry_uid(file->entry); @@ -2975,8 +2975,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len, /* file links (stat.st_nlink) */ set_num_733(bp+13, archive_entry_nlink(file->entry)); - set_num_733(bp+21, uid); - set_num_733(bp+29, gid); + set_num_733(bp+21, (uint32_t)uid); + set_num_733(bp+29, (uint32_t)gid); /* File Serial Number */ if (pxent->dir) set_num_733(bp+37, pxent->dir_location); @@ -3357,8 +3357,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len, bp[3] = length; bp[4] = 1; /* version */ dev = (uint64_t)archive_entry_rdev(file->entry); - set_num_733(bp + 5, dev >> 32); - set_num_733(bp + 13, dev & 0xFFFFFFFF); + set_num_733(bp + 5, (uint32_t)(dev >> 32)); + set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF)); bp += length; } extra_tell_used_size(&ctl, length); @@ -3492,7 +3492,7 @@ set_directory_record(unsigned char *p, size_t n, struct isoent *isoent, set_num_733(bp+11, xisoent->dir_block * LOGICAL_BLOCK_SIZE); else - set_num_733(bp+11, file->cur_content->size); + set_num_733(bp+11, (uint32_t)file->cur_content->size); /* Recording Date and Time */ /* NOTE: * If a file type is symbolic link, you are seeing this @@ -3669,7 +3669,7 @@ wb_set_offset(struct archive_write *a, int64_t off) iso9660->wbuff_tail = iso9660->wbuff_offset + used; if (iso9660->wbuff_offset < iso9660->wbuff_written) { if (used > 0 && - write_to_temp(a, iso9660->wbuff, used) != ARCHIVE_OK) + write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK) return (ARCHIVE_FATAL); iso9660->wbuff_offset = iso9660->wbuff_written; lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET); @@ -3688,12 +3688,12 @@ wb_set_offset(struct archive_write *a, int64_t off) iso9660->wbuff_offset = off; iso9660->wbuff_remaining = sizeof(iso9660->wbuff); } else if (off <= iso9660->wbuff_tail) { - iso9660->wbuff_remaining = - sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset); + iso9660->wbuff_remaining = (size_t) + (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset)); } else { ext_bytes = off - iso9660->wbuff_tail; - iso9660->wbuff_remaining = sizeof(iso9660->wbuff) - - (iso9660->wbuff_tail - iso9660->wbuff_offset); + iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff) + - (iso9660->wbuff_tail - iso9660->wbuff_offset)); while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) { if (write_null(a, (size_t)iso9660->wbuff_remaining) != ARCHIVE_OK) @@ -4814,13 +4814,19 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file) struct archive_wstring ws; if (wp != NULL) { + int r; archive_string_init(&ws); archive_wstrcpy(&ws, wp); cleanup_backslash_2(ws.s); archive_string_empty(&(file->parentdir)); - archive_string_append_from_wcs(&(file->parentdir), + r = archive_string_append_from_wcs(&(file->parentdir), ws.s, ws.length); archive_wstring_free(&ws); + if (r < 0 && errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + return (ARCHIVE_FATAL); + } } } #endif @@ -4923,14 +4929,20 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file) struct archive_wstring ws; if (wp != NULL) { + int r; archive_string_init(&ws); archive_wstrcpy(&ws, wp); cleanup_backslash_2(ws.s); archive_string_empty(&(file->symlink)); - archive_string_append_from_wcs( + r = archive_string_append_from_wcs( &(file->symlink), ws.s, ws.length); archive_wstring_free(&ws); + if (r < 0 && errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + return (ARCHIVE_FATAL); + } } } #endif @@ -5426,8 +5438,8 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location) iso9660->total_file_block = 0; if ((isoent = iso9660->el_torito.catalog) != NULL) { isoent->file->content.location = location; - block = (archive_entry_size(isoent->file->entry) + - LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS; + block = (int)((archive_entry_size(isoent->file->entry) + + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS); location += block; iso9660->total_file_block += block; } @@ -5435,7 +5447,7 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location) isoent->file->content.location = location; size = fd_boot_image_size(iso9660->el_torito.media_type); if (size == 0) - size = archive_entry_size(isoent->file->entry); + size = (size_t)archive_entry_size(isoent->file->entry); block = (size + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS; location += block; iso9660->total_file_block += block; @@ -6262,9 +6274,14 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent, * Get a length of MBS of a full-pathname. */ if ((int)np->file->basename_utf16.length > ffmax) { - archive_strncpy_in_locale(&iso9660->mbs, + if (archive_strncpy_l(&iso9660->mbs, (const char *)np->identifier, l, - iso9660->sconv_from_utf16be); + iso9660->sconv_from_utf16be) != 0 && + errno == ENOMEM) { + archive_set_error(&a->archive, errno, + "No memory"); + return (ARCHIVE_FATAL); + } np->mb_len = iso9660->mbs.length; if (np->mb_len != (int)np->file->basename.length) weight = np->mb_len; @@ -6364,7 +6381,7 @@ isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2) if (0x20 != *s2++) return (0x20 - *(const unsigned char *)(s2 - 1)); - } else if (p1->ext_len < p2->ext_len) { + } else if (p1->ext_len > p2->ext_len) { s1 += l; l = p1->ext_len - p2->ext_len; while (l--) @@ -6452,7 +6469,7 @@ isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2) while (l--) if (0 != *s2++) return (- *(const unsigned char *)(s2 - 1)); - } else if (p1->ext_len < p2->ext_len) { + } else if (p1->ext_len > p2->ext_len) { s1 += l; l = p1->ext_len - p2->ext_len; while (l--) @@ -6622,7 +6639,7 @@ isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth) */ static int isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved, - struct isoent *isoent, struct isoent **newent) + struct isoent *curent, struct isoent **newent) { struct iso9660 *iso9660 = a->format_data; struct isoent *rrmoved, *mvent, *np; @@ -6648,40 +6665,40 @@ isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved, *rr_moved = rrmoved; } /* - * Make a clone of isoent which is going to be relocated + * Make a clone of curent which is going to be relocated * to rr_moved. */ - mvent = isoent_clone(isoent); + mvent = isoent_clone(curent); if (mvent == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory"); return (ARCHIVE_FATAL); } /* linking.. and use for creating "CL", "PL" and "RE" */ - mvent->rr_parent = isoent->parent; - isoent->rr_child = mvent; + mvent->rr_parent = curent->parent; + curent->rr_child = mvent; /* - * Move subdirectories from the isoent to mvent + * Move subdirectories from the curent to mvent */ - if (isoent->children.first != NULL) { - *mvent->children.last = isoent->children.first; - mvent->children.last = isoent->children.last; + if (curent->children.first != NULL) { + *mvent->children.last = curent->children.first; + mvent->children.last = curent->children.last; } for (np = mvent->children.first; np != NULL; np = np->chnext) np->parent = mvent; - mvent->children.cnt = isoent->children.cnt; - isoent->children.cnt = 0; - isoent->children.first = NULL; - isoent->children.last = &isoent->children.first; + mvent->children.cnt = curent->children.cnt; + curent->children.cnt = 0; + curent->children.first = NULL; + curent->children.last = &curent->children.first; - if (isoent->subdirs.first != NULL) { - *mvent->subdirs.last = isoent->subdirs.first; - mvent->subdirs.last = isoent->subdirs.last; + if (curent->subdirs.first != NULL) { + *mvent->subdirs.last = curent->subdirs.first; + mvent->subdirs.last = curent->subdirs.last; } - mvent->subdirs.cnt = isoent->subdirs.cnt; - isoent->subdirs.cnt = 0; - isoent->subdirs.first = NULL; - isoent->subdirs.last = &isoent->subdirs.first; + mvent->subdirs.cnt = curent->subdirs.cnt; + curent->subdirs.cnt = 0; + curent->subdirs.first = NULL; + curent->subdirs.last = &curent->subdirs.first; /* * The mvent becomes a child of the rr_moved entry. @@ -6694,7 +6711,7 @@ isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved, * has to set the flag as a file. * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry. */ - isoent->dir = 0; + curent->dir = 0; *newent = mvent; @@ -7408,7 +7425,8 @@ zisofs_init(struct archive_write *a, struct isofile *file) /* Mark file->zisofs to create RRIP 'ZF' Use Entry. */ file->zisofs.header_size = ZF_HEADER_SIZE >> 2; file->zisofs.log2_bs = ZF_LOG2_BS; - file->zisofs.uncompressed_size = archive_entry_size(file->entry); + file->zisofs.uncompressed_size = + (uint32_t)archive_entry_size(file->entry); /* Calculate a size of Block Pointers of zisofs. */ ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1) @@ -7436,13 +7454,14 @@ zisofs_init(struct archive_write *a, struct isofile *file) * file. */ tsize = ZF_HEADER_SIZE + bpsize; - if (write_null(a, tsize) != ARCHIVE_OK) + if (write_null(a, (size_t)tsize) != ARCHIVE_OK) return (ARCHIVE_FATAL); /* * Initialize some variables to make zisofs. */ - archive_le32enc(&(iso9660->zisofs.block_pointers[0]), tsize); + archive_le32enc(&(iso9660->zisofs.block_pointers[0]), + (uint32_t)tsize); iso9660->zisofs.remaining = file->zisofs.uncompressed_size; iso9660->zisofs.making = 1; iso9660->zisofs.allzero = 1; @@ -7471,7 +7490,7 @@ zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s) entry_size = archive_entry_size(file->entry); if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size) - magic_max = entry_size; + magic_max = (int)entry_size; else magic_max = sizeof(iso9660->zisofs.magic_buffer); @@ -7647,7 +7666,7 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s) iso9660->zisofs.block_pointers_idx ++; archive_le32enc(&(iso9660->zisofs.block_pointers[ iso9660->zisofs.block_pointers_idx]), - iso9660->zisofs.total_size); + (uint32_t)iso9660->zisofs.total_size); r = zisofs_init_zstream(a); if (r != ARCHIVE_OK) return (ARCHIVE_FATAL); @@ -7776,9 +7795,9 @@ zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs, size_t ceil, xsize; /* Allocate block pointers buffer. */ - ceil = (zisofs->pz_uncompressed_size + - (1LL << zisofs->pz_log2_bs) - 1) - >> zisofs->pz_log2_bs; + ceil = (size_t)((zisofs->pz_uncompressed_size + + (((int64_t)1) << zisofs->pz_log2_bs) - 1) + >> zisofs->pz_log2_bs); xsize = (ceil + 1) * 4; if (zisofs->block_pointers == NULL) { size_t alloc = ((xsize >> 10) + 1) << 10; @@ -7999,7 +8018,7 @@ zisofs_rewind_boot_file(struct archive_write *a) fd = iso9660->temp_fd; new_offset = wb_offset(a); read_offset = file->content.offset_of_temp; - remaining = file->content.size; + remaining = (size_t)file->content.size; if (remaining > 1024 * 32) rbuff_size = 1024 * 32; else diff --git a/contrib/libarchive/libarchive/archive_write_set_format_mtree.c b/contrib/libarchive/libarchive/archive_write_set_format_mtree.c index 0a0bfb1..9fcff9f 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_mtree.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_mtree.c @@ -389,13 +389,13 @@ dir_len(struct mtree_entry *me) else if (*p == '/') al = p - path; } - if (l == -1) + if (l == (size_t)-1) goto alen; size = p - path; rp = p = path; while (*p != '\0') { l = mbtowc(&wc, p, size); - if (l == -1) + if (l == (size_t)-1) goto alen; if (l == 1 && (wc == L'/' || wc == L'\\')) rp = p; @@ -404,7 +404,7 @@ dir_len(struct mtree_entry *me) } return (rp - path + 1); alen: - if (al == -1) + if (al == (size_t)-1) return (0); return (al + 1); } @@ -1079,7 +1079,7 @@ archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n) struct mtree_writer *mtree= a->format_data; if (n > mtree->entry_bytes_remaining) - n = mtree->entry_bytes_remaining; + n = (size_t)mtree->entry_bytes_remaining; mtree->entry_bytes_remaining -= n; /* We don't need to compute a regular file sum */ diff --git a/contrib/libarchive/libarchive/archive_write_set_format_pax.c b/contrib/libarchive/libarchive/archive_write_set_format_pax.c index 15e92e9..459af72 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_pax.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_pax.c @@ -334,8 +334,7 @@ archive_write_pax_header_xattrs(struct archive_write *a, url_encoded_name = url_encode(name); if (url_encoded_name != NULL) { /* Convert narrow-character to UTF-8. */ - r = archive_strcpy_in_locale( - &(pax->l_url_encoded_name), + r = archive_strcpy_l(&(pax->l_url_encoded_name), url_encoded_name, pax->sconv_utf8); free(url_encoded_name); /* Done with this. */ if (r == 0) @@ -1324,7 +1323,7 @@ archive_write_pax_header(struct archive_write *a, return (ARCHIVE_FATAL); } /* Pad out the end of the entry. */ - r = __archive_write_nulls(a, pax->entry_padding); + r = __archive_write_nulls(a, (size_t)pax->entry_padding); if (r != ARCHIVE_OK) { /* If a write fails, we're pretty much toast. */ return (ARCHIVE_FATAL); @@ -1666,7 +1665,7 @@ archive_write_pax_finish_entry(struct archive_write *a) pax->sparse_list = sb; } } - ret = __archive_write_nulls(a, remaining + pax->entry_padding); + ret = __archive_write_nulls(a, (size_t)(remaining + pax->entry_padding)); pax->entry_bytes_remaining = pax->entry_padding = 0; return (ret); } @@ -1713,7 +1712,7 @@ archive_write_pax_data(struct archive_write *a, const void *buff, size_t s) p = ((const unsigned char *)buff) + total; ws = s - total; if (ws > pax->sparse_list->remaining) - ws = pax->sparse_list->remaining; + ws = (size_t)pax->sparse_list->remaining; if (pax->sparse_list->is_hole) { /* Current block is hole thus we do not write diff --git a/contrib/libarchive/libarchive/archive_write_set_format_ustar.c b/contrib/libarchive/libarchive/archive_write_set_format_ustar.c index 1b86740..7f868f1 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_ustar.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_ustar.c @@ -742,7 +742,7 @@ archive_write_ustar_finish_entry(struct archive_write *a) ustar = (struct ustar *)a->format_data; ret = __archive_write_nulls(a, - ustar->entry_bytes_remaining + ustar->entry_padding); + (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding)); ustar->entry_bytes_remaining = ustar->entry_padding = 0; return (ret); } @@ -755,7 +755,7 @@ archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s) ustar = (struct ustar *)a->format_data; if (s > ustar->entry_bytes_remaining) - s = ustar->entry_bytes_remaining; + s = (size_t)ustar->entry_bytes_remaining; ret = __archive_write_output(a, buff, s); ustar->entry_bytes_remaining -= s; if (ret != ARCHIVE_OK) diff --git a/contrib/libarchive/libarchive/archive_write_set_format_xar.c b/contrib/libarchive/libarchive/archive_write_set_format_xar.c index 988a971..3a48e05 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_xar.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_xar.c @@ -46,10 +46,6 @@ __FBSDID("$FreeBSD$"); #include <zlib.h> #endif -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - #include "archive.h" #include "archive_crypto_private.h" #include "archive_endian.h" @@ -660,7 +656,7 @@ xar_write_data(struct archive_write *a, const void *buff, size_t s) xar = (struct xar *)a->format_data; if (s > xar->bytes_remaining) - s = xar->bytes_remaining; + s = (size_t)xar->bytes_remaining; if (s == 0 || xar->cur_file == NULL) return (0); if (xar->cur_file->data.compression == NONE) { @@ -741,7 +737,7 @@ xar_finish_entry(struct archive_write *a) return (ARCHIVE_OK); while (xar->bytes_remaining > 0) { - s = xar->bytes_remaining; + s = (size_t)xar->bytes_remaining; if (s > a->null_length) s = a->null_length; w = xar_write_data(a, a->nulls, s); @@ -2600,10 +2596,10 @@ compression_init_encoder_gzip(struct archive *a, * a non-const pointer. */ strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in; strm->avail_in = lastrm->avail_in; - strm->total_in = lastrm->total_in; + strm->total_in = (uLong)lastrm->total_in; strm->next_out = lastrm->next_out; strm->avail_out = lastrm->avail_out; - strm->total_out = lastrm->total_out; + strm->total_out = (uLong)lastrm->total_out; if (deflateInit2(strm, level, Z_DEFLATED, (withheader)?15:-15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { @@ -2633,10 +2629,10 @@ compression_code_gzip(struct archive *a, * a non-const pointer. */ strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in; strm->avail_in = lastrm->avail_in; - strm->total_in = lastrm->total_in; + strm->total_in = (uLong)lastrm->total_in; strm->next_out = lastrm->next_out; strm->avail_out = lastrm->avail_out; - strm->total_out = lastrm->total_out; + strm->total_out = (uLong)lastrm->total_out; r = deflate(strm, (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH); lastrm->next_in = strm->next_in; @@ -2872,6 +2868,7 @@ compression_init_encoder_xz(struct archive *a, if (level > 6) level = 6; if (lzma_lzma_preset(&lzma_opt, level)) { + free(strm); lastrm->real_stream = NULL; archive_set_error(a, ENOMEM, "Internal error initializing compression library"); diff --git a/contrib/libarchive/libarchive/archive_write_set_format_zip.c b/contrib/libarchive/libarchive/archive_write_set_format_zip.c index 57835fc..b0b6c44 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_zip.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_zip.c @@ -109,69 +109,75 @@ static unsigned int dos_time(const time_t); static size_t path_length(struct archive_entry *); static int write_path(struct archive_entry *, struct archive_write *); -struct zip_local_file_header { - char signature[4]; - char version[2]; - char flags[2]; - char compression[2]; - char timedate[4]; - char crc32[4]; - char compressed_size[4]; - char uncompressed_size[4]; - char filename_length[2]; - char extra_length[2]; -}; - -struct zip_file_header { - char signature[4]; - char version_by[2]; - char version_extract[2]; - char flags[2]; - char compression[2]; - char timedate[4]; - char crc32[4]; - char compressed_size[4]; - char uncompressed_size[4]; - char filename_length[2]; - char extra_length[2]; - char comment_length[2]; - char disk_number[2]; - char attributes_internal[2]; - char attributes_external[4]; - char offset[4]; -}; - -struct zip_data_descriptor { - char signature[4]; /* Not mandatory, but recommended by specification. */ - char crc32[4]; - char compressed_size[4]; - char uncompressed_size[4]; -}; - -struct zip_extra_data_local { - char time_id[2]; - char time_size[2]; - char time_flag[1]; - char mtime[4]; - char atime[4]; - char ctime[4]; - char unix_id[2]; - char unix_size[2]; - char unix_version; - char unix_uid_size; - char unix_uid[4]; - char unix_gid_size; - char unix_gid[4]; -}; - -struct zip_extra_data_central { - char time_id[2]; - char time_size[2]; - char time_flag[1]; - char mtime[4]; - char unix_id[2]; - char unix_size[2]; -}; +#define LOCAL_FILE_HEADER_SIGNATURE 0 +#define LOCAL_FILE_HEADER_VERSION 4 +#define LOCAL_FILE_HEADER_FLAGS 6 +#define LOCAL_FILE_HEADER_COMPRESSION 8 +#define LOCAL_FILE_HEADER_TIMEDATE 10 +#define LOCAL_FILE_HEADER_CRC32 14 +#define LOCAL_FILE_HEADER_COMPRESSED_SIZE 18 +#define LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE 22 +#define LOCAL_FILE_HEADER_FILENAME_LENGTH 26 +#define LOCAL_FILE_HEADER_EXTRA_LENGTH 28 +#define SIZE_LOCAL_FILE_HEADER 30 + +#define FILE_HEADER_SIGNATURE 0 +#define FILE_HEADER_VERSION_BY 4 +#define FILE_HEADER_VERSION_EXTRACT 6 +#define FILE_HEADER_FLAGS 8 +#define FILE_HEADER_COMPRESSION 10 +#define FILE_HEADER_TIMEDATE 12 +#define FILE_HEADER_CRC32 16 +#define FILE_HEADER_COMPRESSED_SIZE 20 +#define FILE_HEADER_UNCOMPRESSED_SIZE 24 +#define FILE_HEADER_FILENAME_LENGTH 28 +#define FILE_HEADER_EXTRA_LENGTH 30 +#define FILE_HEADER_COMMENT_LENGTH 32 +#define FILE_HEADER_DISK_NUMBER 34 +#define FILE_HEADER_ATTRIBUTES_INTERNAL 36 +#define FILE_HEADER_ATTRIBUTES_EXTERNAL 38 +#define FILE_HEADER_OFFSET 42 +#define SIZE_FILE_HEADER 46 + + /* Not mandatory, but recommended by specification. */ +#define DATA_DESCRIPTOR_SIGNATURE 0 +#define DATA_DESCRIPTOR_CRC32 4 +#define DATA_DESCRIPTOR_COMPRESSED_SIZE 8 +#define DATA_DESCRIPTOR_UNCOMPRESSED_SIZE 12 +#define SIZE_DATA_DESCRIPTOR 16 + +#define EXTRA_DATA_LOCAL_TIME_ID 0 +#define EXTRA_DATA_LOCAL_TIME_SIZE 2 +#define EXTRA_DATA_LOCAL_TIME_FLAG 4 +#define EXTRA_DATA_LOCAL_MTIME 5 +#define EXTRA_DATA_LOCAL_ATIME 9 +#define EXTRA_DATA_LOCAL_CTIME 13 +#define EXTRA_DATA_LOCAL_UNIX_ID 17 +#define EXTRA_DATA_LOCAL_UNIX_SIZE 19 +#define EXTRA_DATA_LOCAL_UNIX_VERSION 21 +#define EXTRA_DATA_LOCAL_UNIX_UID_SIZE 22 +#define EXTRA_DATA_LOCAL_UNIX_UID 23 +#define EXTRA_DATA_LOCAL_UNIX_GID_SIZE 27 +#define EXTRA_DATA_LOCAL_UNIX_GID 28 +#define SIZE_EXTRA_DATA_LOCAL 32 + +#define EXTRA_DATA_CENTRAL_TIME_ID 0 +#define EXTRA_DATA_CENTRAL_TIME_SIZE 2 +#define EXTRA_DATA_CENTRAL_TIME_FLAG 4 +#define EXTRA_DATA_CENTRAL_MTIME 5 +#define EXTRA_DATA_CENTRAL_UNIX_ID 9 +#define EXTRA_DATA_CENTRAL_UNIX_SIZE 11 +#define SIZE_EXTRA_DATA_CENTRAL 13 + +#define CENTRAL_DIRECTORY_END_SIGNATURE 0 +#define CENTRAL_DIRECTORY_END_DISK 4 +#define CENTRAL_DIRECTORY_END_START_DISK 6 +#define CENTRAL_DIRECTORY_END_ENTRIES_DISK 8 +#define CENTRAL_DIRECTORY_END_ENTRIES 10 +#define CENTRAL_DIRECTORY_END_SIZE 12 +#define CENTRAL_DIRECTORY_END_OFFSET 16 +#define CENTRAL_DIRECTORY_END_COMMENT_LENGTH 20 +#define SIZE_CENTRAL_DIRECTORY_END 22 struct zip_file_header_link { struct zip_file_header_link *next; @@ -184,7 +190,7 @@ struct zip_file_header_link { }; struct zip { - struct zip_data_descriptor data_descriptor; + uint8_t data_descriptor[SIZE_DATA_DESCRIPTOR]; struct zip_file_header_link *central_directory; struct zip_file_header_link *central_directory_end; int64_t offset; @@ -203,17 +209,6 @@ struct zip { #endif }; -struct zip_central_directory_end { - char signature[4]; - char disk[2]; - char start_disk[2]; - char entries_disk[2]; - char entries[2]; - char size[4]; - char offset[4]; - char comment_length[2]; -}; - static int archive_write_zip_options(struct archive_write *a, const char *key, const char *val) @@ -291,6 +286,7 @@ archive_write_set_format_zip(struct archive *_a) zip->len_buf = 65536; zip->buf = malloc(zip->len_buf); if (zip->buf == NULL) { + free(zip); archive_set_error(&a->archive, ENOMEM, "Can't allocate compression buffer"); return (ARCHIVE_FATAL); @@ -310,7 +306,7 @@ archive_write_set_format_zip(struct archive *_a) a->archive.archive_format = ARCHIVE_FORMAT_ZIP; a->archive.archive_format_name = "ZIP"; - archive_le32enc(&zip->data_descriptor.signature, + archive_le32enc(&zip->data_descriptor[DATA_DESCRIPTOR_SIGNATURE], ZIP_SIGNATURE_DATA_DESCRIPTOR); return (ARCHIVE_OK); @@ -332,9 +328,9 @@ static int archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) { struct zip *zip; - struct zip_local_file_header h; - struct zip_extra_data_local e; - struct zip_data_descriptor *d; + uint8_t h[SIZE_LOCAL_FILE_HEADER]; + uint8_t e[SIZE_EXTRA_DATA_LOCAL]; + uint8_t *d; struct zip_file_header_link *l; struct archive_string_conv *sconv; int ret, ret2 = ARCHIVE_OK; @@ -374,7 +370,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) #endif } } - d = &zip->data_descriptor; + d = zip->data_descriptor; size = archive_entry_size(entry); zip->remaining_data_bytes = size; @@ -411,21 +407,47 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) { if (errno == ENOMEM) { + archive_entry_free(l->entry); + free(l); archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathname"); return (ARCHIVE_FATAL); } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate pathname '%s' to %s", + "Can't translate Pathname '%s' to %s", archive_entry_pathname(entry), archive_string_conversion_charset_name(sconv)); ret2 = ARCHIVE_WARN; } if (len > 0) archive_entry_set_pathname(l->entry, p); + + /* + * Although there is no character-set regulation for Symlink, + * it is suitable to convert a character-set of Symlinke to + * what those of the Pathname has been converted to. + */ + if (type == AE_IFLNK) { + if (archive_entry_symlink_l(entry, &p, &len, sconv)) { + if (errno == ENOMEM) { + archive_entry_free(l->entry); + free(l); + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory " + " for Symlink"); + return (ARCHIVE_FATAL); + } + /* + * Even if the strng conversion failed, + * we should not report the error since + * thre is no regulation for. + */ + } else if (len > 0) + archive_entry_set_symlink(l->entry, p); + } } - /* If all character of a filename is ASCII, Reset UTF-8 Name flag. */ + /* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */ if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 && is_all_ascii(archive_entry_pathname(l->entry))) l->flags &= ~ZIP_FLAGS_UTF8_NAME; @@ -458,13 +480,16 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) * directory. */ l->offset = zip->written_bytes; - memset(&h, 0, sizeof(h)); - archive_le32enc(&h.signature, ZIP_SIGNATURE_LOCAL_FILE_HEADER); - archive_le16enc(&h.version, ZIP_VERSION_EXTRACT); - archive_le16enc(&h.flags, l->flags); - archive_le16enc(&h.compression, l->compression); - archive_le32enc(&h.timedate, dos_time(archive_entry_mtime(entry))); - archive_le16enc(&h.filename_length, (uint16_t)path_length(l->entry)); + memset(h, 0, sizeof(h)); + archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE], + ZIP_SIGNATURE_LOCAL_FILE_HEADER); + archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT); + archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags); + archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression); + archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE], + dos_time(archive_entry_mtime(entry))); + archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH], + (uint16_t)path_length(l->entry)); switch (l->compression) { case COMPRESSION_STORE: @@ -472,12 +497,15 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) * specification says to set to zero when using data * descriptors. Otherwise the end of the data for an * entry is rather difficult to find. */ - archive_le32enc(&h.compressed_size, size); - archive_le32enc(&h.uncompressed_size, size); + archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE], + (uint32_t)size); + archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE], + (uint32_t)size); break; #ifdef HAVE_ZLIB_H case COMPRESSION_DEFLATE: - archive_le32enc(&h.uncompressed_size, size); + archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE], + (uint32_t)size); zip->stream.zalloc = Z_NULL; zip->stream.zfree = Z_NULL; @@ -495,28 +523,33 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) } /* Formatting extra data. */ - archive_le16enc(&h.extra_length, sizeof(e)); - archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP); - archive_le16enc(&e.time_size, sizeof(e.time_flag) + - sizeof(e.mtime) + sizeof(e.atime) + sizeof(e.ctime)); - e.time_flag[0] = 0x07; - archive_le32enc(&e.mtime, archive_entry_mtime(entry)); - archive_le32enc(&e.atime, archive_entry_atime(entry)); - archive_le32enc(&e.ctime, archive_entry_ctime(entry)); - - archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX); - archive_le16enc(&e.unix_size, sizeof(e.unix_version) + - sizeof(e.unix_uid_size) + sizeof(e.unix_uid) + - sizeof(e.unix_gid_size) + sizeof(e.unix_gid)); - e.unix_version = 1; - e.unix_uid_size = 4; - archive_le32enc(&e.unix_uid, archive_entry_uid(entry)); - e.unix_gid_size = 4; - archive_le32enc(&e.unix_gid, archive_entry_gid(entry)); - - archive_le32enc(&d->uncompressed_size, size); - - ret = __archive_write_output(a, &h, sizeof(h)); + archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e)); + archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID], + ZIP_SIGNATURE_EXTRA_TIMESTAMP); + archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3); + e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07; + archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME], + (uint32_t)archive_entry_mtime(entry)); + archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME], + (uint32_t)archive_entry_atime(entry)); + archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME], + (uint32_t)archive_entry_ctime(entry)); + + archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID], + ZIP_SIGNATURE_EXTRA_NEW_UNIX); + archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2); + e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1; + e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4; + archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID], + (uint32_t)archive_entry_uid(entry)); + e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4; + archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID], + (uint32_t)archive_entry_gid(entry)); + + archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE], + (uint32_t)size); + + ret = __archive_write_output(a, h, sizeof(h)); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += sizeof(h); @@ -526,7 +559,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) return (ARCHIVE_FATAL); zip->written_bytes += ret; - ret = __archive_write_output(a, &e, sizeof(e)); + ret = __archive_write_output(a, e, sizeof(e)); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += sizeof(e); @@ -535,11 +568,11 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) const unsigned char *p; p = (const unsigned char *)archive_entry_symlink(l->entry); - ret = __archive_write_output(a, p, size); + ret = __archive_write_output(a, p, (size_t)size); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += size; - l->crc32 = crc32(l->crc32, p, size); + l->crc32 = crc32(l->crc32, p, (unsigned)size); } if (ret2 != ARCHIVE_OK) @@ -606,7 +639,7 @@ archive_write_zip_finish_entry(struct archive_write *a) /* Write the data descripter after file data has been written. */ int ret; struct zip *zip = a->format_data; - struct zip_data_descriptor *d = &zip->data_descriptor; + uint8_t *d = zip->data_descriptor; struct zip_file_header_link *l = zip->central_directory_end; #if HAVE_ZLIB_H size_t reminder; @@ -637,12 +670,13 @@ archive_write_zip_finish_entry(struct archive_write *a) #endif } - archive_le32enc(&d->crc32, l->crc32); - archive_le32enc(&d->compressed_size, l->compressed_size); - ret = __archive_write_output(a, d, sizeof(*d)); + archive_le32enc(&d[DATA_DESCRIPTOR_CRC32], l->crc32); + archive_le32enc(&d[DATA_DESCRIPTOR_COMPRESSED_SIZE], + (uint32_t)l->compressed_size); + ret = __archive_write_output(a, d, SIZE_DATA_DESCRIPTOR); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); - zip->written_bytes += sizeof(*d); + zip->written_bytes += SIZE_DATA_DESCRIPTOR; return (ARCHIVE_OK); } @@ -651,9 +685,9 @@ archive_write_zip_close(struct archive_write *a) { struct zip *zip; struct zip_file_header_link *l; - struct zip_file_header h; - struct zip_central_directory_end end; - struct zip_extra_data_central e; + uint8_t h[SIZE_FILE_HEADER]; + uint8_t end[SIZE_CENTRAL_DIRECTORY_END]; + uint8_t e[SIZE_EXTRA_DATA_CENTRAL]; int64_t offset_start, offset_end; int entries; int ret; @@ -670,10 +704,10 @@ archive_write_zip_close(struct archive_write *a) * - disk_number * - attributes_internal */ - memset(&h, 0, sizeof(h)); - archive_le32enc(&h.signature, ZIP_SIGNATURE_FILE_HEADER); - archive_le16enc(&h.version_by, ZIP_VERSION_BY); - archive_le16enc(&h.version_extract, ZIP_VERSION_EXTRACT); + memset(h, 0, sizeof(h)); + archive_le32enc(&h[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER); + archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY); + archive_le16enc(&h[FILE_HEADER_VERSION_EXTRACT], ZIP_VERSION_EXTRACT); entries = 0; offset_start = zip->written_bytes; @@ -681,31 +715,34 @@ archive_write_zip_close(struct archive_write *a) /* Formatting individual header fields per entry and * writing each entry. */ while (l != NULL) { - archive_le16enc(&h.flags, l->flags); - archive_le16enc(&h.compression, l->compression); - archive_le32enc(&h.timedate, + archive_le16enc(&h[FILE_HEADER_FLAGS], l->flags); + archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression); + archive_le32enc(&h[FILE_HEADER_TIMEDATE], dos_time(archive_entry_mtime(l->entry))); - archive_le32enc(&h.crc32, l->crc32); - archive_le32enc(&h.compressed_size, l->compressed_size); - archive_le32enc(&h.uncompressed_size, - archive_entry_size(l->entry)); - archive_le16enc(&h.filename_length, + archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32); + archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE], + (uint32_t)l->compressed_size); + archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE], + (uint32_t)archive_entry_size(l->entry)); + archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH], (uint16_t)path_length(l->entry)); - archive_le16enc(&h.extra_length, sizeof(e)); - archive_le16enc(&h.attributes_external[2], + archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e)); + archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2], archive_entry_mode(l->entry)); - archive_le32enc(&h.offset, l->offset); + archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset); /* Formatting extra data. */ - archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP); - archive_le16enc(&e.time_size, - sizeof(e.mtime) + sizeof(e.time_flag)); - e.time_flag[0] = 0x07; - archive_le32enc(&e.mtime, archive_entry_mtime(l->entry)); - archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX); - archive_le16enc(&e.unix_size, 0x0000); - - ret = __archive_write_output(a, &h, sizeof(h)); + archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID], + ZIP_SIGNATURE_EXTRA_TIMESTAMP); + archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4); + e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07; + archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME], + (uint32_t)archive_entry_mtime(l->entry)); + archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID], + ZIP_SIGNATURE_EXTRA_NEW_UNIX); + archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000); + + ret = __archive_write_output(a, h, sizeof(h)); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += sizeof(h); @@ -715,7 +752,7 @@ archive_write_zip_close(struct archive_write *a) return (ARCHIVE_FATAL); zip->written_bytes += ret; - ret = __archive_write_output(a, &e, sizeof(e)); + ret = __archive_write_output(a, e, sizeof(e)); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += sizeof(e); @@ -726,15 +763,18 @@ archive_write_zip_close(struct archive_write *a) offset_end = zip->written_bytes; /* Formatting end of central directory. */ - memset(&end, 0, sizeof(end)); - archive_le32enc(&end.signature, ZIP_SIGNATURE_CENTRAL_DIRECTORY_END); - archive_le16enc(&end.entries_disk, entries); - archive_le16enc(&end.entries, entries); - archive_le32enc(&end.size, offset_end - offset_start); - archive_le32enc(&end.offset, offset_start); + memset(end, 0, sizeof(end)); + archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE], + ZIP_SIGNATURE_CENTRAL_DIRECTORY_END); + archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries); + archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries); + archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE], + (uint32_t)(offset_end - offset_start)); + archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET], + (uint32_t)offset_start); /* Writing end of central directory. */ - ret = __archive_write_output(a, &end, sizeof(end)); + ret = __archive_write_output(a, end, sizeof(end)); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += sizeof(end); diff --git a/contrib/libarchive/libarchive/archive_write_set_options.3 b/contrib/libarchive/libarchive/archive_write_set_options.3 index 9a8ea3d..9d60515 100644 --- a/contrib/libarchive/libarchive/archive_write_set_options.3 +++ b/contrib/libarchive/libarchive/archive_write_set_options.3 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $ +.\" $FreeBSD$ .\" -.Dd Feb 27, 2010 +.Dd February 2, 2012 .Dt ARCHIVE_WRITE_OPTIONS 3 .Os .Sh NAME @@ -33,8 +33,8 @@ .Nm archive_write_set_option , .Nm archive_write_set_options .Nd functions controlling options for reading archives -.Sh SYNOPSIS -.\" +.Sh LIBRARY +Streaming Archive Library (libarchive, -larchive) .Sh SYNOPSIS .Ft int .Fo archive_write_set_filter_option diff --git a/contrib/libarchive/libarchive/cpio.5 b/contrib/libarchive/libarchive/cpio.5 index 5bc60fe..1a2886f 100644 --- a/contrib/libarchive/libarchive/cpio.5 +++ b/contrib/libarchive/libarchive/cpio.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 5, 2007 +.Dd December 23, 2011 .Dt CPIO 5 .Os .Sh NAME diff --git a/contrib/libarchive/libarchive/libarchive-formats.5 b/contrib/libarchive/libarchive/libarchive-formats.5 index 9975e6a..0fdf470 100644 --- a/contrib/libarchive/libarchive/libarchive-formats.5 +++ b/contrib/libarchive/libarchive/libarchive-formats.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 27, 2009 +.Dd March 18, 2012 .Dt LIBARCHIVE-FORMATS 5 .Os .Sh NAME @@ -51,11 +51,11 @@ functions to enable all supported formats. The .Xr libarchive 3 library can read most tar archives. -However, it only writes POSIX-standard +It can write POSIX-standard .Dq ustar and .Dq pax interchange -formats. +formats and a subset of the legacy GNU tar format. .Pp All tar formats store each entry in one or more 512-byte records. The first record is used for file metadata, including filename, @@ -70,13 +70,18 @@ subsequent entries. .It Cm gnutar The .Xr libarchive 3 -library can read GNU-format tar archives. +library can read most GNU-format tar archives. It currently supports the most popular GNU extensions, including modern long filename and linkname support, as well as atime and ctime data. The libarchive library does not support multi-volume archives, nor the old GNU long filename format. It can read GNU sparse file entries, including the new POSIX-based -formats, but cannot write GNU sparse file entries. +formats. +.Pp +The +.Xr libarchive 3 +library can write GNU tar format, including long filename +and linkname support, as well as atime and ctime data. .It Cm pax The .Xr libarchive 3 @@ -98,6 +103,14 @@ archiver and a few LIBARCHIVE keys. The libarchive library can read most of the SCHILY keys and most of the GNU keys introduced by GNU tar. It silently ignores any keywords that it does not understand. +.Pp +The pax interchange format converts filenames to Unicode +and stores them using the UTF-8 encoding. +Prior to libarchive 3.0, libarchive erroneously assumed +that the system wide-character routines natively supported +Unicode. +This caused it to mis-handle non-ASCII filenames on systems +that did not satisfy this assumption. .It Cm restricted pax The libarchive library can also write pax archives in which it attempts to suppress the extended attributes entry whenever @@ -135,6 +148,8 @@ security information cannot be stored. Archive entries are limited to 8 gigabytes in size. .El Note that the pax interchange format has none of these restrictions. +The ustar format is old and widely supported. +It is recommended when compatibility is the primary concern. .El .Pp The libarchive library also reads a variety of commonly-used extensions to @@ -268,19 +283,68 @@ If both extensions are present, the Joliet extensions will be used and the Rockridge extensions will be ignored. In particular, this can create problems with hardlinks and symlinks, which are supported by Rockridge but not by Joliet. +.Pp +Libarchive reads ISO9660 images using a streaming strategy. +This allows it to read compressed images directly +(decompressing on the fly) and allows it to read images +directly from network sockets, pipes, and other non-seekable +data sources. +This strategy works well for optimized ISO9660 images created +by many popular programs. +Such programs collect all directory information at the beginning +of the ISO9660 image so it can be read from a physical disk +with a minimum of seeking. +However, not all ISO9660 images can be read in this fashion. +.Pp +Libarchive can also write ISO9660 images. +Such images are fully optimized with the directory information +preceding all file data. +This is done by storing all file data to a temporary file +while collecting directory information in memory. +When the image is finished, libarchive writes out the +directory structure followed by the file data. +The location used for the temporary file can be changed +by the usual environment variables. .Ss Zip format Libarchive can read and write zip format archives that have uncompressed entries and entries compressed with the .Dq deflate algorithm. -Older zip compression algorithms are not supported. -It can extract jar archives, archives that use Zip64 extensions and many +Other zip compression algorithms are not supported. +It can extract jar archives, archives that use Zip64 extensions and self-extracting zip archives. -Libarchive reads Zip archives as they are being streamed, -which allows it to read archives of arbitrary size. -It currently does not use the central directory; this -limits libarchive's ability to support some self-extracting -archives and ones that have been modified in certain ways. +Libarchive can use either of two different strategies for +reading Zip archives: +a streaming strategy which is fast and can handle extremely +large archives, and a seeking strategy which can correctly +process self-extracting Zip archives and archives with +deleted members or other in-place modifications. +.Pp +The streaming reader processes Zip archives as they are read. +It can read archives of arbitrary size from tape or +network sockets, and can decode Zip archives that have +been separately compressed or encoded. +However, self-extracting Zip archives and archives with +certain types of modifications cannot be correctly +handled. +Such archives require that the reader first process the +Central Directory, which is ordinarily located +at the end of a Zip archive and is thus inaccessible +to the streaming reader. +If the program using libarchive has enabled seek support, then +libarchive will use this to processes the central directory first. +.Pp +In particular, the seeking reader must be used to +correctly handle self-extracting archives. +Such archives consist of a program followed by a regular +Zip archive. +The streaming reader cannot parse the initial program +portion, but the seeking reader starts by reading the +Central Directory from the end of the archive. +Similarly, Zip archives that have been modified in-place +can have deleted entries or other garbage data that +can only be accurately detected by first reading the +Central Directory. .Ss Archive (library) file format The Unix archive format (commonly created by the .Xr ar 1 @@ -342,12 +406,18 @@ using libarchive. If it cannot locate and open the file on disk, libarchive will return an error for any attempt to read the entry body. +.Ss LHA +XXX Information about libarchive's LHA support XXX +.Ss CAB +XXX Information about libarchive's CAB support XXX +.Ss XAR +XXX Information about libarchive's XAR support XXX .Ss RAR -libarchive has limited support to read files in RAR format. Currently, -libarchive can read single RAR files in RARv3 format which have been either -created uncompressed, or compressed using any of the compression methods -supported by the RARv3 format. libarchive can also extract RAR files which have -been created as self-extracting RAR files. +Libarchive has limited support for reading RAR format archives. +Currently, libarchive can read RARv3 format archives +which have been either created uncompressed, or compressed using +any of the compression methods supported by the RARv3 format. +Libarchive can also read self-extracting RAR archives. .Sh SEE ALSO .Xr ar 1 , .Xr cpio 1 , diff --git a/contrib/libarchive/libarchive/libarchive.3 b/contrib/libarchive/libarchive/libarchive.3 index 6222d8e..3a9a841 100644 --- a/contrib/libarchive/libarchive/libarchive.3 +++ b/contrib/libarchive/libarchive/libarchive.3 @@ -24,14 +24,12 @@ .\" .\" $FreeBSD$ .\" -.Dd February 6, 2010 +.Dd March 18, 2012 .Dt LIBARCHIVE 3 .Os .Sh NAME .Nm libarchive .Nd functions for reading and writing streaming archives -.Sh LIBRARY -.Lb libarchive .Sh OVERVIEW The .Nm @@ -66,15 +64,33 @@ most common cpio archive formats, .It ISO9660 CD images (including RockRidge and Joliet extensions), .It -Zip archives. +Zip archives, +.It +ar archives (including GNU/SysV and BSD extensions), +.It +Microsoft CAB archives, +.It +LHA archives, +.It +mtree file tree descriptions, +.It +RAR archives, +.It +XAR archives. .El The library automatically detects archives compressed with .Xr gzip 1 , .Xr bzip2 1 , .Xr xz 1 , +.Xr lzip 1 , or .Xr compress 1 and decompresses them transparently. +It can similarly detect and decode archives processed with +.Xr uuencode 1 +or which have an +.Xr rpm 1 +header. .Pp When writing an archive, you can specify the compression to be used and the format to use. @@ -93,7 +109,17 @@ POSIX octet-oriented cpio archives, .It Zip archive, .It -two different variants of shar archives. +two different variants of shar archives, +.It +ISO9660 CD images, +.It +7-Zip archives, +.It +ar archives, +.It +mtree file tree descriptions, +.It +XAR archives. .El Pax interchange format is an extension of the tar archive format that eliminates essentially all of the limitations of historic tar formats @@ -145,9 +171,21 @@ operations. .Sh READING ENTRIES FROM DISK The .Xr archive_read_disk 3 -provides some support for populating +supports for populating .Xr archive_entry 3 objects from information in the filesystem. +This includes the information accessible from the +.Xr stat 2 +system call as well as ACLs, extended attributes, +and other metadata. +The +.Xr archive_read_disk 3 +API also supports iterating over directory trees, +which allows directories of files to be read using +an API compatible with +the +.Xr archive_read 3 +API. .Sh DESCRIPTION Detailed descriptions of each function are provided by the corresponding manual pages. @@ -227,7 +265,7 @@ library first appeared in .An -nosplit The .Nm libarchive -library was written by +library was originally written by .An Tim Kientzle Aq kientzle@acm.org . .Sh BUGS Some archive formats support information that is not supported by @@ -244,13 +282,8 @@ is supported by all formats. For example, cpio formats do not support nanosecond timestamps; old tar formats do not support large device numbers. .Pp -The -.Xr archive_read_disk 3 -API should support iterating over filesystems; -that would make it possible to share code among -disk-to-archive, archive-to-archive, archive-to-disk, -and disk-to-disk operations. -Currently, it only supports reading the -information for a single file. -(Which is still quite useful, as it hides a lot -of system-specific details.) +The ISO9660 reader cannot yet read all ISO9660 images; +it should learn how to seek. +.Pp +The AR writer requires the client program to use +two passes, unlike all other libarchive writers. diff --git a/contrib/libarchive/libarchive/libarchive_changes.3 b/contrib/libarchive/libarchive/libarchive_changes.3 index 6ee6af2..bacd6e1 100644 --- a/contrib/libarchive/libarchive/libarchive_changes.3 +++ b/contrib/libarchive/libarchive/libarchive_changes.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 27, 2011 +.Dd December 23, 2011 .Dt LIBARCHIVE_CHANGES 3 .Os .Sh NAME diff --git a/contrib/libarchive/libarchive/libarchive_internals.3 b/contrib/libarchive/libarchive/libarchive_internals.3 index 3700f24..4aa09f9 100644 --- a/contrib/libarchive/libarchive/libarchive_internals.3 +++ b/contrib/libarchive/libarchive/libarchive_internals.3 @@ -24,8 +24,8 @@ .\" .\" $FreeBSD$ .\" -.Dd April 16, 2007 -.Dt LIBARCHIVE 3 +.Dd January 26, 2011 +.Dt LIBARCHIVE_INTERNALS 3 .Os .Sh NAME .Nm libarchive_internals diff --git a/contrib/libarchive/libarchive/tar.5 b/contrib/libarchive/libarchive/tar.5 index fbae6e4..688bb92 100644 --- a/contrib/libarchive/libarchive/tar.5 +++ b/contrib/libarchive/libarchive/tar.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 27, 2009 +.Dd December 23, 2011 .Dt TAR 5 .Os .Sh NAME diff --git a/contrib/libarchive/libarchive/test/main.c b/contrib/libarchive/libarchive/test/main.c index 35e48a8..9d692d1 100644 --- a/contrib/libarchive/libarchive/test/main.c +++ b/contrib/libarchive/libarchive/test/main.c @@ -24,6 +24,9 @@ */ #include "test.h" +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -31,6 +34,16 @@ #ifdef HAVE_ICONV_H #include <iconv.h> #endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include <linux/ext2_fs.h> /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ +#endif #include <limits.h> #include <locale.h> #ifdef HAVE_SIGNAL_H @@ -114,7 +127,14 @@ __FBSDID("$FreeBSD$"); #endif #if defined(_WIN32) && !defined(__CYGWIN__) -void *GetFunctionKernel32(const char *name) +static void *GetFunctionKernel32(const char *); +static int my_CreateSymbolicLinkA(const char *, const char *, int); +static int my_CreateHardLinkA(const char *, const char *); +static int my_GetFileInformationByName(const char *, + BY_HANDLE_FILE_INFORMATION *); + +static void * +GetFunctionKernel32(const char *name) { static HINSTANCE lib; static int set; @@ -153,7 +173,7 @@ my_CreateHardLinkA(const char *linkname, const char *target) return f == NULL ? 0 : (*f)(linkname, target, NULL); } -int +static int my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) { HANDLE h; @@ -1505,7 +1525,7 @@ assertion_make_dir(const char *file, int line, const char *dirname, int mode) /* Create a file with the specified contents and report any failures. */ int assertion_make_file(const char *file, int line, - const char *path, int mode, const char *contents) + const char *path, int mode, int csize, const void *contents) { #if defined(_WIN32) && !defined(__CYGWIN__) /* TODO: Rework this to set file mode as well. */ @@ -1519,8 +1539,13 @@ assertion_make_file(const char *file, int line, return (0); } if (contents != NULL) { - if (strlen(contents) - != fwrite(contents, 1, strlen(contents), f)) { + size_t wsize; + + if (csize < 0) + wsize = strlen(contents); + else + wsize = (size_t)csize; + if (wsize != fwrite(contents, 1, wsize, f)) { fclose(f); failure_start(file, line, "Could not write file %s", path); @@ -1540,10 +1565,16 @@ assertion_make_file(const char *file, int line, return (0); } if (contents != NULL) { - if ((ssize_t)strlen(contents) - != write(fd, contents, strlen(contents))) { + ssize_t wsize; + + if (csize < 0) + wsize = (ssize_t)strlen(contents); + else + wsize = (ssize_t)csize; + if (wsize != write(fd, contents, wsize)) { close(fd); - failure_start(file, line, "Could not write to %s", path); + failure_start(file, line, + "Could not write to %s", path); failure_finish(NULL); return (0); } @@ -1714,6 +1745,52 @@ assertion_utimes(const char *file, int line, #endif /* defined(_WIN32) && !defined(__CYGWIN__) */ } +/* Set nodump, report failures. */ +int +assertion_nodump(const char *file, int line, const char *pathname) +{ +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + int r; + + assertion_count(file, line); + r = chflags(pathname, UF_NODUMP); + if (r < 0) { + failure_start(file, line, "Can't set nodump %s\n", pathname); + failure_finish(NULL); + return (0); + } +#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ + && defined(EXT2_NODUMP_FL) + int fd, r, flags; + + assertion_count(file, line); + fd = open(pathname, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + failure_start(file, line, "Can't open %s\n", pathname); + failure_finish(NULL); + return (0); + } + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) { + failure_start(file, line, "Can't get flags %s\n", pathname); + failure_finish(NULL); + return (0); + } + flags |= EXT2_NODUMP_FL; + r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + if (r < 0) { + failure_start(file, line, "Can't set nodump %s\n", pathname); + failure_finish(NULL); + return (0); + } + close(fd); +#else + (void)pathname; /* UNUSED */ + assertion_count(file, line); +#endif + return (1); +} + /* * * UTILITIES for use by tests. @@ -1742,7 +1819,7 @@ canSymlink(void) return (value); ++tested; - assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a"); + assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); /* Note: Cygwin has its own symlink() emulation that does not * use the Win32 CreateSymbolicLink() function. */ #if defined(_WIN32) && !defined(__CYGWIN__) @@ -1792,6 +1869,70 @@ canGunzip(void) } /* + * Can this filesystem handle nodump flags. + */ +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + +int +canNodump(void) +{ + const char *path = "cannodumptest"; + struct stat sb; + + assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); + if (chflags(path, UF_NODUMP) < 0) + return (0); + if (stat(path, &sb) < 0) + return (0); + if (sb.st_flags & UF_NODUMP) + return (1); + return (0); +} + +#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ + && defined(EXT2_NODUMP_FL) + +int +canNodump(void) +{ + const char *path = "cannodumptest"; + int fd, r, flags; + + assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return (0); + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) + return (0); + flags |= EXT2_NODUMP_FL; + r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + if (r < 0) + return (0); + close(fd); + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return (0); + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) + return (0); + close(fd); + if (flags & EXT2_NODUMP_FL) + return (1); + return (0); +} + +#else + +int +canNodump() +{ + return (0); +} + +#endif + +/* * Sleep as needed; useful for verifying disk timestamp changes by * ensuring that the wall-clock time has actually changed before we * go back to re-read something from disk. @@ -2234,17 +2375,77 @@ success: return strdup(buff); } +static int +get_test_set(int *test_set, int limit, const char *test) +{ + int start, end; + int idx = 0; + + if (test == NULL) { + /* Default: Run all tests. */ + for (;idx < limit; idx++) + test_set[idx] = idx; + return (limit); + } + if (*test >= '0' && *test <= '9') { + const char *vp = test; + start = 0; + while (*vp >= '0' && *vp <= '9') { + start *= 10; + start += *vp - '0'; + ++vp; + } + if (*vp == '\0') { + end = start; + } else if (*vp == '-') { + ++vp; + if (*vp == '\0') { + end = limit - 1; + } else { + end = 0; + while (*vp >= '0' && *vp <= '9') { + end *= 10; + end += *vp - '0'; + ++vp; + } + } + } else + return (-1); + if (start < 0 || end >= limit || start > end) + return (-1); + while (start <= end) + test_set[idx++] = start++; + } else { + size_t len = strlen(test); + for (start = 0; start < limit; ++start) { + const char *name = tests[start].name; + const char *p; + + while ((p = strchr(name, test[0])) != NULL) { + if (strncmp(p, test, len) == 0) { + test_set[idx++] = start; + break; + } else + name = p + 1; + } + + } + } + return ((idx == 0)?-1:idx); +} + int main(int argc, char **argv) { static const int limit = sizeof(tests) / sizeof(tests[0]); - int i = 0, j = 0, start, end, tests_run = 0, tests_failed = 0, option; + int test_set[sizeof(tests) / sizeof(tests[0])]; + int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; time_t now; char *refdir_alloc = NULL; const char *progname; char **saved_argv; const char *tmp, *option_arg, *p; - char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL; + char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; char tmpdir_timestamp[256]; (void)argc; /* UNUSED */ @@ -2330,6 +2531,19 @@ main(int argc, char **argv) if (getenv(ENVBASE "_DEBUG") != NULL) dump_on_failure = 1; + /* Allow -v to be controlled through the environment. */ + if (getenv("_VERBOSITY_LEVEL") != NULL) + { + vlevel = getenv("_VERBOSITY_LEVEL"); + verbosity = atoi(vlevel); + if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) + { + /* Unsupported verbosity levels are silently ignored */ + vlevel = NULL; + verbosity = VERBOSITY_PASSFAIL; + } + } + /* Get the directory holding test files from environment. */ refdir = getenv(ENVBASE "_TEST_FILES"); @@ -2377,7 +2591,8 @@ main(int argc, char **argv) #endif break; case 'q': - verbosity--; + if (!vlevel) + verbosity--; break; case 'r': refdir = option_arg; @@ -2386,7 +2601,8 @@ main(int argc, char **argv) until_failure++; break; case 'v': - verbosity++; + if (!vlevel) + verbosity++; break; default: fprintf(stderr, "Unrecognized option '%c'\n", @@ -2499,78 +2715,27 @@ main(int argc, char **argv) saved_argv = argv; do { argv = saved_argv; - if (*argv == NULL) { - /* Default: Run all tests. */ - for (i = 0; i < limit; i++) { + do { + int test_num; + + test_num = get_test_set(test_set, limit, *argv); + if (test_num < 0) { + printf("*** INVALID Test %s\n", *argv); + free(refdir_alloc); + usage(progname); + return (1); + } + for (i = 0; i < test_num; i++) { tests_run++; - if (test_run(i, tmpdir)) { + if (test_run(test_set[i], tmpdir)) { tests_failed++; if (until_failure) goto finish; } } - } else { - while (*(argv) != NULL) { - if (**argv >= '0' && **argv <= '9') { - char *vp = *argv; - start = 0; - while (*vp >= '0' && *vp <= '9') { - start *= 10; - start += *vp - '0'; - ++vp; - } - if (*vp == '\0') { - end = start; - } else if (*vp == '-') { - ++vp; - if (*vp == '\0') { - end = limit - 1; - } else { - end = 0; - while (*vp >= '0' && *vp <= '9') { - end *= 10; - end += *vp - '0'; - ++vp; - } - } - } else { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - usage(progname); - return (1); - } - if (start < 0 || end >= limit || start > end) { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - usage(progname); - return (1); - } - } else { - for (start = 0; start < limit; ++start) { - if (strcmp(*argv, tests[start].name) == 0) - break; - } - end = start; - if (start >= limit) { - printf("*** INVALID Test ``%s''\n", - *argv); - free(refdir_alloc); - usage(progname); - /* usage() never returns */ - } - } - while (start <= end) { - tests_run++; - if (test_run(start, tmpdir)) { - tests_failed++; - if (until_failure) - goto finish; - } - ++start; - } + if (*argv != NULL) argv++; - } - } + } while (*argv != NULL); } while (until_failure); finish: diff --git a/contrib/libarchive/libarchive/test/read_open_memory.c b/contrib/libarchive/libarchive/test/read_open_memory.c index 0d88df5..5ee8b30 100644 --- a/contrib/libarchive/libarchive/test/read_open_memory.c +++ b/contrib/libarchive/libarchive/test/read_open_memory.c @@ -68,7 +68,7 @@ read_open_memory(struct archive *a, void *buff, size_t size, size_t read_size) * that internals work correctly with just the minimal entry points. */ int -read_open_memory2(struct archive *a, void *buff, size_t size, size_t read_size) +read_open_memory_minimal(struct archive *a, void *buff, size_t size, size_t read_size) { return read_open_memory_internal(a, buff, size, read_size, 1); } diff --git a/contrib/libarchive/libarchive/test/test.h b/contrib/libarchive/libarchive/test/test.h index eb78f79..01a12fd 100644 --- a/contrib/libarchive/libarchive/test/test.h +++ b/contrib/libarchive/libarchive/test/test.h @@ -194,11 +194,15 @@ #define assertMakeDir(dirname, mode) \ assertion_make_dir(__FILE__, __LINE__, dirname, mode) #define assertMakeFile(path, mode, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, contents) + assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) +#define assertMakeBinFile(path, mode, csize, contents) \ + assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) #define assertMakeHardlink(newfile, oldfile) \ assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) #define assertMakeSymlink(newfile, linkto) \ assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) +#define assertNodump(path) \ + assertion_nodump(__FILE__, __LINE__, path) #define assertUmask(mask) \ assertion_umask(__FILE__, __LINE__, mask) #define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ @@ -241,9 +245,10 @@ int assertion_is_not_hardlink(const char *, int, const char *, const char *); int assertion_is_reg(const char *, int, const char *, int); int assertion_is_symlink(const char *, int, const char *, const char *); int assertion_make_dir(const char *, int, const char *, int); -int assertion_make_file(const char *, int, const char *, int, const char *); +int assertion_make_file(const char *, int, const char *, int, int, const void *); int assertion_make_hardlink(const char *, int, const char *newpath, const char *); int assertion_make_symlink(const char *, int, const char *newpath, const char *); +int assertion_nodump(const char *, int, const char *); int assertion_non_empty_file(const char *, int, const char *); int assertion_text_file_contents(const char *, int, const char *buff, const char *f); int assertion_umask(const char *, int, int); @@ -267,6 +272,9 @@ int canGzip(void); /* Return true if this platform can run the "gunzip" program. */ int canGunzip(void); +/* Return true if this filesystem can handle nodump flags. */ +int canNodump(void); + /* Return true if the file has large i-node number(>0xffffffff). */ int is_LargeInode(const char *); @@ -289,8 +297,8 @@ const char *testworkdir; /* Special customized read-from-memory interface. */ int read_open_memory(struct archive *, void *, size_t, size_t); -/* "2" version exercises a slightly different set of libarchive APIs. */ -int read_open_memory2(struct archive *, void *, size_t, size_t); +/* _minimal version exercises a slightly different set of libarchive APIs. */ +int read_open_memory_minimal(struct archive *, void *, size_t, size_t); /* _seek version produces a seekable file. */ int read_open_memory_seek(struct archive *, void *, size_t, size_t); diff --git a/contrib/libarchive/tar/test/test_getdate.c b/contrib/libarchive/libarchive/test/test_archive_getdate.c index cd6d55a..4be359b 100644 --- a/contrib/libarchive/tar/test/test_getdate.c +++ b/contrib/libarchive/libarchive/test/test_archive_getdate.c @@ -31,9 +31,10 @@ __FBSDID("$FreeBSD$"); * Verify that the getdate() function works. */ -time_t get_date(time_t, const char *); +time_t __archive_get_date(time_t, const char *); +#define get_date __archive_get_date -DEFINE_TEST(test_getdate) +DEFINE_TEST(test_archive_getdate) { time_t now = time(NULL); diff --git a/contrib/libarchive/libarchive/test/test_archive_match_owner.c b/contrib/libarchive/libarchive/test/test_archive_match_owner.c new file mode 100644 index 0000000..6bf9c6f --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_archive_match_owner.c @@ -0,0 +1,289 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" +__FBSDID("$FreeBSD$"); + +static void +test_uid(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_uid(m, 1000)); + assertEqualIntA(m, 0, archive_match_include_uid(m, 1002)); + + archive_entry_set_uid(ae, 0); + failure("uid 0 should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_uid(ae, 1000); + failure("uid 1000 should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_uid(ae, 1001); + failure("uid 1001 should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_uid(ae, 1002); + failure("uid 1002 should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_uid(ae, 1003); + failure("uid 1003 should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_gid(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_gid(m, 1000)); + assertEqualIntA(m, 0, archive_match_include_gid(m, 1002)); + + archive_entry_set_gid(ae, 0); + failure("uid 0 should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_gid(ae, 1000); + failure("uid 1000 should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_gid(ae, 1001); + failure("uid 1001 should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_gid(ae, 1002); + failure("uid 1002 should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_gid(ae, 1003); + failure("uid 1003 should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_uname_mbs(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_uname(m, "foo")); + assertEqualIntA(m, 0, archive_match_include_uname(m, "bar")); + + archive_entry_copy_uname(ae, "unknown"); + failure("User 'unknown' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_uname(ae, "foo"); + failure("User 'foo' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_uname(ae, "foo1"); + failure("User 'foo1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_uname(ae, "bar"); + failure("User 'bar' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_uname(ae, "bar1"); + failure("User 'bar1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_uname_wcs(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_uname_w(m, L"foo")); + assertEqualIntA(m, 0, archive_match_include_uname_w(m, L"bar")); + + archive_entry_copy_uname_w(ae, L"unknown"); + failure("User 'unknown' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_uname_w(ae, L"foo"); + failure("User 'foo' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_uname_w(ae, L"foo1"); + failure("User 'foo1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_uname_w(ae, L"bar"); + failure("User 'bar' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_uname_w(ae, L"bar1"); + failure("User 'bar1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_gname_mbs(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_gname(m, "foo")); + assertEqualIntA(m, 0, archive_match_include_gname(m, "bar")); + + archive_entry_copy_gname(ae, "unknown"); + failure("Group 'unknown' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_gname(ae, "foo"); + failure("Group 'foo' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_gname(ae, "foo1"); + failure("Group 'foo1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_gname(ae, "bar"); + failure("Group 'bar' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_gname(ae, "bar1"); + failure("Group 'bar1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_gname_wcs(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_gname_w(m, L"foo")); + assertEqualIntA(m, 0, archive_match_include_gname_w(m, L"bar")); + + archive_entry_copy_gname_w(ae, L"unknown"); + failure("Group 'unknown' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_gname_w(ae, L"foo"); + failure("Group 'foo' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_gname_w(ae, L"foo1"); + failure("Group 'foo1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_copy_gname_w(ae, L"bar"); + failure("Group 'bar' should not be excluded"); + assertEqualInt(0, archive_match_owner_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_copy_gname_w(ae, L"bar1"); + failure("Group 'bar1' should be excluded"); + assertEqualInt(1, archive_match_owner_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +DEFINE_TEST(test_archive_match_owner) +{ + test_uid(); + test_gid(); + test_uname_mbs(); + test_uname_wcs(); + test_gname_mbs(); + test_gname_wcs(); +} diff --git a/contrib/libarchive/libarchive/test/test_archive_match_path.c b/contrib/libarchive/libarchive/test/test_archive_match_path.c new file mode 100644 index 0000000..5e9b9a8 --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_archive_match_path.c @@ -0,0 +1,450 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" +__FBSDID("$FreeBSD$"); + +static void +test_exclusion_mbs(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + /* Test for pattern "^aa*" */ + assertEqualIntA(m, 0, archive_match_exclude_pattern(m, "^aa*")); + + /* Test with 'aa1234', which should be excluded. */ + archive_entry_copy_pathname(ae, "aa1234"); + failure("'aa1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"aa1234"); + failure("'aa1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Test with 'a1234', which should not be excluded. */ + archive_entry_copy_pathname(ae, "a1234"); + failure("'a1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"a1234"); + failure("'a1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_exclusion_wcs(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + /* Test for pattern "^aa*" */ + assertEqualIntA(m, 0, archive_match_exclude_pattern_w(m, L"^aa*")); + + /* Test with 'aa1234', which should be excluded. */ + archive_entry_copy_pathname(ae, "aa1234"); + failure("'aa1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"aa1234"); + failure("'aa1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Test with 'a1234', which should not be excluded. */ + archive_entry_copy_pathname(ae, "a1234"); + failure("'a1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"a1234"); + failure("'a1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +exclusion_from_file(struct archive *m) +{ + struct archive_entry *ae; + + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + /* Test with 'first', which should not be excluded. */ + archive_entry_copy_pathname(ae, "first"); + failure("'first' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"first"); + failure("'first' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Test with 'second', which should be excluded. */ + archive_entry_copy_pathname(ae, "second"); + failure("'second' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"second"); + failure("'second' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Test with 'third', which should not be excluded. */ + archive_entry_copy_pathname(ae, "third"); + failure("'third' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"third"); + failure("'third' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Test with 'four', which should be excluded. */ + archive_entry_copy_pathname(ae, "four"); + failure("'four' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"four"); + failure("'four' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); +} + +static void +test_exclusion_from_file_mbs(void) +{ + struct archive *m; + + /* Test1: read exclusion patterns from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + assertEqualIntA(m, 0, + archive_match_exclude_pattern_from_file(m, "exclusion", 0)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); + + /* Test2: read exclusion patterns in a null separator from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + /* Test for pattern reading from file */ + assertEqualIntA(m, 0, + archive_match_exclude_pattern_from_file(m, "exclusion_null", 1)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); +} + +static void +test_exclusion_from_file_wcs(void) +{ + struct archive *m; + + /* Test1: read exclusion patterns from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + assertEqualIntA(m, 0, + archive_match_exclude_pattern_from_file_w(m, L"exclusion", 0)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); + + /* Test2: read exclusion patterns in a null separator from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + /* Test for pattern reading from file */ + assertEqualIntA(m, 0, + archive_match_exclude_pattern_from_file_w(m, L"exclusion_null", 1)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); +} + +static void +test_inclusion_mbs(void) +{ + struct archive_entry *ae; + struct archive *m; + const char *mp; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + /* Test for pattern "^aa*" */ + assertEqualIntA(m, 0, archive_match_include_pattern(m, "^aa*")); + + /* Test with 'aa1234', which should not be excluded. */ + archive_entry_copy_pathname(ae, "aa1234"); + failure("'aa1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"aa1234"); + failure("'aa1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Test with 'a1234', which should be excluded. */ + archive_entry_copy_pathname(ae, "a1234"); + failure("'a1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"a1234"); + failure("'a1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify unmatched_inclusions. */ + assertEqualInt(0, archive_match_path_unmatched_inclusions(m)); + assertEqualIntA(m, ARCHIVE_EOF, + archive_match_path_unmatched_inclusions_next(m, &mp)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_inclusion_wcs(void) +{ + struct archive_entry *ae; + struct archive *m; + const char *mp; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + /* Test for pattern "^aa*" */ + assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"^aa*")); + + /* Test with 'aa1234', which should not be excluded. */ + archive_entry_copy_pathname(ae, "aa1234"); + failure("'aa1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"aa1234"); + failure("'aa1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Test with 'a1234', which should be excluded. */ + archive_entry_copy_pathname(ae, "a1234"); + failure("'a1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"a1234"); + failure("'a1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify unmatched_inclusions. */ + assertEqualInt(0, archive_match_path_unmatched_inclusions(m)); + assertEqualIntA(m, ARCHIVE_EOF, + archive_match_path_unmatched_inclusions_next(m, &mp)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_inclusion_from_file_mbs(void) +{ + struct archive *m; + + /* Test1: read inclusion patterns from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + assertEqualIntA(m, 0, + archive_match_include_pattern_from_file(m, "inclusion", 0)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); + + /* Test2: read inclusion patterns in a null separator from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + assertEqualIntA(m, 0, + archive_match_include_pattern_from_file(m, "inclusion_null", 1)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); +} + +static void +test_inclusion_from_file_wcs(void) +{ + struct archive *m; + + /* Test1: read inclusion patterns from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + /* Test for pattern reading from file */ + assertEqualIntA(m, 0, + archive_match_include_pattern_from_file_w(m, L"inclusion", 0)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); + + /* Test2: read inclusion patterns in a null separator from file */ + if (!assert((m = archive_match_new()) != NULL)) + return; + /* Test for pattern reading from file */ + assertEqualIntA(m, 0, + archive_match_include_pattern_from_file_w(m, L"inclusion_null", 1)); + exclusion_from_file(m); + /* Clean up. */ + archive_match_free(m); +} + +static void +test_exclusion_and_inclusion(void) +{ + struct archive_entry *ae; + struct archive *m; + const char *mp; + const wchar_t *wp; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_exclude_pattern(m, "^aaa*")); + assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"^aa*")); + assertEqualIntA(m, 0, archive_match_include_pattern(m, "^a1*")); + + /* Test with 'aa1234', which should not be excluded. */ + archive_entry_copy_pathname(ae, "aa1234"); + failure("'aa1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"aa1234"); + failure("'aa1234' should not be excluded"); + assertEqualInt(0, archive_match_path_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Test with 'aaa1234', which should be excluded. */ + archive_entry_copy_pathname(ae, "aaa1234"); + failure("'aaa1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_clear(ae); + archive_entry_copy_pathname_w(ae, L"aaa1234"); + failure("'aaa1234' should be excluded"); + assertEqualInt(1, archive_match_path_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify unmatched_inclusions. */ + assertEqualInt(1, archive_match_path_unmatched_inclusions(m)); + /* Verify unmatched inclusion patterns. */ + assertEqualIntA(m, ARCHIVE_OK, + archive_match_path_unmatched_inclusions_next(m, &mp)); + assertEqualString("^a1*", mp); + assertEqualIntA(m, ARCHIVE_EOF, + archive_match_path_unmatched_inclusions_next(m, &mp)); + /* Verify unmatched inclusion patterns again in Wide-Char. */ + assertEqualIntA(m, ARCHIVE_OK, + archive_match_path_unmatched_inclusions_next_w(m, &wp)); + assertEqualWString(L"^a1*", wp); + assertEqualIntA(m, ARCHIVE_EOF, + archive_match_path_unmatched_inclusions_next_w(m, &wp)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +DEFINE_TEST(test_archive_match_path) +{ + /* Make exclusion sample files which contain exclusion patterns. */ + assertMakeFile("exclusion", 0666, "second\nfour\n"); + assertMakeBinFile("exclusion_null", 0666, 12, "second\0four\0"); + /* Make inclusion sample files which contain inclusion patterns. */ + assertMakeFile("inclusion", 0666, "first\nthird\n"); + assertMakeBinFile("inclusion_null", 0666, 12, "first\0third\0"); + + test_exclusion_mbs(); + test_exclusion_wcs(); + test_exclusion_from_file_mbs(); + test_exclusion_from_file_wcs(); + test_inclusion_mbs(); + test_inclusion_wcs(); + test_inclusion_from_file_mbs(); + test_inclusion_from_file_wcs(); + test_exclusion_and_inclusion(); +} diff --git a/contrib/libarchive/libarchive/test/test_archive_match_time.c b/contrib/libarchive/libarchive/test/test_archive_match_time.c new file mode 100644 index 0000000..c951e0d --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_archive_match_time.c @@ -0,0 +1,1358 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" +__FBSDID("$FreeBSD$"); + +time_t __archive_get_date(time_t, const char *); + +static void +test_newer_time(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_time(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_NEWER, 7880, 0)); + + archive_entry_copy_pathname(ae, "file1"); + archive_entry_set_mtime(ae, 7880, 0); + archive_entry_set_ctime(ae, 7880, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7879, 999); + archive_entry_set_ctime(ae, 7879, 999); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, 7881, 0); + archive_entry_set_ctime(ae, 7881, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, 7880, 1); + archive_entry_set_ctime(ae, 7880, 0); + failure("Its mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, 7880, 0); + archive_entry_set_ctime(ae, 7880, 1); + failure("Its ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_newer_time_str(void) +{ + struct archive_entry *ae; + struct archive *m; + time_t now, t; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + time(&now); + + assertEqualIntA(m, 0, archive_match_include_date(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_NEWER, "1980/2/1 0:0:0 UTC")); + + /* Test1: Allow newer time. */ + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/2/1 0:0:1 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 1); + archive_entry_set_ctime(ae, t, 0); + failure("Its mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 1); + failure("Its ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + + /* Test2: Allow equal or newer time. */ + assertEqualIntA(m, 0, archive_match_include_date(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_EQUAL, + "1980/2/1 0:0:0 UTC")); + + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/2/1 0:0:1 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_newer_time_str_w(void) +{ + struct archive_entry *ae; + struct archive *m; + time_t now, t; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + time(&now); + + assertEqualIntA(m, 0, archive_match_include_date_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_NEWER, L"1980/2/1 0:0:0 UTC")); + + /* Test1: Allow newer time. */ + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/2/1 0:0:1 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 1); + archive_entry_set_ctime(ae, t, 0); + failure("Its mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 1); + failure("Its ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + + /* Test2: Allow equal or newer time. */ + assertEqualIntA(m, 0, archive_match_include_date_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_EQUAL, + L"1980/2/1 0:0:0 UTC")); + + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/2/1 0:0:1 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_newer_mtime_than_file_mbs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: newer mtime than a file specified in MBS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, "mid_mtime")); + + /* Verify 'old_mtime' file. */ + archive_entry_copy_pathname(ae, "old_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_mtime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_newer_ctime_than_file_mbs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: newer ctime than a file specified in MBS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, "mid_ctime")); + + /* Verify 'old_ctime' file. */ + archive_entry_copy_pathname(ae, "old_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_newer_mtime_than_file_wcs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: newer mtime than a file specified in WCS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, L"mid_mtime")); + + /* Verify 'old_mtime' file. */ + archive_entry_copy_pathname(ae, "old_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_mtime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_newer_ctime_than_file_wcs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: newer ctime than a file specified in WCS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, L"mid_ctime")); + + /* Verify 'old_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "old_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_older_time(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + assertEqualIntA(m, 0, archive_match_include_time(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_OLDER, 7880, 0)); + + archive_entry_copy_pathname(ae, "file1"); + archive_entry_set_mtime(ae, 7880, 0); + archive_entry_set_ctime(ae, 7880, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7879, 999); + archive_entry_set_ctime(ae, 7879, 999); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, 7881, 0); + archive_entry_set_ctime(ae, 7881, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, 7880, 1); + archive_entry_set_ctime(ae, 7879, 0); + failure("Its mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + archive_entry_set_mtime(ae, 7879, 0); + archive_entry_set_ctime(ae, 7880, 1); + failure("Its ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_older_time_str(void) +{ + struct archive_entry *ae; + struct archive *m; + time_t now, t; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + time(&now); + + /* Test1: Allow newer time. */ + assertEqualIntA(m, 0, archive_match_include_date(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_OLDER, "1980/2/1 0:0:0 UTC")); + + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_ctime(ae, t, 0); + failure("Its mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_ctime(ae, t, 0); + failure("Its ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Test2: Allow equal or newer time. */ + assertEqualIntA(m, 0, archive_match_include_date(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_OLDER | ARCHIVE_MATCH_EQUAL, + "1980/2/1 0:0:0 UTC")); + + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_older_time_str_w(void) +{ + struct archive_entry *ae; + struct archive *m; + time_t now, t; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + time(&now); + + /* Test1: Allow newer time. */ + assertEqualIntA(m, 0, archive_match_include_date_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_OLDER, L"1980/2/1 0:0:0 UTC")); + + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_ctime(ae, t, 0); + failure("Its mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_ctime(ae, t, 0); + failure("Its ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Test2: Allow equal or newer time. */ + assertEqualIntA(m, 0, archive_match_include_date_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME | + ARCHIVE_MATCH_OLDER | ARCHIVE_MATCH_EQUAL, + L"1980/2/1 0:0:0 UTC")); + + archive_entry_copy_pathname(ae, "file1"); + t = __archive_get_date(now, "1980/2/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + t = __archive_get_date(now, "1980/1/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + t = __archive_get_date(now, "1980/3/1 0:0:0 UTC"); + archive_entry_set_mtime(ae, t, 0); + archive_entry_set_ctime(ae, t, 0); + failure("Both Its mtime and ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_older_mtime_than_file_mbs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: older mtime than a file specified in MBS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, "mid_mtime")); + + /* Verify 'old_mtime' file. */ + archive_entry_copy_pathname(ae, "old_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_mtime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'mid_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_older_ctime_than_file_mbs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: older ctime than a file specified in MBS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, "mid_ctime")); + + /* Verify 'old_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "old_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'mid_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_older_mtime_than_file_wcs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: older mtime than a file specified in WCS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, L"mid_mtime")); + + /* Verify 'old_mtime' file. */ + archive_entry_copy_pathname(ae, "old_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_mtime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'mid_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_older_ctime_than_file_wcs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: older ctime than a file specified in WCS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, L"mid_ctime")); + + /* Verify 'old_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "old_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'mid_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'new_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_mtime_between_files_mbs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: mtime between file specified in MBS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, "old_mtime")); + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, "new_mtime")); + + /* Verify 'old_mtime' file. */ + archive_entry_copy_pathname(ae, "old_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_mtime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'new_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_mtime_between_files_wcs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: mtime between file specified in WCS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, L"old_mtime")); + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, L"new_mtime")); + + /* Verify 'old_mtime' file. */ + archive_entry_copy_pathname(ae, "old_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_mtime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'new_mtime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_mtime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_mtime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_ctime_between_files_mbs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: ctime between files specified in MBS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, "old_ctime")); + assertEqualIntA(m, 0, archive_match_include_file_time(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, "new_ctime")); + + /* Verify 'old_ctime' file. */ + archive_entry_copy_pathname(ae, "old_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'new_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +test_ctime_between_files_wcs(void) +{ + struct archive *a; + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + if (!assert((a = archive_read_disk_new()) != NULL)) { + archive_match_free(m); + archive_entry_free(ae); + return; + } + + /* + * Test: ctime between files specified in WCS file name. + */ + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, L"old_ctime")); + assertEqualIntA(m, 0, archive_match_include_file_time_w(m, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, L"new_ctime")); + + /* Verify 'old_ctime' file. */ + archive_entry_copy_pathname(ae, "old_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("old_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Verify 'mid_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "mid_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("mid_ctime should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + /* Verify 'new_ctime' file. */ + archive_entry_clear(ae); + archive_entry_copy_pathname(ae, "new_ctime"); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + failure("new_ctime should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* Clean up. */ + archive_read_free(a); + archive_entry_free(ae); + archive_match_free(m); +} + +static void +excluded(struct archive *m) +{ + struct archive_entry *ae; + + if (!assert((ae = archive_entry_new()) != NULL)) + return; + + archive_entry_copy_pathname(ae, "file1"); + archive_entry_set_mtime(ae, 7879, 999); + failure("It should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 0); + failure("It should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 1); + failure("It should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + archive_entry_copy_pathname(ae, "file2"); + archive_entry_set_mtime(ae, 7879, 999); + failure("It should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 0); + failure("It should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 1); + failure("It should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + archive_entry_copy_pathname(ae, "file3"); + archive_entry_set_mtime(ae, 7879, 999); + failure("It should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 0); + failure("It should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 1); + failure("It should be excluded"); + assertEqualInt(1, archive_match_time_excluded(m, ae)); + assertEqualInt(1, archive_match_excluded(m, ae)); + + /* + * "file4" is not registered, that sort of a file should not be + * excluded with any mtime. + */ + archive_entry_copy_pathname(ae, "file4"); + archive_entry_set_mtime(ae, 7879, 999); + failure("It should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 0); + failure("It should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + archive_entry_set_mtime(ae, 7880, 1); + failure("It should not be excluded"); + assertEqualInt(0, archive_match_time_excluded(m, ae)); + assertEqualInt(0, archive_match_excluded(m, ae)); + + + /* Clean up. */ + archive_entry_free(ae); +} + +static void +test_pathname_newer_mtime(void) +{ + struct archive_entry *ae; + struct archive *m; + + if (!assert((m = archive_match_new()) != NULL)) + return; + if (!assert((ae = archive_entry_new()) != NULL)) { + archive_match_free(m); + return; + } + + archive_entry_copy_pathname(ae, "file1"); + archive_entry_set_mtime(ae, 7880, 0); + assertEqualIntA(m, 0, archive_match_exclude_entry(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER | + ARCHIVE_MATCH_EQUAL, ae)); + archive_entry_copy_pathname(ae, "file2"); + archive_entry_set_mtime(ae, 1, 0); + assertEqualIntA(m, 0, archive_match_exclude_entry(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER | + ARCHIVE_MATCH_EQUAL, ae)); + archive_entry_copy_pathname(ae, "file3"); + archive_entry_set_mtime(ae, 99999, 0); + assertEqualIntA(m, 0, archive_match_exclude_entry(m, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER | + ARCHIVE_MATCH_EQUAL, ae)); + + excluded(m); + + /* Clean up. */ + archive_entry_free(ae); + archive_match_free(m); +} + +DEFINE_TEST(test_archive_match_time) +{ + struct stat st; + + /* Test: matching newer times. */ + test_newer_time(); + test_newer_time_str(); + test_newer_time_str_w(); + /* Test: matching older times. */ + test_older_time(); + test_older_time_str(); + test_older_time_str_w(); + + /* + * Create sample files for tests matching mtime. + * ctimes of those files may be all the same or the ctime of + * new_mtime may be older than old_mtime. + */ + assertMakeFile("new_mtime", 0666, "new"); + assertUtimes("new_mtime", 10002, 0, 10002, 0); + assertMakeFile("mid_mtime", 0666, "mid"); + assertUtimes("mid_mtime", 10001, 0, 10001, 0); + assertMakeFile("old_mtime", 0666, "old"); + assertUtimes("old_mtime", 10000, 0, 10000, 0); + + /* + * Create sample files for tests matching ctime. + * the mtime of mid_ctime is older than old_ctime and also the mtime + * of new_ctime is older than both mid_ctime and old_ctime. + */ + assertMakeFile("old_ctime", 0666, "old"); + assertUtimes("old_ctime", 10002, 0, 10002, 0); + assertEqualInt(0, stat("old_ctime", &st)); + sleepUntilAfter(st.st_ctime); + assertMakeFile("mid_ctime", 0666, "mid"); + assertUtimes("mid_ctime", 10001, 0, 10001, 0); + assertEqualInt(0, stat("mid_ctime", &st)); + sleepUntilAfter(st.st_ctime); + assertMakeFile("new_ctime", 0666, "new"); + assertUtimes("new_ctime", 10000, 0, 10000, 0); + + /* + * Test: matching mtime which indicated by files on the disk. + */ + test_newer_mtime_than_file_mbs(); + test_newer_mtime_than_file_wcs(); + test_older_mtime_than_file_mbs(); + test_older_mtime_than_file_wcs(); + test_mtime_between_files_mbs(); + test_mtime_between_files_wcs(); + + /* + * Test: matching ctime which indicated by files on the disk. + */ + test_newer_ctime_than_file_mbs(); + test_newer_ctime_than_file_wcs(); + test_older_ctime_than_file_mbs(); + test_older_ctime_than_file_wcs(); + test_ctime_between_files_mbs(); + test_ctime_between_files_wcs(); + + /* Test: matching both pathname and mtime. */ + test_pathname_newer_mtime(); +} diff --git a/contrib/libarchive/libarchive/test/test_archive_pathmatch.c b/contrib/libarchive/libarchive/test/test_archive_pathmatch.c new file mode 100644 index 0000000..fed6ad7 --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_archive_pathmatch.c @@ -0,0 +1,244 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +#define __LIBARCHIVE_TEST +#include "archive_pathmatch.h" + +/* + * Verify that the pattern matcher implements the wildcard logic specified + * in SUSv2 for the cpio command. This is essentially the + * shell glob syntax: + * * - matches any sequence of chars, including '/' + * ? - matches any single char, including '/' + * [...] - matches any of a set of chars, '-' specifies a range, + * initial '!' is undefined + * + * The specification in SUSv2 is a bit incomplete, I assume the following: + * Trailing '-' in [...] is not special. + * + * TODO: Figure out if there's a good way to extend this to handle + * Windows paths that use '\' as a path separator. <sigh> + */ + +DEFINE_TEST(test_archive_pathmatch) +{ + assertEqualInt(1, archive_pathmatch("a/b/c", "a/b/c", 0)); + assertEqualInt(0, archive_pathmatch("a/b/", "a/b/c", 0)); + assertEqualInt(0, archive_pathmatch("a/b", "a/b/c", 0)); + assertEqualInt(0, archive_pathmatch("a/b/c", "a/b/", 0)); + assertEqualInt(0, archive_pathmatch("a/b/c", "a/b", 0)); + + /* Empty pattern only matches empty string. */ + assertEqualInt(1, archive_pathmatch("","", 0)); + assertEqualInt(0, archive_pathmatch("","a", 0)); + assertEqualInt(1, archive_pathmatch("*","", 0)); + assertEqualInt(1, archive_pathmatch("*","a", 0)); + assertEqualInt(1, archive_pathmatch("*","abcd", 0)); + /* SUSv2: * matches / */ + assertEqualInt(1, archive_pathmatch("*","abcd/efgh/ijkl", 0)); + assertEqualInt(1, archive_pathmatch("abcd*efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(1, archive_pathmatch("abcd***efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(1, archive_pathmatch("abcd***/efgh/ijkl","abcd/efgh/ijkl", 0)); + assertEqualInt(0, archive_pathmatch("?", "", 0)); + assertEqualInt(0, archive_pathmatch("?", "\0", 0)); + assertEqualInt(1, archive_pathmatch("?", "a", 0)); + assertEqualInt(0, archive_pathmatch("?", "ab", 0)); + assertEqualInt(1, archive_pathmatch("?", ".", 0)); + assertEqualInt(1, archive_pathmatch("?", "?", 0)); + assertEqualInt(1, archive_pathmatch("a", "a", 0)); + assertEqualInt(0, archive_pathmatch("a", "ab", 0)); + assertEqualInt(0, archive_pathmatch("a", "ab", 0)); + assertEqualInt(1, archive_pathmatch("a?c", "abc", 0)); + /* SUSv2: ? matches / */ + assertEqualInt(1, archive_pathmatch("a?c", "a/c", 0)); + assertEqualInt(1, archive_pathmatch("a?*c*", "a/c", 0)); + assertEqualInt(1, archive_pathmatch("*a*", "a/c", 0)); + assertEqualInt(1, archive_pathmatch("*a*", "/a/c", 0)); + assertEqualInt(1, archive_pathmatch("*a*", "defaaaaaaa", 0)); + assertEqualInt(0, archive_pathmatch("a*", "defghi", 0)); + assertEqualInt(0, archive_pathmatch("*a*", "defghi", 0)); + + /* Character classes */ + assertEqualInt(1, archive_pathmatch("abc[def", "abc[def", 0)); + assertEqualInt(0, archive_pathmatch("abc[def]", "abc[def", 0)); + assertEqualInt(0, archive_pathmatch("abc[def", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[def]", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[def]", "abce", 0)); + assertEqualInt(1, archive_pathmatch("abc[def]", "abcf", 0)); + assertEqualInt(0, archive_pathmatch("abc[def]", "abcg", 0)); + assertEqualInt(1, archive_pathmatch("abc[d*f]", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[d*f]", "abc*", 0)); + assertEqualInt(0, archive_pathmatch("abc[d*f]", "abcdefghi", 0)); + assertEqualInt(0, archive_pathmatch("abc[d*", "abcdefghi", 0)); + assertEqualInt(1, archive_pathmatch("abc[d*", "abc[defghi", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-f]", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-f]", "abce", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-f]", "abcf", 0)); + assertEqualInt(0, archive_pathmatch("abc[d-f]", "abcg", 0)); + assertEqualInt(0, archive_pathmatch("abc[d-fh-k]", "abca", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-k]", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-k]", "abce", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-k]", "abcf", 0)); + assertEqualInt(0, archive_pathmatch("abc[d-fh-k]", "abcg", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-k]", "abch", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-k]", "abci", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-k]", "abcj", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-k]", "abck", 0)); + assertEqualInt(0, archive_pathmatch("abc[d-fh-k]", "abcl", 0)); + assertEqualInt(0, archive_pathmatch("abc[d-fh-k]", "abc-", 0)); + + /* [] matches nothing, [!] is the same as ? */ + assertEqualInt(0, archive_pathmatch("abc[]efg", "abcdefg", 0)); + assertEqualInt(0, archive_pathmatch("abc[]efg", "abcqefg", 0)); + assertEqualInt(0, archive_pathmatch("abc[]efg", "abcefg", 0)); + assertEqualInt(1, archive_pathmatch("abc[!]efg", "abcdefg", 0)); + assertEqualInt(1, archive_pathmatch("abc[!]efg", "abcqefg", 0)); + assertEqualInt(0, archive_pathmatch("abc[!]efg", "abcefg", 0)); + + /* I assume: Trailing '-' is non-special. */ + assertEqualInt(0, archive_pathmatch("abc[d-fh-]", "abcl", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-]", "abch", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-]", "abc-", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-fh-]", "abc-", 0)); + + /* ']' can be backslash-quoted within a character class. */ + assertEqualInt(1, archive_pathmatch("abc[\\]]", "abc]", 0)); + assertEqualInt(1, archive_pathmatch("abc[\\]d]", "abc]", 0)); + assertEqualInt(1, archive_pathmatch("abc[\\]d]", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[d\\]]", "abc]", 0)); + assertEqualInt(1, archive_pathmatch("abc[d\\]]", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[d]e]", "abcde]", 0)); + assertEqualInt(1, archive_pathmatch("abc[d\\]e]", "abc]", 0)); + assertEqualInt(0, archive_pathmatch("abc[d\\]e]", "abcd]e", 0)); + assertEqualInt(0, archive_pathmatch("abc[d]e]", "abc]", 0)); + + /* backslash-quoted chars can appear as either end of a range. */ + assertEqualInt(1, archive_pathmatch("abc[\\d-f]gh", "abcegh", 0)); + assertEqualInt(0, archive_pathmatch("abc[\\d-f]gh", "abcggh", 0)); + assertEqualInt(0, archive_pathmatch("abc[\\d-f]gh", "abc\\gh", 0)); + assertEqualInt(1, archive_pathmatch("abc[d-\\f]gh", "abcegh", 0)); + assertEqualInt(1, archive_pathmatch("abc[\\d-\\f]gh", "abcegh", 0)); + assertEqualInt(1, archive_pathmatch("abc[\\d-\\f]gh", "abcegh", 0)); + /* backslash-quoted '-' isn't special. */ + assertEqualInt(0, archive_pathmatch("abc[d\\-f]gh", "abcegh", 0)); + assertEqualInt(1, archive_pathmatch("abc[d\\-f]gh", "abc-gh", 0)); + + /* Leading '!' negates a character class. */ + assertEqualInt(0, archive_pathmatch("abc[!d]", "abcd", 0)); + assertEqualInt(1, archive_pathmatch("abc[!d]", "abce", 0)); + assertEqualInt(1, archive_pathmatch("abc[!d]", "abcc", 0)); + assertEqualInt(0, archive_pathmatch("abc[!d-z]", "abcq", 0)); + assertEqualInt(1, archive_pathmatch("abc[!d-gi-z]", "abch", 0)); + assertEqualInt(1, archive_pathmatch("abc[!fgijkl]", "abch", 0)); + assertEqualInt(0, archive_pathmatch("abc[!fghijkl]", "abch", 0)); + + /* Backslash quotes next character. */ + assertEqualInt(0, archive_pathmatch("abc\\[def]", "abc\\d", 0)); + assertEqualInt(1, archive_pathmatch("abc\\[def]", "abc[def]", 0)); + assertEqualInt(0, archive_pathmatch("abc\\\\[def]", "abc[def]", 0)); + assertEqualInt(0, archive_pathmatch("abc\\\\[def]", "abc\\[def]", 0)); + assertEqualInt(1, archive_pathmatch("abc\\\\[def]", "abc\\d", 0)); + assertEqualInt(1, archive_pathmatch("abcd\\", "abcd\\", 0)); + assertEqualInt(0, archive_pathmatch("abcd\\", "abcd\\[", 0)); + assertEqualInt(0, archive_pathmatch("abcd\\", "abcde", 0)); + assertEqualInt(0, archive_pathmatch("abcd\\[", "abcd\\", 0)); + + /* + * Because '.' and '/' have special meanings, we can + * identify many equivalent paths even if they're expressed + * differently. (But quoting a character with '\\' suppresses + * special meanings!) + */ + assertEqualInt(0, archive_pathmatch("a/b/", "a/bc", 0)); + assertEqualInt(1, archive_pathmatch("a/./b", "a/b", 0)); + assertEqualInt(0, archive_pathmatch("a\\/./b", "a/b", 0)); + assertEqualInt(0, archive_pathmatch("a/\\./b", "a/b", 0)); + assertEqualInt(0, archive_pathmatch("a/.\\/b", "a/b", 0)); + assertEqualInt(0, archive_pathmatch("a\\/\\.\\/b", "a/b", 0)); + assertEqualInt(1, archive_pathmatch("./abc/./def/", "abc/def/", 0)); + assertEqualInt(1, archive_pathmatch("abc/def", "./././abc/./def", 0)); + assertEqualInt(1, archive_pathmatch("abc/def/././//", "./././abc/./def/", 0)); + assertEqualInt(1, archive_pathmatch(".////abc/.//def", "./././abc/./def", 0)); + assertEqualInt(1, archive_pathmatch("./abc?def/", "abc/def/", 0)); + failure("\"?./\" is not the same as \"/./\""); + assertEqualInt(0, archive_pathmatch("./abc?./def/", "abc/def/", 0)); + failure("Trailing '/' should match no trailing '/'"); + assertEqualInt(1, archive_pathmatch("./abc/./def/", "abc/def", 0)); + failure("Trailing '/./' is still the same directory."); + assertEqualInt(1, archive_pathmatch("./abc/./def/./", "abc/def", 0)); + failure("Trailing '/.' is still the same directory."); + assertEqualInt(1, archive_pathmatch("./abc/./def/.", "abc/def", 0)); + assertEqualInt(1, archive_pathmatch("./abc/./def", "abc/def/", 0)); + failure("Trailing '/./' is still the same directory."); + assertEqualInt(1, archive_pathmatch("./abc/./def", "abc/def/./", 0)); + failure("Trailing '/.' is still the same directory."); + assertEqualInt(1, archive_pathmatch("./abc*/./def", "abc/def/.", 0)); + + /* Matches not anchored at beginning. */ + assertEqualInt(0, + archive_pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(1, + archive_pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(0, + archive_pathmatch("^bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(1, + archive_pathmatch("b/c/d", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(0, + archive_pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(0, + archive_pathmatch("^b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + + /* Matches not anchored at end. */ + assertEqualInt(0, + archive_pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("abcd", "abcd/", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("abcd", "abcd/.", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + archive_pathmatch("abc", "abcd", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("a/b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + archive_pathmatch("a/b/c$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("a/b/c$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("a/b/c$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("a/b/c/", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + archive_pathmatch("a/b/c/$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("a/b/c/$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + archive_pathmatch("a/b/c/$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + archive_pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); +} diff --git a/contrib/libarchive/libarchive/test/test_archive_string_conversion.c b/contrib/libarchive/libarchive/test/test_archive_string_conversion.c index 8b833ea..fea141d 100644 --- a/contrib/libarchive/libarchive/test/test_archive_string_conversion.c +++ b/contrib/libarchive/libarchive/test/test_archive_string_conversion.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2011 Michihiro NAKAJIMA + * Copyright (c) 2011-2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$"); Execute the following to rebuild the data for this program: tail -n +36 test_archive_string_conversion.c | /bin/sh # -# This requires http://unicode.org/Public/UNIDATA/NormalizationTest.txt +# This requires http://unicode.org/Public/6.0.0/ucd/NormalizationTest.txt # if="NormalizationTest.txt" if [ ! -f ${if} ]; then @@ -158,7 +158,7 @@ unicode_to_wc(wchar_t *wp, uint32_t uc) */ static int scan_unicode_pattern(char *out, wchar_t *wout, char *u16be, char *u16le, - const char *pattern, int exclude_mac_nfd) + const char *pattern, int mac_nfd) { unsigned uc = 0; const char *p = pattern; @@ -166,6 +166,7 @@ scan_unicode_pattern(char *out, wchar_t *wout, char *u16be, char *u16le, wchar_t *owp = wout; char *op16be = u16be; char *op16le = u16le; + int ret = 0; for (;;) { if (*p >= '0' && *p <= '9') @@ -173,14 +174,31 @@ scan_unicode_pattern(char *out, wchar_t *wout, char *u16be, char *u16le, else if (*p >= 'A' && *p <= 'F') uc = (uc << 4) + (*p - 'A' + 0x0a); else { - if (exclude_mac_nfd) { + if (mac_nfd && op == out) { /* * These are not converted to NFD on Mac OS. + * U+2000 - U+2FFF + * U+F900 - U+FAFF + * U+2F800 - U+2FAFF */ - if ((uc >= 0x2000 && uc <= 0x2FFF) || - (uc >= 0xF900 && uc <= 0xFAFF) || - (uc >= 0x2F800 && uc <= 0x2FAFF)) - return (-1); + switch (uc) { + case 0x2194: case 0x219A: case 0x219B: + case 0x21AE: case 0x21CD: case 0x21CE: + case 0x21CF: case 0x2204: case 0x2209: + case 0x220C: case 0x2224: case 0x2226: + case 0x2241: case 0x2244: case 0x2247: + case 0x2249: case 0x2260: case 0x2262: + case 0x226D: case 0x226E: case 0x226F: + case 0x2270: case 0x2271: case 0x2274: + case 0x2275: case 0x2276: case 0x2278: + case 0x2279: case 0x227A: case 0x227B: + case 0x2280: case 0x2281: case 0x2284: + case 0x2285: case 0x2288: case 0x2289: + case 0x22AC: case 0x22AD: case 0x22AE: + case 0x22AF: case 0x22E0: case 0x22E1: + case 0x22E2: case 0x22E3: case 0x22EA: + case 0x22EB: case 0x22EC: case 0x22ED: + /* * Those code points are not converted to * NFD on Mac OS. I do not know the reason @@ -190,9 +208,10 @@ scan_unicode_pattern(char *out, wchar_t *wout, char *u16be, char *u16le, * 1109C ==> 1109B 110BA * 110AB ==> 110A5 110BA */ - if (uc == 0x1109A || uc == 0x1109C || - uc == 0x110AB) - return (-1); + case 0x1109A: case 0x1109C: case 0x110AB: + ret = 1; + break; + } } op16be += unicode_to_utf16be(op16be, uc); op16le += unicode_to_utf16le(op16le, uc); @@ -211,7 +230,7 @@ scan_unicode_pattern(char *out, wchar_t *wout, char *u16be, char *u16le, } p++; } - return (0); + return (ret); } static int @@ -230,27 +249,26 @@ is_wc_unicode(void) * On other platforms, the characters to be Form C. */ static void -test_archive_string_normalization(void) +test_archive_string_normalization_nfc(const char *testdata) { struct archive *a, *a2; - struct archive_entry *ae; struct archive_string utf8; struct archive_mstring mstr; struct archive_string_conv *f_sconv8, *t_sconv8; struct archive_string_conv *f_sconv16be, *f_sconv16le; FILE *fp; char buff[512]; - static const char reffile[] = "test_archive_string_conversion.txt.Z"; - ssize_t size; int line = 0; int locale_is_utf8, wc_is_unicode; + int sconv_opt = SCONV_SET_OPT_NORMALIZATION_C; locale_is_utf8 = (NULL != setlocale(LC_ALL, "en_US.UTF-8")); wc_is_unicode = is_wc_unicode(); /* If it doesn't exist, just warn and return. */ if (!locale_is_utf8 && !wc_is_unicode) { - skipping("invalid encoding tests require a suitable locale;" - " en_US.UTF-8 not available on this system"); + skipping("A test of string normalization for NFC requires " + "a suitable locale; en_US.UTF-8 not available on this " + "system"); return; } @@ -258,27 +276,9 @@ test_archive_string_normalization(void) memset(&mstr, 0, sizeof(mstr)); /* - * Extract a test pattern file. - */ - extract_reference_file(reffile); - assert((a = archive_read_new()) != NULL); - assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); - assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_raw(a)); - assertEqualIntA(a, ARCHIVE_OK, - archive_read_open_filename(a, reffile, 512)); - - assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assert((fp = fopen("testdata.txt", "w")) != NULL); - while ((size = archive_read_data(a, buff, 512)) > 0) - fwrite(buff, 1, size, fp); - fclose(fp); - - /* Open a test pattern file. */ - assert((fp = fopen("testdata.txt", "r")) != NULL); - - /* * Create string conversion objects. */ + assert((a = archive_read_new()) != NULL); assertA(NULL != (f_sconv8 = archive_string_conversion_from_charset(a, "UTF-8", 0))); assertA(NULL != (f_sconv16be = @@ -289,13 +289,18 @@ test_archive_string_normalization(void) assertA(NULL != (t_sconv8 = archive_string_conversion_to_charset(a2, "UTF-8", 0))); if (f_sconv8 == NULL || f_sconv16be == NULL || f_sconv16le == NULL || - t_sconv8 == NULL || fp == NULL) { + t_sconv8 == NULL) { /* We cannot continue this test. */ - if (fp != NULL) - fclose(fp); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); return; } + archive_string_conversion_set_opt(f_sconv8, sconv_opt); + archive_string_conversion_set_opt(f_sconv16be, sconv_opt); + archive_string_conversion_set_opt(f_sconv16le, sconv_opt); + archive_string_conversion_set_opt(t_sconv8, sconv_opt); + + /* Open a test pattern file. */ + assert((fp = fopen(testdata, "r")) != NULL); /* * Read test data. @@ -311,6 +316,9 @@ test_archive_string_normalization(void) char utf16le_nfc[80], utf16le_nfd[80]; wchar_t wc_nfc[40], wc_nfd[40]; char *e, *p; + const wchar_t *wp; + const char *mp; + size_t mplen; line++; if (buff[0] == '#') @@ -332,74 +340,22 @@ test_archive_string_normalization(void) nfd[sizeof(nfd)-1] = '\0'; /* - * Convert an NFC pattern to UTF-8 bytes. + * Get an NFC patterns. */ -#if defined(__APPLE__) - if (scan_unicode_pattern(utf8_nfc, wc_nfc, utf16be_nfc, utf16le_nfc, - nfc, 1) != 0) - continue; -#else scan_unicode_pattern(utf8_nfc, wc_nfc, utf16be_nfc, utf16le_nfc, nfc, 0); -#endif /* - * Convert an NFD pattern to UTF-8 bytes. + * Get an NFD patterns. */ scan_unicode_pattern(utf8_nfd, wc_nfd, utf16be_nfd, utf16le_nfd, nfd, 0); if (locale_is_utf8) { -#if defined(__APPLE__) - /* - * Normalize an NFC string for import. - */ - assertEqualInt(0, archive_strcpy_in_locale( - &utf8, utf8_nfc, f_sconv8)); - failure("NFC(%s) should be converted to NFD(%s):%d", - nfc, nfd, line); - assertEqualUTF8String(utf8_nfd, utf8.s); - - /* - * Normalize an NFD string for import. - */ - assertEqualInt(0, archive_strcpy_in_locale( - &utf8, utf8_nfd, f_sconv8)); - failure("NFD(%s) should not be any changed:%d", - nfd, line); - assertEqualUTF8String(utf8_nfd, utf8.s); - - /* - * Copy an NFD string for export. - */ - assertEqualInt(0, archive_strcpy_in_locale( - &utf8, utf8_nfd, t_sconv8)); - failure("NFD(%s) should not be any changed:%d", - nfd, line); - assertEqualUTF8String(utf8_nfd, utf8.s); - - /* - * Normalize an NFC string in UTF-16BE for import. - */ - assertEqualInt(0, archive_strncpy_in_locale( - &utf8, utf16be_nfc, 100000, f_sconv16be)); - failure("NFC(%s) should be converted to NFD(%s):%d", - nfc, nfd, line); - assertEqualUTF8String(utf8_nfd, utf8.s); - - /* - * Normalize an NFC string in UTF-16LE for import. - */ - assertEqualInt(0, archive_strncpy_in_locale( - &utf8, utf16le_nfc, 100000, f_sconv16le)); - failure("NFC(%s) should be converted to NFD(%s):%d", - nfc, nfd, line); - assertEqualUTF8String(utf8_nfd, utf8.s); -#else /* * Normalize an NFD string for import. */ - assertEqualInt(0, archive_strcpy_in_locale( + assertEqualInt(0, archive_strcpy_l( &utf8, utf8_nfd, f_sconv8)); failure("NFD(%s) should be converted to NFC(%s):%d", nfd, nfc, line); @@ -408,7 +364,7 @@ test_archive_string_normalization(void) /* * Normalize an NFC string for import. */ - assertEqualInt(0, archive_strcpy_in_locale( + assertEqualInt(0, archive_strcpy_l( &utf8, utf8_nfc, f_sconv8)); failure("NFC(%s) should not be any changed:%d", nfc, line); @@ -417,7 +373,7 @@ test_archive_string_normalization(void) /* * Copy an NFC string for export. */ - assertEqualInt(0, archive_strcpy_in_locale( + assertEqualInt(0, archive_strcpy_l( &utf8, utf8_nfc, t_sconv8)); failure("NFC(%s) should not be any changed:%d", nfc, line); @@ -426,7 +382,7 @@ test_archive_string_normalization(void) /* * Normalize an NFD string in UTF-16BE for import. */ - assertEqualInt(0, archive_strncpy_in_locale( + assertEqualInt(0, archive_strncpy_l( &utf8, utf16be_nfd, 100000, f_sconv16be)); failure("NFD(%s) should be converted to NFC(%s):%d", nfd, nfc, line); @@ -435,12 +391,11 @@ test_archive_string_normalization(void) /* * Normalize an NFD string in UTF-16LE for import. */ - assertEqualInt(0, archive_strncpy_in_locale( + assertEqualInt(0, archive_strncpy_l( &utf8, utf16le_nfd, 100000, f_sconv16le)); failure("NFD(%s) should be converted to NFC(%s):%d", nfd, nfc, line); assertEqualUTF8String(utf8_nfc, utf8.s); -#endif } /* @@ -451,99 +406,299 @@ test_archive_string_normalization(void) * locale UTF-8. */ if (locale_is_utf8 || wc_is_unicode) { - const wchar_t *wp; - const char *mp; - size_t mplen; - -#if defined(__APPLE__) /* * Normalize an NFD string in UTF-8 for import. */ assertEqualInt(0, archive_mstring_copy_mbs_len_l( - &mstr, utf8_nfc, 100000, f_sconv8)); + &mstr, utf8_nfd, 100000, f_sconv8)); assertEqualInt(0, archive_mstring_get_wcs(a, &mstr, &wp)); - failure("UTF-8 NFC(%s) should be converted " - "to WCS NFD(%s):%d", nfc, nfd, line); - assertEqualWString(wc_nfd, wp); + failure("UTF-8 NFD(%s) should be converted " + "to WCS NFC(%s):%d", nfd, nfc, line); + assertEqualWString(wc_nfc, wp); /* * Normalize an NFD string in UTF-16BE for import. */ assertEqualInt(0, archive_mstring_copy_mbs_len_l( - &mstr, utf16be_nfc, 100000, f_sconv16be)); + &mstr, utf16be_nfd, 100000, f_sconv16be)); assertEqualInt(0, archive_mstring_get_wcs(a, &mstr, &wp)); - failure("UTF-16BE NFC(%s) should be converted " - "to WCS NFD(%s):%d", nfc, nfd, line); - assertEqualWString(wc_nfd, wp); + failure("UTF-8 NFD(%s) should be converted " + "to WCS NFC(%s):%d", nfd, nfc, line); + assertEqualWString(wc_nfc, wp); /* * Normalize an NFD string in UTF-16LE for import. */ assertEqualInt(0, archive_mstring_copy_mbs_len_l( - &mstr, utf16le_nfc, 100000, f_sconv16le)); + &mstr, utf16le_nfd, 100000, f_sconv16le)); assertEqualInt(0, archive_mstring_get_wcs(a, &mstr, &wp)); - failure("UTF-16LE NFC(%s) should be converted " - "to WCS NFD(%s):%d", nfc, nfd, line); - assertEqualWString(wc_nfd, wp); + failure("UTF-8 NFD(%s) should be converted " + "to WCS NFC(%s):%d", nfd, nfc, line); + assertEqualWString(wc_nfc, wp); /* - * Copy an NFD wide-string for export. + * Copy an NFC wide-string for export. */ - assertEqualInt(0, archive_mstring_copy_wcs( - &mstr, wc_nfd)); + assertEqualInt(0, + archive_mstring_copy_wcs(&mstr, wc_nfc)); assertEqualInt(0, archive_mstring_get_mbs_l( &mstr, &mp, &mplen, t_sconv8)); - failure("WCS NFD(%s) should be UTF-8 NFD:%d" - ,nfd, line); - assertEqualUTF8String(utf8_nfd, mp); -#else + failure("WCS NFC(%s) should be UTF-8 NFC:%d" + ,nfc, line); + assertEqualUTF8String(utf8_nfc, mp); + } + } + + archive_string_free(&utf8); + archive_mstring_clean(&mstr); + fclose(fp); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a2)); +} + +static void +test_archive_string_normalization_mac_nfd(const char *testdata) +{ + struct archive *a, *a2; + struct archive_string utf8; + struct archive_mstring mstr; + struct archive_string_conv *f_sconv8, *t_sconv8; + struct archive_string_conv *f_sconv16be, *f_sconv16le; + FILE *fp; + char buff[512]; + int line = 0; + int locale_is_utf8, wc_is_unicode; + int sconv_opt = SCONV_SET_OPT_NORMALIZATION_D; + + locale_is_utf8 = (NULL != setlocale(LC_ALL, "en_US.UTF-8")); + wc_is_unicode = is_wc_unicode(); + /* If it doesn't exist, just warn and return. */ + if (!locale_is_utf8 && !wc_is_unicode) { + skipping("A test of string normalization for NFD requires " + "a suitable locale; en_US.UTF-8 not available on this " + "system"); + return; + } + + archive_string_init(&utf8); + memset(&mstr, 0, sizeof(mstr)); + + /* + * Create string conversion objects. + */ + assert((a = archive_read_new()) != NULL); + assertA(NULL != (f_sconv8 = + archive_string_conversion_from_charset(a, "UTF-8", 0))); + assertA(NULL != (f_sconv16be = + archive_string_conversion_from_charset(a, "UTF-16BE", 0))); + assertA(NULL != (f_sconv16le = + archive_string_conversion_from_charset(a, "UTF-16LE", 0))); + assert((a2 = archive_write_new()) != NULL); + assertA(NULL != (t_sconv8 = + archive_string_conversion_to_charset(a2, "UTF-8", 0))); + if (f_sconv8 == NULL || f_sconv16be == NULL || f_sconv16le == NULL || + t_sconv8 == NULL) { + /* We cannot continue this test. */ + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + return; + } + archive_string_conversion_set_opt(f_sconv8, sconv_opt); + archive_string_conversion_set_opt(f_sconv16be, sconv_opt); + archive_string_conversion_set_opt(f_sconv16le, sconv_opt); + archive_string_conversion_set_opt(t_sconv8, sconv_opt); + + /* Open a test pattern file. */ + assert((fp = fopen(testdata, "r")) != NULL); + + /* + * Read test data. + * Test data format: + * <NFC Unicode pattern> ';' <NFD Unicode pattern> '\n' + * Unicode pattern format: + * [0-9A-F]{4,5}([ ][0-9A-F]{4,5}){0,} + */ + while (fgets(buff, sizeof(buff), fp) != NULL) { + char nfc[80], nfd[80]; + char utf8_nfc[80], utf8_nfd[80]; + char utf16be_nfc[80], utf16be_nfd[80]; + char utf16le_nfc[80], utf16le_nfd[80]; + wchar_t wc_nfc[40], wc_nfd[40]; + char *e, *p; + const wchar_t *wp; + const char *mp; + size_t mplen; + int should_be_nfc; + + line++; + if (buff[0] == '#') + continue; + p = strchr(buff, ';'); + if (p == NULL) + continue; + *p++ = '\0'; + /* Copy an NFC pattern */ + strncpy(nfc, buff, sizeof(nfc)-1); + nfc[sizeof(nfc)-1] = '\0'; + e = p; + p = strchr(p, '\n'); + if (p == NULL) + continue; + *p = '\0'; + /* Copy an NFD pattern */ + strncpy(nfd, e, sizeof(nfd)-1); + nfd[sizeof(nfd)-1] = '\0'; + + /* + * Get an NFC patterns. + */ + should_be_nfc = scan_unicode_pattern(utf8_nfc, wc_nfc, + utf16be_nfc, utf16le_nfc, nfc, 1); + + /* + * Get an NFD patterns. + */ + scan_unicode_pattern(utf8_nfd, wc_nfd, utf16be_nfd, utf16le_nfd, + nfd, 0); + + if (locale_is_utf8) { + /* + * Normalize an NFC string for import. + */ + assertEqualInt(0, archive_strcpy_l( + &utf8, utf8_nfc, f_sconv8)); + if (should_be_nfc) { + failure("NFC(%s) should not be converted to" + " NFD(%s):%d", nfc, nfd, line); + assertEqualUTF8String(utf8_nfc, utf8.s); + } else { + failure("NFC(%s) should be converted to" + " NFD(%s):%d", nfc, nfd, line); + assertEqualUTF8String(utf8_nfd, utf8.s); + } + + /* + * Normalize an NFD string for import. + */ + assertEqualInt(0, archive_strcpy_l( + &utf8, utf8_nfd, f_sconv8)); + failure("NFD(%s) should not be any changed:%d", + nfd, line); + assertEqualUTF8String(utf8_nfd, utf8.s); + + /* + * Copy an NFD string for export. + */ + assertEqualInt(0, archive_strcpy_l( + &utf8, utf8_nfd, t_sconv8)); + failure("NFD(%s) should not be any changed:%d", + nfd, line); + assertEqualUTF8String(utf8_nfd, utf8.s); + + /* + * Normalize an NFC string in UTF-16BE for import. + */ + assertEqualInt(0, archive_strncpy_l( + &utf8, utf16be_nfc, 100000, f_sconv16be)); + if (should_be_nfc) { + failure("NFC(%s) should not be converted to" + " NFD(%s):%d", nfc, nfd, line); + assertEqualUTF8String(utf8_nfc, utf8.s); + } else { + failure("NFC(%s) should be converted to" + " NFD(%s):%d", nfc, nfd, line); + assertEqualUTF8String(utf8_nfd, utf8.s); + } + + /* + * Normalize an NFC string in UTF-16LE for import. + */ + assertEqualInt(0, archive_strncpy_l( + &utf8, utf16le_nfc, 100000, f_sconv16le)); + if (should_be_nfc) { + failure("NFC(%s) should not be converted to" + " NFD(%s):%d", nfc, nfd, line); + assertEqualUTF8String(utf8_nfc, utf8.s); + } else { + failure("NFC(%s) should be converted to" + " NFD(%s):%d", nfc, nfd, line); + assertEqualUTF8String(utf8_nfd, utf8.s); + } + } + + /* + * Test for archive_mstring interface. + * In specific, Windows platform UTF-16BE is directly + * converted to/from wide-character to avoid the effect of + * current locale since windows platform cannot make + * locale UTF-8. + */ + if (locale_is_utf8 || wc_is_unicode) { /* * Normalize an NFD string in UTF-8 for import. */ assertEqualInt(0, archive_mstring_copy_mbs_len_l( - &mstr, utf8_nfd, 100000, f_sconv8)); + &mstr, utf8_nfc, 100000, f_sconv8)); assertEqualInt(0, archive_mstring_get_wcs(a, &mstr, &wp)); - failure("UTF-8 NFD(%s) should be converted " - "to WCS NFC(%s):%d", nfd, nfc, line); - assertEqualWString(wc_nfc, wp); + if (should_be_nfc) { + failure("UTF-8 NFC(%s) should not be converted " + "to WCS NFD(%s):%d", nfc, nfd, line); + assertEqualWString(wc_nfc, wp); + } else { + failure("UTF-8 NFC(%s) should be converted " + "to WCS NFD(%s):%d", nfc, nfd, line); + assertEqualWString(wc_nfd, wp); + } /* * Normalize an NFD string in UTF-16BE for import. */ assertEqualInt(0, archive_mstring_copy_mbs_len_l( - &mstr, utf16be_nfd, 100000, f_sconv16be)); + &mstr, utf16be_nfc, 100000, f_sconv16be)); assertEqualInt(0, archive_mstring_get_wcs(a, &mstr, &wp)); - failure("UTF-8 NFD(%s) should be converted " - "to WCS NFC(%s):%d", nfd, nfc, line); - assertEqualWString(wc_nfc, wp); + if (should_be_nfc) { + failure("UTF-16BE NFC(%s) should not be " + "converted to WCS NFD(%s):%d", + nfc, nfd, line); + assertEqualWString(wc_nfc, wp); + } else { + failure("UTF-16BE NFC(%s) should be converted " + "to WCS NFD(%s):%d", nfc, nfd, line); + assertEqualWString(wc_nfd, wp); + } /* * Normalize an NFD string in UTF-16LE for import. */ assertEqualInt(0, archive_mstring_copy_mbs_len_l( - &mstr, utf16le_nfd, 100000, f_sconv16le)); + &mstr, utf16le_nfc, 100000, f_sconv16le)); assertEqualInt(0, archive_mstring_get_wcs(a, &mstr, &wp)); - failure("UTF-8 NFD(%s) should be converted " - "to WCS NFC(%s):%d", nfd, nfc, line); - assertEqualWString(wc_nfc, wp); + if (should_be_nfc) { + failure("UTF-16LE NFC(%s) should not be " + "converted to WCS NFD(%s):%d", + nfc, nfd, line); + assertEqualWString(wc_nfc, wp); + } else { + failure("UTF-16LE NFC(%s) should be converted " + "to WCS NFD(%s):%d", nfc, nfd, line); + assertEqualWString(wc_nfd, wp); + } /* - * Copy an NFC wide-string for export. + * Copy an NFD wide-string for export. */ assertEqualInt(0, archive_mstring_copy_wcs( - &mstr, wc_nfc)); + &mstr, wc_nfd)); assertEqualInt(0, archive_mstring_get_mbs_l( &mstr, &mp, &mplen, t_sconv8)); - failure("WCS NFC(%s) should be UTF-8 NFC:%d" - ,nfc, line); - assertEqualUTF8String(utf8_nfc, mp); -#endif + failure("WCS NFD(%s) should be UTF-8 NFD:%d" + ,nfd, line); + assertEqualUTF8String(utf8_nfd, mp); } } @@ -624,6 +779,32 @@ test_archive_string_canonicalization(void) DEFINE_TEST(test_archive_string_conversion) { - test_archive_string_normalization(); + static const char reffile[] = "test_archive_string_conversion.txt.Z"; + static const char testdata[] = "testdata.txt"; + struct archive *a; + struct archive_entry *ae; + char buff[512]; + ssize_t size; + FILE *fp; + + /* + * Extract a test pattern file. + */ + extract_reference_file(reffile); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_raw(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, reffile, 512)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assert((fp = fopen(testdata, "w")) != NULL); + while ((size = archive_read_data(a, buff, 512)) > 0) + fwrite(buff, 1, size, fp); + fclose(fp); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + + test_archive_string_normalization_nfc(testdata); + test_archive_string_normalization_mac_nfd(testdata); test_archive_string_canonicalization(); } diff --git a/contrib/libarchive/libarchive/test/test_compat_zip.c b/contrib/libarchive/libarchive/test/test_compat_zip.c index 9785d42..3ebf28c 100644 --- a/contrib/libarchive/libarchive/test/test_compat_zip.c +++ b/contrib/libarchive/libarchive/test/test_compat_zip.c @@ -238,19 +238,19 @@ test_compat_zip_5(void) assertEqualString("Metadata/Job_PT.xml", archive_entry_pathname(ae)); assertEqualInt(3559, archive_entry_size(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); - assertEqualInt(0777, archive_entry_perm(ae)); + assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Metadata/MXDC_Empty_PT.xml", archive_entry_pathname(ae)); assertEqualInt(456, archive_entry_size(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); - assertEqualInt(0777, archive_entry_perm(ae)); + assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Metadata/Page1_Thumbnail.JPG", archive_entry_pathname(ae)); assertEqualInt(1495, archive_entry_size(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); - assertEqualInt(0777, archive_entry_perm(ae)); + assertEqualInt(0666, archive_entry_perm(ae)); /* TODO: Read some of the file data and verify it. The code to read uncompressed Zip entries with "file at end" semantics is tricky and should be verified more carefully. */ @@ -298,21 +298,21 @@ test_compat_zip_5(void) assertEqualInt(0, archive_entry_size(ae)); assert(!archive_entry_size_is_set(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); - assertEqualInt(0777, archive_entry_perm(ae)); + assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Metadata/MXDC_Empty_PT.xml", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_size(ae)); assert(!archive_entry_size_is_set(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); - assertEqualInt(0777, archive_entry_perm(ae)); + assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Metadata/Page1_Thumbnail.JPG", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_size(ae)); assert(!archive_entry_size_is_set(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); - assertEqualInt(0777, archive_entry_perm(ae)); + assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Pages/_rels/1.fpage.rels", archive_entry_pathname(ae)); @@ -420,7 +420,7 @@ test_compat_zip_7(void) for (i = 1; i < 1000; ++i) { assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); - assertEqualIntA(a, ARCHIVE_OK, read_open_memory2(a, p, s, i)); + assertEqualIntA(a, ARCHIVE_OK, read_open_memory_minimal(a, p, s, i)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a)); diff --git a/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c b/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c index 6741ee1..3ecfbc2 100644 --- a/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c +++ b/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2010 Michihiro NAKAJIMA + * Copyright (c) 2010-2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,6 +66,9 @@ test_basic(void) size_t size; int64_t offset; int file_count; +#if defined(_WIN32) && !defined(__CYGWIN__) + wchar_t *wcwd, *wp, *fullpath; +#endif assertMakeDir("dir1", 0755); assertMakeFile("dir1/file1", 0644, "0123456789"); @@ -89,6 +92,7 @@ test_basic(void) assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); if (strcmp(archive_entry_pathname(ae), "dir1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/file1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -102,6 +106,7 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/file2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -115,9 +120,11 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 11); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub1/file1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -131,9 +138,11 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub2/file1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -147,6 +156,7 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub2/file2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -160,15 +170,19 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub2/sub1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub2/sub2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub2/sub3") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (strcmp(archive_entry_pathname(ae), "dir1/sub2/sub3/file") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -182,6 +196,7 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 3); + assertEqualInt(0, archive_read_disk_can_descend(a)); } if (archive_entry_filetype(ae) == AE_IFDIR) { /* Descend into the current object */ @@ -205,6 +220,7 @@ test_basic(void) assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); if (wcscmp(archive_entry_pathname_w(ae), L"dir1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/file1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -218,6 +234,7 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/file2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -231,9 +248,11 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 11); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub1/file1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -247,9 +266,11 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub2/file1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -263,6 +284,7 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub2/file2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -276,15 +298,19 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 10); + assertEqualInt(0, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub2/sub1") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub2/sub2") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub2/sub3") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + assertEqualInt(1, archive_read_disk_can_descend(a)); } else if (wcscmp(archive_entry_pathname_w(ae), L"dir1/sub2/sub3/file") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFREG); @@ -298,6 +324,7 @@ test_basic(void) archive_read_data_block(a, &p, &size, &offset)); assertEqualInt((int)size, 0); assertEqualInt((int)offset, 3); + assertEqualInt(0, archive_read_disk_can_descend(a)); } if (archive_entry_filetype(ae) == AE_IFDIR) { /* Descend into the current object */ @@ -318,6 +345,7 @@ test_basic(void) /* dir1/file1 */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(0, archive_read_disk_can_descend(a)); assertEqualString(archive_entry_pathname(ae), "dir1/file1"); assertEqualInt(archive_entry_filetype(ae), AE_IFREG); assertEqualInt(archive_entry_size(ae), 10); @@ -342,6 +370,7 @@ test_basic(void) /* dir1/file1 */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(0, archive_read_disk_can_descend(a)); assertEqualString(archive_entry_pathname(ae), "dir1/file1"); assertEqualInt(archive_entry_filetype(ae), AE_IFREG); assertEqualInt(archive_entry_size(ae), 10); @@ -353,6 +382,7 @@ test_basic(void) /* dir1/sub1 */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(1, archive_read_disk_can_descend(a)); assertEqualString(archive_entry_pathname(ae), "dir1/sub1"); assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); @@ -361,6 +391,7 @@ test_basic(void) /* dir1/sub1/file1 */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(0, archive_read_disk_can_descend(a)); assertEqualString(archive_entry_pathname(ae), "dir1/sub1/file1"); assertEqualInt(archive_entry_filetype(ae), AE_IFREG); assertEqualInt(archive_entry_size(ae), 10); @@ -375,6 +406,96 @@ test_basic(void) /* Close the disk object. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + /* + * Test for a full-path beginning with "//?/" + */ + wcwd = _wgetcwd(NULL, 0); + fullpath = malloc(sizeof(wchar_t) * (wcslen(wcwd) + 32)); + wcscpy(fullpath, L"//?/"); + wcscat(fullpath, wcwd); + wcscat(fullpath, L"/dir1/file1"); + free(wcwd); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, fullpath)); + while ((wcwd = wcschr(fullpath, L'\\')) != NULL) + *wcwd = L'/'; + + /* dir1/file1 */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(0, archive_read_disk_can_descend(a)); + assertEqualWString(archive_entry_pathname_w(ae), fullpath); + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + + /* There is no entry. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + free(fullpath); + + /* + * Test for wild card '*' or '?' with "//?/" prefix. + */ + wcwd = _wgetcwd(NULL, 0); + fullpath = malloc(sizeof(wchar_t) * (wcslen(wcwd) + 32)); + wcscpy(fullpath, L"//?/"); + wcscat(fullpath, wcwd); + wcscat(fullpath, L"/dir1/*1"); + free(wcwd); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, fullpath)); + while ((wcwd = wcschr(fullpath, L'\\')) != NULL) + *wcwd = L'/'; + + /* dir1/file1 */ + wp = wcsrchr(fullpath, L'/'); + wcscpy(wp+1, L"file1"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(0, archive_read_disk_can_descend(a)); + assertEqualWString(archive_entry_pathname_w(ae), fullpath); + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + + /* dir1/sub1 */ + wcscpy(wp+1, L"sub1"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(1, archive_read_disk_can_descend(a)); + assertEqualWString(archive_entry_pathname_w(ae), fullpath); + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a)); + + /* dir1/sub1/file1 */ + wcscpy(wp+1, L"sub1/file1"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + assertEqualInt(0, archive_read_disk_can_descend(a)); + assertEqualWString(archive_entry_pathname_w(ae), fullpath); + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + + /* There is no entry. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + free(fullpath); + #endif /* @@ -969,11 +1090,13 @@ test_restore_atime(void) failure("There must be no entry"); assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); - failure("Atime must not be restored"); + failure("Atime should be restored"); assertFileAtimeRecent("at"); + failure("Atime should be restored"); assertFileAtimeRecent("at/f1"); + failure("Atime should be restored"); assertFileAtimeRecent("at/f2"); - failure("The atime of a empty file must not be changed"); + failure("The atime of a empty file should not be changed"); assertFileAtime("at/fe", 886611, 0); /* Close the disk object. */ @@ -1033,13 +1156,403 @@ test_restore_atime(void) failure("There must be no entry"); assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); - failure("Atime must be restored"); + failure("Atime should be restored"); assertFileAtime("at", 886622, 0); + failure("Atime should be restored"); assertFileAtime("at/f1", 886600, 0); + failure("Atime should be restored"); assertFileAtime("at/f2", 886611, 0); - failure("The atime of a empty file must not be changed"); + failure("The atime of a empty file should not be changed"); assertFileAtime("at/fe", 886611, 0); + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + /* + * Test3: Traversals with archive_read_disk_set_atime_restored() but + * no data read as a listing. + */ + assertUtimes("at/f1", 886600, 0, 886600, 0); + assertUtimes("at/f2", 886611, 0, 886611, 0); + assertUtimes("at/fe", 886611, 0, 886611, 0); + assertUtimes("at", 886622, 0, 886622, 0); + file_count = 4; + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_atime_restored(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at")); + + failure("Directory traversals should work as well"); + while (file_count--) { + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + if (strcmp(archive_entry_pathname(ae), "at") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + } else if (strcmp(archive_entry_pathname(ae), "at/f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + } else if (strcmp(archive_entry_pathname(ae), "at/f2") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 11); + } else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 0); + } + if (archive_entry_filetype(ae) == AE_IFDIR) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + /* There is no entry. */ + failure("There must be no entry"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + failure("Atime should be restored"); + assertFileAtime("at", 886622, 0); + failure("Atime should be restored"); + assertFileAtime("at/f1", 886600, 0); + failure("Atime should be restored"); + assertFileAtime("at/f2", 886611, 0); + failure("The atime of a empty file should not be changed"); + assertFileAtime("at/fe", 886611, 0); + + if (!canNodump()) { + /* Destroy the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + archive_entry_free(ae); + skipping("Can't test atime with nodump on this filesystem"); + return; + } + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + /* + * Test4: Traversals with archive_read_disk_set_atime_restored() and + * archive_read_disk_honor_nodump(). + */ + assertNodump("at/f1"); + assertNodump("at/f2"); + assertUtimes("at/f1", 886600, 0, 886600, 0); + assertUtimes("at/f2", 886611, 0, 886611, 0); + assertUtimes("at/fe", 886611, 0, 886611, 0); + assertUtimes("at", 886622, 0, 886622, 0); + file_count = 2; + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a, + ARCHIVE_READDISK_RESTORE_ATIME | ARCHIVE_READDISK_HONOR_NODUMP)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at")); + + failure("Directory traversals should work as well"); + while (file_count--) { + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + if (strcmp(archive_entry_pathname(ae), "at") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + } else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 0); + } + if (archive_entry_filetype(ae) == AE_IFDIR) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + /* There is no entry. */ + failure("There must be no entry"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + failure("Atime should be restored"); + assertFileAtime("at", 886622, 0); + failure("Atime should be restored"); + assertFileAtime("at/f1", 886600, 0); + failure("Atime should be restored"); + assertFileAtime("at/f2", 886611, 0); + failure("The atime of a empty file should not be changed"); + assertFileAtime("at/fe", 886611, 0); + + /* Destroy the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + archive_entry_free(ae); +} + +static int +metadata_filter(struct archive *a, void *data, struct archive_entry *ae) +{ + (void)data; /* UNUSED */ + + failure("CTime should be set"); + assertEqualInt(8, archive_entry_ctime_is_set(ae)); + failure("MTime should be set"); + assertEqualInt(16, archive_entry_mtime_is_set(ae)); + + if (archive_entry_mtime(ae) < 886611) + return (0); + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + failure("archive_read_disk_can_descend should work" + " in metadata filter"); + assertEqualIntA(a, 1, archive_read_disk_can_descend(a)); + failure("archive_read_disk_descend should work" + " in metadata filter"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a)); + } + return (1); +} + +static void +test_callbacks(void) +{ + struct archive *a; + struct archive *m; + struct archive_entry *ae; + const void *p; + size_t size; + int64_t offset; + int file_count; + + assertMakeDir("cb", 0755); + assertMakeFile("cb/f1", 0644, "0123456789"); + assertMakeFile("cb/f2", 0644, "hello world"); + assertMakeFile("cb/fe", 0644, NULL); + assertUtimes("cb/f1", 886600, 0, 886600, 0); + assertUtimes("cb/f2", 886611, 0, 886611, 0); + assertUtimes("cb/fe", 886611, 0, 886611, 0); + assertUtimes("cb", 886622, 0, 886622, 0); + + assert((ae = archive_entry_new()) != NULL); + if (assert((a = archive_read_disk_new()) != NULL)) { + archive_entry_free(ae); + return; + } + if (assert((m = archive_match_new()) != NULL)) { + archive_entry_free(ae); + archive_read_free(a); + return; + } + + /* + * Test1: Traversals with a name filter. + */ + file_count = 3; + assertEqualIntA(m, ARCHIVE_OK, + archive_match_exclude_pattern(m, "cb/f2")); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_set_matching(a, m, NULL, NULL)); + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "cb")); + while (file_count--) { + archive_entry_clear(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + failure("File 'cb/f2' should be exclueded"); + assert(strcmp(archive_entry_pathname(ae), "cb/f2") != 0); + if (strcmp(archive_entry_pathname(ae), "cb") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + } else if (strcmp(archive_entry_pathname(ae), "cb/f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 10); + } else if (strcmp(archive_entry_pathname(ae), "cb/fe") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 0); + } + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + /* There is no entry. */ + failure("There should be no entry"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + /* + * Test2: Traversals with a metadata filter. + */ + assertUtimes("cb/f1", 886600, 0, 886600, 0); + assertUtimes("cb/f2", 886611, 0, 886611, 0); + assertUtimes("cb/fe", 886611, 0, 886611, 0); + assertUtimes("cb", 886622, 0, 886622, 0); + file_count = 3; + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_set_metadata_filter_callback(a, metadata_filter, + NULL)); + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "cb")); + + while (file_count--) { + archive_entry_clear(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + failure("File 'cb/f1' should be exclueded"); + assert(strcmp(archive_entry_pathname(ae), "cb/f1") != 0); + if (strcmp(archive_entry_pathname(ae), "cb") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + } else if (strcmp(archive_entry_pathname(ae), "cb/f2") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 11); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 11); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "hello world", 11); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 11); + } else if (strcmp(archive_entry_pathname(ae), "cb/fe") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 0); + } + } + /* There is no entry. */ + failure("There should be no entry"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Destroy the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + assertEqualInt(ARCHIVE_OK, archive_match_free(m)); + archive_entry_free(ae); +} + +static void +test_nodump(void) +{ + struct archive *a; + struct archive_entry *ae; + const void *p; + size_t size; + int64_t offset; + int file_count; + + if (!canNodump()) { + skipping("Can't test nodump on this filesystem"); + return; + } + + assertMakeDir("nd", 0755); + assertMakeFile("nd/f1", 0644, "0123456789"); + assertMakeFile("nd/f2", 0644, "hello world"); + assertMakeFile("nd/fe", 0644, NULL); + assertNodump("nd/f2"); + assertUtimes("nd/f1", 886600, 0, 886600, 0); + assertUtimes("nd/f2", 886611, 0, 886611, 0); + assertUtimes("nd/fe", 886611, 0, 886611, 0); + assertUtimes("nd", 886622, 0, 886622, 0); + + assert((ae = archive_entry_new()) != NULL); + assert((a = archive_read_disk_new()) != NULL); + + /* + * Test1: Traversals without archive_read_disk_honor_nodump(). + */ + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd")); + + file_count = 4; + while (file_count--) { + archive_entry_clear(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + if (strcmp(archive_entry_pathname(ae), "nd") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + } else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 10); + } else if (strcmp(archive_entry_pathname(ae), "nd/f2") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 11); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 11); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "hello world", 11); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 11); + } else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 0); + } + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + /* There is no entry. */ + failure("There should be no entry"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + /* + * Test2: Traversals with archive_read_disk_honor_nodump(). + */ + assertUtimes("nd/f1", 886600, 0, 886600, 0); + assertUtimes("nd/f2", 886611, 0, 886611, 0); + assertUtimes("nd/fe", 886611, 0, 886611, 0); + assertUtimes("nd", 886622, 0, 886622, 0); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a, + ARCHIVE_READDISK_RESTORE_ATIME | ARCHIVE_READDISK_HONOR_NODUMP)); + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd")); + + file_count = 3; + while (file_count--) { + archive_entry_clear(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + failure("File 'nd/f2' should be exclueded"); + assert(strcmp(archive_entry_pathname(ae), "nd/f2") != 0); + if (strcmp(archive_entry_pathname(ae), "nd") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + } else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 10); + } else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 0); + } + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + /* There is no entry. */ + failure("There should be no entry"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + failure("Atime should be restored"); + assertFileAtime("nd/f2", 886611, 0); + /* Destroy the disk object. */ assertEqualInt(ARCHIVE_OK, archive_read_free(a)); archive_entry_free(ae); @@ -1057,4 +1570,8 @@ DEFINE_TEST(test_read_disk_directory_traversals) test_symlink_logical_loop(); /* Test to restore atime. */ test_restore_atime(); + /* Test callbacks. */ + test_callbacks(); + /* Test nodump. */ + test_nodump(); } diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip.c b/contrib/libarchive/libarchive/test/test_read_format_7zip.c index a4cc555..043ef9f 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_7zip.c +++ b/contrib/libarchive/libarchive/test/test_read_format_7zip.c @@ -26,8 +26,8 @@ __FBSDID("$FreeBSD"); /* - * Extract a non-encorded file. - * The header of the 7z archive files is not encdoed. + * Extract a non-encoded file. + * The header of the 7z archive files is not encoded. */ static void test_copy() @@ -46,7 +46,7 @@ test_copy() /* Verify regular file1. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assertEqualInt((AE_IFREG | 0777), archive_entry_mode(ae)); + assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); assertEqualString("file1", archive_entry_pathname(ae)); assertEqualInt(86401, archive_entry_mtime(ae)); assertEqualInt(60, archive_entry_size(ae)); @@ -139,7 +139,7 @@ test_empty_file() /* * Extract an encoded file. - * The header of the 7z archive files is not encdoed. + * The header of the 7z archive files is not encoded. */ static void test_plain_header(const char *refname) @@ -180,7 +180,7 @@ test_plain_header(const char *refname) /* * Extract multi files. - * The header of the 7z archive files is encdoed with LZMA. + * The header of the 7z archive files is encoded with LZMA. */ static void test_extract_all_files(const char *refname) @@ -255,7 +255,7 @@ test_extract_all_files(const char *refname) /* * Extract last file. - * The header of the 7z archive files is encdoed with LZMA. + * The header of the 7z archive files is encoded with LZMA. */ static void test_extract_last_file(const char *refname) @@ -323,7 +323,7 @@ test_extract_last_file(const char *refname) } /* - * Extract a mixed archive file which has both LZMA and LZMA2 encoded files. + * Extract a mixed archive file which has both LZMA and LZMA2 encoded files. * LZMA: file1, file2, file3, file4 * LZMA2: zfile1, zfile2, zfile3, zfile4 */ @@ -510,7 +510,7 @@ test_bcj(const char *refname) /* Verify regular x86exe. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assertEqualInt((AE_IFREG | 0555), archive_entry_mode(ae)); + assertEqualInt((AE_IFREG | 0444), archive_entry_mode(ae) & ~0111); assertEqualString("x86exe", archive_entry_pathname(ae)); assertEqualInt(172802, archive_entry_mtime(ae)); assertEqualInt(27328, archive_entry_size(ae)); @@ -565,7 +565,7 @@ test_ppmd() /* Verify regular file1. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assertEqualInt((AE_IFREG | 0777), archive_entry_mode(ae)); + assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); assertEqualString("ppmd_test.txt", archive_entry_pathname(ae)); assertEqualInt(1322464589, archive_entry_mtime(ae)); assertEqualInt(102400, archive_entry_size(ae)); diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab.c b/contrib/libarchive/libarchive/test/test_read_format_cab.c index 4e8607e..004d6e8 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_cab.c +++ b/contrib/libarchive/libarchive/test/test_read_format_cab.c @@ -199,7 +199,7 @@ verify(const char *refname, enum comp_type comp) /* Verify regular empty. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assertEqualInt((AE_IFREG | 0777), archive_entry_mode(ae)); + assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); assertEqualString("empty", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_uid(ae)); assertEqualInt(0, archive_entry_gid(ae)); @@ -211,7 +211,7 @@ verify(const char *refname, enum comp_type comp) * file to check if we properly handle multiple CFDATA. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assertEqualInt((AE_IFREG | 0777), archive_entry_mode(ae)); + assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); assertEqualString("zero", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_uid(ae)); assertEqualInt(0, archive_entry_gid(ae)); @@ -232,7 +232,7 @@ verify(const char *refname, enum comp_type comp) /* Verify regular file1. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assertEqualInt((AE_IFREG | 0777), archive_entry_mode(ae)); + assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); assertEqualString("dir1/file1", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_uid(ae)); assertEqualInt(0, archive_entry_gid(ae)); @@ -242,7 +242,7 @@ verify(const char *refname, enum comp_type comp) /* Verify regular file2. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); - assertEqualInt((AE_IFREG | 0777), archive_entry_mode(ae)); + assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); assertEqualString("dir2/file2", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_uid(ae)); assertEqualInt(0, archive_entry_gid(ae)); @@ -269,13 +269,121 @@ finish: assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } +/* + * Skip beginning files and Read the last file. + */ +static void +verify2(const char *refname, enum comp_type comp) +{ + struct archive_entry *ae; + struct archive *a; + char buff[128]; + char zero[128]; + + memset(zero, 0, sizeof(zero)); + extract_reference_file(refname); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + /* Verify regular empty. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + if (comp != STORE) { + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + } + /* Verify regular file1. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + + /* Verify regular file2. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); + assertEqualString("dir2/file2", archive_entry_pathname(ae)); + assertEqualInt(0, archive_entry_uid(ae)); + assertEqualInt(0, archive_entry_gid(ae)); + assertEqualInt(file2_size, archive_entry_size(ae)); + assertEqualInt(file2_size, archive_read_data(a, buff, file2_size)); + assertEqualMem(buff, file2, file2_size); + + /* End of archive. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + if (comp != STORE) { + assertEqualInt(4, archive_file_count(a)); + } else { + assertEqualInt(3, archive_file_count(a)); + } + + /* Verify archive format. */ + assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a)); + assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a)); + + /* Close the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +/* + * Skip all file like 'bsdtar tvf foo.cab'. + */ +static void +verify3(const char *refname, enum comp_type comp) +{ + struct archive_entry *ae; + struct archive *a; + char zero[128]; + + memset(zero, 0, sizeof(zero)); + extract_reference_file(refname); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + /* Verify regular empty. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + if (comp != STORE) { + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + } + /* Verify regular file1. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + + /* Verify regular file2. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + + /* End of archive. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + if (comp != STORE) { + assertEqualInt(4, archive_file_count(a)); + } else { + assertEqualInt(3, archive_file_count(a)); + } + + /* Verify archive format. */ + assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a)); + assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a)); + + /* Close the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + DEFINE_TEST(test_read_format_cab) { /* Verify Cabinet file in no compression. */ verify("test_read_format_cab_1.cab", STORE); + verify2("test_read_format_cab_1.cab", STORE); + verify3("test_read_format_cab_1.cab", STORE); /* Verify Cabinet file in MSZIP. */ verify("test_read_format_cab_2.cab", MSZIP); + verify2("test_read_format_cab_2.cab", MSZIP); + verify3("test_read_format_cab_2.cab", MSZIP); /* Verify Cabinet file in LZX. */ verify("test_read_format_cab_3.cab", LZX); + verify2("test_read_format_cab_3.cab", LZX); + verify3("test_read_format_cab_3.cab", LZX); } diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c index f0d27a3..b354b8c 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c +++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c @@ -51,7 +51,7 @@ Name: ${NAME} Version: 1.0.0 Release: 1 License: BSD -URL: http://code.google.com/p/libarchive +URL: http://libarchive.github.com/ BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-root diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c index 338a088..582096b 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c +++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c @@ -51,7 +51,7 @@ Name: ${NAME} Version: 1.0.0 Release: 1 License: BSD -URL: http://code.google.com/p/libarchive +URL: http://libarchive.github.com/ BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-root diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar.c b/contrib/libarchive/libarchive/test/test_read_format_rar.c index 8a73a78..a7c61f9 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_rar.c +++ b/contrib/libarchive/libarchive/test/test_read_format_rar.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2011 Andres Mejia + * Copyright (c) 2011-2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -278,9 +279,19 @@ test_unicode_UTF8(void) assertEqualInt(41453, archive_entry_mode(ae)); assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff))); + /* Sixth header */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualUTF8String( + "abcdefghijklmnopqrs\xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88.txt", + archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertEqualInt(16, archive_entry_size(ae)); + assertEqualInt(33204, archive_entry_mode(ae)); + assertEqualIntA(a, 16, archive_read_data(a, buff, sizeof(buff))); + /* Test EOF */ assertA(1 == archive_read_next_header(a, &ae)); - assertEqualInt(5, archive_file_count(a)); + assertEqualInt(6, archive_file_count(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } @@ -364,9 +375,19 @@ test_unicode_CP932(void) assertEqualInt(41453, archive_entry_mode(ae)); assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff))); + /* Sixth header */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualUTF8String( + "abcdefghijklmnopqrs\x83\x65\x83\x58\x83\x67.txt", + archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertEqualInt(16, archive_entry_size(ae)); + assertEqualInt(33204, archive_entry_mode(ae)); + assertEqualIntA(a, 16, archive_read_data(a, buff, sizeof(buff))); + /* Test EOF */ assertA(1 == archive_read_next_header(a, &ae)); - assertEqualInt(5, archive_file_count(a)); + assertEqualInt(6, archive_file_count(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar_unicode.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar_unicode.rar.uu index cfe6e40..8469e99 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_rar_unicode.rar.uu +++ b/contrib/libarchive/libarchive/test/test_read_format_rar_unicode.rar.uu @@ -11,7 +11,8 @@ M5H*U@J*#=(-(@XN#7P"(:&A@,(@P7*JP95<P1##5,*BI,.LPP#``\"8YA&UX M=."2,P````````````(`````#VGA/A0P#@`0````E5R"OH+F`(AH:&`PB#`` M\.H)?ED.="""2``V````-@````,E@OM=6%0+/Q0P*`#MH0``Z*&HXX&@XX*( M7..#E>."H>."I..#JP"(:&A@,(@P7*K5,*$PI##K,.:\HN6ME^F5M^.!A..# -ME>."H>."I..#J^60C6QO;F<M9FEL96YA;64M:6XMYKRBY:V7+G1X=,0]>P!` -"!P`` +ME>."H>."I..#J^60C6QO;F<M9FEL96YA;64M:6XMYKRBY:V7+G1X=)MJ=""` +M0``/````$`````,%T+85W81G0!TS(`"T@0``86)C9&5F9VAI:FML;6YO<'%R +D<^.#AN."N>.#B"YT>'0`D/\0?^2Y_">#,#TN'-+$/7L`0`<` ` end diff --git a/contrib/libarchive/libarchive/test/test_read_format_tar_filename.c b/contrib/libarchive/libarchive/test/test_read_format_tar_filename.c index abec4ec..ee2bf81 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_tar_filename.c +++ b/contrib/libarchive/libarchive/test/test_read_format_tar_filename.c @@ -34,7 +34,7 @@ __FBSDID("$FreeBSD"); * - the filename of second file is stored in UTF-8. * * Whenever hdrcharset option is specified, we will correctly read the - * filename of sencod file, which is stored in UTF-8 by default. + * filename of second file, which is stored in UTF-8 by default. */ static void diff --git a/contrib/libarchive/libarchive/test/test_read_pax_truncated.c b/contrib/libarchive/libarchive/test/test_read_pax_truncated.c index 0c36bb4..8c61f26 100644 --- a/contrib/libarchive/libarchive/test/test_read_pax_truncated.c +++ b/contrib/libarchive/libarchive/test/test_read_pax_truncated.c @@ -71,10 +71,10 @@ DEFINE_TEST(test_read_pax_truncated) assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); /* If it's truncated very early, the file type detection should fail. */ if (i < 512) { - assertEqualIntA(a, ARCHIVE_FATAL, read_open_memory2(a, buff, i, 13)); + assertEqualIntA(a, ARCHIVE_FATAL, read_open_memory_minimal(a, buff, i, 13)); goto wrap_up; } else { - assertEqualIntA(a, ARCHIVE_OK, read_open_memory2(a, buff, i, 13)); + assertEqualIntA(a, ARCHIVE_OK, read_open_memory_minimal(a, buff, i, 13)); } /* If it's truncated in a header, the header read should fail. */ diff --git a/contrib/libarchive/libarchive/test/test_read_position.c b/contrib/libarchive/libarchive/test/test_read_position.c index 69e4796..5e7f05f 100644 --- a/contrib/libarchive/libarchive/test/test_read_position.c +++ b/contrib/libarchive/libarchive/test/test_read_position.c @@ -105,7 +105,7 @@ DEFINE_TEST(test_read_position) /* Read the archive back without a skip function. */ assert(NULL != (a = archive_read_new())); assertA(0 == archive_read_support_format_tar(a)); - assertA(0 == read_open_memory2(a, buff, sizeof(buff), 512)); + assertA(0 == read_open_memory_minimal(a, buff, sizeof(buff), 512)); verify_read_positions(a); archive_read_free(a); diff --git a/contrib/libarchive/libarchive/test/test_sparse_basic.c b/contrib/libarchive/libarchive/test/test_sparse_basic.c index 1d62e7c..d564f0c 100644 --- a/contrib/libarchive/libarchive/test/test_sparse_basic.c +++ b/contrib/libarchive/libarchive/test/test_sparse_basic.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2010 Michihiro NAKAJIMA + * Copyright (c) 2010-2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,9 +31,6 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif -#ifdef HAVE_SYS_UTSNAME_H -#include <sys/utsname.h> -#endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif @@ -169,31 +166,12 @@ is_sparse_supported(const char *path) { HOLE, 1024 }, { DATA, 10240 }, { END, 0 } }; - struct utsname ut; - char *p, *e; - long d; int fd, r; struct fiemap *fm; char buff[1024]; const char *testfile = "can_sparse"; (void)path; /* UNUSED */ - memset(&ut, 0, sizeof(ut)); - assertEqualInt(uname(&ut), 0); - p = ut.release; - d = strtol(p, &e, 10); - if (d < 2 || *e != '.') - return (0); - if (d == 2) { - p = e + 1; - d = strtol(p, &e, 10); - if (d < 6 || *e != '.') - return (0); - p = e + 1; - d = strtol(p, NULL, 10); - if (d < 28) - return (0); - } create_sparse_file(testfile, sparse_file); fd = open(testfile, O_RDWR); if (fd < 0) @@ -205,11 +183,9 @@ is_sparse_supported(const char *path) fm->fm_extent_count = (sizeof(buff) - sizeof(*fm))/ sizeof(struct fiemap_extent); r = ioctl(fd, FS_IOC_FIEMAP, fm); - if (r < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) - return (0);/* Not supported. */ close(fd); unlink(testfile); - return (1); + return (r >= 0); } #else diff --git a/contrib/libarchive/libarchive/test/test_write_format_zip.c b/contrib/libarchive/libarchive/test/test_write_format_zip.c index d9bfe5d..76f88f7 100644 --- a/contrib/libarchive/libarchive/test/test_write_format_zip.c +++ b/contrib/libarchive/libarchive/test/test_write_format_zip.c @@ -91,7 +91,7 @@ verify_contents(struct archive *a, int expect_details) assertEqualInt(0, archive_entry_size(ae)); assertEqualString("file1", archive_entry_symlink(ae)); } else { - assertEqualInt(AE_IFREG | 0777, archive_entry_mode(ae)); + assertEqualInt(AE_IFREG | 0666, archive_entry_mode(ae)); assertEqualInt(0, archive_entry_size(ae)); } diff --git a/contrib/libarchive/libarchive_fe/err.c b/contrib/libarchive/libarchive_fe/err.c index eb3f9f3..a017398 100644 --- a/contrib/libarchive/libarchive_fe/err.c +++ b/contrib/libarchive/libarchive_fe/err.c @@ -40,6 +40,8 @@ __FBSDID("$FreeBSD$"); #include "err.h" +static void lafe_vwarnc(int, const char *, va_list) __LA_PRINTFLIKE(2, 0); + const char *lafe_progname; static void diff --git a/contrib/libarchive/libarchive_fe/err.h b/contrib/libarchive/libarchive_fe/err.h index 4812b28..86f9f5b 100644 --- a/contrib/libarchive/libarchive_fe/err.h +++ b/contrib/libarchive/libarchive_fe/err.h @@ -35,9 +35,17 @@ #define __LA_DEAD #endif +#if defined(__GNUC__) && (__GNUC__ > 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) +#define __LA_PRINTFLIKE(f,a) __attribute__((__format__(__printf__, f, a))) +#else +#define __LA_PRINTFLIKE(f,a) +#endif + extern const char *lafe_progname; -void lafe_warnc(int code, const char *fmt, ...); -void lafe_errc(int eval, int code, const char *fmt, ...) __LA_DEAD; +void lafe_warnc(int code, const char *fmt, ...) __LA_PRINTFLIKE(2, 3); +void lafe_errc(int eval, int code, const char *fmt, ...) __LA_DEAD + __LA_PRINTFLIKE(3, 4); #endif diff --git a/contrib/libarchive/libarchive_fe/matching.c b/contrib/libarchive/libarchive_fe/matching.c deleted file mode 100644 index 5a4834c..0000000 --- a/contrib/libarchive/libarchive_fe/matching.c +++ /dev/null @@ -1,281 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "lafe_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include "err.h" -#include "line_reader.h" -#include "matching.h" -#include "pathmatch.h" - -struct match { - struct match *next; - int matches; - char pattern[1]; -}; - -struct lafe_matching { - struct match *exclusions; - int exclusions_count; - struct match *inclusions; - int inclusions_count; - int inclusions_unmatched_count; -}; - -static void add_pattern(struct match **list, const char *pattern); -static void initialize_matching(struct lafe_matching **); -static int match_exclusion(struct match *, const char *pathname); -static int match_inclusion(struct match *, const char *pathname); - -/* - * The matching logic here needs to be re-thought. I started out to - * try to mimic gtar's matching logic, but it's not entirely - * consistent. In particular 'tar -t' and 'tar -x' interpret patterns - * on the command line as anchored, but --exclude doesn't. - */ - -/* - * Utility functions to manage exclusion/inclusion patterns - */ - -int -lafe_exclude(struct lafe_matching **matching, const char *pattern) -{ - - if (*matching == NULL) - initialize_matching(matching); - add_pattern(&((*matching)->exclusions), pattern); - (*matching)->exclusions_count++; - return (0); -} - -int -lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname) -{ - struct lafe_line_reader *lr; - const char *p; - int ret = 0; - - lr = lafe_line_reader(pathname, 0); - while ((p = lafe_line_reader_next(lr)) != NULL) { - if (lafe_exclude(matching, p) != 0) - ret = -1; - } - lafe_line_reader_free(lr); - return (ret); -} - -int -lafe_include(struct lafe_matching **matching, const char *pattern) -{ - - if (*matching == NULL) - initialize_matching(matching); - add_pattern(&((*matching)->inclusions), pattern); - (*matching)->inclusions_count++; - (*matching)->inclusions_unmatched_count++; - return (0); -} - -int -lafe_include_from_file(struct lafe_matching **matching, const char *pathname, - int nullSeparator) -{ - struct lafe_line_reader *lr; - const char *p; - int ret = 0; - - lr = lafe_line_reader(pathname, nullSeparator); - while ((p = lafe_line_reader_next(lr)) != NULL) { - if (lafe_include(matching, p) != 0) - ret = -1; - } - lafe_line_reader_free(lr); - return (ret); -} - -static void -add_pattern(struct match **list, const char *pattern) -{ - struct match *match; - size_t len; - - len = strlen(pattern); - match = malloc(sizeof(*match) + len + 1); - if (match == NULL) - lafe_errc(1, errno, "Out of memory"); - strcpy(match->pattern, pattern); - /* Both "foo/" and "foo" should match "foo/bar". */ - if (len && match->pattern[len - 1] == '/') - match->pattern[len - 1] = '\0'; - match->next = *list; - *list = match; - match->matches = 0; -} - - -int -lafe_excluded(struct lafe_matching *matching, const char *pathname) -{ - struct match *match; - struct match *matched; - - if (matching == NULL) - return (0); - - /* Mark off any unmatched inclusions. */ - /* In particular, if a filename does appear in the archive and - * is explicitly included and excluded, then we don't report - * it as missing even though we don't extract it. - */ - matched = NULL; - for (match = matching->inclusions; match != NULL; match = match->next){ - if (match->matches == 0 - && match_inclusion(match, pathname)) { - matching->inclusions_unmatched_count--; - match->matches++; - matched = match; - } - } - - /* Exclusions take priority */ - for (match = matching->exclusions; match != NULL; match = match->next){ - if (match_exclusion(match, pathname)) - return (1); - } - - /* It's not excluded and we found an inclusion above, so it's included. */ - if (matched != NULL) - return (0); - - - /* We didn't find an unmatched inclusion, check the remaining ones. */ - for (match = matching->inclusions; match != NULL; match = match->next){ - /* We looked at previously-unmatched inclusions already. */ - if (match->matches > 0 - && match_inclusion(match, pathname)) { - match->matches++; - return (0); - } - } - - /* If there were inclusions, default is to exclude. */ - if (matching->inclusions != NULL) - return (1); - - /* No explicit inclusions, default is to match. */ - return (0); -} - -/* - * This is a little odd, but it matches the default behavior of - * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' - * - */ -static int -match_exclusion(struct match *match, const char *pathname) -{ - return (lafe_pathmatch(match->pattern, - pathname, - PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END)); -} - -/* - * Again, mimic gtar: inclusions are always anchored (have to match - * the beginning of the path) even though exclusions are not anchored. - */ -static int -match_inclusion(struct match *match, const char *pathname) -{ - return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END)); -} - -void -lafe_cleanup_exclusions(struct lafe_matching **matching) -{ - struct match *p, *q; - - if (*matching == NULL) - return; - - for (p = (*matching)->inclusions; p != NULL; ) { - q = p; - p = p->next; - free(q); - } - - for (p = (*matching)->exclusions; p != NULL; ) { - q = p; - p = p->next; - free(q); - } - - free(*matching); - *matching = NULL; -} - -static void -initialize_matching(struct lafe_matching **matching) -{ - *matching = calloc(sizeof(**matching), 1); - if (*matching == NULL) - lafe_errc(1, errno, "No memory"); -} - -int -lafe_unmatched_inclusions(struct lafe_matching *matching) -{ - - if (matching == NULL) - return (0); - return (matching->inclusions_unmatched_count); -} - -int -lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg) -{ - struct match *p; - - if (matching == NULL) - return (0); - - for (p = matching->inclusions; p != NULL; p = p->next) { - if (p->matches == 0) - lafe_warnc(0, "%s: %s", p->pattern, msg); - } - - return (matching->inclusions_unmatched_count); -} diff --git a/contrib/libarchive/tar/bsdtar.1 b/contrib/libarchive/tar/bsdtar.1 index 4dc7fe2..8298544 100644 --- a/contrib/libarchive/tar/bsdtar.1 +++ b/contrib/libarchive/tar/bsdtar.1 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Oct 12, 2009 +.Dd December 24, 2011 .Dt TAR 1 .Os .Sh NAME diff --git a/contrib/libarchive/tar/bsdtar.c b/contrib/libarchive/tar/bsdtar.c index fa99984..50f9c99 100644 --- a/contrib/libarchive/tar/bsdtar.c +++ b/contrib/libarchive/tar/bsdtar.c @@ -118,9 +118,6 @@ need_report(void) } #endif -/* External function to parse a date/time string */ -time_t get_date(time_t, const char *); - static void long_help(void); static void only_mode(struct bsdtar *, const char *opt, const char *valid); @@ -140,7 +137,6 @@ main(int argc, char **argv) char option_o; char possible_help_request; char buff[16]; - time_t now; /* * Use a pointer for consistency, but stack-allocated storage @@ -192,8 +188,6 @@ main(int argc, char **argv) lafe_progname = *argv; } - time(&now); - #if HAVE_SETLOCALE if (setlocale(LC_ALL, "") == NULL) lafe_warnc(0, "Failed to set default locale"); @@ -241,11 +235,14 @@ main(int argc, char **argv) * Enable Mac OS "copyfile()" extension by default. * This has no effect on other platforms. */ - bsdtar->enable_copyfile = 1; + bsdtar->readdisk_flags |= ARCHIVE_READDISK_MAC_COPYFILE; #ifdef COPYFILE_DISABLE_VAR if (getenv(COPYFILE_DISABLE_VAR)) - bsdtar->enable_copyfile = 0; + bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE; #endif + bsdtar->matching = archive_match_new(); + if (bsdtar->matching == NULL) + lafe_errc(1, errno, "Out of memory"); bsdtar->argv = argv; bsdtar->argc = argc; @@ -287,10 +284,11 @@ main(int argc, char **argv) bsdtar->option_chroot = 1; break; case OPTION_DISABLE_COPYFILE: /* Mac OS X */ - bsdtar->enable_copyfile = 0; + bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE; break; case OPTION_EXCLUDE: /* GNU tar */ - if (lafe_exclude(&bsdtar->matching, bsdtar->argument)) + if (archive_match_exclude_pattern( + bsdtar->matching, bsdtar->argument) != ARCHIVE_OK) lafe_errc(1, 0, "Couldn't exclude %s\n", bsdtar->argument); break; @@ -341,7 +339,8 @@ main(int argc, char **argv) * no one else needs this to filter entries * when transforming archives. */ - if (lafe_include(&bsdtar->matching, bsdtar->argument)) + if (archive_match_include_pattern(bsdtar->matching, + bsdtar->argument) != ARCHIVE_OK) lafe_errc(1, 0, "Failed to add %s to inclusion list", bsdtar->argument); @@ -395,39 +394,35 @@ main(int argc, char **argv) * TODO: Add corresponding "older" options to reverse these. */ case OPTION_NEWER_CTIME: /* GNU tar */ - bsdtar->newer_ctime_filter = 1; - bsdtar->newer_ctime_sec = get_date(now, bsdtar->argument); + if (archive_match_include_date(bsdtar->matching, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, + bsdtar->argument) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); break; case OPTION_NEWER_CTIME_THAN: - { - struct stat st; - if (stat(bsdtar->argument, &st) != 0) - lafe_errc(1, 0, - "Can't open file %s", bsdtar->argument); - bsdtar->newer_ctime_filter = 1; - bsdtar->newer_ctime_sec = st.st_ctime; - bsdtar->newer_ctime_nsec = - ARCHIVE_STAT_CTIME_NANOS(&st); - } + if (archive_match_include_file_time(bsdtar->matching, + ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, + bsdtar->argument) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); break; case OPTION_NEWER_MTIME: /* GNU tar */ - bsdtar->newer_mtime_filter = 1; - bsdtar->newer_mtime_sec = get_date(now, bsdtar->argument); + if (archive_match_include_date(bsdtar->matching, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, + bsdtar->argument) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); break; case OPTION_NEWER_MTIME_THAN: - { - struct stat st; - if (stat(bsdtar->argument, &st) != 0) - lafe_errc(1, 0, - "Can't open file %s", bsdtar->argument); - bsdtar->newer_mtime_filter = 1; - bsdtar->newer_mtime_sec = st.st_mtime; - bsdtar->newer_mtime_nsec = - ARCHIVE_STAT_MTIME_NANOS(&st); - } + if (archive_match_include_file_time(bsdtar->matching, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, + bsdtar->argument) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); break; case OPTION_NODUMP: /* star */ - bsdtar->option_honor_nodump = 1; + bsdtar->readdisk_flags |= ARCHIVE_READDISK_HONOR_NODUMP; break; case OPTION_NO_SAME_OWNER: /* GNU tar */ bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; @@ -454,7 +449,8 @@ main(int argc, char **argv) option_o = 1; /* Record it and resolve it later. */ break; case OPTION_ONE_FILE_SYSTEM: /* GNU tar */ - bsdtar->option_dont_traverse_mounts = 1; + bsdtar->readdisk_flags |= + ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS; break; case OPTION_OPTIONS: bsdtar->option_options = bsdtar->argument; @@ -559,10 +555,11 @@ main(int argc, char **argv) bsdtar->option_interactive = 1; break; case 'X': /* GNU tar */ - if (lafe_exclude_from_file(&bsdtar->matching, bsdtar->argument)) - lafe_errc(1, 0, - "failed to process exclusions from file %s", - bsdtar->argument); + if (archive_match_exclude_pattern_from_file( + bsdtar->matching, bsdtar->argument, 0) + != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); break; case 'x': /* SUSv2 */ set_mode(bsdtar, opt); @@ -612,11 +609,11 @@ main(int argc, char **argv) "Must specify one of -c, -r, -t, -u, -x"); /* Check boolean options only permitted in certain modes. */ - if (bsdtar->option_dont_traverse_mounts) + if (bsdtar->readdisk_flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) only_mode(bsdtar, "--one-file-system", "cru"); if (bsdtar->option_fast_read) only_mode(bsdtar, "--fast-read", "xt"); - if (bsdtar->option_honor_nodump) + if (bsdtar->readdisk_flags & ARCHIVE_READDISK_HONOR_NODUMP) only_mode(bsdtar, "--nodump", "cru"); if (option_o > 0) { switch (bsdtar->mode) { @@ -684,7 +681,7 @@ main(int argc, char **argv) break; } - lafe_cleanup_exclusions(&bsdtar->matching); + archive_match_free(bsdtar->matching); #if HAVE_REGEX_H cleanup_substitution(bsdtar); #endif diff --git a/contrib/libarchive/tar/bsdtar.h b/contrib/libarchive/tar/bsdtar.h index e561a62..1528c48 100644 --- a/contrib/libarchive/tar/bsdtar.h +++ b/contrib/libarchive/tar/bsdtar.h @@ -28,8 +28,6 @@ #include "bsdtar_platform.h" #include <stdio.h> -#include "matching.h" - #define DEFAULT_BYTES_PER_BLOCK (20*512) /* @@ -46,16 +44,11 @@ struct bsdtar { const char *create_format; /* -F format */ char *pending_chdir; /* -C dir */ const char *names_from_file; /* -T file */ - int newer_ctime_filter; /* --newer/--newer-than */ - time_t newer_ctime_sec; /* --newer/--newer-than */ - long newer_ctime_nsec; /* --newer/--newer-than */ - int newer_mtime_filter; /* --newer-mtime/--newer-mtime-than */ - time_t newer_mtime_sec; /* --newer-mtime */ - long newer_mtime_nsec; /* --newer-mtime-than */ int bytes_per_block; /* -b block_size */ int bytes_in_last_block; /* See -b handling. */ int verbose; /* -v */ int extract_flags; /* Flags for extract operation */ + int readdisk_flags; /* Flags for read disk operation */ int strip_components; /* Remove this many leading dirs */ int gid; /* --gid */ const char *gname; /* --gname */ @@ -67,10 +60,8 @@ struct bsdtar { const char *compress_program; char option_absolute_paths; /* -P */ char option_chroot; /* --chroot */ - char option_dont_traverse_mounts; /* --one-file-system */ char option_fast_read; /* --fast-read */ const char *option_options; /* --options */ - char option_honor_nodump; /* --nodump */ char option_interactive; /* -w */ char option_no_owner; /* -o */ char option_no_subdirs; /* -n */ @@ -81,7 +72,6 @@ struct bsdtar { char option_unlink_first; /* -U */ char option_warn_links; /* --check-links */ char day_first; /* show day before month in -tv output */ - char enable_copyfile; /* For Mac OS */ /* Option parser state */ int getopt_state; @@ -111,7 +101,8 @@ struct bsdtar { struct name_cache *gname_cache; /* for write.c */ char *buff; /* for write.c */ size_t buff_size; /* for write.c */ - struct lafe_matching *matching; /* for matching.c */ + int first_fs; /* for write.c */ + struct archive *matching; /* for matching.c */ struct security *security; /* for read.c */ struct name_cache *uname_cache; /* for write.c */ struct siginfo_data *siginfo; /* for siginfo.c */ diff --git a/contrib/libarchive/tar/read.c b/contrib/libarchive/tar/read.c index 12d4b6a..87ee735 100644 --- a/contrib/libarchive/tar/read.c +++ b/contrib/libarchive/tar/read.c @@ -77,12 +77,15 @@ struct progress_data { static void list_item_verbose(struct bsdtar *, FILE *, struct archive_entry *); static void read_archive(struct bsdtar *bsdtar, char mode, struct archive *); +static int unmatched_inclusions_warn(struct archive *matching, const char *); + void tar_mode_t(struct bsdtar *bsdtar) { read_archive(bsdtar, 't', NULL); - if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) + if (unmatched_inclusions_warn(bsdtar->matching, + "Not found in archive") != 0) bsdtar->return_value = 1; } @@ -100,7 +103,8 @@ tar_mode_x(struct bsdtar *bsdtar) read_archive(bsdtar, 'x', writer); - if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) + if (unmatched_inclusions_warn(bsdtar->matching, + "Not found in archive") != 0) bsdtar->return_value = 1; archive_write_free(writer); } @@ -152,17 +156,21 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer) struct archive *a; struct archive_entry *entry; int r; - time_t sec; - long nsec; while (*bsdtar->argv) { - lafe_include(&bsdtar->matching, *bsdtar->argv); + if (archive_match_include_pattern(bsdtar->matching, + *bsdtar->argv) != ARCHIVE_OK) + lafe_errc(1, 0, "Error inclusion pattern: %s", + archive_error_string(bsdtar->matching)); bsdtar->argv++; } if (bsdtar->names_from_file != NULL) - lafe_include_from_file(&bsdtar->matching, - bsdtar->names_from_file, bsdtar->option_null); + if (archive_match_include_pattern_from_file( + bsdtar->matching, bsdtar->names_from_file, + bsdtar->option_null) != ARCHIVE_OK) + lafe_errc(1, 0, "Error inclusion pattern: %s", + archive_error_string(bsdtar->matching)); a = archive_read_new(); if (bsdtar->compress_program != NULL) @@ -199,7 +207,7 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer) for (;;) { /* Support --fast-read option */ if (bsdtar->option_fast_read && - lafe_unmatched_inclusions(bsdtar->matching) == 0) + archive_match_path_unmatched_inclusions(bsdtar->matching) == 0) break; r = archive_read_next_header(a, &entry); @@ -232,42 +240,6 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer) archive_entry_set_gname(entry, bsdtar->gname); /* - * Exclude entries that are too old. - */ - if (bsdtar->newer_ctime_filter) { - /* Use ctime if format provides, else mtime. */ - if (archive_entry_ctime_is_set(entry)) { - sec = archive_entry_ctime(entry); - nsec = archive_entry_ctime_nsec(entry); - } else if (archive_entry_mtime_is_set(entry)) { - sec = archive_entry_mtime(entry); - nsec = archive_entry_mtime_nsec(entry); - } else { - sec = 0; - nsec = 0; - } - if (sec < bsdtar->newer_ctime_sec) - continue; /* Too old, skip it. */ - if (sec == bsdtar->newer_ctime_sec - && nsec <= bsdtar->newer_ctime_nsec) - continue; /* Too old, skip it. */ - } - if (bsdtar->newer_mtime_filter) { - if (archive_entry_mtime_is_set(entry)) { - sec = archive_entry_mtime(entry); - nsec = archive_entry_mtime_nsec(entry); - } else { - sec = 0; - nsec = 0; - } - if (sec < bsdtar->newer_mtime_sec) - continue; /* Too old, skip it. */ - if (sec == bsdtar->newer_mtime_sec - && nsec <= bsdtar->newer_mtime_nsec) - continue; /* Too old, skip it. */ - } - - /* * Note that pattern exclusions are checked before * pathname rewrites are handled. This gives more * control over exclusions, since rewrites always lose @@ -276,7 +248,7 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer) * rewrite, there would be no way to exclude foo1/bar * while allowing foo2/bar.) */ - if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry))) + if (archive_match_excluded(bsdtar->matching, entry)) continue; /* Excluded by a pattern test. */ if (mode == 't') { @@ -471,3 +443,21 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) else if (archive_entry_symlink(entry)) /* Symbolic link */ safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); } + +static int +unmatched_inclusions_warn(struct archive *matching, const char *msg) +{ + const char *p; + int r; + + if (matching == NULL) + return (0); + + while ((r = archive_match_path_unmatched_inclusions_next( + matching, &p)) == ARCHIVE_OK) + lafe_warnc(0, "%s: %s", p, msg); + if (r == ARCHIVE_FATAL) + lafe_errc(1, errno, "Out of memory"); + + return (archive_match_path_unmatched_inclusions(matching)); +} diff --git a/contrib/libarchive/tar/test/main.c b/contrib/libarchive/tar/test/main.c index 798b4e0..0d617e3 100644 --- a/contrib/libarchive/tar/test/main.c +++ b/contrib/libarchive/tar/test/main.c @@ -24,6 +24,9 @@ */ #include "test.h" +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -31,6 +34,16 @@ #ifdef HAVE_ICONV_H #include <iconv.h> #endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include <linux/ext2_fs.h> /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ +#endif #include <limits.h> #include <locale.h> #ifdef HAVE_SIGNAL_H @@ -116,7 +129,14 @@ __FBSDID("$FreeBSD$"); #endif #if defined(_WIN32) && !defined(__CYGWIN__) -void *GetFunctionKernel32(const char *name) +static void *GetFunctionKernel32(const char *); +static int my_CreateSymbolicLinkA(const char *, const char *, int); +static int my_CreateHardLinkA(const char *, const char *); +static int my_GetFileInformationByName(const char *, + BY_HANDLE_FILE_INFORMATION *); + +static void * +GetFunctionKernel32(const char *name) { static HINSTANCE lib; static int set; @@ -155,7 +175,7 @@ my_CreateHardLinkA(const char *linkname, const char *target) return f == NULL ? 0 : (*f)(linkname, target, NULL); } -int +static int my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) { HANDLE h; @@ -1507,7 +1527,7 @@ assertion_make_dir(const char *file, int line, const char *dirname, int mode) /* Create a file with the specified contents and report any failures. */ int assertion_make_file(const char *file, int line, - const char *path, int mode, const char *contents) + const char *path, int mode, int csize, const void *contents) { #if defined(_WIN32) && !defined(__CYGWIN__) /* TODO: Rework this to set file mode as well. */ @@ -1521,8 +1541,13 @@ assertion_make_file(const char *file, int line, return (0); } if (contents != NULL) { - if (strlen(contents) - != fwrite(contents, 1, strlen(contents), f)) { + size_t wsize; + + if (csize < 0) + wsize = strlen(contents); + else + wsize = (size_t)csize; + if (wsize != fwrite(contents, 1, wsize, f)) { fclose(f); failure_start(file, line, "Could not write file %s", path); @@ -1542,10 +1567,16 @@ assertion_make_file(const char *file, int line, return (0); } if (contents != NULL) { - if ((ssize_t)strlen(contents) - != write(fd, contents, strlen(contents))) { + ssize_t wsize; + + if (csize < 0) + wsize = (ssize_t)strlen(contents); + else + wsize = (ssize_t)csize; + if (wsize != write(fd, contents, wsize)) { close(fd); - failure_start(file, line, "Could not write to %s", path); + failure_start(file, line, + "Could not write to %s", path); failure_finish(NULL); return (0); } @@ -1716,6 +1747,52 @@ assertion_utimes(const char *file, int line, #endif /* defined(_WIN32) && !defined(__CYGWIN__) */ } +/* Set nodump, report failures. */ +int +assertion_nodump(const char *file, int line, const char *pathname) +{ +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + int r; + + assertion_count(file, line); + r = chflags(pathname, UF_NODUMP); + if (r < 0) { + failure_start(file, line, "Can't set nodump %s\n", pathname); + failure_finish(NULL); + return (0); + } +#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ + && defined(EXT2_NODUMP_FL) + int fd, r, flags; + + assertion_count(file, line); + fd = open(pathname, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + failure_start(file, line, "Can't open %s\n", pathname); + failure_finish(NULL); + return (0); + } + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) { + failure_start(file, line, "Can't get flags %s\n", pathname); + failure_finish(NULL); + return (0); + } + flags |= EXT2_NODUMP_FL; + r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + if (r < 0) { + failure_start(file, line, "Can't set nodump %s\n", pathname); + failure_finish(NULL); + return (0); + } + close(fd); +#else + (void)pathname; /* UNUSED */ + assertion_count(file, line); +#endif + return (1); +} + /* * * UTILITIES for use by tests. @@ -1744,7 +1821,7 @@ canSymlink(void) return (value); ++tested; - assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a"); + assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); /* Note: Cygwin has its own symlink() emulation that does not * use the Win32 CreateSymbolicLink() function. */ #if defined(_WIN32) && !defined(__CYGWIN__) @@ -1794,6 +1871,70 @@ canGunzip(void) } /* + * Can this filesystem handle nodump flags. + */ +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + +int +canNodump(void) +{ + const char *path = "cannodumptest"; + struct stat sb; + + assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); + if (chflags(path, UF_NODUMP) < 0) + return (0); + if (stat(path, &sb) < 0) + return (0); + if (sb.st_flags & UF_NODUMP) + return (1); + return (0); +} + +#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ + && defined(EXT2_NODUMP_FL) + +int +canNodump(void) +{ + const char *path = "cannodumptest"; + int fd, r, flags; + + assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return (0); + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) + return (0); + flags |= EXT2_NODUMP_FL; + r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + if (r < 0) + return (0); + close(fd); + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return (0); + r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); + if (r < 0) + return (0); + close(fd); + if (flags & EXT2_NODUMP_FL) + return (1); + return (0); +} + +#else + +int +canNodump() +{ + return (0); +} + +#endif + +/* * Sleep as needed; useful for verifying disk timestamp changes by * ensuring that the wall-clock time has actually changed before we * go back to re-read something from disk. @@ -2236,17 +2377,77 @@ success: return strdup(buff); } +static int +get_test_set(int *test_set, int limit, const char *test) +{ + int start, end; + int idx = 0; + + if (test == NULL) { + /* Default: Run all tests. */ + for (;idx < limit; idx++) + test_set[idx] = idx; + return (limit); + } + if (*test >= '0' && *test <= '9') { + const char *vp = test; + start = 0; + while (*vp >= '0' && *vp <= '9') { + start *= 10; + start += *vp - '0'; + ++vp; + } + if (*vp == '\0') { + end = start; + } else if (*vp == '-') { + ++vp; + if (*vp == '\0') { + end = limit - 1; + } else { + end = 0; + while (*vp >= '0' && *vp <= '9') { + end *= 10; + end += *vp - '0'; + ++vp; + } + } + } else + return (-1); + if (start < 0 || end >= limit || start > end) + return (-1); + while (start <= end) + test_set[idx++] = start++; + } else { + size_t len = strlen(test); + for (start = 0; start < limit; ++start) { + const char *name = tests[start].name; + const char *p; + + while ((p = strchr(name, test[0])) != NULL) { + if (strncmp(p, test, len) == 0) { + test_set[idx++] = start; + break; + } else + name = p + 1; + } + + } + } + return ((idx == 0)?-1:idx); +} + int main(int argc, char **argv) { static const int limit = sizeof(tests) / sizeof(tests[0]); - int i = 0, j = 0, start, end, tests_run = 0, tests_failed = 0, option; + int test_set[sizeof(tests) / sizeof(tests[0])]; + int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; time_t now; char *refdir_alloc = NULL; const char *progname; char **saved_argv; const char *tmp, *option_arg, *p; - char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL; + char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; char tmpdir_timestamp[256]; (void)argc; /* UNUSED */ @@ -2332,6 +2533,19 @@ main(int argc, char **argv) if (getenv(ENVBASE "_DEBUG") != NULL) dump_on_failure = 1; + /* Allow -v to be controlled through the environment. */ + if (getenv("_VERBOSITY_LEVEL") != NULL) + { + vlevel = getenv("_VERBOSITY_LEVEL"); + verbosity = atoi(vlevel); + if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) + { + /* Unsupported verbosity levels are silently ignored */ + vlevel = NULL; + verbosity = VERBOSITY_PASSFAIL; + } + } + /* Get the directory holding test files from environment. */ refdir = getenv(ENVBASE "_TEST_FILES"); @@ -2379,7 +2593,8 @@ main(int argc, char **argv) #endif break; case 'q': - verbosity--; + if (!vlevel) + verbosity--; break; case 'r': refdir = option_arg; @@ -2388,7 +2603,8 @@ main(int argc, char **argv) until_failure++; break; case 'v': - verbosity++; + if (!vlevel) + verbosity++; break; default: fprintf(stderr, "Unrecognized option '%c'\n", @@ -2501,78 +2717,27 @@ main(int argc, char **argv) saved_argv = argv; do { argv = saved_argv; - if (*argv == NULL) { - /* Default: Run all tests. */ - for (i = 0; i < limit; i++) { + do { + int test_num; + + test_num = get_test_set(test_set, limit, *argv); + if (test_num < 0) { + printf("*** INVALID Test %s\n", *argv); + free(refdir_alloc); + usage(progname); + return (1); + } + for (i = 0; i < test_num; i++) { tests_run++; - if (test_run(i, tmpdir)) { + if (test_run(test_set[i], tmpdir)) { tests_failed++; if (until_failure) goto finish; } } - } else { - while (*(argv) != NULL) { - if (**argv >= '0' && **argv <= '9') { - char *vp = *argv; - start = 0; - while (*vp >= '0' && *vp <= '9') { - start *= 10; - start += *vp - '0'; - ++vp; - } - if (*vp == '\0') { - end = start; - } else if (*vp == '-') { - ++vp; - if (*vp == '\0') { - end = limit - 1; - } else { - end = 0; - while (*vp >= '0' && *vp <= '9') { - end *= 10; - end += *vp - '0'; - ++vp; - } - } - } else { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - usage(progname); - return (1); - } - if (start < 0 || end >= limit || start > end) { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - usage(progname); - return (1); - } - } else { - for (start = 0; start < limit; ++start) { - if (strcmp(*argv, tests[start].name) == 0) - break; - } - end = start; - if (start >= limit) { - printf("*** INVALID Test ``%s''\n", - *argv); - free(refdir_alloc); - usage(progname); - /* usage() never returns */ - } - } - while (start <= end) { - tests_run++; - if (test_run(start, tmpdir)) { - tests_failed++; - if (until_failure) - goto finish; - } - ++start; - } + if (*argv != NULL) argv++; - } - } + } while (*argv != NULL); } while (until_failure); finish: diff --git a/contrib/libarchive/tar/test/test.h b/contrib/libarchive/tar/test/test.h index 43462cc..4c6e9cb 100644 --- a/contrib/libarchive/tar/test/test.h +++ b/contrib/libarchive/tar/test/test.h @@ -196,11 +196,15 @@ #define assertMakeDir(dirname, mode) \ assertion_make_dir(__FILE__, __LINE__, dirname, mode) #define assertMakeFile(path, mode, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, contents) + assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) +#define assertMakeBinFile(path, mode, csize, contents) \ + assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) #define assertMakeHardlink(newfile, oldfile) \ assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) #define assertMakeSymlink(newfile, linkto) \ assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) +#define assertNodump(path) \ + assertion_nodump(__FILE__, __LINE__, path) #define assertUmask(mask) \ assertion_umask(__FILE__, __LINE__, mask) #define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ @@ -243,9 +247,10 @@ int assertion_is_not_hardlink(const char *, int, const char *, const char *); int assertion_is_reg(const char *, int, const char *, int); int assertion_is_symlink(const char *, int, const char *, const char *); int assertion_make_dir(const char *, int, const char *, int); -int assertion_make_file(const char *, int, const char *, int, const char *); +int assertion_make_file(const char *, int, const char *, int, int, const void *); int assertion_make_hardlink(const char *, int, const char *newpath, const char *); int assertion_make_symlink(const char *, int, const char *newpath, const char *); +int assertion_nodump(const char *, int, const char *); int assertion_non_empty_file(const char *, int, const char *); int assertion_text_file_contents(const char *, int, const char *buff, const char *f); int assertion_umask(const char *, int, int); @@ -269,6 +274,9 @@ int canGzip(void); /* Return true if this platform can run the "gunzip" program. */ int canGunzip(void); +/* Return true if this filesystem can handle nodump flags. */ +int canNodump(void); + /* Return true if the file has large i-node number(>0xffffffff). */ int is_LargeInode(const char *); diff --git a/contrib/libarchive/tar/test/test_format_newc.c b/contrib/libarchive/tar/test/test_format_newc.c new file mode 100644 index 0000000..808fa4b --- /dev/null +++ b/contrib/libarchive/tar/test/test_format_newc.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +DEFINE_TEST(test_format_newc) +{ + + assertMakeFile("file1", 0644, "file1"); + assertMakeFile("file2", 0644, "file2"); + assertMakeHardlink("file3", "file1"); + + /* Test 1: Create an archive file with a newc format. */ + assertEqualInt(0, + systemf("%s -cf test1.cpio --format newc file1 file2 file3", + testprog)); + assertMakeDir("test1", 0755); + assertChdir("test1"); + assertEqualInt(0, + systemf("%s -xf ../test1.cpio >test.out 2>test.err", testprog)); + assertFileContents("file1", 5, "file1"); + assertFileContents("file2", 5, "file2"); + assertFileContents("file1", 5, "file3"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertChdir(".."); + + /* Test 2: Exclude one of hardlinked files. */ + assertEqualInt(0, + systemf("%s -cf test2.cpio --format newc file1 file2", + testprog)); + assertMakeDir("test2", 0755); + assertChdir("test2"); + assertEqualInt(0, + systemf("%s -xf ../test2.cpio >test.out 2>test.err", testprog)); + assertFileContents("file1", 5, "file1"); + assertFileContents("file2", 5, "file2"); + assertFileNotExists("file3"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertChdir(".."); +} diff --git a/contrib/libarchive/tar/test/test_option_nodump.c b/contrib/libarchive/tar/test/test_option_nodump.c new file mode 100644 index 0000000..768f64a --- /dev/null +++ b/contrib/libarchive/tar/test/test_option_nodump.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +DEFINE_TEST(test_option_nodump) +{ + + if (!canNodump()) { + skipping("Can't test nodump on this filesystem"); + return; + } + + assertMakeFile("file1", 0644, "file1"); + assertMakeFile("file2", 0644, "file2"); + assertMakeFile("file3", 0644, "file3"); + assertNodump("file2"); + + /* Test 1: Without --nodump */ + assertEqualInt(0, systemf("%s -cf test1.tar file1 file2 file3", + testprog)); + assertMakeDir("test1", 0755); + assertChdir("test1"); + assertEqualInt(0, + systemf("%s -xf ../test1.tar >test.out 2>test.err", testprog)); + assertFileContents("file1", 5, "file1"); + assertFileContents("file2", 5, "file2"); + assertFileContents("file3", 5, "file3"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertChdir(".."); + + /* Test 2: With --nodump */ + assertEqualInt(0, systemf("%s -cf test2.tar --nodump file1 file2 file3", + testprog)); + assertMakeDir("test2", 0755); + assertChdir("test2"); + assertEqualInt(0, + systemf("%s -xf ../test2.tar >test.out 2>test.err", testprog)); + assertFileContents("file1", 5, "file1"); + assertFileNotExists("file2"); + assertFileContents("file3", 5, "file3"); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + assertChdir(".."); +} diff --git a/contrib/libarchive/tar/tree.c b/contrib/libarchive/tar/tree.c deleted file mode 100644 index a5bcdf4..0000000 --- a/contrib/libarchive/tar/tree.c +++ /dev/null @@ -1,848 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/*- - * This is a new directory-walking system that addresses a number - * of problems I've had with fts(3). In particular, it has no - * pathname-length limits (other than the size of 'int'), handles - * deep logical traversals, uses considerably less memory, and has - * an opaque interface (easier to modify in the future). - * - * Internally, it keeps a single list of "tree_entry" items that - * represent filesystem objects that require further attention. - * Non-directories are not kept in memory: they are pulled from - * readdir(), returned to the client, then freed as soon as possible. - * Any directory entry to be traversed gets pushed onto the stack. - * - * There is surprisingly little information that needs to be kept for - * each item on the stack. Just the name, depth (represented here as the - * string length of the parent directory's pathname), and some markers - * indicating how to get back to the parent (via chdir("..") for a - * regular dir or via fchdir(2) for a symlink). - */ -#include "bsdtar_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_DIRECT_H -#include <direct.h> -#endif -#ifdef HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#if defined(HAVE_WINDOWS_H) && !defined(__CYGWIN__) -#include <windows.h> -#endif - -#include "tree.h" - -/* - * TODO: - * 1) Loop checking. - * 3) Arbitrary logical traversals by closing/reopening intermediate fds. - */ - -struct tree_entry { - int depth; - struct tree_entry *next; - struct tree_entry *parent; - char *name; - size_t dirname_length; - dev_t dev; - ino_t ino; - int flags; - /* How to return back to the parent of a symlink. */ -#ifdef HAVE_FCHDIR - int symlink_parent_fd; -#elif defined(_WIN32) && !defined(__CYGWIN__) - char *symlink_parent_path; -#else -#error fchdir function required. -#endif -}; - -/* Definitions for tree_entry.flags bitmap. */ -#define isDir 1 /* This entry is a regular directory. */ -#define isDirLink 2 /* This entry is a symbolic link to a directory. */ -#define needsFirstVisit 4 /* This is an initial entry. */ -#define needsDescent 8 /* This entry needs to be previsited. */ -#define needsOpen 16 /* This is a directory that needs to be opened. */ -#define needsAscent 32 /* This entry needs to be postvisited. */ - -/* - * On Windows, "first visit" is handled as a pattern to be handed to - * _findfirst(). This is consistent with Windows conventions that - * file patterns are handled within the application. On Posix, - * "first visit" is just returned to the client. - */ - -/* - * Local data for this package. - */ -struct tree { - struct tree_entry *stack; - struct tree_entry *current; -#if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE d; - BY_HANDLE_FILE_INFORMATION fileInfo; -#define INVALID_DIR_HANDLE INVALID_HANDLE_VALUE - WIN32_FIND_DATA _findData; - WIN32_FIND_DATA *findData; -#else - DIR *d; -#define INVALID_DIR_HANDLE NULL - struct dirent *de; -#endif - int flags; - int visit_type; - int tree_errno; /* Error code from last failed operation. */ - - /* Dynamically-sized buffer for holding path */ - char *buff; - size_t buff_length; - - const char *basename; /* Last path element */ - size_t dirname_length; /* Leading dir length */ - size_t path_length; /* Total path length */ - - int depth; - int openCount; - int maxOpenCount; - - struct stat lst; - struct stat st; -}; - -/* Definitions for tree.flags bitmap. */ -#define hasStat 16 /* The st entry is valid. */ -#define hasLstat 32 /* The lst entry is valid. */ -#define hasFileInfo 64 /* The Windows fileInfo entry is valid. */ - -#if defined(_WIN32) && !defined(__CYGWIN__) -static int -tree_dir_next_windows(struct tree *t, const char *pattern); -#else -static int -tree_dir_next_posix(struct tree *t); -#endif - -#ifdef HAVE_DIRENT_D_NAMLEN -/* BSD extension; avoids need for a strlen() call. */ -#define D_NAMELEN(dp) (dp)->d_namlen -#else -#define D_NAMELEN(dp) (strlen((dp)->d_name)) -#endif - -#include <stdio.h> -void -tree_dump(struct tree *t, FILE *out) -{ - char buff[300]; - struct tree_entry *te; - - fprintf(out, "\tdepth: %d\n", t->depth); - fprintf(out, "\tbuff: %s\n", t->buff); - fprintf(out, "\tpwd: %s\n", getcwd(buff, sizeof(buff))); - fprintf(out, "\tbasename: %s\n", t->basename); - fprintf(out, "\tstack:\n"); - for (te = t->stack; te != NULL; te = te->next) { - fprintf(out, "\t\t%s%d:\"%s\" %s%s%s%s%s%s\n", - t->current == te ? "*" : " ", - te->depth, - te->name, - te->flags & needsFirstVisit ? "V" : "", - te->flags & needsDescent ? "D" : "", - te->flags & needsOpen ? "O" : "", - te->flags & needsAscent ? "A" : "", - te->flags & isDirLink ? "L" : "", - (t->current == te && t->d) ? "+" : "" - ); - } -} - -/* - * Add a directory path to the current stack. - */ -static void -tree_push(struct tree *t, const char *path) -{ - struct tree_entry *te; - - te = malloc(sizeof(*te)); - memset(te, 0, sizeof(*te)); - te->next = t->stack; - te->parent = t->current; - if (te->parent) - te->depth = te->parent->depth + 1; - t->stack = te; -#ifdef HAVE_FCHDIR - te->symlink_parent_fd = -1; - te->name = strdup(path); -#elif defined(_WIN32) && !defined(__CYGWIN__) - te->symlink_parent_path = NULL; - te->name = strdup(path); -#endif - te->flags = needsDescent | needsOpen | needsAscent; - te->dirname_length = t->dirname_length; -} - -/* - * Append a name to the current dir path. - */ -static void -tree_append(struct tree *t, const char *name, size_t name_length) -{ - char *p; - size_t size_needed; - - if (t->buff != NULL) - t->buff[t->dirname_length] = '\0'; - /* Strip trailing '/' from name, unless entire name is "/". */ - while (name_length > 1 && name[name_length - 1] == '/') - name_length--; - - /* Resize pathname buffer as needed. */ - size_needed = name_length + 1 + t->dirname_length; - if (t->buff_length < size_needed) { - if (t->buff_length < 1024) - t->buff_length = 1024; - while (t->buff_length < size_needed) - t->buff_length *= 2; - t->buff = realloc(t->buff, t->buff_length); - } - if (t->buff == NULL) - abort(); - p = t->buff + t->dirname_length; - t->path_length = t->dirname_length + name_length; - /* Add a separating '/' if it's needed. */ - if (t->dirname_length > 0 && p[-1] != '/') { - *p++ = '/'; - t->path_length ++; - } -#if HAVE_STRNCPY_S - strncpy_s(p, t->buff_length - (p - t->buff), name, name_length); -#else - strncpy(p, name, name_length); -#endif - p[name_length] = '\0'; - t->basename = p; -} - -/* - * Open a directory tree for traversal. - */ -struct tree * -tree_open(const char *path) -{ -#ifdef HAVE_FCHDIR - struct tree *t; - - t = malloc(sizeof(*t)); - memset(t, 0, sizeof(*t)); - /* First item is set up a lot like a symlink traversal. */ - tree_push(t, path); - t->stack->flags = needsFirstVisit | isDirLink | needsAscent; - t->stack->symlink_parent_fd = open(".", O_RDONLY); - t->openCount++; - t->d = INVALID_DIR_HANDLE; - return (t); -#elif defined(_WIN32) && !defined(__CYGWIN__) - struct tree *t; - char *cwd = _getcwd(NULL, 0); - char *pathname, *p, *base; - wchar_t *wcs, *wp; - size_t l, wlen; - - /* Take care of '\' character in multi-byte character-set. - * Some multi-byte character-set have been using '\' character - * for a part of its character code. */ - l = MultiByteToWideChar(CP_OEMCP, 0, path, strlen(path), NULL, 0); - if (l == 0) - abort(); - wcs = malloc(sizeof(*wcs) * (l+1)); - if (wcs == NULL) - abort(); - l = MultiByteToWideChar(CP_OEMCP, 0, path, strlen(path), wcs, l); - wcs[l] = L'\0'; - wlen = l; - for (wp = wcs; *wp != L'\0'; ++wp) { - if (*wp == L'\\') - *wp = L'/'; - } - l = WideCharToMultiByte(CP_OEMCP, 0, wcs, wlen, NULL, 0, NULL, NULL); - if (l == 0) - abort(); - pathname = malloc(l+1); - if (pathname == NULL) - abort(); - l = WideCharToMultiByte(CP_OEMCP, 0, wcs, wlen, pathname, l, NULL, NULL); - pathname[l] = '\0'; - free(wcs); - base = pathname; -#if defined(_WIN32) && !defined(__CYGWIN__) - /* ASCII version APIs do not accept the path which begin with - * "//?/" prefix. */ - if (strncmp(base, "//?/", 4) == 0) - base += 4; -#endif - - t = malloc(sizeof(*t)); - memset(t, 0, sizeof(*t)); - /* First item is set up a lot like a symlink traversal. */ - /* printf("Looking for wildcard in %s\n", path); */ - /* TODO: wildcard detection here screws up on \\?\c:\ UNC names */ - if (strchr(base, '*') || strchr(base, '?')) { - /* It has a wildcard in it... */ - /* Separate the last element. */ - p = strrchr(base, '/'); - if (p != NULL) { - *p = '\0'; - chdir(base); - tree_append(t, base, p - base); - t->dirname_length = t->path_length; - base = p + 1; - } - } - tree_push(t, base); - free(pathname); - t->stack->flags = needsFirstVisit | isDirLink | needsAscent; - t->stack->symlink_parent_path = cwd; - t->d = INVALID_DIR_HANDLE; - return (t); -#endif -} - -/* - * We've finished a directory; ascend back to the parent. - */ -static int -tree_ascend(struct tree *t) -{ - struct tree_entry *te; - int r = 0; - - te = t->stack; - t->depth--; - if (te->flags & isDirLink) { -#ifdef HAVE_FCHDIR - if (fchdir(te->symlink_parent_fd) != 0) { - t->tree_errno = errno; - r = TREE_ERROR_FATAL; - } - close(te->symlink_parent_fd); -#elif defined(_WIN32) && !defined(__CYGWIN__) - if (SetCurrentDirectory(te->symlink_parent_path) == 0) { - t->tree_errno = errno; - r = TREE_ERROR_FATAL; - } - free(te->symlink_parent_path); - te->symlink_parent_path = NULL; -#endif - t->openCount--; - } else { -#if defined(_WIN32) && !defined(__CYGWIN__) - if (SetCurrentDirectory("..") == 0) { -#else - if (chdir("..") != 0) { -#endif - t->tree_errno = errno; - r = TREE_ERROR_FATAL; - } - } - return (r); -} - -/* - * Pop the working stack. - */ -static void -tree_pop(struct tree *t) -{ - struct tree_entry *te; - - if (t->buff) - t->buff[t->dirname_length] = '\0'; - if (t->stack == t->current && t->current != NULL) - t->current = t->current->parent; - te = t->stack; - t->stack = te->next; - t->dirname_length = te->dirname_length; - if (t->buff) { - t->basename = t->buff + t->dirname_length; - while (t->basename[0] == '/') - t->basename++; - } - free(te->name); - free(te); -} - -/* - * Get the next item in the tree traversal. - */ -int -tree_next(struct tree *t) -{ - int r; - - /* If we're called again after a fatal error, that's an API - * violation. Just crash now. */ - if (t->visit_type == TREE_ERROR_FATAL) { - fprintf(stderr, "Unable to continue traversing" - " directory hierarchy after a fatal error."); - abort(); - } - - while (t->stack != NULL) { - /* If there's an open dir, get the next entry from there. */ - if (t->d != INVALID_DIR_HANDLE) { -#if defined(_WIN32) && !defined(__CYGWIN__) - r = tree_dir_next_windows(t, NULL); -#else - r = tree_dir_next_posix(t); -#endif - if (r == 0) - continue; - return (r); - } - - if (t->stack->flags & needsFirstVisit) { -#if defined(_WIN32) && !defined(__CYGWIN__) - char *d = t->stack->name; - t->stack->flags &= ~needsFirstVisit; - if (strchr(d, '*') || strchr(d, '?')) { - r = tree_dir_next_windows(t, d); - if (r == 0) - continue; - return (r); - } - /* Not a pattern, handle it as-is... */ -#endif - /* Top stack item needs a regular visit. */ - t->current = t->stack; - tree_append(t, t->stack->name, strlen(t->stack->name)); - /* t->dirname_length = t->path_length; */ - /* tree_pop(t); */ - t->stack->flags &= ~needsFirstVisit; - return (t->visit_type = TREE_REGULAR); - } else if (t->stack->flags & needsDescent) { - /* Top stack item is dir to descend into. */ - t->current = t->stack; - tree_append(t, t->stack->name, strlen(t->stack->name)); - t->stack->flags &= ~needsDescent; - /* If it is a link, set up fd for the ascent. */ - if (t->stack->flags & isDirLink) { -#ifdef HAVE_FCHDIR - t->stack->symlink_parent_fd = open(".", O_RDONLY); - t->openCount++; - if (t->openCount > t->maxOpenCount) - t->maxOpenCount = t->openCount; -#elif defined(_WIN32) && !defined(__CYGWIN__) - t->stack->symlink_parent_path = _getcwd(NULL, 0); -#endif - } - t->dirname_length = t->path_length; -#if defined(_WIN32) && !defined(__CYGWIN__) - if (t->path_length == 259 || !SetCurrentDirectory(t->stack->name) != 0) -#else - if (chdir(t->stack->name) != 0) -#endif - { - /* chdir() failed; return error */ - tree_pop(t); - t->tree_errno = errno; - return (t->visit_type = TREE_ERROR_DIR); - } - t->depth++; - return (t->visit_type = TREE_POSTDESCENT); - } else if (t->stack->flags & needsOpen) { - t->stack->flags &= ~needsOpen; -#if defined(_WIN32) && !defined(__CYGWIN__) - r = tree_dir_next_windows(t, "*"); -#else - r = tree_dir_next_posix(t); -#endif - if (r == 0) - continue; - return (r); - } else if (t->stack->flags & needsAscent) { - /* Top stack item is dir and we're done with it. */ - r = tree_ascend(t); - tree_pop(t); - t->visit_type = r != 0 ? r : TREE_POSTASCENT; - return (t->visit_type); - } else { - /* Top item on stack is dead. */ - tree_pop(t); - t->flags &= ~hasLstat; - t->flags &= ~hasStat; - } - } - return (t->visit_type = 0); -} - -#if defined(_WIN32) && !defined(__CYGWIN__) -static int -tree_dir_next_windows(struct tree *t, const char *pattern) -{ - const char *name; - size_t namelen; - int r; - - for (;;) { - if (pattern != NULL) { - t->d = FindFirstFile(pattern, &t->_findData); - if (t->d == INVALID_DIR_HANDLE) { - r = tree_ascend(t); /* Undo "chdir" */ - tree_pop(t); - t->tree_errno = errno; - t->visit_type = r != 0 ? r : TREE_ERROR_DIR; - return (t->visit_type); - } - t->findData = &t->_findData; - pattern = NULL; - } else if (!FindNextFile(t->d, &t->_findData)) { - FindClose(t->d); - t->d = INVALID_DIR_HANDLE; - t->findData = NULL; - return (0); - } - name = t->findData->cFileName; - namelen = strlen(name); - t->flags &= ~hasLstat; - t->flags &= ~hasStat; - if (name[0] == '.' && name[1] == '\0') - continue; - if (name[0] == '.' && name[1] == '.' && name[2] == '\0') - continue; - tree_append(t, name, namelen); - return (t->visit_type = TREE_REGULAR); - } -} -#else -static int -tree_dir_next_posix(struct tree *t) -{ - int r; - const char *name; - size_t namelen; - - if (t->d == NULL) { - if ((t->d = opendir(".")) == NULL) { - r = tree_ascend(t); /* Undo "chdir" */ - tree_pop(t); - t->tree_errno = errno; - t->visit_type = r != 0 ? r : TREE_ERROR_DIR; - return (t->visit_type); - } - } - for (;;) { - t->de = readdir(t->d); - if (t->de == NULL) { - closedir(t->d); - t->d = INVALID_DIR_HANDLE; - return (0); - } - name = t->de->d_name; - namelen = D_NAMELEN(t->de); - t->flags &= ~hasLstat; - t->flags &= ~hasStat; - if (name[0] == '.' && name[1] == '\0') - continue; - if (name[0] == '.' && name[1] == '.' && name[2] == '\0') - continue; - tree_append(t, name, namelen); - return (t->visit_type = TREE_REGULAR); - } -} -#endif - -/* - * Return error code. - */ -int -tree_errno(struct tree *t) -{ - return (t->tree_errno); -} - -/* - * Called by the client to mark the directory just returned from - * tree_next() as needing to be visited. - */ -void -tree_descend(struct tree *t) -{ - if (t->visit_type != TREE_REGULAR) - return; - - if (tree_current_is_physical_dir(t)) { - tree_push(t, t->basename); - t->stack->flags |= isDir; - } else if (tree_current_is_dir(t)) { - tree_push(t, t->basename); - t->stack->flags |= isDirLink; - } -} - -/* - * Get the stat() data for the entry just returned from tree_next(). - */ -const struct stat * -tree_current_stat(struct tree *t) -{ - if (!(t->flags & hasStat)) { - if (stat(tree_current_access_path(t), &t->st) != 0) - return NULL; - t->flags |= hasStat; - } - return (&t->st); -} - -#if defined(_WIN32) && !defined(__CYGWIN__) -const BY_HANDLE_FILE_INFORMATION * -tree_current_file_information(struct tree *t) -{ - if (!(t->flags & hasFileInfo)) { - HANDLE h = CreateFile(tree_current_access_path(t), - 0, 0, NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); - if (h == INVALID_HANDLE_VALUE) - return NULL; - if (!GetFileInformationByHandle(h, &t->fileInfo)) { - CloseHandle(h); - return NULL; - } - CloseHandle(h); - t->flags |= hasFileInfo; - } - return (&t->fileInfo); -} -#endif -/* - * Get the lstat() data for the entry just returned from tree_next(). - */ -const struct stat * -tree_current_lstat(struct tree *t) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - return (tree_current_stat(t)); -#else - if (!(t->flags & hasLstat)) { - if (lstat(tree_current_access_path(t), &t->lst) != 0) - return NULL; - t->flags |= hasLstat; - } - return (&t->lst); -#endif -} - -/* - * Test whether current entry is a dir or link to a dir. - */ -int -tree_current_is_dir(struct tree *t) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - if (t->findData) - return (t->findData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); - if (tree_current_file_information(t)) - return (t->fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); - return (0); -#else - const struct stat *st; - /* - * If we already have lstat() info, then try some - * cheap tests to determine if this is a dir. - */ - if (t->flags & hasLstat) { - /* If lstat() says it's a dir, it must be a dir. */ - if (S_ISDIR(tree_current_lstat(t)->st_mode)) - return 1; - /* Not a dir; might be a link to a dir. */ - /* If it's not a link, then it's not a link to a dir. */ - if (!S_ISLNK(tree_current_lstat(t)->st_mode)) - return 0; - /* - * It's a link, but we don't know what it's a link to, - * so we'll have to use stat(). - */ - } - - st = tree_current_stat(t); - /* If we can't stat it, it's not a dir. */ - if (st == NULL) - return 0; - /* Use the definitive test. Hopefully this is cached. */ - return (S_ISDIR(st->st_mode)); -#endif -} - -/* - * Test whether current entry is a physical directory. Usually, we - * already have at least one of stat() or lstat() in memory, so we - * use tricks to try to avoid an extra trip to the disk. - */ -int -tree_current_is_physical_dir(struct tree *t) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - if (tree_current_is_physical_link(t)) - return (0); - return (tree_current_is_dir(t)); -#else - const struct stat *st; - - /* - * If stat() says it isn't a dir, then it's not a dir. - * If stat() data is cached, this check is free, so do it first. - */ - if ((t->flags & hasStat) - && (!S_ISDIR(tree_current_stat(t)->st_mode))) - return 0; - - /* - * Either stat() said it was a dir (in which case, we have - * to determine whether it's really a link to a dir) or - * stat() info wasn't available. So we use lstat(), which - * hopefully is already cached. - */ - - st = tree_current_lstat(t); - /* If we can't stat it, it's not a dir. */ - if (st == NULL) - return 0; - /* Use the definitive test. Hopefully this is cached. */ - return (S_ISDIR(st->st_mode)); -#endif -} - -/* - * Test whether current entry is a symbolic link. - */ -int -tree_current_is_physical_link(struct tree *t) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) -#ifndef IO_REPARSE_TAG_SYMLINK -/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */ -#define IO_REPARSE_TAG_SYMLINK 0xA000000CL -#endif - if (t->findData) - return ((t->findData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) - && (t->findData->dwReserved0 == IO_REPARSE_TAG_SYMLINK)); - return (0); -#else - const struct stat *st = tree_current_lstat(t); - if (st == NULL) - return 0; - return (S_ISLNK(st->st_mode)); -#endif -} - -/* - * Return the access path for the entry just returned from tree_next(). - */ -const char * -tree_current_access_path(struct tree *t) -{ - return (t->basename); -} - -/* - * Return the full path for the entry just returned from tree_next(). - */ -const char * -tree_current_path(struct tree *t) -{ - return (t->buff); -} - -/* - * Return the length of the path for the entry just returned from tree_next(). - */ -size_t -tree_current_pathlen(struct tree *t) -{ - return (t->path_length); -} - -/* - * Return the nesting depth of the entry just returned from tree_next(). - */ -int -tree_current_depth(struct tree *t) -{ - return (t->depth); -} - -/* - * Terminate the traversal and release any resources. - */ -void -tree_close(struct tree *t) -{ - /* Release anything remaining in the stack. */ - while (t->stack != NULL) - tree_pop(t); - free(t->buff); - /* TODO: Ensure that premature close() resets cwd */ -#if 0 -#ifdef HAVE_FCHDIR - if (t->initialDirFd >= 0) { - int s = fchdir(t->initialDirFd); - (void)s; /* UNUSED */ - close(t->initialDirFd); - t->initialDirFd = -1; - } -#elif defined(_WIN32) && !defined(__CYGWIN__) - if (t->initialDir != NULL) { - SetCurrentDir(t->initialDir); - free(t->initialDir); - t->initialDir = NULL; - } -#endif -#endif - free(t); -} diff --git a/contrib/libarchive/tar/tree.h b/contrib/libarchive/tar/tree.h deleted file mode 100644 index 3ae74fd..0000000 --- a/contrib/libarchive/tar/tree.h +++ /dev/null @@ -1,141 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/*- - * A set of routines for traversing directory trees. - * Similar in concept to the fts library, but with a few - * important differences: - * * Uses less memory. In particular, fts stores an entire directory - * in memory at a time. This package only keeps enough subdirectory - * information in memory to track the traversal. Information - * about non-directories is discarded as soon as possible. - * * Supports very deep logical traversals. The fts package - * uses "non-chdir" approach for logical traversals. This - * package does use a chdir approach for logical traversals - * and can therefore handle pathnames much longer than PATH_MAX. - * * Supports deep physical traversals "out of the box." - * Due to the memory optimizations above, there's no need to - * limit dir names to 32k. - */ - -#include <sys/stat.h> -#include <stdio.h> - -struct tree; - -/* Initiate/terminate a tree traversal. */ -struct tree *tree_open(const char * /* pathname */); -void tree_close(struct tree *); - -/* - * tree_next() returns Zero if there is no next entry, non-zero if - * there is. Note that directories are visited three times. - * Directories are always visited first as part of enumerating their - * parent; that is a "regular" visit. If tree_descend() is invoked at - * that time, the directory is added to a work list and will - * subsequently be visited two more times: once just after descending - * into the directory ("postdescent") and again just after ascending - * back to the parent ("postascent"). - * - * TREE_ERROR_DIR is returned if the descent failed (because the - * directory couldn't be opened, for instance). This is returned - * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a - * fatal error, but it does imply that the relevant subtree won't be - * visited. TREE_ERROR_FATAL is returned for an error that left the - * traversal completely hosed. Right now, this is only returned for - * chdir() failures during ascent. - */ -#define TREE_REGULAR 1 -#define TREE_POSTDESCENT 2 -#define TREE_POSTASCENT 3 -#define TREE_ERROR_DIR -1 -#define TREE_ERROR_FATAL -2 - -int tree_next(struct tree *); - -/* Errno value associated with the last traversal error. */ -int tree_errno(struct tree *); - -/* - * Request that current entry be visited. If you invoke it on every - * directory, you'll get a physical traversal. This is ignored if the - * current entry isn't a directory or a link to a directory. So, if - * you invoke this on every returned path, you'll get a full logical - * traversal. - */ -void tree_descend(struct tree *); - -/* - * Return information about the current entry. - */ - -/* Current depth in the traversal. */ -int tree_current_depth(struct tree *); - -/* - * The current full pathname, length of the full pathname, and a name - * that can be used to access the file. Because tree does use chdir - * extensively, the access path is almost never the same as the full - * current path. - * - * TODO: Flesh out this interface to provide other information. In - * particular, Windows can provide file size, mode, and some permission - * information without invoking stat() at all. - * - * TODO: On platforms that support it, use openat()-style operations - * to eliminate the chdir() operations entirely while still supporting - * arbitrarily deep traversals. This makes access_path troublesome to - * support, of course, which means we'll need a rich enough interface - * that clients can function without it. (In particular, we'll need - * tree_current_open() that returns an open file descriptor.) - * - * TODO: Provide tree_current_archive_entry(). - */ -const char *tree_current_path(struct tree *); -size_t tree_current_pathlen(struct tree *); -const char *tree_current_access_path(struct tree *); - -/* - * Request the lstat() or stat() data for the current path. Since the - * tree package needs to do some of this anyway, and caches the - * results, you should take advantage of it here if you need it rather - * than make a redundant stat() or lstat() call of your own. - */ -const struct stat *tree_current_stat(struct tree *); -const struct stat *tree_current_lstat(struct tree *); - -/* The following functions use tricks to avoid a certain number of - * stat()/lstat() calls. */ -/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */ -int tree_current_is_physical_dir(struct tree *); -/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */ -int tree_current_is_physical_link(struct tree *); -/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */ -int tree_current_is_dir(struct tree *); - -/* For testing/debugging: Dump the internal status to the given filehandle. */ -void tree_dump(struct tree *, FILE *); diff --git a/contrib/libarchive/tar/write.c b/contrib/libarchive/tar/write.c index 799d511..f8987c7 100644 --- a/contrib/libarchive/tar/write.c +++ b/contrib/libarchive/tar/write.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,9 +30,6 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -56,20 +54,6 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_LIMITS_H #include <limits.h> #endif -#ifdef HAVE_LINUX_FS_H -#include <linux/fs.h> /* for Linux file flags */ -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include <linux/ext2_fs.h> /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -/* This header exists but is broken on Cygwin. */ -#include <ext2fs/ext2_fs.h> -#endif #ifdef HAVE_PATHS_H #include <paths.h> #endif @@ -93,7 +77,6 @@ __FBSDID("$FreeBSD$"); #include "bsdtar.h" #include "err.h" #include "line_reader.h" -#include "tree.h" #ifndef O_BINARY #define O_BINARY 0 @@ -110,28 +93,27 @@ struct archive_dir { struct archive_dir_entry *head, *tail; }; -static void add_dir_list(struct bsdtar *bsdtar, const char *path, - time_t mtime_sec, int mtime_nsec); static int append_archive(struct bsdtar *, struct archive *, struct archive *ina); static int append_archive_filename(struct bsdtar *, struct archive *, const char *fname); static void archive_names_from_file(struct bsdtar *bsdtar, struct archive *a); -static int copy_file_data(struct bsdtar *, struct archive *a, - struct archive *ina, struct archive_entry *); -static int new_enough(struct bsdtar *, const char *path, - const struct stat *); +static int copy_file_data_block(struct bsdtar *, + struct archive *a, struct archive *, + struct archive_entry *); +static void excluded_callback(struct archive *, void *, + struct archive_entry *); static void report_write(struct bsdtar *, struct archive *, struct archive_entry *, int64_t progress); static void test_for_append(struct bsdtar *); +static int metadata_filter(struct archive *, void *, + struct archive_entry *); static void write_archive(struct archive *, struct bsdtar *); static void write_entry(struct bsdtar *, struct archive *, struct archive_entry *); static void write_file(struct bsdtar *, struct archive *, struct archive_entry *); -static int write_file_data(struct bsdtar *, struct archive *, - struct archive_entry *, int fd, size_t align); static void write_hierarchy(struct bsdtar *, struct archive *, const char *); @@ -360,9 +342,11 @@ tar_mode_u(struct bsdtar *bsdtar) lafe_errc(1, 0, "Cannot append to compressed archive."); } - add_dir_list(bsdtar, archive_entry_pathname(entry), - archive_entry_mtime(entry), - archive_entry_mtime_nsec(entry)); + if (archive_match_exclude_entry(bsdtar->matching, + ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER | + ARCHIVE_MATCH_EQUAL, entry) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); /* Record the last format determination we see */ format = archive_format(a); /* Keep going until we hit end-of-archive */ @@ -426,8 +410,30 @@ write_archive(struct archive *a, struct bsdtar *bsdtar) lafe_errc(1, 0, "cannot create link resolver"); archive_entry_linkresolver_set_strategy(bsdtar->resolver, archive_format(a)); + + /* Create a read_disk object. */ if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) lafe_errc(1, 0, "Cannot create read_disk object"); + /* Tell the read_disk how handle symlink. */ + switch (bsdtar->symlink_mode) { + case 'H': + archive_read_disk_set_symlink_hybrid(bsdtar->diskreader); + break; + case 'L': + archive_read_disk_set_symlink_logical(bsdtar->diskreader); + break; + default: + archive_read_disk_set_symlink_physical(bsdtar->diskreader); + break; + } + /* Register entry filters. */ + archive_read_disk_set_matching(bsdtar->diskreader, + bsdtar->matching, excluded_callback, bsdtar); + archive_read_disk_set_metadata_filter_callback( + bsdtar->diskreader, metadata_filter, bsdtar); + /* Set the behavior of archive_read_disk. */ + archive_read_disk_set_behavior(bsdtar->diskreader, + bsdtar->readdisk_flags); archive_read_disk_set_standard_lookup(bsdtar->diskreader); if (bsdtar->names_from_file != NULL) @@ -467,11 +473,57 @@ write_archive(struct archive *a, struct bsdtar *bsdtar) bsdtar->argv++; } + archive_read_disk_set_matching(bsdtar->diskreader, NULL, NULL, NULL); + archive_read_disk_set_metadata_filter_callback( + bsdtar->diskreader, NULL, NULL); entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); while (entry != NULL) { + int r; + struct archive_entry *entry2; + struct archive *disk = bsdtar->diskreader; + + /* + * This tricky code here is to correctly read the cotents + * of the entry because the disk reader bsdtar->diskreader + * is pointing at does not have any information about the + * entry by this time and using archive_read_data_block() + * with the disk reader consequently must fail. And we + * have to re-open the entry to read the contents. + */ + /* TODO: Work with -C option as well. */ + r = archive_read_disk_open(disk, + archive_entry_sourcepath(entry)); + if (r != ARCHIVE_OK) { + lafe_warnc(archive_errno(disk), + "%s", archive_error_string(disk)); + bsdtar->return_value = 1; + archive_entry_free(entry); + continue; + } + + /* + * Invoke archive_read_next_header2() to work + * archive_read_data_block(), which is called via write_file(), + * without failure. + */ + entry2 = archive_entry_new(); + r = archive_read_next_header2(disk, entry2); + archive_entry_free(entry2); + if (r != ARCHIVE_OK) { + lafe_warnc(archive_errno(disk), + "%s", archive_error_string(disk)); + if (r == ARCHIVE_FATAL) + bsdtar->return_value = 1; + else + archive_read_close(disk); + archive_entry_free(entry); + continue; + } + write_file(bsdtar, a, entry); archive_entry_free(entry); + archive_read_close(disk); entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); } @@ -584,10 +636,7 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) int e; while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) { - if (!new_enough(bsdtar, archive_entry_pathname(in_entry), - archive_entry_stat(in_entry))) - continue; - if (lafe_excluded(bsdtar->matching, archive_entry_pathname(in_entry))) + if (archive_match_excluded(bsdtar->matching, in_entry)) continue; if (bsdtar->option_interactive && !yes("copy '%s'", archive_entry_pathname(in_entry))) @@ -613,7 +662,7 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) if (e >= ARCHIVE_WARN) { if (archive_entry_size(in_entry) == 0) archive_read_data_skip(ina); - else if (copy_file_data(bsdtar, a, ina, in_entry)) + else if (copy_file_data_block(bsdtar, a, ina, in_entry)) exit(1); } @@ -624,204 +673,168 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) return (e == ARCHIVE_EOF ? ARCHIVE_OK : e); } -/* Helper function to copy data between archives. */ +/* Helper function to copy file to archive. */ static int -copy_file_data(struct bsdtar *bsdtar, struct archive *a, - struct archive *ina, struct archive_entry *entry) +copy_file_data_block(struct bsdtar *bsdtar, struct archive *a, + struct archive *in_a, struct archive_entry *entry) { - ssize_t bytes_read; + size_t bytes_read; ssize_t bytes_written; - int64_t progress = 0; + int64_t offset, progress = 0; + char *null_buff = NULL; + const void *buff; + int r; - bytes_read = archive_read_data(ina, bsdtar->buff, bsdtar->buff_size); - while (bytes_read > 0) { + while ((r = archive_read_data_block(in_a, &buff, + &bytes_read, &offset)) == ARCHIVE_OK) { if (need_report()) report_write(bsdtar, a, entry, progress); - bytes_written = archive_write_data(a, bsdtar->buff, - bytes_read); - if (bytes_written < bytes_read) { + if (offset > progress) { + int64_t sparse = offset - progress; + size_t ns; + + if (null_buff == NULL) { + null_buff = bsdtar->buff; + memset(null_buff, 0, bsdtar->buff_size); + } + + while (sparse > 0) { + if (sparse > (int64_t)bsdtar->buff_size) + ns = bsdtar->buff_size; + else + ns = (size_t)sparse; + bytes_written = + archive_write_data(a, null_buff, ns); + if (bytes_written < 0) { + /* Write failed; this is bad */ + lafe_warnc(0, "%s", + archive_error_string(a)); + return (-1); + } + if ((size_t)bytes_written < ns) { + /* Write was truncated; warn but + * continue. */ + lafe_warnc(0, + "%s: Truncated write; file may " + "have grown while being archived.", + archive_entry_pathname(entry)); + return (0); + } + progress += bytes_written; + sparse -= bytes_written; + } + } + + bytes_written = archive_write_data(a, buff, bytes_read); + if (bytes_written < 0) { + /* Write failed; this is bad */ lafe_warnc(0, "%s", archive_error_string(a)); return (-1); } + if ((size_t)bytes_written < bytes_read) { + /* Write was truncated; warn but continue. */ + lafe_warnc(0, + "%s: Truncated write; file may have grown " + "while being archived.", + archive_entry_pathname(entry)); + return (0); + } progress += bytes_written; - bytes_read = archive_read_data(ina, bsdtar->buff, bsdtar->buff_size); } - + if (r < ARCHIVE_WARN) { + lafe_warnc(archive_errno(a), "%s", archive_error_string(a)); + return (-1); + } return (0); } +static void +excluded_callback(struct archive *a, void *_data, struct archive_entry *entry) +{ + struct bsdtar *bsdtar = (struct bsdtar *)_data; + + if (bsdtar->option_no_subdirs) + return; + if (!archive_read_disk_can_descend(a)) + return; + if (bsdtar->option_interactive && + !yes("add '%s'", archive_entry_pathname(entry))) + return; + archive_read_disk_descend(a); +} + +static int +metadata_filter(struct archive *a, void *_data, struct archive_entry *entry) +{ + struct bsdtar *bsdtar = (struct bsdtar *)_data; + + /* XXX TODO: check whether this filesystem is + * synthetic and/or local. Add a new + * --local-only option to skip non-local + * filesystems. Skip synthetic filesystems + * regardless. + * + * The results should be cached, since + * tree.c doesn't usually visit a directory + * and the directory contents together. A simple + * move-to-front list should perform quite well. + * + * Use archive_read_disk_current_filesystem_is_remote(). + */ + + /* + * If the user vetoes this file/directory, skip it. + * We want this to be fairly late; if some other + * check would veto this file, we shouldn't bother + * the user with it. + */ + if (bsdtar->option_interactive && + !yes("add '%s'", archive_entry_pathname(entry))) + return (0); + + /* Note: if user vetoes, we won't descend. */ + if (!bsdtar->option_no_subdirs && archive_read_disk_can_descend(a)) + archive_read_disk_descend(a); + + return (1); +} + /* * Add the file or dir hierarchy named by 'path' to the archive */ static void write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) { + struct archive *disk = bsdtar->diskreader; struct archive_entry *entry = NULL, *spare_entry = NULL; - struct tree *tree; - char symlink_mode = bsdtar->symlink_mode; - dev_t first_dev = 0; - int dev_recorded = 0; - int tree_ret; - - tree = tree_open(path); + int r; - if (!tree) { - lafe_warnc(errno, "%s: Cannot open", path); + r = archive_read_disk_open(disk, path); + if (r != ARCHIVE_OK) { + lafe_warnc(archive_errno(disk), + "%s", archive_error_string(disk)); bsdtar->return_value = 1; return; } + bsdtar->first_fs = -1; - while ((tree_ret = tree_next(tree)) != 0) { - int r; - const char *name = tree_current_path(tree); - const struct stat *st = NULL; /* info to use for this entry */ - const struct stat *lst = NULL; /* lstat() information */ - int descend; - - if (tree_ret == TREE_ERROR_FATAL) - lafe_errc(1, tree_errno(tree), - "%s: Unable to continue traversing directory tree", - name); - if (tree_ret == TREE_ERROR_DIR) { - lafe_warnc(errno, - "%s: Couldn't visit directory", name); - bsdtar->return_value = 1; - } - if (tree_ret != TREE_REGULAR) - continue; - - /* - * If this file/dir is excluded by a filename - * pattern, skip it. - */ - if (lafe_excluded(bsdtar->matching, name)) - continue; - - /* - * Get lstat() info from the tree library. - */ - lst = tree_current_lstat(tree); - if (lst == NULL) { - /* Couldn't lstat(); must not exist. */ - lafe_warnc(errno, "%s: Cannot stat", name); - /* Return error if files disappear during traverse. */ - bsdtar->return_value = 1; - continue; - } - - /* - * Distinguish 'L'/'P'/'H' symlink following. - */ - switch(symlink_mode) { - case 'H': - /* 'H': After the first item, rest like 'P'. */ - symlink_mode = 'P'; - /* 'H': First item (from command line) like 'L'. */ - /* FALLTHROUGH */ - case 'L': - /* 'L': Do descend through a symlink to dir. */ - descend = tree_current_is_dir(tree); - /* 'L': Follow symlinks to files. */ - archive_read_disk_set_symlink_logical(bsdtar->diskreader); - /* 'L': Archive symlinks as targets, if we can. */ - st = tree_current_stat(tree); - if (st != NULL) - break; - /* If stat fails, we have a broken symlink; - * in that case, don't follow the link. */ - /* FALLTHROUGH */ - default: - /* 'P': Don't descend through a symlink to dir. */ - descend = tree_current_is_physical_dir(tree); - /* 'P': Don't follow symlinks to files. */ - archive_read_disk_set_symlink_physical(bsdtar->diskreader); - /* 'P': Archive symlinks as symlinks. */ - st = lst; + for (;;) { + archive_entry_free(entry); + entry = archive_entry_new(); + r = archive_read_next_header2(disk, entry); + if (r == ARCHIVE_EOF) break; - } - - if (bsdtar->option_no_subdirs) - descend = 0; - - /* - * Are we about to cross to a new filesystem? - */ - if (!dev_recorded) { - /* This is the initial file system. */ - first_dev = lst->st_dev; - dev_recorded = 1; - } else if (lst->st_dev == first_dev) { - /* The starting file system is always acceptable. */ - } else if (descend == 0) { - /* We're not descending, so no need to check. */ - } else if (bsdtar->option_dont_traverse_mounts) { - descend = 0; - } else { - /* We're prepared to cross a mount point. */ - - /* XXX TODO: check whether this filesystem is - * synthetic and/or local. Add a new - * --local-only option to skip non-local - * filesystems. Skip synthetic filesystems - * regardless. - * - * The results should be cached, since - * tree.c doesn't usually visit a directory - * and the directory contents together. A simple - * move-to-front list should perform quite well. - * - * This is going to be heavily OS dependent: - * FreeBSD's statfs() in conjunction with getvfsbyname() - * provides all of this; NetBSD's statvfs() does - * most of it; other systems will vary. - */ - } - - /* - * In -u mode, check that the file is newer than what's - * already in the archive; in all modes, obey --newerXXX flags. - */ - if (!new_enough(bsdtar, name, st)) { - if (!descend) - continue; - if (bsdtar->option_interactive && - !yes("add '%s'", name)) + else if (r != ARCHIVE_OK) { + lafe_warnc(archive_errno(disk), + "%s", archive_error_string(disk)); + if (r == ARCHIVE_FATAL) { + bsdtar->return_value = 1; + return; + } else if (r < ARCHIVE_WARN) continue; - tree_descend(tree); - continue; } - archive_entry_free(entry); - entry = archive_entry_new(); - - archive_entry_set_pathname(entry, name); - archive_entry_copy_sourcepath(entry, - tree_current_access_path(tree)); - - /* Populate the archive_entry with metadata from the disk. */ - /* XXX TODO: Arrange to open a regular file before - * calling this so we can pass in an fd and shorten - * the race to query metadata. The linkify dance - * makes this more complex than it might sound. */ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* TODO: tree.c uses stat(), which is badly broken - * on Windows. To fix this, we should - * deprecate tree_current_stat() and provide a new - * call tree_populate_entry(t, entry). This call - * would use stat() internally on POSIX and - * GetInfoByFileHandle() internally on Windows. - * This would be another step towards a tree-walker - * that can be integrated deep into libarchive. - * For now, just set st to NULL on Windows; - * archive_read_disk_entry_from_file() should - * be smart enough to use platform-appropriate - * ways to probe file information. - */ - st = NULL; -#endif - r = archive_read_disk_entry_from_file(bsdtar->diskreader, - entry, -1, st); if (bsdtar->uid >= 0) { archive_entry_set_uid(entry, bsdtar->uid); if (!bsdtar->uname) @@ -840,68 +853,6 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) archive_entry_set_uname(entry, bsdtar->uname); if (bsdtar->gname) archive_entry_set_gname(entry, bsdtar->gname); - if (r != ARCHIVE_OK) - lafe_warnc(archive_errno(bsdtar->diskreader), - "%s", archive_error_string(bsdtar->diskreader)); - if (r < ARCHIVE_WARN) - continue; - - /* XXX TODO: Just use flag data from entry; avoid the - * duplicate check here. */ - - /* - * If this file/dir is flagged "nodump" and we're - * honoring such flags, skip this file/dir. - */ -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - /* BSD systems store flags in struct stat */ - if (bsdtar->option_honor_nodump && - (lst->st_flags & UF_NODUMP)) - continue; -#endif - -#if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) - /* Linux uses ioctl to read flags. */ - if (bsdtar->option_honor_nodump) { - int fd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY); - if (fd >= 0) { - unsigned long fflags; - int r = ioctl(fd, EXT2_IOC_GETFLAGS, &fflags); - close(fd); - if (r >= 0 && (fflags & EXT2_NODUMP_FL)) - continue; - } - } -#endif - -#ifdef __APPLE__ - if (bsdtar->enable_copyfile) { - /* If we're using copyfile(), ignore "._XXX" files. */ - const char *bname = strrchr(name, '/'); - if (bname == NULL) - bname = name; - else - ++bname; - if (bname[0] == '.' && bname[1] == '_') - continue; - } else { - /* If not, drop the copyfile() data. */ - archive_entry_copy_mac_metadata(entry, NULL, 0); - } -#endif - - /* - * If the user vetoes this file/directory, skip it. - * We want this to be fairly late; if some other - * check would veto this file, we shouldn't bother - * the user with it. - */ - if (bsdtar->option_interactive && - !yes("add '%s'", name)) - continue; - - if (descend) - tree_descend(tree); /* * Rewrite the pathname to be archived. If rewrite @@ -933,7 +884,7 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) fprintf(stderr, "\n"); } archive_entry_free(entry); - tree_close(tree); + archive_read_close(disk); } /* @@ -954,29 +905,7 @@ static void write_entry(struct bsdtar *bsdtar, struct archive *a, struct archive_entry *entry) { - int fd = -1; int e; - size_t align = 4096; - - if (archive_entry_size(entry) > 0) { - const char *pathname = archive_entry_sourcepath(entry); - /* TODO: Use O_DIRECT here and set 'align' to the - * actual filesystem block size. As of July 2010, new - * directory-traversal code is going in that will make - * it much easier to track filesystem properties like - * this during the traversal. */ - fd = open(pathname, O_RDONLY | O_BINARY); - align = 4096; - if (fd == -1) { - bsdtar->return_value = 1; - if (!bsdtar->verbose) - lafe_warnc(errno, - "%s: could not open file", pathname); - else - fprintf(stderr, ": %s", strerror(errno)); - return; - } - } e = archive_write_header(a, entry); if (e != ARCHIVE_OK) { @@ -997,17 +926,10 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, * to inform us that the archive body won't get stored. In * that case, just skip the write. */ - if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) { - if (write_file_data(bsdtar, a, entry, fd, align)) + if (e >= ARCHIVE_WARN && archive_entry_size(entry) > 0) { + if (copy_file_data_block(bsdtar, a, bsdtar->diskreader, entry)) exit(1); } - - /* - * If we opened a file, close it now even if there was an error - * which made us decide not to write the archive body. - */ - if (fd >= 0) - close(fd); } static void @@ -1038,144 +960,6 @@ report_write(struct bsdtar *bsdtar, struct archive *a, tar_i64toa(archive_entry_size(entry))); } - -/* Helper function to copy file to archive. */ -static int -write_file_data(struct bsdtar *bsdtar, struct archive *a, - struct archive_entry *entry, int fd, size_t align) -{ - ssize_t bytes_read; - ssize_t bytes_written; - int64_t progress = 0; - size_t buff_size; - char *buff = bsdtar->buff; - - /* Round 'buff' up to the next multiple of 'align' and reduce - * 'buff_size' accordingly. */ - buff = (char *)((((uintptr_t)buff + align - 1) / align) * align); - buff_size = bsdtar->buff + bsdtar->buff_size - buff; - buff_size = (buff_size / align) * align; - - bytes_read = read(fd, buff, buff_size); - while (bytes_read > 0) { - if (need_report()) - report_write(bsdtar, a, entry, progress); - - bytes_written = archive_write_data(a, buff, bytes_read); - if (bytes_written < 0) { - /* Write failed; this is bad */ - lafe_warnc(0, "%s", archive_error_string(a)); - return (-1); - } - if (bytes_written < bytes_read) { - /* Write was truncated; warn but continue. */ - lafe_warnc(0, - "%s: Truncated write; file may have grown while being archived.", - archive_entry_pathname(entry)); - return (0); - } - progress += bytes_written; - bytes_read = read(fd, buff, buff_size); - } - if (bytes_read < 0) { - lafe_warnc(errno, - "%s: Read error", - archive_entry_pathname(entry)); - bsdtar->return_value = 1; - } - return 0; -} - -/* - * Test if the specified file is new enough to include in the archive. - */ -static int -new_enough(struct bsdtar *bsdtar, const char *path, const struct stat *st) -{ - struct archive_dir_entry *p; - - /* - * If this file/dir is excluded by a time comparison, skip it. - */ - if (bsdtar->newer_ctime_filter) { - if (st->st_ctime < bsdtar->newer_ctime_sec) - return (0); /* Too old, skip it. */ - if (st->st_ctime == bsdtar->newer_ctime_sec - && ARCHIVE_STAT_CTIME_NANOS(st) - <= bsdtar->newer_ctime_nsec) - return (0); /* Too old, skip it. */ - } - if (bsdtar->newer_mtime_filter) { - if (st->st_mtime < bsdtar->newer_mtime_sec) - return (0); /* Too old, skip it. */ - if (st->st_mtime == bsdtar->newer_mtime_sec - && ARCHIVE_STAT_MTIME_NANOS(st) - <= bsdtar->newer_mtime_nsec) - return (0); /* Too old, skip it. */ - } - - /* - * In -u mode, we only write an entry if it's newer than - * what was already in the archive. - */ - if (bsdtar->archive_dir != NULL && - bsdtar->archive_dir->head != NULL) { - for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) { - if (pathcmp(path, p->name)==0) - return (p->mtime_sec < st->st_mtime || - (p->mtime_sec == st->st_mtime && - p->mtime_nsec - < ARCHIVE_STAT_MTIME_NANOS(st))); - } - } - - /* If the file wasn't rejected, include it. */ - return (1); -} - -/* - * Add an entry to the dir list for 'u' mode. - * - * XXX TODO: Make this fast. - */ -static void -add_dir_list(struct bsdtar *bsdtar, const char *path, - time_t mtime_sec, int mtime_nsec) -{ - struct archive_dir_entry *p; - - /* - * Search entire list to see if this file has appeared before. - * If it has, override the timestamp data. - */ - p = bsdtar->archive_dir->head; - while (p != NULL) { - if (strcmp(path, p->name)==0) { - p->mtime_sec = mtime_sec; - p->mtime_nsec = mtime_nsec; - return; - } - p = p->next; - } - - p = malloc(sizeof(*p)); - if (p == NULL) - lafe_errc(1, ENOMEM, "Can't read archive directory"); - - p->name = strdup(path); - if (p->name == NULL) - lafe_errc(1, ENOMEM, "Can't read archive directory"); - p->mtime_sec = mtime_sec; - p->mtime_nsec = mtime_nsec; - p->next = NULL; - if (bsdtar->archive_dir->tail == NULL) { - bsdtar->archive_dir->head = bsdtar->archive_dir->tail = p; - } else { - bsdtar->archive_dir->tail->next = p; - bsdtar->archive_dir->tail = p; - } -} - static void test_for_append(struct bsdtar *bsdtar) { |