1 /*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2012 Michihiro NAKAJIMA
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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.
25 */
26
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD$");
29
30 #ifdef HAVE_ERRNO_H
31 #include <errno.h>
32 #endif
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39
40 #include "archive.h"
41 #include "archive_private.h"
42 #include "archive_entry.h"
43 #include "archive_pathmatch.h"
44 #include "archive_rb.h"
45 #include "archive_string.h"
46
47 struct match {
48 struct match *next;
49 int matches;
50 struct archive_mstring pattern;
51 };
52
53 struct match_list {
54 struct match *first;
55 struct match **last;
56 int count;
57 int unmatched_count;
58 struct match *unmatched_next;
59 int unmatched_eof;
60 };
61
62 struct match_file {
63 struct archive_rb_node node;
64 struct match_file *next;
65 struct archive_mstring pathname;
66 int flag;
67 time_t mtime_sec;
68 long mtime_nsec;
69 time_t ctime_sec;
70 long ctime_nsec;
71 };
72
73 struct entry_list {
74 struct match_file *first;
75 struct match_file **last;
76 int count;
77 };
78
79 struct id_array {
80 size_t size;/* Allocated size */
81 size_t count;
82 int64_t *ids;
83 };
84
85 #define PATTERN_IS_SET 1
86 #define TIME_IS_SET 2
87 #define ID_IS_SET 4
88
89 struct archive_match {
90 struct archive archive;
91
92 /* exclusion/inclusion set flag. */
93 int setflag;
94
95 /*
96 * Matching filename patterns.
97 */
98 struct match_list exclusions;
99 struct match_list inclusions;
100
101 /*
102 * Matching time stamps.
103 */
104 time_t now;
105 int newer_mtime_filter;
106 time_t newer_mtime_sec;
107 long newer_mtime_nsec;
108 int newer_ctime_filter;
109 time_t newer_ctime_sec;
110 long newer_ctime_nsec;
111 int older_mtime_filter;
112 time_t older_mtime_sec;
113 long older_mtime_nsec;
114 int older_ctime_filter;
115 time_t older_ctime_sec;
116 long older_ctime_nsec;
117 /*
118 * Matching time stamps with its filename.
119 */
120 struct archive_rb_tree exclusion_tree;
121 struct entry_list exclusion_entry_list;
122
123 /*
124 * Matching file owners.
125 */
126 struct id_array inclusion_uids;
127 struct id_array inclusion_gids;
128 struct match_list inclusion_unames;
129 struct match_list inclusion_gnames;
130 };
131
132 static int add_pattern_from_file(struct archive_match *,
133 struct match_list *, int, const void *, int);
134 static int add_entry(struct archive_match *, int,
135 struct archive_entry *);
136 static int add_owner_id(struct archive_match *, struct id_array *,
137 int64_t);
138 static int add_owner_name(struct archive_match *, struct match_list *,
139 int, const void *);
140 static int add_pattern_mbs(struct archive_match *, struct match_list *,
141 const char *);
142 static int add_pattern_wcs(struct archive_match *, struct match_list *,
143 const wchar_t *);
144 static int cmp_key_mbs(const struct archive_rb_node *, const void *);
145 static int cmp_key_wcs(const struct archive_rb_node *, const void *);
146 static int cmp_node_mbs(const struct archive_rb_node *,
147 const struct archive_rb_node *);
148 static int cmp_node_wcs(const struct archive_rb_node *,
149 const struct archive_rb_node *);
150 static void entry_list_add(struct entry_list *, struct match_file *);
151 static void entry_list_free(struct entry_list *);
152 static void entry_list_init(struct entry_list *);
153 static int error_nomem(struct archive_match *);
154 static void match_list_add(struct match_list *, struct match *);
155 static void match_list_free(struct match_list *);
156 static void match_list_init(struct match_list *);
157 static int match_list_unmatched_inclusions_next(struct archive_match *,
158 struct match_list *, int, const void **);
159 static int match_owner_id(struct id_array *, int64_t);
160 #if !defined(_WIN32) || defined(__CYGWIN__)
161 static int match_owner_name_mbs(struct archive_match *,
162 struct match_list *, const char *);
163 #else
164 static int match_owner_name_wcs(struct archive_match *,
165 struct match_list *, const wchar_t *);
166 #endif
167 static int match_path_exclusion(struct archive_match *,
168 struct match *, int, const void *);
169 static int match_path_inclusion(struct archive_match *,
170 struct match *, int, const void *);
171 static int owner_excluded(struct archive_match *,
172 struct archive_entry *);
173 static int path_excluded(struct archive_match *, int, const void *);
174 static int set_timefilter(struct archive_match *, int, time_t, long,
175 time_t, long);
176 static int set_timefilter_pathname_mbs(struct archive_match *,
177 int, const char *);
178 static int set_timefilter_pathname_wcs(struct archive_match *,
179 int, const wchar_t *);
180 static int set_timefilter_date(struct archive_match *, int, const char *);
181 static int set_timefilter_date_w(struct archive_match *, int,
182 const wchar_t *);
183 static int time_excluded(struct archive_match *,
184 struct archive_entry *);
185 static int validate_time_flag(struct archive *, int, const char *);
186
187 time_t __archive_get_date(time_t now, const char *);
188 #define get_date __archive_get_date
189
190 static const struct archive_rb_tree_ops rb_ops_mbs = {
191 cmp_node_mbs, cmp_key_mbs
192 };
193
194 static const struct archive_rb_tree_ops rb_ops_wcs = {
195 cmp_node_wcs, cmp_key_wcs
196 };
197
198 /*
199 * The matching logic here needs to be re-thought. I started out to
200 * try to mimic gtar's matching logic, but it's not entirely
201 * consistent. In particular 'tar -t' and 'tar -x' interpret patterns
202 * on the command line as anchored, but --exclude doesn't.
203 */
204
205 static int
error_nomem(struct archive_match * a)206 error_nomem(struct archive_match *a)
207 {
208 archive_set_error(&(a->archive), ENOMEM, "No memory");
209 a->archive.state = ARCHIVE_STATE_FATAL;
210 return (ARCHIVE_FATAL);
211 }
212
213 /*
214 * Create an ARCHIVE_MATCH object.
215 */
216 struct archive *
archive_match_new(void)217 archive_match_new(void)
218 {
219 struct archive_match *a;
220
221 a = (struct archive_match *)calloc(1, sizeof(*a));
222 if (a == NULL)
223 return (NULL);
224 a->archive.magic = ARCHIVE_MATCH_MAGIC;
225 a->archive.state = ARCHIVE_STATE_NEW;
226 match_list_init(&(a->inclusions));
227 match_list_init(&(a->exclusions));
228 __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
229 entry_list_init(&(a->exclusion_entry_list));
230 match_list_init(&(a->inclusion_unames));
231 match_list_init(&(a->inclusion_gnames));
232 time(&a->now);
233 return (&(a->archive));
234 }
235
236 /*
237 * Free an ARCHIVE_MATCH object.
238 */
239 int
archive_match_free(struct archive * _a)240 archive_match_free(struct archive *_a)
241 {
242 struct archive_match *a;
243
244 if (_a == NULL)
245 return (ARCHIVE_OK);
246 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
247 ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free");
248 a = (struct archive_match *)_a;
249 match_list_free(&(a->inclusions));
250 match_list_free(&(a->exclusions));
251 entry_list_free(&(a->exclusion_entry_list));
252 free(a->inclusion_uids.ids);
253 free(a->inclusion_gids.ids);
254 match_list_free(&(a->inclusion_unames));
255 match_list_free(&(a->inclusion_gnames));
256 free(a);
257 return (ARCHIVE_OK);
258 }
259
260 /*
261 * Convenience function to perform all exclusion tests.
262 *
263 * Returns 1 if archive entry is excluded.
264 * Returns 0 if archive entry is not excluded.
265 * Returns <0 if something error happened.
266 */
267 int
archive_match_excluded(struct archive * _a,struct archive_entry * entry)268 archive_match_excluded(struct archive *_a, struct archive_entry *entry)
269 {
270 struct archive_match *a;
271 int r;
272
273 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
274 ARCHIVE_STATE_NEW, "archive_match_excluded_ae");
275
276 a = (struct archive_match *)_a;
277 if (entry == NULL) {
278 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
279 return (ARCHIVE_FAILED);
280 }
281
282 r = 0;
283 if (a->setflag & PATTERN_IS_SET) {
284 #if defined(_WIN32) && !defined(__CYGWIN__)
285 r = path_excluded(a, 0, archive_entry_pathname_w(entry));
286 #else
287 r = path_excluded(a, 1, archive_entry_pathname(entry));
288 #endif
289 if (r != 0)
290 return (r);
291 }
292
293 if (a->setflag & TIME_IS_SET) {
294 r = time_excluded(a, entry);
295 if (r != 0)
296 return (r);
297 }
298
299 if (a->setflag & ID_IS_SET)
300 r = owner_excluded(a, entry);
301 return (r);
302 }
303
304 /*
305 * Utility functions to manage exclusion/inclusion patterns
306 */
307
308 int
archive_match_exclude_pattern(struct archive * _a,const char * pattern)309 archive_match_exclude_pattern(struct archive *_a, const char *pattern)
310 {
311 struct archive_match *a;
312 int r;
313
314 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
315 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern");
316 a = (struct archive_match *)_a;
317
318 if (pattern == NULL || *pattern == '\0') {
319 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
320 return (ARCHIVE_FAILED);
321 }
322 if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
323 return (r);
324 return (ARCHIVE_OK);
325 }
326
327 int
archive_match_exclude_pattern_w(struct archive * _a,const wchar_t * pattern)328 archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern)
329 {
330 struct archive_match *a;
331 int r;
332
333 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
334 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w");
335 a = (struct archive_match *)_a;
336
337 if (pattern == NULL || *pattern == L'\0') {
338 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
339 return (ARCHIVE_FAILED);
340 }
341 if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
342 return (r);
343 return (ARCHIVE_OK);
344 }
345
346 int
archive_match_exclude_pattern_from_file(struct archive * _a,const char * pathname,int nullSeparator)347 archive_match_exclude_pattern_from_file(struct archive *_a,
348 const char *pathname, int nullSeparator)
349 {
350 struct archive_match *a;
351
352 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
353 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file");
354 a = (struct archive_match *)_a;
355
356 return add_pattern_from_file(a, &(a->exclusions), 1, pathname,
357 nullSeparator);
358 }
359
360 int
archive_match_exclude_pattern_from_file_w(struct archive * _a,const wchar_t * pathname,int nullSeparator)361 archive_match_exclude_pattern_from_file_w(struct archive *_a,
362 const wchar_t *pathname, int nullSeparator)
363 {
364 struct archive_match *a;
365
366 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
367 ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w");
368 a = (struct archive_match *)_a;
369
370 return add_pattern_from_file(a, &(a->exclusions), 0, pathname,
371 nullSeparator);
372 }
373
374 int
archive_match_include_pattern(struct archive * _a,const char * pattern)375 archive_match_include_pattern(struct archive *_a, const char *pattern)
376 {
377 struct archive_match *a;
378 int r;
379
380 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
381 ARCHIVE_STATE_NEW, "archive_match_include_pattern");
382 a = (struct archive_match *)_a;
383
384 if (pattern == NULL || *pattern == '\0') {
385 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
386 return (ARCHIVE_FAILED);
387 }
388 if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
389 return (r);
390 return (ARCHIVE_OK);
391 }
392
393 int
archive_match_include_pattern_w(struct archive * _a,const wchar_t * pattern)394 archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern)
395 {
396 struct archive_match *a;
397 int r;
398
399 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
400 ARCHIVE_STATE_NEW, "archive_match_include_pattern_w");
401 a = (struct archive_match *)_a;
402
403 if (pattern == NULL || *pattern == L'\0') {
404 archive_set_error(&(a->archive), EINVAL, "pattern is empty");
405 return (ARCHIVE_FAILED);
406 }
407 if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
408 return (r);
409 return (ARCHIVE_OK);
410 }
411
412 int
archive_match_include_pattern_from_file(struct archive * _a,const char * pathname,int nullSeparator)413 archive_match_include_pattern_from_file(struct archive *_a,
414 const char *pathname, int nullSeparator)
415 {
416 struct archive_match *a;
417
418 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
419 ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file");
420 a = (struct archive_match *)_a;
421
422 return add_pattern_from_file(a, &(a->inclusions), 1, pathname,
423 nullSeparator);
424 }
425
426 int
archive_match_include_pattern_from_file_w(struct archive * _a,const wchar_t * pathname,int nullSeparator)427 archive_match_include_pattern_from_file_w(struct archive *_a,
428 const wchar_t *pathname, int nullSeparator)
429 {
430 struct archive_match *a;
431
432 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
433 ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w");
434 a = (struct archive_match *)_a;
435
436 return add_pattern_from_file(a, &(a->inclusions), 0, pathname,
437 nullSeparator);
438 }
439
440 /*
441 * Test functions for pathname patterns.
442 *
443 * Returns 1 if archive entry is excluded.
444 * Returns 0 if archive entry is not excluded.
445 * Returns <0 if something error happened.
446 */
447 int
archive_match_path_excluded(struct archive * _a,struct archive_entry * entry)448 archive_match_path_excluded(struct archive *_a,
449 struct archive_entry *entry)
450 {
451 struct archive_match *a;
452
453 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
454 ARCHIVE_STATE_NEW, "archive_match_path_excluded");
455
456 a = (struct archive_match *)_a;
457 if (entry == NULL) {
458 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
459 return (ARCHIVE_FAILED);
460 }
461
462 /* If we don't have exclusion/inclusion pattern set at all,
463 * the entry is always not excluded. */
464 if ((a->setflag & PATTERN_IS_SET) == 0)
465 return (0);
466 #if defined(_WIN32) && !defined(__CYGWIN__)
467 return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
468 #else
469 return (path_excluded(a, 1, archive_entry_pathname(entry)));
470 #endif
471 }
472
473 /*
474 * Utilty functions to get statistic information for inclusion patterns.
475 */
476 int
archive_match_path_unmatched_inclusions(struct archive * _a)477 archive_match_path_unmatched_inclusions(struct archive *_a)
478 {
479 struct archive_match *a;
480
481 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
482 ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
483 a = (struct archive_match *)_a;
484
485 return (a->inclusions.unmatched_count);
486 }
487
488 int
archive_match_path_unmatched_inclusions_next(struct archive * _a,const char ** _p)489 archive_match_path_unmatched_inclusions_next(struct archive *_a,
490 const char **_p)
491 {
492 struct archive_match *a;
493 const void *v;
494 int r;
495
496 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
497 ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next");
498 a = (struct archive_match *)_a;
499
500 r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v);
501 *_p = (const char *)v;
502 return (r);
503 }
504
505 int
archive_match_path_unmatched_inclusions_next_w(struct archive * _a,const wchar_t ** _p)506 archive_match_path_unmatched_inclusions_next_w(struct archive *_a,
507 const wchar_t **_p)
508 {
509 struct archive_match *a;
510 const void *v;
511 int r;
512
513 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
514 ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w");
515 a = (struct archive_match *)_a;
516
517 r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v);
518 *_p = (const wchar_t *)v;
519 return (r);
520 }
521
522 /*
523 * Add inclusion/exclusion patterns.
524 */
525 static int
add_pattern_mbs(struct archive_match * a,struct match_list * list,const char * pattern)526 add_pattern_mbs(struct archive_match *a, struct match_list *list,
527 const char *pattern)
528 {
529 struct match *match;
530 size_t len;
531
532 match = calloc(1, sizeof(*match));
533 if (match == NULL)
534 return (error_nomem(a));
535 /* Both "foo/" and "foo" should match "foo/bar". */
536 len = strlen(pattern);
537 if (len && pattern[len - 1] == '/')
538 --len;
539 archive_mstring_copy_mbs_len(&(match->pattern), pattern, len);
540 match_list_add(list, match);
541 a->setflag |= PATTERN_IS_SET;
542 return (ARCHIVE_OK);
543 }
544
545 static int
add_pattern_wcs(struct archive_match * a,struct match_list * list,const wchar_t * pattern)546 add_pattern_wcs(struct archive_match *a, struct match_list *list,
547 const wchar_t *pattern)
548 {
549 struct match *match;
550 size_t len;
551
552 match = calloc(1, sizeof(*match));
553 if (match == NULL)
554 return (error_nomem(a));
555 /* Both "foo/" and "foo" should match "foo/bar". */
556 len = wcslen(pattern);
557 if (len && pattern[len - 1] == L'/')
558 --len;
559 archive_mstring_copy_wcs_len(&(match->pattern), pattern, len);
560 match_list_add(list, match);
561 a->setflag |= PATTERN_IS_SET;
562 return (ARCHIVE_OK);
563 }
564
565 static int
add_pattern_from_file(struct archive_match * a,struct match_list * mlist,int mbs,const void * pathname,int nullSeparator)566 add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
567 int mbs, const void *pathname, int nullSeparator)
568 {
569 struct archive *ar;
570 struct archive_entry *ae;
571 struct archive_string as;
572 const void *buff;
573 size_t size;
574 int64_t offset;
575 int r;
576
577 ar = archive_read_new();
578 if (ar == NULL) {
579 archive_set_error(&(a->archive), ENOMEM, "No memory");
580 return (ARCHIVE_FATAL);
581 }
582 r = archive_read_support_format_raw(ar);
583 if (r != ARCHIVE_OK) {
584 archive_copy_error(&(a->archive), ar);
585 archive_read_free(ar);
586 return (r);
587 }
588 if (mbs)
589 r = archive_read_open_filename(ar, pathname, 512*20);
590 else
591 r = archive_read_open_filename_w(ar, pathname, 512*20);
592 if (r != ARCHIVE_OK) {
593 archive_copy_error(&(a->archive), ar);
594 archive_read_free(ar);
595 return (r);
596 }
597 r = archive_read_next_header(ar, &ae);
598 if (r != ARCHIVE_OK) {
599 archive_copy_error(&(a->archive), ar);
600 archive_read_free(ar);
601 return (r);
602 }
603
604 archive_string_init(&as);
605
606 while ((r = archive_read_data_block(ar, &buff, &size, &offset))
607 == ARCHIVE_OK) {
608 const char *b = (const char *)buff;
609
610 while (size) {
611 const char *s = (const char *)b;
612 size_t length = 0;
613 int found_separator = 0;
614
615 while (length < size) {
616 if (nullSeparator) {
617 if (*b == '\0') {
618 found_separator = 1;
619 break;
620 }
621 } else {
622 if (*b == 0x0d || *b == 0x0a) {
623 found_separator = 1;
624 break;
625 }
626 }
627 b++;
628 length++;
629 }
630 if (!found_separator) {
631 archive_strncat(&as, s, length);
632 /* Read next data block. */
633 break;
634 }
635 b++;
636 size -= length + 1;
637 archive_strncat(&as, s, length);
638
639 /* If the line is not empty, add the pattern. */
640 if (archive_strlen(&as) > 0) {
641 /* Add pattern. */
642 r = add_pattern_mbs(a, mlist, as.s);
643 if (r != ARCHIVE_OK) {
644 archive_read_free(ar);
645 archive_string_free(&as);
646 return (r);
647 }
648 archive_string_empty(&as);
649 }
650 }
651 }
652
653 /* If something error happend, report it immediately. */
654 if (r < ARCHIVE_OK) {
655 archive_copy_error(&(a->archive), ar);
656 archive_read_free(ar);
657 archive_string_free(&as);
658 return (r);
659 }
660
661 /* If the line is not empty, add the pattern. */
662 if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) {
663 /* Add pattern. */
664 r = add_pattern_mbs(a, mlist, as.s);
665 if (r != ARCHIVE_OK) {
666 archive_read_free(ar);
667 archive_string_free(&as);
668 return (r);
669 }
670 }
671 archive_read_free(ar);
672 archive_string_free(&as);
673 return (ARCHIVE_OK);
674 }
675
676 /*
677 * Test if pathname is excluded by inclusion/exclusion patterns.
678 */
679 static int
path_excluded(struct archive_match * a,int mbs,const void * pathname)680 path_excluded(struct archive_match *a, int mbs, const void *pathname)
681 {
682 struct match *match;
683 struct match *matched;
684 int r;
685
686 if (a == NULL)
687 return (0);
688
689 /* Mark off any unmatched inclusions. */
690 /* In particular, if a filename does appear in the archive and
691 * is explicitly included and excluded, then we don't report
692 * it as missing even though we don't extract it.
693 */
694 matched = NULL;
695 for (match = a->inclusions.first; match != NULL;
696 match = match->next){
697 if (match->matches == 0 &&
698 (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
699 if (r < 0)
700 return (r);
701 a->inclusions.unmatched_count--;
702 match->matches++;
703 matched = match;
704 }
705 }
706
707 /* Exclusions take priority */
708 for (match = a->exclusions.first; match != NULL;
709 match = match->next){
710 r = match_path_exclusion(a, match, mbs, pathname);
711 if (r)
712 return (r);
713 }
714
715 /* It's not excluded and we found an inclusion above, so it's
716 * included. */
717 if (matched != NULL)
718 return (0);
719
720
721 /* We didn't find an unmatched inclusion, check the remaining ones. */
722 for (match = a->inclusions.first; match != NULL;
723 match = match->next){
724 /* We looked at previously-unmatched inclusions already. */
725 if (match->matches > 0 &&
726 (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
727 if (r < 0)
728 return (r);
729 match->matches++;
730 return (0);
731 }
732 }
733
734 /* If there were inclusions, default is to exclude. */
735 if (a->inclusions.first != NULL)
736 return (1);
737
738 /* No explicit inclusions, default is to match. */
739 return (0);
740 }
741
742 /*
743 * This is a little odd, but it matches the default behavior of
744 * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
745 *
746 */
747 static int
match_path_exclusion(struct archive_match * a,struct match * m,int mbs,const void * pn)748 match_path_exclusion(struct archive_match *a, struct match *m,
749 int mbs, const void *pn)
750 {
751 int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END;
752 int r;
753
754 if (mbs) {
755 const char *p;
756 r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
757 if (r == 0)
758 return (archive_pathmatch(p, (const char *)pn, flag));
759 } else {
760 const wchar_t *p;
761 r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
762 if (r == 0)
763 return (archive_pathmatch_w(p, (const wchar_t *)pn,
764 flag));
765 }
766 if (errno == ENOMEM)
767 return (error_nomem(a));
768 return (0);
769 }
770
771 /*
772 * Again, mimic gtar: inclusions are always anchored (have to match
773 * the beginning of the path) even though exclusions are not anchored.
774 */
775 static int
match_path_inclusion(struct archive_match * a,struct match * m,int mbs,const void * pn)776 match_path_inclusion(struct archive_match *a, struct match *m,
777 int mbs, const void *pn)
778 {
779 int flag = PATHMATCH_NO_ANCHOR_END;
780 int r;
781
782 if (mbs) {
783 const char *p;
784 r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
785 if (r == 0)
786 return (archive_pathmatch(p, (const char *)pn, flag));
787 } else {
788 const wchar_t *p;
789 r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
790 if (r == 0)
791 return (archive_pathmatch_w(p, (const wchar_t *)pn,
792 flag));
793 }
794 if (errno == ENOMEM)
795 return (error_nomem(a));
796 return (0);
797 }
798
799 static void
match_list_init(struct match_list * list)800 match_list_init(struct match_list *list)
801 {
802 list->first = NULL;
803 list->last = &(list->first);
804 list->count = 0;
805 }
806
807 static void
match_list_free(struct match_list * list)808 match_list_free(struct match_list *list)
809 {
810 struct match *p, *q;
811
812 for (p = list->first; p != NULL; ) {
813 q = p;
814 p = p->next;
815 archive_mstring_clean(&(q->pattern));
816 free(q);
817 }
818 }
819
820 static void
match_list_add(struct match_list * list,struct match * m)821 match_list_add(struct match_list *list, struct match *m)
822 {
823 *list->last = m;
824 list->last = &(m->next);
825 list->count++;
826 list->unmatched_count++;
827 }
828
829 static int
match_list_unmatched_inclusions_next(struct archive_match * a,struct match_list * list,int mbs,const void ** vp)830 match_list_unmatched_inclusions_next(struct archive_match *a,
831 struct match_list *list, int mbs, const void **vp)
832 {
833 struct match *m;
834
835 *vp = NULL;
836 if (list->unmatched_eof) {
837 list->unmatched_eof = 0;
838 return (ARCHIVE_EOF);
839 }
840 if (list->unmatched_next == NULL) {
841 if (list->unmatched_count == 0)
842 return (ARCHIVE_EOF);
843 list->unmatched_next = list->first;
844 }
845
846 for (m = list->unmatched_next; m != NULL; m = m->next) {
847 int r;
848
849 if (m->matches)
850 continue;
851 if (mbs) {
852 const char *p;
853 r = archive_mstring_get_mbs(&(a->archive),
854 &(m->pattern), &p);
855 if (r < 0 && errno == ENOMEM)
856 return (error_nomem(a));
857 if (p == NULL)
858 p = "";
859 *vp = p;
860 } else {
861 const wchar_t *p;
862 r = archive_mstring_get_wcs(&(a->archive),
863 &(m->pattern), &p);
864 if (r < 0 && errno == ENOMEM)
865 return (error_nomem(a));
866 if (p == NULL)
867 p = L"";
868 *vp = p;
869 }
870 list->unmatched_next = m->next;
871 if (list->unmatched_next == NULL)
872 /* To return EOF next time. */
873 list->unmatched_eof = 1;
874 return (ARCHIVE_OK);
875 }
876 list->unmatched_next = NULL;
877 return (ARCHIVE_EOF);
878 }
879
880 /*
881 * Utility functions to manage inclusion timestamps.
882 */
883 int
archive_match_include_time(struct archive * _a,int flag,time_t sec,long nsec)884 archive_match_include_time(struct archive *_a, int flag, time_t sec,
885 long nsec)
886 {
887 int r;
888
889 r = validate_time_flag(_a, flag, "archive_match_include_time");
890 if (r != ARCHIVE_OK)
891 return (r);
892 return set_timefilter((struct archive_match *)_a, flag,
893 sec, nsec, sec, nsec);
894 }
895
896 int
archive_match_include_date(struct archive * _a,int flag,const char * datestr)897 archive_match_include_date(struct archive *_a, int flag,
898 const char *datestr)
899 {
900 int r;
901
902 r = validate_time_flag(_a, flag, "archive_match_include_date");
903 if (r != ARCHIVE_OK)
904 return (r);
905 return set_timefilter_date((struct archive_match *)_a, flag, datestr);
906 }
907
908 int
archive_match_include_date_w(struct archive * _a,int flag,const wchar_t * datestr)909 archive_match_include_date_w(struct archive *_a, int flag,
910 const wchar_t *datestr)
911 {
912 int r;
913
914 r = validate_time_flag(_a, flag, "archive_match_include_date_w");
915 if (r != ARCHIVE_OK)
916 return (r);
917
918 return set_timefilter_date_w((struct archive_match *)_a, flag, datestr);
919 }
920
921 int
archive_match_include_file_time(struct archive * _a,int flag,const char * pathname)922 archive_match_include_file_time(struct archive *_a, int flag,
923 const char *pathname)
924 {
925 int r;
926
927 r = validate_time_flag(_a, flag, "archive_match_include_file_time");
928 if (r != ARCHIVE_OK)
929 return (r);
930 return set_timefilter_pathname_mbs((struct archive_match *)_a,
931 flag, pathname);
932 }
933
934 int
archive_match_include_file_time_w(struct archive * _a,int flag,const wchar_t * pathname)935 archive_match_include_file_time_w(struct archive *_a, int flag,
936 const wchar_t *pathname)
937 {
938 int r;
939
940 r = validate_time_flag(_a, flag, "archive_match_include_file_time_w");
941 if (r != ARCHIVE_OK)
942 return (r);
943 return set_timefilter_pathname_wcs((struct archive_match *)_a,
944 flag, pathname);
945 }
946
947 int
archive_match_exclude_entry(struct archive * _a,int flag,struct archive_entry * entry)948 archive_match_exclude_entry(struct archive *_a, int flag,
949 struct archive_entry *entry)
950 {
951 struct archive_match *a;
952 int r;
953
954 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
955 ARCHIVE_STATE_NEW, "archive_match_time_include_entry");
956 a = (struct archive_match *)_a;
957
958 if (entry == NULL) {
959 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
960 return (ARCHIVE_FAILED);
961 }
962 r = validate_time_flag(_a, flag, "archive_match_exclude_entry");
963 if (r != ARCHIVE_OK)
964 return (r);
965 return (add_entry(a, flag, entry));
966 }
967
968 /*
969 * Test function for time stamps.
970 *
971 * Returns 1 if archive entry is excluded.
972 * Returns 0 if archive entry is not excluded.
973 * Returns <0 if something error happened.
974 */
975 int
archive_match_time_excluded(struct archive * _a,struct archive_entry * entry)976 archive_match_time_excluded(struct archive *_a,
977 struct archive_entry *entry)
978 {
979 struct archive_match *a;
980
981 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
982 ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae");
983
984 a = (struct archive_match *)_a;
985 if (entry == NULL) {
986 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
987 return (ARCHIVE_FAILED);
988 }
989
990 /* If we don't have inclusion time set at all, the entry is always
991 * not excluded. */
992 if ((a->setflag & TIME_IS_SET) == 0)
993 return (0);
994 return (time_excluded(a, entry));
995 }
996
997 static int
validate_time_flag(struct archive * _a,int flag,const char * _fn)998 validate_time_flag(struct archive *_a, int flag, const char *_fn)
999 {
1000 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1001 ARCHIVE_STATE_NEW, _fn);
1002
1003 /* Check a type of time. */
1004 if (flag &
1005 ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) {
1006 archive_set_error(_a, EINVAL, "Invalid time flag");
1007 return (ARCHIVE_FAILED);
1008 }
1009 if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) {
1010 archive_set_error(_a, EINVAL, "No time flag");
1011 return (ARCHIVE_FAILED);
1012 }
1013
1014 /* Check a type of comparison. */
1015 if (flag &
1016 ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
1017 | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) {
1018 archive_set_error(_a, EINVAL, "Invalid comparison flag");
1019 return (ARCHIVE_FAILED);
1020 }
1021 if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
1022 | ARCHIVE_MATCH_EQUAL)) == 0) {
1023 archive_set_error(_a, EINVAL, "No comparison flag");
1024 return (ARCHIVE_FAILED);
1025 }
1026
1027 return (ARCHIVE_OK);
1028 }
1029
1030 #define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\
1031 ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL)
1032 static int
set_timefilter(struct archive_match * a,int timetype,time_t mtime_sec,long mtime_nsec,time_t ctime_sec,long ctime_nsec)1033 set_timefilter(struct archive_match *a, int timetype,
1034 time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec)
1035 {
1036 if (timetype & ARCHIVE_MATCH_MTIME) {
1037 if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
1038 a->newer_mtime_filter = timetype;
1039 a->newer_mtime_sec = mtime_sec;
1040 a->newer_mtime_nsec = mtime_nsec;
1041 a->setflag |= TIME_IS_SET;
1042 }
1043 if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
1044 a->older_mtime_filter = timetype;
1045 a->older_mtime_sec = mtime_sec;
1046 a->older_mtime_nsec = mtime_nsec;
1047 a->setflag |= TIME_IS_SET;
1048 }
1049 }
1050 if (timetype & ARCHIVE_MATCH_CTIME) {
1051 if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
1052 a->newer_ctime_filter = timetype;
1053 a->newer_ctime_sec = ctime_sec;
1054 a->newer_ctime_nsec = ctime_nsec;
1055 a->setflag |= TIME_IS_SET;
1056 }
1057 if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
1058 a->older_ctime_filter = timetype;
1059 a->older_ctime_sec = ctime_sec;
1060 a->older_ctime_nsec = ctime_nsec;
1061 a->setflag |= TIME_IS_SET;
1062 }
1063 }
1064 return (ARCHIVE_OK);
1065 }
1066
1067 static int
set_timefilter_date(struct archive_match * a,int timetype,const char * datestr)1068 set_timefilter_date(struct archive_match *a, int timetype, const char *datestr)
1069 {
1070 time_t t;
1071
1072 if (datestr == NULL || *datestr == '\0') {
1073 archive_set_error(&(a->archive), EINVAL, "date is empty");
1074 return (ARCHIVE_FAILED);
1075 }
1076 t = get_date(a->now, datestr);
1077 if (t == (time_t)-1) {
1078 archive_set_error(&(a->archive), EINVAL, "invalid date string");
1079 return (ARCHIVE_FAILED);
1080 }
1081 return set_timefilter(a, timetype, t, 0, t, 0);
1082 }
1083
1084 static int
set_timefilter_date_w(struct archive_match * a,int timetype,const wchar_t * datestr)1085 set_timefilter_date_w(struct archive_match *a, int timetype,
1086 const wchar_t *datestr)
1087 {
1088 struct archive_string as;
1089 time_t t;
1090
1091 if (datestr == NULL || *datestr == L'\0') {
1092 archive_set_error(&(a->archive), EINVAL, "date is empty");
1093 return (ARCHIVE_FAILED);
1094 }
1095
1096 archive_string_init(&as);
1097 if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) {
1098 archive_string_free(&as);
1099 if (errno == ENOMEM)
1100 return (error_nomem(a));
1101 archive_set_error(&(a->archive), -1,
1102 "Failed to convert WCS to MBS");
1103 return (ARCHIVE_FAILED);
1104 }
1105 t = get_date(a->now, as.s);
1106 archive_string_free(&as);
1107 if (t == (time_t)-1) {
1108 archive_set_error(&(a->archive), EINVAL, "invalid date string");
1109 return (ARCHIVE_FAILED);
1110 }
1111 return set_timefilter(a, timetype, t, 0, t, 0);
1112 }
1113
1114 #if defined(_WIN32) && !defined(__CYGWIN__)
1115 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
1116 static int
set_timefilter_find_data(struct archive_match * a,int timetype,DWORD ftLastWriteTime_dwHighDateTime,DWORD ftLastWriteTime_dwLowDateTime,DWORD ftCreationTime_dwHighDateTime,DWORD ftCreationTime_dwLowDateTime)1117 set_timefilter_find_data(struct archive_match *a, int timetype,
1118 DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime,
1119 DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime)
1120 {
1121 ULARGE_INTEGER utc;
1122 time_t ctime_sec, mtime_sec;
1123 long ctime_ns, mtime_ns;
1124
1125 utc.HighPart = ftCreationTime_dwHighDateTime;
1126 utc.LowPart = ftCreationTime_dwLowDateTime;
1127 if (utc.QuadPart >= EPOC_TIME) {
1128 utc.QuadPart -= EPOC_TIME;
1129 ctime_sec = (time_t)(utc.QuadPart / 10000000);
1130 ctime_ns = (long)(utc.QuadPart % 10000000) * 100;
1131 } else {
1132 ctime_sec = 0;
1133 ctime_ns = 0;
1134 }
1135 utc.HighPart = ftLastWriteTime_dwHighDateTime;
1136 utc.LowPart = ftLastWriteTime_dwLowDateTime;
1137 if (utc.QuadPart >= EPOC_TIME) {
1138 utc.QuadPart -= EPOC_TIME;
1139 mtime_sec = (time_t)(utc.QuadPart / 10000000);
1140 mtime_ns = (long)(utc.QuadPart % 10000000) * 100;
1141 } else {
1142 mtime_sec = 0;
1143 mtime_ns = 0;
1144 }
1145 return set_timefilter(a, timetype,
1146 mtime_sec, mtime_ns, ctime_sec, ctime_ns);
1147 }
1148
1149 static int
set_timefilter_pathname_mbs(struct archive_match * a,int timetype,const char * path)1150 set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
1151 const char *path)
1152 {
1153 /* NOTE: stat() on Windows cannot handle nano seconds. */
1154 HANDLE h;
1155 WIN32_FIND_DATA d;
1156
1157 if (path == NULL || *path == '\0') {
1158 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1159 return (ARCHIVE_FAILED);
1160 }
1161 h = FindFirstFileA(path, &d);
1162 if (h == INVALID_HANDLE_VALUE) {
1163 la_dosmaperr(GetLastError());
1164 archive_set_error(&(a->archive), errno,
1165 "Failed to FindFirstFileA");
1166 return (ARCHIVE_FAILED);
1167 }
1168 FindClose(h);
1169 return set_timefilter_find_data(a, timetype,
1170 d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
1171 d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
1172 }
1173
1174 static int
set_timefilter_pathname_wcs(struct archive_match * a,int timetype,const wchar_t * path)1175 set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
1176 const wchar_t *path)
1177 {
1178 HANDLE h;
1179 WIN32_FIND_DATAW d;
1180
1181 if (path == NULL || *path == L'\0') {
1182 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1183 return (ARCHIVE_FAILED);
1184 }
1185 h = FindFirstFileW(path, &d);
1186 if (h == INVALID_HANDLE_VALUE) {
1187 la_dosmaperr(GetLastError());
1188 archive_set_error(&(a->archive), errno,
1189 "Failed to FindFirstFile");
1190 return (ARCHIVE_FAILED);
1191 }
1192 FindClose(h);
1193 return set_timefilter_find_data(a, timetype,
1194 d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
1195 d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
1196 }
1197
1198 #else /* _WIN32 && !__CYGWIN__ */
1199
1200 static int
set_timefilter_stat(struct archive_match * a,int timetype,struct stat * st)1201 set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st)
1202 {
1203 struct archive_entry *ae;
1204 time_t ctime_sec, mtime_sec;
1205 long ctime_ns, mtime_ns;
1206
1207 ae = archive_entry_new();
1208 if (ae == NULL)
1209 return (error_nomem(a));
1210 archive_entry_copy_stat(ae, st);
1211 ctime_sec = archive_entry_ctime(ae);
1212 ctime_ns = archive_entry_ctime_nsec(ae);
1213 mtime_sec = archive_entry_mtime(ae);
1214 mtime_ns = archive_entry_mtime_nsec(ae);
1215 archive_entry_free(ae);
1216 return set_timefilter(a, timetype, mtime_sec, mtime_ns,
1217 ctime_sec, ctime_ns);
1218 }
1219
1220 static int
set_timefilter_pathname_mbs(struct archive_match * a,int timetype,const char * path)1221 set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
1222 const char *path)
1223 {
1224 struct stat st;
1225
1226 if (path == NULL || *path == '\0') {
1227 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1228 return (ARCHIVE_FAILED);
1229 }
1230 if (stat(path, &st) != 0) {
1231 archive_set_error(&(a->archive), errno, "Failed to stat()");
1232 return (ARCHIVE_FAILED);
1233 }
1234 return (set_timefilter_stat(a, timetype, &st));
1235 }
1236
1237 static int
set_timefilter_pathname_wcs(struct archive_match * a,int timetype,const wchar_t * path)1238 set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
1239 const wchar_t *path)
1240 {
1241 struct archive_string as;
1242 int r;
1243
1244 if (path == NULL || *path == L'\0') {
1245 archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1246 return (ARCHIVE_FAILED);
1247 }
1248
1249 /* Convert WCS filename to MBS filename. */
1250 archive_string_init(&as);
1251 if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) {
1252 archive_string_free(&as);
1253 if (errno == ENOMEM)
1254 return (error_nomem(a));
1255 archive_set_error(&(a->archive), -1,
1256 "Failed to convert WCS to MBS");
1257 return (ARCHIVE_FAILED);
1258 }
1259
1260 r = set_timefilter_pathname_mbs(a, timetype, as.s);
1261 archive_string_free(&as);
1262
1263 return (r);
1264 }
1265 #endif /* _WIN32 && !__CYGWIN__ */
1266
1267 /*
1268 * Call back funtions for archive_rb.
1269 */
1270 static int
cmp_node_mbs(const struct archive_rb_node * n1,const struct archive_rb_node * n2)1271 cmp_node_mbs(const struct archive_rb_node *n1,
1272 const struct archive_rb_node *n2)
1273 {
1274 struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
1275 struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
1276 const char *p1, *p2;
1277
1278 archive_mstring_get_mbs(NULL, &(f1->pathname), &p1);
1279 archive_mstring_get_mbs(NULL, &(f2->pathname), &p2);
1280 if (p1 == NULL)
1281 return (1);
1282 if (p2 == NULL)
1283 return (-1);
1284 return (strcmp(p1, p2));
1285 }
1286
1287 static int
cmp_key_mbs(const struct archive_rb_node * n,const void * key)1288 cmp_key_mbs(const struct archive_rb_node *n, const void *key)
1289 {
1290 struct match_file *f = (struct match_file *)(uintptr_t)n;
1291 const char *p;
1292
1293 archive_mstring_get_mbs(NULL, &(f->pathname), &p);
1294 if (p == NULL)
1295 return (-1);
1296 return (strcmp(p, (const char *)key));
1297 }
1298
1299 static int
cmp_node_wcs(const struct archive_rb_node * n1,const struct archive_rb_node * n2)1300 cmp_node_wcs(const struct archive_rb_node *n1,
1301 const struct archive_rb_node *n2)
1302 {
1303 struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
1304 struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
1305 const wchar_t *p1, *p2;
1306
1307 archive_mstring_get_wcs(NULL, &(f1->pathname), &p1);
1308 archive_mstring_get_wcs(NULL, &(f2->pathname), &p2);
1309 if (p1 == NULL)
1310 return (1);
1311 if (p2 == NULL)
1312 return (-1);
1313 return (wcscmp(p1, p2));
1314 }
1315
1316 static int
cmp_key_wcs(const struct archive_rb_node * n,const void * key)1317 cmp_key_wcs(const struct archive_rb_node *n, const void *key)
1318 {
1319 struct match_file *f = (struct match_file *)(uintptr_t)n;
1320 const wchar_t *p;
1321
1322 archive_mstring_get_wcs(NULL, &(f->pathname), &p);
1323 if (p == NULL)
1324 return (-1);
1325 return (wcscmp(p, (const wchar_t *)key));
1326 }
1327
1328 static void
entry_list_init(struct entry_list * list)1329 entry_list_init(struct entry_list *list)
1330 {
1331 list->first = NULL;
1332 list->last = &(list->first);
1333 list->count = 0;
1334 }
1335
1336 static void
entry_list_free(struct entry_list * list)1337 entry_list_free(struct entry_list *list)
1338 {
1339 struct match_file *p, *q;
1340
1341 for (p = list->first; p != NULL; ) {
1342 q = p;
1343 p = p->next;
1344 archive_mstring_clean(&(q->pathname));
1345 free(q);
1346 }
1347 }
1348
1349 static void
entry_list_add(struct entry_list * list,struct match_file * file)1350 entry_list_add(struct entry_list *list, struct match_file *file)
1351 {
1352 *list->last = file;
1353 list->last = &(file->next);
1354 list->count++;
1355 }
1356
1357 static int
add_entry(struct archive_match * a,int flag,struct archive_entry * entry)1358 add_entry(struct archive_match *a, int flag,
1359 struct archive_entry *entry)
1360 {
1361 struct match_file *f;
1362 const void *pathname;
1363 int r;
1364
1365 f = calloc(1, sizeof(*f));
1366 if (f == NULL)
1367 return (error_nomem(a));
1368
1369 #if defined(_WIN32) && !defined(__CYGWIN__)
1370 pathname = archive_entry_pathname_w(entry);
1371 if (pathname == NULL) {
1372 free(f);
1373 archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
1374 return (ARCHIVE_FAILED);
1375 }
1376 archive_mstring_copy_wcs(&(f->pathname), pathname);
1377 a->exclusion_tree.rbt_ops = &rb_ops_wcs;
1378 #else
1379 (void)rb_ops_wcs;
1380 pathname = archive_entry_pathname(entry);
1381 if (pathname == NULL) {
1382 free(f);
1383 archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
1384 return (ARCHIVE_FAILED);
1385 }
1386 archive_mstring_copy_mbs(&(f->pathname), pathname);
1387 a->exclusion_tree.rbt_ops = &rb_ops_mbs;
1388 #endif
1389 f->flag = flag;
1390 f->mtime_sec = archive_entry_mtime(entry);
1391 f->mtime_nsec = archive_entry_mtime_nsec(entry);
1392 f->ctime_sec = archive_entry_ctime(entry);
1393 f->ctime_nsec = archive_entry_ctime_nsec(entry);
1394 r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node));
1395 if (!r) {
1396 struct match_file *f2;
1397
1398 /* Get the duplicated file. */
1399 f2 = (struct match_file *)__archive_rb_tree_find_node(
1400 &(a->exclusion_tree), pathname);
1401
1402 /*
1403 * We always overwrite comparison condision.
1404 * If you do not want to overwrite it, you should not
1405 * call archive_match_exclude_entry(). We cannot know
1406 * what behavior you really expect since overwriting
1407 * condition might be different with the flag.
1408 */
1409 if (f2 != NULL) {
1410 f2->flag = f->flag;
1411 f2->mtime_sec = f->mtime_sec;
1412 f2->mtime_nsec = f->mtime_nsec;
1413 f2->ctime_sec = f->ctime_sec;
1414 f2->ctime_nsec = f->ctime_nsec;
1415 }
1416 /* Release the duplicated file. */
1417 archive_mstring_clean(&(f->pathname));
1418 free(f);
1419 return (ARCHIVE_OK);
1420 }
1421 entry_list_add(&(a->exclusion_entry_list), f);
1422 a->setflag |= TIME_IS_SET;
1423 return (ARCHIVE_OK);
1424 }
1425
1426 /*
1427 * Test if entry is excluded by its timestamp.
1428 */
1429 static int
time_excluded(struct archive_match * a,struct archive_entry * entry)1430 time_excluded(struct archive_match *a, struct archive_entry *entry)
1431 {
1432 struct match_file *f;
1433 const void *pathname;
1434 time_t sec;
1435 long nsec;
1436
1437 /*
1438 * If this file/dir is excluded by a time comparison, skip it.
1439 */
1440 if (a->newer_ctime_filter) {
1441 /* If ctime is not set, use mtime instead. */
1442 if (archive_entry_ctime_is_set(entry))
1443 sec = archive_entry_ctime(entry);
1444 else
1445 sec = archive_entry_mtime(entry);
1446 if (sec < a->newer_ctime_sec)
1447 return (1); /* Too old, skip it. */
1448 if (sec == a->newer_ctime_sec) {
1449 if (archive_entry_ctime_is_set(entry))
1450 nsec = archive_entry_ctime_nsec(entry);
1451 else
1452 nsec = archive_entry_mtime_nsec(entry);
1453 if (nsec < a->newer_ctime_nsec)
1454 return (1); /* Too old, skip it. */
1455 if (nsec == a->newer_ctime_nsec &&
1456 (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL)
1457 == 0)
1458 return (1); /* Equal, skip it. */
1459 }
1460 }
1461 if (a->older_ctime_filter) {
1462 /* If ctime is not set, use mtime instead. */
1463 if (archive_entry_ctime_is_set(entry))
1464 sec = archive_entry_ctime(entry);
1465 else
1466 sec = archive_entry_mtime(entry);
1467 if (sec > a->older_ctime_sec)
1468 return (1); /* Too new, skip it. */
1469 if (sec == a->older_ctime_sec) {
1470 if (archive_entry_ctime_is_set(entry))
1471 nsec = archive_entry_ctime_nsec(entry);
1472 else
1473 nsec = archive_entry_mtime_nsec(entry);
1474 if (nsec > a->older_ctime_nsec)
1475 return (1); /* Too new, skip it. */
1476 if (nsec == a->older_ctime_nsec &&
1477 (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
1478 == 0)
1479 return (1); /* Eeual, skip it. */
1480 }
1481 }
1482 if (a->newer_mtime_filter) {
1483 sec = archive_entry_mtime(entry);
1484 if (sec < a->newer_mtime_sec)
1485 return (1); /* Too old, skip it. */
1486 if (sec == a->newer_mtime_sec) {
1487 nsec = archive_entry_mtime_nsec(entry);
1488 if (nsec < a->newer_mtime_nsec)
1489 return (1); /* Too old, skip it. */
1490 if (nsec == a->newer_mtime_nsec &&
1491 (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL)
1492 == 0)
1493 return (1); /* Equal, skip it. */
1494 }
1495 }
1496 if (a->older_mtime_filter) {
1497 sec = archive_entry_mtime(entry);
1498 if (sec > a->older_mtime_sec)
1499 return (1); /* Too new, skip it. */
1500 nsec = archive_entry_mtime_nsec(entry);
1501 if (sec == a->older_mtime_sec) {
1502 if (nsec > a->older_mtime_nsec)
1503 return (1); /* Too new, skip it. */
1504 if (nsec == a->older_mtime_nsec &&
1505 (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL)
1506 == 0)
1507 return (1); /* Equal, skip it. */
1508 }
1509 }
1510
1511 /* If there is no excluson list, include the file. */
1512 if (a->exclusion_entry_list.count == 0)
1513 return (0);
1514
1515 #if defined(_WIN32) && !defined(__CYGWIN__)
1516 pathname = archive_entry_pathname_w(entry);
1517 a->exclusion_tree.rbt_ops = &rb_ops_wcs;
1518 #else
1519 (void)rb_ops_wcs;
1520 pathname = archive_entry_pathname(entry);
1521 a->exclusion_tree.rbt_ops = &rb_ops_mbs;
1522 #endif
1523 if (pathname == NULL)
1524 return (0);
1525
1526 f = (struct match_file *)__archive_rb_tree_find_node(
1527 &(a->exclusion_tree), pathname);
1528 /* If the file wasn't rejected, include it. */
1529 if (f == NULL)
1530 return (0);
1531
1532 if (f->flag & ARCHIVE_MATCH_CTIME) {
1533 sec = archive_entry_ctime(entry);
1534 if (f->ctime_sec > sec) {
1535 if (f->flag & ARCHIVE_MATCH_OLDER)
1536 return (1);
1537 } else if (f->ctime_sec < sec) {
1538 if (f->flag & ARCHIVE_MATCH_NEWER)
1539 return (1);
1540 } else {
1541 nsec = archive_entry_ctime_nsec(entry);
1542 if (f->ctime_nsec > nsec) {
1543 if (f->flag & ARCHIVE_MATCH_OLDER)
1544 return (1);
1545 } else if (f->ctime_nsec < nsec) {
1546 if (f->flag & ARCHIVE_MATCH_NEWER)
1547 return (1);
1548 } else if (f->flag & ARCHIVE_MATCH_EQUAL)
1549 return (1);
1550 }
1551 }
1552 if (f->flag & ARCHIVE_MATCH_MTIME) {
1553 sec = archive_entry_mtime(entry);
1554 if (f->mtime_sec > sec) {
1555 if (f->flag & ARCHIVE_MATCH_OLDER)
1556 return (1);
1557 } else if (f->mtime_sec < sec) {
1558 if (f->flag & ARCHIVE_MATCH_NEWER)
1559 return (1);
1560 } else {
1561 nsec = archive_entry_mtime_nsec(entry);
1562 if (f->mtime_nsec > nsec) {
1563 if (f->flag & ARCHIVE_MATCH_OLDER)
1564 return (1);
1565 } else if (f->mtime_nsec < nsec) {
1566 if (f->flag & ARCHIVE_MATCH_NEWER)
1567 return (1);
1568 } else if (f->flag & ARCHIVE_MATCH_EQUAL)
1569 return (1);
1570 }
1571 }
1572 return (0);
1573 }
1574
1575 /*
1576 * Utility functions to manage inclusion owners
1577 */
1578
1579 int
archive_match_include_uid(struct archive * _a,int64_t uid)1580 archive_match_include_uid(struct archive *_a, int64_t uid)
1581 {
1582 struct archive_match *a;
1583
1584 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1585 ARCHIVE_STATE_NEW, "archive_match_include_uid");
1586 a = (struct archive_match *)_a;
1587 return (add_owner_id(a, &(a->inclusion_uids), uid));
1588 }
1589
1590 int
archive_match_include_gid(struct archive * _a,int64_t gid)1591 archive_match_include_gid(struct archive *_a, int64_t gid)
1592 {
1593 struct archive_match *a;
1594
1595 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1596 ARCHIVE_STATE_NEW, "archive_match_include_gid");
1597 a = (struct archive_match *)_a;
1598 return (add_owner_id(a, &(a->inclusion_gids), gid));
1599 }
1600
1601 int
archive_match_include_uname(struct archive * _a,const char * uname)1602 archive_match_include_uname(struct archive *_a, const char *uname)
1603 {
1604 struct archive_match *a;
1605
1606 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1607 ARCHIVE_STATE_NEW, "archive_match_include_uname");
1608 a = (struct archive_match *)_a;
1609 return (add_owner_name(a, &(a->inclusion_unames), 1, uname));
1610 }
1611
1612 int
archive_match_include_uname_w(struct archive * _a,const wchar_t * uname)1613 archive_match_include_uname_w(struct archive *_a, const wchar_t *uname)
1614 {
1615 struct archive_match *a;
1616
1617 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1618 ARCHIVE_STATE_NEW, "archive_match_include_uname_w");
1619 a = (struct archive_match *)_a;
1620 return (add_owner_name(a, &(a->inclusion_unames), 0, uname));
1621 }
1622
1623 int
archive_match_include_gname(struct archive * _a,const char * gname)1624 archive_match_include_gname(struct archive *_a, const char *gname)
1625 {
1626 struct archive_match *a;
1627
1628 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1629 ARCHIVE_STATE_NEW, "archive_match_include_gname");
1630 a = (struct archive_match *)_a;
1631 return (add_owner_name(a, &(a->inclusion_gnames), 1, gname));
1632 }
1633
1634 int
archive_match_include_gname_w(struct archive * _a,const wchar_t * gname)1635 archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
1636 {
1637 struct archive_match *a;
1638
1639 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1640 ARCHIVE_STATE_NEW, "archive_match_include_gname_w");
1641 a = (struct archive_match *)_a;
1642 return (add_owner_name(a, &(a->inclusion_gnames), 0, gname));
1643 }
1644
1645 /*
1646 * Test function for owner(uid, gid, uname, gname).
1647 *
1648 * Returns 1 if archive entry is excluded.
1649 * Returns 0 if archive entry is not excluded.
1650 * Returns <0 if something error happened.
1651 */
1652 int
archive_match_owner_excluded(struct archive * _a,struct archive_entry * entry)1653 archive_match_owner_excluded(struct archive *_a,
1654 struct archive_entry *entry)
1655 {
1656 struct archive_match *a;
1657
1658 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1659 ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae");
1660
1661 a = (struct archive_match *)_a;
1662 if (entry == NULL) {
1663 archive_set_error(&(a->archive), EINVAL, "entry is NULL");
1664 return (ARCHIVE_FAILED);
1665 }
1666
1667 /* If we don't have inclusion id set at all, the entry is always
1668 * not excluded. */
1669 if ((a->setflag & ID_IS_SET) == 0)
1670 return (0);
1671 return (owner_excluded(a, entry));
1672 }
1673
1674 static int
add_owner_id(struct archive_match * a,struct id_array * ids,int64_t id)1675 add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
1676 {
1677 unsigned i;
1678
1679 if (ids->count + 1 >= ids->size) {
1680 void *p;
1681
1682 if (ids->size == 0)
1683 ids->size = 8;
1684 else
1685 ids->size *= 2;
1686 p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
1687 if (p == NULL)
1688 return (error_nomem(a));
1689 ids->ids = (int64_t *)p;
1690 }
1691
1692 /* Find an insert point. */
1693 for (i = 0; i < ids->count; i++) {
1694 if (ids->ids[i] >= id)
1695 break;
1696 }
1697
1698 /* Add oowner id. */
1699 if (i == ids->count)
1700 ids->ids[ids->count++] = id;
1701 else if (ids->ids[i] != id) {
1702 memmove(&(ids->ids[i+1]), &(ids->ids[i]),
1703 (ids->count - i) * sizeof(ids->ids[0]));
1704 ids->ids[i] = id;
1705 ids->count++;
1706 }
1707 a->setflag |= ID_IS_SET;
1708 return (ARCHIVE_OK);
1709 }
1710
1711 static int
match_owner_id(struct id_array * ids,int64_t id)1712 match_owner_id(struct id_array *ids, int64_t id)
1713 {
1714 unsigned b, m, t;
1715
1716 t = 0;
1717 b = (unsigned)ids->count;
1718 while (t < b) {
1719 m = (t + b)>>1;
1720 if (ids->ids[m] == id)
1721 return (1);
1722 if (ids->ids[m] < id)
1723 t = m + 1;
1724 else
1725 b = m;
1726 }
1727 return (0);
1728 }
1729
1730 static int
add_owner_name(struct archive_match * a,struct match_list * list,int mbs,const void * name)1731 add_owner_name(struct archive_match *a, struct match_list *list,
1732 int mbs, const void *name)
1733 {
1734 struct match *match;
1735
1736 match = calloc(1, sizeof(*match));
1737 if (match == NULL)
1738 return (error_nomem(a));
1739 if (mbs)
1740 archive_mstring_copy_mbs(&(match->pattern), name);
1741 else
1742 archive_mstring_copy_wcs(&(match->pattern), name);
1743 match_list_add(list, match);
1744 a->setflag |= ID_IS_SET;
1745 return (ARCHIVE_OK);
1746 }
1747
1748 #if !defined(_WIN32) || defined(__CYGWIN__)
1749 static int
match_owner_name_mbs(struct archive_match * a,struct match_list * list,const char * name)1750 match_owner_name_mbs(struct archive_match *a, struct match_list *list,
1751 const char *name)
1752 {
1753 struct match *m;
1754 const char *p;
1755
1756 if (name == NULL || *name == '\0')
1757 return (0);
1758 for (m = list->first; m; m = m->next) {
1759 if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p)
1760 < 0 && errno == ENOMEM)
1761 return (error_nomem(a));
1762 if (p != NULL && strcmp(p, name) == 0) {
1763 m->matches++;
1764 return (1);
1765 }
1766 }
1767 return (0);
1768 }
1769 #else
1770 static int
match_owner_name_wcs(struct archive_match * a,struct match_list * list,const wchar_t * name)1771 match_owner_name_wcs(struct archive_match *a, struct match_list *list,
1772 const wchar_t *name)
1773 {
1774 struct match *m;
1775 const wchar_t *p;
1776
1777 if (name == NULL || *name == L'\0')
1778 return (0);
1779 for (m = list->first; m; m = m->next) {
1780 if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p)
1781 < 0 && errno == ENOMEM)
1782 return (error_nomem(a));
1783 if (p != NULL && wcscmp(p, name) == 0) {
1784 m->matches++;
1785 return (1);
1786 }
1787 }
1788 return (0);
1789 }
1790 #endif
1791
1792 /*
1793 * Test if entry is excluded by uid, gid, uname or gname.
1794 */
1795 static int
owner_excluded(struct archive_match * a,struct archive_entry * entry)1796 owner_excluded(struct archive_match *a, struct archive_entry *entry)
1797 {
1798 int r;
1799
1800 if (a->inclusion_uids.count) {
1801 if (!match_owner_id(&(a->inclusion_uids),
1802 archive_entry_uid(entry)))
1803 return (1);
1804 }
1805
1806 if (a->inclusion_gids.count) {
1807 if (!match_owner_id(&(a->inclusion_gids),
1808 archive_entry_gid(entry)))
1809 return (1);
1810 }
1811
1812 if (a->inclusion_unames.count) {
1813 #if defined(_WIN32) && !defined(__CYGWIN__)
1814 r = match_owner_name_wcs(a, &(a->inclusion_unames),
1815 archive_entry_uname_w(entry));
1816 #else
1817 r = match_owner_name_mbs(a, &(a->inclusion_unames),
1818 archive_entry_uname(entry));
1819 #endif
1820 if (!r)
1821 return (1);
1822 else if (r < 0)
1823 return (r);
1824 }
1825
1826 if (a->inclusion_gnames.count) {
1827 #if defined(_WIN32) && !defined(__CYGWIN__)
1828 r = match_owner_name_wcs(a, &(a->inclusion_gnames),
1829 archive_entry_gname_w(entry));
1830 #else
1831 r = match_owner_name_mbs(a, &(a->inclusion_gnames),
1832 archive_entry_gname(entry));
1833 #endif
1834 if (!r)
1835 return (1);
1836 else if (r < 0)
1837 return (r);
1838 }
1839 return (0);
1840 }
1841
1842