Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmlibarchive/libarchive/archive_match.c
Line
Count
Source
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
4.65k
#define PATTERN_IS_SET    1
87
4.65k
#define TIME_IS_SET   2
88
4.65k
#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
0
#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
0
{
214
0
  archive_set_error(&(a->archive), ENOMEM, "No memory");
215
0
  a->archive.state = ARCHIVE_STATE_FATAL;
216
0
  return (ARCHIVE_FATAL);
217
0
}
218
219
/*
220
 * Create an ARCHIVE_MATCH object.
221
 */
222
struct archive *
223
archive_match_new(void)
224
29.0k
{
225
29.0k
  struct archive_match *a;
226
227
29.0k
  a = calloc(1, sizeof(*a));
228
29.0k
  if (a == NULL)
229
0
    return (NULL);
230
29.0k
  a->archive.magic = ARCHIVE_MATCH_MAGIC;
231
29.0k
  a->archive.state = ARCHIVE_STATE_NEW;
232
29.0k
  a->recursive_include = 1;
233
29.0k
  match_list_init(&(a->inclusions));
234
29.0k
  match_list_init(&(a->exclusions));
235
29.0k
  __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops);
236
29.0k
  entry_list_init(&(a->exclusion_entry_list));
237
29.0k
  match_list_init(&(a->inclusion_unames));
238
29.0k
  match_list_init(&(a->inclusion_gnames));
239
29.0k
  time(&a->now);
240
29.0k
  return (&(a->archive));
241
29.0k
}
242
243
/*
244
 * Free an ARCHIVE_MATCH object.
245
 */
246
int
247
archive_match_free(struct archive *_a)
248
29.0k
{
249
29.0k
  struct archive_match *a;
250
251
29.0k
  if (_a == NULL)
252
0
    return (ARCHIVE_OK);
253
29.0k
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
254
29.0k
      ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free");
255
29.0k
  a = (struct archive_match *)_a;
256
29.0k
  match_list_free(&(a->inclusions));
257
29.0k
  match_list_free(&(a->exclusions));
258
29.0k
  entry_list_free(&(a->exclusion_entry_list));
259
29.0k
  free(a->inclusion_uids.ids);
260
29.0k
  free(a->inclusion_gids.ids);
261
29.0k
  match_list_free(&(a->inclusion_unames));
262
29.0k
  match_list_free(&(a->inclusion_gnames));
263
29.0k
  free(a);
264
29.0k
  return (ARCHIVE_OK);
265
29.0k
}
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
4.65k
{
277
4.65k
  struct archive_match *a;
278
4.65k
  int r;
279
280
4.65k
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
281
4.65k
      ARCHIVE_STATE_NEW, "archive_match_excluded_ae");
282
283
4.65k
  a = (struct archive_match *)_a;
284
4.65k
  if (entry == NULL) {
285
0
    archive_set_error(&(a->archive), EINVAL, "entry is NULL");
286
0
    return (ARCHIVE_FAILED);
287
0
  }
288
289
4.65k
  r = 0;
290
4.65k
  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
0
    r = path_excluded(a, 1, archive_entry_pathname(entry));
295
0
#endif
296
0
    if (r != 0)
297
0
      return (r);
298
0
  }
299
300
4.65k
  if (a->setflag & TIME_IS_SET) {
301
0
    r = time_excluded(a, entry);
302
0
    if (r != 0)
303
0
      return (r);
304
0
  }
305
306
4.65k
  if (a->setflag & ID_IS_SET)
307
0
    r = owner_excluded(a, entry);
308
4.65k
  return (r);
309
4.65k
}
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
0
{
318
0
  struct archive_match *a;
319
0
  int r;
320
321
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
322
0
      ARCHIVE_STATE_NEW, "archive_match_exclude_pattern");
323
0
  a = (struct archive_match *)_a;
324
325
0
  if (pattern == NULL || *pattern == '\0') {
326
0
    archive_set_error(&(a->archive), EINVAL, "pattern is empty");
327
0
    return (ARCHIVE_FAILED);
328
0
  }
329
0
  if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
330
0
    return (r);
331
0
  return (ARCHIVE_OK);
332
0
}
333
334
int
335
archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern)
336
0
{
337
0
  struct archive_match *a;
338
0
  int r;
339
340
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
341
0
      ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w");
342
0
  a = (struct archive_match *)_a;
343
344
0
  if (pattern == NULL || *pattern == L'\0') {
345
0
    archive_set_error(&(a->archive), EINVAL, "pattern is empty");
346
0
    return (ARCHIVE_FAILED);
347
0
  }
348
0
  if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
349
0
    return (r);
350
0
  return (ARCHIVE_OK);
351
0
}
352
353
int
354
archive_match_exclude_pattern_from_file(struct archive *_a,
355
    const char *pathname, int nullSeparator)
356
0
{
357
0
  struct archive_match *a;
358
359
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
360
0
      ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file");
361
0
  a = (struct archive_match *)_a;
362
363
0
  return add_pattern_from_file(a, &(a->exclusions), 1, pathname,
364
0
    nullSeparator);
365
0
}
366
367
int
368
archive_match_exclude_pattern_from_file_w(struct archive *_a,
369
    const wchar_t *pathname, int nullSeparator)
370
0
{
371
0
  struct archive_match *a;
372
373
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
374
0
      ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w");
375
0
  a = (struct archive_match *)_a;
376
377
0
  return add_pattern_from_file(a, &(a->exclusions), 0, pathname,
378
0
    nullSeparator);
379
0
}
380
381
int
382
archive_match_include_pattern(struct archive *_a, const char *pattern)
383
0
{
384
0
  struct archive_match *a;
385
0
  int r;
386
387
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
388
0
      ARCHIVE_STATE_NEW, "archive_match_include_pattern");
389
0
  a = (struct archive_match *)_a;
390
391
0
  if (pattern == NULL || *pattern == '\0') {
392
0
    archive_set_error(&(a->archive), EINVAL, "pattern is empty");
393
0
    return (ARCHIVE_FAILED);
394
0
  }
395
0
  if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
396
0
    return (r);
397
0
  return (ARCHIVE_OK);
398
0
}
399
400
int
401
archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern)
402
0
{
403
0
  struct archive_match *a;
404
0
  int r;
405
406
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
407
0
      ARCHIVE_STATE_NEW, "archive_match_include_pattern_w");
408
0
  a = (struct archive_match *)_a;
409
410
0
  if (pattern == NULL || *pattern == L'\0') {
411
0
    archive_set_error(&(a->archive), EINVAL, "pattern is empty");
412
0
    return (ARCHIVE_FAILED);
413
0
  }
414
0
  if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
415
0
    return (r);
416
0
  return (ARCHIVE_OK);
417
0
}
418
419
int
420
archive_match_include_pattern_from_file(struct archive *_a,
421
    const char *pathname, int nullSeparator)
422
0
{
423
0
  struct archive_match *a;
424
425
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
426
0
      ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file");
427
0
  a = (struct archive_match *)_a;
428
429
0
  return add_pattern_from_file(a, &(a->inclusions), 1, pathname,
430
0
    nullSeparator);
431
0
}
432
433
int
434
archive_match_include_pattern_from_file_w(struct archive *_a,
435
    const wchar_t *pathname, int nullSeparator)
436
0
{
437
0
  struct archive_match *a;
438
439
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
440
0
      ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w");
441
0
  a = (struct archive_match *)_a;
442
443
0
  return add_pattern_from_file(a, &(a->inclusions), 0, pathname,
444
0
    nullSeparator);
445
0
}
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
0
{
458
0
  struct archive_match *a;
459
460
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
461
0
      ARCHIVE_STATE_NEW, "archive_match_path_excluded");
462
463
0
  a = (struct archive_match *)_a;
464
0
  if (entry == NULL) {
465
0
    archive_set_error(&(a->archive), EINVAL, "entry is NULL");
466
0
    return (ARCHIVE_FAILED);
467
0
  }
468
469
  /* If we don't have exclusion/inclusion pattern set at all,
470
   * the entry is always not excluded. */
471
0
  if ((a->setflag & PATTERN_IS_SET) == 0)
472
0
    return (0);
473
#if defined(_WIN32) && !defined(__CYGWIN__)
474
  return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
475
#else
476
0
  return (path_excluded(a, 1, archive_entry_pathname(entry)));
477
0
#endif
478
0
}
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
0
{
493
0
  struct archive_match *a;
494
495
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
496
0
      ARCHIVE_STATE_NEW, "archive_match_set_inclusion_recursion");
497
0
  a = (struct archive_match *)_a;
498
0
  a->recursive_include = enabled;
499
0
  return (ARCHIVE_OK);
500
0
}
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
0
{
508
0
  struct archive_match *a;
509
510
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
511
0
      ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
512
0
  a = (struct archive_match *)_a;
513
514
0
  if (a->inclusions.unmatched_count > (size_t)INT_MAX)
515
0
    return INT_MAX;
516
0
  return (int)(a->inclusions.unmatched_count);
517
0
}
518
519
int
520
archive_match_path_unmatched_inclusions_next(struct archive *_a,
521
    const char **_p)
522
10.9k
{
523
10.9k
  struct archive_match *a;
524
10.9k
  const void *v;
525
10.9k
  int r;
526
527
10.9k
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
528
10.9k
      ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next");
529
10.9k
  a = (struct archive_match *)_a;
530
531
10.9k
  r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v);
532
10.9k
  *_p = (const char *)v;
533
10.9k
  return (r);
534
10.9k
}
535
536
int
537
archive_match_path_unmatched_inclusions_next_w(struct archive *_a,
538
    const wchar_t **_p)
539
0
{
540
0
  struct archive_match *a;
541
0
  const void *v;
542
0
  int r;
543
544
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
545
0
      ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w");
546
0
  a = (struct archive_match *)_a;
547
548
0
  r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v);
549
0
  *_p = (const wchar_t *)v;
550
0
  return (r);
551
0
}
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
0
{
560
0
  struct match *match;
561
0
  size_t len;
562
563
0
  match = calloc(1, sizeof(*match));
564
0
  if (match == NULL)
565
0
    return (error_nomem(a));
566
  /* Both "foo/" and "foo" should match "foo/bar". */
567
0
  len = strlen(pattern);
568
0
  if (len && pattern[len - 1] == '/')
569
0
    --len;
570
0
  archive_mstring_copy_mbs_len(&(match->pattern), pattern, len);
571
0
  match_list_add(list, match);
572
0
  a->setflag |= PATTERN_IS_SET;
573
0
  return (ARCHIVE_OK);
574
0
}
575
576
static int
577
add_pattern_wcs(struct archive_match *a, struct match_list *list,
578
    const wchar_t *pattern)
579
0
{
580
0
  struct match *match;
581
0
  size_t len;
582
583
0
  match = calloc(1, sizeof(*match));
584
0
  if (match == NULL)
585
0
    return (error_nomem(a));
586
  /* Both "foo/" and "foo" should match "foo/bar". */
587
0
  len = wcslen(pattern);
588
0
  if (len && pattern[len - 1] == L'/')
589
0
    --len;
590
0
  archive_mstring_copy_wcs_len(&(match->pattern), pattern, len);
591
0
  match_list_add(list, match);
592
0
  a->setflag |= PATTERN_IS_SET;
593
0
  return (ARCHIVE_OK);
594
0
}
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
0
{
600
0
  struct archive *ar;
601
0
  struct archive_entry *ae;
602
0
  struct archive_string as;
603
0
  const void *buff;
604
0
  size_t size;
605
0
  int64_t offset;
606
0
  int r;
607
608
0
  ar = archive_read_new();
609
0
  if (ar == NULL) {
610
0
    archive_set_error(&(a->archive), ENOMEM, "No memory");
611
0
    return (ARCHIVE_FATAL);
612
0
  }
613
0
  r = archive_read_support_format_raw(ar);
614
0
  if (r == ARCHIVE_OK)
615
0
    r = archive_read_support_format_empty(ar);
616
0
  if (r != ARCHIVE_OK) {
617
0
    archive_copy_error(&(a->archive), ar);
618
0
    archive_read_free(ar);
619
0
    return (r);
620
0
  }
621
0
  if (mbs)
622
0
    r = archive_read_open_filename(ar, pathname, 512*20);
623
0
  else
624
0
    r = archive_read_open_filename_w(ar, pathname, 512*20);
625
0
  if (r != ARCHIVE_OK) {
626
0
    archive_copy_error(&(a->archive), ar);
627
0
    archive_read_free(ar);
628
0
    return (r);
629
0
  }
630
0
  r = archive_read_next_header(ar, &ae);
631
0
  if (r != ARCHIVE_OK) {
632
0
    archive_read_free(ar);
633
0
    if (r == ARCHIVE_EOF) {
634
0
      return (ARCHIVE_OK);
635
0
    } else {
636
0
      archive_copy_error(&(a->archive), ar);
637
0
      return (r);
638
0
    }
639
0
  }
640
641
0
  archive_string_init(&as);
642
643
0
  while ((r = archive_read_data_block(ar, &buff, &size, &offset))
644
0
      == ARCHIVE_OK) {
645
0
    const char *b = (const char *)buff;
646
647
0
    while (size) {
648
0
      const char *s = (const char *)b;
649
0
      size_t length = 0;
650
0
      int found_separator = 0;
651
652
0
      while (length < size) {
653
0
        if (nullSeparator) {
654
0
          if (*b == '\0') {
655
0
            found_separator = 1;
656
0
            break;
657
0
          }
658
0
        } else {
659
0
          if (*b == 0x0d || *b == 0x0a) {
660
0
            found_separator = 1;
661
0
            break;
662
0
          }
663
0
        }
664
0
        b++;
665
0
        length++;
666
0
      }
667
0
      if (!found_separator) {
668
0
        archive_strncat(&as, s, length);
669
        /* Read next data block. */
670
0
        break;
671
0
      }
672
0
      b++;
673
0
      size -= length + 1;
674
0
      archive_strncat(&as, s, length);
675
676
      /* If the line is not empty, add the pattern. */
677
0
      if (archive_strlen(&as) > 0) {
678
        /* Add pattern. */
679
0
        r = add_pattern_mbs(a, mlist, as.s);
680
0
        if (r != ARCHIVE_OK) {
681
0
          archive_read_free(ar);
682
0
          archive_string_free(&as);
683
0
          return (r);
684
0
        }
685
0
        archive_string_empty(&as);
686
0
      }
687
0
    }
688
0
  }
689
690
  /* If an error occurred, report it immediately. */
691
0
  if (r < ARCHIVE_OK) {
692
0
    archive_copy_error(&(a->archive), ar);
693
0
    archive_read_free(ar);
694
0
    archive_string_free(&as);
695
0
    return (r);
696
0
  }
697
698
  /* If the line is not empty, add the pattern. */
699
0
  if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) {
700
    /* Add pattern. */
701
0
    r = add_pattern_mbs(a, mlist, as.s);
702
0
    if (r != ARCHIVE_OK) {
703
0
      archive_read_free(ar);
704
0
      archive_string_free(&as);
705
0
      return (r);
706
0
    }
707
0
  }
708
0
  archive_read_free(ar);
709
0
  archive_string_free(&as);
710
0
  return (ARCHIVE_OK);
711
0
}
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
0
{
719
0
  struct match *match;
720
0
  struct match *matched;
721
0
  int r;
722
723
0
  if (a == NULL)
724
0
    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
0
  matched = NULL;
732
0
  for (match = a->inclusions.first; match != NULL;
733
0
      match = match->next){
734
0
    if (!match->matched &&
735
0
        (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
736
0
      if (r < 0)
737
0
        return (r);
738
0
      a->inclusions.unmatched_count--;
739
0
      match->matched = 1;
740
0
      matched = match;
741
0
    }
742
0
  }
743
744
  /* Exclusions take priority. */
745
0
  for (match = a->exclusions.first; match != NULL;
746
0
      match = match->next){
747
0
    r = match_path_exclusion(a, match, mbs, pathname);
748
0
    if (r)
749
0
      return (r);
750
0
  }
751
752
  /* It's not excluded and we found an inclusion above, so it's
753
   * included. */
754
0
  if (matched != NULL)
755
0
    return (0);
756
757
758
  /* We didn't find an unmatched inclusion, check the remaining ones. */
759
0
  for (match = a->inclusions.first; match != NULL;
760
0
      match = match->next){
761
    /* We looked at previously-unmatched inclusions already. */
762
0
    if (match->matched &&
763
0
        (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
764
0
      if (r < 0)
765
0
        return (r);
766
0
      return (0);
767
0
    }
768
0
  }
769
770
  /* If there were inclusions, default is to exclude. */
771
0
  if (a->inclusions.first != NULL)
772
0
      return (1);
773
774
  /* No explicit inclusions, default is to match. */
775
0
  return (0);
776
0
}
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
0
{
787
0
  int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END;
788
0
  int r;
789
790
0
  if (mbs) {
791
0
    const char *p;
792
0
    r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
793
0
    if (r == 0)
794
0
      return (archive_pathmatch(p, (const char *)pn, flag));
795
0
  } else {
796
0
    const wchar_t *p;
797
0
    r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
798
0
    if (r == 0)
799
0
      return (archive_pathmatch_w(p, (const wchar_t *)pn,
800
0
        flag));
801
0
  }
802
0
  if (errno == ENOMEM)
803
0
    return (error_nomem(a));
804
0
  return (0);
805
0
}
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
0
{
815
  /* Recursive operation requires only a prefix match. */
816
0
  int flag = a->recursive_include ?
817
0
    PATHMATCH_NO_ANCHOR_END :
818
0
    0;
819
0
  int r;
820
821
0
  if (mbs) {
822
0
    const char *p;
823
0
    r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
824
0
    if (r == 0)
825
0
      return (archive_pathmatch(p, (const char *)pn, flag));
826
0
  } else {
827
0
    const wchar_t *p;
828
0
    r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
829
0
    if (r == 0)
830
0
      return (archive_pathmatch_w(p, (const wchar_t *)pn,
831
0
        flag));
832
0
  }
833
0
  if (errno == ENOMEM)
834
0
    return (error_nomem(a));
835
0
  return (0);
836
0
}
837
838
static void
839
match_list_init(struct match_list *list)
840
116k
{
841
116k
  list->first = NULL;
842
116k
  list->last = &(list->first);
843
116k
}
844
845
static void
846
match_list_free(struct match_list *list)
847
116k
{
848
116k
  struct match *p, *q;
849
850
116k
  for (p = list->first; p != NULL; ) {
851
0
    q = p;
852
0
    p = p->next;
853
0
    archive_mstring_clean(&(q->pattern));
854
0
    free(q);
855
0
  }
856
116k
}
857
858
static void
859
match_list_add(struct match_list *list, struct match *m)
860
0
{
861
0
  *list->last = m;
862
0
  list->last = &(m->next);
863
0
  list->unmatched_count++;
864
0
}
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
10.9k
{
870
10.9k
  struct match *m;
871
872
10.9k
  *vp = NULL;
873
10.9k
  if (list->unmatched_eof) {
874
0
    list->unmatched_eof = 0;
875
0
    return (ARCHIVE_EOF);
876
0
  }
877
10.9k
  if (list->unmatched_next == NULL) {
878
10.9k
    if (list->unmatched_count == 0)
879
10.9k
      return (ARCHIVE_EOF);
880
0
    list->unmatched_next = list->first;
881
0
  }
882
883
0
  for (m = list->unmatched_next; m != NULL; m = m->next) {
884
0
    int r;
885
886
0
    if (m->matched)
887
0
      continue;
888
0
    if (mbs) {
889
0
      const char *p;
890
0
      r = archive_mstring_get_mbs(&(a->archive),
891
0
        &(m->pattern), &p);
892
0
      if (r < 0 && errno == ENOMEM)
893
0
        return (error_nomem(a));
894
0
      if (p == NULL)
895
0
        p = "";
896
0
      *vp = p;
897
0
    } else {
898
0
      const wchar_t *p;
899
0
      r = archive_mstring_get_wcs(&(a->archive),
900
0
        &(m->pattern), &p);
901
0
      if (r < 0 && errno == ENOMEM)
902
0
        return (error_nomem(a));
903
0
      if (p == NULL)
904
0
        p = L"";
905
0
      *vp = p;
906
0
    }
907
0
    list->unmatched_next = m->next;
908
0
    if (list->unmatched_next == NULL)
909
      /* To return EOF next time. */
910
0
      list->unmatched_eof = 1;
911
0
    return (ARCHIVE_OK);
912
0
  }
913
0
  list->unmatched_next = NULL;
914
0
  return (ARCHIVE_EOF);
915
0
}
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
0
{
924
0
  int r;
925
926
0
  r = validate_time_flag(_a, flag, "archive_match_include_time");
927
0
  if (r != ARCHIVE_OK)
928
0
    return (r);
929
0
  return set_timefilter((struct archive_match *)_a, flag,
930
0
      sec, nsec, sec, nsec);
931
0
}
932
933
int
934
archive_match_include_date(struct archive *_a, int flag,
935
    const char *datestr)
936
0
{
937
0
  int r;
938
939
0
  r = validate_time_flag(_a, flag, "archive_match_include_date");
940
0
  if (r != ARCHIVE_OK)
941
0
    return (r);
942
0
  return set_timefilter_date((struct archive_match *)_a, flag, datestr);
943
0
}
944
945
int
946
archive_match_include_date_w(struct archive *_a, int flag,
947
    const wchar_t *datestr)
948
0
{
949
0
  int r;
950
951
0
  r = validate_time_flag(_a, flag, "archive_match_include_date_w");
952
0
  if (r != ARCHIVE_OK)
953
0
    return (r);
954
955
0
  return set_timefilter_date_w((struct archive_match *)_a, flag, datestr);
956
0
}
957
958
int
959
archive_match_include_file_time(struct archive *_a, int flag,
960
    const char *pathname)
961
0
{
962
0
  int r;
963
964
0
  r = validate_time_flag(_a, flag, "archive_match_include_file_time");
965
0
  if (r != ARCHIVE_OK)
966
0
    return (r);
967
0
  return set_timefilter_pathname_mbs((struct archive_match *)_a,
968
0
      flag, pathname);
969
0
}
970
971
int
972
archive_match_include_file_time_w(struct archive *_a, int flag,
973
    const wchar_t *pathname)
974
0
{
975
0
  int r;
976
977
0
  r = validate_time_flag(_a, flag, "archive_match_include_file_time_w");
978
0
  if (r != ARCHIVE_OK)
979
0
    return (r);
980
0
  return set_timefilter_pathname_wcs((struct archive_match *)_a,
981
0
      flag, pathname);
982
0
}
983
984
int
985
archive_match_exclude_entry(struct archive *_a, int flag,
986
    struct archive_entry *entry)
987
0
{
988
0
  struct archive_match *a;
989
0
  int r;
990
991
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
992
0
      ARCHIVE_STATE_NEW, "archive_match_time_include_entry");
993
0
  a = (struct archive_match *)_a;
994
995
0
  if (entry == NULL) {
996
0
    archive_set_error(&(a->archive), EINVAL, "entry is NULL");
997
0
    return (ARCHIVE_FAILED);
998
0
  }
999
0
  r = validate_time_flag(_a, flag, "archive_match_exclude_entry");
1000
0
  if (r != ARCHIVE_OK)
1001
0
    return (r);
1002
0
  return (add_entry(a, flag, entry));
1003
0
}
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
0
{
1016
0
  struct archive_match *a;
1017
1018
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1019
0
      ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae");
1020
1021
0
  a = (struct archive_match *)_a;
1022
0
  if (entry == NULL) {
1023
0
    archive_set_error(&(a->archive), EINVAL, "entry is NULL");
1024
0
    return (ARCHIVE_FAILED);
1025
0
  }
1026
1027
  /* If we don't have inclusion time set at all, the entry is always
1028
   * not excluded. */
1029
0
  if ((a->setflag & TIME_IS_SET) == 0)
1030
0
    return (0);
1031
0
  return (time_excluded(a, entry));
1032
0
}
1033
1034
static int
1035
validate_time_flag(struct archive *_a, int flag, const char *_fn)
1036
0
{
1037
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1038
0
      ARCHIVE_STATE_NEW, _fn);
1039
1040
  /* Check a type of time. */
1041
0
  if (flag &
1042
0
     ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) {
1043
0
    archive_set_error(_a, EINVAL, "Invalid time flag");
1044
0
    return (ARCHIVE_FAILED);
1045
0
  }
1046
0
  if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) {
1047
0
    archive_set_error(_a, EINVAL, "No time flag");
1048
0
    return (ARCHIVE_FAILED);
1049
0
  }
1050
1051
  /* Check a type of comparison. */
1052
0
  if (flag &
1053
0
     ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
1054
0
      | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) {
1055
0
    archive_set_error(_a, EINVAL, "Invalid comparison flag");
1056
0
    return (ARCHIVE_FAILED);
1057
0
  }
1058
0
  if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
1059
0
      | ARCHIVE_MATCH_EQUAL)) == 0) {
1060
0
    archive_set_error(_a, EINVAL, "No comparison flag");
1061
0
    return (ARCHIVE_FAILED);
1062
0
  }
1063
1064
0
  return (ARCHIVE_OK);
1065
0
}
1066
1067
0
#define JUST_EQUAL(t) (((t) &  (ARCHIVE_MATCH_EQUAL |\
1068
0
  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
0
{
1073
0
  if (timetype & ARCHIVE_MATCH_MTIME) {
1074
0
    if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
1075
0
      a->newer_mtime_filter = timetype;
1076
0
      a->newer_mtime_sec = mtime_sec;
1077
0
      a->newer_mtime_nsec = mtime_nsec;
1078
0
      a->setflag |= TIME_IS_SET;
1079
0
    }
1080
0
    if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
1081
0
      a->older_mtime_filter = timetype;
1082
0
      a->older_mtime_sec = mtime_sec;
1083
0
      a->older_mtime_nsec = mtime_nsec;
1084
0
      a->setflag |= TIME_IS_SET;
1085
0
    }
1086
0
  }
1087
0
  if (timetype & ARCHIVE_MATCH_CTIME) {
1088
0
    if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
1089
0
      a->newer_ctime_filter = timetype;
1090
0
      a->newer_ctime_sec = ctime_sec;
1091
0
      a->newer_ctime_nsec = ctime_nsec;
1092
0
      a->setflag |= TIME_IS_SET;
1093
0
    }
1094
0
    if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
1095
0
      a->older_ctime_filter = timetype;
1096
0
      a->older_ctime_sec = ctime_sec;
1097
0
      a->older_ctime_nsec = ctime_nsec;
1098
0
      a->setflag |= TIME_IS_SET;
1099
0
    }
1100
0
  }
1101
0
  return (ARCHIVE_OK);
1102
0
}
1103
1104
static int
1105
set_timefilter_date(struct archive_match *a, int timetype, const char *datestr)
1106
0
{
1107
0
  time_t t;
1108
1109
0
  if (datestr == NULL || *datestr == '\0') {
1110
0
    archive_set_error(&(a->archive), EINVAL, "date is empty");
1111
0
    return (ARCHIVE_FAILED);
1112
0
  }
1113
0
  t = get_date(a->now, datestr);
1114
0
  if (t == (time_t)-1) {
1115
0
    archive_set_error(&(a->archive), EINVAL, "invalid date string");
1116
0
    return (ARCHIVE_FAILED);
1117
0
  }
1118
0
  return set_timefilter(a, timetype, t, 0, t, 0);
1119
0
}
1120
1121
static int
1122
set_timefilter_date_w(struct archive_match *a, int timetype,
1123
    const wchar_t *datestr)
1124
0
{
1125
0
  struct archive_string as;
1126
0
  time_t t;
1127
1128
0
  if (datestr == NULL || *datestr == L'\0') {
1129
0
    archive_set_error(&(a->archive), EINVAL, "date is empty");
1130
0
    return (ARCHIVE_FAILED);
1131
0
  }
1132
1133
0
  archive_string_init(&as);
1134
0
  if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) {
1135
0
    archive_string_free(&as);
1136
0
    if (errno == ENOMEM)
1137
0
      return (error_nomem(a));
1138
0
    archive_set_error(&(a->archive), -1,
1139
0
        "Failed to convert WCS to MBS");
1140
0
    return (ARCHIVE_FAILED);
1141
0
  }
1142
0
  t = get_date(a->now, as.s);
1143
0
  archive_string_free(&as);
1144
0
  if (t == (time_t)-1) {
1145
0
    archive_set_error(&(a->archive), EINVAL, "invalid date string");
1146
0
    return (ARCHIVE_FAILED);
1147
0
  }
1148
0
  return set_timefilter(a, timetype, t, 0, t, 0);
1149
0
}
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
0
{
1215
0
  struct archive_entry *ae;
1216
0
  time_t ctime_sec, mtime_sec;
1217
0
  long ctime_ns, mtime_ns;
1218
1219
0
  ae = archive_entry_new();
1220
0
  if (ae == NULL)
1221
0
    return (error_nomem(a));
1222
0
  archive_entry_copy_stat(ae, st);
1223
0
  ctime_sec = archive_entry_ctime(ae);
1224
0
  ctime_ns = archive_entry_ctime_nsec(ae);
1225
0
  mtime_sec = archive_entry_mtime(ae);
1226
0
  mtime_ns = archive_entry_mtime_nsec(ae);
1227
0
  archive_entry_free(ae);
1228
0
  return set_timefilter(a, timetype, mtime_sec, mtime_ns,
1229
0
      ctime_sec, ctime_ns);
1230
0
}
1231
1232
static int
1233
set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
1234
    const char *path)
1235
0
{
1236
0
  struct stat st;
1237
1238
0
  if (path == NULL || *path == '\0') {
1239
0
    archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1240
0
    return (ARCHIVE_FAILED);
1241
0
  }
1242
0
  if (la_stat(path, &st) != 0) {
1243
0
    archive_set_error(&(a->archive), errno, "Failed to stat()");
1244
0
    return (ARCHIVE_FAILED);
1245
0
  }
1246
0
  return (set_timefilter_stat(a, timetype, &st));
1247
0
}
1248
1249
static int
1250
set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
1251
    const wchar_t *path)
1252
0
{
1253
0
  struct archive_string as;
1254
0
  int r;
1255
1256
0
  if (path == NULL || *path == L'\0') {
1257
0
    archive_set_error(&(a->archive), EINVAL, "pathname is empty");
1258
0
    return (ARCHIVE_FAILED);
1259
0
  }
1260
1261
  /* Convert WCS filename to MBS filename. */
1262
0
  archive_string_init(&as);
1263
0
  if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) {
1264
0
    archive_string_free(&as);
1265
0
    if (errno == ENOMEM)
1266
0
      return (error_nomem(a));
1267
0
    archive_set_error(&(a->archive), -1,
1268
0
        "Failed to convert WCS to MBS");
1269
0
    return (ARCHIVE_FAILED);
1270
0
  }
1271
1272
0
  r = set_timefilter_pathname_mbs(a, timetype, as.s);
1273
0
  archive_string_free(&as);
1274
1275
0
  return (r);
1276
0
}
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
0
{
1287
0
  struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
1288
0
  struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
1289
0
  const char *p1, *p2;
1290
1291
0
  archive_mstring_get_mbs(NULL, &(f1->pathname), &p1);
1292
0
  archive_mstring_get_mbs(NULL, &(f2->pathname), &p2);
1293
0
  if (p1 == NULL)
1294
0
    return (1);
1295
0
  if (p2 == NULL)
1296
0
    return (-1);
1297
0
  return (strcmp(p1, p2));
1298
0
}
1299
1300
static int
1301
cmp_key_mbs(const struct archive_rb_node *n, const void *key)
1302
0
{
1303
0
  struct match_file *f = (struct match_file *)(uintptr_t)n;
1304
0
  const char *p;
1305
1306
0
  archive_mstring_get_mbs(NULL, &(f->pathname), &p);
1307
0
  if (p == NULL)
1308
0
    return (-1);
1309
0
  return (strcmp(p, (const char *)key));
1310
0
}
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
29.0k
{
1345
29.0k
  list->first = NULL;
1346
29.0k
  list->last = &(list->first);
1347
29.0k
}
1348
1349
static void
1350
entry_list_free(struct entry_list *list)
1351
29.0k
{
1352
29.0k
  struct match_file *p, *q;
1353
1354
29.0k
  for (p = list->first; p != NULL; ) {
1355
0
    q = p;
1356
0
    p = p->next;
1357
0
    archive_mstring_clean(&(q->pathname));
1358
0
    free(q);
1359
0
  }
1360
29.0k
}
1361
1362
static void
1363
entry_list_add(struct entry_list *list, struct match_file *file)
1364
0
{
1365
0
  *list->last = file;
1366
0
  list->last = &(file->next);
1367
0
}
1368
1369
static int
1370
add_entry(struct archive_match *a, int flag,
1371
    struct archive_entry *entry)
1372
0
{
1373
0
  struct match_file *f;
1374
0
  const void *pathname;
1375
0
  int r;
1376
1377
0
  f = calloc(1, sizeof(*f));
1378
0
  if (f == NULL)
1379
0
    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
0
  pathname = archive_entry_pathname(entry);
1391
0
  if (pathname == NULL) {
1392
0
    free(f);
1393
0
    archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
1394
0
    return (ARCHIVE_FAILED);
1395
0
  }
1396
0
  archive_mstring_copy_mbs(&(f->pathname), pathname);
1397
0
#endif
1398
0
  f->flag = flag;
1399
0
  f->mtime_sec = archive_entry_mtime(entry);
1400
0
  f->mtime_nsec = archive_entry_mtime_nsec(entry);
1401
0
  f->ctime_sec = archive_entry_ctime(entry);
1402
0
  f->ctime_nsec = archive_entry_ctime_nsec(entry);
1403
0
  r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node));
1404
0
  if (!r) {
1405
0
    struct match_file *f2;
1406
1407
    /* Get the duplicated file. */
1408
0
    f2 = (struct match_file *)__archive_rb_tree_find_node(
1409
0
      &(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
0
    if (f2 != NULL) {
1419
0
      f2->flag = f->flag;
1420
0
      f2->mtime_sec = f->mtime_sec;
1421
0
      f2->mtime_nsec = f->mtime_nsec;
1422
0
      f2->ctime_sec = f->ctime_sec;
1423
0
      f2->ctime_nsec = f->ctime_nsec;
1424
0
    }
1425
    /* Release the duplicated file. */
1426
0
    archive_mstring_clean(&(f->pathname));
1427
0
    free(f);
1428
0
    return (ARCHIVE_OK);
1429
0
  }
1430
0
  entry_list_add(&(a->exclusion_entry_list), f);
1431
0
  a->setflag |= TIME_IS_SET;
1432
0
  return (ARCHIVE_OK);
1433
0
}
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
0
{
1441
0
  struct match_file *f;
1442
0
  const void *pathname;
1443
0
  time_t sec;
1444
0
  long nsec;
1445
1446
  /*
1447
   * If this file/dir is excluded by a time comparison, skip it.
1448
   */
1449
0
  if (a->newer_ctime_filter) {
1450
    /* If ctime is not set, use mtime instead. */
1451
0
    if (archive_entry_ctime_is_set(entry))
1452
0
      sec = archive_entry_ctime(entry);
1453
0
    else
1454
0
      sec = archive_entry_mtime(entry);
1455
0
    if (sec < a->newer_ctime_sec)
1456
0
      return (1); /* Too old, skip it. */
1457
0
    if (sec == a->newer_ctime_sec) {
1458
0
      if (archive_entry_ctime_is_set(entry))
1459
0
        nsec = archive_entry_ctime_nsec(entry);
1460
0
      else
1461
0
        nsec = archive_entry_mtime_nsec(entry);
1462
0
      if (nsec < a->newer_ctime_nsec)
1463
0
        return (1); /* Too old, skip it. */
1464
0
      if (nsec == a->newer_ctime_nsec &&
1465
0
          (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL)
1466
0
            == 0)
1467
0
        return (1); /* Equal, skip it. */
1468
0
    }
1469
0
  }
1470
0
  if (a->older_ctime_filter) {
1471
    /* If ctime is not set, use mtime instead. */
1472
0
    if (archive_entry_ctime_is_set(entry))
1473
0
      sec = archive_entry_ctime(entry);
1474
0
    else
1475
0
      sec = archive_entry_mtime(entry);
1476
0
    if (sec > a->older_ctime_sec)
1477
0
      return (1); /* Too new, skip it. */
1478
0
    if (sec == a->older_ctime_sec) {
1479
0
      if (archive_entry_ctime_is_set(entry))
1480
0
        nsec = archive_entry_ctime_nsec(entry);
1481
0
      else
1482
0
        nsec = archive_entry_mtime_nsec(entry);
1483
0
      if (nsec > a->older_ctime_nsec)
1484
0
        return (1); /* Too new, skip it. */
1485
0
      if (nsec == a->older_ctime_nsec &&
1486
0
          (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
1487
0
            == 0)
1488
0
        return (1); /* Equal, skip it. */
1489
0
    }
1490
0
  }
1491
0
  if (a->newer_mtime_filter) {
1492
0
    sec = archive_entry_mtime(entry);
1493
0
    if (sec < a->newer_mtime_sec)
1494
0
      return (1); /* Too old, skip it. */
1495
0
    if (sec == a->newer_mtime_sec) {
1496
0
      nsec = archive_entry_mtime_nsec(entry);
1497
0
      if (nsec < a->newer_mtime_nsec)
1498
0
        return (1); /* Too old, skip it. */
1499
0
      if (nsec == a->newer_mtime_nsec &&
1500
0
          (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL)
1501
0
             == 0)
1502
0
        return (1); /* Equal, skip it. */
1503
0
    }
1504
0
  }
1505
0
  if (a->older_mtime_filter) {
1506
0
    sec = archive_entry_mtime(entry);
1507
0
    if (sec > a->older_mtime_sec)
1508
0
      return (1); /* Too new, skip it. */
1509
0
    nsec = archive_entry_mtime_nsec(entry);
1510
0
    if (sec == a->older_mtime_sec) {
1511
0
      if (nsec > a->older_mtime_nsec)
1512
0
        return (1); /* Too new, skip it. */
1513
0
      if (nsec == a->older_mtime_nsec &&
1514
0
          (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL)
1515
0
             == 0)
1516
0
        return (1); /* Equal, skip it. */
1517
0
    }
1518
0
  }
1519
1520
  /* If there is no exclusion list, include the file. */
1521
0
  if (a->exclusion_entry_list.first == NULL)
1522
0
    return (0);
1523
1524
#if defined(_WIN32) && !defined(__CYGWIN__)
1525
  pathname = archive_entry_pathname_w(entry);
1526
#else
1527
0
  pathname = archive_entry_pathname(entry);
1528
0
#endif
1529
0
  if (pathname == NULL)
1530
0
    return (0);
1531
1532
0
  f = (struct match_file *)__archive_rb_tree_find_node(
1533
0
    &(a->exclusion_tree), pathname);
1534
  /* If the file wasn't rejected, include it. */
1535
0
  if (f == NULL)
1536
0
    return (0);
1537
1538
0
  if (f->flag & ARCHIVE_MATCH_CTIME) {
1539
0
    sec = archive_entry_ctime(entry);
1540
0
    if (f->ctime_sec > sec) {
1541
0
      if (f->flag & ARCHIVE_MATCH_OLDER)
1542
0
        return (1);
1543
0
    } else if (f->ctime_sec < sec) {
1544
0
      if (f->flag & ARCHIVE_MATCH_NEWER)
1545
0
        return (1);
1546
0
    } else {
1547
0
      nsec = archive_entry_ctime_nsec(entry);
1548
0
      if (f->ctime_nsec > nsec) {
1549
0
        if (f->flag & ARCHIVE_MATCH_OLDER)
1550
0
          return (1);
1551
0
      } else if (f->ctime_nsec < nsec) {
1552
0
        if (f->flag & ARCHIVE_MATCH_NEWER)
1553
0
          return (1);
1554
0
      } else if (f->flag & ARCHIVE_MATCH_EQUAL)
1555
0
        return (1);
1556
0
    }
1557
0
  }
1558
0
  if (f->flag & ARCHIVE_MATCH_MTIME) {
1559
0
    sec = archive_entry_mtime(entry);
1560
0
    if (f->mtime_sec > sec) {
1561
0
      if (f->flag & ARCHIVE_MATCH_OLDER)
1562
0
        return (1);
1563
0
    } else if (f->mtime_sec < sec) {
1564
0
      if (f->flag & ARCHIVE_MATCH_NEWER)
1565
0
        return (1);
1566
0
    } else {
1567
0
      nsec = archive_entry_mtime_nsec(entry);
1568
0
      if (f->mtime_nsec > nsec) {
1569
0
        if (f->flag & ARCHIVE_MATCH_OLDER)
1570
0
          return (1);
1571
0
      } else if (f->mtime_nsec < nsec) {
1572
0
        if (f->flag & ARCHIVE_MATCH_NEWER)
1573
0
          return (1);
1574
0
      } else if (f->flag & ARCHIVE_MATCH_EQUAL)
1575
0
        return (1);
1576
0
    }
1577
0
  }
1578
0
  return (0);
1579
0
}
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
0
{
1588
0
  struct archive_match *a;
1589
1590
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1591
0
      ARCHIVE_STATE_NEW, "archive_match_include_uid");
1592
0
  a = (struct archive_match *)_a;
1593
0
  return (add_owner_id(a, &(a->inclusion_uids), uid));
1594
0
}
1595
1596
int
1597
archive_match_include_gid(struct archive *_a, la_int64_t gid)
1598
0
{
1599
0
  struct archive_match *a;
1600
1601
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1602
0
      ARCHIVE_STATE_NEW, "archive_match_include_gid");
1603
0
  a = (struct archive_match *)_a;
1604
0
  return (add_owner_id(a, &(a->inclusion_gids), gid));
1605
0
}
1606
1607
int
1608
archive_match_include_uname(struct archive *_a, const char *uname)
1609
0
{
1610
0
  struct archive_match *a;
1611
1612
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1613
0
      ARCHIVE_STATE_NEW, "archive_match_include_uname");
1614
0
  a = (struct archive_match *)_a;
1615
0
  return (add_owner_name(a, &(a->inclusion_unames), 1, uname));
1616
0
}
1617
1618
int
1619
archive_match_include_uname_w(struct archive *_a, const wchar_t *uname)
1620
0
{
1621
0
  struct archive_match *a;
1622
1623
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1624
0
      ARCHIVE_STATE_NEW, "archive_match_include_uname_w");
1625
0
  a = (struct archive_match *)_a;
1626
0
  return (add_owner_name(a, &(a->inclusion_unames), 0, uname));
1627
0
}
1628
1629
int
1630
archive_match_include_gname(struct archive *_a, const char *gname)
1631
0
{
1632
0
  struct archive_match *a;
1633
1634
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1635
0
      ARCHIVE_STATE_NEW, "archive_match_include_gname");
1636
0
  a = (struct archive_match *)_a;
1637
0
  return (add_owner_name(a, &(a->inclusion_gnames), 1, gname));
1638
0
}
1639
1640
int
1641
archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
1642
0
{
1643
0
  struct archive_match *a;
1644
1645
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1646
0
      ARCHIVE_STATE_NEW, "archive_match_include_gname_w");
1647
0
  a = (struct archive_match *)_a;
1648
0
  return (add_owner_name(a, &(a->inclusion_gnames), 0, gname));
1649
0
}
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
0
{
1662
0
  struct archive_match *a;
1663
1664
0
  archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
1665
0
      ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae");
1666
1667
0
  a = (struct archive_match *)_a;
1668
0
  if (entry == NULL) {
1669
0
    archive_set_error(&(a->archive), EINVAL, "entry is NULL");
1670
0
    return (ARCHIVE_FAILED);
1671
0
  }
1672
1673
  /* If we don't have inclusion id set at all, the entry is always
1674
   * not excluded. */
1675
0
  if ((a->setflag & ID_IS_SET) == 0)
1676
0
    return (0);
1677
0
  return (owner_excluded(a, entry));
1678
0
}
1679
1680
static int
1681
add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
1682
0
{
1683
0
  size_t i;
1684
1685
0
  if (ids->count + 1 >= ids->size) {
1686
0
    void *p;
1687
1688
0
    if (ids->size == 0)
1689
0
      ids->size = 8;
1690
0
    else
1691
0
      ids->size *= 2;
1692
0
    p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
1693
0
    if (p == NULL)
1694
0
      return (error_nomem(a));
1695
0
    ids->ids = (int64_t *)p;
1696
0
  }
1697
1698
  /* Find an insert point. */
1699
0
  for (i = 0; i < ids->count; i++) {
1700
0
    if (ids->ids[i] >= id)
1701
0
      break;
1702
0
  }
1703
1704
  /* Add owner id. */
1705
0
  if (i == ids->count)
1706
0
    ids->ids[ids->count++] = id;
1707
0
  else if (ids->ids[i] != id) {
1708
0
    memmove(&(ids->ids[i+1]), &(ids->ids[i]),
1709
0
        (ids->count - i) * sizeof(ids->ids[0]));
1710
0
    ids->ids[i] = id;
1711
0
    ids->count++;
1712
0
  }
1713
0
  a->setflag |= ID_IS_SET;
1714
0
  return (ARCHIVE_OK);
1715
0
}
1716
1717
static int
1718
match_owner_id(struct id_array *ids, int64_t id)
1719
0
{
1720
0
  size_t b, m, t;
1721
1722
0
  t = 0;
1723
0
  b = ids->count;
1724
0
  while (t < b) {
1725
0
    m = (t + b)>>1;
1726
0
    if (ids->ids[m] == id)
1727
0
      return (1);
1728
0
    if (ids->ids[m] < id)
1729
0
      t = m + 1;
1730
0
    else
1731
0
      b = m;
1732
0
  }
1733
0
  return (0);
1734
0
}
1735
1736
static int
1737
add_owner_name(struct archive_match *a, struct match_list *list,
1738
    int mbs, const void *name)
1739
0
{
1740
0
  struct match *match;
1741
1742
0
  match = calloc(1, sizeof(*match));
1743
0
  if (match == NULL)
1744
0
    return (error_nomem(a));
1745
0
  if (mbs)
1746
0
    archive_mstring_copy_mbs(&(match->pattern), name);
1747
0
  else
1748
0
    archive_mstring_copy_wcs(&(match->pattern), name);
1749
0
  match_list_add(list, match);
1750
0
  a->setflag |= ID_IS_SET;
1751
0
  return (ARCHIVE_OK);
1752
0
}
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
0
{
1759
0
  struct match *m;
1760
0
  const char *p;
1761
1762
0
  if (name == NULL || *name == '\0')
1763
0
    return (0);
1764
0
  for (m = list->first; m; m = m->next) {
1765
0
    if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p)
1766
0
        < 0 && errno == ENOMEM)
1767
0
      return (error_nomem(a));
1768
0
    if (p != NULL && strcmp(p, name) == 0) {
1769
0
      m->matched = 1;
1770
0
      return (1);
1771
0
    }
1772
0
  }
1773
0
  return (0);
1774
0
}
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
0
{
1804
0
  int r;
1805
1806
0
  if (a->inclusion_uids.count) {
1807
0
    if (!match_owner_id(&(a->inclusion_uids),
1808
0
        archive_entry_uid(entry)))
1809
0
      return (1);
1810
0
  }
1811
1812
0
  if (a->inclusion_gids.count) {
1813
0
    if (!match_owner_id(&(a->inclusion_gids),
1814
0
        archive_entry_gid(entry)))
1815
0
      return (1);
1816
0
  }
1817
1818
0
  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
0
    r = match_owner_name_mbs(a, &(a->inclusion_unames),
1824
0
      archive_entry_uname(entry));
1825
0
#endif
1826
0
    if (!r)
1827
0
      return (1);
1828
0
    else if (r < 0)
1829
0
      return (r);
1830
0
  }
1831
1832
0
  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
0
    r = match_owner_name_mbs(a, &(a->inclusion_gnames),
1838
0
      archive_entry_gname(entry));
1839
0
#endif
1840
0
    if (!r)
1841
0
      return (1);
1842
0
    else if (r < 0)
1843
0
      return (r);
1844
0
  }
1845
0
  return (0);
1846
0
}