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