archive_match.c revision 348608
1129198Scognet/*- 2129198Scognet * Copyright (c) 2003-2007 Tim Kientzle 3139735Simp * Copyright (c) 2012 Michihiro NAKAJIMA 4129198Scognet * All rights reserved. 5129198Scognet * 6129198Scognet * Redistribution and use in source and binary forms, with or without 7129198Scognet * modification, are permitted provided that the following conditions 8129198Scognet * are met: 9129198Scognet * 1. Redistributions of source code must retain the above copyright 10129198Scognet * notice, this list of conditions and the following disclaimer. 11129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 12129198Scognet * notice, this list of conditions and the following disclaimer in the 13129198Scognet * documentation and/or other materials provided with the distribution. 14129198Scognet * 15129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18129198Scognet * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19129198Scognet * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20129198Scognet * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21129198Scognet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22129198Scognet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23129198Scognet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24129198Scognet * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25129198Scognet */ 26129198Scognet 27129198Scognet#include "archive_platform.h" 28129198Scognet__FBSDID("$FreeBSD$"); 29129198Scognet 30129198Scognet#ifdef HAVE_ERRNO_H 31129198Scognet#include <errno.h> 32129198Scognet#endif 33129198Scognet#ifdef HAVE_STDLIB_H 34129198Scognet#include <stdlib.h> 35129198Scognet#endif 36129198Scognet#ifdef HAVE_STRING_H 37129198Scognet#include <string.h> 38129198Scognet#endif 39129198Scognet 40129198Scognet#include "archive.h" 41129198Scognet#include "archive_private.h" 42129198Scognet#include "archive_entry.h" 43129198Scognet#include "archive_getdate.h" 44129198Scognet#include "archive_pathmatch.h" 45129198Scognet#include "archive_rb.h" 46129198Scognet#include "archive_string.h" 47129198Scognet 48129198Scognetstruct match { 49129198Scognet struct match *next; 50129198Scognet int matches; 51129198Scognet struct archive_mstring pattern; 52129198Scognet}; 53129198Scognet 54129198Scognetstruct match_list { 55129198Scognet struct match *first; 56129198Scognet struct match **last; 57129198Scognet int count; 58273827Sandrew int unmatched_count; 59129198Scognet struct match *unmatched_next; 60129198Scognet int unmatched_eof; 61129198Scognet}; 62129198Scognet 63129198Scognetstruct match_file { 64129198Scognet struct archive_rb_node node; 65129198Scognet struct match_file *next; 66129198Scognet struct archive_mstring pathname; 67129198Scognet int flag; 68129198Scognet time_t mtime_sec; 69129198Scognet long mtime_nsec; 70129198Scognet time_t ctime_sec; 71129198Scognet long ctime_nsec; 72129198Scognet}; 73129198Scognet 74129198Scognetstruct entry_list { 75129198Scognet struct match_file *first; 76129198Scognet struct match_file **last; 77129198Scognet int count; 78129198Scognet}; 79129198Scognet 80129198Scognetstruct id_array { 81129198Scognet size_t size;/* Allocated size */ 82129198Scognet size_t count; 83129198Scognet int64_t *ids; 84129198Scognet}; 85129198Scognet 86129198Scognet#define PATTERN_IS_SET 1 87129198Scognet#define TIME_IS_SET 2 88129198Scognet#define ID_IS_SET 4 89129198Scognet 90129198Scognetstruct archive_match { 91129198Scognet struct archive archive; 92129198Scognet 93129198Scognet /* exclusion/inclusion set flag. */ 94129198Scognet int setflag; 95129198Scognet 96129198Scognet /* Recursively include directory content? */ 97129198Scognet int recursive_include; 98129198Scognet 99129198Scognet /* 100129198Scognet * Matching filename patterns. 101129198Scognet */ 102129198Scognet struct match_list exclusions; 103129198Scognet struct match_list inclusions; 104129198Scognet 105129198Scognet /* 106129198Scognet * Matching time stamps. 107129198Scognet */ 108129198Scognet time_t now; 109129198Scognet int newer_mtime_filter; 110129198Scognet time_t newer_mtime_sec; 111129198Scognet long newer_mtime_nsec; 112129198Scognet int newer_ctime_filter; 113129198Scognet time_t newer_ctime_sec; 114129198Scognet long newer_ctime_nsec; 115129198Scognet int older_mtime_filter; 116129198Scognet time_t older_mtime_sec; 117129198Scognet long older_mtime_nsec; 118129198Scognet int older_ctime_filter; 119129198Scognet time_t older_ctime_sec; 120129198Scognet long older_ctime_nsec; 121129198Scognet /* 122129198Scognet * Matching time stamps with its filename. 123129198Scognet */ 124129198Scognet struct archive_rb_tree exclusion_tree; 125129198Scognet struct entry_list exclusion_entry_list; 126129198Scognet 127129198Scognet /* 128129198Scognet * Matching file owners. 129129198Scognet */ 130129198Scognet struct id_array inclusion_uids; 131129198Scognet struct id_array inclusion_gids; 132129198Scognet struct match_list inclusion_unames; 133129198Scognet struct match_list inclusion_gnames; 134273827Sandrew}; 135239687Sgonzo 136239687Sgonzostatic int add_pattern_from_file(struct archive_match *, 137239687Sgonzo struct match_list *, int, const void *, int); 138239687Sgonzostatic int add_entry(struct archive_match *, int, 139239687Sgonzo struct archive_entry *); 140239687Sgonzostatic int add_owner_id(struct archive_match *, struct id_array *, 141239687Sgonzo int64_t); 142239687Sgonzostatic int add_owner_name(struct archive_match *, struct match_list *, 143239687Sgonzo int, const void *); 144239687Sgonzostatic int add_pattern_mbs(struct archive_match *, struct match_list *, 145129198Scognet const char *); 146236991Simpstatic int add_pattern_wcs(struct archive_match *, struct match_list *, 147129198Scognet const wchar_t *); 148236991Simpstatic int cmp_key_mbs(const struct archive_rb_node *, const void *); 149129198Scognetstatic int cmp_key_wcs(const struct archive_rb_node *, const void *); 150129198Scognetstatic int cmp_node_mbs(const struct archive_rb_node *, 151129198Scognet const struct archive_rb_node *); 152129198Scognetstatic int cmp_node_wcs(const struct archive_rb_node *, 153129198Scognet const struct archive_rb_node *); 154129198Scognetstatic void entry_list_add(struct entry_list *, struct match_file *); 155129198Scognetstatic void entry_list_free(struct entry_list *); 156129198Scognetstatic void entry_list_init(struct entry_list *); 157129198Scognetstatic int error_nomem(struct archive_match *); 158129198Scognetstatic void match_list_add(struct match_list *, struct match *); 159129198Scognetstatic void match_list_free(struct match_list *); 160129198Scognetstatic void match_list_init(struct match_list *); 161129198Scognetstatic int match_list_unmatched_inclusions_next(struct archive_match *, 162129198Scognet struct match_list *, int, const void **); 163129198Scognetstatic int match_owner_id(struct id_array *, int64_t); 164129198Scognet#if !defined(_WIN32) || defined(__CYGWIN__) 165129198Scognetstatic int match_owner_name_mbs(struct archive_match *, 166129198Scognet struct match_list *, const char *); 167129198Scognet#else 168129198Scognetstatic int match_owner_name_wcs(struct archive_match *, 169129198Scognet struct match_list *, const wchar_t *); 170129198Scognet#endif 171129198Scognetstatic int match_path_exclusion(struct archive_match *, 172129198Scognet struct match *, int, const void *); 173129198Scognetstatic int match_path_inclusion(struct archive_match *, 174129198Scognet struct match *, int, const void *); 175129198Scognetstatic int owner_excluded(struct archive_match *, 176129198Scognet struct archive_entry *); 177129198Scognetstatic int path_excluded(struct archive_match *, int, const void *); 178129198Scognetstatic int set_timefilter(struct archive_match *, int, time_t, long, 179129198Scognet time_t, long); 180129198Scognetstatic int set_timefilter_pathname_mbs(struct archive_match *, 181129198Scognet int, const char *); 182129198Scognetstatic int set_timefilter_pathname_wcs(struct archive_match *, 183129198Scognet int, const wchar_t *); 184129198Scognetstatic int set_timefilter_date(struct archive_match *, int, const char *); 185129198Scognetstatic int set_timefilter_date_w(struct archive_match *, int, 186129198Scognet const wchar_t *); 187129198Scognetstatic int time_excluded(struct archive_match *, 188129198Scognet struct archive_entry *); 189129198Scognetstatic int validate_time_flag(struct archive *, int, const char *); 190129198Scognet 191129198Scognet#define get_date __archive_get_date 192129198Scognet 193129198Scognetstatic const struct archive_rb_tree_ops rb_ops_mbs = { 194129198Scognet cmp_node_mbs, cmp_key_mbs 195129198Scognet}; 196129198Scognet 197129198Scognetstatic const struct archive_rb_tree_ops rb_ops_wcs = { 198129198Scognet cmp_node_wcs, cmp_key_wcs 199129198Scognet}; 200129198Scognet 201129198Scognet/* 202129198Scognet * The matching logic here needs to be re-thought. I started out to 203129198Scognet * try to mimic gtar's matching logic, but it's not entirely 204129198Scognet * consistent. In particular 'tar -t' and 'tar -x' interpret patterns 205129198Scognet * on the command line as anchored, but --exclude doesn't. 206129198Scognet */ 207129198Scognet 208129198Scognetstatic int 209129198Scogneterror_nomem(struct archive_match *a) 210129198Scognet{ 211129198Scognet archive_set_error(&(a->archive), ENOMEM, "No memory"); 212129198Scognet a->archive.state = ARCHIVE_STATE_FATAL; 213129198Scognet return (ARCHIVE_FATAL); 214129198Scognet} 215129198Scognet 216129198Scognet/* 217129198Scognet * Create an ARCHIVE_MATCH object. 218129198Scognet */ 219129198Scognetstruct archive * 220129198Scognetarchive_match_new(void) 221129198Scognet{ 222129198Scognet struct archive_match *a; 223129198Scognet 224129198Scognet a = (struct archive_match *)calloc(1, sizeof(*a)); 225129198Scognet if (a == NULL) 226129198Scognet return (NULL); 227129198Scognet a->archive.magic = ARCHIVE_MATCH_MAGIC; 228129198Scognet a->archive.state = ARCHIVE_STATE_NEW; 229129198Scognet a->recursive_include = 1; 230129198Scognet match_list_init(&(a->inclusions)); 231129198Scognet match_list_init(&(a->exclusions)); 232129198Scognet __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); 233129198Scognet entry_list_init(&(a->exclusion_entry_list)); 234129198Scognet match_list_init(&(a->inclusion_unames)); 235129198Scognet match_list_init(&(a->inclusion_gnames)); 236129198Scognet time(&a->now); 237129198Scognet return (&(a->archive)); 238129198Scognet} 239129198Scognet 240129198Scognet/* 241129198Scognet * Free an ARCHIVE_MATCH object. 242129198Scognet */ 243129198Scognetint 244129198Scognetarchive_match_free(struct archive *_a) 245129198Scognet{ 246129198Scognet struct archive_match *a; 247129198Scognet 248129198Scognet if (_a == NULL) 249129198Scognet return (ARCHIVE_OK); 250129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 251129198Scognet ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free"); 252129198Scognet a = (struct archive_match *)_a; 253129198Scognet match_list_free(&(a->inclusions)); 254129198Scognet match_list_free(&(a->exclusions)); 255129198Scognet entry_list_free(&(a->exclusion_entry_list)); 256129198Scognet free(a->inclusion_uids.ids); 257129198Scognet free(a->inclusion_gids.ids); 258129198Scognet match_list_free(&(a->inclusion_unames)); 259129198Scognet match_list_free(&(a->inclusion_gnames)); 260129198Scognet free(a); 261129198Scognet return (ARCHIVE_OK); 262129198Scognet} 263129198Scognet 264129198Scognet/* 265129198Scognet * Convenience function to perform all exclusion tests. 266129198Scognet * 267129198Scognet * Returns 1 if archive entry is excluded. 268129198Scognet * Returns 0 if archive entry is not excluded. 269129198Scognet * Returns <0 if something error happened. 270129198Scognet */ 271129198Scognetint 272129198Scognetarchive_match_excluded(struct archive *_a, struct archive_entry *entry) 273129198Scognet{ 274129198Scognet struct archive_match *a; 275129198Scognet int r; 276129198Scognet 277129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 278129198Scognet ARCHIVE_STATE_NEW, "archive_match_excluded_ae"); 279129198Scognet 280129198Scognet a = (struct archive_match *)_a; 281129198Scognet if (entry == NULL) { 282129198Scognet archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 283129198Scognet return (ARCHIVE_FAILED); 284129198Scognet } 285129198Scognet 286129198Scognet r = 0; 287129198Scognet if (a->setflag & PATTERN_IS_SET) { 288129198Scognet#if defined(_WIN32) && !defined(__CYGWIN__) 289129198Scognet r = path_excluded(a, 0, archive_entry_pathname_w(entry)); 290129198Scognet#else 291129198Scognet r = path_excluded(a, 1, archive_entry_pathname(entry)); 292279467Sdim#endif 293129198Scognet if (r != 0) 294129198Scognet return (r); 295129198Scognet } 296129198Scognet 297129198Scognet if (a->setflag & TIME_IS_SET) { 298129198Scognet r = time_excluded(a, entry); 299129198Scognet if (r != 0) 300129198Scognet return (r); 301129198Scognet } 302129198Scognet 303129198Scognet if (a->setflag & ID_IS_SET) 304129198Scognet r = owner_excluded(a, entry); 305129198Scognet return (r); 306129198Scognet} 307129198Scognet 308129198Scognet/* 309129198Scognet * Utility functions to manage exclusion/inclusion patterns 310129198Scognet */ 311129198Scognet 312129198Scognetint 313129198Scognetarchive_match_exclude_pattern(struct archive *_a, const char *pattern) 314129198Scognet{ 315129198Scognet struct archive_match *a; 316129198Scognet int r; 317129198Scognet 318129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 319129198Scognet ARCHIVE_STATE_NEW, "archive_match_exclude_pattern"); 320129198Scognet a = (struct archive_match *)_a; 321129198Scognet 322129198Scognet if (pattern == NULL || *pattern == '\0') { 323129198Scognet archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 324129198Scognet return (ARCHIVE_FAILED); 325129198Scognet } 326129198Scognet if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) 327129198Scognet return (r); 328129198Scognet return (ARCHIVE_OK); 329129198Scognet} 330129198Scognet 331129198Scognetint 332129198Scognetarchive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern) 333129198Scognet{ 334129198Scognet struct archive_match *a; 335129198Scognet int r; 336129198Scognet 337129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 338129198Scognet ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w"); 339129198Scognet a = (struct archive_match *)_a; 340129198Scognet 341129198Scognet if (pattern == NULL || *pattern == L'\0') { 342129198Scognet archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 343129198Scognet return (ARCHIVE_FAILED); 344236991Simp } 345129198Scognet if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) 346129198Scognet return (r); 347129198Scognet return (ARCHIVE_OK); 348129198Scognet} 349129198Scognet 350129198Scognetint 351129198Scognetarchive_match_exclude_pattern_from_file(struct archive *_a, 352129198Scognet const char *pathname, int nullSeparator) 353129198Scognet{ 354129198Scognet struct archive_match *a; 355129198Scognet 356129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 357129198Scognet ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file"); 358129198Scognet a = (struct archive_match *)_a; 359129198Scognet 360129198Scognet return add_pattern_from_file(a, &(a->exclusions), 1, pathname, 361129198Scognet nullSeparator); 362129198Scognet} 363129198Scognet 364129198Scognetint 365129198Scognetarchive_match_exclude_pattern_from_file_w(struct archive *_a, 366129198Scognet const wchar_t *pathname, int nullSeparator) 367129198Scognet{ 368129198Scognet struct archive_match *a; 369129198Scognet 370129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 371129198Scognet ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w"); 372129198Scognet a = (struct archive_match *)_a; 373129198Scognet 374129198Scognet return add_pattern_from_file(a, &(a->exclusions), 0, pathname, 375129198Scognet nullSeparator); 376129198Scognet} 377129198Scognet 378129198Scognetint 379129198Scognetarchive_match_include_pattern(struct archive *_a, const char *pattern) 380129198Scognet{ 381129198Scognet struct archive_match *a; 382129198Scognet int r; 383129198Scognet 384129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 385129198Scognet ARCHIVE_STATE_NEW, "archive_match_include_pattern"); 386129198Scognet a = (struct archive_match *)_a; 387129198Scognet 388129198Scognet if (pattern == NULL || *pattern == '\0') { 389129198Scognet archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 390129198Scognet return (ARCHIVE_FAILED); 391129198Scognet } 392129198Scognet if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) 393129198Scognet return (r); 394129198Scognet return (ARCHIVE_OK); 395129198Scognet} 396129198Scognet 397129198Scognetint 398129198Scognetarchive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern) 399129198Scognet{ 400129198Scognet struct archive_match *a; 401129198Scognet int r; 402129198Scognet 403129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 404129198Scognet ARCHIVE_STATE_NEW, "archive_match_include_pattern_w"); 405129198Scognet a = (struct archive_match *)_a; 406129198Scognet 407129198Scognet if (pattern == NULL || *pattern == L'\0') { 408129198Scognet archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 409129198Scognet return (ARCHIVE_FAILED); 410129198Scognet } 411129198Scognet if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) 412129198Scognet return (r); 413129198Scognet return (ARCHIVE_OK); 414129198Scognet} 415129198Scognet 416129198Scognetint 417129198Scognetarchive_match_include_pattern_from_file(struct archive *_a, 418129198Scognet const char *pathname, int nullSeparator) 419129198Scognet{ 420129198Scognet struct archive_match *a; 421129198Scognet 422129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 423129198Scognet ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file"); 424129198Scognet a = (struct archive_match *)_a; 425129198Scognet 426129198Scognet return add_pattern_from_file(a, &(a->inclusions), 1, pathname, 427129198Scognet nullSeparator); 428129198Scognet} 429129198Scognet 430129198Scognetint 431129198Scognetarchive_match_include_pattern_from_file_w(struct archive *_a, 432129198Scognet const wchar_t *pathname, int nullSeparator) 433129198Scognet{ 434129198Scognet struct archive_match *a; 435129198Scognet 436129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 437129198Scognet ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w"); 438129198Scognet a = (struct archive_match *)_a; 439129198Scognet 440129198Scognet return add_pattern_from_file(a, &(a->inclusions), 0, pathname, 441129198Scognet nullSeparator); 442129198Scognet} 443129198Scognet 444129198Scognet/* 445129198Scognet * Test functions for pathname patterns. 446129198Scognet * 447129198Scognet * Returns 1 if archive entry is excluded. 448129198Scognet * Returns 0 if archive entry is not excluded. 449129198Scognet * Returns <0 if something error happened. 450129198Scognet */ 451129198Scognetint 452129198Scognetarchive_match_path_excluded(struct archive *_a, 453129198Scognet struct archive_entry *entry) 454129198Scognet{ 455129198Scognet struct archive_match *a; 456129198Scognet 457129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 458129198Scognet ARCHIVE_STATE_NEW, "archive_match_path_excluded"); 459129198Scognet 460129198Scognet a = (struct archive_match *)_a; 461129198Scognet if (entry == NULL) { 462129198Scognet archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 463129198Scognet return (ARCHIVE_FAILED); 464129198Scognet } 465129198Scognet 466129198Scognet /* If we don't have exclusion/inclusion pattern set at all, 467129198Scognet * the entry is always not excluded. */ 468129198Scognet if ((a->setflag & PATTERN_IS_SET) == 0) 469129198Scognet return (0); 470129198Scognet#if defined(_WIN32) && !defined(__CYGWIN__) 471129198Scognet return (path_excluded(a, 0, archive_entry_pathname_w(entry))); 472129198Scognet#else 473129198Scognet return (path_excluded(a, 1, archive_entry_pathname(entry))); 474129198Scognet#endif 475129198Scognet} 476129198Scognet 477129198Scognet/* 478129198Scognet * When recursive inclusion of directory content is enabled, 479129198Scognet * an inclusion pattern that matches a directory will also 480129198Scognet * include everything beneath that directory. Enabled by default. 481129198Scognet * 482129198Scognet * For compatibility with GNU tar, exclusion patterns always 483129198Scognet * match if a subset of the full patch matches (i.e., they are 484129198Scognet * are not rooted at the beginning of the path) and thus there 485129198Scognet * is no corresponding non-recursive exclusion mode. 486129198Scognet */ 487129198Scognetint 488129198Scognetarchive_match_set_inclusion_recursion(struct archive *_a, int enabled) 489129198Scognet{ 490129198Scognet struct archive_match *a; 491129198Scognet 492129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 493129198Scognet ARCHIVE_STATE_NEW, "archive_match_set_inclusion_recursion"); 494129198Scognet a = (struct archive_match *)_a; 495129198Scognet a->recursive_include = enabled; 496129198Scognet return (ARCHIVE_OK); 497129198Scognet} 498129198Scognet 499129198Scognet/* 500129198Scognet * Utility functions to get statistic information for inclusion patterns. 501129198Scognet */ 502129198Scognetint 503129198Scognetarchive_match_path_unmatched_inclusions(struct archive *_a) 504129198Scognet{ 505129198Scognet struct archive_match *a; 506129198Scognet 507129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 508129198Scognet ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions"); 509129198Scognet a = (struct archive_match *)_a; 510129198Scognet 511129198Scognet return (a->inclusions.unmatched_count); 512129198Scognet} 513129198Scognet 514129198Scognetint 515129198Scognetarchive_match_path_unmatched_inclusions_next(struct archive *_a, 516129198Scognet const char **_p) 517129198Scognet{ 518129198Scognet struct archive_match *a; 519129198Scognet const void *v; 520129198Scognet int r; 521129198Scognet 522129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 523129198Scognet ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next"); 524129198Scognet a = (struct archive_match *)_a; 525129198Scognet 526129198Scognet r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v); 527129198Scognet *_p = (const char *)v; 528129198Scognet return (r); 529129198Scognet} 530129198Scognet 531129198Scognetint 532129198Scognetarchive_match_path_unmatched_inclusions_next_w(struct archive *_a, 533129198Scognet const wchar_t **_p) 534129198Scognet{ 535129198Scognet struct archive_match *a; 536129198Scognet const void *v; 537129198Scognet int r; 538129198Scognet 539129198Scognet archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 540129198Scognet ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w"); 541129198Scognet a = (struct archive_match *)_a; 542129198Scognet 543129198Scognet r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v); 544129198Scognet *_p = (const wchar_t *)v; 545129198Scognet return (r); 546129198Scognet} 547129198Scognet 548129198Scognet/* 549129198Scognet * Add inclusion/exclusion patterns. 550129198Scognet */ 551129198Scognetstatic int 552129198Scognetadd_pattern_mbs(struct archive_match *a, struct match_list *list, 553129198Scognet const char *pattern) 554129198Scognet{ 555129198Scognet struct match *match; 556129198Scognet size_t len; 557129198Scognet 558129198Scognet match = calloc(1, sizeof(*match)); 559129198Scognet if (match == NULL) 560129198Scognet return (error_nomem(a)); 561129198Scognet /* Both "foo/" and "foo" should match "foo/bar". */ 562129198Scognet len = strlen(pattern); 563129198Scognet if (len && pattern[len - 1] == '/') 564129198Scognet --len; 565129198Scognet archive_mstring_copy_mbs_len(&(match->pattern), pattern, len); 566129198Scognet match_list_add(list, match); 567129198Scognet a->setflag |= PATTERN_IS_SET; 568129198Scognet return (ARCHIVE_OK); 569129198Scognet} 570129198Scognet 571129198Scognetstatic int 572129198Scognetadd_pattern_wcs(struct archive_match *a, struct match_list *list, 573129198Scognet const wchar_t *pattern) 574129198Scognet{ 575129198Scognet struct match *match; 576129198Scognet size_t len; 577129198Scognet 578129198Scognet match = calloc(1, sizeof(*match)); 579129198Scognet if (match == NULL) 580129198Scognet return (error_nomem(a)); 581129198Scognet /* Both "foo/" and "foo" should match "foo/bar". */ 582129198Scognet len = wcslen(pattern); 583129198Scognet if (len && pattern[len - 1] == L'/') 584129198Scognet --len; 585129198Scognet archive_mstring_copy_wcs_len(&(match->pattern), pattern, len); 586129198Scognet match_list_add(list, match); 587129198Scognet a->setflag |= PATTERN_IS_SET; 588129198Scognet return (ARCHIVE_OK); 589129198Scognet} 590129198Scognet 591129198Scognetstatic int 592129198Scognetadd_pattern_from_file(struct archive_match *a, struct match_list *mlist, 593129198Scognet int mbs, const void *pathname, int nullSeparator) 594129198Scognet{ 595129198Scognet struct archive *ar; 596129198Scognet struct archive_entry *ae; 597129198Scognet struct archive_string as; 598129198Scognet const void *buff; 599129198Scognet size_t size; 600129198Scognet int64_t offset; 601129198Scognet int r; 602129198Scognet 603129198Scognet ar = archive_read_new(); 604129198Scognet if (ar == NULL) { 605129198Scognet archive_set_error(&(a->archive), ENOMEM, "No memory"); 606129198Scognet return (ARCHIVE_FATAL); 607129198Scognet } 608129198Scognet r = archive_read_support_format_raw(ar); 609129198Scognet r = archive_read_support_format_empty(ar); 610129198Scognet if (r != ARCHIVE_OK) { 611129198Scognet archive_copy_error(&(a->archive), ar); 612129198Scognet archive_read_free(ar); 613129198Scognet return (r); 614129198Scognet } 615129198Scognet if (mbs) 616129198Scognet r = archive_read_open_filename(ar, pathname, 512*20); 617129198Scognet else 618129198Scognet r = archive_read_open_filename_w(ar, pathname, 512*20); 619129198Scognet if (r != ARCHIVE_OK) { 620129198Scognet archive_copy_error(&(a->archive), ar); 621129198Scognet archive_read_free(ar); 622129198Scognet return (r); 623129198Scognet } 624129198Scognet r = archive_read_next_header(ar, &ae); 625129198Scognet if (r != ARCHIVE_OK) { 626129198Scognet archive_read_free(ar); 627129198Scognet if (r == ARCHIVE_EOF) { 628129198Scognet return (ARCHIVE_OK); 629129198Scognet } else { 630129198Scognet archive_copy_error(&(a->archive), ar); 631129198Scognet return (r); 632129198Scognet } 633129198Scognet } 634129198Scognet 635129198Scognet archive_string_init(&as); 636129198Scognet 637129198Scognet while ((r = archive_read_data_block(ar, &buff, &size, &offset)) 638129198Scognet == ARCHIVE_OK) { 639129198Scognet const char *b = (const char *)buff; 640129198Scognet 641129198Scognet while (size) { 642129198Scognet const char *s = (const char *)b; 643129198Scognet size_t length = 0; 644129198Scognet int found_separator = 0; 645129198Scognet 646129198Scognet while (length < size) { 647129198Scognet if (nullSeparator) { 648129198Scognet if (*b == '\0') { 649129198Scognet found_separator = 1; 650129198Scognet break; 651129198Scognet } 652129198Scognet } else { 653129198Scognet if (*b == 0x0d || *b == 0x0a) { 654129198Scognet found_separator = 1; 655129198Scognet break; 656129198Scognet } 657129198Scognet } 658129198Scognet b++; 659129198Scognet length++; 660129198Scognet } 661129198Scognet if (!found_separator) { 662129198Scognet archive_strncat(&as, s, length); 663129198Scognet /* Read next data block. */ 664129198Scognet break; 665129198Scognet } 666129198Scognet b++; 667129198Scognet size -= length + 1; 668129198Scognet archive_strncat(&as, s, length); 669129198Scognet 670129198Scognet /* If the line is not empty, add the pattern. */ 671129198Scognet if (archive_strlen(&as) > 0) { 672129198Scognet /* Add pattern. */ 673129198Scognet r = add_pattern_mbs(a, mlist, as.s); 674129198Scognet if (r != ARCHIVE_OK) { 675129198Scognet archive_read_free(ar); 676129198Scognet archive_string_free(&as); 677129198Scognet return (r); 678129198Scognet } 679129198Scognet archive_string_empty(&as); 680129198Scognet } 681129198Scognet } 682129198Scognet } 683129198Scognet 684129198Scognet /* If an error occurred, report it immediately. */ 685129198Scognet if (r < ARCHIVE_OK) { 686129198Scognet archive_copy_error(&(a->archive), ar); 687129198Scognet archive_read_free(ar); 688129198Scognet archive_string_free(&as); 689129198Scognet return (r); 690129198Scognet } 691129198Scognet 692129198Scognet /* If the line is not empty, add the pattern. */ 693129198Scognet if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { 694 /* Add pattern. */ 695 r = add_pattern_mbs(a, mlist, as.s); 696 if (r != ARCHIVE_OK) { 697 archive_read_free(ar); 698 archive_string_free(&as); 699 return (r); 700 } 701 } 702 archive_read_free(ar); 703 archive_string_free(&as); 704 return (ARCHIVE_OK); 705} 706 707/* 708 * Test if pathname is excluded by inclusion/exclusion patterns. 709 */ 710static int 711path_excluded(struct archive_match *a, int mbs, const void *pathname) 712{ 713 struct match *match; 714 struct match *matched; 715 int r; 716 717 if (a == NULL) 718 return (0); 719 720 /* Mark off any unmatched inclusions. */ 721 /* In particular, if a filename does appear in the archive and 722 * is explicitly included and excluded, then we don't report 723 * it as missing even though we don't extract it. 724 */ 725 matched = NULL; 726 for (match = a->inclusions.first; match != NULL; 727 match = match->next){ 728 if (match->matches == 0 && 729 (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 730 if (r < 0) 731 return (r); 732 a->inclusions.unmatched_count--; 733 match->matches++; 734 matched = match; 735 } 736 } 737 738 /* Exclusions take priority */ 739 for (match = a->exclusions.first; match != NULL; 740 match = match->next){ 741 r = match_path_exclusion(a, match, mbs, pathname); 742 if (r) 743 return (r); 744 } 745 746 /* It's not excluded and we found an inclusion above, so it's 747 * included. */ 748 if (matched != NULL) 749 return (0); 750 751 752 /* We didn't find an unmatched inclusion, check the remaining ones. */ 753 for (match = a->inclusions.first; match != NULL; 754 match = match->next){ 755 /* We looked at previously-unmatched inclusions already. */ 756 if (match->matches > 0 && 757 (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 758 if (r < 0) 759 return (r); 760 match->matches++; 761 return (0); 762 } 763 } 764 765 /* If there were inclusions, default is to exclude. */ 766 if (a->inclusions.first != NULL) 767 return (1); 768 769 /* No explicit inclusions, default is to match. */ 770 return (0); 771} 772 773/* 774 * This is a little odd, but it matches the default behavior of 775 * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' 776 * 777 */ 778static int 779match_path_exclusion(struct archive_match *a, struct match *m, 780 int mbs, const void *pn) 781{ 782 int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END; 783 int r; 784 785 if (mbs) { 786 const char *p; 787 r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 788 if (r == 0) 789 return (archive_pathmatch(p, (const char *)pn, flag)); 790 } else { 791 const wchar_t *p; 792 r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 793 if (r == 0) 794 return (archive_pathmatch_w(p, (const wchar_t *)pn, 795 flag)); 796 } 797 if (errno == ENOMEM) 798 return (error_nomem(a)); 799 return (0); 800} 801 802/* 803 * Again, mimic gtar: inclusions are always anchored (have to match 804 * the beginning of the path) even though exclusions are not anchored. 805 */ 806static int 807match_path_inclusion(struct archive_match *a, struct match *m, 808 int mbs, const void *pn) 809{ 810 /* Recursive operation requires only a prefix match. */ 811 int flag = a->recursive_include ? 812 PATHMATCH_NO_ANCHOR_END : 813 0; 814 int r; 815 816 if (mbs) { 817 const char *p; 818 r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 819 if (r == 0) 820 return (archive_pathmatch(p, (const char *)pn, flag)); 821 } else { 822 const wchar_t *p; 823 r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 824 if (r == 0) 825 return (archive_pathmatch_w(p, (const wchar_t *)pn, 826 flag)); 827 } 828 if (errno == ENOMEM) 829 return (error_nomem(a)); 830 return (0); 831} 832 833static void 834match_list_init(struct match_list *list) 835{ 836 list->first = NULL; 837 list->last = &(list->first); 838 list->count = 0; 839} 840 841static void 842match_list_free(struct match_list *list) 843{ 844 struct match *p, *q; 845 846 for (p = list->first; p != NULL; ) { 847 q = p; 848 p = p->next; 849 archive_mstring_clean(&(q->pattern)); 850 free(q); 851 } 852} 853 854static void 855match_list_add(struct match_list *list, struct match *m) 856{ 857 *list->last = m; 858 list->last = &(m->next); 859 list->count++; 860 list->unmatched_count++; 861} 862 863static int 864match_list_unmatched_inclusions_next(struct archive_match *a, 865 struct match_list *list, int mbs, const void **vp) 866{ 867 struct match *m; 868 869 *vp = NULL; 870 if (list->unmatched_eof) { 871 list->unmatched_eof = 0; 872 return (ARCHIVE_EOF); 873 } 874 if (list->unmatched_next == NULL) { 875 if (list->unmatched_count == 0) 876 return (ARCHIVE_EOF); 877 list->unmatched_next = list->first; 878 } 879 880 for (m = list->unmatched_next; m != NULL; m = m->next) { 881 int r; 882 883 if (m->matches) 884 continue; 885 if (mbs) { 886 const char *p; 887 r = archive_mstring_get_mbs(&(a->archive), 888 &(m->pattern), &p); 889 if (r < 0 && errno == ENOMEM) 890 return (error_nomem(a)); 891 if (p == NULL) 892 p = ""; 893 *vp = p; 894 } else { 895 const wchar_t *p; 896 r = archive_mstring_get_wcs(&(a->archive), 897 &(m->pattern), &p); 898 if (r < 0 && errno == ENOMEM) 899 return (error_nomem(a)); 900 if (p == NULL) 901 p = L""; 902 *vp = p; 903 } 904 list->unmatched_next = m->next; 905 if (list->unmatched_next == NULL) 906 /* To return EOF next time. */ 907 list->unmatched_eof = 1; 908 return (ARCHIVE_OK); 909 } 910 list->unmatched_next = NULL; 911 return (ARCHIVE_EOF); 912} 913 914/* 915 * Utility functions to manage inclusion timestamps. 916 */ 917int 918archive_match_include_time(struct archive *_a, int flag, time_t sec, 919 long nsec) 920{ 921 int r; 922 923 r = validate_time_flag(_a, flag, "archive_match_include_time"); 924 if (r != ARCHIVE_OK) 925 return (r); 926 return set_timefilter((struct archive_match *)_a, flag, 927 sec, nsec, sec, nsec); 928} 929 930int 931archive_match_include_date(struct archive *_a, int flag, 932 const char *datestr) 933{ 934 int r; 935 936 r = validate_time_flag(_a, flag, "archive_match_include_date"); 937 if (r != ARCHIVE_OK) 938 return (r); 939 return set_timefilter_date((struct archive_match *)_a, flag, datestr); 940} 941 942int 943archive_match_include_date_w(struct archive *_a, int flag, 944 const wchar_t *datestr) 945{ 946 int r; 947 948 r = validate_time_flag(_a, flag, "archive_match_include_date_w"); 949 if (r != ARCHIVE_OK) 950 return (r); 951 952 return set_timefilter_date_w((struct archive_match *)_a, flag, datestr); 953} 954 955int 956archive_match_include_file_time(struct archive *_a, int flag, 957 const char *pathname) 958{ 959 int r; 960 961 r = validate_time_flag(_a, flag, "archive_match_include_file_time"); 962 if (r != ARCHIVE_OK) 963 return (r); 964 return set_timefilter_pathname_mbs((struct archive_match *)_a, 965 flag, pathname); 966} 967 968int 969archive_match_include_file_time_w(struct archive *_a, int flag, 970 const wchar_t *pathname) 971{ 972 int r; 973 974 r = validate_time_flag(_a, flag, "archive_match_include_file_time_w"); 975 if (r != ARCHIVE_OK) 976 return (r); 977 return set_timefilter_pathname_wcs((struct archive_match *)_a, 978 flag, pathname); 979} 980 981int 982archive_match_exclude_entry(struct archive *_a, int flag, 983 struct archive_entry *entry) 984{ 985 struct archive_match *a; 986 int r; 987 988 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 989 ARCHIVE_STATE_NEW, "archive_match_time_include_entry"); 990 a = (struct archive_match *)_a; 991 992 if (entry == NULL) { 993 archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 994 return (ARCHIVE_FAILED); 995 } 996 r = validate_time_flag(_a, flag, "archive_match_exclude_entry"); 997 if (r != ARCHIVE_OK) 998 return (r); 999 return (add_entry(a, flag, entry)); 1000} 1001 1002/* 1003 * Test function for time stamps. 1004 * 1005 * Returns 1 if archive entry is excluded. 1006 * Returns 0 if archive entry is not excluded. 1007 * Returns <0 if something error happened. 1008 */ 1009int 1010archive_match_time_excluded(struct archive *_a, 1011 struct archive_entry *entry) 1012{ 1013 struct archive_match *a; 1014 1015 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1016 ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae"); 1017 1018 a = (struct archive_match *)_a; 1019 if (entry == NULL) { 1020 archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 1021 return (ARCHIVE_FAILED); 1022 } 1023 1024 /* If we don't have inclusion time set at all, the entry is always 1025 * not excluded. */ 1026 if ((a->setflag & TIME_IS_SET) == 0) 1027 return (0); 1028 return (time_excluded(a, entry)); 1029} 1030 1031static int 1032validate_time_flag(struct archive *_a, int flag, const char *_fn) 1033{ 1034 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1035 ARCHIVE_STATE_NEW, _fn); 1036 1037 /* Check a type of time. */ 1038 if (flag & 1039 ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) { 1040 archive_set_error(_a, EINVAL, "Invalid time flag"); 1041 return (ARCHIVE_FAILED); 1042 } 1043 if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) { 1044 archive_set_error(_a, EINVAL, "No time flag"); 1045 return (ARCHIVE_FAILED); 1046 } 1047 1048 /* Check a type of comparison. */ 1049 if (flag & 1050 ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 1051 | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) { 1052 archive_set_error(_a, EINVAL, "Invalid comparison flag"); 1053 return (ARCHIVE_FAILED); 1054 } 1055 if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 1056 | ARCHIVE_MATCH_EQUAL)) == 0) { 1057 archive_set_error(_a, EINVAL, "No comparison flag"); 1058 return (ARCHIVE_FAILED); 1059 } 1060 1061 return (ARCHIVE_OK); 1062} 1063 1064#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\ 1065 ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL) 1066static int 1067set_timefilter(struct archive_match *a, int timetype, 1068 time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec) 1069{ 1070 if (timetype & ARCHIVE_MATCH_MTIME) { 1071 if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 1072 a->newer_mtime_filter = timetype; 1073 a->newer_mtime_sec = mtime_sec; 1074 a->newer_mtime_nsec = mtime_nsec; 1075 a->setflag |= TIME_IS_SET; 1076 } 1077 if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 1078 a->older_mtime_filter = timetype; 1079 a->older_mtime_sec = mtime_sec; 1080 a->older_mtime_nsec = mtime_nsec; 1081 a->setflag |= TIME_IS_SET; 1082 } 1083 } 1084 if (timetype & ARCHIVE_MATCH_CTIME) { 1085 if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 1086 a->newer_ctime_filter = timetype; 1087 a->newer_ctime_sec = ctime_sec; 1088 a->newer_ctime_nsec = ctime_nsec; 1089 a->setflag |= TIME_IS_SET; 1090 } 1091 if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 1092 a->older_ctime_filter = timetype; 1093 a->older_ctime_sec = ctime_sec; 1094 a->older_ctime_nsec = ctime_nsec; 1095 a->setflag |= TIME_IS_SET; 1096 } 1097 } 1098 return (ARCHIVE_OK); 1099} 1100 1101static int 1102set_timefilter_date(struct archive_match *a, int timetype, const char *datestr) 1103{ 1104 time_t t; 1105 1106 if (datestr == NULL || *datestr == '\0') { 1107 archive_set_error(&(a->archive), EINVAL, "date is empty"); 1108 return (ARCHIVE_FAILED); 1109 } 1110 t = get_date(a->now, datestr); 1111 if (t == (time_t)-1) { 1112 archive_set_error(&(a->archive), EINVAL, "invalid date string"); 1113 return (ARCHIVE_FAILED); 1114 } 1115 return set_timefilter(a, timetype, t, 0, t, 0); 1116} 1117 1118static int 1119set_timefilter_date_w(struct archive_match *a, int timetype, 1120 const wchar_t *datestr) 1121{ 1122 struct archive_string as; 1123 time_t t; 1124 1125 if (datestr == NULL || *datestr == L'\0') { 1126 archive_set_error(&(a->archive), EINVAL, "date is empty"); 1127 return (ARCHIVE_FAILED); 1128 } 1129 1130 archive_string_init(&as); 1131 if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { 1132 archive_string_free(&as); 1133 if (errno == ENOMEM) 1134 return (error_nomem(a)); 1135 archive_set_error(&(a->archive), -1, 1136 "Failed to convert WCS to MBS"); 1137 return (ARCHIVE_FAILED); 1138 } 1139 t = get_date(a->now, as.s); 1140 archive_string_free(&as); 1141 if (t == (time_t)-1) { 1142 archive_set_error(&(a->archive), EINVAL, "invalid date string"); 1143 return (ARCHIVE_FAILED); 1144 } 1145 return set_timefilter(a, timetype, t, 0, t, 0); 1146} 1147 1148#if defined(_WIN32) && !defined(__CYGWIN__) 1149#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) 1150static int 1151set_timefilter_find_data(struct archive_match *a, int timetype, 1152 DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, 1153 DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) 1154{ 1155 ULARGE_INTEGER utc; 1156 time_t ctime_sec, mtime_sec; 1157 long ctime_ns, mtime_ns; 1158 1159 utc.HighPart = ftCreationTime_dwHighDateTime; 1160 utc.LowPart = ftCreationTime_dwLowDateTime; 1161 if (utc.QuadPart >= EPOC_TIME) { 1162 utc.QuadPart -= EPOC_TIME; 1163 ctime_sec = (time_t)(utc.QuadPart / 10000000); 1164 ctime_ns = (long)(utc.QuadPart % 10000000) * 100; 1165 } else { 1166 ctime_sec = 0; 1167 ctime_ns = 0; 1168 } 1169 utc.HighPart = ftLastWriteTime_dwHighDateTime; 1170 utc.LowPart = ftLastWriteTime_dwLowDateTime; 1171 if (utc.QuadPart >= EPOC_TIME) { 1172 utc.QuadPart -= EPOC_TIME; 1173 mtime_sec = (time_t)(utc.QuadPart / 10000000); 1174 mtime_ns = (long)(utc.QuadPart % 10000000) * 100; 1175 } else { 1176 mtime_sec = 0; 1177 mtime_ns = 0; 1178 } 1179 return set_timefilter(a, timetype, 1180 mtime_sec, mtime_ns, ctime_sec, ctime_ns); 1181} 1182 1183static int 1184set_timefilter_pathname_mbs(struct archive_match *a, int timetype, 1185 const char *path) 1186{ 1187 /* NOTE: stat() on Windows cannot handle nano seconds. */ 1188 HANDLE h; 1189 WIN32_FIND_DATAA d; 1190 1191 if (path == NULL || *path == '\0') { 1192 archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1193 return (ARCHIVE_FAILED); 1194 } 1195 h = FindFirstFileA(path, &d); 1196 if (h == INVALID_HANDLE_VALUE) { 1197 la_dosmaperr(GetLastError()); 1198 archive_set_error(&(a->archive), errno, 1199 "Failed to FindFirstFileA"); 1200 return (ARCHIVE_FAILED); 1201 } 1202 FindClose(h); 1203 return set_timefilter_find_data(a, timetype, 1204 d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 1205 d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 1206} 1207 1208static int 1209set_timefilter_pathname_wcs(struct archive_match *a, int timetype, 1210 const wchar_t *path) 1211{ 1212 HANDLE h; 1213 WIN32_FIND_DATAW d; 1214 1215 if (path == NULL || *path == L'\0') { 1216 archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1217 return (ARCHIVE_FAILED); 1218 } 1219 h = FindFirstFileW(path, &d); 1220 if (h == INVALID_HANDLE_VALUE) { 1221 la_dosmaperr(GetLastError()); 1222 archive_set_error(&(a->archive), errno, 1223 "Failed to FindFirstFile"); 1224 return (ARCHIVE_FAILED); 1225 } 1226 FindClose(h); 1227 return set_timefilter_find_data(a, timetype, 1228 d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 1229 d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 1230} 1231 1232#else /* _WIN32 && !__CYGWIN__ */ 1233 1234static int 1235set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st) 1236{ 1237 struct archive_entry *ae; 1238 time_t ctime_sec, mtime_sec; 1239 long ctime_ns, mtime_ns; 1240 1241 ae = archive_entry_new(); 1242 if (ae == NULL) 1243 return (error_nomem(a)); 1244 archive_entry_copy_stat(ae, st); 1245 ctime_sec = archive_entry_ctime(ae); 1246 ctime_ns = archive_entry_ctime_nsec(ae); 1247 mtime_sec = archive_entry_mtime(ae); 1248 mtime_ns = archive_entry_mtime_nsec(ae); 1249 archive_entry_free(ae); 1250 return set_timefilter(a, timetype, mtime_sec, mtime_ns, 1251 ctime_sec, ctime_ns); 1252} 1253 1254static int 1255set_timefilter_pathname_mbs(struct archive_match *a, int timetype, 1256 const char *path) 1257{ 1258 struct stat st; 1259 1260 if (path == NULL || *path == '\0') { 1261 archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1262 return (ARCHIVE_FAILED); 1263 } 1264 if (la_stat(path, &st) != 0) { 1265 archive_set_error(&(a->archive), errno, "Failed to stat()"); 1266 return (ARCHIVE_FAILED); 1267 } 1268 return (set_timefilter_stat(a, timetype, &st)); 1269} 1270 1271static int 1272set_timefilter_pathname_wcs(struct archive_match *a, int timetype, 1273 const wchar_t *path) 1274{ 1275 struct archive_string as; 1276 int r; 1277 1278 if (path == NULL || *path == L'\0') { 1279 archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 1280 return (ARCHIVE_FAILED); 1281 } 1282 1283 /* Convert WCS filename to MBS filename. */ 1284 archive_string_init(&as); 1285 if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { 1286 archive_string_free(&as); 1287 if (errno == ENOMEM) 1288 return (error_nomem(a)); 1289 archive_set_error(&(a->archive), -1, 1290 "Failed to convert WCS to MBS"); 1291 return (ARCHIVE_FAILED); 1292 } 1293 1294 r = set_timefilter_pathname_mbs(a, timetype, as.s); 1295 archive_string_free(&as); 1296 1297 return (r); 1298} 1299#endif /* _WIN32 && !__CYGWIN__ */ 1300 1301/* 1302 * Call back functions for archive_rb. 1303 */ 1304static int 1305cmp_node_mbs(const struct archive_rb_node *n1, 1306 const struct archive_rb_node *n2) 1307{ 1308 struct match_file *f1 = (struct match_file *)(uintptr_t)n1; 1309 struct match_file *f2 = (struct match_file *)(uintptr_t)n2; 1310 const char *p1, *p2; 1311 1312 archive_mstring_get_mbs(NULL, &(f1->pathname), &p1); 1313 archive_mstring_get_mbs(NULL, &(f2->pathname), &p2); 1314 if (p1 == NULL) 1315 return (1); 1316 if (p2 == NULL) 1317 return (-1); 1318 return (strcmp(p1, p2)); 1319} 1320 1321static int 1322cmp_key_mbs(const struct archive_rb_node *n, const void *key) 1323{ 1324 struct match_file *f = (struct match_file *)(uintptr_t)n; 1325 const char *p; 1326 1327 archive_mstring_get_mbs(NULL, &(f->pathname), &p); 1328 if (p == NULL) 1329 return (-1); 1330 return (strcmp(p, (const char *)key)); 1331} 1332 1333static int 1334cmp_node_wcs(const struct archive_rb_node *n1, 1335 const struct archive_rb_node *n2) 1336{ 1337 struct match_file *f1 = (struct match_file *)(uintptr_t)n1; 1338 struct match_file *f2 = (struct match_file *)(uintptr_t)n2; 1339 const wchar_t *p1, *p2; 1340 1341 archive_mstring_get_wcs(NULL, &(f1->pathname), &p1); 1342 archive_mstring_get_wcs(NULL, &(f2->pathname), &p2); 1343 if (p1 == NULL) 1344 return (1); 1345 if (p2 == NULL) 1346 return (-1); 1347 return (wcscmp(p1, p2)); 1348} 1349 1350static int 1351cmp_key_wcs(const struct archive_rb_node *n, const void *key) 1352{ 1353 struct match_file *f = (struct match_file *)(uintptr_t)n; 1354 const wchar_t *p; 1355 1356 archive_mstring_get_wcs(NULL, &(f->pathname), &p); 1357 if (p == NULL) 1358 return (-1); 1359 return (wcscmp(p, (const wchar_t *)key)); 1360} 1361 1362static void 1363entry_list_init(struct entry_list *list) 1364{ 1365 list->first = NULL; 1366 list->last = &(list->first); 1367 list->count = 0; 1368} 1369 1370static void 1371entry_list_free(struct entry_list *list) 1372{ 1373 struct match_file *p, *q; 1374 1375 for (p = list->first; p != NULL; ) { 1376 q = p; 1377 p = p->next; 1378 archive_mstring_clean(&(q->pathname)); 1379 free(q); 1380 } 1381} 1382 1383static void 1384entry_list_add(struct entry_list *list, struct match_file *file) 1385{ 1386 *list->last = file; 1387 list->last = &(file->next); 1388 list->count++; 1389} 1390 1391static int 1392add_entry(struct archive_match *a, int flag, 1393 struct archive_entry *entry) 1394{ 1395 struct match_file *f; 1396 const void *pathname; 1397 int r; 1398 1399 f = calloc(1, sizeof(*f)); 1400 if (f == NULL) 1401 return (error_nomem(a)); 1402 1403#if defined(_WIN32) && !defined(__CYGWIN__) 1404 pathname = archive_entry_pathname_w(entry); 1405 if (pathname == NULL) { 1406 free(f); 1407 archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 1408 return (ARCHIVE_FAILED); 1409 } 1410 archive_mstring_copy_wcs(&(f->pathname), pathname); 1411 a->exclusion_tree.rbt_ops = &rb_ops_wcs; 1412#else 1413 (void)rb_ops_wcs; 1414 pathname = archive_entry_pathname(entry); 1415 if (pathname == NULL) { 1416 free(f); 1417 archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 1418 return (ARCHIVE_FAILED); 1419 } 1420 archive_mstring_copy_mbs(&(f->pathname), pathname); 1421 a->exclusion_tree.rbt_ops = &rb_ops_mbs; 1422#endif 1423 f->flag = flag; 1424 f->mtime_sec = archive_entry_mtime(entry); 1425 f->mtime_nsec = archive_entry_mtime_nsec(entry); 1426 f->ctime_sec = archive_entry_ctime(entry); 1427 f->ctime_nsec = archive_entry_ctime_nsec(entry); 1428 r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node)); 1429 if (!r) { 1430 struct match_file *f2; 1431 1432 /* Get the duplicated file. */ 1433 f2 = (struct match_file *)__archive_rb_tree_find_node( 1434 &(a->exclusion_tree), pathname); 1435 1436 /* 1437 * We always overwrite comparison condition. 1438 * If you do not want to overwrite it, you should not 1439 * call archive_match_exclude_entry(). We cannot know 1440 * what behavior you really expect since overwriting 1441 * condition might be different with the flag. 1442 */ 1443 if (f2 != NULL) { 1444 f2->flag = f->flag; 1445 f2->mtime_sec = f->mtime_sec; 1446 f2->mtime_nsec = f->mtime_nsec; 1447 f2->ctime_sec = f->ctime_sec; 1448 f2->ctime_nsec = f->ctime_nsec; 1449 } 1450 /* Release the duplicated file. */ 1451 archive_mstring_clean(&(f->pathname)); 1452 free(f); 1453 return (ARCHIVE_OK); 1454 } 1455 entry_list_add(&(a->exclusion_entry_list), f); 1456 a->setflag |= TIME_IS_SET; 1457 return (ARCHIVE_OK); 1458} 1459 1460/* 1461 * Test if entry is excluded by its timestamp. 1462 */ 1463static int 1464time_excluded(struct archive_match *a, struct archive_entry *entry) 1465{ 1466 struct match_file *f; 1467 const void *pathname; 1468 time_t sec; 1469 long nsec; 1470 1471 /* 1472 * If this file/dir is excluded by a time comparison, skip it. 1473 */ 1474 if (a->newer_ctime_filter) { 1475 /* If ctime is not set, use mtime instead. */ 1476 if (archive_entry_ctime_is_set(entry)) 1477 sec = archive_entry_ctime(entry); 1478 else 1479 sec = archive_entry_mtime(entry); 1480 if (sec < a->newer_ctime_sec) 1481 return (1); /* Too old, skip it. */ 1482 if (sec == a->newer_ctime_sec) { 1483 if (archive_entry_ctime_is_set(entry)) 1484 nsec = archive_entry_ctime_nsec(entry); 1485 else 1486 nsec = archive_entry_mtime_nsec(entry); 1487 if (nsec < a->newer_ctime_nsec) 1488 return (1); /* Too old, skip it. */ 1489 if (nsec == a->newer_ctime_nsec && 1490 (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL) 1491 == 0) 1492 return (1); /* Equal, skip it. */ 1493 } 1494 } 1495 if (a->older_ctime_filter) { 1496 /* If ctime is not set, use mtime instead. */ 1497 if (archive_entry_ctime_is_set(entry)) 1498 sec = archive_entry_ctime(entry); 1499 else 1500 sec = archive_entry_mtime(entry); 1501 if (sec > a->older_ctime_sec) 1502 return (1); /* Too new, skip it. */ 1503 if (sec == a->older_ctime_sec) { 1504 if (archive_entry_ctime_is_set(entry)) 1505 nsec = archive_entry_ctime_nsec(entry); 1506 else 1507 nsec = archive_entry_mtime_nsec(entry); 1508 if (nsec > a->older_ctime_nsec) 1509 return (1); /* Too new, skip it. */ 1510 if (nsec == a->older_ctime_nsec && 1511 (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) 1512 == 0) 1513 return (1); /* Equal, skip it. */ 1514 } 1515 } 1516 if (a->newer_mtime_filter) { 1517 sec = archive_entry_mtime(entry); 1518 if (sec < a->newer_mtime_sec) 1519 return (1); /* Too old, skip it. */ 1520 if (sec == a->newer_mtime_sec) { 1521 nsec = archive_entry_mtime_nsec(entry); 1522 if (nsec < a->newer_mtime_nsec) 1523 return (1); /* Too old, skip it. */ 1524 if (nsec == a->newer_mtime_nsec && 1525 (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL) 1526 == 0) 1527 return (1); /* Equal, skip it. */ 1528 } 1529 } 1530 if (a->older_mtime_filter) { 1531 sec = archive_entry_mtime(entry); 1532 if (sec > a->older_mtime_sec) 1533 return (1); /* Too new, skip it. */ 1534 nsec = archive_entry_mtime_nsec(entry); 1535 if (sec == a->older_mtime_sec) { 1536 if (nsec > a->older_mtime_nsec) 1537 return (1); /* Too new, skip it. */ 1538 if (nsec == a->older_mtime_nsec && 1539 (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL) 1540 == 0) 1541 return (1); /* Equal, skip it. */ 1542 } 1543 } 1544 1545 /* If there is no exclusion list, include the file. */ 1546 if (a->exclusion_entry_list.count == 0) 1547 return (0); 1548 1549#if defined(_WIN32) && !defined(__CYGWIN__) 1550 pathname = archive_entry_pathname_w(entry); 1551 a->exclusion_tree.rbt_ops = &rb_ops_wcs; 1552#else 1553 (void)rb_ops_wcs; 1554 pathname = archive_entry_pathname(entry); 1555 a->exclusion_tree.rbt_ops = &rb_ops_mbs; 1556#endif 1557 if (pathname == NULL) 1558 return (0); 1559 1560 f = (struct match_file *)__archive_rb_tree_find_node( 1561 &(a->exclusion_tree), pathname); 1562 /* If the file wasn't rejected, include it. */ 1563 if (f == NULL) 1564 return (0); 1565 1566 if (f->flag & ARCHIVE_MATCH_CTIME) { 1567 sec = archive_entry_ctime(entry); 1568 if (f->ctime_sec > sec) { 1569 if (f->flag & ARCHIVE_MATCH_OLDER) 1570 return (1); 1571 } else if (f->ctime_sec < sec) { 1572 if (f->flag & ARCHIVE_MATCH_NEWER) 1573 return (1); 1574 } else { 1575 nsec = archive_entry_ctime_nsec(entry); 1576 if (f->ctime_nsec > nsec) { 1577 if (f->flag & ARCHIVE_MATCH_OLDER) 1578 return (1); 1579 } else if (f->ctime_nsec < nsec) { 1580 if (f->flag & ARCHIVE_MATCH_NEWER) 1581 return (1); 1582 } else if (f->flag & ARCHIVE_MATCH_EQUAL) 1583 return (1); 1584 } 1585 } 1586 if (f->flag & ARCHIVE_MATCH_MTIME) { 1587 sec = archive_entry_mtime(entry); 1588 if (f->mtime_sec > sec) { 1589 if (f->flag & ARCHIVE_MATCH_OLDER) 1590 return (1); 1591 } else if (f->mtime_sec < sec) { 1592 if (f->flag & ARCHIVE_MATCH_NEWER) 1593 return (1); 1594 } else { 1595 nsec = archive_entry_mtime_nsec(entry); 1596 if (f->mtime_nsec > nsec) { 1597 if (f->flag & ARCHIVE_MATCH_OLDER) 1598 return (1); 1599 } else if (f->mtime_nsec < nsec) { 1600 if (f->flag & ARCHIVE_MATCH_NEWER) 1601 return (1); 1602 } else if (f->flag & ARCHIVE_MATCH_EQUAL) 1603 return (1); 1604 } 1605 } 1606 return (0); 1607} 1608 1609/* 1610 * Utility functions to manage inclusion owners 1611 */ 1612 1613int 1614archive_match_include_uid(struct archive *_a, la_int64_t uid) 1615{ 1616 struct archive_match *a; 1617 1618 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1619 ARCHIVE_STATE_NEW, "archive_match_include_uid"); 1620 a = (struct archive_match *)_a; 1621 return (add_owner_id(a, &(a->inclusion_uids), uid)); 1622} 1623 1624int 1625archive_match_include_gid(struct archive *_a, la_int64_t gid) 1626{ 1627 struct archive_match *a; 1628 1629 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1630 ARCHIVE_STATE_NEW, "archive_match_include_gid"); 1631 a = (struct archive_match *)_a; 1632 return (add_owner_id(a, &(a->inclusion_gids), gid)); 1633} 1634 1635int 1636archive_match_include_uname(struct archive *_a, const char *uname) 1637{ 1638 struct archive_match *a; 1639 1640 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1641 ARCHIVE_STATE_NEW, "archive_match_include_uname"); 1642 a = (struct archive_match *)_a; 1643 return (add_owner_name(a, &(a->inclusion_unames), 1, uname)); 1644} 1645 1646int 1647archive_match_include_uname_w(struct archive *_a, const wchar_t *uname) 1648{ 1649 struct archive_match *a; 1650 1651 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1652 ARCHIVE_STATE_NEW, "archive_match_include_uname_w"); 1653 a = (struct archive_match *)_a; 1654 return (add_owner_name(a, &(a->inclusion_unames), 0, uname)); 1655} 1656 1657int 1658archive_match_include_gname(struct archive *_a, const char *gname) 1659{ 1660 struct archive_match *a; 1661 1662 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1663 ARCHIVE_STATE_NEW, "archive_match_include_gname"); 1664 a = (struct archive_match *)_a; 1665 return (add_owner_name(a, &(a->inclusion_gnames), 1, gname)); 1666} 1667 1668int 1669archive_match_include_gname_w(struct archive *_a, const wchar_t *gname) 1670{ 1671 struct archive_match *a; 1672 1673 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1674 ARCHIVE_STATE_NEW, "archive_match_include_gname_w"); 1675 a = (struct archive_match *)_a; 1676 return (add_owner_name(a, &(a->inclusion_gnames), 0, gname)); 1677} 1678 1679/* 1680 * Test function for owner(uid, gid, uname, gname). 1681 * 1682 * Returns 1 if archive entry is excluded. 1683 * Returns 0 if archive entry is not excluded. 1684 * Returns <0 if something error happened. 1685 */ 1686int 1687archive_match_owner_excluded(struct archive *_a, 1688 struct archive_entry *entry) 1689{ 1690 struct archive_match *a; 1691 1692 archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 1693 ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae"); 1694 1695 a = (struct archive_match *)_a; 1696 if (entry == NULL) { 1697 archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 1698 return (ARCHIVE_FAILED); 1699 } 1700 1701 /* If we don't have inclusion id set at all, the entry is always 1702 * not excluded. */ 1703 if ((a->setflag & ID_IS_SET) == 0) 1704 return (0); 1705 return (owner_excluded(a, entry)); 1706} 1707 1708static int 1709add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) 1710{ 1711 unsigned i; 1712 1713 if (ids->count + 1 >= ids->size) { 1714 void *p; 1715 1716 if (ids->size == 0) 1717 ids->size = 8; 1718 else 1719 ids->size *= 2; 1720 p = realloc(ids->ids, sizeof(*ids->ids) * ids->size); 1721 if (p == NULL) 1722 return (error_nomem(a)); 1723 ids->ids = (int64_t *)p; 1724 } 1725 1726 /* Find an insert point. */ 1727 for (i = 0; i < ids->count; i++) { 1728 if (ids->ids[i] >= id) 1729 break; 1730 } 1731 1732 /* Add owner id. */ 1733 if (i == ids->count) 1734 ids->ids[ids->count++] = id; 1735 else if (ids->ids[i] != id) { 1736 memmove(&(ids->ids[i+1]), &(ids->ids[i]), 1737 (ids->count - i) * sizeof(ids->ids[0])); 1738 ids->ids[i] = id; 1739 ids->count++; 1740 } 1741 a->setflag |= ID_IS_SET; 1742 return (ARCHIVE_OK); 1743} 1744 1745static int 1746match_owner_id(struct id_array *ids, int64_t id) 1747{ 1748 unsigned b, m, t; 1749 1750 t = 0; 1751 b = (unsigned)ids->count; 1752 while (t < b) { 1753 m = (t + b)>>1; 1754 if (ids->ids[m] == id) 1755 return (1); 1756 if (ids->ids[m] < id) 1757 t = m + 1; 1758 else 1759 b = m; 1760 } 1761 return (0); 1762} 1763 1764static int 1765add_owner_name(struct archive_match *a, struct match_list *list, 1766 int mbs, const void *name) 1767{ 1768 struct match *match; 1769 1770 match = calloc(1, sizeof(*match)); 1771 if (match == NULL) 1772 return (error_nomem(a)); 1773 if (mbs) 1774 archive_mstring_copy_mbs(&(match->pattern), name); 1775 else 1776 archive_mstring_copy_wcs(&(match->pattern), name); 1777 match_list_add(list, match); 1778 a->setflag |= ID_IS_SET; 1779 return (ARCHIVE_OK); 1780} 1781 1782#if !defined(_WIN32) || defined(__CYGWIN__) 1783static int 1784match_owner_name_mbs(struct archive_match *a, struct match_list *list, 1785 const char *name) 1786{ 1787 struct match *m; 1788 const char *p; 1789 1790 if (name == NULL || *name == '\0') 1791 return (0); 1792 for (m = list->first; m; m = m->next) { 1793 if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p) 1794 < 0 && errno == ENOMEM) 1795 return (error_nomem(a)); 1796 if (p != NULL && strcmp(p, name) == 0) { 1797 m->matches++; 1798 return (1); 1799 } 1800 } 1801 return (0); 1802} 1803#else 1804static int 1805match_owner_name_wcs(struct archive_match *a, struct match_list *list, 1806 const wchar_t *name) 1807{ 1808 struct match *m; 1809 const wchar_t *p; 1810 1811 if (name == NULL || *name == L'\0') 1812 return (0); 1813 for (m = list->first; m; m = m->next) { 1814 if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p) 1815 < 0 && errno == ENOMEM) 1816 return (error_nomem(a)); 1817 if (p != NULL && wcscmp(p, name) == 0) { 1818 m->matches++; 1819 return (1); 1820 } 1821 } 1822 return (0); 1823} 1824#endif 1825 1826/* 1827 * Test if entry is excluded by uid, gid, uname or gname. 1828 */ 1829static int 1830owner_excluded(struct archive_match *a, struct archive_entry *entry) 1831{ 1832 int r; 1833 1834 if (a->inclusion_uids.count) { 1835 if (!match_owner_id(&(a->inclusion_uids), 1836 archive_entry_uid(entry))) 1837 return (1); 1838 } 1839 1840 if (a->inclusion_gids.count) { 1841 if (!match_owner_id(&(a->inclusion_gids), 1842 archive_entry_gid(entry))) 1843 return (1); 1844 } 1845 1846 if (a->inclusion_unames.count) { 1847#if defined(_WIN32) && !defined(__CYGWIN__) 1848 r = match_owner_name_wcs(a, &(a->inclusion_unames), 1849 archive_entry_uname_w(entry)); 1850#else 1851 r = match_owner_name_mbs(a, &(a->inclusion_unames), 1852 archive_entry_uname(entry)); 1853#endif 1854 if (!r) 1855 return (1); 1856 else if (r < 0) 1857 return (r); 1858 } 1859 1860 if (a->inclusion_gnames.count) { 1861#if defined(_WIN32) && !defined(__CYGWIN__) 1862 r = match_owner_name_wcs(a, &(a->inclusion_gnames), 1863 archive_entry_gname_w(entry)); 1864#else 1865 r = match_owner_name_mbs(a, &(a->inclusion_gnames), 1866 archive_entry_gname(entry)); 1867#endif 1868 if (!r) 1869 return (1); 1870 else if (r < 0) 1871 return (r); 1872 } 1873 return (0); 1874} 1875 1876