2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2012 Michihiro NAKAJIMA
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD$");
41 #include "archive_private.h"
42 #include "archive_entry.h"
43 #include "archive_getdate.h"
44 #include "archive_pathmatch.h"
45 #include "archive_rb.h"
46 #include "archive_string.h"
51 struct archive_mstring pattern;
59 struct match *unmatched_next;
64 struct archive_rb_node node;
65 struct match_file *next;
66 struct archive_mstring pathname;
75 struct match_file *first;
76 struct match_file **last;
81 size_t size;/* Allocated size */
86 #define PATTERN_IS_SET 1
90 struct archive_match {
91 struct archive archive;
93 /* exclusion/inclusion set flag. */
96 /* Recursively include directory content? */
97 int recursive_include;
100 * Matching filename patterns.
102 struct match_list exclusions;
103 struct match_list inclusions;
106 * Matching time stamps.
109 int newer_mtime_filter;
110 time_t newer_mtime_sec;
111 long newer_mtime_nsec;
112 int newer_ctime_filter;
113 time_t newer_ctime_sec;
114 long newer_ctime_nsec;
115 int older_mtime_filter;
116 time_t older_mtime_sec;
117 long older_mtime_nsec;
118 int older_ctime_filter;
119 time_t older_ctime_sec;
120 long older_ctime_nsec;
122 * Matching time stamps with its filename.
124 struct archive_rb_tree exclusion_tree;
125 struct entry_list exclusion_entry_list;
128 * Matching file owners.
130 struct id_array inclusion_uids;
131 struct id_array inclusion_gids;
132 struct match_list inclusion_unames;
133 struct match_list inclusion_gnames;
136 static int add_pattern_from_file(struct archive_match *,
137 struct match_list *, int, const void *, int);
138 static int add_entry(struct archive_match *, int,
139 struct archive_entry *);
140 static int add_owner_id(struct archive_match *, struct id_array *,
142 static int add_owner_name(struct archive_match *, struct match_list *,
144 static int add_pattern_mbs(struct archive_match *, struct match_list *,
146 static int add_pattern_wcs(struct archive_match *, struct match_list *,
148 static int cmp_key_mbs(const struct archive_rb_node *, const void *);
149 static int cmp_key_wcs(const struct archive_rb_node *, const void *);
150 static int cmp_node_mbs(const struct archive_rb_node *,
151 const struct archive_rb_node *);
152 static int cmp_node_wcs(const struct archive_rb_node *,
153 const struct archive_rb_node *);
154 static void entry_list_add(struct entry_list *, struct match_file *);
155 static void entry_list_free(struct entry_list *);
156 static void entry_list_init(struct entry_list *);
157 static int error_nomem(struct archive_match *);
158 static void match_list_add(struct match_list *, struct match *);
159 static void match_list_free(struct match_list *);
160 static void match_list_init(struct match_list *);
161 static int match_list_unmatched_inclusions_next(struct archive_match *,
162 struct match_list *, int, const void **);
163 static int match_owner_id(struct id_array *, int64_t);
164 #if !defined(_WIN32) || defined(__CYGWIN__)
165 static int match_owner_name_mbs(struct archive_match *,
166 struct match_list *, const char *);
168 static int match_owner_name_wcs(struct archive_match *,
169 struct match_list *, const wchar_t *);
171 static int match_path_exclusion(struct archive_match *,
172 struct match *, int, const void *);
173 static int match_path_inclusion(struct archive_match *,
174 struct match *, int, const void *);
175 static int owner_excluded(struct archive_match *,
176 struct archive_entry *);
177 static int path_excluded(struct archive_match *, int, const void *);
178 static int set_timefilter(struct archive_match *, int, time_t, long,
180 static int set_timefilter_pathname_mbs(struct archive_match *,
182 static int set_timefilter_pathname_wcs(struct archive_match *,
183 int, const wchar_t *);
184 static int set_timefilter_date(struct archive_match *, int, const char *);
185 static int set_timefilter_date_w(struct archive_match *, int,
187 static int time_excluded(struct archive_match *,
188 struct archive_entry *);
189 static int validate_time_flag(struct archive *, int, const char *);
191 #define get_date __archive_get_date
193 static const struct archive_rb_tree_ops rb_ops_mbs = {
194 cmp_node_mbs, cmp_key_mbs
197 static const struct archive_rb_tree_ops rb_ops_wcs = {
198 cmp_node_wcs, cmp_key_wcs
202 * The matching logic here needs to be re-thought. I started out to
203 * try to mimic gtar's matching logic, but it's not entirely
204 * consistent. In particular 'tar -t' and 'tar -x' interpret patterns
205 * on the command line as anchored, but --exclude doesn't.
209 error_nomem(struct archive_match *a)
211 archive_set_error(&(a->archive), ENOMEM, "No memory");
212 a->archive.state = ARCHIVE_STATE_FATAL;
213 return (ARCHIVE_FATAL);
217 * Create an ARCHIVE_MATCH object.
220 archive_match_new(void)
222 struct archive_match *a;
224 a = (struct archive_match *)calloc(1, sizeof(*a));
227 a->archive.magic = ARCHIVE_MATCH_MAGIC;
228 a->archive.state = ARCHIVE_STATE_NEW;
229 a->recursive_include = 1;
230 match_list_init(&(a->inclusions));
231 match_list_init(&(a->exclusions));
232 __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
233 entry_list_init(&(a->exclusion_entry_list));
234 match_list_init(&(a->inclusion_unames));
235 match_list_init(&(a->inclusion_gnames));
237 return (&(a->archive));
241 * Free an ARCHIVE_MATCH object.
244 archive_match_free(struct archive *_a)
246 struct archive_match *a;
250 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
251 ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free");
252 a = (struct archive_match *)_a;
253 match_list_free(&(a->inclusions));
254 match_list_free(&(a->exclusions));
255 entry_list_free(&(a->exclusion_entry_list));
256 free(a->inclusion_uids.ids);
257 free(a->inclusion_gids.ids);
258 match_list_free(&(a->inclusion_unames));
259 match_list_free(&(a->inclusion_gnames));
265 * Convenience function to perform all exclusion tests.
267 * Returns 1 if archive entry is excluded.
268 * Returns 0 if archive entry is not excluded.
269 * Returns <0 if something error happened.
272 archive_match_excluded(struct archive *_a, struct archive_entry *entry)
274 struct archive_match *a;
277 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
278 ARCHIVE_STATE_NEW, "archive_match_excluded_ae");
280 a = (struct archive_match *)_a;
282 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
283 return (ARCHIVE_FAILED);
287 if (a->setflag & PATTERN_IS_SET) {
288 #if defined(_WIN32) && !defined(__CYGWIN__)
289 r = path_excluded(a, 0, archive_entry_pathname_w(entry));
291 r = path_excluded(a, 1, archive_entry_pathname(entry));
297 if (a->setflag & TIME_IS_SET) {
298 r = time_excluded(a, entry);
303 if (a->setflag & ID_IS_SET)
304 r = owner_excluded(a, entry);
309 * Utility functions to manage exclusion/inclusion patterns
313 archive_match_exclude_pattern(struct archive *_a, const char *pattern)
315 struct archive_match *a;
318 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
319 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern");
320 a = (struct archive_match *)_a;
322 if (pattern == NULL || *pattern == '\0') {
323 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
324 return (ARCHIVE_FAILED);
326 if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
332 archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern)
334 struct archive_match *a;
337 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
338 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w");
339 a = (struct archive_match *)_a;
341 if (pattern == NULL || *pattern == L'\0') {
342 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
343 return (ARCHIVE_FAILED);
345 if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
351 archive_match_exclude_pattern_from_file(struct archive *_a,
352 const char *pathname, int nullSeparator)
354 struct archive_match *a;
356 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
357 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file");
358 a = (struct archive_match *)_a;
360 return add_pattern_from_file(a, &(a->exclusions), 1, pathname,
365 archive_match_exclude_pattern_from_file_w(struct archive *_a,
366 const wchar_t *pathname, int nullSeparator)
368 struct archive_match *a;
370 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
371 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w");
372 a = (struct archive_match *)_a;
374 return add_pattern_from_file(a, &(a->exclusions), 0, pathname,
379 archive_match_include_pattern(struct archive *_a, const char *pattern)
381 struct archive_match *a;
384 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
385 ARCHIVE_STATE_NEW, "archive_match_include_pattern");
386 a = (struct archive_match *)_a;
388 if (pattern == NULL || *pattern == '\0') {
389 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
390 return (ARCHIVE_FAILED);
392 if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
398 archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern)
400 struct archive_match *a;
403 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
404 ARCHIVE_STATE_NEW, "archive_match_include_pattern_w");
405 a = (struct archive_match *)_a;
407 if (pattern == NULL || *pattern == L'\0') {
408 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
409 return (ARCHIVE_FAILED);
411 if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
417 archive_match_include_pattern_from_file(struct archive *_a,
418 const char *pathname, int nullSeparator)
420 struct archive_match *a;
422 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
423 ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file");
424 a = (struct archive_match *)_a;
426 return add_pattern_from_file(a, &(a->inclusions), 1, pathname,
431 archive_match_include_pattern_from_file_w(struct archive *_a,
432 const wchar_t *pathname, int nullSeparator)
434 struct archive_match *a;
436 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
437 ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w");
438 a = (struct archive_match *)_a;
440 return add_pattern_from_file(a, &(a->inclusions), 0, pathname,
445 * Test functions for pathname patterns.
447 * Returns 1 if archive entry is excluded.
448 * Returns 0 if archive entry is not excluded.
449 * Returns <0 if something error happened.
452 archive_match_path_excluded(struct archive *_a,
453 struct archive_entry *entry)
455 struct archive_match *a;
457 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
458 ARCHIVE_STATE_NEW, "archive_match_path_excluded");
460 a = (struct archive_match *)_a;
462 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
463 return (ARCHIVE_FAILED);
466 /* If we don't have exclusion/inclusion pattern set at all,
467 * the entry is always not excluded. */
468 if ((a->setflag & PATTERN_IS_SET) == 0)
470 #if defined(_WIN32) && !defined(__CYGWIN__)
471 return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
473 return (path_excluded(a, 1, archive_entry_pathname(entry)));
478 * When recursive inclusion of directory content is enabled,
479 * an inclusion pattern that matches a directory will also
480 * include everything beneath that directory. Enabled by default.
482 * For compatibility with GNU tar, exclusion patterns always
483 * match if a subset of the full patch matches (i.e., they are
484 * are not rooted at the beginning of the path) and thus there
485 * is no corresponding non-recursive exclusion mode.
488 archive_match_set_inclusion_recursion(struct archive *_a, int enabled)
490 struct archive_match *a;
492 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
493 ARCHIVE_STATE_NEW, "archive_match_set_inclusion_recursion");
494 a = (struct archive_match *)_a;
495 a->recursive_include = enabled;
500 * Utility functions to get statistic information for inclusion patterns.
503 archive_match_path_unmatched_inclusions(struct archive *_a)
505 struct archive_match *a;
507 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
508 ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
509 a = (struct archive_match *)_a;
511 return (a->inclusions.unmatched_count);
515 archive_match_path_unmatched_inclusions_next(struct archive *_a,
518 struct archive_match *a;
522 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
523 ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next");
524 a = (struct archive_match *)_a;
526 r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v);
527 *_p = (const char *)v;
532 archive_match_path_unmatched_inclusions_next_w(struct archive *_a,
535 struct archive_match *a;
539 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
540 ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w");
541 a = (struct archive_match *)_a;
543 r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v);
544 *_p = (const wchar_t *)v;
549 * Add inclusion/exclusion patterns.
552 add_pattern_mbs(struct archive_match *a, struct match_list *list,
558 match = calloc(1, sizeof(*match));
560 return (error_nomem(a));
561 /* Both "foo/" and "foo" should match "foo/bar". */
562 len = strlen(pattern);
563 if (len && pattern[len - 1] == '/')
565 archive_mstring_copy_mbs_len(&(match->pattern), pattern, len);
566 match_list_add(list, match);
567 a->setflag |= PATTERN_IS_SET;
572 add_pattern_wcs(struct archive_match *a, struct match_list *list,
573 const wchar_t *pattern)
578 match = calloc(1, sizeof(*match));
580 return (error_nomem(a));
581 /* Both "foo/" and "foo" should match "foo/bar". */
582 len = wcslen(pattern);
583 if (len && pattern[len - 1] == L'/')
585 archive_mstring_copy_wcs_len(&(match->pattern), pattern, len);
586 match_list_add(list, match);
587 a->setflag |= PATTERN_IS_SET;
592 add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
593 int mbs, const void *pathname, int nullSeparator)
596 struct archive_entry *ae;
597 struct archive_string as;
603 ar = archive_read_new();
605 archive_set_error(&(a->archive), ENOMEM, "No memory");
606 return (ARCHIVE_FATAL);
608 r = archive_read_support_format_raw(ar);
609 r = archive_read_support_format_empty(ar);
610 if (r != ARCHIVE_OK) {
611 archive_copy_error(&(a->archive), ar);
612 archive_read_free(ar);
616 r = archive_read_open_filename(ar, pathname, 512*20);
618 r = archive_read_open_filename_w(ar, pathname, 512*20);
619 if (r != ARCHIVE_OK) {
620 archive_copy_error(&(a->archive), ar);
621 archive_read_free(ar);
624 r = archive_read_next_header(ar, &ae);
625 if (r != ARCHIVE_OK) {
626 archive_read_free(ar);
627 if (r == ARCHIVE_EOF) {
630 archive_copy_error(&(a->archive), ar);
635 archive_string_init(&as);
637 while ((r = archive_read_data_block(ar, &buff, &size, &offset))
639 const char *b = (const char *)buff;
642 const char *s = (const char *)b;
644 int found_separator = 0;
646 while (length < size) {
653 if (*b == 0x0d || *b == 0x0a) {
661 if (!found_separator) {
662 archive_strncat(&as, s, length);
663 /* Read next data block. */
668 archive_strncat(&as, s, length);
670 /* If the line is not empty, add the pattern. */
671 if (archive_strlen(&as) > 0) {
673 r = add_pattern_mbs(a, mlist, as.s);
674 if (r != ARCHIVE_OK) {
675 archive_read_free(ar);
676 archive_string_free(&as);
679 archive_string_empty(&as);
684 /* If an error occurred, report it immediately. */
685 if (r < ARCHIVE_OK) {
686 archive_copy_error(&(a->archive), ar);
687 archive_read_free(ar);
688 archive_string_free(&as);
692 /* If the line is not empty, add the pattern. */
693 if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) {
695 r = add_pattern_mbs(a, mlist, as.s);
696 if (r != ARCHIVE_OK) {
697 archive_read_free(ar);
698 archive_string_free(&as);
702 archive_read_free(ar);
703 archive_string_free(&as);
708 * Test if pathname is excluded by inclusion/exclusion patterns.
711 path_excluded(struct archive_match *a, int mbs, const void *pathname)
714 struct match *matched;
720 /* Mark off any unmatched inclusions. */
721 /* In particular, if a filename does appear in the archive and
722 * is explicitly included and excluded, then we don't report
723 * it as missing even though we don't extract it.
726 for (match = a->inclusions.first; match != NULL;
727 match = match->next){
728 if (match->matches == 0 &&
729 (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
732 a->inclusions.unmatched_count--;
738 /* Exclusions take priority */
739 for (match = a->exclusions.first; match != NULL;
740 match = match->next){
741 r = match_path_exclusion(a, match, mbs, pathname);
746 /* It's not excluded and we found an inclusion above, so it's
752 /* We didn't find an unmatched inclusion, check the remaining ones. */
753 for (match = a->inclusions.first; match != NULL;
754 match = match->next){
755 /* We looked at previously-unmatched inclusions already. */
756 if (match->matches > 0 &&
757 (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
765 /* If there were inclusions, default is to exclude. */
766 if (a->inclusions.first != NULL)
769 /* No explicit inclusions, default is to match. */
774 * This is a little odd, but it matches the default behavior of
775 * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
779 match_path_exclusion(struct archive_match *a, struct match *m,
780 int mbs, const void *pn)
782 int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END;
787 r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
789 return (archive_pathmatch(p, (const char *)pn, flag));
792 r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
794 return (archive_pathmatch_w(p, (const wchar_t *)pn,
798 return (error_nomem(a));
803 * Again, mimic gtar: inclusions are always anchored (have to match
804 * the beginning of the path) even though exclusions are not anchored.
807 match_path_inclusion(struct archive_match *a, struct match *m,
808 int mbs, const void *pn)
810 /* Recursive operation requires only a prefix match. */
811 int flag = a->recursive_include ?
812 PATHMATCH_NO_ANCHOR_END :
818 r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
820 return (archive_pathmatch(p, (const char *)pn, flag));
823 r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
825 return (archive_pathmatch_w(p, (const wchar_t *)pn,
829 return (error_nomem(a));
834 match_list_init(struct match_list *list)
837 list->last = &(list->first);
842 match_list_free(struct match_list *list)
846 for (p = list->first; p != NULL; ) {
849 archive_mstring_clean(&(q->pattern));
855 match_list_add(struct match_list *list, struct match *m)
858 list->last = &(m->next);
860 list->unmatched_count++;
864 match_list_unmatched_inclusions_next(struct archive_match *a,
865 struct match_list *list, int mbs, const void **vp)
870 if (list->unmatched_eof) {
871 list->unmatched_eof = 0;
872 return (ARCHIVE_EOF);
874 if (list->unmatched_next == NULL) {
875 if (list->unmatched_count == 0)
876 return (ARCHIVE_EOF);
877 list->unmatched_next = list->first;
880 for (m = list->unmatched_next; m != NULL; m = m->next) {
887 r = archive_mstring_get_mbs(&(a->archive),
889 if (r < 0 && errno == ENOMEM)
890 return (error_nomem(a));
896 r = archive_mstring_get_wcs(&(a->archive),
898 if (r < 0 && errno == ENOMEM)
899 return (error_nomem(a));
904 list->unmatched_next = m->next;
905 if (list->unmatched_next == NULL)
906 /* To return EOF next time. */
907 list->unmatched_eof = 1;
910 list->unmatched_next = NULL;
911 return (ARCHIVE_EOF);
915 * Utility functions to manage inclusion timestamps.
918 archive_match_include_time(struct archive *_a, int flag, time_t sec,
923 r = validate_time_flag(_a, flag, "archive_match_include_time");
926 return set_timefilter((struct archive_match *)_a, flag,
927 sec, nsec, sec, nsec);
931 archive_match_include_date(struct archive *_a, int flag,
936 r = validate_time_flag(_a, flag, "archive_match_include_date");
939 return set_timefilter_date((struct archive_match *)_a, flag, datestr);
943 archive_match_include_date_w(struct archive *_a, int flag,
944 const wchar_t *datestr)
948 r = validate_time_flag(_a, flag, "archive_match_include_date_w");
952 return set_timefilter_date_w((struct archive_match *)_a, flag, datestr);
956 archive_match_include_file_time(struct archive *_a, int flag,
957 const char *pathname)
961 r = validate_time_flag(_a, flag, "archive_match_include_file_time");
964 return set_timefilter_pathname_mbs((struct archive_match *)_a,
969 archive_match_include_file_time_w(struct archive *_a, int flag,
970 const wchar_t *pathname)
974 r = validate_time_flag(_a, flag, "archive_match_include_file_time_w");
977 return set_timefilter_pathname_wcs((struct archive_match *)_a,
982 archive_match_exclude_entry(struct archive *_a, int flag,
983 struct archive_entry *entry)
985 struct archive_match *a;
988 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
989 ARCHIVE_STATE_NEW, "archive_match_time_include_entry");
990 a = (struct archive_match *)_a;
993 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
994 return (ARCHIVE_FAILED);
996 r = validate_time_flag(_a, flag, "archive_match_exclude_entry");
999 return (add_entry(a, flag, entry));
1003 * Test function for time stamps.
1005 * Returns 1 if archive entry is excluded.
1006 * Returns 0 if archive entry is not excluded.
1007 * Returns <0 if something error happened.
1010 archive_match_time_excluded(struct archive *_a,
1011 struct archive_entry *entry)
1013 struct archive_match *a;
1015 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1016 ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae");
1018 a = (struct archive_match *)_a;
1019 if (entry == NULL) {
1020 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
1021 return (ARCHIVE_FAILED);
1024 /* If we don't have inclusion time set at all, the entry is always
1026 if ((a->setflag & TIME_IS_SET) == 0)
1028 return (time_excluded(a, entry));
1032 validate_time_flag(struct archive *_a, int flag, const char *_fn)
1034 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1035 ARCHIVE_STATE_NEW, _fn);
1037 /* Check a type of time. */
1039 ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) {
1040 archive_set_error(_a, EINVAL, "Invalid time flag");
1041 return (ARCHIVE_FAILED);
1043 if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) {
1044 archive_set_error(_a, EINVAL, "No time flag");
1045 return (ARCHIVE_FAILED);
1048 /* Check a type of comparison. */
1050 ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
1051 | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) {
1052 archive_set_error(_a, EINVAL, "Invalid comparison flag");
1053 return (ARCHIVE_FAILED);
1055 if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
1056 | ARCHIVE_MATCH_EQUAL)) == 0) {
1057 archive_set_error(_a, EINVAL, "No comparison flag");
1058 return (ARCHIVE_FAILED);
1061 return (ARCHIVE_OK);
1064 #define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\
1065 ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL)
1067 set_timefilter(struct archive_match *a, int timetype,
1068 time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec)
1070 if (timetype & ARCHIVE_MATCH_MTIME) {
1071 if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
1072 a->newer_mtime_filter = timetype;
1073 a->newer_mtime_sec = mtime_sec;
1074 a->newer_mtime_nsec = mtime_nsec;
1075 a->setflag |= TIME_IS_SET;
1077 if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
1078 a->older_mtime_filter = timetype;
1079 a->older_mtime_sec = mtime_sec;
1080 a->older_mtime_nsec = mtime_nsec;
1081 a->setflag |= TIME_IS_SET;
1084 if (timetype & ARCHIVE_MATCH_CTIME) {
1085 if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
1086 a->newer_ctime_filter = timetype;
1087 a->newer_ctime_sec = ctime_sec;
1088 a->newer_ctime_nsec = ctime_nsec;
1089 a->setflag |= TIME_IS_SET;
1091 if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
1092 a->older_ctime_filter = timetype;
1093 a->older_ctime_sec = ctime_sec;
1094 a->older_ctime_nsec = ctime_nsec;
1095 a->setflag |= TIME_IS_SET;
1098 return (ARCHIVE_OK);
1102 set_timefilter_date(struct archive_match *a, int timetype, const char *datestr)
1106 if (datestr == NULL || *datestr == '\0') {
1107 archive_set_error(&(a->archive), EINVAL, "date is empty");
1108 return (ARCHIVE_FAILED);
1110 t = get_date(a->now, datestr);
1111 if (t == (time_t)-1) {
1112 archive_set_error(&(a->archive), EINVAL, "invalid date string");
1113 return (ARCHIVE_FAILED);
1115 return set_timefilter(a, timetype, t, 0, t, 0);
1119 set_timefilter_date_w(struct archive_match *a, int timetype,
1120 const wchar_t *datestr)
1122 struct archive_string as;
1125 if (datestr == NULL || *datestr == L'\0') {
1126 archive_set_error(&(a->archive), EINVAL, "date is empty");
1127 return (ARCHIVE_FAILED);
1130 archive_string_init(&as);
1131 if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) {
1132 archive_string_free(&as);
1133 if (errno == ENOMEM)
1134 return (error_nomem(a));
1135 archive_set_error(&(a->archive), -1,
1136 "Failed to convert WCS to MBS");
1137 return (ARCHIVE_FAILED);
1139 t = get_date(a->now, as.s);
1140 archive_string_free(&as);
1141 if (t == (time_t)-1) {
1142 archive_set_error(&(a->archive), EINVAL, "invalid date string");
1143 return (ARCHIVE_FAILED);
1145 return set_timefilter(a, timetype, t, 0, t, 0);
1148 #if defined(_WIN32) && !defined(__CYGWIN__)
1149 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
1151 set_timefilter_find_data(struct archive_match *a, int timetype,
1152 DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime,
1153 DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime)
1156 time_t ctime_sec, mtime_sec;
1157 long ctime_ns, mtime_ns;
1159 utc.HighPart = ftCreationTime_dwHighDateTime;
1160 utc.LowPart = ftCreationTime_dwLowDateTime;
1161 if (utc.QuadPart >= EPOC_TIME) {
1162 utc.QuadPart -= EPOC_TIME;
1163 ctime_sec = (time_t)(utc.QuadPart / 10000000);
1164 ctime_ns = (long)(utc.QuadPart % 10000000) * 100;
1169 utc.HighPart = ftLastWriteTime_dwHighDateTime;
1170 utc.LowPart = ftLastWriteTime_dwLowDateTime;
1171 if (utc.QuadPart >= EPOC_TIME) {
1172 utc.QuadPart -= EPOC_TIME;
1173 mtime_sec = (time_t)(utc.QuadPart / 10000000);
1174 mtime_ns = (long)(utc.QuadPart % 10000000) * 100;
1179 return set_timefilter(a, timetype,
1180 mtime_sec, mtime_ns, ctime_sec, ctime_ns);
1184 set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
1187 /* NOTE: stat() on Windows cannot handle nano seconds. */
1191 if (path == NULL || *path == '\0') {
1192 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1193 return (ARCHIVE_FAILED);
1195 h = FindFirstFileA(path, &d);
1196 if (h == INVALID_HANDLE_VALUE) {
1197 la_dosmaperr(GetLastError());
1198 archive_set_error(&(a->archive), errno,
1199 "Failed to FindFirstFileA");
1200 return (ARCHIVE_FAILED);
1203 return set_timefilter_find_data(a, timetype,
1204 d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
1205 d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
1209 set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
1210 const wchar_t *path)
1215 if (path == NULL || *path == L'\0') {
1216 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1217 return (ARCHIVE_FAILED);
1219 h = FindFirstFileW(path, &d);
1220 if (h == INVALID_HANDLE_VALUE) {
1221 la_dosmaperr(GetLastError());
1222 archive_set_error(&(a->archive), errno,
1223 "Failed to FindFirstFile");
1224 return (ARCHIVE_FAILED);
1227 return set_timefilter_find_data(a, timetype,
1228 d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
1229 d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
1232 #else /* _WIN32 && !__CYGWIN__ */
1235 set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st)
1237 struct archive_entry *ae;
1238 time_t ctime_sec, mtime_sec;
1239 long ctime_ns, mtime_ns;
1241 ae = archive_entry_new();
1243 return (error_nomem(a));
1244 archive_entry_copy_stat(ae, st);
1245 ctime_sec = archive_entry_ctime(ae);
1246 ctime_ns = archive_entry_ctime_nsec(ae);
1247 mtime_sec = archive_entry_mtime(ae);
1248 mtime_ns = archive_entry_mtime_nsec(ae);
1249 archive_entry_free(ae);
1250 return set_timefilter(a, timetype, mtime_sec, mtime_ns,
1251 ctime_sec, ctime_ns);
1255 set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
1260 if (path == NULL || *path == '\0') {
1261 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1262 return (ARCHIVE_FAILED);
1264 if (la_stat(path, &st) != 0) {
1265 archive_set_error(&(a->archive), errno, "Failed to stat()");
1266 return (ARCHIVE_FAILED);
1268 return (set_timefilter_stat(a, timetype, &st));
1272 set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
1273 const wchar_t *path)
1275 struct archive_string as;
1278 if (path == NULL || *path == L'\0') {
1279 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1280 return (ARCHIVE_FAILED);
1283 /* Convert WCS filename to MBS filename. */
1284 archive_string_init(&as);
1285 if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) {
1286 archive_string_free(&as);
1287 if (errno == ENOMEM)
1288 return (error_nomem(a));
1289 archive_set_error(&(a->archive), -1,
1290 "Failed to convert WCS to MBS");
1291 return (ARCHIVE_FAILED);
1294 r = set_timefilter_pathname_mbs(a, timetype, as.s);
1295 archive_string_free(&as);
1299 #endif /* _WIN32 && !__CYGWIN__ */
1302 * Call back functions for archive_rb.
1305 cmp_node_mbs(const struct archive_rb_node *n1,
1306 const struct archive_rb_node *n2)
1308 struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
1309 struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
1310 const char *p1, *p2;
1312 archive_mstring_get_mbs(NULL, &(f1->pathname), &p1);
1313 archive_mstring_get_mbs(NULL, &(f2->pathname), &p2);
1318 return (strcmp(p1, p2));
1322 cmp_key_mbs(const struct archive_rb_node *n, const void *key)
1324 struct match_file *f = (struct match_file *)(uintptr_t)n;
1327 archive_mstring_get_mbs(NULL, &(f->pathname), &p);
1330 return (strcmp(p, (const char *)key));
1334 cmp_node_wcs(const struct archive_rb_node *n1,
1335 const struct archive_rb_node *n2)
1337 struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
1338 struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
1339 const wchar_t *p1, *p2;
1341 archive_mstring_get_wcs(NULL, &(f1->pathname), &p1);
1342 archive_mstring_get_wcs(NULL, &(f2->pathname), &p2);
1347 return (wcscmp(p1, p2));
1351 cmp_key_wcs(const struct archive_rb_node *n, const void *key)
1353 struct match_file *f = (struct match_file *)(uintptr_t)n;
1356 archive_mstring_get_wcs(NULL, &(f->pathname), &p);
1359 return (wcscmp(p, (const wchar_t *)key));
1363 entry_list_init(struct entry_list *list)
1366 list->last = &(list->first);
1371 entry_list_free(struct entry_list *list)
1373 struct match_file *p, *q;
1375 for (p = list->first; p != NULL; ) {
1378 archive_mstring_clean(&(q->pathname));
1384 entry_list_add(struct entry_list *list, struct match_file *file)
1387 list->last = &(file->next);
1392 add_entry(struct archive_match *a, int flag,
1393 struct archive_entry *entry)
1395 struct match_file *f;
1396 const void *pathname;
1399 f = calloc(1, sizeof(*f));
1401 return (error_nomem(a));
1403 #if defined(_WIN32) && !defined(__CYGWIN__)
1404 pathname = archive_entry_pathname_w(entry);
1405 if (pathname == NULL) {
1407 archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
1408 return (ARCHIVE_FAILED);
1410 archive_mstring_copy_wcs(&(f->pathname), pathname);
1411 a->exclusion_tree.rbt_ops = &rb_ops_wcs;
1414 pathname = archive_entry_pathname(entry);
1415 if (pathname == NULL) {
1417 archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
1418 return (ARCHIVE_FAILED);
1420 archive_mstring_copy_mbs(&(f->pathname), pathname);
1421 a->exclusion_tree.rbt_ops = &rb_ops_mbs;
1424 f->mtime_sec = archive_entry_mtime(entry);
1425 f->mtime_nsec = archive_entry_mtime_nsec(entry);
1426 f->ctime_sec = archive_entry_ctime(entry);
1427 f->ctime_nsec = archive_entry_ctime_nsec(entry);
1428 r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node));
1430 struct match_file *f2;
1432 /* Get the duplicated file. */
1433 f2 = (struct match_file *)__archive_rb_tree_find_node(
1434 &(a->exclusion_tree), pathname);
1437 * We always overwrite comparison condition.
1438 * If you do not want to overwrite it, you should not
1439 * call archive_match_exclude_entry(). We cannot know
1440 * what behavior you really expect since overwriting
1441 * condition might be different with the flag.
1445 f2->mtime_sec = f->mtime_sec;
1446 f2->mtime_nsec = f->mtime_nsec;
1447 f2->ctime_sec = f->ctime_sec;
1448 f2->ctime_nsec = f->ctime_nsec;
1450 /* Release the duplicated file. */
1451 archive_mstring_clean(&(f->pathname));
1453 return (ARCHIVE_OK);
1455 entry_list_add(&(a->exclusion_entry_list), f);
1456 a->setflag |= TIME_IS_SET;
1457 return (ARCHIVE_OK);
1461 * Test if entry is excluded by its timestamp.
1464 time_excluded(struct archive_match *a, struct archive_entry *entry)
1466 struct match_file *f;
1467 const void *pathname;
1472 * If this file/dir is excluded by a time comparison, skip it.
1474 if (a->newer_ctime_filter) {
1475 /* If ctime is not set, use mtime instead. */
1476 if (archive_entry_ctime_is_set(entry))
1477 sec = archive_entry_ctime(entry);
1479 sec = archive_entry_mtime(entry);
1480 if (sec < a->newer_ctime_sec)
1481 return (1); /* Too old, skip it. */
1482 if (sec == a->newer_ctime_sec) {
1483 if (archive_entry_ctime_is_set(entry))
1484 nsec = archive_entry_ctime_nsec(entry);
1486 nsec = archive_entry_mtime_nsec(entry);
1487 if (nsec < a->newer_ctime_nsec)
1488 return (1); /* Too old, skip it. */
1489 if (nsec == a->newer_ctime_nsec &&
1490 (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL)
1492 return (1); /* Equal, skip it. */
1495 if (a->older_ctime_filter) {
1496 /* If ctime is not set, use mtime instead. */
1497 if (archive_entry_ctime_is_set(entry))
1498 sec = archive_entry_ctime(entry);
1500 sec = archive_entry_mtime(entry);
1501 if (sec > a->older_ctime_sec)
1502 return (1); /* Too new, skip it. */
1503 if (sec == a->older_ctime_sec) {
1504 if (archive_entry_ctime_is_set(entry))
1505 nsec = archive_entry_ctime_nsec(entry);
1507 nsec = archive_entry_mtime_nsec(entry);
1508 if (nsec > a->older_ctime_nsec)
1509 return (1); /* Too new, skip it. */
1510 if (nsec == a->older_ctime_nsec &&
1511 (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
1513 return (1); /* Equal, skip it. */
1516 if (a->newer_mtime_filter) {
1517 sec = archive_entry_mtime(entry);
1518 if (sec < a->newer_mtime_sec)
1519 return (1); /* Too old, skip it. */
1520 if (sec == a->newer_mtime_sec) {
1521 nsec = archive_entry_mtime_nsec(entry);
1522 if (nsec < a->newer_mtime_nsec)
1523 return (1); /* Too old, skip it. */
1524 if (nsec == a->newer_mtime_nsec &&
1525 (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL)
1527 return (1); /* Equal, skip it. */
1530 if (a->older_mtime_filter) {
1531 sec = archive_entry_mtime(entry);
1532 if (sec > a->older_mtime_sec)
1533 return (1); /* Too new, skip it. */
1534 nsec = archive_entry_mtime_nsec(entry);
1535 if (sec == a->older_mtime_sec) {
1536 if (nsec > a->older_mtime_nsec)
1537 return (1); /* Too new, skip it. */
1538 if (nsec == a->older_mtime_nsec &&
1539 (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL)
1541 return (1); /* Equal, skip it. */
1545 /* If there is no exclusion list, include the file. */
1546 if (a->exclusion_entry_list.count == 0)
1549 #if defined(_WIN32) && !defined(__CYGWIN__)
1550 pathname = archive_entry_pathname_w(entry);
1551 a->exclusion_tree.rbt_ops = &rb_ops_wcs;
1554 pathname = archive_entry_pathname(entry);
1555 a->exclusion_tree.rbt_ops = &rb_ops_mbs;
1557 if (pathname == NULL)
1560 f = (struct match_file *)__archive_rb_tree_find_node(
1561 &(a->exclusion_tree), pathname);
1562 /* If the file wasn't rejected, include it. */
1566 if (f->flag & ARCHIVE_MATCH_CTIME) {
1567 sec = archive_entry_ctime(entry);
1568 if (f->ctime_sec > sec) {
1569 if (f->flag & ARCHIVE_MATCH_OLDER)
1571 } else if (f->ctime_sec < sec) {
1572 if (f->flag & ARCHIVE_MATCH_NEWER)
1575 nsec = archive_entry_ctime_nsec(entry);
1576 if (f->ctime_nsec > nsec) {
1577 if (f->flag & ARCHIVE_MATCH_OLDER)
1579 } else if (f->ctime_nsec < nsec) {
1580 if (f->flag & ARCHIVE_MATCH_NEWER)
1582 } else if (f->flag & ARCHIVE_MATCH_EQUAL)
1586 if (f->flag & ARCHIVE_MATCH_MTIME) {
1587 sec = archive_entry_mtime(entry);
1588 if (f->mtime_sec > sec) {
1589 if (f->flag & ARCHIVE_MATCH_OLDER)
1591 } else if (f->mtime_sec < sec) {
1592 if (f->flag & ARCHIVE_MATCH_NEWER)
1595 nsec = archive_entry_mtime_nsec(entry);
1596 if (f->mtime_nsec > nsec) {
1597 if (f->flag & ARCHIVE_MATCH_OLDER)
1599 } else if (f->mtime_nsec < nsec) {
1600 if (f->flag & ARCHIVE_MATCH_NEWER)
1602 } else if (f->flag & ARCHIVE_MATCH_EQUAL)
1610 * Utility functions to manage inclusion owners
1614 archive_match_include_uid(struct archive *_a, la_int64_t uid)
1616 struct archive_match *a;
1618 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1619 ARCHIVE_STATE_NEW, "archive_match_include_uid");
1620 a = (struct archive_match *)_a;
1621 return (add_owner_id(a, &(a->inclusion_uids), uid));
1625 archive_match_include_gid(struct archive *_a, la_int64_t gid)
1627 struct archive_match *a;
1629 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1630 ARCHIVE_STATE_NEW, "archive_match_include_gid");
1631 a = (struct archive_match *)_a;
1632 return (add_owner_id(a, &(a->inclusion_gids), gid));
1636 archive_match_include_uname(struct archive *_a, const char *uname)
1638 struct archive_match *a;
1640 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1641 ARCHIVE_STATE_NEW, "archive_match_include_uname");
1642 a = (struct archive_match *)_a;
1643 return (add_owner_name(a, &(a->inclusion_unames), 1, uname));
1647 archive_match_include_uname_w(struct archive *_a, const wchar_t *uname)
1649 struct archive_match *a;
1651 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1652 ARCHIVE_STATE_NEW, "archive_match_include_uname_w");
1653 a = (struct archive_match *)_a;
1654 return (add_owner_name(a, &(a->inclusion_unames), 0, uname));
1658 archive_match_include_gname(struct archive *_a, const char *gname)
1660 struct archive_match *a;
1662 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1663 ARCHIVE_STATE_NEW, "archive_match_include_gname");
1664 a = (struct archive_match *)_a;
1665 return (add_owner_name(a, &(a->inclusion_gnames), 1, gname));
1669 archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
1671 struct archive_match *a;
1673 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1674 ARCHIVE_STATE_NEW, "archive_match_include_gname_w");
1675 a = (struct archive_match *)_a;
1676 return (add_owner_name(a, &(a->inclusion_gnames), 0, gname));
1680 * Test function for owner(uid, gid, uname, gname).
1682 * Returns 1 if archive entry is excluded.
1683 * Returns 0 if archive entry is not excluded.
1684 * Returns <0 if something error happened.
1687 archive_match_owner_excluded(struct archive *_a,
1688 struct archive_entry *entry)
1690 struct archive_match *a;
1692 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1693 ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae");
1695 a = (struct archive_match *)_a;
1696 if (entry == NULL) {
1697 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
1698 return (ARCHIVE_FAILED);
1701 /* If we don't have inclusion id set at all, the entry is always
1703 if ((a->setflag & ID_IS_SET) == 0)
1705 return (owner_excluded(a, entry));
1709 add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
1713 if (ids->count + 1 >= ids->size) {
1720 p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
1722 return (error_nomem(a));
1723 ids->ids = (int64_t *)p;
1726 /* Find an insert point. */
1727 for (i = 0; i < ids->count; i++) {
1728 if (ids->ids[i] >= id)
1733 if (i == ids->count)
1734 ids->ids[ids->count++] = id;
1735 else if (ids->ids[i] != id) {
1736 memmove(&(ids->ids[i+1]), &(ids->ids[i]),
1737 (ids->count - i) * sizeof(ids->ids[0]));
1741 a->setflag |= ID_IS_SET;
1742 return (ARCHIVE_OK);
1746 match_owner_id(struct id_array *ids, int64_t id)
1751 b = (unsigned)ids->count;
1754 if (ids->ids[m] == id)
1756 if (ids->ids[m] < id)
1765 add_owner_name(struct archive_match *a, struct match_list *list,
1766 int mbs, const void *name)
1768 struct match *match;
1770 match = calloc(1, sizeof(*match));
1772 return (error_nomem(a));
1774 archive_mstring_copy_mbs(&(match->pattern), name);
1776 archive_mstring_copy_wcs(&(match->pattern), name);
1777 match_list_add(list, match);
1778 a->setflag |= ID_IS_SET;
1779 return (ARCHIVE_OK);
1782 #if !defined(_WIN32) || defined(__CYGWIN__)
1784 match_owner_name_mbs(struct archive_match *a, struct match_list *list,
1790 if (name == NULL || *name == '\0')
1792 for (m = list->first; m; m = m->next) {
1793 if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p)
1794 < 0 && errno == ENOMEM)
1795 return (error_nomem(a));
1796 if (p != NULL && strcmp(p, name) == 0) {
1805 match_owner_name_wcs(struct archive_match *a, struct match_list *list,
1806 const wchar_t *name)
1811 if (name == NULL || *name == L'\0')
1813 for (m = list->first; m; m = m->next) {
1814 if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p)
1815 < 0 && errno == ENOMEM)
1816 return (error_nomem(a));
1817 if (p != NULL && wcscmp(p, name) == 0) {
1827 * Test if entry is excluded by uid, gid, uname or gname.
1830 owner_excluded(struct archive_match *a, struct archive_entry *entry)
1834 if (a->inclusion_uids.count) {
1835 if (!match_owner_id(&(a->inclusion_uids),
1836 archive_entry_uid(entry)))
1840 if (a->inclusion_gids.count) {
1841 if (!match_owner_id(&(a->inclusion_gids),
1842 archive_entry_gid(entry)))
1846 if (a->inclusion_unames.count) {
1847 #if defined(_WIN32) && !defined(__CYGWIN__)
1848 r = match_owner_name_wcs(a, &(a->inclusion_unames),
1849 archive_entry_uname_w(entry));
1851 r = match_owner_name_mbs(a, &(a->inclusion_unames),
1852 archive_entry_uname(entry));
1860 if (a->inclusion_gnames.count) {
1861 #if defined(_WIN32) && !defined(__CYGWIN__)
1862 r = match_owner_name_wcs(a, &(a->inclusion_gnames),
1863 archive_entry_gname_w(entry));
1865 r = match_owner_name_mbs(a, &(a->inclusion_gnames),
1866 archive_entry_gname(entry));