archive_match.c revision 299529
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 96238825Smm /* 97238825Smm * Matching filename patterns. 98238825Smm */ 99238825Smm struct match_list exclusions; 100238825Smm struct match_list inclusions; 101238825Smm 102238825Smm /* 103238825Smm * Matching time stamps. 104238825Smm */ 105238825Smm time_t now; 106238825Smm int newer_mtime_filter; 107238825Smm time_t newer_mtime_sec; 108238825Smm long newer_mtime_nsec; 109238825Smm int newer_ctime_filter; 110238825Smm time_t newer_ctime_sec; 111238825Smm long newer_ctime_nsec; 112238825Smm int older_mtime_filter; 113238825Smm time_t older_mtime_sec; 114238825Smm long older_mtime_nsec; 115238825Smm int older_ctime_filter; 116238825Smm time_t older_ctime_sec; 117238825Smm long older_ctime_nsec; 118238825Smm /* 119238825Smm * Matching time stamps with its filename. 120238825Smm */ 121238825Smm struct archive_rb_tree exclusion_tree; 122238825Smm struct entry_list exclusion_entry_list; 123238825Smm 124238825Smm /* 125238825Smm * Matching file owners. 126238825Smm */ 127238825Smm struct id_array inclusion_uids; 128238825Smm struct id_array inclusion_gids; 129238825Smm struct match_list inclusion_unames; 130238825Smm struct match_list inclusion_gnames; 131238825Smm}; 132238825Smm 133238825Smmstatic int add_pattern_from_file(struct archive_match *, 134238825Smm struct match_list *, int, const void *, int); 135238825Smmstatic int add_entry(struct archive_match *, int, 136238825Smm struct archive_entry *); 137238825Smmstatic int add_owner_id(struct archive_match *, struct id_array *, 138238825Smm int64_t); 139238825Smmstatic int add_owner_name(struct archive_match *, struct match_list *, 140238825Smm int, const void *); 141238825Smmstatic int add_pattern_mbs(struct archive_match *, struct match_list *, 142238825Smm const char *); 143238825Smmstatic int add_pattern_wcs(struct archive_match *, struct match_list *, 144238825Smm const wchar_t *); 145238825Smmstatic int cmp_key_mbs(const struct archive_rb_node *, const void *); 146238825Smmstatic int cmp_key_wcs(const struct archive_rb_node *, const void *); 147238825Smmstatic int cmp_node_mbs(const struct archive_rb_node *, 148238825Smm const struct archive_rb_node *); 149238825Smmstatic int cmp_node_wcs(const struct archive_rb_node *, 150238825Smm const struct archive_rb_node *); 151238825Smmstatic void entry_list_add(struct entry_list *, struct match_file *); 152238825Smmstatic void entry_list_free(struct entry_list *); 153238825Smmstatic void entry_list_init(struct entry_list *); 154238825Smmstatic int error_nomem(struct archive_match *); 155238825Smmstatic void match_list_add(struct match_list *, struct match *); 156238825Smmstatic void match_list_free(struct match_list *); 157238825Smmstatic void match_list_init(struct match_list *); 158238825Smmstatic int match_list_unmatched_inclusions_next(struct archive_match *, 159238825Smm struct match_list *, int, const void **); 160238825Smmstatic int match_owner_id(struct id_array *, int64_t); 161238825Smm#if !defined(_WIN32) || defined(__CYGWIN__) 162238825Smmstatic int match_owner_name_mbs(struct archive_match *, 163238825Smm struct match_list *, const char *); 164238825Smm#else 165238825Smmstatic int match_owner_name_wcs(struct archive_match *, 166238825Smm struct match_list *, const wchar_t *); 167238825Smm#endif 168238825Smmstatic int match_path_exclusion(struct archive_match *, 169238825Smm struct match *, int, const void *); 170238825Smmstatic int match_path_inclusion(struct archive_match *, 171238825Smm struct match *, int, const void *); 172238825Smmstatic int owner_excluded(struct archive_match *, 173238825Smm struct archive_entry *); 174238825Smmstatic int path_excluded(struct archive_match *, int, const void *); 175238825Smmstatic int set_timefilter(struct archive_match *, int, time_t, long, 176238825Smm time_t, long); 177238825Smmstatic int set_timefilter_pathname_mbs(struct archive_match *, 178238825Smm int, const char *); 179238825Smmstatic int set_timefilter_pathname_wcs(struct archive_match *, 180238825Smm int, const wchar_t *); 181238825Smmstatic int set_timefilter_date(struct archive_match *, int, const char *); 182238825Smmstatic int set_timefilter_date_w(struct archive_match *, int, 183238825Smm const wchar_t *); 184238825Smmstatic int time_excluded(struct archive_match *, 185238825Smm struct archive_entry *); 186238825Smmstatic int validate_time_flag(struct archive *, int, const char *); 187238825Smm 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); 583299529Smm r = archive_read_support_format_empty(ar); 584238825Smm if (r != ARCHIVE_OK) { 585238825Smm archive_copy_error(&(a->archive), ar); 586238825Smm archive_read_free(ar); 587238825Smm return (r); 588238825Smm } 589238825Smm if (mbs) 590238825Smm r = archive_read_open_filename(ar, pathname, 512*20); 591238825Smm else 592238825Smm r = archive_read_open_filename_w(ar, pathname, 512*20); 593238825Smm if (r != ARCHIVE_OK) { 594238825Smm archive_copy_error(&(a->archive), ar); 595238825Smm archive_read_free(ar); 596238825Smm return (r); 597238825Smm } 598238825Smm r = archive_read_next_header(ar, &ae); 599238825Smm if (r != ARCHIVE_OK) { 600238825Smm archive_read_free(ar); 601299529Smm if (r == ARCHIVE_EOF) { 602299529Smm return (ARCHIVE_OK); 603299529Smm } else { 604299529Smm archive_copy_error(&(a->archive), ar); 605299529Smm return (r); 606299529Smm } 607238825Smm } 608238825Smm 609238825Smm archive_string_init(&as); 610238825Smm 611238825Smm while ((r = archive_read_data_block(ar, &buff, &size, &offset)) 612238825Smm == ARCHIVE_OK) { 613238825Smm const char *b = (const char *)buff; 614238825Smm 615238825Smm while (size) { 616238825Smm const char *s = (const char *)b; 617238825Smm size_t length = 0; 618238825Smm int found_separator = 0; 619238825Smm 620238825Smm while (length < size) { 621238825Smm if (nullSeparator) { 622238825Smm if (*b == '\0') { 623238825Smm found_separator = 1; 624238825Smm break; 625238825Smm } 626238825Smm } else { 627238825Smm if (*b == 0x0d || *b == 0x0a) { 628238825Smm found_separator = 1; 629238825Smm break; 630238825Smm } 631238825Smm } 632238825Smm b++; 633238825Smm length++; 634238825Smm } 635238825Smm if (!found_separator) { 636238825Smm archive_strncat(&as, s, length); 637238825Smm /* Read next data block. */ 638238825Smm break; 639238825Smm } 640238825Smm b++; 641238825Smm size -= length + 1; 642238825Smm archive_strncat(&as, s, length); 643238825Smm 644238825Smm /* If the line is not empty, add the pattern. */ 645238825Smm if (archive_strlen(&as) > 0) { 646238825Smm /* Add pattern. */ 647238825Smm r = add_pattern_mbs(a, mlist, as.s); 648238825Smm if (r != ARCHIVE_OK) { 649238825Smm archive_read_free(ar); 650238825Smm archive_string_free(&as); 651238825Smm return (r); 652238825Smm } 653238825Smm archive_string_empty(&as); 654238825Smm } 655238825Smm } 656238825Smm } 657238825Smm 658238825Smm /* If something error happend, report it immediately. */ 659238825Smm if (r < ARCHIVE_OK) { 660238825Smm archive_copy_error(&(a->archive), ar); 661238825Smm archive_read_free(ar); 662238825Smm archive_string_free(&as); 663238825Smm return (r); 664238825Smm } 665238825Smm 666238825Smm /* If the line is not empty, add the pattern. */ 667238825Smm if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { 668238825Smm /* Add pattern. */ 669238825Smm r = add_pattern_mbs(a, mlist, as.s); 670238825Smm if (r != ARCHIVE_OK) { 671238825Smm archive_read_free(ar); 672238825Smm archive_string_free(&as); 673238825Smm return (r); 674238825Smm } 675238825Smm } 676238825Smm archive_read_free(ar); 677238825Smm archive_string_free(&as); 678238825Smm return (ARCHIVE_OK); 679238825Smm} 680238825Smm 681238825Smm/* 682238825Smm * Test if pathname is excluded by inclusion/exclusion patterns. 683238825Smm */ 684238825Smmstatic int 685238825Smmpath_excluded(struct archive_match *a, int mbs, const void *pathname) 686238825Smm{ 687238825Smm struct match *match; 688238825Smm struct match *matched; 689238825Smm int r; 690238825Smm 691238825Smm if (a == NULL) 692238825Smm return (0); 693238825Smm 694238825Smm /* Mark off any unmatched inclusions. */ 695238825Smm /* In particular, if a filename does appear in the archive and 696238825Smm * is explicitly included and excluded, then we don't report 697238825Smm * it as missing even though we don't extract it. 698238825Smm */ 699238825Smm matched = NULL; 700238825Smm for (match = a->inclusions.first; match != NULL; 701238825Smm match = match->next){ 702238825Smm if (match->matches == 0 && 703238825Smm (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 704238825Smm if (r < 0) 705238825Smm return (r); 706238825Smm a->inclusions.unmatched_count--; 707238825Smm match->matches++; 708238825Smm matched = match; 709238825Smm } 710238825Smm } 711238825Smm 712238825Smm /* Exclusions take priority */ 713238825Smm for (match = a->exclusions.first; match != NULL; 714238825Smm match = match->next){ 715238825Smm r = match_path_exclusion(a, match, mbs, pathname); 716238825Smm if (r) 717238825Smm return (r); 718238825Smm } 719238825Smm 720238825Smm /* It's not excluded and we found an inclusion above, so it's 721238825Smm * included. */ 722238825Smm if (matched != NULL) 723238825Smm return (0); 724238825Smm 725238825Smm 726238825Smm /* We didn't find an unmatched inclusion, check the remaining ones. */ 727238825Smm for (match = a->inclusions.first; match != NULL; 728238825Smm match = match->next){ 729238825Smm /* We looked at previously-unmatched inclusions already. */ 730238825Smm if (match->matches > 0 && 731238825Smm (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 732238825Smm if (r < 0) 733238825Smm return (r); 734238825Smm match->matches++; 735238825Smm return (0); 736238825Smm } 737238825Smm } 738238825Smm 739238825Smm /* If there were inclusions, default is to exclude. */ 740238825Smm if (a->inclusions.first != NULL) 741238825Smm return (1); 742238825Smm 743238825Smm /* No explicit inclusions, default is to match. */ 744238825Smm return (0); 745238825Smm} 746238825Smm 747238825Smm/* 748238825Smm * This is a little odd, but it matches the default behavior of 749238825Smm * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' 750238825Smm * 751238825Smm */ 752238825Smmstatic int 753238825Smmmatch_path_exclusion(struct archive_match *a, struct match *m, 754238825Smm int mbs, const void *pn) 755238825Smm{ 756238825Smm int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END; 757238825Smm int r; 758238825Smm 759238825Smm if (mbs) { 760238825Smm const char *p; 761238825Smm r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 762238825Smm if (r == 0) 763238825Smm return (archive_pathmatch(p, (const char *)pn, flag)); 764238825Smm } else { 765238825Smm const wchar_t *p; 766238825Smm r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 767238825Smm if (r == 0) 768238825Smm return (archive_pathmatch_w(p, (const wchar_t *)pn, 769238825Smm flag)); 770238825Smm } 771238825Smm if (errno == ENOMEM) 772238825Smm return (error_nomem(a)); 773238825Smm return (0); 774238825Smm} 775238825Smm 776238825Smm/* 777238825Smm * Again, mimic gtar: inclusions are always anchored (have to match 778238825Smm * the beginning of the path) even though exclusions are not anchored. 779238825Smm */ 780238825Smmstatic int 781238825Smmmatch_path_inclusion(struct archive_match *a, struct match *m, 782238825Smm int mbs, const void *pn) 783238825Smm{ 784238825Smm int flag = PATHMATCH_NO_ANCHOR_END; 785238825Smm int r; 786238825Smm 787238825Smm if (mbs) { 788238825Smm const char *p; 789238825Smm r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 790238825Smm if (r == 0) 791238825Smm return (archive_pathmatch(p, (const char *)pn, flag)); 792238825Smm } else { 793238825Smm const wchar_t *p; 794238825Smm r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 795238825Smm if (r == 0) 796238825Smm return (archive_pathmatch_w(p, (const wchar_t *)pn, 797238825Smm flag)); 798238825Smm } 799238825Smm if (errno == ENOMEM) 800238825Smm return (error_nomem(a)); 801238825Smm return (0); 802238825Smm} 803238825Smm 804238825Smmstatic void 805238825Smmmatch_list_init(struct match_list *list) 806238825Smm{ 807238825Smm list->first = NULL; 808238825Smm list->last = &(list->first); 809238825Smm list->count = 0; 810238825Smm} 811238825Smm 812238825Smmstatic void 813238825Smmmatch_list_free(struct match_list *list) 814238825Smm{ 815238825Smm struct match *p, *q; 816238825Smm 817238825Smm for (p = list->first; p != NULL; ) { 818238825Smm q = p; 819238825Smm p = p->next; 820238825Smm archive_mstring_clean(&(q->pattern)); 821238825Smm free(q); 822238825Smm } 823238825Smm} 824238825Smm 825238825Smmstatic void 826238825Smmmatch_list_add(struct match_list *list, struct match *m) 827238825Smm{ 828238825Smm *list->last = m; 829238825Smm list->last = &(m->next); 830238825Smm list->count++; 831238825Smm list->unmatched_count++; 832238825Smm} 833238825Smm 834238825Smmstatic int 835238825Smmmatch_list_unmatched_inclusions_next(struct archive_match *a, 836238825Smm struct match_list *list, int mbs, const void **vp) 837238825Smm{ 838238825Smm struct match *m; 839238825Smm 840238825Smm *vp = NULL; 841238825Smm if (list->unmatched_eof) { 842238825Smm list->unmatched_eof = 0; 843238825Smm return (ARCHIVE_EOF); 844238825Smm } 845238825Smm if (list->unmatched_next == NULL) { 846238825Smm if (list->unmatched_count == 0) 847238825Smm return (ARCHIVE_EOF); 848238825Smm list->unmatched_next = list->first; 849238825Smm } 850238825Smm 851238825Smm for (m = list->unmatched_next; m != NULL; m = m->next) { 852238825Smm int r; 853238825Smm 854238825Smm if (m->matches) 855238825Smm continue; 856238825Smm if (mbs) { 857238825Smm const char *p; 858238825Smm r = archive_mstring_get_mbs(&(a->archive), 859238825Smm &(m->pattern), &p); 860238825Smm if (r < 0 && errno == ENOMEM) 861238825Smm return (error_nomem(a)); 862238825Smm if (p == NULL) 863238825Smm p = ""; 864238825Smm *vp = p; 865238825Smm } else { 866238825Smm const wchar_t *p; 867238825Smm r = archive_mstring_get_wcs(&(a->archive), 868238825Smm &(m->pattern), &p); 869238825Smm if (r < 0 && errno == ENOMEM) 870238825Smm return (error_nomem(a)); 871238825Smm if (p == NULL) 872238825Smm p = L""; 873238825Smm *vp = p; 874238825Smm } 875238825Smm list->unmatched_next = m->next; 876238825Smm if (list->unmatched_next == NULL) 877238825Smm /* To return EOF next time. */ 878238825Smm list->unmatched_eof = 1; 879238825Smm return (ARCHIVE_OK); 880238825Smm } 881238825Smm list->unmatched_next = NULL; 882238825Smm return (ARCHIVE_EOF); 883238825Smm} 884238825Smm 885238825Smm/* 886238825Smm * Utility functions to manage inclusion timestamps. 887238825Smm */ 888238825Smmint 889238825Smmarchive_match_include_time(struct archive *_a, int flag, time_t sec, 890238825Smm long nsec) 891238825Smm{ 892238825Smm int r; 893238825Smm 894238825Smm r = validate_time_flag(_a, flag, "archive_match_include_time"); 895238825Smm if (r != ARCHIVE_OK) 896238825Smm return (r); 897238825Smm return set_timefilter((struct archive_match *)_a, flag, 898238825Smm sec, nsec, sec, nsec); 899238825Smm} 900238825Smm 901238825Smmint 902238825Smmarchive_match_include_date(struct archive *_a, int flag, 903238825Smm const char *datestr) 904238825Smm{ 905238825Smm int r; 906238825Smm 907238825Smm r = validate_time_flag(_a, flag, "archive_match_include_date"); 908238825Smm if (r != ARCHIVE_OK) 909238825Smm return (r); 910238825Smm return set_timefilter_date((struct archive_match *)_a, flag, datestr); 911238825Smm} 912238825Smm 913238825Smmint 914238825Smmarchive_match_include_date_w(struct archive *_a, int flag, 915238825Smm const wchar_t *datestr) 916238825Smm{ 917238825Smm int r; 918238825Smm 919238825Smm r = validate_time_flag(_a, flag, "archive_match_include_date_w"); 920238825Smm if (r != ARCHIVE_OK) 921238825Smm return (r); 922238825Smm 923238825Smm return set_timefilter_date_w((struct archive_match *)_a, flag, datestr); 924238825Smm} 925238825Smm 926238825Smmint 927238825Smmarchive_match_include_file_time(struct archive *_a, int flag, 928238825Smm const char *pathname) 929238825Smm{ 930238825Smm int r; 931238825Smm 932238825Smm r = validate_time_flag(_a, flag, "archive_match_include_file_time"); 933238825Smm if (r != ARCHIVE_OK) 934238825Smm return (r); 935238825Smm return set_timefilter_pathname_mbs((struct archive_match *)_a, 936238825Smm flag, pathname); 937238825Smm} 938238825Smm 939238825Smmint 940238825Smmarchive_match_include_file_time_w(struct archive *_a, int flag, 941238825Smm const wchar_t *pathname) 942238825Smm{ 943238825Smm int r; 944238825Smm 945238825Smm r = validate_time_flag(_a, flag, "archive_match_include_file_time_w"); 946238825Smm if (r != ARCHIVE_OK) 947238825Smm return (r); 948238825Smm return set_timefilter_pathname_wcs((struct archive_match *)_a, 949238825Smm flag, pathname); 950238825Smm} 951238825Smm 952238825Smmint 953238825Smmarchive_match_exclude_entry(struct archive *_a, int flag, 954238825Smm struct archive_entry *entry) 955238825Smm{ 956238825Smm struct archive_match *a; 957238825Smm int r; 958238825Smm 959238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 960238825Smm ARCHIVE_STATE_NEW, "archive_match_time_include_entry"); 961238825Smm a = (struct archive_match *)_a; 962238825Smm 963238825Smm if (entry == NULL) { 964238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 965238825Smm return (ARCHIVE_FAILED); 966238825Smm } 967238825Smm r = validate_time_flag(_a, flag, "archive_match_exclude_entry"); 968238825Smm if (r != ARCHIVE_OK) 969238825Smm return (r); 970238825Smm return (add_entry(a, flag, entry)); 971238825Smm} 972238825Smm 973238825Smm/* 974238825Smm * Test function for time stamps. 975238825Smm * 976238825Smm * Returns 1 if archive entry is excluded. 977238825Smm * Returns 0 if archive entry is not excluded. 978238825Smm * Returns <0 if something error happened. 979238825Smm */ 980238825Smmint 981238825Smmarchive_match_time_excluded(struct archive *_a, 982238825Smm struct archive_entry *entry) 983238825Smm{ 984238825Smm struct archive_match *a; 985238825Smm 986238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 987238825Smm ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae"); 988238825Smm 989238825Smm a = (struct archive_match *)_a; 990238825Smm if (entry == NULL) { 991238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 992238825Smm return (ARCHIVE_FAILED); 993238825Smm } 994238825Smm 995238825Smm /* If we don't have inclusion time set at all, the entry is always 996238825Smm * not excluded. */ 997238825Smm if ((a->setflag & TIME_IS_SET) == 0) 998238825Smm return (0); 999238825Smm return (time_excluded(a, entry)); 1000238825Smm} 1001238825Smm 1002238825Smmstatic int 1003238825Smmvalidate_time_flag(struct archive *_a, int flag, const char *_fn) 1004238825Smm{ 1005238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1006238825Smm ARCHIVE_STATE_NEW, _fn); 1007238825Smm 1008238825Smm /* Check a type of time. */ 1009238825Smm if (flag & 1010238825Smm ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) { 1011238825Smm archive_set_error(_a, EINVAL, "Invalid time flag"); 1012238825Smm return (ARCHIVE_FAILED); 1013238825Smm } 1014238825Smm if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) { 1015238825Smm archive_set_error(_a, EINVAL, "No time flag"); 1016238825Smm return (ARCHIVE_FAILED); 1017238825Smm } 1018238825Smm 1019238825Smm /* Check a type of comparison. */ 1020238825Smm if (flag & 1021238825Smm ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 1022238825Smm | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) { 1023238825Smm archive_set_error(_a, EINVAL, "Invalid comparison flag"); 1024238825Smm return (ARCHIVE_FAILED); 1025238825Smm } 1026238825Smm if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 1027238825Smm | ARCHIVE_MATCH_EQUAL)) == 0) { 1028238825Smm archive_set_error(_a, EINVAL, "No comparison flag"); 1029238825Smm return (ARCHIVE_FAILED); 1030238825Smm } 1031238825Smm 1032238825Smm return (ARCHIVE_OK); 1033238825Smm} 1034238825Smm 1035238825Smm#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\ 1036238825Smm ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL) 1037238825Smmstatic int 1038238825Smmset_timefilter(struct archive_match *a, int timetype, 1039238825Smm time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec) 1040238825Smm{ 1041238825Smm if (timetype & ARCHIVE_MATCH_MTIME) { 1042238825Smm if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 1043238825Smm a->newer_mtime_filter = timetype; 1044238825Smm a->newer_mtime_sec = mtime_sec; 1045238825Smm a->newer_mtime_nsec = mtime_nsec; 1046238825Smm a->setflag |= TIME_IS_SET; 1047238825Smm } 1048238825Smm if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 1049238825Smm a->older_mtime_filter = timetype; 1050238825Smm a->older_mtime_sec = mtime_sec; 1051238825Smm a->older_mtime_nsec = mtime_nsec; 1052238825Smm a->setflag |= TIME_IS_SET; 1053238825Smm } 1054238825Smm } 1055238825Smm if (timetype & ARCHIVE_MATCH_CTIME) { 1056238825Smm if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 1057238825Smm a->newer_ctime_filter = timetype; 1058238825Smm a->newer_ctime_sec = ctime_sec; 1059238825Smm a->newer_ctime_nsec = ctime_nsec; 1060238825Smm a->setflag |= TIME_IS_SET; 1061238825Smm } 1062238825Smm if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 1063238825Smm a->older_ctime_filter = timetype; 1064238825Smm a->older_ctime_sec = ctime_sec; 1065238825Smm a->older_ctime_nsec = ctime_nsec; 1066238825Smm a->setflag |= TIME_IS_SET; 1067238825Smm } 1068238825Smm } 1069238825Smm return (ARCHIVE_OK); 1070238825Smm} 1071238825Smm 1072238825Smmstatic int 1073238825Smmset_timefilter_date(struct archive_match *a, int timetype, const char *datestr) 1074238825Smm{ 1075238825Smm time_t t; 1076238825Smm 1077238825Smm if (datestr == NULL || *datestr == '\0') { 1078238825Smm archive_set_error(&(a->archive), EINVAL, "date is empty"); 1079238825Smm return (ARCHIVE_FAILED); 1080238825Smm } 1081238825Smm t = get_date(a->now, datestr); 1082238825Smm if (t == (time_t)-1) { 1083238825Smm archive_set_error(&(a->archive), EINVAL, "invalid date string"); 1084238825Smm return (ARCHIVE_FAILED); 1085238825Smm } 1086238825Smm return set_timefilter(a, timetype, t, 0, t, 0); 1087238825Smm} 1088238825Smm 1089238825Smmstatic int 1090238825Smmset_timefilter_date_w(struct archive_match *a, int timetype, 1091238825Smm const wchar_t *datestr) 1092238825Smm{ 1093238825Smm struct archive_string as; 1094238825Smm time_t t; 1095238825Smm 1096238825Smm if (datestr == NULL || *datestr == L'\0') { 1097238825Smm archive_set_error(&(a->archive), EINVAL, "date is empty"); 1098238825Smm return (ARCHIVE_FAILED); 1099238825Smm } 1100238825Smm 1101238825Smm archive_string_init(&as); 1102238825Smm if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { 1103238825Smm archive_string_free(&as); 1104238825Smm if (errno == ENOMEM) 1105238825Smm return (error_nomem(a)); 1106238825Smm archive_set_error(&(a->archive), -1, 1107238825Smm "Failed to convert WCS to MBS"); 1108238825Smm return (ARCHIVE_FAILED); 1109238825Smm } 1110238825Smm t = get_date(a->now, as.s); 1111238825Smm archive_string_free(&as); 1112238825Smm if (t == (time_t)-1) { 1113238825Smm archive_set_error(&(a->archive), EINVAL, "invalid date string"); 1114238825Smm return (ARCHIVE_FAILED); 1115238825Smm } 1116238825Smm return set_timefilter(a, timetype, t, 0, t, 0); 1117238825Smm} 1118238825Smm 1119238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1120238825Smm#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) 1121238825Smmstatic int 1122238825Smmset_timefilter_find_data(struct archive_match *a, int timetype, 1123238825Smm DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, 1124238825Smm DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) 1125238825Smm{ 1126238825Smm ULARGE_INTEGER utc; 1127238825Smm time_t ctime_sec, mtime_sec; 1128238825Smm long ctime_ns, mtime_ns; 1129238825Smm 1130238825Smm utc.HighPart = ftCreationTime_dwHighDateTime; 1131238825Smm utc.LowPart = ftCreationTime_dwLowDateTime; 1132238825Smm if (utc.QuadPart >= EPOC_TIME) { 1133238825Smm utc.QuadPart -= EPOC_TIME; 1134238825Smm ctime_sec = (time_t)(utc.QuadPart / 10000000); 1135238825Smm ctime_ns = (long)(utc.QuadPart % 10000000) * 100; 1136238825Smm } else { 1137238825Smm ctime_sec = 0; 1138238825Smm ctime_ns = 0; 1139238825Smm } 1140238825Smm utc.HighPart = ftLastWriteTime_dwHighDateTime; 1141238825Smm utc.LowPart = ftLastWriteTime_dwLowDateTime; 1142238825Smm if (utc.QuadPart >= EPOC_TIME) { 1143238825Smm utc.QuadPart -= EPOC_TIME; 1144238825Smm mtime_sec = (time_t)(utc.QuadPart / 10000000); 1145238825Smm mtime_ns = (long)(utc.QuadPart % 10000000) * 100; 1146238825Smm } else { 1147238825Smm mtime_sec = 0; 1148238825Smm mtime_ns = 0; 1149238825Smm } 1150238825Smm return set_timefilter(a, timetype, 1151238825Smm mtime_sec, mtime_ns, ctime_sec, ctime_ns); 1152238825Smm} 1153238825Smm 1154238825Smmstatic int 1155238825Smmset_timefilter_pathname_mbs(struct archive_match *a, int timetype, 1156238825Smm const char *path) 1157238825Smm{ 1158238825Smm /* NOTE: stat() on Windows cannot handle nano seconds. */ 1159238825Smm HANDLE h; 1160299529Smm WIN32_FIND_DATAA d; 1161238825Smm 1162238825Smm if (path == NULL || *path == '\0') { 1163238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1164238825Smm return (ARCHIVE_FAILED); 1165238825Smm } 1166238825Smm h = FindFirstFileA(path, &d); 1167238825Smm if (h == INVALID_HANDLE_VALUE) { 1168238825Smm la_dosmaperr(GetLastError()); 1169238825Smm archive_set_error(&(a->archive), errno, 1170238825Smm "Failed to FindFirstFileA"); 1171238825Smm return (ARCHIVE_FAILED); 1172238825Smm } 1173238825Smm FindClose(h); 1174238825Smm return set_timefilter_find_data(a, timetype, 1175238825Smm d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 1176238825Smm d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 1177238825Smm} 1178238825Smm 1179238825Smmstatic int 1180238825Smmset_timefilter_pathname_wcs(struct archive_match *a, int timetype, 1181238825Smm const wchar_t *path) 1182238825Smm{ 1183238825Smm HANDLE h; 1184238825Smm WIN32_FIND_DATAW d; 1185238825Smm 1186238825Smm if (path == NULL || *path == L'\0') { 1187238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1188238825Smm return (ARCHIVE_FAILED); 1189238825Smm } 1190238825Smm h = FindFirstFileW(path, &d); 1191238825Smm if (h == INVALID_HANDLE_VALUE) { 1192238825Smm la_dosmaperr(GetLastError()); 1193238825Smm archive_set_error(&(a->archive), errno, 1194238825Smm "Failed to FindFirstFile"); 1195238825Smm return (ARCHIVE_FAILED); 1196238825Smm } 1197238825Smm FindClose(h); 1198238825Smm return set_timefilter_find_data(a, timetype, 1199238825Smm d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 1200238825Smm d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 1201238825Smm} 1202238825Smm 1203238825Smm#else /* _WIN32 && !__CYGWIN__ */ 1204238825Smm 1205238825Smmstatic int 1206238825Smmset_timefilter_stat(struct archive_match *a, int timetype, struct stat *st) 1207238825Smm{ 1208238825Smm struct archive_entry *ae; 1209238825Smm time_t ctime_sec, mtime_sec; 1210238825Smm long ctime_ns, mtime_ns; 1211238825Smm 1212238825Smm ae = archive_entry_new(); 1213238825Smm if (ae == NULL) 1214238825Smm return (error_nomem(a)); 1215238825Smm archive_entry_copy_stat(ae, st); 1216238825Smm ctime_sec = archive_entry_ctime(ae); 1217238825Smm ctime_ns = archive_entry_ctime_nsec(ae); 1218238825Smm mtime_sec = archive_entry_mtime(ae); 1219238825Smm mtime_ns = archive_entry_mtime_nsec(ae); 1220238825Smm archive_entry_free(ae); 1221238825Smm return set_timefilter(a, timetype, mtime_sec, mtime_ns, 1222238825Smm ctime_sec, ctime_ns); 1223238825Smm} 1224238825Smm 1225238825Smmstatic int 1226238825Smmset_timefilter_pathname_mbs(struct archive_match *a, int timetype, 1227238825Smm const char *path) 1228238825Smm{ 1229238825Smm struct stat st; 1230238825Smm 1231238825Smm if (path == NULL || *path == '\0') { 1232238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1233238825Smm return (ARCHIVE_FAILED); 1234238825Smm } 1235238825Smm if (stat(path, &st) != 0) { 1236238825Smm archive_set_error(&(a->archive), errno, "Failed to stat()"); 1237238825Smm return (ARCHIVE_FAILED); 1238238825Smm } 1239238825Smm return (set_timefilter_stat(a, timetype, &st)); 1240238825Smm} 1241238825Smm 1242238825Smmstatic int 1243238825Smmset_timefilter_pathname_wcs(struct archive_match *a, int timetype, 1244238825Smm const wchar_t *path) 1245238825Smm{ 1246238825Smm struct archive_string as; 1247238825Smm int r; 1248238825Smm 1249238825Smm if (path == NULL || *path == L'\0') { 1250238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1251238825Smm return (ARCHIVE_FAILED); 1252238825Smm } 1253238825Smm 1254238825Smm /* Convert WCS filename to MBS filename. */ 1255238825Smm archive_string_init(&as); 1256238825Smm if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { 1257238825Smm archive_string_free(&as); 1258238825Smm if (errno == ENOMEM) 1259238825Smm return (error_nomem(a)); 1260238825Smm archive_set_error(&(a->archive), -1, 1261238825Smm "Failed to convert WCS to MBS"); 1262238825Smm return (ARCHIVE_FAILED); 1263238825Smm } 1264238825Smm 1265238825Smm r = set_timefilter_pathname_mbs(a, timetype, as.s); 1266238825Smm archive_string_free(&as); 1267238825Smm 1268238825Smm return (r); 1269238825Smm} 1270238825Smm#endif /* _WIN32 && !__CYGWIN__ */ 1271238825Smm 1272238825Smm/* 1273238825Smm * Call back funtions for archive_rb. 1274238825Smm */ 1275238825Smmstatic int 1276238825Smmcmp_node_mbs(const struct archive_rb_node *n1, 1277238825Smm const struct archive_rb_node *n2) 1278238825Smm{ 1279238825Smm struct match_file *f1 = (struct match_file *)(uintptr_t)n1; 1280238825Smm struct match_file *f2 = (struct match_file *)(uintptr_t)n2; 1281238825Smm const char *p1, *p2; 1282238825Smm 1283238825Smm archive_mstring_get_mbs(NULL, &(f1->pathname), &p1); 1284238825Smm archive_mstring_get_mbs(NULL, &(f2->pathname), &p2); 1285238825Smm if (p1 == NULL) 1286238825Smm return (1); 1287238825Smm if (p2 == NULL) 1288238825Smm return (-1); 1289238825Smm return (strcmp(p1, p2)); 1290238825Smm} 1291238825Smm 1292238825Smmstatic int 1293238825Smmcmp_key_mbs(const struct archive_rb_node *n, const void *key) 1294238825Smm{ 1295238825Smm struct match_file *f = (struct match_file *)(uintptr_t)n; 1296238825Smm const char *p; 1297238825Smm 1298238825Smm archive_mstring_get_mbs(NULL, &(f->pathname), &p); 1299238825Smm if (p == NULL) 1300238825Smm return (-1); 1301238825Smm return (strcmp(p, (const char *)key)); 1302238825Smm} 1303238825Smm 1304238825Smmstatic int 1305238825Smmcmp_node_wcs(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 wchar_t *p1, *p2; 1311238825Smm 1312238825Smm archive_mstring_get_wcs(NULL, &(f1->pathname), &p1); 1313238825Smm archive_mstring_get_wcs(NULL, &(f2->pathname), &p2); 1314238825Smm if (p1 == NULL) 1315238825Smm return (1); 1316238825Smm if (p2 == NULL) 1317238825Smm return (-1); 1318238825Smm return (wcscmp(p1, p2)); 1319238825Smm} 1320238825Smm 1321238825Smmstatic int 1322238825Smmcmp_key_wcs(const struct archive_rb_node *n, const void *key) 1323238825Smm{ 1324238825Smm struct match_file *f = (struct match_file *)(uintptr_t)n; 1325238825Smm const wchar_t *p; 1326238825Smm 1327238825Smm archive_mstring_get_wcs(NULL, &(f->pathname), &p); 1328238825Smm if (p == NULL) 1329238825Smm return (-1); 1330238825Smm return (wcscmp(p, (const wchar_t *)key)); 1331238825Smm} 1332238825Smm 1333238825Smmstatic void 1334238825Smmentry_list_init(struct entry_list *list) 1335238825Smm{ 1336238825Smm list->first = NULL; 1337238825Smm list->last = &(list->first); 1338238825Smm list->count = 0; 1339238825Smm} 1340238825Smm 1341238825Smmstatic void 1342238825Smmentry_list_free(struct entry_list *list) 1343238825Smm{ 1344238825Smm struct match_file *p, *q; 1345238825Smm 1346238825Smm for (p = list->first; p != NULL; ) { 1347238825Smm q = p; 1348238825Smm p = p->next; 1349238825Smm archive_mstring_clean(&(q->pathname)); 1350238825Smm free(q); 1351238825Smm } 1352238825Smm} 1353238825Smm 1354238825Smmstatic void 1355238825Smmentry_list_add(struct entry_list *list, struct match_file *file) 1356238825Smm{ 1357238825Smm *list->last = file; 1358238825Smm list->last = &(file->next); 1359238825Smm list->count++; 1360238825Smm} 1361238825Smm 1362238825Smmstatic int 1363238825Smmadd_entry(struct archive_match *a, int flag, 1364238825Smm struct archive_entry *entry) 1365238825Smm{ 1366238825Smm struct match_file *f; 1367238825Smm const void *pathname; 1368238825Smm int r; 1369238825Smm 1370238825Smm f = calloc(1, sizeof(*f)); 1371238825Smm if (f == NULL) 1372238825Smm return (error_nomem(a)); 1373238825Smm 1374238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1375238825Smm pathname = archive_entry_pathname_w(entry); 1376238825Smm if (pathname == NULL) { 1377238825Smm free(f); 1378238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 1379238825Smm return (ARCHIVE_FAILED); 1380238825Smm } 1381238825Smm archive_mstring_copy_wcs(&(f->pathname), pathname); 1382238825Smm a->exclusion_tree.rbt_ops = &rb_ops_wcs; 1383238825Smm#else 1384248616Smm (void)rb_ops_wcs; 1385238825Smm pathname = archive_entry_pathname(entry); 1386238825Smm if (pathname == NULL) { 1387238825Smm free(f); 1388238825Smm archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 1389238825Smm return (ARCHIVE_FAILED); 1390238825Smm } 1391238825Smm archive_mstring_copy_mbs(&(f->pathname), pathname); 1392238825Smm a->exclusion_tree.rbt_ops = &rb_ops_mbs; 1393238825Smm#endif 1394238825Smm f->flag = flag; 1395238825Smm f->mtime_sec = archive_entry_mtime(entry); 1396238825Smm f->mtime_nsec = archive_entry_mtime_nsec(entry); 1397238825Smm f->ctime_sec = archive_entry_ctime(entry); 1398238825Smm f->ctime_nsec = archive_entry_ctime_nsec(entry); 1399238825Smm r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node)); 1400238825Smm if (!r) { 1401238825Smm struct match_file *f2; 1402238825Smm 1403238825Smm /* Get the duplicated file. */ 1404238825Smm f2 = (struct match_file *)__archive_rb_tree_find_node( 1405238825Smm &(a->exclusion_tree), pathname); 1406238825Smm 1407238825Smm /* 1408238825Smm * We always overwrite comparison condision. 1409238825Smm * If you do not want to overwrite it, you should not 1410238825Smm * call archive_match_exclude_entry(). We cannot know 1411238825Smm * what behavior you really expect since overwriting 1412238825Smm * condition might be different with the flag. 1413238825Smm */ 1414238825Smm if (f2 != NULL) { 1415238825Smm f2->flag = f->flag; 1416238825Smm f2->mtime_sec = f->mtime_sec; 1417238825Smm f2->mtime_nsec = f->mtime_nsec; 1418238825Smm f2->ctime_sec = f->ctime_sec; 1419238825Smm f2->ctime_nsec = f->ctime_nsec; 1420238825Smm } 1421238825Smm /* Release the duplicated file. */ 1422238825Smm archive_mstring_clean(&(f->pathname)); 1423238825Smm free(f); 1424238825Smm return (ARCHIVE_OK); 1425238825Smm } 1426238825Smm entry_list_add(&(a->exclusion_entry_list), f); 1427238825Smm a->setflag |= TIME_IS_SET; 1428238825Smm return (ARCHIVE_OK); 1429238825Smm} 1430238825Smm 1431238825Smm/* 1432238825Smm * Test if entry is excluded by its timestamp. 1433238825Smm */ 1434238825Smmstatic int 1435238825Smmtime_excluded(struct archive_match *a, struct archive_entry *entry) 1436238825Smm{ 1437238825Smm struct match_file *f; 1438238825Smm const void *pathname; 1439238825Smm time_t sec; 1440238825Smm long nsec; 1441238825Smm 1442238825Smm /* 1443238825Smm * If this file/dir is excluded by a time comparison, skip it. 1444238825Smm */ 1445238825Smm if (a->newer_ctime_filter) { 1446238825Smm /* If ctime is not set, use mtime instead. */ 1447238825Smm if (archive_entry_ctime_is_set(entry)) 1448238825Smm sec = archive_entry_ctime(entry); 1449238825Smm else 1450238825Smm sec = archive_entry_mtime(entry); 1451238825Smm if (sec < a->newer_ctime_sec) 1452238825Smm return (1); /* Too old, skip it. */ 1453238825Smm if (sec == a->newer_ctime_sec) { 1454238825Smm if (archive_entry_ctime_is_set(entry)) 1455238825Smm nsec = archive_entry_ctime_nsec(entry); 1456238825Smm else 1457238825Smm nsec = archive_entry_mtime_nsec(entry); 1458238825Smm if (nsec < a->newer_ctime_nsec) 1459238825Smm return (1); /* Too old, skip it. */ 1460238825Smm if (nsec == a->newer_ctime_nsec && 1461238825Smm (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL) 1462238825Smm == 0) 1463238825Smm return (1); /* Equal, skip it. */ 1464238825Smm } 1465238825Smm } 1466238825Smm if (a->older_ctime_filter) { 1467238825Smm /* If ctime is not set, use mtime instead. */ 1468238825Smm if (archive_entry_ctime_is_set(entry)) 1469238825Smm sec = archive_entry_ctime(entry); 1470238825Smm else 1471238825Smm sec = archive_entry_mtime(entry); 1472238825Smm if (sec > a->older_ctime_sec) 1473238825Smm return (1); /* Too new, skip it. */ 1474238825Smm if (sec == a->older_ctime_sec) { 1475238825Smm if (archive_entry_ctime_is_set(entry)) 1476238825Smm nsec = archive_entry_ctime_nsec(entry); 1477238825Smm else 1478238825Smm nsec = archive_entry_mtime_nsec(entry); 1479238825Smm if (nsec > a->older_ctime_nsec) 1480238825Smm return (1); /* Too new, skip it. */ 1481238825Smm if (nsec == a->older_ctime_nsec && 1482238825Smm (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) 1483238825Smm == 0) 1484238825Smm return (1); /* Eeual, skip it. */ 1485238825Smm } 1486238825Smm } 1487238825Smm if (a->newer_mtime_filter) { 1488238825Smm sec = archive_entry_mtime(entry); 1489238825Smm if (sec < a->newer_mtime_sec) 1490238825Smm return (1); /* Too old, skip it. */ 1491238825Smm if (sec == a->newer_mtime_sec) { 1492238825Smm nsec = archive_entry_mtime_nsec(entry); 1493238825Smm if (nsec < a->newer_mtime_nsec) 1494238825Smm return (1); /* Too old, skip it. */ 1495238825Smm if (nsec == a->newer_mtime_nsec && 1496238825Smm (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL) 1497238825Smm == 0) 1498238825Smm return (1); /* Equal, skip it. */ 1499238825Smm } 1500238825Smm } 1501238825Smm if (a->older_mtime_filter) { 1502238825Smm sec = archive_entry_mtime(entry); 1503238825Smm if (sec > a->older_mtime_sec) 1504238825Smm return (1); /* Too new, skip it. */ 1505238825Smm nsec = archive_entry_mtime_nsec(entry); 1506238825Smm if (sec == a->older_mtime_sec) { 1507238825Smm if (nsec > a->older_mtime_nsec) 1508238825Smm return (1); /* Too new, skip it. */ 1509238825Smm if (nsec == a->older_mtime_nsec && 1510238825Smm (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL) 1511238825Smm == 0) 1512238825Smm return (1); /* Equal, skip it. */ 1513238825Smm } 1514238825Smm } 1515238825Smm 1516238825Smm /* If there is no excluson list, include the file. */ 1517238825Smm if (a->exclusion_entry_list.count == 0) 1518238825Smm return (0); 1519238825Smm 1520238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1521238825Smm pathname = archive_entry_pathname_w(entry); 1522238825Smm a->exclusion_tree.rbt_ops = &rb_ops_wcs; 1523238825Smm#else 1524248616Smm (void)rb_ops_wcs; 1525238825Smm pathname = archive_entry_pathname(entry); 1526238825Smm a->exclusion_tree.rbt_ops = &rb_ops_mbs; 1527238825Smm#endif 1528238825Smm if (pathname == NULL) 1529238825Smm return (0); 1530238825Smm 1531238825Smm f = (struct match_file *)__archive_rb_tree_find_node( 1532238825Smm &(a->exclusion_tree), pathname); 1533238825Smm /* If the file wasn't rejected, include it. */ 1534238825Smm if (f == NULL) 1535238825Smm return (0); 1536238825Smm 1537238825Smm if (f->flag & ARCHIVE_MATCH_CTIME) { 1538238825Smm sec = archive_entry_ctime(entry); 1539238825Smm if (f->ctime_sec > sec) { 1540238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1541238825Smm return (1); 1542238825Smm } else if (f->ctime_sec < sec) { 1543238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1544238825Smm return (1); 1545238825Smm } else { 1546238825Smm nsec = archive_entry_ctime_nsec(entry); 1547238825Smm if (f->ctime_nsec > nsec) { 1548238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1549238825Smm return (1); 1550238825Smm } else if (f->ctime_nsec < nsec) { 1551238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1552238825Smm return (1); 1553238825Smm } else if (f->flag & ARCHIVE_MATCH_EQUAL) 1554238825Smm return (1); 1555238825Smm } 1556238825Smm } 1557238825Smm if (f->flag & ARCHIVE_MATCH_MTIME) { 1558238825Smm sec = archive_entry_mtime(entry); 1559238825Smm if (f->mtime_sec > sec) { 1560238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1561238825Smm return (1); 1562238825Smm } else if (f->mtime_sec < sec) { 1563238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1564238825Smm return (1); 1565238825Smm } else { 1566238825Smm nsec = archive_entry_mtime_nsec(entry); 1567238825Smm if (f->mtime_nsec > nsec) { 1568238825Smm if (f->flag & ARCHIVE_MATCH_OLDER) 1569238825Smm return (1); 1570238825Smm } else if (f->mtime_nsec < nsec) { 1571238825Smm if (f->flag & ARCHIVE_MATCH_NEWER) 1572238825Smm return (1); 1573238825Smm } else if (f->flag & ARCHIVE_MATCH_EQUAL) 1574238825Smm return (1); 1575238825Smm } 1576238825Smm } 1577238825Smm return (0); 1578238825Smm} 1579238825Smm 1580238825Smm/* 1581238825Smm * Utility functions to manage inclusion owners 1582238825Smm */ 1583238825Smm 1584238825Smmint 1585238825Smmarchive_match_include_uid(struct archive *_a, int64_t uid) 1586238825Smm{ 1587238825Smm struct archive_match *a; 1588238825Smm 1589238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1590238825Smm ARCHIVE_STATE_NEW, "archive_match_include_uid"); 1591238825Smm a = (struct archive_match *)_a; 1592238825Smm return (add_owner_id(a, &(a->inclusion_uids), uid)); 1593238825Smm} 1594238825Smm 1595238825Smmint 1596238825Smmarchive_match_include_gid(struct archive *_a, int64_t gid) 1597238825Smm{ 1598238825Smm struct archive_match *a; 1599238825Smm 1600238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1601238825Smm ARCHIVE_STATE_NEW, "archive_match_include_gid"); 1602238825Smm a = (struct archive_match *)_a; 1603238825Smm return (add_owner_id(a, &(a->inclusion_gids), gid)); 1604238825Smm} 1605238825Smm 1606238825Smmint 1607238825Smmarchive_match_include_uname(struct archive *_a, const char *uname) 1608238825Smm{ 1609238825Smm struct archive_match *a; 1610238825Smm 1611238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1612238825Smm ARCHIVE_STATE_NEW, "archive_match_include_uname"); 1613238825Smm a = (struct archive_match *)_a; 1614238825Smm return (add_owner_name(a, &(a->inclusion_unames), 1, uname)); 1615238825Smm} 1616238825Smm 1617238825Smmint 1618238825Smmarchive_match_include_uname_w(struct archive *_a, const wchar_t *uname) 1619238825Smm{ 1620238825Smm struct archive_match *a; 1621238825Smm 1622238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1623238825Smm ARCHIVE_STATE_NEW, "archive_match_include_uname_w"); 1624238825Smm a = (struct archive_match *)_a; 1625238825Smm return (add_owner_name(a, &(a->inclusion_unames), 0, uname)); 1626238825Smm} 1627238825Smm 1628238825Smmint 1629238825Smmarchive_match_include_gname(struct archive *_a, const char *gname) 1630238825Smm{ 1631238825Smm struct archive_match *a; 1632238825Smm 1633238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1634238825Smm ARCHIVE_STATE_NEW, "archive_match_include_gname"); 1635238825Smm a = (struct archive_match *)_a; 1636238825Smm return (add_owner_name(a, &(a->inclusion_gnames), 1, gname)); 1637238825Smm} 1638238825Smm 1639238825Smmint 1640238825Smmarchive_match_include_gname_w(struct archive *_a, const wchar_t *gname) 1641238825Smm{ 1642238825Smm struct archive_match *a; 1643238825Smm 1644238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1645238825Smm ARCHIVE_STATE_NEW, "archive_match_include_gname_w"); 1646238825Smm a = (struct archive_match *)_a; 1647238825Smm return (add_owner_name(a, &(a->inclusion_gnames), 0, gname)); 1648238825Smm} 1649238825Smm 1650238825Smm/* 1651238825Smm * Test function for owner(uid, gid, uname, gname). 1652238825Smm * 1653238825Smm * Returns 1 if archive entry is excluded. 1654238825Smm * Returns 0 if archive entry is not excluded. 1655238825Smm * Returns <0 if something error happened. 1656238825Smm */ 1657238825Smmint 1658238825Smmarchive_match_owner_excluded(struct archive *_a, 1659238825Smm struct archive_entry *entry) 1660238825Smm{ 1661238825Smm struct archive_match *a; 1662238825Smm 1663238825Smm archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1664238825Smm ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae"); 1665238825Smm 1666238825Smm a = (struct archive_match *)_a; 1667238825Smm if (entry == NULL) { 1668238825Smm archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 1669238825Smm return (ARCHIVE_FAILED); 1670238825Smm } 1671238825Smm 1672238825Smm /* If we don't have inclusion id set at all, the entry is always 1673238825Smm * not excluded. */ 1674238825Smm if ((a->setflag & ID_IS_SET) == 0) 1675238825Smm return (0); 1676238825Smm return (owner_excluded(a, entry)); 1677238825Smm} 1678238825Smm 1679238825Smmstatic int 1680238825Smmadd_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) 1681238825Smm{ 1682238825Smm unsigned i; 1683238825Smm 1684238825Smm if (ids->count + 1 >= ids->size) { 1685248616Smm void *p; 1686248616Smm 1687238825Smm if (ids->size == 0) 1688238825Smm ids->size = 8; 1689238825Smm else 1690238825Smm ids->size *= 2; 1691248616Smm p = realloc(ids->ids, sizeof(*ids->ids) * ids->size); 1692248616Smm if (p == NULL) 1693238825Smm return (error_nomem(a)); 1694248616Smm ids->ids = (int64_t *)p; 1695238825Smm } 1696238825Smm 1697238825Smm /* Find an insert point. */ 1698238825Smm for (i = 0; i < ids->count; i++) { 1699238825Smm if (ids->ids[i] >= id) 1700238825Smm break; 1701238825Smm } 1702238825Smm 1703238825Smm /* Add oowner id. */ 1704238825Smm if (i == ids->count) 1705238825Smm ids->ids[ids->count++] = id; 1706238825Smm else if (ids->ids[i] != id) { 1707238825Smm memmove(&(ids->ids[i+1]), &(ids->ids[i]), 1708238825Smm (ids->count - i) * sizeof(ids->ids[0])); 1709238825Smm ids->ids[i] = id; 1710238825Smm ids->count++; 1711238825Smm } 1712238825Smm a->setflag |= ID_IS_SET; 1713238825Smm return (ARCHIVE_OK); 1714238825Smm} 1715238825Smm 1716238825Smmstatic int 1717238825Smmmatch_owner_id(struct id_array *ids, int64_t id) 1718238825Smm{ 1719238825Smm unsigned b, m, t; 1720238825Smm 1721238825Smm t = 0; 1722248616Smm b = (unsigned)ids->count; 1723238825Smm while (t < b) { 1724238825Smm m = (t + b)>>1; 1725238825Smm if (ids->ids[m] == id) 1726238825Smm return (1); 1727238825Smm if (ids->ids[m] < id) 1728238825Smm t = m + 1; 1729238825Smm else 1730238825Smm b = m; 1731238825Smm } 1732238825Smm return (0); 1733238825Smm} 1734238825Smm 1735238825Smmstatic int 1736238825Smmadd_owner_name(struct archive_match *a, struct match_list *list, 1737238825Smm int mbs, const void *name) 1738238825Smm{ 1739238825Smm struct match *match; 1740238825Smm 1741238825Smm match = calloc(1, sizeof(*match)); 1742238825Smm if (match == NULL) 1743238825Smm return (error_nomem(a)); 1744238825Smm if (mbs) 1745238825Smm archive_mstring_copy_mbs(&(match->pattern), name); 1746238825Smm else 1747238825Smm archive_mstring_copy_wcs(&(match->pattern), name); 1748238825Smm match_list_add(list, match); 1749238825Smm a->setflag |= ID_IS_SET; 1750238825Smm return (ARCHIVE_OK); 1751238825Smm} 1752238825Smm 1753238825Smm#if !defined(_WIN32) || defined(__CYGWIN__) 1754238825Smmstatic int 1755238825Smmmatch_owner_name_mbs(struct archive_match *a, struct match_list *list, 1756238825Smm const char *name) 1757238825Smm{ 1758238825Smm struct match *m; 1759238825Smm const char *p; 1760238825Smm 1761238825Smm if (name == NULL || *name == '\0') 1762238825Smm return (0); 1763238825Smm for (m = list->first; m; m = m->next) { 1764238825Smm if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p) 1765238825Smm < 0 && errno == ENOMEM) 1766238825Smm return (error_nomem(a)); 1767238825Smm if (p != NULL && strcmp(p, name) == 0) { 1768238825Smm m->matches++; 1769238825Smm return (1); 1770238825Smm } 1771238825Smm } 1772238825Smm return (0); 1773238825Smm} 1774238825Smm#else 1775238825Smmstatic int 1776238825Smmmatch_owner_name_wcs(struct archive_match *a, struct match_list *list, 1777238825Smm const wchar_t *name) 1778238825Smm{ 1779238825Smm struct match *m; 1780238825Smm const wchar_t *p; 1781238825Smm 1782238825Smm if (name == NULL || *name == L'\0') 1783238825Smm return (0); 1784238825Smm for (m = list->first; m; m = m->next) { 1785238825Smm if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p) 1786238825Smm < 0 && errno == ENOMEM) 1787238825Smm return (error_nomem(a)); 1788238825Smm if (p != NULL && wcscmp(p, name) == 0) { 1789238825Smm m->matches++; 1790238825Smm return (1); 1791238825Smm } 1792238825Smm } 1793238825Smm return (0); 1794238825Smm} 1795238825Smm#endif 1796238825Smm 1797238825Smm/* 1798238825Smm * Test if entry is excluded by uid, gid, uname or gname. 1799238825Smm */ 1800238825Smmstatic int 1801238825Smmowner_excluded(struct archive_match *a, struct archive_entry *entry) 1802238825Smm{ 1803238825Smm int r; 1804238825Smm 1805238825Smm if (a->inclusion_uids.count) { 1806238825Smm if (!match_owner_id(&(a->inclusion_uids), 1807238825Smm archive_entry_uid(entry))) 1808238825Smm return (1); 1809238825Smm } 1810238825Smm 1811238825Smm if (a->inclusion_gids.count) { 1812238825Smm if (!match_owner_id(&(a->inclusion_gids), 1813238825Smm archive_entry_gid(entry))) 1814238825Smm return (1); 1815238825Smm } 1816238825Smm 1817238825Smm if (a->inclusion_unames.count) { 1818238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1819238825Smm r = match_owner_name_wcs(a, &(a->inclusion_unames), 1820238825Smm archive_entry_uname_w(entry)); 1821238825Smm#else 1822238825Smm r = match_owner_name_mbs(a, &(a->inclusion_unames), 1823238825Smm archive_entry_uname(entry)); 1824238825Smm#endif 1825238825Smm if (!r) 1826238825Smm return (1); 1827238825Smm else if (r < 0) 1828238825Smm return (r); 1829238825Smm } 1830238825Smm 1831238825Smm if (a->inclusion_gnames.count) { 1832238825Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1833238825Smm r = match_owner_name_wcs(a, &(a->inclusion_gnames), 1834238825Smm archive_entry_gname_w(entry)); 1835238825Smm#else 1836238825Smm r = match_owner_name_mbs(a, &(a->inclusion_gnames), 1837238825Smm archive_entry_gname(entry)); 1838238825Smm#endif 1839238825Smm if (!r) 1840238825Smm return (1); 1841238825Smm else if (r < 0) 1842238825Smm return (r); 1843238825Smm } 1844238825Smm return (0); 1845238825Smm} 1846238825Smm 1847