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