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