diff options
-rw-r--r-- | Makefile.am | 8 | ||||
-rw-r--r-- | cpio/CMakeLists.txt | 2 | ||||
-rw-r--r-- | cpio/cpio.c | 21 | ||||
-rw-r--r-- | cpio/cpio.h | 2 | ||||
-rw-r--r-- | cpio/test/CMakeLists.txt | 2 | ||||
-rw-r--r-- | cpio/test/test_pathmatch.c | 243 | ||||
-rw-r--r-- | libarchive/archive_pathmatch.h | 2 | ||||
-rw-r--r-- | libarchive/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libarchive/test/test_archive_pathmatch.c | 244 | ||||
-rw-r--r-- | libarchive_fe/matching.c | 222 | ||||
-rw-r--r-- | libarchive_fe/matching.h | 14 | ||||
-rw-r--r-- | libarchive_fe/pathmatch.c | 255 | ||||
-rw-r--r-- | libarchive_fe/pathmatch.h | 42 | ||||
-rw-r--r-- | tar/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tar/bsdtar.c | 93 | ||||
-rw-r--r-- | tar/bsdtar.h | 8 | ||||
-rw-r--r-- | tar/read.c | 74 | ||||
-rw-r--r-- | tar/write.c | 110 |
18 files changed, 349 insertions, 996 deletions
diff --git a/Makefile.am b/Makefile.am index 3cac4263..56ee8634 100644 --- a/Makefile.am +++ b/Makefile.am @@ -261,6 +261,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_archive_matching_owner.c \ libarchive/test/test_archive_matching_path.c \ libarchive/test/test_archive_matching_time.c \ + libarchive/test/test_archive_pathmatch.c \ libarchive/test/test_archive_read_close_twice.c \ libarchive/test/test_archive_read_close_twice_open_fd.c \ libarchive/test/test_archive_read_close_twice_open_filename.c \ @@ -580,9 +581,7 @@ libarchive_fe_la_SOURCES= \ libarchive_fe/line_reader.c \ libarchive_fe/line_reader.h \ libarchive_fe/matching.c \ - libarchive_fe/matching.h \ - libarchive_fe/pathmatch.c \ - libarchive_fe/pathmatch.h + libarchive_fe/matching.h # # @@ -789,8 +788,7 @@ bsdcpio_test_SOURCES= \ cpio/test/test_option_z.c \ cpio/test/test_owner_parse.c \ cpio/test/test_passthrough_dotdot.c \ - cpio/test/test_passthrough_reverse.c \ - cpio/test/test_pathmatch.c + cpio/test/test_passthrough_reverse.c bsdcpio_test_CPPFLAGS= \ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ diff --git a/cpio/CMakeLists.txt b/cpio/CMakeLists.txt index ce500b1c..98e34496 100644 --- a/cpio/CMakeLists.txt +++ b/cpio/CMakeLists.txt @@ -17,8 +17,6 @@ IF(ENABLE_CPIO) ../libarchive_fe/line_reader.h ../libarchive_fe/matching.c ../libarchive_fe/matching.h - ../libarchive_fe/pathmatch.c - ../libarchive_fe/pathmatch.h ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe) IF(WIN32 AND NOT CYGWIN) diff --git a/cpio/cpio.c b/cpio/cpio.c index 025c50cf..c919d380 100644 --- a/cpio/cpio.c +++ b/cpio/cpio.c @@ -189,6 +189,10 @@ main(int argc, char *argv[]) cpio->bytes_per_block = 512; cpio->filename = NULL; + cpio->matching = archive_matching_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 */ @@ -215,14 +219,17 @@ main(int argc, char *argv[]) cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR; break; case 'E': /* NetBSD/OpenBSD */ - lafe_include_from_file(&cpio->matching, + lafe_include_from_file(cpio->matching, cpio->argument, cpio->option_null); break; case 'F': /* NetBSD/OpenBSD/GNU cpio */ cpio->filename = cpio->argument; break; case 'f': /* POSIX 1997 */ - lafe_exclude(&cpio->matching, cpio->argument); + if (archive_matching_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; @@ -384,7 +391,10 @@ main(int argc, char *argv[]) break; case 'i': while (*cpio->argv != NULL) { - lafe_include(&cpio->matching, *cpio->argv); + if (archive_matching_include_pattern(cpio->matching, + *cpio->argv) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(cpio->matching)); --cpio->argc; ++cpio->argv; } @@ -404,6 +414,7 @@ main(int argc, char *argv[]) "Must specify at least one of -i, -o, or -p"); } + archive_matching_free(cpio->matching); free_cache(cpio->gname_cache); free_cache(cpio->uname_cache); return (cpio->return_value); @@ -869,7 +880,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_matching_path_excluded_ae(cpio->matching, entry)) continue; if (cpio->option_rename) { destpath = cpio_rename(archive_entry_pathname(entry)); @@ -971,7 +982,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_matching_path_excluded_ae(cpio->matching, entry)) continue; if (cpio->verbose) list_item_verbose(cpio, entry); diff --git a/cpio/cpio.h b/cpio/cpio.h index dc68e66a..9e5af674 100644 --- a/cpio/cpio.h +++ b/cpio/cpio.h @@ -88,7 +88,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/cpio/test/CMakeLists.txt b/cpio/test/CMakeLists.txt index 2196c19a..a06ae049 100644 --- a/cpio/test/CMakeLists.txt +++ b/cpio/test/CMakeLists.txt @@ -7,7 +7,6 @@ IF(ENABLE_CPIO AND ENABLE_TEST) SET(bsdcpio_test_SOURCES ../cmdline.c ../../libarchive_fe/err.c - ../../libarchive_fe/pathmatch.c main.c test.h test_0.c @@ -37,7 +36,6 @@ IF(ENABLE_CPIO AND ENABLE_TEST) test_owner_parse.c test_passthrough_dotdot.c test_passthrough_reverse.c - test_pathmatch.c ) # diff --git a/cpio/test/test_pathmatch.c b/cpio/test/test_pathmatch.c deleted file mode 100644 index 177c2bcc..00000000 --- a/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/libarchive/archive_pathmatch.h b/libarchive/archive_pathmatch.h index 259599ac..e6901774 100644 --- a/libarchive/archive_pathmatch.h +++ b/libarchive/archive_pathmatch.h @@ -27,8 +27,10 @@ */ #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 diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 4c970553..479681cd 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -18,6 +18,7 @@ IF(ENABLE_TEST) test_archive_matching_owner.c test_archive_matching_path.c test_archive_matching_time.c + test_archive_pathmatch.c test_archive_read_close_twice.c test_archive_read_close_twice_open_fd.c test_archive_read_close_twice_open_filename.c diff --git a/libarchive/test/test_archive_pathmatch.c b/libarchive/test/test_archive_pathmatch.c new file mode 100644 index 00000000..fed6ad78 --- /dev/null +++ b/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/libarchive_fe/matching.c b/libarchive_fe/matching.c index 4ba60822..be454b5b 100644 --- a/libarchive_fe/matching.c +++ b/libarchive_fe/matching.c @@ -29,61 +29,17 @@ __FBSDID("$FreeBSD: src/usr.bin/cpio/matching.c,v 1.2 2008/06/21 02:20:20 kientz #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) +lafe_exclude_from_file(struct archive *matching, const char *pathname) { struct lafe_line_reader *lr; const char *p; @@ -91,27 +47,16 @@ lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname) lr = lafe_line_reader(pathname, 0); while ((p = lafe_line_reader_next(lr)) != NULL) { - if (lafe_exclude(matching, p) != 0) - ret = -1; + ret = archive_matching_exclude_pattern(matching, p); + if (ret == ARCHIVE_FATAL) + lafe_errc(1, errno, "Out of memory"); } 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, +lafe_include_from_file(struct archive *matching, const char *pathname, int nullSeparator) { struct lafe_line_reader *lr; @@ -120,162 +65,11 @@ lafe_include_from_file(struct lafe_matching **matching, const char *pathname, lr = lafe_line_reader(pathname, nullSeparator); while ((p = lafe_line_reader_next(lr)) != NULL) { - if (lafe_include(matching, p) != 0) - ret = -1; + ret = archive_matching_include_pattern(matching, p); + if (ret == ARCHIVE_FATAL) + lafe_errc(1, errno, "Out of memory"); } 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/libarchive_fe/matching.h b/libarchive_fe/matching.h index f4edebd4..4c174a84 100644 --- a/libarchive_fe/matching.h +++ b/libarchive_fe/matching.h @@ -29,18 +29,10 @@ #ifndef MATCHING_H #define MATCHING_H -struct lafe_matching; +#include "archive.h" -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, +int lafe_exclude_from_file(struct archive *, const char *pathname); +int lafe_include_from_file(struct archive *, const char *pathname, int nullSeparator); -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); - #endif diff --git a/libarchive_fe/pathmatch.c b/libarchive_fe/pathmatch.c deleted file mode 100644 index ff8a1050..00000000 --- a/libarchive_fe/pathmatch.c +++ /dev/null @@ -1,255 +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 - * in this position and unchanged. - * 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_STRING_H -#include <string.h> -#endif - -#include "pathmatch.h" - -/* - * Check whether a character 'c' is matched by a list specification [...]: - * * Leading '!' or '^' negates the class. - * * <char>-<char> is a range of characters - * * \<char> removes any special meaning for <char> - * - * Some interesting boundary cases: - * a-d-e is one range (a-d) followed by two single characters - and e. - * \a-\d is same as a-d - * a\-d is three single characters: a, d, - - * Trailing - is not special (so [a-] is two characters a and -). - * Initial - is not special ([a-] is same as [-a] is same as [\\-a]) - * This function never sees a trailing \. - * [] always fails - * [!] always succeeds - */ -static int -pm_list(const char *start, const char *end, const char c, int flags) -{ - const char *p = start; - char rangeStart = '\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 == '!' || *p == '^') && p < end) { - match = 0; - nomatch = 1; - ++p; - } - - while (p < end) { - nextRangeStart = '\0'; - switch (*p) { - case '-': - /* Trailing or initial '-' is not special. */ - if ((rangeStart == '\0') || (p == end - 1)) { - if (*p == c) - return (match); - } else { - char rangeEnd = *++p; - if (rangeEnd == '\\') - rangeEnd = *++p; - if ((rangeStart <= c) && (c <= rangeEnd)) - return (match); - } - break; - case '\\': - ++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. - */ -static const char * -pm_slashskip(const char *s) { - while ((*s == '/') - || (s[0] == '.' && s[1] == '/') - || (s[0] == '.' && s[1] == '\0')) - ++s; - return (s); -} - -static int -pm(const char *p, const char *s, int flags) -{ - const char *end; - - /* - * Ignore leading './', './/', '././', etc. - */ - if (s[0] == '.' && s[1] == '/') - s = pm_slashskip(s + 1); - if (p[0] == '.' && p[1] == '/') - p = pm_slashskip(p + 1); - - for (;;) { - switch (*p) { - case '\0': - if (s[0] == '/') { - if (flags & PATHMATCH_NO_ANCHOR_END) - return (1); - /* "dir" == "dir/" == "dir/." */ - s = pm_slashskip(s); - } - return (*s == '\0'); - case '?': - /* ? always succeeds, unless we hit end of 's' */ - if (*s == '\0') - return (0); - break; - case '*': - /* "*" == "**" == "***" ... */ - while (*p == '*') - ++p; - /* Trailing '*' always succeeds. */ - if (*p == '\0') - return (1); - while (*s) { - if (lafe_pathmatch(p, s, flags)) - return (1); - ++s; - } - return (0); - case '[': - /* - * Find the end of the [...] character class, - * ignoring \] that might occur within the class. - */ - end = p + 1; - while (*end != '\0' && *end != ']') { - if (*end == '\\' && end[1] != '\0') - ++end; - ++end; - } - if (*end == ']') { - /* We found [...], try to match it. */ - if (!pm_list(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 '\\': - /* Trailing '\\' matches itself. */ - if (p[1] == '\0') { - if (*s != '\\') - return (0); - } else { - ++p; - if (*p != *s) - return (0); - } - break; - case '/': - if (*s != '/' && *s != '\0') - return (0); - /* Note: pattern "/\./" won't match "/"; - * pm_slashskip() correctly stops at backslash. */ - p = pm_slashskip(p); - s = pm_slashskip(s); - if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)) - return (1); - --p; /* Counteract the increment below. */ - --s; - break; - case '$': - /* '$' is special only at end of pattern and only - * if PATHMATCH_NO_ANCHOR_END is specified. */ - if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ - /* "dir" == "dir/" == "dir/." */ - return (*pm_slashskip(s) == '\0'); - } - /* Otherwise, '$' is not special. */ - /* FALL THROUGH */ - default: - if (*p != *s) - return (0); - break; - } - ++p; - ++s; - } -} - -/* Main entry point. */ -int -lafe_pathmatch(const char *p, const char *s, int flags) -{ - /* Empty pattern only matches the empty string. */ - if (p == NULL || *p == '\0') - return (s == NULL || *s == '\0'); - - /* Leading '^' anchors the start of the pattern. */ - if (*p == '^') { - ++p; - flags &= ~PATHMATCH_NO_ANCHOR_START; - } - - if (*p == '/' && *s != '/') - return (0); - - /* Certain patterns and file names anchor implicitly. */ - if (*p == '*' || *p == '/' || *p == '/') { - while (*p == '/') - ++p; - while (*s == '/') - ++s; - return (pm(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 = strchr(s, '/')) { - if (*s == '/') - s++; - if (pm(p, s, flags)) - return (1); - } - return (0); - } - - /* Default: Match from beginning. */ - return (pm(p, s, flags)); -} diff --git a/libarchive_fe/pathmatch.h b/libarchive_fe/pathmatch.h deleted file mode 100644 index a92f3aef..00000000 --- a/libarchive_fe/pathmatch.h +++ /dev/null @@ -1,42 +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 - * in this position and unchanged. - * 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$ - */ - -#ifndef LAFE_PATHMATCH_H -#define LAFE_PATHMATCH_H - -/* Don't anchor at beginning unless the pattern starts with "^" */ -#define PATHMATCH_NO_ANCHOR_START 1 -/* Don't anchor at end unless the pattern ends with "$" */ -#define PATHMATCH_NO_ANCHOR_END 2 - -/* Note that "^" and "$" are not special unless you set the corresponding - * flag above. */ - -int lafe_pathmatch(const char *p, const char *s, int flags); - -#endif diff --git a/tar/CMakeLists.txt b/tar/CMakeLists.txt index b3b931e9..39b336cd 100644 --- a/tar/CMakeLists.txt +++ b/tar/CMakeLists.txt @@ -22,8 +22,6 @@ IF(ENABLE_TAR) ../libarchive_fe/line_reader.h ../libarchive_fe/matching.c ../libarchive_fe/matching.h - ../libarchive_fe/pathmatch.c - ../libarchive_fe/pathmatch.h ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe) IF(WIN32 AND NOT CYGWIN) diff --git a/tar/bsdtar.c b/tar/bsdtar.c index 5f89959c..a2d4617f 100644 --- a/tar/bsdtar.c +++ b/tar/bsdtar.c @@ -121,7 +121,6 @@ need_report(void) /* External function to parse a date/time string */ time_t get_date(time_t, const char *); -static int get_filetime(const char *, int, time_t *, long *); static void long_help(void); static void only_mode(struct bsdtar *, const char *opt, const char *valid); @@ -247,6 +246,9 @@ main(int argc, char **argv) if (getenv(COPYFILE_DISABLE_VAR)) bsdtar->enable_copyfile = 0; #endif + bsdtar->matching = archive_matching_new(); + if (bsdtar->matching == NULL) + lafe_errc(1, errno, "Out of memory"); bsdtar->argv = argv; bsdtar->argc = argc; @@ -291,7 +293,8 @@ main(int argc, char **argv) bsdtar->enable_copyfile = 0; break; case OPTION_EXCLUDE: /* GNU tar */ - if (lafe_exclude(&bsdtar->matching, bsdtar->argument)) + if (archive_matching_exclude_pattern( + bsdtar->matching, bsdtar->argument) != ARCHIVE_OK) lafe_errc(1, 0, "Couldn't exclude %s\n", bsdtar->argument); break; @@ -342,7 +345,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_matching_include_pattern(bsdtar->matching, + bsdtar->argument) != ARCHIVE_OK) lafe_errc(1, 0, "Failed to add %s to inclusion list", bsdtar->argument); @@ -396,30 +400,28 @@ 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_matching_newer_ctime(bsdtar->matching, + get_date(now, bsdtar->argument), 0) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); break; case OPTION_NEWER_CTIME_THAN: - if (get_filetime(bsdtar->argument, 1/*ctime*/, - &bsdtar->newer_ctime_sec, - &bsdtar->newer_ctime_nsec) == 0) - bsdtar->newer_ctime_filter = 1; - else - lafe_errc(1, 0, - "Can't open file %s", bsdtar->argument); + if (archive_matching_newer_ctime_than(bsdtar->matching, + 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_matching_newer_mtime(bsdtar->matching, + get_date(now, bsdtar->argument), 0) != ARCHIVE_OK) + lafe_errc(1, 0, "Error : %s", + archive_error_string(bsdtar->matching)); break; case OPTION_NEWER_MTIME_THAN: - if (get_filetime(bsdtar->argument, 0/*mtime*/, - &bsdtar->newer_mtime_sec, - &bsdtar->newer_mtime_nsec) == 0) - bsdtar->newer_mtime_filter = 1; - else - lafe_errc(1, 0, - "Can't open file %s", bsdtar->argument); + if (archive_matching_newer_mtime_than(bsdtar->matching, + 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; @@ -554,7 +556,8 @@ main(int argc, char **argv) bsdtar->option_interactive = 1; break; case 'X': /* GNU tar */ - if (lafe_exclude_from_file(&bsdtar->matching, bsdtar->argument)) + if (lafe_exclude_from_file(bsdtar->matching, + bsdtar->argument)) lafe_errc(1, 0, "failed to process exclusions from file %s", bsdtar->argument); @@ -679,7 +682,7 @@ main(int argc, char **argv) break; } - lafe_cleanup_exclusions(&bsdtar->matching); + archive_matching_free(bsdtar->matching); #if HAVE_REGEX_H cleanup_substitution(bsdtar); #endif @@ -690,50 +693,6 @@ main(int argc, char **argv) return (bsdtar->return_value); } -static int -get_filetime(const char *path, int is_ctime, time_t *time, long *ns) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* NOTE: stat() on Windows cannot handle nano seconds. */ -#define EPOC_TIME (116444736000000000ui64) - HANDLE h; - WIN32_FIND_DATA d; - ULARGE_INTEGER utc; - - h = FindFirstFile(path, &d); - if (h == INVALID_HANDLE_VALUE) - return (-1); - FindClose(h); - if (is_ctime) { - utc.HighPart = d.ftCreationTime.dwHighDateTime; - utc.LowPart = d.ftCreationTime.dwLowDateTime; - } else { - utc.HighPart = d.ftLastWriteTime.dwHighDateTime; - utc.LowPart = d.ftLastWriteTime.dwLowDateTime; - } - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - *time = (time_t)(utc.QuadPart / 10000000); - *ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - *time = 0; - *ns = 0; - } -#else - struct stat st; - if (stat(path, &st) != 0) - return (-1); - if (is_ctime) { - *time = st.st_ctime; - *ns = ARCHIVE_STAT_CTIME_NANOS(&st); - } else { - *time = st.st_mtime; - *ns = ARCHIVE_STAT_MTIME_NANOS(&st); - } -#endif - return (0); -} - static void set_mode(struct bsdtar *bsdtar, char opt) { diff --git a/tar/bsdtar.h b/tar/bsdtar.h index 9c8bf7f0..a85e9364 100644 --- a/tar/bsdtar.h +++ b/tar/bsdtar.h @@ -46,12 +46,6 @@ 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 */ @@ -112,7 +106,7 @@ struct bsdtar { char *buff; /* for write.c */ size_t buff_size; /* for write.c */ int first_fs; /* for write.c */ - struct lafe_matching *matching; /* for matching.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 */ @@ -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,16 +156,17 @@ 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_matching_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, + lafe_include_from_file(bsdtar->matching, bsdtar->names_from_file, bsdtar->option_null); a = archive_read_new(); @@ -199,7 +204,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_matching_path_unmatched_inclusions(bsdtar->matching) == 0) break; r = archive_read_next_header(a, &entry); @@ -234,38 +239,8 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer) /* * 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. */ - } + if (archive_matching_time_excluded_ae(bsdtar->matching, entry)) + continue; /* skip it. */ /* * Note that pattern exclusions are checked before @@ -276,7 +251,8 @@ 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_matching_path_excluded_ae(bsdtar->matching, + entry)) continue; /* Excluded by a pattern test. */ if (mode == 't') { @@ -471,3 +447,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_matching_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_matching_path_unmatched_inclusions(matching)); +} diff --git a/tar/write.c b/tar/write.c index 99d4d78f..c3a70161 100644 --- a/tar/write.c +++ b/tar/write.c @@ -93,8 +93,6 @@ 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 *, @@ -106,7 +104,6 @@ static int copy_file_data_block(struct bsdtar *, struct archive_entry *); static int name_filter(struct archive *, void *, struct archive_entry *); -static int new_enough(struct bsdtar *, struct archive_entry *); static void report_write(struct bsdtar *, struct archive *, struct archive_entry *, int64_t progress); static void test_for_append(struct bsdtar *); @@ -345,9 +342,10 @@ 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_matching_pathname_newer_mtime_ae(bsdtar->matching, + 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 */ @@ -593,10 +591,11 @@ 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, in_entry)) + if (archive_matching_time_excluded_ae(bsdtar->matching, + in_entry)) continue; - if (lafe_excluded(bsdtar->matching, - archive_entry_pathname(in_entry))) + if (archive_matching_path_excluded_ae(bsdtar->matching, + in_entry)) continue; if (bsdtar->option_interactive && !yes("copy '%s'", archive_entry_pathname(in_entry))) @@ -718,7 +717,7 @@ name_filter(struct archive *a, void *_data, struct archive_entry *entry) * If this file/dir is excluded by a filename * pattern, skip it. */ - if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry))) + if (archive_matching_path_excluded_ae(bsdtar->matching, entry)) return (0); return (1); } @@ -732,7 +731,7 @@ metadata_filter(struct archive *a, void *_data, struct archive_entry *entry) * 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, entry)) { + if (archive_matching_time_excluded_ae(bsdtar->matching, entry)) { if (bsdtar->option_no_subdirs) return (0); if (!archive_read_disk_can_descend(a)) @@ -943,95 +942,6 @@ report_write(struct bsdtar *bsdtar, struct archive *a, tar_i64toa(archive_entry_size(entry))); } -/* - * Test if the specified file is new enough to include in the archive. - */ -static int -new_enough(struct bsdtar *bsdtar, struct archive_entry *e) -{ - struct archive_dir_entry *p; - - /* - * If this file/dir is excluded by a time comparison, skip it. - */ - if (bsdtar->newer_ctime_filter) { - if (archive_entry_ctime(e) < bsdtar->newer_ctime_sec) - return (0); /* Too old, skip it. */ - if (archive_entry_ctime(e) == bsdtar->newer_ctime_sec - && archive_entry_ctime_nsec(e) <= bsdtar->newer_ctime_nsec) - return (0); /* Too old, skip it. */ - } - if (bsdtar->newer_mtime_filter) { - if (archive_entry_mtime(e) < bsdtar->newer_mtime_sec) - return (0); /* Too old, skip it. */ - if (archive_entry_mtime(e) == bsdtar->newer_mtime_sec - && archive_entry_mtime_nsec(e) <= 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) { - const char *path = archive_entry_pathname(e); - for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) { - if (pathcmp(path, p->name)==0) - return (p->mtime_sec < archive_entry_mtime(e) || - (p->mtime_sec == archive_entry_mtime(e) && - p->mtime_nsec - < archive_entry_mtime_nsec(e))); - } - } - - /* 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) { |