1238825Smm/*- 2238825Smm * Copyright (c) 2003-2007 Tim Kientzle 3238825Smm * Copyright (c) 2012 Michihiro NAKAJIMA 4238825Smm * All rights reserved. 5238825Smm * 6238825Smm * Redistribution and use in source and binary forms, with or without 7238825Smm * modification, are permitted provided that the following conditions 8238825Smm * are met: 9238825Smm * 1. Redistributions of source code must retain the above copyright 10238825Smm * notice, this list of conditions and the following disclaimer. 11238825Smm * 2. Redistributions in binary form must reproduce the above copyright 12238825Smm * notice, this list of conditions and the following disclaimer in the 13238825Smm * documentation and/or other materials provided with the distribution. 14238825Smm * 15238825Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16238825Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17238825Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18238825Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19238825Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20238825Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21238825Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22238825Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23238825Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24238825Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25238825Smm */ 26238825Smm 27238825Smm#include "archive_platform.h" 28238825Smm__FBSDID("$FreeBSD$"); 29238825Smm 30238825Smm#ifdef HAVE_ERRNO_H 31238825Smm#include <errno.h> 32238825Smm#endif 33238825Smm#ifdef HAVE_STDLIB_H 34238825Smm#include <stdlib.h> 35238825Smm#endif 36238825Smm#ifdef HAVE_STRING_H 37238825Smm#include <string.h> 38238825Smm#endif 39238825Smm 40238825Smm#include "archive.h" 41238825Smm#include "archive_private.h" 42238825Smm#include "archive_entry.h" 43299529Smm#include "archive_getdate.h" 44238825Smm#include "archive_pathmatch.h" 45238825Smm#include "archive_rb.h" 46238825Smm#include "archive_string.h" 47238825Smm 48238825Smmstruct match { 49238825Smm struct match *next; 50238825Smm int matches; 51238825Smm struct archive_mstring pattern; 52238825Smm}; 53238825Smm 54238825Smmstruct match_list { 55238825Smm struct match *first; 56238825Smm struct match **last; 57238825Smm int count; 58238825Smm int unmatched_count; 59238825Smm struct match *unmatched_next; 60238825Smm int unmatched_eof; 61238825Smm}; 62238825Smm 63238825Smmstruct match_file { 64238825Smm struct archive_rb_node node; 65238825Smm struct match_file *next; 66238825Smm struct archive_mstring pathname; 67238825Smm int flag; 68238825Smm time_t mtime_sec; 69238825Smm long mtime_nsec; 70238825Smm time_t ctime_sec; 71238825Smm long ctime_nsec; 72238825Smm}; 73238825Smm 74238825Smmstruct entry_list { 75238825Smm struct match_file *first; 76238825Smm struct match_file **last; 77238825Smm int count; 78238825Smm}; 79238825Smm 80238825Smmstruct id_array { 81238825Smm size_t size;/* Allocated size */ 82238825Smm size_t count; 83238825Smm int64_t *ids; 84238825Smm}; 85238825Smm 86238825Smm#define PATTERN_IS_SET 1 87238825Smm#define TIME_IS_SET 2 88238825Smm#define ID_IS_SET 4 89238825Smm 90238825Smmstruct archive_match { 91238825Smm struct archive archive; 92238825Smm 93238825Smm /* exclusion/inclusion set flag. */ 94238825Smm int setflag; 95238825Smm 96348607Smm /* Recursively include directory content? */ 97348607Smm int recursive_include; 98348607Smm 99238825Smm /* 100238825Smm * Matching filename patterns. 101238825Smm */ 102238825Smm struct match_list exclusions; 103238825Smm struct match_list inclusions; 104238825Smm 105238825Smm /* 106238825Smm * Matching time stamps. 107238825Smm */ 108238825Smm time_t now; 109238825Smm int newer_mtime_filter; 110238825Smm time_t newer_mtime_sec; 111238825Smm long newer_mtime_nsec; 112238825Smm int newer_ctime_filter; 113238825Smm time_t newer_ctime_sec; 114238825Smm long newer_ctime_nsec; 115238825Smm int older_mtime_filter; 116238825Smm time_t older_mtime_sec; 117238825Smm long older_mtime_nsec; 118238825Smm int older_ctime_filter; 119238825Smm time_t older_ctime_sec; 120238825Smm long older_ctime_nsec; 121238825Smm /* 122238825Smm * Matching time stamps with its filename. 123238825Smm */ 124238825Smm struct archive_rb_tree exclusion_tree; 125238825Smm struct entry_list exclusion_entry_list; 126238825Smm 127238825Smm /* 128238825Smm * Matching file owners. 129238825Smm */ 130238825Smm struct id_array inclusion_uids; 131238825Smm struct id_array inclusion_gids; 132238825Smm struct match_list inclusion_unames; 133238825Smm struct match_list inclusion_gnames; 134238825Smm}; 135238825Smm 136238825Smmstatic int add_pattern_from_file(struct archive_match *, 137238825Smm struct match_list *, int, const void *, int); 138238825Smmstatic int add_entry(struct archive_match *, int, 139238825Smm struct archive_entry *); 140238825Smmstatic int add_owner_id(struct archive_match *, struct id_array *, 141238825Smm int64_t); 142238825Smmstatic int add_owner_name(struct archive_match *, struct match_list *, 143238825Smm int, const void *); 144238825Smmstatic int add_pattern_mbs(struct archive_match *, struct match_list *, 145238825Smm const char *); 146238825Smmstatic int add_pattern_wcs(struct archive_match *, struct match_list *, 147238825Smm const wchar_t *); 148238825Smmstatic int cmp_key_mbs(const struct archive_rb_node *, const void *); 149238825Smmstatic int cmp_key_wcs(const struct archive_rb_node *, const void *); 150238825Smmstatic int cmp_node_mbs(const struct archive_rb_node *, 151238825Smm const struct archive_rb_node *); 152238825Smmstatic int cmp_node_wcs(const struct archive_rb_node *, 153238825Smm const struct archive_rb_node *); 154238825Smmstatic void entry_list_add(struct entry_list *, struct match_file *); 155238825Smmstatic void entry_list_free(struct entry_list *); 156238825Smmstatic void entry_list_init(struct entry_list *); 157238825Smmstatic int error_nomem(struct archive_match *); 158238825Smmstatic void match_list_add(struct match_list *, struct match *); 159238825Smmstatic void match_list_free(struct match_list *); 160238825Smmstatic void match_list_init(struct match_list *); 161238825Smmstatic int match_list_unmatched_inclusions_next(struct archive_match *, 162238825Smm struct match_list *, int, const void **); 163238825Smmstatic int match_owner_id(struct id_array *, int64_t); 164238825Smm#if !defined(_WIN32) || defined(__CYGWIN__) 165238825Smmstatic int match_owner_name_mbs(struct archive_match *, 166238825Smm struct match_list *, const char *); 167238825Smm#else 168238825Smmstatic int match_owner_name_wcs(struct archive_match *, 169238825Smm struct match_list *, const wchar_t *); 170238825Smm#endif 171238825Smmstatic int match_path_exclusion(struct archive_match *, 172238825Smm struct match *, int, const void *); 173238825Smmstatic int match_path_inclusion(struct archive_match *, 174238825Smm struct match *, int, const void *); 175238825Smmstatic int owner_excluded(struct archive_match *, 176238825Smm struct archive_entry *); 177238825Smmstatic int path_excluded(struct archive_match *, int, const void *); 178238825Smmstatic int set_timefilter(struct archive_match *, int, time_t, long, 179238825Smm time_t, long); 180238825Smmstatic int set_timefilter_pathname_mbs(struct archive_match *, 181238825Smm int, const char *); 182238825Smmstatic int set_timefilter_pathname_wcs(struct archive_match *, 183238825Smm int, const wchar_t *); 184238825Smmstatic int set_timefilter_date(struct archive_match *, int, const char *); 185238825Smmstatic int set_timefilter_date_w(struct archive_match *, int, 186238825Smm const wchar_t *); 187238825Smmstatic int time_excluded(struct archive_match *, 188238825Smm struct archive_entry *); 189238825Smmstatic int validate_time_flag(struct archive *, int, const char *); 190238825Smm 191238825Smm#define get_date __archive_get_date 192238825Smm 193238825Smmstatic const struct archive_rb_tree_ops rb_ops_mbs = { 194238825Smm cmp_node_mbs, cmp_key_mbs 195238825Smm}; 196238825Smm 197238825Smmstatic const struct archive_rb_tree_ops rb_ops_wcs = { 198238825Smm cmp_node_wcs, cmp_key_wcs 199238825Smm}; 200238825Smm 201238825Smm/* 202238825Smm * The matching logic here needs to be re-thought. I started out to 203238825Smm * try to mimic gtar's matching logic, but it's not entirely 204238825Smm * consistent. In particular 'tar -t' and 'tar -x' interpret patterns 205238825Smm * on the command line as anchored, but --exclude doesn't. 206238825Smm */ 207238825Smm 208238825Smmstatic int 209238825Smmerror_nomem(struct archive_match *a) 210238825Smm{ 211238825Smm archive_set_error(&(a->archive), ENOMEM, "No memory"); 212238825Smm a->archive.state = ARCHIVE_STATE_FATAL; 213238825Smm return (ARCHIVE_FATAL); 214238825Smm} 215238825Smm 216238825Smm/* 217238825Smm * Create an ARCHIVE_MATCH object. 218238825Smm */ 219238825Smmstruct archive * 220238825Smmarchive_match_new(void) 221238825Smm{ 222238825Smm struct archive_match *a; 223238825Smm 224238825Smm a = (struct archive_match *)calloc(1, sizeof(*a)); 225238825Smm if (a == NULL) 226238825Smm return (NULL); 227238825Smm a->archive.magic = ARCHIVE_MATCH_MAGIC; 228238825Smm a->archive.state = ARCHIVE_STATE_NEW; 229348607Smm a->recursive_include = 1; 230238825Smm match_list_init(&(a->inclusions)); 231238825Smm match_list_init(&(a->exclusions)); 232238825Smm __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); 233238825Smm entry_list_init(&(a->exclusion_entry_list)); 234238825Smm match_list_init(&(a->inclusion_unames)); 235238825Smm match_list_init(&(a->inclusion_gnames)); 236238825Smm time(&a->now); 237238825Smm return (&(a->archive)); 238238825Smm} 239238825Smm 240238825Smm/* 241238825Smm * Free an ARCHIVE_MATCH object. 242238825Smm */ 243238825Smmint 244238825Smmarchive_match_free(struct archive *_a) 245238825Smm{ 246238825Smm struct archive_match *a; 247238825Smm 248238825Smm if (_a == NULL) 249238825Smm return (ARCHIVE_OK); 250238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 251238825Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free"); 252238825Smm a = (struct archive_match *)_a; 253238825Smm match_list_free(&(a->inclusions)); 254238825Smm match_list_free(&(a->exclusions)); 255238825Smm entry_list_free(&(a->exclusion_entry_list)); 256238825Smm free(a->inclusion_uids.ids); 257238825Smm free(a->inclusion_gids.ids); 258238825Smm match_list_free(&(a->inclusion_unames)); 259238825Smm match_list_free(&(a->inclusion_gnames)); 260238825Smm free(a); 261238825Smm return (ARCHIVE_OK); 262238825Smm} 263238825Smm 264238825Smm/* 265238825Smm * Convenience function to perform all exclusion tests. 266238825Smm * 267238825Smm * Returns 1 if archive entry is excluded. 268238825Smm * Returns 0 if archive entry is not excluded. 269238825Smm * Returns <0 if something error happened. 270238825Smm */ 271238825Smmint 272238825Smmarchive_match_excluded(struct archive *_a, struct archive_entry *entry) 273238825Smm{ 274238825Smm struct archive_match *a; 275238825Smm int r; 276238825Smm 277238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 278238825Smm ARCHIVE_STATE_NEW, "archive_match_excluded_ae"); 279238825Smm 280238825Smm a = (struct archive_match *)_a; 281238825Smm if (entry == NULL) { 282238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 283238825Smm return (ARCHIVE_FAILED); 284238825Smm } 285238825Smm 286238825Smm r = 0; 287238825Smm if (a->setflag & PATTERN_IS_SET) { 288238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 289238825Smm r = path_excluded(a, 0, archive_entry_pathname_w(entry)); 290238825Smm#else 291238825Smm r = path_excluded(a, 1, archive_entry_pathname(entry)); 292238825Smm#endif 293238825Smm if (r != 0) 294238825Smm return (r); 295238825Smm } 296238825Smm 297238825Smm if (a->setflag & TIME_IS_SET) { 298238825Smm r = time_excluded(a, entry); 299238825Smm if (r != 0) 300238825Smm return (r); 301238825Smm } 302238825Smm 303238825Smm if (a->setflag & ID_IS_SET) 304238825Smm r = owner_excluded(a, entry); 305238825Smm return (r); 306238825Smm} 307238825Smm 308238825Smm/* 309238825Smm * Utility functions to manage exclusion/inclusion patterns 310238825Smm */ 311238825Smm 312238825Smmint 313238825Smmarchive_match_exclude_pattern(struct archive *_a, const char *pattern) 314238825Smm{ 315238825Smm struct archive_match *a; 316238825Smm int r; 317238825Smm 318238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 319238825Smm ARCHIVE_STATE_NEW, "archive_match_exclude_pattern"); 320238825Smm a = (struct archive_match *)_a; 321238825Smm 322238825Smm if (pattern == NULL || *pattern == '\0') { 323238825Smm archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 324238825Smm return (ARCHIVE_FAILED); 325238825Smm } 326238825Smm if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) 327238825Smm return (r); 328238825Smm return (ARCHIVE_OK); 329238825Smm} 330238825Smm 331238825Smmint 332238825Smmarchive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern) 333238825Smm{ 334238825Smm struct archive_match *a; 335238825Smm int r; 336238825Smm 337238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 338238825Smm ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w"); 339238825Smm a = (struct archive_match *)_a; 340238825Smm 341238825Smm if (pattern == NULL || *pattern == L'\0') { 342238825Smm archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 343238825Smm return (ARCHIVE_FAILED); 344238825Smm } 345238825Smm if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) 346238825Smm return (r); 347238825Smm return (ARCHIVE_OK); 348238825Smm} 349238825Smm 350238825Smmint 351238825Smmarchive_match_exclude_pattern_from_file(struct archive *_a, 352238825Smm const char *pathname, int nullSeparator) 353238825Smm{ 354238825Smm struct archive_match *a; 355238825Smm 356238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 357238825Smm ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file"); 358238825Smm a = (struct archive_match *)_a; 359238825Smm 360238825Smm return add_pattern_from_file(a, &(a->exclusions), 1, pathname, 361238825Smm nullSeparator); 362238825Smm} 363238825Smm 364238825Smmint 365238825Smmarchive_match_exclude_pattern_from_file_w(struct archive *_a, 366238825Smm const wchar_t *pathname, int nullSeparator) 367238825Smm{ 368238825Smm struct archive_match *a; 369238825Smm 370238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 371238825Smm ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w"); 372238825Smm a = (struct archive_match *)_a; 373238825Smm 374238825Smm return add_pattern_from_file(a, &(a->exclusions), 0, pathname, 375238825Smm nullSeparator); 376238825Smm} 377238825Smm 378238825Smmint 379238825Smmarchive_match_include_pattern(struct archive *_a, const char *pattern) 380238825Smm{ 381238825Smm struct archive_match *a; 382238825Smm int r; 383238825Smm 384238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 385238825Smm ARCHIVE_STATE_NEW, "archive_match_include_pattern"); 386238825Smm a = (struct archive_match *)_a; 387238825Smm 388238825Smm if (pattern == NULL || *pattern == '\0') { 389238825Smm archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 390238825Smm return (ARCHIVE_FAILED); 391238825Smm } 392238825Smm if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) 393238825Smm return (r); 394238825Smm return (ARCHIVE_OK); 395238825Smm} 396238825Smm 397238825Smmint 398238825Smmarchive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern) 399238825Smm{ 400238825Smm struct archive_match *a; 401238825Smm int r; 402238825Smm 403238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 404238825Smm ARCHIVE_STATE_NEW, "archive_match_include_pattern_w"); 405238825Smm a = (struct archive_match *)_a; 406238825Smm 407238825Smm if (pattern == NULL || *pattern == L'\0') { 408238825Smm archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 409238825Smm return (ARCHIVE_FAILED); 410238825Smm } 411238825Smm if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) 412238825Smm return (r); 413238825Smm return (ARCHIVE_OK); 414238825Smm} 415238825Smm 416238825Smmint 417238825Smmarchive_match_include_pattern_from_file(struct archive *_a, 418238825Smm const char *pathname, int nullSeparator) 419238825Smm{ 420238825Smm struct archive_match *a; 421238825Smm 422238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 423238825Smm ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file"); 424238825Smm a = (struct archive_match *)_a; 425238825Smm 426238825Smm return add_pattern_from_file(a, &(a->inclusions), 1, pathname, 427238825Smm nullSeparator); 428238825Smm} 429238825Smm 430238825Smmint 431238825Smmarchive_match_include_pattern_from_file_w(struct archive *_a, 432238825Smm const wchar_t *pathname, int nullSeparator) 433238825Smm{ 434238825Smm struct archive_match *a; 435238825Smm 436238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 437238825Smm ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w"); 438238825Smm a = (struct archive_match *)_a; 439238825Smm 440238825Smm return add_pattern_from_file(a, &(a->inclusions), 0, pathname, 441238825Smm nullSeparator); 442238825Smm} 443238825Smm 444238825Smm/* 445238825Smm * Test functions for pathname patterns. 446238825Smm * 447238825Smm * Returns 1 if archive entry is excluded. 448238825Smm * Returns 0 if archive entry is not excluded. 449238825Smm * Returns <0 if something error happened. 450238825Smm */ 451238825Smmint 452238825Smmarchive_match_path_excluded(struct archive *_a, 453238825Smm struct archive_entry *entry) 454238825Smm{ 455238825Smm struct archive_match *a; 456238825Smm 457238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 458238825Smm ARCHIVE_STATE_NEW, "archive_match_path_excluded"); 459238825Smm 460238825Smm a = (struct archive_match *)_a; 461238825Smm if (entry == NULL) { 462238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 463238825Smm return (ARCHIVE_FAILED); 464238825Smm } 465238825Smm 466238825Smm /* If we don't have exclusion/inclusion pattern set at all, 467238825Smm * the entry is always not excluded. */ 468238825Smm if ((a->setflag & PATTERN_IS_SET) == 0) 469238825Smm return (0); 470238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 471238825Smm return (path_excluded(a, 0, archive_entry_pathname_w(entry))); 472238825Smm#else 473238825Smm return (path_excluded(a, 1, archive_entry_pathname(entry))); 474238825Smm#endif 475238825Smm} 476238825Smm 477238825Smm/* 478348607Smm * When recursive inclusion of directory content is enabled, 479348607Smm * an inclusion pattern that matches a directory will also 480348607Smm * include everything beneath that directory. Enabled by default. 481348607Smm * 482348607Smm * For compatibility with GNU tar, exclusion patterns always 483348607Smm * match if a subset of the full patch matches (i.e., they are 484348607Smm * are not rooted at the beginning of the path) and thus there 485348607Smm * is no corresponding non-recursive exclusion mode. 486348607Smm */ 487348607Smmint 488348607Smmarchive_match_set_inclusion_recursion(struct archive *_a, int enabled) 489348607Smm{ 490348607Smm struct archive_match *a; 491348607Smm 492348607Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 493348607Smm ARCHIVE_STATE_NEW, "archive_match_set_inclusion_recursion"); 494348607Smm a = (struct archive_match *)_a; 495348607Smm a->recursive_include = enabled; 496348607Smm return (ARCHIVE_OK); 497348607Smm} 498348607Smm 499348607Smm/* 500313570Smm * Utility functions to get statistic information for inclusion patterns. 501238825Smm */ 502238825Smmint 503238825Smmarchive_match_path_unmatched_inclusions(struct archive *_a) 504238825Smm{ 505238825Smm struct archive_match *a; 506238825Smm 507238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 508238825Smm ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions"); 509238825Smm a = (struct archive_match *)_a; 510238825Smm 511238825Smm return (a->inclusions.unmatched_count); 512238825Smm} 513238825Smm 514238825Smmint 515238825Smmarchive_match_path_unmatched_inclusions_next(struct archive *_a, 516238825Smm const char **_p) 517238825Smm{ 518238825Smm struct archive_match *a; 519238825Smm const void *v; 520238825Smm int r; 521238825Smm 522238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 523238825Smm ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next"); 524238825Smm a = (struct archive_match *)_a; 525238825Smm 526238825Smm r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v); 527238825Smm *_p = (const char *)v; 528238825Smm return (r); 529238825Smm} 530238825Smm 531238825Smmint 532238825Smmarchive_match_path_unmatched_inclusions_next_w(struct archive *_a, 533238825Smm const wchar_t **_p) 534238825Smm{ 535238825Smm struct archive_match *a; 536238825Smm const void *v; 537238825Smm int r; 538238825Smm 539238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 540238825Smm ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w"); 541238825Smm a = (struct archive_match *)_a; 542238825Smm 543238825Smm r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v); 544238825Smm *_p = (const wchar_t *)v; 545238825Smm return (r); 546238825Smm} 547238825Smm 548238825Smm/* 549238825Smm * Add inclusion/exclusion patterns. 550238825Smm */ 551238825Smmstatic int 552238825Smmadd_pattern_mbs(struct archive_match *a, struct match_list *list, 553238825Smm const char *pattern) 554238825Smm{ 555238825Smm struct match *match; 556238825Smm size_t len; 557238825Smm 558238825Smm match = calloc(1, sizeof(*match)); 559238825Smm if (match == NULL) 560238825Smm return (error_nomem(a)); 561238825Smm /* Both "foo/" and "foo" should match "foo/bar". */ 562238825Smm len = strlen(pattern); 563238825Smm if (len && pattern[len - 1] == '/') 564238825Smm --len; 565238825Smm archive_mstring_copy_mbs_len(&(match->pattern), pattern, len); 566238825Smm match_list_add(list, match); 567238825Smm a->setflag |= PATTERN_IS_SET; 568238825Smm return (ARCHIVE_OK); 569238825Smm} 570238825Smm 571238825Smmstatic int 572238825Smmadd_pattern_wcs(struct archive_match *a, struct match_list *list, 573238825Smm const wchar_t *pattern) 574238825Smm{ 575238825Smm struct match *match; 576238825Smm size_t len; 577238825Smm 578238825Smm match = calloc(1, sizeof(*match)); 579238825Smm if (match == NULL) 580238825Smm return (error_nomem(a)); 581238825Smm /* Both "foo/" and "foo" should match "foo/bar". */ 582238825Smm len = wcslen(pattern); 583238825Smm if (len && pattern[len - 1] == L'/') 584238825Smm --len; 585238825Smm archive_mstring_copy_wcs_len(&(match->pattern), pattern, len); 586238825Smm match_list_add(list, match); 587238825Smm a->setflag |= PATTERN_IS_SET; 588238825Smm return (ARCHIVE_OK); 589238825Smm} 590238825Smm 591238825Smmstatic int 592238825Smmadd_pattern_from_file(struct archive_match *a, struct match_list *mlist, 593238825Smm int mbs, const void *pathname, int nullSeparator) 594238825Smm{ 595238825Smm struct archive *ar; 596238825Smm struct archive_entry *ae; 597238825Smm struct archive_string as; 598238825Smm const void *buff; 599238825Smm size_t size; 600238825Smm int64_t offset; 601238825Smm int r; 602238825Smm 603238825Smm ar = archive_read_new(); 604238825Smm if (ar == NULL) { 605238825Smm archive_set_error(&(a->archive), ENOMEM, "No memory"); 606238825Smm return (ARCHIVE_FATAL); 607238825Smm } 608238825Smm r = archive_read_support_format_raw(ar); 609299529Smm r = archive_read_support_format_empty(ar); 610238825Smm if (r != ARCHIVE_OK) { 611238825Smm archive_copy_error(&(a->archive), ar); 612238825Smm archive_read_free(ar); 613238825Smm return (r); 614238825Smm } 615238825Smm if (mbs) 616238825Smm r = archive_read_open_filename(ar, pathname, 512*20); 617238825Smm else 618238825Smm r = archive_read_open_filename_w(ar, pathname, 512*20); 619238825Smm if (r != ARCHIVE_OK) { 620238825Smm archive_copy_error(&(a->archive), ar); 621238825Smm archive_read_free(ar); 622238825Smm return (r); 623238825Smm } 624238825Smm r = archive_read_next_header(ar, &ae); 625238825Smm if (r != ARCHIVE_OK) { 626238825Smm archive_read_free(ar); 627299529Smm if (r == ARCHIVE_EOF) { 628299529Smm return (ARCHIVE_OK); 629299529Smm } else { 630299529Smm archive_copy_error(&(a->archive), ar); 631299529Smm return (r); 632299529Smm } 633238825Smm } 634238825Smm 635238825Smm archive_string_init(&as); 636238825Smm 637238825Smm while ((r = archive_read_data_block(ar, &buff, &size, &offset)) 638238825Smm == ARCHIVE_OK) { 639238825Smm const char *b = (const char *)buff; 640238825Smm 641238825Smm while (size) { 642238825Smm const char *s = (const char *)b; 643238825Smm size_t length = 0; 644238825Smm int found_separator = 0; 645238825Smm 646238825Smm while (length < size) { 647238825Smm if (nullSeparator) { 648238825Smm if (*b == '\0') { 649238825Smm found_separator = 1; 650238825Smm break; 651238825Smm } 652238825Smm } else { 653238825Smm if (*b == 0x0d || *b == 0x0a) { 654238825Smm found_separator = 1; 655238825Smm break; 656238825Smm } 657238825Smm } 658238825Smm b++; 659238825Smm length++; 660238825Smm } 661238825Smm if (!found_separator) { 662238825Smm archive_strncat(&as, s, length); 663238825Smm /* Read next data block. */ 664238825Smm break; 665238825Smm } 666238825Smm b++; 667238825Smm size -= length + 1; 668238825Smm archive_strncat(&as, s, length); 669238825Smm 670238825Smm /* If the line is not empty, add the pattern. */ 671238825Smm if (archive_strlen(&as) > 0) { 672238825Smm /* Add pattern. */ 673238825Smm r = add_pattern_mbs(a, mlist, as.s); 674238825Smm if (r != ARCHIVE_OK) { 675238825Smm archive_read_free(ar); 676238825Smm archive_string_free(&as); 677238825Smm return (r); 678238825Smm } 679238825Smm archive_string_empty(&as); 680238825Smm } 681238825Smm } 682238825Smm } 683238825Smm 684305188Smm /* If an error occurred, report it immediately. */ 685238825Smm if (r < ARCHIVE_OK) { 686238825Smm archive_copy_error(&(a->archive), ar); 687238825Smm archive_read_free(ar); 688238825Smm archive_string_free(&as); 689238825Smm return (r); 690238825Smm } 691238825Smm 692238825Smm /* If the line is not empty, add the pattern. */ 693238825Smm if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { 694238825Smm /* Add pattern. */ 695238825Smm r = add_pattern_mbs(a, mlist, as.s); 696238825Smm if (r != ARCHIVE_OK) { 697238825Smm archive_read_free(ar); 698238825Smm archive_string_free(&as); 699238825Smm return (r); 700238825Smm } 701238825Smm } 702238825Smm archive_read_free(ar); 703238825Smm archive_string_free(&as); 704238825Smm return (ARCHIVE_OK); 705238825Smm} 706238825Smm 707238825Smm/* 708238825Smm * Test if pathname is excluded by inclusion/exclusion patterns. 709238825Smm */ 710238825Smmstatic int 711238825Smmpath_excluded(struct archive_match *a, int mbs, const void *pathname) 712238825Smm{ 713238825Smm struct match *match; 714238825Smm struct match *matched; 715238825Smm int r; 716238825Smm 717238825Smm if (a == NULL) 718238825Smm return (0); 719238825Smm 720238825Smm /* Mark off any unmatched inclusions. */ 721238825Smm /* In particular, if a filename does appear in the archive and 722238825Smm * is explicitly included and excluded, then we don't report 723238825Smm * it as missing even though we don't extract it. 724238825Smm */ 725238825Smm matched = NULL; 726238825Smm for (match = a->inclusions.first; match != NULL; 727238825Smm match = match->next){ 728238825Smm if (match->matches == 0 && 729238825Smm (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 730238825Smm if (r < 0) 731238825Smm return (r); 732238825Smm a->inclusions.unmatched_count--; 733238825Smm match->matches++; 734238825Smm matched = match; 735238825Smm } 736238825Smm } 737238825Smm 738238825Smm /* Exclusions take priority */ 739238825Smm for (match = a->exclusions.first; match != NULL; 740238825Smm match = match->next){ 741238825Smm r = match_path_exclusion(a, match, mbs, pathname); 742238825Smm if (r) 743238825Smm return (r); 744238825Smm } 745238825Smm 746238825Smm /* It's not excluded and we found an inclusion above, so it's 747238825Smm * included. */ 748238825Smm if (matched != NULL) 749238825Smm return (0); 750238825Smm 751238825Smm 752238825Smm /* We didn't find an unmatched inclusion, check the remaining ones. */ 753238825Smm for (match = a->inclusions.first; match != NULL; 754238825Smm match = match->next){ 755238825Smm /* We looked at previously-unmatched inclusions already. */ 756238825Smm if (match->matches > 0 && 757238825Smm (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 758238825Smm if (r < 0) 759238825Smm return (r); 760238825Smm match->matches++; 761238825Smm return (0); 762238825Smm } 763238825Smm } 764238825Smm 765238825Smm /* If there were inclusions, default is to exclude. */ 766238825Smm if (a->inclusions.first != NULL) 767238825Smm return (1); 768238825Smm 769238825Smm /* No explicit inclusions, default is to match. */ 770238825Smm return (0); 771238825Smm} 772238825Smm 773238825Smm/* 774238825Smm * This is a little odd, but it matches the default behavior of 775238825Smm * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' 776238825Smm * 777238825Smm */ 778238825Smmstatic int 779238825Smmmatch_path_exclusion(struct archive_match *a, struct match *m, 780238825Smm int mbs, const void *pn) 781238825Smm{ 782238825Smm int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END; 783238825Smm int r; 784238825Smm 785238825Smm if (mbs) { 786238825Smm const char *p; 787238825Smm r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 788238825Smm if (r == 0) 789238825Smm return (archive_pathmatch(p, (const char *)pn, flag)); 790238825Smm } else { 791238825Smm const wchar_t *p; 792238825Smm r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 793238825Smm if (r == 0) 794238825Smm return (archive_pathmatch_w(p, (const wchar_t *)pn, 795238825Smm flag)); 796238825Smm } 797238825Smm if (errno == ENOMEM) 798238825Smm return (error_nomem(a)); 799238825Smm return (0); 800238825Smm} 801238825Smm 802238825Smm/* 803238825Smm * Again, mimic gtar: inclusions are always anchored (have to match 804238825Smm * the beginning of the path) even though exclusions are not anchored. 805238825Smm */ 806238825Smmstatic int 807238825Smmmatch_path_inclusion(struct archive_match *a, struct match *m, 808238825Smm int mbs, const void *pn) 809238825Smm{ 810348607Smm /* Recursive operation requires only a prefix match. */ 811348607Smm int flag = a->recursive_include ? 812348607Smm PATHMATCH_NO_ANCHOR_END : 813348607Smm 0; 814238825Smm int r; 815238825Smm 816238825Smm if (mbs) { 817238825Smm const char *p; 818238825Smm r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 819238825Smm if (r == 0) 820238825Smm return (archive_pathmatch(p, (const char *)pn, flag)); 821238825Smm } else { 822238825Smm const wchar_t *p; 823238825Smm r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 824238825Smm if (r == 0) 825238825Smm return (archive_pathmatch_w(p, (const wchar_t *)pn, 826238825Smm flag)); 827238825Smm } 828238825Smm if (errno == ENOMEM) 829238825Smm return (error_nomem(a)); 830238825Smm return (0); 831238825Smm} 832238825Smm 833238825Smmstatic void 834238825Smmmatch_list_init(struct match_list *list) 835238825Smm{ 836238825Smm list->first = NULL; 837238825Smm list->last = &(list->first); 838238825Smm list->count = 0; 839238825Smm} 840238825Smm 841238825Smmstatic void 842238825Smmmatch_list_free(struct match_list *list) 843238825Smm{ 844238825Smm struct match *p, *q; 845238825Smm 846238825Smm for (p = list->first; p != NULL; ) { 847238825Smm q = p; 848238825Smm p = p->next; 849238825Smm archive_mstring_clean(&(q->pattern)); 850238825Smm free(q); 851238825Smm } 852238825Smm} 853238825Smm 854238825Smmstatic void 855238825Smmmatch_list_add(struct match_list *list, struct match *m) 856238825Smm{ 857238825Smm *list->last = m; 858238825Smm list->last = &(m->next); 859238825Smm list->count++; 860238825Smm list->unmatched_count++; 861238825Smm} 862238825Smm 863238825Smmstatic int 864238825Smmmatch_list_unmatched_inclusions_next(struct archive_match *a, 865238825Smm struct match_list *list, int mbs, const void **vp) 866238825Smm{ 867238825Smm struct match *m; 868238825Smm 869238825Smm *vp = NULL; 870238825Smm if (list->unmatched_eof) { 871238825Smm list->unmatched_eof = 0; 872238825Smm return (ARCHIVE_EOF); 873238825Smm } 874238825Smm if (list->unmatched_next == NULL) { 875238825Smm if (list->unmatched_count == 0) 876238825Smm return (ARCHIVE_EOF); 877238825Smm list->unmatched_next = list->first; 878238825Smm } 879238825Smm 880238825Smm for (m = list->unmatched_next; m != NULL; m = m->next) { 881238825Smm int r; 882238825Smm 883238825Smm if (m->matches) 884238825Smm continue; 885238825Smm if (mbs) { 886238825Smm const char *p; 887238825Smm r = archive_mstring_get_mbs(&(a->archive), 888238825Smm &(m->pattern), &p); 889238825Smm if (r < 0 && errno == ENOMEM) 890238825Smm return (error_nomem(a)); 891238825Smm if (p == NULL) 892238825Smm p = ""; 893238825Smm *vp = p; 894238825Smm } else { 895238825Smm const wchar_t *p; 896238825Smm r = archive_mstring_get_wcs(&(a->archive), 897238825Smm &(m->pattern), &p); 898238825Smm if (r < 0 && errno == ENOMEM) 899238825Smm return (error_nomem(a)); 900238825Smm if (p == NULL) 901238825Smm p = L""; 902238825Smm *vp = p; 903238825Smm } 904238825Smm list->unmatched_next = m->next; 905238825Smm if (list->unmatched_next == NULL) 906238825Smm /* To return EOF next time. */ 907238825Smm list->unmatched_eof = 1; 908238825Smm return (ARCHIVE_OK); 909238825Smm } 910238825Smm list->unmatched_next = NULL; 911238825Smm return (ARCHIVE_EOF); 912238825Smm} 913238825Smm 914238825Smm/* 915238825Smm * Utility functions to manage inclusion timestamps. 916238825Smm */ 917238825Smmint 918238825Smmarchive_match_include_time(struct archive *_a, int flag, time_t sec, 919238825Smm long nsec) 920238825Smm{ 921238825Smm int r; 922238825Smm 923238825Smm r = validate_time_flag(_a, flag, "archive_match_include_time"); 924238825Smm if (r != ARCHIVE_OK) 925238825Smm return (r); 926238825Smm return set_timefilter((struct archive_match *)_a, flag, 927238825Smm sec, nsec, sec, nsec); 928238825Smm} 929238825Smm 930238825Smmint 931238825Smmarchive_match_include_date(struct archive *_a, int flag, 932238825Smm const char *datestr) 933238825Smm{ 934238825Smm int r; 935238825Smm 936238825Smm r = validate_time_flag(_a, flag, "archive_match_include_date"); 937238825Smm if (r != ARCHIVE_OK) 938238825Smm return (r); 939238825Smm return set_timefilter_date((struct archive_match *)_a, flag, datestr); 940238825Smm} 941238825Smm 942238825Smmint 943238825Smmarchive_match_include_date_w(struct archive *_a, int flag, 944238825Smm const wchar_t *datestr) 945238825Smm{ 946238825Smm int r; 947238825Smm 948238825Smm r = validate_time_flag(_a, flag, "archive_match_include_date_w"); 949238825Smm if (r != ARCHIVE_OK) 950238825Smm return (r); 951238825Smm 952238825Smm return set_timefilter_date_w((struct archive_match *)_a, flag, datestr); 953238825Smm} 954238825Smm 955238825Smmint 956238825Smmarchive_match_include_file_time(struct archive *_a, int flag, 957238825Smm const char *pathname) 958238825Smm{ 959238825Smm int r; 960238825Smm 961238825Smm r = validate_time_flag(_a, flag, "archive_match_include_file_time"); 962238825Smm if (r != ARCHIVE_OK) 963238825Smm return (r); 964238825Smm return set_timefilter_pathname_mbs((struct archive_match *)_a, 965238825Smm flag, pathname); 966238825Smm} 967238825Smm 968238825Smmint 969238825Smmarchive_match_include_file_time_w(struct archive *_a, int flag, 970238825Smm const wchar_t *pathname) 971238825Smm{ 972238825Smm int r; 973238825Smm 974238825Smm r = validate_time_flag(_a, flag, "archive_match_include_file_time_w"); 975238825Smm if (r != ARCHIVE_OK) 976238825Smm return (r); 977238825Smm return set_timefilter_pathname_wcs((struct archive_match *)_a, 978238825Smm flag, pathname); 979238825Smm} 980238825Smm 981238825Smmint 982238825Smmarchive_match_exclude_entry(struct archive *_a, int flag, 983238825Smm struct archive_entry *entry) 984238825Smm{ 985238825Smm struct archive_match *a; 986238825Smm int r; 987238825Smm 988238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 989238825Smm ARCHIVE_STATE_NEW, "archive_match_time_include_entry"); 990238825Smm a = (struct archive_match *)_a; 991238825Smm 992238825Smm if (entry == NULL) { 993238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 994238825Smm return (ARCHIVE_FAILED); 995238825Smm } 996238825Smm r = validate_time_flag(_a, flag, "archive_match_exclude_entry"); 997238825Smm if (r != ARCHIVE_OK) 998238825Smm return (r); 999238825Smm return (add_entry(a, flag, entry)); 1000238825Smm} 1001238825Smm 1002238825Smm/* 1003238825Smm * Test function for time stamps. 1004238825Smm * 1005238825Smm * Returns 1 if archive entry is excluded. 1006238825Smm * Returns 0 if archive entry is not excluded. 1007238825Smm * Returns <0 if something error happened. 1008238825Smm */ 1009238825Smmint 1010238825Smmarchive_match_time_excluded(struct archive *_a, 1011238825Smm struct archive_entry *entry) 1012238825Smm{ 1013238825Smm struct archive_match *a; 1014238825Smm 1015238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1016238825Smm ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae"); 1017238825Smm 1018238825Smm a = (struct archive_match *)_a; 1019238825Smm if (entry == NULL) { 1020238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 1021238825Smm return (ARCHIVE_FAILED); 1022238825Smm } 1023238825Smm 1024238825Smm /* If we don't have inclusion time set at all, the entry is always 1025238825Smm * not excluded. */ 1026238825Smm if ((a->setflag & TIME_IS_SET) == 0) 1027238825Smm return (0); 1028238825Smm return (time_excluded(a, entry)); 1029238825Smm} 1030238825Smm 1031238825Smmstatic int 1032238825Smmvalidate_time_flag(struct archive *_a, int flag, const char *_fn) 1033238825Smm{ 1034238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1035238825Smm ARCHIVE_STATE_NEW, _fn); 1036238825Smm 1037238825Smm /* Check a type of time. */ 1038238825Smm if (flag & 1039238825Smm ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) { 1040238825Smm archive_set_error(_a, EINVAL, "Invalid time flag"); 1041238825Smm return (ARCHIVE_FAILED); 1042238825Smm } 1043238825Smm if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) { 1044238825Smm archive_set_error(_a, EINVAL, "No time flag"); 1045238825Smm return (ARCHIVE_FAILED); 1046238825Smm } 1047238825Smm 1048238825Smm /* Check a type of comparison. */ 1049238825Smm if (flag & 1050238825Smm ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 1051238825Smm | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) { 1052238825Smm archive_set_error(_a, EINVAL, "Invalid comparison flag"); 1053238825Smm return (ARCHIVE_FAILED); 1054238825Smm } 1055238825Smm if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 1056238825Smm | ARCHIVE_MATCH_EQUAL)) == 0) { 1057238825Smm archive_set_error(_a, EINVAL, "No comparison flag"); 1058238825Smm return (ARCHIVE_FAILED); 1059238825Smm } 1060238825Smm 1061238825Smm return (ARCHIVE_OK); 1062238825Smm} 1063238825Smm 1064238825Smm#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\ 1065238825Smm ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL) 1066238825Smmstatic int 1067238825Smmset_timefilter(struct archive_match *a, int timetype, 1068238825Smm time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec) 1069238825Smm{ 1070238825Smm if (timetype & ARCHIVE_MATCH_MTIME) { 1071238825Smm if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 1072238825Smm a->newer_mtime_filter = timetype; 1073238825Smm a->newer_mtime_sec = mtime_sec; 1074238825Smm a->newer_mtime_nsec = mtime_nsec; 1075238825Smm a->setflag |= TIME_IS_SET; 1076238825Smm } 1077238825Smm if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 1078238825Smm a->older_mtime_filter = timetype; 1079238825Smm a->older_mtime_sec = mtime_sec; 1080238825Smm a->older_mtime_nsec = mtime_nsec; 1081238825Smm a->setflag |= TIME_IS_SET; 1082238825Smm } 1083238825Smm } 1084238825Smm if (timetype & ARCHIVE_MATCH_CTIME) { 1085238825Smm if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 1086238825Smm a->newer_ctime_filter = timetype; 1087238825Smm a->newer_ctime_sec = ctime_sec; 1088238825Smm a->newer_ctime_nsec = ctime_nsec; 1089238825Smm a->setflag |= TIME_IS_SET; 1090238825Smm } 1091238825Smm if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 1092238825Smm a->older_ctime_filter = timetype; 1093238825Smm a->older_ctime_sec = ctime_sec; 1094238825Smm a->older_ctime_nsec = ctime_nsec; 1095238825Smm a->setflag |= TIME_IS_SET; 1096238825Smm } 1097238825Smm } 1098238825Smm return (ARCHIVE_OK); 1099238825Smm} 1100238825Smm 1101238825Smmstatic int 1102238825Smmset_timefilter_date(struct archive_match *a, int timetype, const char *datestr) 1103238825Smm{ 1104238825Smm time_t t; 1105238825Smm 1106238825Smm if (datestr == NULL || *datestr == '\0') { 1107238825Smm archive_set_error(&(a->archive), EINVAL, "date is empty"); 1108238825Smm return (ARCHIVE_FAILED); 1109238825Smm } 1110238825Smm t = get_date(a->now, datestr); 1111238825Smm if (t == (time_t)-1) { 1112238825Smm archive_set_error(&(a->archive), EINVAL, "invalid date string"); 1113238825Smm return (ARCHIVE_FAILED); 1114238825Smm } 1115238825Smm return set_timefilter(a, timetype, t, 0, t, 0); 1116238825Smm} 1117238825Smm 1118238825Smmstatic int 1119238825Smmset_timefilter_date_w(struct archive_match *a, int timetype, 1120238825Smm const wchar_t *datestr) 1121238825Smm{ 1122238825Smm struct archive_string as; 1123238825Smm time_t t; 1124238825Smm 1125238825Smm if (datestr == NULL || *datestr == L'\0') { 1126238825Smm archive_set_error(&(a->archive), EINVAL, "date is empty"); 1127238825Smm return (ARCHIVE_FAILED); 1128238825Smm } 1129238825Smm 1130238825Smm archive_string_init(&as); 1131238825Smm if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { 1132238825Smm archive_string_free(&as); 1133238825Smm if (errno == ENOMEM) 1134238825Smm return (error_nomem(a)); 1135238825Smm archive_set_error(&(a->archive), -1, 1136238825Smm "Failed to convert WCS to MBS"); 1137238825Smm return (ARCHIVE_FAILED); 1138238825Smm } 1139238825Smm t = get_date(a->now, as.s); 1140238825Smm archive_string_free(&as); 1141238825Smm if (t == (time_t)-1) { 1142238825Smm archive_set_error(&(a->archive), EINVAL, "invalid date string"); 1143238825Smm return (ARCHIVE_FAILED); 1144238825Smm } 1145238825Smm return set_timefilter(a, timetype, t, 0, t, 0); 1146238825Smm} 1147238825Smm 1148238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1149238825Smm#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) 1150238825Smmstatic int 1151238825Smmset_timefilter_find_data(struct archive_match *a, int timetype, 1152238825Smm DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, 1153238825Smm DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) 1154238825Smm{ 1155238825Smm ULARGE_INTEGER utc; 1156238825Smm time_t ctime_sec, mtime_sec; 1157238825Smm long ctime_ns, mtime_ns; 1158238825Smm 1159238825Smm utc.HighPart = ftCreationTime_dwHighDateTime; 1160238825Smm utc.LowPart = ftCreationTime_dwLowDateTime; 1161238825Smm if (utc.QuadPart >= EPOC_TIME) { 1162238825Smm utc.QuadPart -= EPOC_TIME; 1163238825Smm ctime_sec = (time_t)(utc.QuadPart / 10000000); 1164238825Smm ctime_ns = (long)(utc.QuadPart % 10000000) * 100; 1165238825Smm } else { 1166238825Smm ctime_sec = 0; 1167238825Smm ctime_ns = 0; 1168238825Smm } 1169238825Smm utc.HighPart = ftLastWriteTime_dwHighDateTime; 1170238825Smm utc.LowPart = ftLastWriteTime_dwLowDateTime; 1171238825Smm if (utc.QuadPart >= EPOC_TIME) { 1172238825Smm utc.QuadPart -= EPOC_TIME; 1173238825Smm mtime_sec = (time_t)(utc.QuadPart / 10000000); 1174238825Smm mtime_ns = (long)(utc.QuadPart % 10000000) * 100; 1175238825Smm } else { 1176238825Smm mtime_sec = 0; 1177238825Smm mtime_ns = 0; 1178238825Smm } 1179238825Smm return set_timefilter(a, timetype, 1180238825Smm mtime_sec, mtime_ns, ctime_sec, ctime_ns); 1181238825Smm} 1182238825Smm 1183238825Smmstatic int 1184238825Smmset_timefilter_pathname_mbs(struct archive_match *a, int timetype, 1185238825Smm const char *path) 1186238825Smm{ 1187238825Smm /* NOTE: stat() on Windows cannot handle nano seconds. */ 1188238825Smm HANDLE h; 1189299529Smm WIN32_FIND_DATAA d; 1190238825Smm 1191238825Smm if (path == NULL || *path == '\0') { 1192238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1193238825Smm return (ARCHIVE_FAILED); 1194238825Smm } 1195238825Smm h = FindFirstFileA(path, &d); 1196238825Smm if (h == INVALID_HANDLE_VALUE) { 1197238825Smm la_dosmaperr(GetLastError()); 1198238825Smm archive_set_error(&(a->archive), errno, 1199238825Smm "Failed to FindFirstFileA"); 1200238825Smm return (ARCHIVE_FAILED); 1201238825Smm } 1202238825Smm FindClose(h); 1203238825Smm return set_timefilter_find_data(a, timetype, 1204238825Smm d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 1205238825Smm d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 1206238825Smm} 1207238825Smm 1208238825Smmstatic int 1209238825Smmset_timefilter_pathname_wcs(struct archive_match *a, int timetype, 1210238825Smm const wchar_t *path) 1211238825Smm{ 1212238825Smm HANDLE h; 1213238825Smm WIN32_FIND_DATAW d; 1214238825Smm 1215238825Smm if (path == NULL || *path == L'\0') { 1216238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1217238825Smm return (ARCHIVE_FAILED); 1218238825Smm } 1219238825Smm h = FindFirstFileW(path, &d); 1220238825Smm if (h == INVALID_HANDLE_VALUE) { 1221238825Smm la_dosmaperr(GetLastError()); 1222238825Smm archive_set_error(&(a->archive), errno, 1223238825Smm "Failed to FindFirstFile"); 1224238825Smm return (ARCHIVE_FAILED); 1225238825Smm } 1226238825Smm FindClose(h); 1227238825Smm return set_timefilter_find_data(a, timetype, 1228238825Smm d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 1229238825Smm d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 1230238825Smm} 1231238825Smm 1232238825Smm#else /* _WIN32 && !__CYGWIN__ */ 1233238825Smm 1234238825Smmstatic int 1235238825Smmset_timefilter_stat(struct archive_match *a, int timetype, struct stat *st) 1236238825Smm{ 1237238825Smm struct archive_entry *ae; 1238238825Smm time_t ctime_sec, mtime_sec; 1239238825Smm long ctime_ns, mtime_ns; 1240238825Smm 1241238825Smm ae = archive_entry_new(); 1242238825Smm if (ae == NULL) 1243238825Smm return (error_nomem(a)); 1244238825Smm archive_entry_copy_stat(ae, st); 1245238825Smm ctime_sec = archive_entry_ctime(ae); 1246238825Smm ctime_ns = archive_entry_ctime_nsec(ae); 1247238825Smm mtime_sec = archive_entry_mtime(ae); 1248238825Smm mtime_ns = archive_entry_mtime_nsec(ae); 1249238825Smm archive_entry_free(ae); 1250238825Smm return set_timefilter(a, timetype, mtime_sec, mtime_ns, 1251238825Smm ctime_sec, ctime_ns); 1252238825Smm} 1253238825Smm 1254238825Smmstatic int 1255238825Smmset_timefilter_pathname_mbs(struct archive_match *a, int timetype, 1256238825Smm const char *path) 1257238825Smm{ 1258238825Smm struct stat st; 1259238825Smm 1260238825Smm if (path == NULL || *path == '\0') { 1261238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1262238825Smm return (ARCHIVE_FAILED); 1263238825Smm } 1264348607Smm if (la_stat(path, &st) != 0) { 1265238825Smm archive_set_error(&(a->archive), errno, "Failed to stat()"); 1266238825Smm return (ARCHIVE_FAILED); 1267238825Smm } 1268238825Smm return (set_timefilter_stat(a, timetype, &st)); 1269238825Smm} 1270238825Smm 1271238825Smmstatic int 1272238825Smmset_timefilter_pathname_wcs(struct archive_match *a, int timetype, 1273238825Smm const wchar_t *path) 1274238825Smm{ 1275238825Smm struct archive_string as; 1276238825Smm int r; 1277238825Smm 1278238825Smm if (path == NULL || *path == L'\0') { 1279238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1280238825Smm return (ARCHIVE_FAILED); 1281238825Smm } 1282238825Smm 1283238825Smm /* Convert WCS filename to MBS filename. */ 1284238825Smm archive_string_init(&as); 1285238825Smm if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { 1286238825Smm archive_string_free(&as); 1287238825Smm if (errno == ENOMEM) 1288238825Smm return (error_nomem(a)); 1289238825Smm archive_set_error(&(a->archive), -1, 1290238825Smm "Failed to convert WCS to MBS"); 1291238825Smm return (ARCHIVE_FAILED); 1292238825Smm } 1293238825Smm 1294238825Smm r = set_timefilter_pathname_mbs(a, timetype, as.s); 1295238825Smm archive_string_free(&as); 1296238825Smm 1297238825Smm return (r); 1298238825Smm} 1299238825Smm#endif /* _WIN32 && !__CYGWIN__ */ 1300238825Smm 1301238825Smm/* 1302313570Smm * Call back functions for archive_rb. 1303238825Smm */ 1304238825Smmstatic int 1305238825Smmcmp_node_mbs(const struct archive_rb_node *n1, 1306238825Smm const struct archive_rb_node *n2) 1307238825Smm{ 1308238825Smm struct match_file *f1 = (struct match_file *)(uintptr_t)n1; 1309238825Smm struct match_file *f2 = (struct match_file *)(uintptr_t)n2; 1310238825Smm const char *p1, *p2; 1311238825Smm 1312238825Smm archive_mstring_get_mbs(NULL, &(f1->pathname), &p1); 1313238825Smm archive_mstring_get_mbs(NULL, &(f2->pathname), &p2); 1314238825Smm if (p1 == NULL) 1315238825Smm return (1); 1316238825Smm if (p2 == NULL) 1317238825Smm return (-1); 1318238825Smm return (strcmp(p1, p2)); 1319238825Smm} 1320238825Smm 1321238825Smmstatic int 1322238825Smmcmp_key_mbs(const struct archive_rb_node *n, const void *key) 1323238825Smm{ 1324238825Smm struct match_file *f = (struct match_file *)(uintptr_t)n; 1325238825Smm const char *p; 1326238825Smm 1327238825Smm archive_mstring_get_mbs(NULL, &(f->pathname), &p); 1328238825Smm if (p == NULL) 1329238825Smm return (-1); 1330238825Smm return (strcmp(p, (const char *)key)); 1331238825Smm} 1332238825Smm 1333238825Smmstatic int 1334238825Smmcmp_node_wcs(const struct archive_rb_node *n1, 1335238825Smm const struct archive_rb_node *n2) 1336238825Smm{ 1337238825Smm struct match_file *f1 = (struct match_file *)(uintptr_t)n1; 1338238825Smm struct match_file *f2 = (struct match_file *)(uintptr_t)n2; 1339238825Smm const wchar_t *p1, *p2; 1340238825Smm 1341238825Smm archive_mstring_get_wcs(NULL, &(f1->pathname), &p1); 1342238825Smm archive_mstring_get_wcs(NULL, &(f2->pathname), &p2); 1343238825Smm if (p1 == NULL) 1344238825Smm return (1); 1345238825Smm if (p2 == NULL) 1346238825Smm return (-1); 1347238825Smm return (wcscmp(p1, p2)); 1348238825Smm} 1349238825Smm 1350238825Smmstatic int 1351238825Smmcmp_key_wcs(const struct archive_rb_node *n, const void *key) 1352238825Smm{ 1353238825Smm struct match_file *f = (struct match_file *)(uintptr_t)n; 1354238825Smm const wchar_t *p; 1355238825Smm 1356238825Smm archive_mstring_get_wcs(NULL, &(f->pathname), &p); 1357238825Smm if (p == NULL) 1358238825Smm return (-1); 1359238825Smm return (wcscmp(p, (const wchar_t *)key)); 1360238825Smm} 1361238825Smm 1362238825Smmstatic void 1363238825Smmentry_list_init(struct entry_list *list) 1364238825Smm{ 1365238825Smm list->first = NULL; 1366238825Smm list->last = &(list->first); 1367238825Smm list->count = 0; 1368238825Smm} 1369238825Smm 1370238825Smmstatic void 1371238825Smmentry_list_free(struct entry_list *list) 1372238825Smm{ 1373238825Smm struct match_file *p, *q; 1374238825Smm 1375238825Smm for (p = list->first; p != NULL; ) { 1376238825Smm q = p; 1377238825Smm p = p->next; 1378238825Smm archive_mstring_clean(&(q->pathname)); 1379238825Smm free(q); 1380238825Smm } 1381238825Smm} 1382238825Smm 1383238825Smmstatic void 1384238825Smmentry_list_add(struct entry_list *list, struct match_file *file) 1385238825Smm{ 1386238825Smm *list->last = file; 1387238825Smm list->last = &(file->next); 1388238825Smm list->count++; 1389238825Smm} 1390238825Smm 1391238825Smmstatic int 1392238825Smmadd_entry(struct archive_match *a, int flag, 1393238825Smm struct archive_entry *entry) 1394238825Smm{ 1395238825Smm struct match_file *f; 1396238825Smm const void *pathname; 1397238825Smm int r; 1398238825Smm 1399238825Smm f = calloc(1, sizeof(*f)); 1400238825Smm if (f == NULL) 1401238825Smm return (error_nomem(a)); 1402238825Smm 1403238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1404238825Smm pathname = archive_entry_pathname_w(entry); 1405238825Smm if (pathname == NULL) { 1406238825Smm free(f); 1407238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 1408238825Smm return (ARCHIVE_FAILED); 1409238825Smm } 1410238825Smm archive_mstring_copy_wcs(&(f->pathname), pathname); 1411238825Smm a->exclusion_tree.rbt_ops = &rb_ops_wcs; 1412238825Smm#else 1413248616Smm (void)rb_ops_wcs; 1414238825Smm pathname = archive_entry_pathname(entry); 1415238825Smm if (pathname == NULL) { 1416238825Smm free(f); 1417238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 1418238825Smm return (ARCHIVE_FAILED); 1419238825Smm } 1420238825Smm archive_mstring_copy_mbs(&(f->pathname), pathname); 1421238825Smm a->exclusion_tree.rbt_ops = &rb_ops_mbs; 1422238825Smm#endif 1423238825Smm f->flag = flag; 1424238825Smm f->mtime_sec = archive_entry_mtime(entry); 1425238825Smm f->mtime_nsec = archive_entry_mtime_nsec(entry); 1426238825Smm f->ctime_sec = archive_entry_ctime(entry); 1427238825Smm f->ctime_nsec = archive_entry_ctime_nsec(entry); 1428238825Smm r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node)); 1429238825Smm if (!r) { 1430238825Smm struct match_file *f2; 1431238825Smm 1432238825Smm /* Get the duplicated file. */ 1433238825Smm f2 = (struct match_file *)__archive_rb_tree_find_node( 1434238825Smm &(a->exclusion_tree), pathname); 1435238825Smm 1436238825Smm /* 1437313570Smm * We always overwrite comparison condition. 1438238825Smm * If you do not want to overwrite it, you should not 1439238825Smm * call archive_match_exclude_entry(). We cannot know 1440238825Smm * what behavior you really expect since overwriting 1441238825Smm * condition might be different with the flag. 1442238825Smm */ 1443238825Smm if (f2 != NULL) { 1444238825Smm f2->flag = f->flag; 1445238825Smm f2->mtime_sec = f->mtime_sec; 1446238825Smm f2->mtime_nsec = f->mtime_nsec; 1447238825Smm f2->ctime_sec = f->ctime_sec; 1448238825Smm f2->ctime_nsec = f->ctime_nsec; 1449238825Smm } 1450238825Smm /* Release the duplicated file. */ 1451238825Smm archive_mstring_clean(&(f->pathname)); 1452238825Smm free(f); 1453238825Smm return (ARCHIVE_OK); 1454238825Smm } 1455238825Smm entry_list_add(&(a->exclusion_entry_list), f); 1456238825Smm a->setflag |= TIME_IS_SET; 1457238825Smm return (ARCHIVE_OK); 1458238825Smm} 1459238825Smm 1460238825Smm/* 1461238825Smm * Test if entry is excluded by its timestamp. 1462238825Smm */ 1463238825Smmstatic int 1464238825Smmtime_excluded(struct archive_match *a, struct archive_entry *entry) 1465238825Smm{ 1466238825Smm struct match_file *f; 1467238825Smm const void *pathname; 1468238825Smm time_t sec; 1469238825Smm long nsec; 1470238825Smm 1471238825Smm /* 1472238825Smm * If this file/dir is excluded by a time comparison, skip it. 1473238825Smm */ 1474238825Smm if (a->newer_ctime_filter) { 1475238825Smm /* If ctime is not set, use mtime instead. */ 1476238825Smm if (archive_entry_ctime_is_set(entry)) 1477238825Smm sec = archive_entry_ctime(entry); 1478238825Smm else 1479238825Smm sec = archive_entry_mtime(entry); 1480238825Smm if (sec < a->newer_ctime_sec) 1481238825Smm return (1); /* Too old, skip it. */ 1482238825Smm if (sec == a->newer_ctime_sec) { 1483238825Smm if (archive_entry_ctime_is_set(entry)) 1484238825Smm nsec = archive_entry_ctime_nsec(entry); 1485238825Smm else 1486238825Smm nsec = archive_entry_mtime_nsec(entry); 1487238825Smm if (nsec < a->newer_ctime_nsec) 1488238825Smm return (1); /* Too old, skip it. */ 1489238825Smm if (nsec == a->newer_ctime_nsec && 1490238825Smm (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL) 1491238825Smm == 0) 1492238825Smm return (1); /* Equal, skip it. */ 1493238825Smm } 1494238825Smm } 1495238825Smm if (a->older_ctime_filter) { 1496238825Smm /* If ctime is not set, use mtime instead. */ 1497238825Smm if (archive_entry_ctime_is_set(entry)) 1498238825Smm sec = archive_entry_ctime(entry); 1499238825Smm else 1500238825Smm sec = archive_entry_mtime(entry); 1501238825Smm if (sec > a->older_ctime_sec) 1502238825Smm return (1); /* Too new, skip it. */ 1503238825Smm if (sec == a->older_ctime_sec) { 1504238825Smm if (archive_entry_ctime_is_set(entry)) 1505238825Smm nsec = archive_entry_ctime_nsec(entry); 1506238825Smm else 1507238825Smm nsec = archive_entry_mtime_nsec(entry); 1508238825Smm if (nsec > a->older_ctime_nsec) 1509238825Smm return (1); /* Too new, skip it. */ 1510238825Smm if (nsec == a->older_ctime_nsec && 1511238825Smm (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) 1512238825Smm == 0) 1513313570Smm return (1); /* Equal, skip it. */ 1514238825Smm } 1515238825Smm } 1516238825Smm if (a->newer_mtime_filter) { 1517238825Smm sec = archive_entry_mtime(entry); 1518238825Smm if (sec < a->newer_mtime_sec) 1519238825Smm return (1); /* Too old, skip it. */ 1520238825Smm if (sec == a->newer_mtime_sec) { 1521238825Smm nsec = archive_entry_mtime_nsec(entry); 1522238825Smm if (nsec < a->newer_mtime_nsec) 1523238825Smm return (1); /* Too old, skip it. */ 1524238825Smm if (nsec == a->newer_mtime_nsec && 1525238825Smm (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL) 1526238825Smm == 0) 1527238825Smm return (1); /* Equal, skip it. */ 1528238825Smm } 1529238825Smm } 1530238825Smm if (a->older_mtime_filter) { 1531238825Smm sec = archive_entry_mtime(entry); 1532238825Smm if (sec > a->older_mtime_sec) 1533238825Smm return (1); /* Too new, skip it. */ 1534238825Smm nsec = archive_entry_mtime_nsec(entry); 1535238825Smm if (sec == a->older_mtime_sec) { 1536238825Smm if (nsec > a->older_mtime_nsec) 1537238825Smm return (1); /* Too new, skip it. */ 1538238825Smm if (nsec == a->older_mtime_nsec && 1539238825Smm (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL) 1540238825Smm == 0) 1541238825Smm return (1); /* Equal, skip it. */ 1542238825Smm } 1543238825Smm } 1544238825Smm 1545313570Smm /* If there is no exclusion list, include the file. */ 1546238825Smm if (a->exclusion_entry_list.count == 0) 1547238825Smm return (0); 1548238825Smm 1549238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1550238825Smm pathname = archive_entry_pathname_w(entry); 1551238825Smm a->exclusion_tree.rbt_ops = &rb_ops_wcs; 1552238825Smm#else 1553248616Smm (void)rb_ops_wcs; 1554238825Smm pathname = archive_entry_pathname(entry); 1555238825Smm a->exclusion_tree.rbt_ops = &rb_ops_mbs; 1556238825Smm#endif 1557238825Smm if (pathname == NULL) 1558238825Smm return (0); 1559238825Smm 1560238825Smm f = (struct match_file *)__archive_rb_tree_find_node( 1561238825Smm &(a->exclusion_tree), pathname); 1562238825Smm /* If the file wasn't rejected, include it. */ 1563238825Smm if (f == NULL) 1564238825Smm return (0); 1565238825Smm 1566238825Smm if (f->flag & ARCHIVE_MATCH_CTIME) { 1567238825Smm sec = archive_entry_ctime(entry); 1568238825Smm if (f->ctime_sec > sec) { 1569238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1570238825Smm return (1); 1571238825Smm } else if (f->ctime_sec < sec) { 1572238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1573238825Smm return (1); 1574238825Smm } else { 1575238825Smm nsec = archive_entry_ctime_nsec(entry); 1576238825Smm if (f->ctime_nsec > nsec) { 1577238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1578238825Smm return (1); 1579238825Smm } else if (f->ctime_nsec < nsec) { 1580238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1581238825Smm return (1); 1582238825Smm } else if (f->flag & ARCHIVE_MATCH_EQUAL) 1583238825Smm return (1); 1584238825Smm } 1585238825Smm } 1586238825Smm if (f->flag & ARCHIVE_MATCH_MTIME) { 1587238825Smm sec = archive_entry_mtime(entry); 1588238825Smm if (f->mtime_sec > sec) { 1589238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1590238825Smm return (1); 1591238825Smm } else if (f->mtime_sec < sec) { 1592238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1593238825Smm return (1); 1594238825Smm } else { 1595238825Smm nsec = archive_entry_mtime_nsec(entry); 1596238825Smm if (f->mtime_nsec > nsec) { 1597238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1598238825Smm return (1); 1599238825Smm } else if (f->mtime_nsec < nsec) { 1600238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1601238825Smm return (1); 1602238825Smm } else if (f->flag & ARCHIVE_MATCH_EQUAL) 1603238825Smm return (1); 1604238825Smm } 1605238825Smm } 1606238825Smm return (0); 1607238825Smm} 1608238825Smm 1609238825Smm/* 1610238825Smm * Utility functions to manage inclusion owners 1611238825Smm */ 1612238825Smm 1613238825Smmint 1614328827Smmarchive_match_include_uid(struct archive *_a, la_int64_t uid) 1615238825Smm{ 1616238825Smm struct archive_match *a; 1617238825Smm 1618238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1619238825Smm ARCHIVE_STATE_NEW, "archive_match_include_uid"); 1620238825Smm a = (struct archive_match *)_a; 1621238825Smm return (add_owner_id(a, &(a->inclusion_uids), uid)); 1622238825Smm} 1623238825Smm 1624238825Smmint 1625328827Smmarchive_match_include_gid(struct archive *_a, la_int64_t gid) 1626238825Smm{ 1627238825Smm struct archive_match *a; 1628238825Smm 1629238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1630238825Smm ARCHIVE_STATE_NEW, "archive_match_include_gid"); 1631238825Smm a = (struct archive_match *)_a; 1632238825Smm return (add_owner_id(a, &(a->inclusion_gids), gid)); 1633238825Smm} 1634238825Smm 1635238825Smmint 1636238825Smmarchive_match_include_uname(struct archive *_a, const char *uname) 1637238825Smm{ 1638238825Smm struct archive_match *a; 1639238825Smm 1640238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1641238825Smm ARCHIVE_STATE_NEW, "archive_match_include_uname"); 1642238825Smm a = (struct archive_match *)_a; 1643238825Smm return (add_owner_name(a, &(a->inclusion_unames), 1, uname)); 1644238825Smm} 1645238825Smm 1646238825Smmint 1647238825Smmarchive_match_include_uname_w(struct archive *_a, const wchar_t *uname) 1648238825Smm{ 1649238825Smm struct archive_match *a; 1650238825Smm 1651238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1652238825Smm ARCHIVE_STATE_NEW, "archive_match_include_uname_w"); 1653238825Smm a = (struct archive_match *)_a; 1654238825Smm return (add_owner_name(a, &(a->inclusion_unames), 0, uname)); 1655238825Smm} 1656238825Smm 1657238825Smmint 1658238825Smmarchive_match_include_gname(struct archive *_a, const char *gname) 1659238825Smm{ 1660238825Smm struct archive_match *a; 1661238825Smm 1662238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1663238825Smm ARCHIVE_STATE_NEW, "archive_match_include_gname"); 1664238825Smm a = (struct archive_match *)_a; 1665238825Smm return (add_owner_name(a, &(a->inclusion_gnames), 1, gname)); 1666238825Smm} 1667238825Smm 1668238825Smmint 1669238825Smmarchive_match_include_gname_w(struct archive *_a, const wchar_t *gname) 1670238825Smm{ 1671238825Smm struct archive_match *a; 1672238825Smm 1673238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1674238825Smm ARCHIVE_STATE_NEW, "archive_match_include_gname_w"); 1675238825Smm a = (struct archive_match *)_a; 1676238825Smm return (add_owner_name(a, &(a->inclusion_gnames), 0, gname)); 1677238825Smm} 1678238825Smm 1679238825Smm/* 1680238825Smm * Test function for owner(uid, gid, uname, gname). 1681238825Smm * 1682238825Smm * Returns 1 if archive entry is excluded. 1683238825Smm * Returns 0 if archive entry is not excluded. 1684238825Smm * Returns <0 if something error happened. 1685238825Smm */ 1686238825Smmint 1687238825Smmarchive_match_owner_excluded(struct archive *_a, 1688238825Smm struct archive_entry *entry) 1689238825Smm{ 1690238825Smm struct archive_match *a; 1691238825Smm 1692238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1693238825Smm ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae"); 1694238825Smm 1695238825Smm a = (struct archive_match *)_a; 1696238825Smm if (entry == NULL) { 1697238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 1698238825Smm return (ARCHIVE_FAILED); 1699238825Smm } 1700238825Smm 1701238825Smm /* If we don't have inclusion id set at all, the entry is always 1702238825Smm * not excluded. */ 1703238825Smm if ((a->setflag & ID_IS_SET) == 0) 1704238825Smm return (0); 1705238825Smm return (owner_excluded(a, entry)); 1706238825Smm} 1707238825Smm 1708238825Smmstatic int 1709238825Smmadd_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) 1710238825Smm{ 1711238825Smm unsigned i; 1712238825Smm 1713238825Smm if (ids->count + 1 >= ids->size) { 1714248616Smm void *p; 1715248616Smm 1716238825Smm if (ids->size == 0) 1717238825Smm ids->size = 8; 1718238825Smm else 1719238825Smm ids->size *= 2; 1720248616Smm p = realloc(ids->ids, sizeof(*ids->ids) * ids->size); 1721248616Smm if (p == NULL) 1722238825Smm return (error_nomem(a)); 1723248616Smm ids->ids = (int64_t *)p; 1724238825Smm } 1725238825Smm 1726238825Smm /* Find an insert point. */ 1727238825Smm for (i = 0; i < ids->count; i++) { 1728238825Smm if (ids->ids[i] >= id) 1729238825Smm break; 1730238825Smm } 1731238825Smm 1732313570Smm /* Add owner id. */ 1733238825Smm if (i == ids->count) 1734238825Smm ids->ids[ids->count++] = id; 1735238825Smm else if (ids->ids[i] != id) { 1736238825Smm memmove(&(ids->ids[i+1]), &(ids->ids[i]), 1737238825Smm (ids->count - i) * sizeof(ids->ids[0])); 1738238825Smm ids->ids[i] = id; 1739238825Smm ids->count++; 1740238825Smm } 1741238825Smm a->setflag |= ID_IS_SET; 1742238825Smm return (ARCHIVE_OK); 1743238825Smm} 1744238825Smm 1745238825Smmstatic int 1746238825Smmmatch_owner_id(struct id_array *ids, int64_t id) 1747238825Smm{ 1748238825Smm unsigned b, m, t; 1749238825Smm 1750238825Smm t = 0; 1751248616Smm b = (unsigned)ids->count; 1752238825Smm while (t < b) { 1753238825Smm m = (t + b)>>1; 1754238825Smm if (ids->ids[m] == id) 1755238825Smm return (1); 1756238825Smm if (ids->ids[m] < id) 1757238825Smm t = m + 1; 1758238825Smm else 1759238825Smm b = m; 1760238825Smm } 1761238825Smm return (0); 1762238825Smm} 1763238825Smm 1764238825Smmstatic int 1765238825Smmadd_owner_name(struct archive_match *a, struct match_list *list, 1766238825Smm int mbs, const void *name) 1767238825Smm{ 1768238825Smm struct match *match; 1769238825Smm 1770238825Smm match = calloc(1, sizeof(*match)); 1771238825Smm if (match == NULL) 1772238825Smm return (error_nomem(a)); 1773238825Smm if (mbs) 1774238825Smm archive_mstring_copy_mbs(&(match->pattern), name); 1775238825Smm else 1776238825Smm archive_mstring_copy_wcs(&(match->pattern), name); 1777238825Smm match_list_add(list, match); 1778238825Smm a->setflag |= ID_IS_SET; 1779238825Smm return (ARCHIVE_OK); 1780238825Smm} 1781238825Smm 1782238825Smm#if !defined(_WIN32) || defined(__CYGWIN__) 1783238825Smmstatic int 1784238825Smmmatch_owner_name_mbs(struct archive_match *a, struct match_list *list, 1785238825Smm const char *name) 1786238825Smm{ 1787238825Smm struct match *m; 1788238825Smm const char *p; 1789238825Smm 1790238825Smm if (name == NULL || *name == '\0') 1791238825Smm return (0); 1792238825Smm for (m = list->first; m; m = m->next) { 1793238825Smm if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p) 1794238825Smm < 0 && errno == ENOMEM) 1795238825Smm return (error_nomem(a)); 1796238825Smm if (p != NULL && strcmp(p, name) == 0) { 1797238825Smm m->matches++; 1798238825Smm return (1); 1799238825Smm } 1800238825Smm } 1801238825Smm return (0); 1802238825Smm} 1803238825Smm#else 1804238825Smmstatic int 1805238825Smmmatch_owner_name_wcs(struct archive_match *a, struct match_list *list, 1806238825Smm const wchar_t *name) 1807238825Smm{ 1808238825Smm struct match *m; 1809238825Smm const wchar_t *p; 1810238825Smm 1811238825Smm if (name == NULL || *name == L'\0') 1812238825Smm return (0); 1813238825Smm for (m = list->first; m; m = m->next) { 1814238825Smm if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p) 1815238825Smm < 0 && errno == ENOMEM) 1816238825Smm return (error_nomem(a)); 1817238825Smm if (p != NULL && wcscmp(p, name) == 0) { 1818238825Smm m->matches++; 1819238825Smm return (1); 1820238825Smm } 1821238825Smm } 1822238825Smm return (0); 1823238825Smm} 1824238825Smm#endif 1825238825Smm 1826238825Smm/* 1827238825Smm * Test if entry is excluded by uid, gid, uname or gname. 1828238825Smm */ 1829238825Smmstatic int 1830238825Smmowner_excluded(struct archive_match *a, struct archive_entry *entry) 1831238825Smm{ 1832238825Smm int r; 1833238825Smm 1834238825Smm if (a->inclusion_uids.count) { 1835238825Smm if (!match_owner_id(&(a->inclusion_uids), 1836238825Smm archive_entry_uid(entry))) 1837238825Smm return (1); 1838238825Smm } 1839238825Smm 1840238825Smm if (a->inclusion_gids.count) { 1841238825Smm if (!match_owner_id(&(a->inclusion_gids), 1842238825Smm archive_entry_gid(entry))) 1843238825Smm return (1); 1844238825Smm } 1845238825Smm 1846238825Smm if (a->inclusion_unames.count) { 1847238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1848238825Smm r = match_owner_name_wcs(a, &(a->inclusion_unames), 1849238825Smm archive_entry_uname_w(entry)); 1850238825Smm#else 1851238825Smm r = match_owner_name_mbs(a, &(a->inclusion_unames), 1852238825Smm archive_entry_uname(entry)); 1853238825Smm#endif 1854238825Smm if (!r) 1855238825Smm return (1); 1856238825Smm else if (r < 0) 1857238825Smm return (r); 1858238825Smm } 1859238825Smm 1860238825Smm if (a->inclusion_gnames.count) { 1861238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1862238825Smm r = match_owner_name_wcs(a, &(a->inclusion_gnames), 1863238825Smm archive_entry_gname_w(entry)); 1864238825Smm#else 1865238825Smm r = match_owner_name_mbs(a, &(a->inclusion_gnames), 1866238825Smm archive_entry_gname(entry)); 1867238825Smm#endif 1868238825Smm if (!r) 1869238825Smm return (1); 1870238825Smm else if (r < 0) 1871238825Smm return (r); 1872238825Smm } 1873238825Smm return (0); 1874238825Smm} 1875238825Smm 1876