159bf7050SPeter Avalos /*- 259bf7050SPeter Avalos * Copyright (c) 2003-2007 Tim Kientzle 359bf7050SPeter Avalos * Copyright (c) 2012 Michihiro NAKAJIMA 459bf7050SPeter Avalos * All rights reserved. 559bf7050SPeter Avalos * 659bf7050SPeter Avalos * Redistribution and use in source and binary forms, with or without 759bf7050SPeter Avalos * modification, are permitted provided that the following conditions 859bf7050SPeter Avalos * are met: 959bf7050SPeter Avalos * 1. Redistributions of source code must retain the above copyright 1059bf7050SPeter Avalos * notice, this list of conditions and the following disclaimer. 1159bf7050SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1259bf7050SPeter Avalos * notice, this list of conditions and the following disclaimer in the 1359bf7050SPeter Avalos * documentation and/or other materials provided with the distribution. 1459bf7050SPeter Avalos * 1559bf7050SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1659bf7050SPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1759bf7050SPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1859bf7050SPeter Avalos * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1959bf7050SPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2059bf7050SPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2159bf7050SPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2259bf7050SPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2359bf7050SPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2459bf7050SPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2559bf7050SPeter Avalos */ 2659bf7050SPeter Avalos 2759bf7050SPeter Avalos #include "archive_platform.h" 2859bf7050SPeter Avalos __FBSDID("$FreeBSD$"); 2959bf7050SPeter Avalos 3059bf7050SPeter Avalos #ifdef HAVE_ERRNO_H 3159bf7050SPeter Avalos #include <errno.h> 3259bf7050SPeter Avalos #endif 3359bf7050SPeter Avalos #ifdef HAVE_STDLIB_H 3459bf7050SPeter Avalos #include <stdlib.h> 3559bf7050SPeter Avalos #endif 3659bf7050SPeter Avalos #ifdef HAVE_STRING_H 3759bf7050SPeter Avalos #include <string.h> 3859bf7050SPeter Avalos #endif 3959bf7050SPeter Avalos 4059bf7050SPeter Avalos #include "archive.h" 4159bf7050SPeter Avalos #include "archive_private.h" 4259bf7050SPeter Avalos #include "archive_entry.h" 43*6b384f39SPeter Avalos #include "archive_getdate.h" 4459bf7050SPeter Avalos #include "archive_pathmatch.h" 4559bf7050SPeter Avalos #include "archive_rb.h" 4659bf7050SPeter Avalos #include "archive_string.h" 4759bf7050SPeter Avalos 4859bf7050SPeter Avalos struct match { 4959bf7050SPeter Avalos struct match *next; 5059bf7050SPeter Avalos int matches; 5159bf7050SPeter Avalos struct archive_mstring pattern; 5259bf7050SPeter Avalos }; 5359bf7050SPeter Avalos 5459bf7050SPeter Avalos struct match_list { 5559bf7050SPeter Avalos struct match *first; 5659bf7050SPeter Avalos struct match **last; 5759bf7050SPeter Avalos int count; 5859bf7050SPeter Avalos int unmatched_count; 5959bf7050SPeter Avalos struct match *unmatched_next; 6059bf7050SPeter Avalos int unmatched_eof; 6159bf7050SPeter Avalos }; 6259bf7050SPeter Avalos 6359bf7050SPeter Avalos struct match_file { 6459bf7050SPeter Avalos struct archive_rb_node node; 6559bf7050SPeter Avalos struct match_file *next; 6659bf7050SPeter Avalos struct archive_mstring pathname; 6759bf7050SPeter Avalos int flag; 6859bf7050SPeter Avalos time_t mtime_sec; 6959bf7050SPeter Avalos long mtime_nsec; 7059bf7050SPeter Avalos time_t ctime_sec; 7159bf7050SPeter Avalos long ctime_nsec; 7259bf7050SPeter Avalos }; 7359bf7050SPeter Avalos 7459bf7050SPeter Avalos struct entry_list { 7559bf7050SPeter Avalos struct match_file *first; 7659bf7050SPeter Avalos struct match_file **last; 7759bf7050SPeter Avalos int count; 7859bf7050SPeter Avalos }; 7959bf7050SPeter Avalos 8059bf7050SPeter Avalos struct id_array { 8159bf7050SPeter Avalos size_t size;/* Allocated size */ 8259bf7050SPeter Avalos size_t count; 8359bf7050SPeter Avalos int64_t *ids; 8459bf7050SPeter Avalos }; 8559bf7050SPeter Avalos 8659bf7050SPeter Avalos #define PATTERN_IS_SET 1 8759bf7050SPeter Avalos #define TIME_IS_SET 2 8859bf7050SPeter Avalos #define ID_IS_SET 4 8959bf7050SPeter Avalos 9059bf7050SPeter Avalos struct archive_match { 9159bf7050SPeter Avalos struct archive archive; 9259bf7050SPeter Avalos 9359bf7050SPeter Avalos /* exclusion/inclusion set flag. */ 9459bf7050SPeter Avalos int setflag; 9559bf7050SPeter Avalos 9659bf7050SPeter Avalos /* 9759bf7050SPeter Avalos * Matching filename patterns. 9859bf7050SPeter Avalos */ 9959bf7050SPeter Avalos struct match_list exclusions; 10059bf7050SPeter Avalos struct match_list inclusions; 10159bf7050SPeter Avalos 10259bf7050SPeter Avalos /* 10359bf7050SPeter Avalos * Matching time stamps. 10459bf7050SPeter Avalos */ 10559bf7050SPeter Avalos time_t now; 10659bf7050SPeter Avalos int newer_mtime_filter; 10759bf7050SPeter Avalos time_t newer_mtime_sec; 10859bf7050SPeter Avalos long newer_mtime_nsec; 10959bf7050SPeter Avalos int newer_ctime_filter; 11059bf7050SPeter Avalos time_t newer_ctime_sec; 11159bf7050SPeter Avalos long newer_ctime_nsec; 11259bf7050SPeter Avalos int older_mtime_filter; 11359bf7050SPeter Avalos time_t older_mtime_sec; 11459bf7050SPeter Avalos long older_mtime_nsec; 11559bf7050SPeter Avalos int older_ctime_filter; 11659bf7050SPeter Avalos time_t older_ctime_sec; 11759bf7050SPeter Avalos long older_ctime_nsec; 11859bf7050SPeter Avalos /* 11959bf7050SPeter Avalos * Matching time stamps with its filename. 12059bf7050SPeter Avalos */ 12159bf7050SPeter Avalos struct archive_rb_tree exclusion_tree; 12259bf7050SPeter Avalos struct entry_list exclusion_entry_list; 12359bf7050SPeter Avalos 12459bf7050SPeter Avalos /* 12559bf7050SPeter Avalos * Matching file owners. 12659bf7050SPeter Avalos */ 12759bf7050SPeter Avalos struct id_array inclusion_uids; 12859bf7050SPeter Avalos struct id_array inclusion_gids; 12959bf7050SPeter Avalos struct match_list inclusion_unames; 13059bf7050SPeter Avalos struct match_list inclusion_gnames; 13159bf7050SPeter Avalos }; 13259bf7050SPeter Avalos 13359bf7050SPeter Avalos static int add_pattern_from_file(struct archive_match *, 13459bf7050SPeter Avalos struct match_list *, int, const void *, int); 13559bf7050SPeter Avalos static int add_entry(struct archive_match *, int, 13659bf7050SPeter Avalos struct archive_entry *); 13759bf7050SPeter Avalos static int add_owner_id(struct archive_match *, struct id_array *, 13859bf7050SPeter Avalos int64_t); 13959bf7050SPeter Avalos static int add_owner_name(struct archive_match *, struct match_list *, 14059bf7050SPeter Avalos int, const void *); 14159bf7050SPeter Avalos static int add_pattern_mbs(struct archive_match *, struct match_list *, 14259bf7050SPeter Avalos const char *); 14359bf7050SPeter Avalos static int add_pattern_wcs(struct archive_match *, struct match_list *, 14459bf7050SPeter Avalos const wchar_t *); 14559bf7050SPeter Avalos static int cmp_key_mbs(const struct archive_rb_node *, const void *); 14659bf7050SPeter Avalos static int cmp_key_wcs(const struct archive_rb_node *, const void *); 14759bf7050SPeter Avalos static int cmp_node_mbs(const struct archive_rb_node *, 14859bf7050SPeter Avalos const struct archive_rb_node *); 14959bf7050SPeter Avalos static int cmp_node_wcs(const struct archive_rb_node *, 15059bf7050SPeter Avalos const struct archive_rb_node *); 15159bf7050SPeter Avalos static void entry_list_add(struct entry_list *, struct match_file *); 15259bf7050SPeter Avalos static void entry_list_free(struct entry_list *); 15359bf7050SPeter Avalos static void entry_list_init(struct entry_list *); 15459bf7050SPeter Avalos static int error_nomem(struct archive_match *); 15559bf7050SPeter Avalos static void match_list_add(struct match_list *, struct match *); 15659bf7050SPeter Avalos static void match_list_free(struct match_list *); 15759bf7050SPeter Avalos static void match_list_init(struct match_list *); 15859bf7050SPeter Avalos static int match_list_unmatched_inclusions_next(struct archive_match *, 15959bf7050SPeter Avalos struct match_list *, int, const void **); 16059bf7050SPeter Avalos static int match_owner_id(struct id_array *, int64_t); 16159bf7050SPeter Avalos #if !defined(_WIN32) || defined(__CYGWIN__) 16259bf7050SPeter Avalos static int match_owner_name_mbs(struct archive_match *, 16359bf7050SPeter Avalos struct match_list *, const char *); 16459bf7050SPeter Avalos #else 16559bf7050SPeter Avalos static int match_owner_name_wcs(struct archive_match *, 16659bf7050SPeter Avalos struct match_list *, const wchar_t *); 16759bf7050SPeter Avalos #endif 16859bf7050SPeter Avalos static int match_path_exclusion(struct archive_match *, 16959bf7050SPeter Avalos struct match *, int, const void *); 17059bf7050SPeter Avalos static int match_path_inclusion(struct archive_match *, 17159bf7050SPeter Avalos struct match *, int, const void *); 17259bf7050SPeter Avalos static int owner_excluded(struct archive_match *, 17359bf7050SPeter Avalos struct archive_entry *); 17459bf7050SPeter Avalos static int path_excluded(struct archive_match *, int, const void *); 17559bf7050SPeter Avalos static int set_timefilter(struct archive_match *, int, time_t, long, 17659bf7050SPeter Avalos time_t, long); 17759bf7050SPeter Avalos static int set_timefilter_pathname_mbs(struct archive_match *, 17859bf7050SPeter Avalos int, const char *); 17959bf7050SPeter Avalos static int set_timefilter_pathname_wcs(struct archive_match *, 18059bf7050SPeter Avalos int, const wchar_t *); 18159bf7050SPeter Avalos static int set_timefilter_date(struct archive_match *, int, const char *); 18259bf7050SPeter Avalos static int set_timefilter_date_w(struct archive_match *, int, 18359bf7050SPeter Avalos const wchar_t *); 18459bf7050SPeter Avalos static int time_excluded(struct archive_match *, 18559bf7050SPeter Avalos struct archive_entry *); 18659bf7050SPeter Avalos static int validate_time_flag(struct archive *, int, const char *); 18759bf7050SPeter Avalos 18859bf7050SPeter Avalos #define get_date __archive_get_date 18959bf7050SPeter Avalos 19059bf7050SPeter Avalos static const struct archive_rb_tree_ops rb_ops_mbs = { 19159bf7050SPeter Avalos cmp_node_mbs, cmp_key_mbs 19259bf7050SPeter Avalos }; 19359bf7050SPeter Avalos 19459bf7050SPeter Avalos static const struct archive_rb_tree_ops rb_ops_wcs = { 19559bf7050SPeter Avalos cmp_node_wcs, cmp_key_wcs 19659bf7050SPeter Avalos }; 19759bf7050SPeter Avalos 19859bf7050SPeter Avalos /* 19959bf7050SPeter Avalos * The matching logic here needs to be re-thought. I started out to 20059bf7050SPeter Avalos * try to mimic gtar's matching logic, but it's not entirely 20159bf7050SPeter Avalos * consistent. In particular 'tar -t' and 'tar -x' interpret patterns 20259bf7050SPeter Avalos * on the command line as anchored, but --exclude doesn't. 20359bf7050SPeter Avalos */ 20459bf7050SPeter Avalos 20559bf7050SPeter Avalos static int 20659bf7050SPeter Avalos error_nomem(struct archive_match *a) 20759bf7050SPeter Avalos { 20859bf7050SPeter Avalos archive_set_error(&(a->archive), ENOMEM, "No memory"); 20959bf7050SPeter Avalos a->archive.state = ARCHIVE_STATE_FATAL; 21059bf7050SPeter Avalos return (ARCHIVE_FATAL); 21159bf7050SPeter Avalos } 21259bf7050SPeter Avalos 21359bf7050SPeter Avalos /* 21459bf7050SPeter Avalos * Create an ARCHIVE_MATCH object. 21559bf7050SPeter Avalos */ 21659bf7050SPeter Avalos struct archive * 21759bf7050SPeter Avalos archive_match_new(void) 21859bf7050SPeter Avalos { 21959bf7050SPeter Avalos struct archive_match *a; 22059bf7050SPeter Avalos 22159bf7050SPeter Avalos a = (struct archive_match *)calloc(1, sizeof(*a)); 22259bf7050SPeter Avalos if (a == NULL) 22359bf7050SPeter Avalos return (NULL); 22459bf7050SPeter Avalos a->archive.magic = ARCHIVE_MATCH_MAGIC; 22559bf7050SPeter Avalos a->archive.state = ARCHIVE_STATE_NEW; 22659bf7050SPeter Avalos match_list_init(&(a->inclusions)); 22759bf7050SPeter Avalos match_list_init(&(a->exclusions)); 22859bf7050SPeter Avalos __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); 22959bf7050SPeter Avalos entry_list_init(&(a->exclusion_entry_list)); 23059bf7050SPeter Avalos match_list_init(&(a->inclusion_unames)); 23159bf7050SPeter Avalos match_list_init(&(a->inclusion_gnames)); 23259bf7050SPeter Avalos time(&a->now); 23359bf7050SPeter Avalos return (&(a->archive)); 23459bf7050SPeter Avalos } 23559bf7050SPeter Avalos 23659bf7050SPeter Avalos /* 23759bf7050SPeter Avalos * Free an ARCHIVE_MATCH object. 23859bf7050SPeter Avalos */ 23959bf7050SPeter Avalos int 24059bf7050SPeter Avalos archive_match_free(struct archive *_a) 24159bf7050SPeter Avalos { 24259bf7050SPeter Avalos struct archive_match *a; 24359bf7050SPeter Avalos 24459bf7050SPeter Avalos if (_a == NULL) 24559bf7050SPeter Avalos return (ARCHIVE_OK); 24659bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 24759bf7050SPeter Avalos ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free"); 24859bf7050SPeter Avalos a = (struct archive_match *)_a; 24959bf7050SPeter Avalos match_list_free(&(a->inclusions)); 25059bf7050SPeter Avalos match_list_free(&(a->exclusions)); 25159bf7050SPeter Avalos entry_list_free(&(a->exclusion_entry_list)); 25259bf7050SPeter Avalos free(a->inclusion_uids.ids); 25359bf7050SPeter Avalos free(a->inclusion_gids.ids); 25459bf7050SPeter Avalos match_list_free(&(a->inclusion_unames)); 25559bf7050SPeter Avalos match_list_free(&(a->inclusion_gnames)); 25659bf7050SPeter Avalos free(a); 25759bf7050SPeter Avalos return (ARCHIVE_OK); 25859bf7050SPeter Avalos } 25959bf7050SPeter Avalos 26059bf7050SPeter Avalos /* 26159bf7050SPeter Avalos * Convenience function to perform all exclusion tests. 26259bf7050SPeter Avalos * 26359bf7050SPeter Avalos * Returns 1 if archive entry is excluded. 26459bf7050SPeter Avalos * Returns 0 if archive entry is not excluded. 26559bf7050SPeter Avalos * Returns <0 if something error happened. 26659bf7050SPeter Avalos */ 26759bf7050SPeter Avalos int 26859bf7050SPeter Avalos archive_match_excluded(struct archive *_a, struct archive_entry *entry) 26959bf7050SPeter Avalos { 27059bf7050SPeter Avalos struct archive_match *a; 27159bf7050SPeter Avalos int r; 27259bf7050SPeter Avalos 27359bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 27459bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_excluded_ae"); 27559bf7050SPeter Avalos 27659bf7050SPeter Avalos a = (struct archive_match *)_a; 27759bf7050SPeter Avalos if (entry == NULL) { 27859bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 27959bf7050SPeter Avalos return (ARCHIVE_FAILED); 28059bf7050SPeter Avalos } 28159bf7050SPeter Avalos 28259bf7050SPeter Avalos r = 0; 28359bf7050SPeter Avalos if (a->setflag & PATTERN_IS_SET) { 28459bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 28559bf7050SPeter Avalos r = path_excluded(a, 0, archive_entry_pathname_w(entry)); 28659bf7050SPeter Avalos #else 28759bf7050SPeter Avalos r = path_excluded(a, 1, archive_entry_pathname(entry)); 28859bf7050SPeter Avalos #endif 28959bf7050SPeter Avalos if (r != 0) 29059bf7050SPeter Avalos return (r); 29159bf7050SPeter Avalos } 29259bf7050SPeter Avalos 29359bf7050SPeter Avalos if (a->setflag & TIME_IS_SET) { 29459bf7050SPeter Avalos r = time_excluded(a, entry); 29559bf7050SPeter Avalos if (r != 0) 29659bf7050SPeter Avalos return (r); 29759bf7050SPeter Avalos } 29859bf7050SPeter Avalos 29959bf7050SPeter Avalos if (a->setflag & ID_IS_SET) 30059bf7050SPeter Avalos r = owner_excluded(a, entry); 30159bf7050SPeter Avalos return (r); 30259bf7050SPeter Avalos } 30359bf7050SPeter Avalos 30459bf7050SPeter Avalos /* 30559bf7050SPeter Avalos * Utility functions to manage exclusion/inclusion patterns 30659bf7050SPeter Avalos */ 30759bf7050SPeter Avalos 30859bf7050SPeter Avalos int 30959bf7050SPeter Avalos archive_match_exclude_pattern(struct archive *_a, const char *pattern) 31059bf7050SPeter Avalos { 31159bf7050SPeter Avalos struct archive_match *a; 31259bf7050SPeter Avalos int r; 31359bf7050SPeter Avalos 31459bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 31559bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_exclude_pattern"); 31659bf7050SPeter Avalos a = (struct archive_match *)_a; 31759bf7050SPeter Avalos 31859bf7050SPeter Avalos if (pattern == NULL || *pattern == '\0') { 31959bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 32059bf7050SPeter Avalos return (ARCHIVE_FAILED); 32159bf7050SPeter Avalos } 32259bf7050SPeter Avalos if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) 32359bf7050SPeter Avalos return (r); 32459bf7050SPeter Avalos return (ARCHIVE_OK); 32559bf7050SPeter Avalos } 32659bf7050SPeter Avalos 32759bf7050SPeter Avalos int 32859bf7050SPeter Avalos archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern) 32959bf7050SPeter Avalos { 33059bf7050SPeter Avalos struct archive_match *a; 33159bf7050SPeter Avalos int r; 33259bf7050SPeter Avalos 33359bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 33459bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w"); 33559bf7050SPeter Avalos a = (struct archive_match *)_a; 33659bf7050SPeter Avalos 33759bf7050SPeter Avalos if (pattern == NULL || *pattern == L'\0') { 33859bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 33959bf7050SPeter Avalos return (ARCHIVE_FAILED); 34059bf7050SPeter Avalos } 34159bf7050SPeter Avalos if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) 34259bf7050SPeter Avalos return (r); 34359bf7050SPeter Avalos return (ARCHIVE_OK); 34459bf7050SPeter Avalos } 34559bf7050SPeter Avalos 34659bf7050SPeter Avalos int 34759bf7050SPeter Avalos archive_match_exclude_pattern_from_file(struct archive *_a, 34859bf7050SPeter Avalos const char *pathname, int nullSeparator) 34959bf7050SPeter Avalos { 35059bf7050SPeter Avalos struct archive_match *a; 35159bf7050SPeter Avalos 35259bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 35359bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file"); 35459bf7050SPeter Avalos a = (struct archive_match *)_a; 35559bf7050SPeter Avalos 35659bf7050SPeter Avalos return add_pattern_from_file(a, &(a->exclusions), 1, pathname, 35759bf7050SPeter Avalos nullSeparator); 35859bf7050SPeter Avalos } 35959bf7050SPeter Avalos 36059bf7050SPeter Avalos int 36159bf7050SPeter Avalos archive_match_exclude_pattern_from_file_w(struct archive *_a, 36259bf7050SPeter Avalos const wchar_t *pathname, int nullSeparator) 36359bf7050SPeter Avalos { 36459bf7050SPeter Avalos struct archive_match *a; 36559bf7050SPeter Avalos 36659bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 36759bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w"); 36859bf7050SPeter Avalos a = (struct archive_match *)_a; 36959bf7050SPeter Avalos 37059bf7050SPeter Avalos return add_pattern_from_file(a, &(a->exclusions), 0, pathname, 37159bf7050SPeter Avalos nullSeparator); 37259bf7050SPeter Avalos } 37359bf7050SPeter Avalos 37459bf7050SPeter Avalos int 37559bf7050SPeter Avalos archive_match_include_pattern(struct archive *_a, const char *pattern) 37659bf7050SPeter Avalos { 37759bf7050SPeter Avalos struct archive_match *a; 37859bf7050SPeter Avalos int r; 37959bf7050SPeter Avalos 38059bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 38159bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_pattern"); 38259bf7050SPeter Avalos a = (struct archive_match *)_a; 38359bf7050SPeter Avalos 38459bf7050SPeter Avalos if (pattern == NULL || *pattern == '\0') { 38559bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 38659bf7050SPeter Avalos return (ARCHIVE_FAILED); 38759bf7050SPeter Avalos } 38859bf7050SPeter Avalos if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) 38959bf7050SPeter Avalos return (r); 39059bf7050SPeter Avalos return (ARCHIVE_OK); 39159bf7050SPeter Avalos } 39259bf7050SPeter Avalos 39359bf7050SPeter Avalos int 39459bf7050SPeter Avalos archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern) 39559bf7050SPeter Avalos { 39659bf7050SPeter Avalos struct archive_match *a; 39759bf7050SPeter Avalos int r; 39859bf7050SPeter Avalos 39959bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 40059bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_pattern_w"); 40159bf7050SPeter Avalos a = (struct archive_match *)_a; 40259bf7050SPeter Avalos 40359bf7050SPeter Avalos if (pattern == NULL || *pattern == L'\0') { 40459bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pattern is empty"); 40559bf7050SPeter Avalos return (ARCHIVE_FAILED); 40659bf7050SPeter Avalos } 40759bf7050SPeter Avalos if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) 40859bf7050SPeter Avalos return (r); 40959bf7050SPeter Avalos return (ARCHIVE_OK); 41059bf7050SPeter Avalos } 41159bf7050SPeter Avalos 41259bf7050SPeter Avalos int 41359bf7050SPeter Avalos archive_match_include_pattern_from_file(struct archive *_a, 41459bf7050SPeter Avalos const char *pathname, int nullSeparator) 41559bf7050SPeter Avalos { 41659bf7050SPeter Avalos struct archive_match *a; 41759bf7050SPeter Avalos 41859bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 41959bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file"); 42059bf7050SPeter Avalos a = (struct archive_match *)_a; 42159bf7050SPeter Avalos 42259bf7050SPeter Avalos return add_pattern_from_file(a, &(a->inclusions), 1, pathname, 42359bf7050SPeter Avalos nullSeparator); 42459bf7050SPeter Avalos } 42559bf7050SPeter Avalos 42659bf7050SPeter Avalos int 42759bf7050SPeter Avalos archive_match_include_pattern_from_file_w(struct archive *_a, 42859bf7050SPeter Avalos const wchar_t *pathname, int nullSeparator) 42959bf7050SPeter Avalos { 43059bf7050SPeter Avalos struct archive_match *a; 43159bf7050SPeter Avalos 43259bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 43359bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w"); 43459bf7050SPeter Avalos a = (struct archive_match *)_a; 43559bf7050SPeter Avalos 43659bf7050SPeter Avalos return add_pattern_from_file(a, &(a->inclusions), 0, pathname, 43759bf7050SPeter Avalos nullSeparator); 43859bf7050SPeter Avalos } 43959bf7050SPeter Avalos 44059bf7050SPeter Avalos /* 44159bf7050SPeter Avalos * Test functions for pathname patterns. 44259bf7050SPeter Avalos * 44359bf7050SPeter Avalos * Returns 1 if archive entry is excluded. 44459bf7050SPeter Avalos * Returns 0 if archive entry is not excluded. 44559bf7050SPeter Avalos * Returns <0 if something error happened. 44659bf7050SPeter Avalos */ 44759bf7050SPeter Avalos int 44859bf7050SPeter Avalos archive_match_path_excluded(struct archive *_a, 44959bf7050SPeter Avalos struct archive_entry *entry) 45059bf7050SPeter Avalos { 45159bf7050SPeter Avalos struct archive_match *a; 45259bf7050SPeter Avalos 45359bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 45459bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_path_excluded"); 45559bf7050SPeter Avalos 45659bf7050SPeter Avalos a = (struct archive_match *)_a; 45759bf7050SPeter Avalos if (entry == NULL) { 45859bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 45959bf7050SPeter Avalos return (ARCHIVE_FAILED); 46059bf7050SPeter Avalos } 46159bf7050SPeter Avalos 46259bf7050SPeter Avalos /* If we don't have exclusion/inclusion pattern set at all, 46359bf7050SPeter Avalos * the entry is always not excluded. */ 46459bf7050SPeter Avalos if ((a->setflag & PATTERN_IS_SET) == 0) 46559bf7050SPeter Avalos return (0); 46659bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 46759bf7050SPeter Avalos return (path_excluded(a, 0, archive_entry_pathname_w(entry))); 46859bf7050SPeter Avalos #else 46959bf7050SPeter Avalos return (path_excluded(a, 1, archive_entry_pathname(entry))); 47059bf7050SPeter Avalos #endif 47159bf7050SPeter Avalos } 47259bf7050SPeter Avalos 47359bf7050SPeter Avalos /* 47459bf7050SPeter Avalos * Utilty functions to get statistic information for inclusion patterns. 47559bf7050SPeter Avalos */ 47659bf7050SPeter Avalos int 47759bf7050SPeter Avalos archive_match_path_unmatched_inclusions(struct archive *_a) 47859bf7050SPeter Avalos { 47959bf7050SPeter Avalos struct archive_match *a; 48059bf7050SPeter Avalos 48159bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 48259bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions"); 48359bf7050SPeter Avalos a = (struct archive_match *)_a; 48459bf7050SPeter Avalos 48559bf7050SPeter Avalos return (a->inclusions.unmatched_count); 48659bf7050SPeter Avalos } 48759bf7050SPeter Avalos 48859bf7050SPeter Avalos int 48959bf7050SPeter Avalos archive_match_path_unmatched_inclusions_next(struct archive *_a, 49059bf7050SPeter Avalos const char **_p) 49159bf7050SPeter Avalos { 49259bf7050SPeter Avalos struct archive_match *a; 49359bf7050SPeter Avalos const void *v; 49459bf7050SPeter Avalos int r; 49559bf7050SPeter Avalos 49659bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 49759bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next"); 49859bf7050SPeter Avalos a = (struct archive_match *)_a; 49959bf7050SPeter Avalos 50059bf7050SPeter Avalos r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v); 50159bf7050SPeter Avalos *_p = (const char *)v; 50259bf7050SPeter Avalos return (r); 50359bf7050SPeter Avalos } 50459bf7050SPeter Avalos 50559bf7050SPeter Avalos int 50659bf7050SPeter Avalos archive_match_path_unmatched_inclusions_next_w(struct archive *_a, 50759bf7050SPeter Avalos const wchar_t **_p) 50859bf7050SPeter Avalos { 50959bf7050SPeter Avalos struct archive_match *a; 51059bf7050SPeter Avalos const void *v; 51159bf7050SPeter Avalos int r; 51259bf7050SPeter Avalos 51359bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 51459bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w"); 51559bf7050SPeter Avalos a = (struct archive_match *)_a; 51659bf7050SPeter Avalos 51759bf7050SPeter Avalos r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v); 51859bf7050SPeter Avalos *_p = (const wchar_t *)v; 51959bf7050SPeter Avalos return (r); 52059bf7050SPeter Avalos } 52159bf7050SPeter Avalos 52259bf7050SPeter Avalos /* 52359bf7050SPeter Avalos * Add inclusion/exclusion patterns. 52459bf7050SPeter Avalos */ 52559bf7050SPeter Avalos static int 52659bf7050SPeter Avalos add_pattern_mbs(struct archive_match *a, struct match_list *list, 52759bf7050SPeter Avalos const char *pattern) 52859bf7050SPeter Avalos { 52959bf7050SPeter Avalos struct match *match; 53059bf7050SPeter Avalos size_t len; 53159bf7050SPeter Avalos 53259bf7050SPeter Avalos match = calloc(1, sizeof(*match)); 53359bf7050SPeter Avalos if (match == NULL) 53459bf7050SPeter Avalos return (error_nomem(a)); 53559bf7050SPeter Avalos /* Both "foo/" and "foo" should match "foo/bar". */ 53659bf7050SPeter Avalos len = strlen(pattern); 53759bf7050SPeter Avalos if (len && pattern[len - 1] == '/') 53859bf7050SPeter Avalos --len; 53959bf7050SPeter Avalos archive_mstring_copy_mbs_len(&(match->pattern), pattern, len); 54059bf7050SPeter Avalos match_list_add(list, match); 54159bf7050SPeter Avalos a->setflag |= PATTERN_IS_SET; 54259bf7050SPeter Avalos return (ARCHIVE_OK); 54359bf7050SPeter Avalos } 54459bf7050SPeter Avalos 54559bf7050SPeter Avalos static int 54659bf7050SPeter Avalos add_pattern_wcs(struct archive_match *a, struct match_list *list, 54759bf7050SPeter Avalos const wchar_t *pattern) 54859bf7050SPeter Avalos { 54959bf7050SPeter Avalos struct match *match; 55059bf7050SPeter Avalos size_t len; 55159bf7050SPeter Avalos 55259bf7050SPeter Avalos match = calloc(1, sizeof(*match)); 55359bf7050SPeter Avalos if (match == NULL) 55459bf7050SPeter Avalos return (error_nomem(a)); 55559bf7050SPeter Avalos /* Both "foo/" and "foo" should match "foo/bar". */ 55659bf7050SPeter Avalos len = wcslen(pattern); 55759bf7050SPeter Avalos if (len && pattern[len - 1] == L'/') 55859bf7050SPeter Avalos --len; 55959bf7050SPeter Avalos archive_mstring_copy_wcs_len(&(match->pattern), pattern, len); 56059bf7050SPeter Avalos match_list_add(list, match); 56159bf7050SPeter Avalos a->setflag |= PATTERN_IS_SET; 56259bf7050SPeter Avalos return (ARCHIVE_OK); 56359bf7050SPeter Avalos } 56459bf7050SPeter Avalos 56559bf7050SPeter Avalos static int 56659bf7050SPeter Avalos add_pattern_from_file(struct archive_match *a, struct match_list *mlist, 56759bf7050SPeter Avalos int mbs, const void *pathname, int nullSeparator) 56859bf7050SPeter Avalos { 56959bf7050SPeter Avalos struct archive *ar; 57059bf7050SPeter Avalos struct archive_entry *ae; 57159bf7050SPeter Avalos struct archive_string as; 57259bf7050SPeter Avalos const void *buff; 57359bf7050SPeter Avalos size_t size; 57459bf7050SPeter Avalos int64_t offset; 57559bf7050SPeter Avalos int r; 57659bf7050SPeter Avalos 57759bf7050SPeter Avalos ar = archive_read_new(); 57859bf7050SPeter Avalos if (ar == NULL) { 57959bf7050SPeter Avalos archive_set_error(&(a->archive), ENOMEM, "No memory"); 58059bf7050SPeter Avalos return (ARCHIVE_FATAL); 58159bf7050SPeter Avalos } 58259bf7050SPeter Avalos r = archive_read_support_format_raw(ar); 583*6b384f39SPeter Avalos r = archive_read_support_format_empty(ar); 58459bf7050SPeter Avalos if (r != ARCHIVE_OK) { 58559bf7050SPeter Avalos archive_copy_error(&(a->archive), ar); 58659bf7050SPeter Avalos archive_read_free(ar); 58759bf7050SPeter Avalos return (r); 58859bf7050SPeter Avalos } 58959bf7050SPeter Avalos if (mbs) 59059bf7050SPeter Avalos r = archive_read_open_filename(ar, pathname, 512*20); 59159bf7050SPeter Avalos else 59259bf7050SPeter Avalos r = archive_read_open_filename_w(ar, pathname, 512*20); 59359bf7050SPeter Avalos if (r != ARCHIVE_OK) { 59459bf7050SPeter Avalos archive_copy_error(&(a->archive), ar); 59559bf7050SPeter Avalos archive_read_free(ar); 59659bf7050SPeter Avalos return (r); 59759bf7050SPeter Avalos } 59859bf7050SPeter Avalos r = archive_read_next_header(ar, &ae); 59959bf7050SPeter Avalos if (r != ARCHIVE_OK) { 60059bf7050SPeter Avalos archive_read_free(ar); 601*6b384f39SPeter Avalos if (r == ARCHIVE_EOF) { 602*6b384f39SPeter Avalos return (ARCHIVE_OK); 603*6b384f39SPeter Avalos } else { 604*6b384f39SPeter Avalos archive_copy_error(&(a->archive), ar); 60559bf7050SPeter Avalos return (r); 60659bf7050SPeter Avalos } 607*6b384f39SPeter Avalos } 60859bf7050SPeter Avalos 60959bf7050SPeter Avalos archive_string_init(&as); 61059bf7050SPeter Avalos 61159bf7050SPeter Avalos while ((r = archive_read_data_block(ar, &buff, &size, &offset)) 61259bf7050SPeter Avalos == ARCHIVE_OK) { 61359bf7050SPeter Avalos const char *b = (const char *)buff; 61459bf7050SPeter Avalos 61559bf7050SPeter Avalos while (size) { 61659bf7050SPeter Avalos const char *s = (const char *)b; 61759bf7050SPeter Avalos size_t length = 0; 61859bf7050SPeter Avalos int found_separator = 0; 61959bf7050SPeter Avalos 62059bf7050SPeter Avalos while (length < size) { 62159bf7050SPeter Avalos if (nullSeparator) { 62259bf7050SPeter Avalos if (*b == '\0') { 62359bf7050SPeter Avalos found_separator = 1; 62459bf7050SPeter Avalos break; 62559bf7050SPeter Avalos } 62659bf7050SPeter Avalos } else { 62759bf7050SPeter Avalos if (*b == 0x0d || *b == 0x0a) { 62859bf7050SPeter Avalos found_separator = 1; 62959bf7050SPeter Avalos break; 63059bf7050SPeter Avalos } 63159bf7050SPeter Avalos } 63259bf7050SPeter Avalos b++; 63359bf7050SPeter Avalos length++; 63459bf7050SPeter Avalos } 63559bf7050SPeter Avalos if (!found_separator) { 63659bf7050SPeter Avalos archive_strncat(&as, s, length); 63759bf7050SPeter Avalos /* Read next data block. */ 63859bf7050SPeter Avalos break; 63959bf7050SPeter Avalos } 64059bf7050SPeter Avalos b++; 64159bf7050SPeter Avalos size -= length + 1; 64259bf7050SPeter Avalos archive_strncat(&as, s, length); 64359bf7050SPeter Avalos 64459bf7050SPeter Avalos /* If the line is not empty, add the pattern. */ 64559bf7050SPeter Avalos if (archive_strlen(&as) > 0) { 64659bf7050SPeter Avalos /* Add pattern. */ 64759bf7050SPeter Avalos r = add_pattern_mbs(a, mlist, as.s); 64859bf7050SPeter Avalos if (r != ARCHIVE_OK) { 64959bf7050SPeter Avalos archive_read_free(ar); 65059bf7050SPeter Avalos archive_string_free(&as); 65159bf7050SPeter Avalos return (r); 65259bf7050SPeter Avalos } 65359bf7050SPeter Avalos archive_string_empty(&as); 65459bf7050SPeter Avalos } 65559bf7050SPeter Avalos } 65659bf7050SPeter Avalos } 65759bf7050SPeter Avalos 65859bf7050SPeter Avalos /* If something error happend, report it immediately. */ 65959bf7050SPeter Avalos if (r < ARCHIVE_OK) { 66059bf7050SPeter Avalos archive_copy_error(&(a->archive), ar); 66159bf7050SPeter Avalos archive_read_free(ar); 66259bf7050SPeter Avalos archive_string_free(&as); 66359bf7050SPeter Avalos return (r); 66459bf7050SPeter Avalos } 66559bf7050SPeter Avalos 66659bf7050SPeter Avalos /* If the line is not empty, add the pattern. */ 66759bf7050SPeter Avalos if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { 66859bf7050SPeter Avalos /* Add pattern. */ 66959bf7050SPeter Avalos r = add_pattern_mbs(a, mlist, as.s); 67059bf7050SPeter Avalos if (r != ARCHIVE_OK) { 67159bf7050SPeter Avalos archive_read_free(ar); 67259bf7050SPeter Avalos archive_string_free(&as); 67359bf7050SPeter Avalos return (r); 67459bf7050SPeter Avalos } 67559bf7050SPeter Avalos } 67659bf7050SPeter Avalos archive_read_free(ar); 67759bf7050SPeter Avalos archive_string_free(&as); 67859bf7050SPeter Avalos return (ARCHIVE_OK); 67959bf7050SPeter Avalos } 68059bf7050SPeter Avalos 68159bf7050SPeter Avalos /* 68259bf7050SPeter Avalos * Test if pathname is excluded by inclusion/exclusion patterns. 68359bf7050SPeter Avalos */ 68459bf7050SPeter Avalos static int 68559bf7050SPeter Avalos path_excluded(struct archive_match *a, int mbs, const void *pathname) 68659bf7050SPeter Avalos { 68759bf7050SPeter Avalos struct match *match; 68859bf7050SPeter Avalos struct match *matched; 68959bf7050SPeter Avalos int r; 69059bf7050SPeter Avalos 69159bf7050SPeter Avalos if (a == NULL) 69259bf7050SPeter Avalos return (0); 69359bf7050SPeter Avalos 69459bf7050SPeter Avalos /* Mark off any unmatched inclusions. */ 69559bf7050SPeter Avalos /* In particular, if a filename does appear in the archive and 69659bf7050SPeter Avalos * is explicitly included and excluded, then we don't report 69759bf7050SPeter Avalos * it as missing even though we don't extract it. 69859bf7050SPeter Avalos */ 69959bf7050SPeter Avalos matched = NULL; 70059bf7050SPeter Avalos for (match = a->inclusions.first; match != NULL; 70159bf7050SPeter Avalos match = match->next){ 70259bf7050SPeter Avalos if (match->matches == 0 && 70359bf7050SPeter Avalos (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 70459bf7050SPeter Avalos if (r < 0) 70559bf7050SPeter Avalos return (r); 70659bf7050SPeter Avalos a->inclusions.unmatched_count--; 70759bf7050SPeter Avalos match->matches++; 70859bf7050SPeter Avalos matched = match; 70959bf7050SPeter Avalos } 71059bf7050SPeter Avalos } 71159bf7050SPeter Avalos 71259bf7050SPeter Avalos /* Exclusions take priority */ 71359bf7050SPeter Avalos for (match = a->exclusions.first; match != NULL; 71459bf7050SPeter Avalos match = match->next){ 71559bf7050SPeter Avalos r = match_path_exclusion(a, match, mbs, pathname); 71659bf7050SPeter Avalos if (r) 71759bf7050SPeter Avalos return (r); 71859bf7050SPeter Avalos } 71959bf7050SPeter Avalos 72059bf7050SPeter Avalos /* It's not excluded and we found an inclusion above, so it's 72159bf7050SPeter Avalos * included. */ 72259bf7050SPeter Avalos if (matched != NULL) 72359bf7050SPeter Avalos return (0); 72459bf7050SPeter Avalos 72559bf7050SPeter Avalos 72659bf7050SPeter Avalos /* We didn't find an unmatched inclusion, check the remaining ones. */ 72759bf7050SPeter Avalos for (match = a->inclusions.first; match != NULL; 72859bf7050SPeter Avalos match = match->next){ 72959bf7050SPeter Avalos /* We looked at previously-unmatched inclusions already. */ 73059bf7050SPeter Avalos if (match->matches > 0 && 73159bf7050SPeter Avalos (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { 73259bf7050SPeter Avalos if (r < 0) 73359bf7050SPeter Avalos return (r); 73459bf7050SPeter Avalos match->matches++; 73559bf7050SPeter Avalos return (0); 73659bf7050SPeter Avalos } 73759bf7050SPeter Avalos } 73859bf7050SPeter Avalos 73959bf7050SPeter Avalos /* If there were inclusions, default is to exclude. */ 74059bf7050SPeter Avalos if (a->inclusions.first != NULL) 74159bf7050SPeter Avalos return (1); 74259bf7050SPeter Avalos 74359bf7050SPeter Avalos /* No explicit inclusions, default is to match. */ 74459bf7050SPeter Avalos return (0); 74559bf7050SPeter Avalos } 74659bf7050SPeter Avalos 74759bf7050SPeter Avalos /* 74859bf7050SPeter Avalos * This is a little odd, but it matches the default behavior of 74959bf7050SPeter Avalos * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' 75059bf7050SPeter Avalos * 75159bf7050SPeter Avalos */ 75259bf7050SPeter Avalos static int 75359bf7050SPeter Avalos match_path_exclusion(struct archive_match *a, struct match *m, 75459bf7050SPeter Avalos int mbs, const void *pn) 75559bf7050SPeter Avalos { 75659bf7050SPeter Avalos int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END; 75759bf7050SPeter Avalos int r; 75859bf7050SPeter Avalos 75959bf7050SPeter Avalos if (mbs) { 76059bf7050SPeter Avalos const char *p; 76159bf7050SPeter Avalos r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 76259bf7050SPeter Avalos if (r == 0) 76359bf7050SPeter Avalos return (archive_pathmatch(p, (const char *)pn, flag)); 76459bf7050SPeter Avalos } else { 76559bf7050SPeter Avalos const wchar_t *p; 76659bf7050SPeter Avalos r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 76759bf7050SPeter Avalos if (r == 0) 76859bf7050SPeter Avalos return (archive_pathmatch_w(p, (const wchar_t *)pn, 76959bf7050SPeter Avalos flag)); 77059bf7050SPeter Avalos } 77159bf7050SPeter Avalos if (errno == ENOMEM) 77259bf7050SPeter Avalos return (error_nomem(a)); 77359bf7050SPeter Avalos return (0); 77459bf7050SPeter Avalos } 77559bf7050SPeter Avalos 77659bf7050SPeter Avalos /* 77759bf7050SPeter Avalos * Again, mimic gtar: inclusions are always anchored (have to match 77859bf7050SPeter Avalos * the beginning of the path) even though exclusions are not anchored. 77959bf7050SPeter Avalos */ 78059bf7050SPeter Avalos static int 78159bf7050SPeter Avalos match_path_inclusion(struct archive_match *a, struct match *m, 78259bf7050SPeter Avalos int mbs, const void *pn) 78359bf7050SPeter Avalos { 78459bf7050SPeter Avalos int flag = PATHMATCH_NO_ANCHOR_END; 78559bf7050SPeter Avalos int r; 78659bf7050SPeter Avalos 78759bf7050SPeter Avalos if (mbs) { 78859bf7050SPeter Avalos const char *p; 78959bf7050SPeter Avalos r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); 79059bf7050SPeter Avalos if (r == 0) 79159bf7050SPeter Avalos return (archive_pathmatch(p, (const char *)pn, flag)); 79259bf7050SPeter Avalos } else { 79359bf7050SPeter Avalos const wchar_t *p; 79459bf7050SPeter Avalos r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); 79559bf7050SPeter Avalos if (r == 0) 79659bf7050SPeter Avalos return (archive_pathmatch_w(p, (const wchar_t *)pn, 79759bf7050SPeter Avalos flag)); 79859bf7050SPeter Avalos } 79959bf7050SPeter Avalos if (errno == ENOMEM) 80059bf7050SPeter Avalos return (error_nomem(a)); 80159bf7050SPeter Avalos return (0); 80259bf7050SPeter Avalos } 80359bf7050SPeter Avalos 80459bf7050SPeter Avalos static void 80559bf7050SPeter Avalos match_list_init(struct match_list *list) 80659bf7050SPeter Avalos { 80759bf7050SPeter Avalos list->first = NULL; 80859bf7050SPeter Avalos list->last = &(list->first); 80959bf7050SPeter Avalos list->count = 0; 81059bf7050SPeter Avalos } 81159bf7050SPeter Avalos 81259bf7050SPeter Avalos static void 81359bf7050SPeter Avalos match_list_free(struct match_list *list) 81459bf7050SPeter Avalos { 81559bf7050SPeter Avalos struct match *p, *q; 81659bf7050SPeter Avalos 81759bf7050SPeter Avalos for (p = list->first; p != NULL; ) { 81859bf7050SPeter Avalos q = p; 81959bf7050SPeter Avalos p = p->next; 82059bf7050SPeter Avalos archive_mstring_clean(&(q->pattern)); 82159bf7050SPeter Avalos free(q); 82259bf7050SPeter Avalos } 82359bf7050SPeter Avalos } 82459bf7050SPeter Avalos 82559bf7050SPeter Avalos static void 82659bf7050SPeter Avalos match_list_add(struct match_list *list, struct match *m) 82759bf7050SPeter Avalos { 82859bf7050SPeter Avalos *list->last = m; 82959bf7050SPeter Avalos list->last = &(m->next); 83059bf7050SPeter Avalos list->count++; 83159bf7050SPeter Avalos list->unmatched_count++; 83259bf7050SPeter Avalos } 83359bf7050SPeter Avalos 83459bf7050SPeter Avalos static int 83559bf7050SPeter Avalos match_list_unmatched_inclusions_next(struct archive_match *a, 83659bf7050SPeter Avalos struct match_list *list, int mbs, const void **vp) 83759bf7050SPeter Avalos { 83859bf7050SPeter Avalos struct match *m; 83959bf7050SPeter Avalos 84059bf7050SPeter Avalos *vp = NULL; 84159bf7050SPeter Avalos if (list->unmatched_eof) { 84259bf7050SPeter Avalos list->unmatched_eof = 0; 84359bf7050SPeter Avalos return (ARCHIVE_EOF); 84459bf7050SPeter Avalos } 84559bf7050SPeter Avalos if (list->unmatched_next == NULL) { 84659bf7050SPeter Avalos if (list->unmatched_count == 0) 84759bf7050SPeter Avalos return (ARCHIVE_EOF); 84859bf7050SPeter Avalos list->unmatched_next = list->first; 84959bf7050SPeter Avalos } 85059bf7050SPeter Avalos 85159bf7050SPeter Avalos for (m = list->unmatched_next; m != NULL; m = m->next) { 85259bf7050SPeter Avalos int r; 85359bf7050SPeter Avalos 85459bf7050SPeter Avalos if (m->matches) 85559bf7050SPeter Avalos continue; 85659bf7050SPeter Avalos if (mbs) { 85759bf7050SPeter Avalos const char *p; 85859bf7050SPeter Avalos r = archive_mstring_get_mbs(&(a->archive), 85959bf7050SPeter Avalos &(m->pattern), &p); 86059bf7050SPeter Avalos if (r < 0 && errno == ENOMEM) 86159bf7050SPeter Avalos return (error_nomem(a)); 86259bf7050SPeter Avalos if (p == NULL) 86359bf7050SPeter Avalos p = ""; 86459bf7050SPeter Avalos *vp = p; 86559bf7050SPeter Avalos } else { 86659bf7050SPeter Avalos const wchar_t *p; 86759bf7050SPeter Avalos r = archive_mstring_get_wcs(&(a->archive), 86859bf7050SPeter Avalos &(m->pattern), &p); 86959bf7050SPeter Avalos if (r < 0 && errno == ENOMEM) 87059bf7050SPeter Avalos return (error_nomem(a)); 87159bf7050SPeter Avalos if (p == NULL) 87259bf7050SPeter Avalos p = L""; 87359bf7050SPeter Avalos *vp = p; 87459bf7050SPeter Avalos } 87559bf7050SPeter Avalos list->unmatched_next = m->next; 87659bf7050SPeter Avalos if (list->unmatched_next == NULL) 87759bf7050SPeter Avalos /* To return EOF next time. */ 87859bf7050SPeter Avalos list->unmatched_eof = 1; 87959bf7050SPeter Avalos return (ARCHIVE_OK); 88059bf7050SPeter Avalos } 88159bf7050SPeter Avalos list->unmatched_next = NULL; 88259bf7050SPeter Avalos return (ARCHIVE_EOF); 88359bf7050SPeter Avalos } 88459bf7050SPeter Avalos 88559bf7050SPeter Avalos /* 88659bf7050SPeter Avalos * Utility functions to manage inclusion timestamps. 88759bf7050SPeter Avalos */ 88859bf7050SPeter Avalos int 88959bf7050SPeter Avalos archive_match_include_time(struct archive *_a, int flag, time_t sec, 89059bf7050SPeter Avalos long nsec) 89159bf7050SPeter Avalos { 89259bf7050SPeter Avalos int r; 89359bf7050SPeter Avalos 89459bf7050SPeter Avalos r = validate_time_flag(_a, flag, "archive_match_include_time"); 89559bf7050SPeter Avalos if (r != ARCHIVE_OK) 89659bf7050SPeter Avalos return (r); 89759bf7050SPeter Avalos return set_timefilter((struct archive_match *)_a, flag, 89859bf7050SPeter Avalos sec, nsec, sec, nsec); 89959bf7050SPeter Avalos } 90059bf7050SPeter Avalos 90159bf7050SPeter Avalos int 90259bf7050SPeter Avalos archive_match_include_date(struct archive *_a, int flag, 90359bf7050SPeter Avalos const char *datestr) 90459bf7050SPeter Avalos { 90559bf7050SPeter Avalos int r; 90659bf7050SPeter Avalos 90759bf7050SPeter Avalos r = validate_time_flag(_a, flag, "archive_match_include_date"); 90859bf7050SPeter Avalos if (r != ARCHIVE_OK) 90959bf7050SPeter Avalos return (r); 91059bf7050SPeter Avalos return set_timefilter_date((struct archive_match *)_a, flag, datestr); 91159bf7050SPeter Avalos } 91259bf7050SPeter Avalos 91359bf7050SPeter Avalos int 91459bf7050SPeter Avalos archive_match_include_date_w(struct archive *_a, int flag, 91559bf7050SPeter Avalos const wchar_t *datestr) 91659bf7050SPeter Avalos { 91759bf7050SPeter Avalos int r; 91859bf7050SPeter Avalos 91959bf7050SPeter Avalos r = validate_time_flag(_a, flag, "archive_match_include_date_w"); 92059bf7050SPeter Avalos if (r != ARCHIVE_OK) 92159bf7050SPeter Avalos return (r); 92259bf7050SPeter Avalos 92359bf7050SPeter Avalos return set_timefilter_date_w((struct archive_match *)_a, flag, datestr); 92459bf7050SPeter Avalos } 92559bf7050SPeter Avalos 92659bf7050SPeter Avalos int 92759bf7050SPeter Avalos archive_match_include_file_time(struct archive *_a, int flag, 92859bf7050SPeter Avalos const char *pathname) 92959bf7050SPeter Avalos { 93059bf7050SPeter Avalos int r; 93159bf7050SPeter Avalos 93259bf7050SPeter Avalos r = validate_time_flag(_a, flag, "archive_match_include_file_time"); 93359bf7050SPeter Avalos if (r != ARCHIVE_OK) 93459bf7050SPeter Avalos return (r); 93559bf7050SPeter Avalos return set_timefilter_pathname_mbs((struct archive_match *)_a, 93659bf7050SPeter Avalos flag, pathname); 93759bf7050SPeter Avalos } 93859bf7050SPeter Avalos 93959bf7050SPeter Avalos int 94059bf7050SPeter Avalos archive_match_include_file_time_w(struct archive *_a, int flag, 94159bf7050SPeter Avalos const wchar_t *pathname) 94259bf7050SPeter Avalos { 94359bf7050SPeter Avalos int r; 94459bf7050SPeter Avalos 94559bf7050SPeter Avalos r = validate_time_flag(_a, flag, "archive_match_include_file_time_w"); 94659bf7050SPeter Avalos if (r != ARCHIVE_OK) 94759bf7050SPeter Avalos return (r); 94859bf7050SPeter Avalos return set_timefilter_pathname_wcs((struct archive_match *)_a, 94959bf7050SPeter Avalos flag, pathname); 95059bf7050SPeter Avalos } 95159bf7050SPeter Avalos 95259bf7050SPeter Avalos int 95359bf7050SPeter Avalos archive_match_exclude_entry(struct archive *_a, int flag, 95459bf7050SPeter Avalos struct archive_entry *entry) 95559bf7050SPeter Avalos { 95659bf7050SPeter Avalos struct archive_match *a; 95759bf7050SPeter Avalos int r; 95859bf7050SPeter Avalos 95959bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 96059bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_time_include_entry"); 96159bf7050SPeter Avalos a = (struct archive_match *)_a; 96259bf7050SPeter Avalos 96359bf7050SPeter Avalos if (entry == NULL) { 96459bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 96559bf7050SPeter Avalos return (ARCHIVE_FAILED); 96659bf7050SPeter Avalos } 96759bf7050SPeter Avalos r = validate_time_flag(_a, flag, "archive_match_exclude_entry"); 96859bf7050SPeter Avalos if (r != ARCHIVE_OK) 96959bf7050SPeter Avalos return (r); 97059bf7050SPeter Avalos return (add_entry(a, flag, entry)); 97159bf7050SPeter Avalos } 97259bf7050SPeter Avalos 97359bf7050SPeter Avalos /* 97459bf7050SPeter Avalos * Test function for time stamps. 97559bf7050SPeter Avalos * 97659bf7050SPeter Avalos * Returns 1 if archive entry is excluded. 97759bf7050SPeter Avalos * Returns 0 if archive entry is not excluded. 97859bf7050SPeter Avalos * Returns <0 if something error happened. 97959bf7050SPeter Avalos */ 98059bf7050SPeter Avalos int 98159bf7050SPeter Avalos archive_match_time_excluded(struct archive *_a, 98259bf7050SPeter Avalos struct archive_entry *entry) 98359bf7050SPeter Avalos { 98459bf7050SPeter Avalos struct archive_match *a; 98559bf7050SPeter Avalos 98659bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 98759bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae"); 98859bf7050SPeter Avalos 98959bf7050SPeter Avalos a = (struct archive_match *)_a; 99059bf7050SPeter Avalos if (entry == NULL) { 99159bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 99259bf7050SPeter Avalos return (ARCHIVE_FAILED); 99359bf7050SPeter Avalos } 99459bf7050SPeter Avalos 99559bf7050SPeter Avalos /* If we don't have inclusion time set at all, the entry is always 99659bf7050SPeter Avalos * not excluded. */ 99759bf7050SPeter Avalos if ((a->setflag & TIME_IS_SET) == 0) 99859bf7050SPeter Avalos return (0); 99959bf7050SPeter Avalos return (time_excluded(a, entry)); 100059bf7050SPeter Avalos } 100159bf7050SPeter Avalos 100259bf7050SPeter Avalos static int 100359bf7050SPeter Avalos validate_time_flag(struct archive *_a, int flag, const char *_fn) 100459bf7050SPeter Avalos { 100559bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 100659bf7050SPeter Avalos ARCHIVE_STATE_NEW, _fn); 100759bf7050SPeter Avalos 100859bf7050SPeter Avalos /* Check a type of time. */ 100959bf7050SPeter Avalos if (flag & 101059bf7050SPeter Avalos ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) { 101159bf7050SPeter Avalos archive_set_error(_a, EINVAL, "Invalid time flag"); 101259bf7050SPeter Avalos return (ARCHIVE_FAILED); 101359bf7050SPeter Avalos } 101459bf7050SPeter Avalos if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) { 101559bf7050SPeter Avalos archive_set_error(_a, EINVAL, "No time flag"); 101659bf7050SPeter Avalos return (ARCHIVE_FAILED); 101759bf7050SPeter Avalos } 101859bf7050SPeter Avalos 101959bf7050SPeter Avalos /* Check a type of comparison. */ 102059bf7050SPeter Avalos if (flag & 102159bf7050SPeter Avalos ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 102259bf7050SPeter Avalos | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) { 102359bf7050SPeter Avalos archive_set_error(_a, EINVAL, "Invalid comparison flag"); 102459bf7050SPeter Avalos return (ARCHIVE_FAILED); 102559bf7050SPeter Avalos } 102659bf7050SPeter Avalos if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER 102759bf7050SPeter Avalos | ARCHIVE_MATCH_EQUAL)) == 0) { 102859bf7050SPeter Avalos archive_set_error(_a, EINVAL, "No comparison flag"); 102959bf7050SPeter Avalos return (ARCHIVE_FAILED); 103059bf7050SPeter Avalos } 103159bf7050SPeter Avalos 103259bf7050SPeter Avalos return (ARCHIVE_OK); 103359bf7050SPeter Avalos } 103459bf7050SPeter Avalos 103559bf7050SPeter Avalos #define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\ 103659bf7050SPeter Avalos ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL) 103759bf7050SPeter Avalos static int 103859bf7050SPeter Avalos set_timefilter(struct archive_match *a, int timetype, 103959bf7050SPeter Avalos time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec) 104059bf7050SPeter Avalos { 104159bf7050SPeter Avalos if (timetype & ARCHIVE_MATCH_MTIME) { 104259bf7050SPeter Avalos if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 104359bf7050SPeter Avalos a->newer_mtime_filter = timetype; 104459bf7050SPeter Avalos a->newer_mtime_sec = mtime_sec; 104559bf7050SPeter Avalos a->newer_mtime_nsec = mtime_nsec; 104659bf7050SPeter Avalos a->setflag |= TIME_IS_SET; 104759bf7050SPeter Avalos } 104859bf7050SPeter Avalos if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 104959bf7050SPeter Avalos a->older_mtime_filter = timetype; 105059bf7050SPeter Avalos a->older_mtime_sec = mtime_sec; 105159bf7050SPeter Avalos a->older_mtime_nsec = mtime_nsec; 105259bf7050SPeter Avalos a->setflag |= TIME_IS_SET; 105359bf7050SPeter Avalos } 105459bf7050SPeter Avalos } 105559bf7050SPeter Avalos if (timetype & ARCHIVE_MATCH_CTIME) { 105659bf7050SPeter Avalos if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { 105759bf7050SPeter Avalos a->newer_ctime_filter = timetype; 105859bf7050SPeter Avalos a->newer_ctime_sec = ctime_sec; 105959bf7050SPeter Avalos a->newer_ctime_nsec = ctime_nsec; 106059bf7050SPeter Avalos a->setflag |= TIME_IS_SET; 106159bf7050SPeter Avalos } 106259bf7050SPeter Avalos if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { 106359bf7050SPeter Avalos a->older_ctime_filter = timetype; 106459bf7050SPeter Avalos a->older_ctime_sec = ctime_sec; 106559bf7050SPeter Avalos a->older_ctime_nsec = ctime_nsec; 106659bf7050SPeter Avalos a->setflag |= TIME_IS_SET; 106759bf7050SPeter Avalos } 106859bf7050SPeter Avalos } 106959bf7050SPeter Avalos return (ARCHIVE_OK); 107059bf7050SPeter Avalos } 107159bf7050SPeter Avalos 107259bf7050SPeter Avalos static int 107359bf7050SPeter Avalos set_timefilter_date(struct archive_match *a, int timetype, const char *datestr) 107459bf7050SPeter Avalos { 107559bf7050SPeter Avalos time_t t; 107659bf7050SPeter Avalos 107759bf7050SPeter Avalos if (datestr == NULL || *datestr == '\0') { 107859bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "date is empty"); 107959bf7050SPeter Avalos return (ARCHIVE_FAILED); 108059bf7050SPeter Avalos } 108159bf7050SPeter Avalos t = get_date(a->now, datestr); 108259bf7050SPeter Avalos if (t == (time_t)-1) { 108359bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "invalid date string"); 108459bf7050SPeter Avalos return (ARCHIVE_FAILED); 108559bf7050SPeter Avalos } 108659bf7050SPeter Avalos return set_timefilter(a, timetype, t, 0, t, 0); 108759bf7050SPeter Avalos } 108859bf7050SPeter Avalos 108959bf7050SPeter Avalos static int 109059bf7050SPeter Avalos set_timefilter_date_w(struct archive_match *a, int timetype, 109159bf7050SPeter Avalos const wchar_t *datestr) 109259bf7050SPeter Avalos { 109359bf7050SPeter Avalos struct archive_string as; 109459bf7050SPeter Avalos time_t t; 109559bf7050SPeter Avalos 109659bf7050SPeter Avalos if (datestr == NULL || *datestr == L'\0') { 109759bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "date is empty"); 109859bf7050SPeter Avalos return (ARCHIVE_FAILED); 109959bf7050SPeter Avalos } 110059bf7050SPeter Avalos 110159bf7050SPeter Avalos archive_string_init(&as); 110259bf7050SPeter Avalos if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { 110359bf7050SPeter Avalos archive_string_free(&as); 110459bf7050SPeter Avalos if (errno == ENOMEM) 110559bf7050SPeter Avalos return (error_nomem(a)); 110659bf7050SPeter Avalos archive_set_error(&(a->archive), -1, 110759bf7050SPeter Avalos "Failed to convert WCS to MBS"); 110859bf7050SPeter Avalos return (ARCHIVE_FAILED); 110959bf7050SPeter Avalos } 111059bf7050SPeter Avalos t = get_date(a->now, as.s); 111159bf7050SPeter Avalos archive_string_free(&as); 111259bf7050SPeter Avalos if (t == (time_t)-1) { 111359bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "invalid date string"); 111459bf7050SPeter Avalos return (ARCHIVE_FAILED); 111559bf7050SPeter Avalos } 111659bf7050SPeter Avalos return set_timefilter(a, timetype, t, 0, t, 0); 111759bf7050SPeter Avalos } 111859bf7050SPeter Avalos 111959bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 112059bf7050SPeter Avalos #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) 112159bf7050SPeter Avalos static int 112259bf7050SPeter Avalos set_timefilter_find_data(struct archive_match *a, int timetype, 112359bf7050SPeter Avalos DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, 112459bf7050SPeter Avalos DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) 112559bf7050SPeter Avalos { 112659bf7050SPeter Avalos ULARGE_INTEGER utc; 112759bf7050SPeter Avalos time_t ctime_sec, mtime_sec; 112859bf7050SPeter Avalos long ctime_ns, mtime_ns; 112959bf7050SPeter Avalos 113059bf7050SPeter Avalos utc.HighPart = ftCreationTime_dwHighDateTime; 113159bf7050SPeter Avalos utc.LowPart = ftCreationTime_dwLowDateTime; 113259bf7050SPeter Avalos if (utc.QuadPart >= EPOC_TIME) { 113359bf7050SPeter Avalos utc.QuadPart -= EPOC_TIME; 113459bf7050SPeter Avalos ctime_sec = (time_t)(utc.QuadPart / 10000000); 113559bf7050SPeter Avalos ctime_ns = (long)(utc.QuadPart % 10000000) * 100; 113659bf7050SPeter Avalos } else { 113759bf7050SPeter Avalos ctime_sec = 0; 113859bf7050SPeter Avalos ctime_ns = 0; 113959bf7050SPeter Avalos } 114059bf7050SPeter Avalos utc.HighPart = ftLastWriteTime_dwHighDateTime; 114159bf7050SPeter Avalos utc.LowPart = ftLastWriteTime_dwLowDateTime; 114259bf7050SPeter Avalos if (utc.QuadPart >= EPOC_TIME) { 114359bf7050SPeter Avalos utc.QuadPart -= EPOC_TIME; 114459bf7050SPeter Avalos mtime_sec = (time_t)(utc.QuadPart / 10000000); 114559bf7050SPeter Avalos mtime_ns = (long)(utc.QuadPart % 10000000) * 100; 114659bf7050SPeter Avalos } else { 114759bf7050SPeter Avalos mtime_sec = 0; 114859bf7050SPeter Avalos mtime_ns = 0; 114959bf7050SPeter Avalos } 115059bf7050SPeter Avalos return set_timefilter(a, timetype, 115159bf7050SPeter Avalos mtime_sec, mtime_ns, ctime_sec, ctime_ns); 115259bf7050SPeter Avalos } 115359bf7050SPeter Avalos 115459bf7050SPeter Avalos static int 115559bf7050SPeter Avalos set_timefilter_pathname_mbs(struct archive_match *a, int timetype, 115659bf7050SPeter Avalos const char *path) 115759bf7050SPeter Avalos { 115859bf7050SPeter Avalos /* NOTE: stat() on Windows cannot handle nano seconds. */ 115959bf7050SPeter Avalos HANDLE h; 1160*6b384f39SPeter Avalos WIN32_FIND_DATAA d; 116159bf7050SPeter Avalos 116259bf7050SPeter Avalos if (path == NULL || *path == '\0') { 116359bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 116459bf7050SPeter Avalos return (ARCHIVE_FAILED); 116559bf7050SPeter Avalos } 116659bf7050SPeter Avalos h = FindFirstFileA(path, &d); 116759bf7050SPeter Avalos if (h == INVALID_HANDLE_VALUE) { 116859bf7050SPeter Avalos la_dosmaperr(GetLastError()); 116959bf7050SPeter Avalos archive_set_error(&(a->archive), errno, 117059bf7050SPeter Avalos "Failed to FindFirstFileA"); 117159bf7050SPeter Avalos return (ARCHIVE_FAILED); 117259bf7050SPeter Avalos } 117359bf7050SPeter Avalos FindClose(h); 117459bf7050SPeter Avalos return set_timefilter_find_data(a, timetype, 117559bf7050SPeter Avalos d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 117659bf7050SPeter Avalos d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 117759bf7050SPeter Avalos } 117859bf7050SPeter Avalos 117959bf7050SPeter Avalos static int 118059bf7050SPeter Avalos set_timefilter_pathname_wcs(struct archive_match *a, int timetype, 118159bf7050SPeter Avalos const wchar_t *path) 118259bf7050SPeter Avalos { 118359bf7050SPeter Avalos HANDLE h; 118459bf7050SPeter Avalos WIN32_FIND_DATAW d; 118559bf7050SPeter Avalos 118659bf7050SPeter Avalos if (path == NULL || *path == L'\0') { 118759bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 118859bf7050SPeter Avalos return (ARCHIVE_FAILED); 118959bf7050SPeter Avalos } 119059bf7050SPeter Avalos h = FindFirstFileW(path, &d); 119159bf7050SPeter Avalos if (h == INVALID_HANDLE_VALUE) { 119259bf7050SPeter Avalos la_dosmaperr(GetLastError()); 119359bf7050SPeter Avalos archive_set_error(&(a->archive), errno, 119459bf7050SPeter Avalos "Failed to FindFirstFile"); 119559bf7050SPeter Avalos return (ARCHIVE_FAILED); 119659bf7050SPeter Avalos } 119759bf7050SPeter Avalos FindClose(h); 119859bf7050SPeter Avalos return set_timefilter_find_data(a, timetype, 119959bf7050SPeter Avalos d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, 120059bf7050SPeter Avalos d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); 120159bf7050SPeter Avalos } 120259bf7050SPeter Avalos 120359bf7050SPeter Avalos #else /* _WIN32 && !__CYGWIN__ */ 120459bf7050SPeter Avalos 120559bf7050SPeter Avalos static int 120659bf7050SPeter Avalos set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st) 120759bf7050SPeter Avalos { 120859bf7050SPeter Avalos struct archive_entry *ae; 120959bf7050SPeter Avalos time_t ctime_sec, mtime_sec; 121059bf7050SPeter Avalos long ctime_ns, mtime_ns; 121159bf7050SPeter Avalos 121259bf7050SPeter Avalos ae = archive_entry_new(); 121359bf7050SPeter Avalos if (ae == NULL) 121459bf7050SPeter Avalos return (error_nomem(a)); 121559bf7050SPeter Avalos archive_entry_copy_stat(ae, st); 121659bf7050SPeter Avalos ctime_sec = archive_entry_ctime(ae); 121759bf7050SPeter Avalos ctime_ns = archive_entry_ctime_nsec(ae); 121859bf7050SPeter Avalos mtime_sec = archive_entry_mtime(ae); 121959bf7050SPeter Avalos mtime_ns = archive_entry_mtime_nsec(ae); 122059bf7050SPeter Avalos archive_entry_free(ae); 122159bf7050SPeter Avalos return set_timefilter(a, timetype, mtime_sec, mtime_ns, 122259bf7050SPeter Avalos ctime_sec, ctime_ns); 122359bf7050SPeter Avalos } 122459bf7050SPeter Avalos 122559bf7050SPeter Avalos static int 122659bf7050SPeter Avalos set_timefilter_pathname_mbs(struct archive_match *a, int timetype, 122759bf7050SPeter Avalos const char *path) 122859bf7050SPeter Avalos { 122959bf7050SPeter Avalos struct stat st; 123059bf7050SPeter Avalos 123159bf7050SPeter Avalos if (path == NULL || *path == '\0') { 123259bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 123359bf7050SPeter Avalos return (ARCHIVE_FAILED); 123459bf7050SPeter Avalos } 123559bf7050SPeter Avalos if (stat(path, &st) != 0) { 123659bf7050SPeter Avalos archive_set_error(&(a->archive), errno, "Failed to stat()"); 123759bf7050SPeter Avalos return (ARCHIVE_FAILED); 123859bf7050SPeter Avalos } 123959bf7050SPeter Avalos return (set_timefilter_stat(a, timetype, &st)); 124059bf7050SPeter Avalos } 124159bf7050SPeter Avalos 124259bf7050SPeter Avalos static int 124359bf7050SPeter Avalos set_timefilter_pathname_wcs(struct archive_match *a, int timetype, 124459bf7050SPeter Avalos const wchar_t *path) 124559bf7050SPeter Avalos { 124659bf7050SPeter Avalos struct archive_string as; 124759bf7050SPeter Avalos int r; 124859bf7050SPeter Avalos 124959bf7050SPeter Avalos if (path == NULL || *path == L'\0') { 125059bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pathname is empty"); 125159bf7050SPeter Avalos return (ARCHIVE_FAILED); 125259bf7050SPeter Avalos } 125359bf7050SPeter Avalos 125459bf7050SPeter Avalos /* Convert WCS filename to MBS filename. */ 125559bf7050SPeter Avalos archive_string_init(&as); 125659bf7050SPeter Avalos if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { 125759bf7050SPeter Avalos archive_string_free(&as); 125859bf7050SPeter Avalos if (errno == ENOMEM) 125959bf7050SPeter Avalos return (error_nomem(a)); 126059bf7050SPeter Avalos archive_set_error(&(a->archive), -1, 126159bf7050SPeter Avalos "Failed to convert WCS to MBS"); 126259bf7050SPeter Avalos return (ARCHIVE_FAILED); 126359bf7050SPeter Avalos } 126459bf7050SPeter Avalos 126559bf7050SPeter Avalos r = set_timefilter_pathname_mbs(a, timetype, as.s); 126659bf7050SPeter Avalos archive_string_free(&as); 126759bf7050SPeter Avalos 126859bf7050SPeter Avalos return (r); 126959bf7050SPeter Avalos } 127059bf7050SPeter Avalos #endif /* _WIN32 && !__CYGWIN__ */ 127159bf7050SPeter Avalos 127259bf7050SPeter Avalos /* 127359bf7050SPeter Avalos * Call back funtions for archive_rb. 127459bf7050SPeter Avalos */ 127559bf7050SPeter Avalos static int 127659bf7050SPeter Avalos cmp_node_mbs(const struct archive_rb_node *n1, 127759bf7050SPeter Avalos const struct archive_rb_node *n2) 127859bf7050SPeter Avalos { 127959bf7050SPeter Avalos struct match_file *f1 = (struct match_file *)(uintptr_t)n1; 128059bf7050SPeter Avalos struct match_file *f2 = (struct match_file *)(uintptr_t)n2; 128159bf7050SPeter Avalos const char *p1, *p2; 128259bf7050SPeter Avalos 128359bf7050SPeter Avalos archive_mstring_get_mbs(NULL, &(f1->pathname), &p1); 128459bf7050SPeter Avalos archive_mstring_get_mbs(NULL, &(f2->pathname), &p2); 128559bf7050SPeter Avalos if (p1 == NULL) 128659bf7050SPeter Avalos return (1); 128759bf7050SPeter Avalos if (p2 == NULL) 128859bf7050SPeter Avalos return (-1); 128959bf7050SPeter Avalos return (strcmp(p1, p2)); 129059bf7050SPeter Avalos } 129159bf7050SPeter Avalos 129259bf7050SPeter Avalos static int 129359bf7050SPeter Avalos cmp_key_mbs(const struct archive_rb_node *n, const void *key) 129459bf7050SPeter Avalos { 129559bf7050SPeter Avalos struct match_file *f = (struct match_file *)(uintptr_t)n; 129659bf7050SPeter Avalos const char *p; 129759bf7050SPeter Avalos 129859bf7050SPeter Avalos archive_mstring_get_mbs(NULL, &(f->pathname), &p); 129959bf7050SPeter Avalos if (p == NULL) 130059bf7050SPeter Avalos return (-1); 130159bf7050SPeter Avalos return (strcmp(p, (const char *)key)); 130259bf7050SPeter Avalos } 130359bf7050SPeter Avalos 130459bf7050SPeter Avalos static int 130559bf7050SPeter Avalos cmp_node_wcs(const struct archive_rb_node *n1, 130659bf7050SPeter Avalos const struct archive_rb_node *n2) 130759bf7050SPeter Avalos { 130859bf7050SPeter Avalos struct match_file *f1 = (struct match_file *)(uintptr_t)n1; 130959bf7050SPeter Avalos struct match_file *f2 = (struct match_file *)(uintptr_t)n2; 131059bf7050SPeter Avalos const wchar_t *p1, *p2; 131159bf7050SPeter Avalos 131259bf7050SPeter Avalos archive_mstring_get_wcs(NULL, &(f1->pathname), &p1); 131359bf7050SPeter Avalos archive_mstring_get_wcs(NULL, &(f2->pathname), &p2); 131459bf7050SPeter Avalos if (p1 == NULL) 131559bf7050SPeter Avalos return (1); 131659bf7050SPeter Avalos if (p2 == NULL) 131759bf7050SPeter Avalos return (-1); 131859bf7050SPeter Avalos return (wcscmp(p1, p2)); 131959bf7050SPeter Avalos } 132059bf7050SPeter Avalos 132159bf7050SPeter Avalos static int 132259bf7050SPeter Avalos cmp_key_wcs(const struct archive_rb_node *n, const void *key) 132359bf7050SPeter Avalos { 132459bf7050SPeter Avalos struct match_file *f = (struct match_file *)(uintptr_t)n; 132559bf7050SPeter Avalos const wchar_t *p; 132659bf7050SPeter Avalos 132759bf7050SPeter Avalos archive_mstring_get_wcs(NULL, &(f->pathname), &p); 132859bf7050SPeter Avalos if (p == NULL) 132959bf7050SPeter Avalos return (-1); 133059bf7050SPeter Avalos return (wcscmp(p, (const wchar_t *)key)); 133159bf7050SPeter Avalos } 133259bf7050SPeter Avalos 133359bf7050SPeter Avalos static void 133459bf7050SPeter Avalos entry_list_init(struct entry_list *list) 133559bf7050SPeter Avalos { 133659bf7050SPeter Avalos list->first = NULL; 133759bf7050SPeter Avalos list->last = &(list->first); 133859bf7050SPeter Avalos list->count = 0; 133959bf7050SPeter Avalos } 134059bf7050SPeter Avalos 134159bf7050SPeter Avalos static void 134259bf7050SPeter Avalos entry_list_free(struct entry_list *list) 134359bf7050SPeter Avalos { 134459bf7050SPeter Avalos struct match_file *p, *q; 134559bf7050SPeter Avalos 134659bf7050SPeter Avalos for (p = list->first; p != NULL; ) { 134759bf7050SPeter Avalos q = p; 134859bf7050SPeter Avalos p = p->next; 134959bf7050SPeter Avalos archive_mstring_clean(&(q->pathname)); 135059bf7050SPeter Avalos free(q); 135159bf7050SPeter Avalos } 135259bf7050SPeter Avalos } 135359bf7050SPeter Avalos 135459bf7050SPeter Avalos static void 135559bf7050SPeter Avalos entry_list_add(struct entry_list *list, struct match_file *file) 135659bf7050SPeter Avalos { 135759bf7050SPeter Avalos *list->last = file; 135859bf7050SPeter Avalos list->last = &(file->next); 135959bf7050SPeter Avalos list->count++; 136059bf7050SPeter Avalos } 136159bf7050SPeter Avalos 136259bf7050SPeter Avalos static int 136359bf7050SPeter Avalos add_entry(struct archive_match *a, int flag, 136459bf7050SPeter Avalos struct archive_entry *entry) 136559bf7050SPeter Avalos { 136659bf7050SPeter Avalos struct match_file *f; 136759bf7050SPeter Avalos const void *pathname; 136859bf7050SPeter Avalos int r; 136959bf7050SPeter Avalos 137059bf7050SPeter Avalos f = calloc(1, sizeof(*f)); 137159bf7050SPeter Avalos if (f == NULL) 137259bf7050SPeter Avalos return (error_nomem(a)); 137359bf7050SPeter Avalos 137459bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 137559bf7050SPeter Avalos pathname = archive_entry_pathname_w(entry); 137659bf7050SPeter Avalos if (pathname == NULL) { 137759bf7050SPeter Avalos free(f); 137859bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 137959bf7050SPeter Avalos return (ARCHIVE_FAILED); 138059bf7050SPeter Avalos } 138159bf7050SPeter Avalos archive_mstring_copy_wcs(&(f->pathname), pathname); 138259bf7050SPeter Avalos a->exclusion_tree.rbt_ops = &rb_ops_wcs; 138359bf7050SPeter Avalos #else 1384d4d8193eSPeter Avalos (void)rb_ops_wcs; 138559bf7050SPeter Avalos pathname = archive_entry_pathname(entry); 138659bf7050SPeter Avalos if (pathname == NULL) { 138759bf7050SPeter Avalos free(f); 138859bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); 138959bf7050SPeter Avalos return (ARCHIVE_FAILED); 139059bf7050SPeter Avalos } 139159bf7050SPeter Avalos archive_mstring_copy_mbs(&(f->pathname), pathname); 139259bf7050SPeter Avalos a->exclusion_tree.rbt_ops = &rb_ops_mbs; 139359bf7050SPeter Avalos #endif 139459bf7050SPeter Avalos f->flag = flag; 139559bf7050SPeter Avalos f->mtime_sec = archive_entry_mtime(entry); 139659bf7050SPeter Avalos f->mtime_nsec = archive_entry_mtime_nsec(entry); 139759bf7050SPeter Avalos f->ctime_sec = archive_entry_ctime(entry); 139859bf7050SPeter Avalos f->ctime_nsec = archive_entry_ctime_nsec(entry); 139959bf7050SPeter Avalos r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node)); 140059bf7050SPeter Avalos if (!r) { 140159bf7050SPeter Avalos struct match_file *f2; 140259bf7050SPeter Avalos 140359bf7050SPeter Avalos /* Get the duplicated file. */ 140459bf7050SPeter Avalos f2 = (struct match_file *)__archive_rb_tree_find_node( 140559bf7050SPeter Avalos &(a->exclusion_tree), pathname); 140659bf7050SPeter Avalos 140759bf7050SPeter Avalos /* 140859bf7050SPeter Avalos * We always overwrite comparison condision. 140959bf7050SPeter Avalos * If you do not want to overwrite it, you should not 141059bf7050SPeter Avalos * call archive_match_exclude_entry(). We cannot know 141159bf7050SPeter Avalos * what behavior you really expect since overwriting 141259bf7050SPeter Avalos * condition might be different with the flag. 141359bf7050SPeter Avalos */ 141459bf7050SPeter Avalos if (f2 != NULL) { 141559bf7050SPeter Avalos f2->flag = f->flag; 141659bf7050SPeter Avalos f2->mtime_sec = f->mtime_sec; 141759bf7050SPeter Avalos f2->mtime_nsec = f->mtime_nsec; 141859bf7050SPeter Avalos f2->ctime_sec = f->ctime_sec; 141959bf7050SPeter Avalos f2->ctime_nsec = f->ctime_nsec; 142059bf7050SPeter Avalos } 142159bf7050SPeter Avalos /* Release the duplicated file. */ 142259bf7050SPeter Avalos archive_mstring_clean(&(f->pathname)); 142359bf7050SPeter Avalos free(f); 142459bf7050SPeter Avalos return (ARCHIVE_OK); 142559bf7050SPeter Avalos } 142659bf7050SPeter Avalos entry_list_add(&(a->exclusion_entry_list), f); 142759bf7050SPeter Avalos a->setflag |= TIME_IS_SET; 142859bf7050SPeter Avalos return (ARCHIVE_OK); 142959bf7050SPeter Avalos } 143059bf7050SPeter Avalos 143159bf7050SPeter Avalos /* 143259bf7050SPeter Avalos * Test if entry is excluded by its timestamp. 143359bf7050SPeter Avalos */ 143459bf7050SPeter Avalos static int 143559bf7050SPeter Avalos time_excluded(struct archive_match *a, struct archive_entry *entry) 143659bf7050SPeter Avalos { 143759bf7050SPeter Avalos struct match_file *f; 143859bf7050SPeter Avalos const void *pathname; 143959bf7050SPeter Avalos time_t sec; 144059bf7050SPeter Avalos long nsec; 144159bf7050SPeter Avalos 144259bf7050SPeter Avalos /* 144359bf7050SPeter Avalos * If this file/dir is excluded by a time comparison, skip it. 144459bf7050SPeter Avalos */ 144559bf7050SPeter Avalos if (a->newer_ctime_filter) { 144659bf7050SPeter Avalos /* If ctime is not set, use mtime instead. */ 144759bf7050SPeter Avalos if (archive_entry_ctime_is_set(entry)) 144859bf7050SPeter Avalos sec = archive_entry_ctime(entry); 144959bf7050SPeter Avalos else 145059bf7050SPeter Avalos sec = archive_entry_mtime(entry); 145159bf7050SPeter Avalos if (sec < a->newer_ctime_sec) 145259bf7050SPeter Avalos return (1); /* Too old, skip it. */ 145359bf7050SPeter Avalos if (sec == a->newer_ctime_sec) { 145459bf7050SPeter Avalos if (archive_entry_ctime_is_set(entry)) 145559bf7050SPeter Avalos nsec = archive_entry_ctime_nsec(entry); 145659bf7050SPeter Avalos else 145759bf7050SPeter Avalos nsec = archive_entry_mtime_nsec(entry); 145859bf7050SPeter Avalos if (nsec < a->newer_ctime_nsec) 145959bf7050SPeter Avalos return (1); /* Too old, skip it. */ 146059bf7050SPeter Avalos if (nsec == a->newer_ctime_nsec && 146159bf7050SPeter Avalos (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL) 146259bf7050SPeter Avalos == 0) 146359bf7050SPeter Avalos return (1); /* Equal, skip it. */ 146459bf7050SPeter Avalos } 146559bf7050SPeter Avalos } 146659bf7050SPeter Avalos if (a->older_ctime_filter) { 146759bf7050SPeter Avalos /* If ctime is not set, use mtime instead. */ 146859bf7050SPeter Avalos if (archive_entry_ctime_is_set(entry)) 146959bf7050SPeter Avalos sec = archive_entry_ctime(entry); 147059bf7050SPeter Avalos else 147159bf7050SPeter Avalos sec = archive_entry_mtime(entry); 147259bf7050SPeter Avalos if (sec > a->older_ctime_sec) 147359bf7050SPeter Avalos return (1); /* Too new, skip it. */ 147459bf7050SPeter Avalos if (sec == a->older_ctime_sec) { 147559bf7050SPeter Avalos if (archive_entry_ctime_is_set(entry)) 147659bf7050SPeter Avalos nsec = archive_entry_ctime_nsec(entry); 147759bf7050SPeter Avalos else 147859bf7050SPeter Avalos nsec = archive_entry_mtime_nsec(entry); 147959bf7050SPeter Avalos if (nsec > a->older_ctime_nsec) 148059bf7050SPeter Avalos return (1); /* Too new, skip it. */ 148159bf7050SPeter Avalos if (nsec == a->older_ctime_nsec && 148259bf7050SPeter Avalos (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) 148359bf7050SPeter Avalos == 0) 148459bf7050SPeter Avalos return (1); /* Eeual, skip it. */ 148559bf7050SPeter Avalos } 148659bf7050SPeter Avalos } 148759bf7050SPeter Avalos if (a->newer_mtime_filter) { 148859bf7050SPeter Avalos sec = archive_entry_mtime(entry); 148959bf7050SPeter Avalos if (sec < a->newer_mtime_sec) 149059bf7050SPeter Avalos return (1); /* Too old, skip it. */ 149159bf7050SPeter Avalos if (sec == a->newer_mtime_sec) { 149259bf7050SPeter Avalos nsec = archive_entry_mtime_nsec(entry); 149359bf7050SPeter Avalos if (nsec < a->newer_mtime_nsec) 149459bf7050SPeter Avalos return (1); /* Too old, skip it. */ 149559bf7050SPeter Avalos if (nsec == a->newer_mtime_nsec && 149659bf7050SPeter Avalos (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL) 149759bf7050SPeter Avalos == 0) 149859bf7050SPeter Avalos return (1); /* Equal, skip it. */ 149959bf7050SPeter Avalos } 150059bf7050SPeter Avalos } 150159bf7050SPeter Avalos if (a->older_mtime_filter) { 150259bf7050SPeter Avalos sec = archive_entry_mtime(entry); 150359bf7050SPeter Avalos if (sec > a->older_mtime_sec) 150459bf7050SPeter Avalos return (1); /* Too new, skip it. */ 150559bf7050SPeter Avalos nsec = archive_entry_mtime_nsec(entry); 150659bf7050SPeter Avalos if (sec == a->older_mtime_sec) { 150759bf7050SPeter Avalos if (nsec > a->older_mtime_nsec) 150859bf7050SPeter Avalos return (1); /* Too new, skip it. */ 150959bf7050SPeter Avalos if (nsec == a->older_mtime_nsec && 151059bf7050SPeter Avalos (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL) 151159bf7050SPeter Avalos == 0) 151259bf7050SPeter Avalos return (1); /* Equal, skip it. */ 151359bf7050SPeter Avalos } 151459bf7050SPeter Avalos } 151559bf7050SPeter Avalos 151659bf7050SPeter Avalos /* If there is no excluson list, include the file. */ 151759bf7050SPeter Avalos if (a->exclusion_entry_list.count == 0) 151859bf7050SPeter Avalos return (0); 151959bf7050SPeter Avalos 152059bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 152159bf7050SPeter Avalos pathname = archive_entry_pathname_w(entry); 152259bf7050SPeter Avalos a->exclusion_tree.rbt_ops = &rb_ops_wcs; 152359bf7050SPeter Avalos #else 1524d4d8193eSPeter Avalos (void)rb_ops_wcs; 152559bf7050SPeter Avalos pathname = archive_entry_pathname(entry); 152659bf7050SPeter Avalos a->exclusion_tree.rbt_ops = &rb_ops_mbs; 152759bf7050SPeter Avalos #endif 152859bf7050SPeter Avalos if (pathname == NULL) 152959bf7050SPeter Avalos return (0); 153059bf7050SPeter Avalos 153159bf7050SPeter Avalos f = (struct match_file *)__archive_rb_tree_find_node( 153259bf7050SPeter Avalos &(a->exclusion_tree), pathname); 153359bf7050SPeter Avalos /* If the file wasn't rejected, include it. */ 153459bf7050SPeter Avalos if (f == NULL) 153559bf7050SPeter Avalos return (0); 153659bf7050SPeter Avalos 153759bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_CTIME) { 153859bf7050SPeter Avalos sec = archive_entry_ctime(entry); 153959bf7050SPeter Avalos if (f->ctime_sec > sec) { 154059bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_OLDER) 154159bf7050SPeter Avalos return (1); 154259bf7050SPeter Avalos } else if (f->ctime_sec < sec) { 154359bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_NEWER) 154459bf7050SPeter Avalos return (1); 154559bf7050SPeter Avalos } else { 154659bf7050SPeter Avalos nsec = archive_entry_ctime_nsec(entry); 154759bf7050SPeter Avalos if (f->ctime_nsec > nsec) { 154859bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_OLDER) 154959bf7050SPeter Avalos return (1); 155059bf7050SPeter Avalos } else if (f->ctime_nsec < nsec) { 155159bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_NEWER) 155259bf7050SPeter Avalos return (1); 155359bf7050SPeter Avalos } else if (f->flag & ARCHIVE_MATCH_EQUAL) 155459bf7050SPeter Avalos return (1); 155559bf7050SPeter Avalos } 155659bf7050SPeter Avalos } 155759bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_MTIME) { 155859bf7050SPeter Avalos sec = archive_entry_mtime(entry); 155959bf7050SPeter Avalos if (f->mtime_sec > sec) { 156059bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_OLDER) 156159bf7050SPeter Avalos return (1); 156259bf7050SPeter Avalos } else if (f->mtime_sec < sec) { 156359bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_NEWER) 156459bf7050SPeter Avalos return (1); 156559bf7050SPeter Avalos } else { 156659bf7050SPeter Avalos nsec = archive_entry_mtime_nsec(entry); 156759bf7050SPeter Avalos if (f->mtime_nsec > nsec) { 156859bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_OLDER) 156959bf7050SPeter Avalos return (1); 157059bf7050SPeter Avalos } else if (f->mtime_nsec < nsec) { 157159bf7050SPeter Avalos if (f->flag & ARCHIVE_MATCH_NEWER) 157259bf7050SPeter Avalos return (1); 157359bf7050SPeter Avalos } else if (f->flag & ARCHIVE_MATCH_EQUAL) 157459bf7050SPeter Avalos return (1); 157559bf7050SPeter Avalos } 157659bf7050SPeter Avalos } 157759bf7050SPeter Avalos return (0); 157859bf7050SPeter Avalos } 157959bf7050SPeter Avalos 158059bf7050SPeter Avalos /* 158159bf7050SPeter Avalos * Utility functions to manage inclusion owners 158259bf7050SPeter Avalos */ 158359bf7050SPeter Avalos 158459bf7050SPeter Avalos int 158559bf7050SPeter Avalos archive_match_include_uid(struct archive *_a, int64_t uid) 158659bf7050SPeter Avalos { 158759bf7050SPeter Avalos struct archive_match *a; 158859bf7050SPeter Avalos 158959bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 159059bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_uid"); 159159bf7050SPeter Avalos a = (struct archive_match *)_a; 159259bf7050SPeter Avalos return (add_owner_id(a, &(a->inclusion_uids), uid)); 159359bf7050SPeter Avalos } 159459bf7050SPeter Avalos 159559bf7050SPeter Avalos int 159659bf7050SPeter Avalos archive_match_include_gid(struct archive *_a, int64_t gid) 159759bf7050SPeter Avalos { 159859bf7050SPeter Avalos struct archive_match *a; 159959bf7050SPeter Avalos 160059bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 160159bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_gid"); 160259bf7050SPeter Avalos a = (struct archive_match *)_a; 160359bf7050SPeter Avalos return (add_owner_id(a, &(a->inclusion_gids), gid)); 160459bf7050SPeter Avalos } 160559bf7050SPeter Avalos 160659bf7050SPeter Avalos int 160759bf7050SPeter Avalos archive_match_include_uname(struct archive *_a, const char *uname) 160859bf7050SPeter Avalos { 160959bf7050SPeter Avalos struct archive_match *a; 161059bf7050SPeter Avalos 161159bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 161259bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_uname"); 161359bf7050SPeter Avalos a = (struct archive_match *)_a; 161459bf7050SPeter Avalos return (add_owner_name(a, &(a->inclusion_unames), 1, uname)); 161559bf7050SPeter Avalos } 161659bf7050SPeter Avalos 161759bf7050SPeter Avalos int 161859bf7050SPeter Avalos archive_match_include_uname_w(struct archive *_a, const wchar_t *uname) 161959bf7050SPeter Avalos { 162059bf7050SPeter Avalos struct archive_match *a; 162159bf7050SPeter Avalos 162259bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 162359bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_uname_w"); 162459bf7050SPeter Avalos a = (struct archive_match *)_a; 162559bf7050SPeter Avalos return (add_owner_name(a, &(a->inclusion_unames), 0, uname)); 162659bf7050SPeter Avalos } 162759bf7050SPeter Avalos 162859bf7050SPeter Avalos int 162959bf7050SPeter Avalos archive_match_include_gname(struct archive *_a, const char *gname) 163059bf7050SPeter Avalos { 163159bf7050SPeter Avalos struct archive_match *a; 163259bf7050SPeter Avalos 163359bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 163459bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_gname"); 163559bf7050SPeter Avalos a = (struct archive_match *)_a; 163659bf7050SPeter Avalos return (add_owner_name(a, &(a->inclusion_gnames), 1, gname)); 163759bf7050SPeter Avalos } 163859bf7050SPeter Avalos 163959bf7050SPeter Avalos int 164059bf7050SPeter Avalos archive_match_include_gname_w(struct archive *_a, const wchar_t *gname) 164159bf7050SPeter Avalos { 164259bf7050SPeter Avalos struct archive_match *a; 164359bf7050SPeter Avalos 164459bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 164559bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_include_gname_w"); 164659bf7050SPeter Avalos a = (struct archive_match *)_a; 164759bf7050SPeter Avalos return (add_owner_name(a, &(a->inclusion_gnames), 0, gname)); 164859bf7050SPeter Avalos } 164959bf7050SPeter Avalos 165059bf7050SPeter Avalos /* 165159bf7050SPeter Avalos * Test function for owner(uid, gid, uname, gname). 165259bf7050SPeter Avalos * 165359bf7050SPeter Avalos * Returns 1 if archive entry is excluded. 165459bf7050SPeter Avalos * Returns 0 if archive entry is not excluded. 165559bf7050SPeter Avalos * Returns <0 if something error happened. 165659bf7050SPeter Avalos */ 165759bf7050SPeter Avalos int 165859bf7050SPeter Avalos archive_match_owner_excluded(struct archive *_a, 165959bf7050SPeter Avalos struct archive_entry *entry) 166059bf7050SPeter Avalos { 166159bf7050SPeter Avalos struct archive_match *a; 166259bf7050SPeter Avalos 166359bf7050SPeter Avalos archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, 166459bf7050SPeter Avalos ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae"); 166559bf7050SPeter Avalos 166659bf7050SPeter Avalos a = (struct archive_match *)_a; 166759bf7050SPeter Avalos if (entry == NULL) { 166859bf7050SPeter Avalos archive_set_error(&(a->archive), EINVAL, "entry is NULL"); 166959bf7050SPeter Avalos return (ARCHIVE_FAILED); 167059bf7050SPeter Avalos } 167159bf7050SPeter Avalos 167259bf7050SPeter Avalos /* If we don't have inclusion id set at all, the entry is always 167359bf7050SPeter Avalos * not excluded. */ 167459bf7050SPeter Avalos if ((a->setflag & ID_IS_SET) == 0) 167559bf7050SPeter Avalos return (0); 167659bf7050SPeter Avalos return (owner_excluded(a, entry)); 167759bf7050SPeter Avalos } 167859bf7050SPeter Avalos 167959bf7050SPeter Avalos static int 168059bf7050SPeter Avalos add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) 168159bf7050SPeter Avalos { 168259bf7050SPeter Avalos unsigned i; 168359bf7050SPeter Avalos 168459bf7050SPeter Avalos if (ids->count + 1 >= ids->size) { 1685d4d8193eSPeter Avalos void *p; 1686d4d8193eSPeter Avalos 168759bf7050SPeter Avalos if (ids->size == 0) 168859bf7050SPeter Avalos ids->size = 8; 168959bf7050SPeter Avalos else 169059bf7050SPeter Avalos ids->size *= 2; 1691d4d8193eSPeter Avalos p = realloc(ids->ids, sizeof(*ids->ids) * ids->size); 1692d4d8193eSPeter Avalos if (p == NULL) 169359bf7050SPeter Avalos return (error_nomem(a)); 1694d4d8193eSPeter Avalos ids->ids = (int64_t *)p; 169559bf7050SPeter Avalos } 169659bf7050SPeter Avalos 169759bf7050SPeter Avalos /* Find an insert point. */ 169859bf7050SPeter Avalos for (i = 0; i < ids->count; i++) { 169959bf7050SPeter Avalos if (ids->ids[i] >= id) 170059bf7050SPeter Avalos break; 170159bf7050SPeter Avalos } 170259bf7050SPeter Avalos 170359bf7050SPeter Avalos /* Add oowner id. */ 170459bf7050SPeter Avalos if (i == ids->count) 170559bf7050SPeter Avalos ids->ids[ids->count++] = id; 170659bf7050SPeter Avalos else if (ids->ids[i] != id) { 170759bf7050SPeter Avalos memmove(&(ids->ids[i+1]), &(ids->ids[i]), 170859bf7050SPeter Avalos (ids->count - i) * sizeof(ids->ids[0])); 170959bf7050SPeter Avalos ids->ids[i] = id; 171059bf7050SPeter Avalos ids->count++; 171159bf7050SPeter Avalos } 171259bf7050SPeter Avalos a->setflag |= ID_IS_SET; 171359bf7050SPeter Avalos return (ARCHIVE_OK); 171459bf7050SPeter Avalos } 171559bf7050SPeter Avalos 171659bf7050SPeter Avalos static int 171759bf7050SPeter Avalos match_owner_id(struct id_array *ids, int64_t id) 171859bf7050SPeter Avalos { 171959bf7050SPeter Avalos unsigned b, m, t; 172059bf7050SPeter Avalos 172159bf7050SPeter Avalos t = 0; 1722d4d8193eSPeter Avalos b = (unsigned)ids->count; 172359bf7050SPeter Avalos while (t < b) { 172459bf7050SPeter Avalos m = (t + b)>>1; 172559bf7050SPeter Avalos if (ids->ids[m] == id) 172659bf7050SPeter Avalos return (1); 172759bf7050SPeter Avalos if (ids->ids[m] < id) 172859bf7050SPeter Avalos t = m + 1; 172959bf7050SPeter Avalos else 173059bf7050SPeter Avalos b = m; 173159bf7050SPeter Avalos } 173259bf7050SPeter Avalos return (0); 173359bf7050SPeter Avalos } 173459bf7050SPeter Avalos 173559bf7050SPeter Avalos static int 173659bf7050SPeter Avalos add_owner_name(struct archive_match *a, struct match_list *list, 173759bf7050SPeter Avalos int mbs, const void *name) 173859bf7050SPeter Avalos { 173959bf7050SPeter Avalos struct match *match; 174059bf7050SPeter Avalos 174159bf7050SPeter Avalos match = calloc(1, sizeof(*match)); 174259bf7050SPeter Avalos if (match == NULL) 174359bf7050SPeter Avalos return (error_nomem(a)); 174459bf7050SPeter Avalos if (mbs) 174559bf7050SPeter Avalos archive_mstring_copy_mbs(&(match->pattern), name); 174659bf7050SPeter Avalos else 174759bf7050SPeter Avalos archive_mstring_copy_wcs(&(match->pattern), name); 174859bf7050SPeter Avalos match_list_add(list, match); 174959bf7050SPeter Avalos a->setflag |= ID_IS_SET; 175059bf7050SPeter Avalos return (ARCHIVE_OK); 175159bf7050SPeter Avalos } 175259bf7050SPeter Avalos 175359bf7050SPeter Avalos #if !defined(_WIN32) || defined(__CYGWIN__) 175459bf7050SPeter Avalos static int 175559bf7050SPeter Avalos match_owner_name_mbs(struct archive_match *a, struct match_list *list, 175659bf7050SPeter Avalos const char *name) 175759bf7050SPeter Avalos { 175859bf7050SPeter Avalos struct match *m; 175959bf7050SPeter Avalos const char *p; 176059bf7050SPeter Avalos 176159bf7050SPeter Avalos if (name == NULL || *name == '\0') 176259bf7050SPeter Avalos return (0); 176359bf7050SPeter Avalos for (m = list->first; m; m = m->next) { 176459bf7050SPeter Avalos if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p) 176559bf7050SPeter Avalos < 0 && errno == ENOMEM) 176659bf7050SPeter Avalos return (error_nomem(a)); 176759bf7050SPeter Avalos if (p != NULL && strcmp(p, name) == 0) { 176859bf7050SPeter Avalos m->matches++; 176959bf7050SPeter Avalos return (1); 177059bf7050SPeter Avalos } 177159bf7050SPeter Avalos } 177259bf7050SPeter Avalos return (0); 177359bf7050SPeter Avalos } 177459bf7050SPeter Avalos #else 177559bf7050SPeter Avalos static int 177659bf7050SPeter Avalos match_owner_name_wcs(struct archive_match *a, struct match_list *list, 177759bf7050SPeter Avalos const wchar_t *name) 177859bf7050SPeter Avalos { 177959bf7050SPeter Avalos struct match *m; 178059bf7050SPeter Avalos const wchar_t *p; 178159bf7050SPeter Avalos 178259bf7050SPeter Avalos if (name == NULL || *name == L'\0') 178359bf7050SPeter Avalos return (0); 178459bf7050SPeter Avalos for (m = list->first; m; m = m->next) { 178559bf7050SPeter Avalos if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p) 178659bf7050SPeter Avalos < 0 && errno == ENOMEM) 178759bf7050SPeter Avalos return (error_nomem(a)); 178859bf7050SPeter Avalos if (p != NULL && wcscmp(p, name) == 0) { 178959bf7050SPeter Avalos m->matches++; 179059bf7050SPeter Avalos return (1); 179159bf7050SPeter Avalos } 179259bf7050SPeter Avalos } 179359bf7050SPeter Avalos return (0); 179459bf7050SPeter Avalos } 179559bf7050SPeter Avalos #endif 179659bf7050SPeter Avalos 179759bf7050SPeter Avalos /* 179859bf7050SPeter Avalos * Test if entry is excluded by uid, gid, uname or gname. 179959bf7050SPeter Avalos */ 180059bf7050SPeter Avalos static int 180159bf7050SPeter Avalos owner_excluded(struct archive_match *a, struct archive_entry *entry) 180259bf7050SPeter Avalos { 180359bf7050SPeter Avalos int r; 180459bf7050SPeter Avalos 180559bf7050SPeter Avalos if (a->inclusion_uids.count) { 180659bf7050SPeter Avalos if (!match_owner_id(&(a->inclusion_uids), 180759bf7050SPeter Avalos archive_entry_uid(entry))) 180859bf7050SPeter Avalos return (1); 180959bf7050SPeter Avalos } 181059bf7050SPeter Avalos 181159bf7050SPeter Avalos if (a->inclusion_gids.count) { 181259bf7050SPeter Avalos if (!match_owner_id(&(a->inclusion_gids), 181359bf7050SPeter Avalos archive_entry_gid(entry))) 181459bf7050SPeter Avalos return (1); 181559bf7050SPeter Avalos } 181659bf7050SPeter Avalos 181759bf7050SPeter Avalos if (a->inclusion_unames.count) { 181859bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 181959bf7050SPeter Avalos r = match_owner_name_wcs(a, &(a->inclusion_unames), 182059bf7050SPeter Avalos archive_entry_uname_w(entry)); 182159bf7050SPeter Avalos #else 182259bf7050SPeter Avalos r = match_owner_name_mbs(a, &(a->inclusion_unames), 182359bf7050SPeter Avalos archive_entry_uname(entry)); 182459bf7050SPeter Avalos #endif 182559bf7050SPeter Avalos if (!r) 182659bf7050SPeter Avalos return (1); 182759bf7050SPeter Avalos else if (r < 0) 182859bf7050SPeter Avalos return (r); 182959bf7050SPeter Avalos } 183059bf7050SPeter Avalos 183159bf7050SPeter Avalos if (a->inclusion_gnames.count) { 183259bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 183359bf7050SPeter Avalos r = match_owner_name_wcs(a, &(a->inclusion_gnames), 183459bf7050SPeter Avalos archive_entry_gname_w(entry)); 183559bf7050SPeter Avalos #else 183659bf7050SPeter Avalos r = match_owner_name_mbs(a, &(a->inclusion_gnames), 183759bf7050SPeter Avalos archive_entry_gname(entry)); 183859bf7050SPeter Avalos #endif 183959bf7050SPeter Avalos if (!r) 184059bf7050SPeter Avalos return (1); 184159bf7050SPeter Avalos else if (r < 0) 184259bf7050SPeter Avalos return (r); 184359bf7050SPeter Avalos } 184459bf7050SPeter Avalos return (0); 184559bf7050SPeter Avalos } 184659bf7050SPeter Avalos 1847