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