1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846 |
- /*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2012 Michihiro NAKAJIMA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "archive_platform.h"
- __FBSDID("$FreeBSD$");
- #ifdef HAVE_ERRNO_H
- #include <errno.h>
- #endif
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #ifdef HAVE_STRING_H
- #include <string.h>
- #endif
- #include "archive.h"
- #include "archive_private.h"
- #include "archive_entry.h"
- #include "archive_getdate.h"
- #include "archive_pathmatch.h"
- #include "archive_rb.h"
- #include "archive_string.h"
- struct match {
- struct match *next;
- int matches;
- struct archive_mstring pattern;
- };
- struct match_list {
- struct match *first;
- struct match **last;
- int count;
- int unmatched_count;
- struct match *unmatched_next;
- int unmatched_eof;
- };
- struct match_file {
- struct archive_rb_node node;
- struct match_file *next;
- struct archive_mstring pathname;
- int flag;
- time_t mtime_sec;
- long mtime_nsec;
- time_t ctime_sec;
- long ctime_nsec;
- };
- struct entry_list {
- struct match_file *first;
- struct match_file **last;
- int count;
- };
- struct id_array {
- size_t size;/* Allocated size */
- size_t count;
- int64_t *ids;
- };
- #define PATTERN_IS_SET 1
- #define TIME_IS_SET 2
- #define ID_IS_SET 4
- struct archive_match {
- struct archive archive;
- /* exclusion/inclusion set flag. */
- int setflag;
- /*
- * Matching filename patterns.
- */
- struct match_list exclusions;
- struct match_list inclusions;
- /*
- * Matching time stamps.
- */
- time_t now;
- int newer_mtime_filter;
- time_t newer_mtime_sec;
- long newer_mtime_nsec;
- int newer_ctime_filter;
- time_t newer_ctime_sec;
- long newer_ctime_nsec;
- int older_mtime_filter;
- time_t older_mtime_sec;
- long older_mtime_nsec;
- int older_ctime_filter;
- time_t older_ctime_sec;
- long older_ctime_nsec;
- /*
- * Matching time stamps with its filename.
- */
- struct archive_rb_tree exclusion_tree;
- struct entry_list exclusion_entry_list;
- /*
- * Matching file owners.
- */
- struct id_array inclusion_uids;
- struct id_array inclusion_gids;
- struct match_list inclusion_unames;
- struct match_list inclusion_gnames;
- };
- static int add_pattern_from_file(struct archive_match *,
- struct match_list *, int, const void *, int);
- static int add_entry(struct archive_match *, int,
- struct archive_entry *);
- static int add_owner_id(struct archive_match *, struct id_array *,
- int64_t);
- static int add_owner_name(struct archive_match *, struct match_list *,
- int, const void *);
- static int add_pattern_mbs(struct archive_match *, struct match_list *,
- const char *);
- static int add_pattern_wcs(struct archive_match *, struct match_list *,
- const wchar_t *);
- static int cmp_key_mbs(const struct archive_rb_node *, const void *);
- static int cmp_key_wcs(const struct archive_rb_node *, const void *);
- static int cmp_node_mbs(const struct archive_rb_node *,
- const struct archive_rb_node *);
- static int cmp_node_wcs(const struct archive_rb_node *,
- const struct archive_rb_node *);
- static void entry_list_add(struct entry_list *, struct match_file *);
- static void entry_list_free(struct entry_list *);
- static void entry_list_init(struct entry_list *);
- static int error_nomem(struct archive_match *);
- static void match_list_add(struct match_list *, struct match *);
- static void match_list_free(struct match_list *);
- static void match_list_init(struct match_list *);
- static int match_list_unmatched_inclusions_next(struct archive_match *,
- struct match_list *, int, const void **);
- static int match_owner_id(struct id_array *, int64_t);
- #if !defined(_WIN32) || defined(__CYGWIN__)
- static int match_owner_name_mbs(struct archive_match *,
- struct match_list *, const char *);
- #else
- static int match_owner_name_wcs(struct archive_match *,
- struct match_list *, const wchar_t *);
- #endif
- static int match_path_exclusion(struct archive_match *,
- struct match *, int, const void *);
- static int match_path_inclusion(struct archive_match *,
- struct match *, int, const void *);
- static int owner_excluded(struct archive_match *,
- struct archive_entry *);
- static int path_excluded(struct archive_match *, int, const void *);
- static int set_timefilter(struct archive_match *, int, time_t, long,
- time_t, long);
- static int set_timefilter_pathname_mbs(struct archive_match *,
- int, const char *);
- static int set_timefilter_pathname_wcs(struct archive_match *,
- int, const wchar_t *);
- static int set_timefilter_date(struct archive_match *, int, const char *);
- static int set_timefilter_date_w(struct archive_match *, int,
- const wchar_t *);
- static int time_excluded(struct archive_match *,
- struct archive_entry *);
- static int validate_time_flag(struct archive *, int, const char *);
- #define get_date __archive_get_date
- static const struct archive_rb_tree_ops rb_ops_mbs = {
- cmp_node_mbs, cmp_key_mbs
- };
- static const struct archive_rb_tree_ops rb_ops_wcs = {
- cmp_node_wcs, cmp_key_wcs
- };
- /*
- * The matching logic here needs to be re-thought. I started out to
- * try to mimic gtar's matching logic, but it's not entirely
- * consistent. In particular 'tar -t' and 'tar -x' interpret patterns
- * on the command line as anchored, but --exclude doesn't.
- */
- static int
- error_nomem(struct archive_match *a)
- {
- archive_set_error(&(a->archive), ENOMEM, "No memory");
- a->archive.state = ARCHIVE_STATE_FATAL;
- return (ARCHIVE_FATAL);
- }
- /*
- * Create an ARCHIVE_MATCH object.
- */
- struct archive *
- archive_match_new(void)
- {
- struct archive_match *a;
- a = (struct archive_match *)calloc(1, sizeof(*a));
- if (a == NULL)
- return (NULL);
- a->archive.magic = ARCHIVE_MATCH_MAGIC;
- a->archive.state = ARCHIVE_STATE_NEW;
- match_list_init(&(a->inclusions));
- match_list_init(&(a->exclusions));
- __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
- entry_list_init(&(a->exclusion_entry_list));
- match_list_init(&(a->inclusion_unames));
- match_list_init(&(a->inclusion_gnames));
- time(&a->now);
- return (&(a->archive));
- }
- /*
- * Free an ARCHIVE_MATCH object.
- */
- int
- archive_match_free(struct archive *_a)
- {
- struct archive_match *a;
- if (_a == NULL)
- return (ARCHIVE_OK);
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free");
- a = (struct archive_match *)_a;
- match_list_free(&(a->inclusions));
- match_list_free(&(a->exclusions));
- entry_list_free(&(a->exclusion_entry_list));
- free(a->inclusion_uids.ids);
- free(a->inclusion_gids.ids);
- match_list_free(&(a->inclusion_unames));
- match_list_free(&(a->inclusion_gnames));
- free(a);
- return (ARCHIVE_OK);
- }
- /*
- * Convenience function to perform all exclusion tests.
- *
- * Returns 1 if archive entry is excluded.
- * Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
- */
- int
- archive_match_excluded(struct archive *_a, struct archive_entry *entry)
- {
- struct archive_match *a;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_excluded_ae");
- a = (struct archive_match *)_a;
- if (entry == NULL) {
- archive_set_error(&(a->archive), EINVAL, "entry is NULL");
- return (ARCHIVE_FAILED);
- }
- r = 0;
- if (a->setflag & PATTERN_IS_SET) {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- r = path_excluded(a, 0, archive_entry_pathname_w(entry));
- #else
- r = path_excluded(a, 1, archive_entry_pathname(entry));
- #endif
- if (r != 0)
- return (r);
- }
- if (a->setflag & TIME_IS_SET) {
- r = time_excluded(a, entry);
- if (r != 0)
- return (r);
- }
- if (a->setflag & ID_IS_SET)
- r = owner_excluded(a, entry);
- return (r);
- }
- /*
- * Utility functions to manage exclusion/inclusion patterns
- */
- int
- archive_match_exclude_pattern(struct archive *_a, const char *pattern)
- {
- struct archive_match *a;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern");
- a = (struct archive_match *)_a;
- if (pattern == NULL || *pattern == '\0') {
- archive_set_error(&(a->archive), EINVAL, "pattern is empty");
- return (ARCHIVE_FAILED);
- }
- if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
- return (r);
- return (ARCHIVE_OK);
- }
- int
- archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern)
- {
- struct archive_match *a;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w");
- a = (struct archive_match *)_a;
- if (pattern == NULL || *pattern == L'\0') {
- archive_set_error(&(a->archive), EINVAL, "pattern is empty");
- return (ARCHIVE_FAILED);
- }
- if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
- return (r);
- return (ARCHIVE_OK);
- }
- int
- archive_match_exclude_pattern_from_file(struct archive *_a,
- const char *pathname, int nullSeparator)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file");
- a = (struct archive_match *)_a;
- return add_pattern_from_file(a, &(a->exclusions), 1, pathname,
- nullSeparator);
- }
- int
- archive_match_exclude_pattern_from_file_w(struct archive *_a,
- const wchar_t *pathname, int nullSeparator)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w");
- a = (struct archive_match *)_a;
- return add_pattern_from_file(a, &(a->exclusions), 0, pathname,
- nullSeparator);
- }
- int
- archive_match_include_pattern(struct archive *_a, const char *pattern)
- {
- struct archive_match *a;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_pattern");
- a = (struct archive_match *)_a;
- if (pattern == NULL || *pattern == '\0') {
- archive_set_error(&(a->archive), EINVAL, "pattern is empty");
- return (ARCHIVE_FAILED);
- }
- if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
- return (r);
- return (ARCHIVE_OK);
- }
- int
- archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern)
- {
- struct archive_match *a;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_pattern_w");
- a = (struct archive_match *)_a;
- if (pattern == NULL || *pattern == L'\0') {
- archive_set_error(&(a->archive), EINVAL, "pattern is empty");
- return (ARCHIVE_FAILED);
- }
- if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
- return (r);
- return (ARCHIVE_OK);
- }
- int
- archive_match_include_pattern_from_file(struct archive *_a,
- const char *pathname, int nullSeparator)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file");
- a = (struct archive_match *)_a;
- return add_pattern_from_file(a, &(a->inclusions), 1, pathname,
- nullSeparator);
- }
- int
- archive_match_include_pattern_from_file_w(struct archive *_a,
- const wchar_t *pathname, int nullSeparator)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w");
- a = (struct archive_match *)_a;
- return add_pattern_from_file(a, &(a->inclusions), 0, pathname,
- nullSeparator);
- }
- /*
- * Test functions for pathname patterns.
- *
- * Returns 1 if archive entry is excluded.
- * Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
- */
- int
- archive_match_path_excluded(struct archive *_a,
- struct archive_entry *entry)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_path_excluded");
- a = (struct archive_match *)_a;
- if (entry == NULL) {
- archive_set_error(&(a->archive), EINVAL, "entry is NULL");
- return (ARCHIVE_FAILED);
- }
- /* If we don't have exclusion/inclusion pattern set at all,
- * the entry is always not excluded. */
- if ((a->setflag & PATTERN_IS_SET) == 0)
- return (0);
- #if defined(_WIN32) && !defined(__CYGWIN__)
- return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
- #else
- return (path_excluded(a, 1, archive_entry_pathname(entry)));
- #endif
- }
- /*
- * Utility functions to get statistic information for inclusion patterns.
- */
- int
- archive_match_path_unmatched_inclusions(struct archive *_a)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
- a = (struct archive_match *)_a;
- return (a->inclusions.unmatched_count);
- }
- int
- archive_match_path_unmatched_inclusions_next(struct archive *_a,
- const char **_p)
- {
- struct archive_match *a;
- const void *v;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next");
- a = (struct archive_match *)_a;
- r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v);
- *_p = (const char *)v;
- return (r);
- }
- int
- archive_match_path_unmatched_inclusions_next_w(struct archive *_a,
- const wchar_t **_p)
- {
- struct archive_match *a;
- const void *v;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w");
- a = (struct archive_match *)_a;
- r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v);
- *_p = (const wchar_t *)v;
- return (r);
- }
- /*
- * Add inclusion/exclusion patterns.
- */
- static int
- add_pattern_mbs(struct archive_match *a, struct match_list *list,
- const char *pattern)
- {
- struct match *match;
- size_t len;
- match = calloc(1, sizeof(*match));
- if (match == NULL)
- return (error_nomem(a));
- /* Both "foo/" and "foo" should match "foo/bar". */
- len = strlen(pattern);
- if (len && pattern[len - 1] == '/')
- --len;
- archive_mstring_copy_mbs_len(&(match->pattern), pattern, len);
- match_list_add(list, match);
- a->setflag |= PATTERN_IS_SET;
- return (ARCHIVE_OK);
- }
- static int
- add_pattern_wcs(struct archive_match *a, struct match_list *list,
- const wchar_t *pattern)
- {
- struct match *match;
- size_t len;
- match = calloc(1, sizeof(*match));
- if (match == NULL)
- return (error_nomem(a));
- /* Both "foo/" and "foo" should match "foo/bar". */
- len = wcslen(pattern);
- if (len && pattern[len - 1] == L'/')
- --len;
- archive_mstring_copy_wcs_len(&(match->pattern), pattern, len);
- match_list_add(list, match);
- a->setflag |= PATTERN_IS_SET;
- return (ARCHIVE_OK);
- }
- static int
- add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
- int mbs, const void *pathname, int nullSeparator)
- {
- struct archive *ar;
- struct archive_entry *ae;
- struct archive_string as;
- const void *buff;
- size_t size;
- int64_t offset;
- int r;
- ar = archive_read_new();
- if (ar == NULL) {
- archive_set_error(&(a->archive), ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- r = archive_read_support_format_raw(ar);
- r = archive_read_support_format_empty(ar);
- if (r != ARCHIVE_OK) {
- archive_copy_error(&(a->archive), ar);
- archive_read_free(ar);
- return (r);
- }
- if (mbs)
- r = archive_read_open_filename(ar, pathname, 512*20);
- else
- r = archive_read_open_filename_w(ar, pathname, 512*20);
- if (r != ARCHIVE_OK) {
- archive_copy_error(&(a->archive), ar);
- archive_read_free(ar);
- return (r);
- }
- r = archive_read_next_header(ar, &ae);
- if (r != ARCHIVE_OK) {
- archive_read_free(ar);
- if (r == ARCHIVE_EOF) {
- return (ARCHIVE_OK);
- } else {
- archive_copy_error(&(a->archive), ar);
- return (r);
- }
- }
- archive_string_init(&as);
- while ((r = archive_read_data_block(ar, &buff, &size, &offset))
- == ARCHIVE_OK) {
- const char *b = (const char *)buff;
- while (size) {
- const char *s = (const char *)b;
- size_t length = 0;
- int found_separator = 0;
- while (length < size) {
- if (nullSeparator) {
- if (*b == '\0') {
- found_separator = 1;
- break;
- }
- } else {
- if (*b == 0x0d || *b == 0x0a) {
- found_separator = 1;
- break;
- }
- }
- b++;
- length++;
- }
- if (!found_separator) {
- archive_strncat(&as, s, length);
- /* Read next data block. */
- break;
- }
- b++;
- size -= length + 1;
- archive_strncat(&as, s, length);
- /* If the line is not empty, add the pattern. */
- if (archive_strlen(&as) > 0) {
- /* Add pattern. */
- r = add_pattern_mbs(a, mlist, as.s);
- if (r != ARCHIVE_OK) {
- archive_read_free(ar);
- archive_string_free(&as);
- return (r);
- }
- archive_string_empty(&as);
- }
- }
- }
- /* If an error occurred, report it immediately. */
- if (r < ARCHIVE_OK) {
- archive_copy_error(&(a->archive), ar);
- archive_read_free(ar);
- archive_string_free(&as);
- return (r);
- }
- /* If the line is not empty, add the pattern. */
- if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) {
- /* Add pattern. */
- r = add_pattern_mbs(a, mlist, as.s);
- if (r != ARCHIVE_OK) {
- archive_read_free(ar);
- archive_string_free(&as);
- return (r);
- }
- }
- archive_read_free(ar);
- archive_string_free(&as);
- return (ARCHIVE_OK);
- }
- /*
- * Test if pathname is excluded by inclusion/exclusion patterns.
- */
- static int
- path_excluded(struct archive_match *a, int mbs, const void *pathname)
- {
- struct match *match;
- struct match *matched;
- int r;
- if (a == NULL)
- return (0);
- /* Mark off any unmatched inclusions. */
- /* In particular, if a filename does appear in the archive and
- * is explicitly included and excluded, then we don't report
- * it as missing even though we don't extract it.
- */
- matched = NULL;
- for (match = a->inclusions.first; match != NULL;
- match = match->next){
- if (match->matches == 0 &&
- (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
- if (r < 0)
- return (r);
- a->inclusions.unmatched_count--;
- match->matches++;
- matched = match;
- }
- }
- /* Exclusions take priority */
- for (match = a->exclusions.first; match != NULL;
- match = match->next){
- r = match_path_exclusion(a, match, mbs, pathname);
- if (r)
- return (r);
- }
- /* It's not excluded and we found an inclusion above, so it's
- * included. */
- if (matched != NULL)
- return (0);
- /* We didn't find an unmatched inclusion, check the remaining ones. */
- for (match = a->inclusions.first; match != NULL;
- match = match->next){
- /* We looked at previously-unmatched inclusions already. */
- if (match->matches > 0 &&
- (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
- if (r < 0)
- return (r);
- match->matches++;
- return (0);
- }
- }
- /* If there were inclusions, default is to exclude. */
- if (a->inclusions.first != NULL)
- return (1);
- /* No explicit inclusions, default is to match. */
- return (0);
- }
- /*
- * This is a little odd, but it matches the default behavior of
- * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
- *
- */
- static int
- match_path_exclusion(struct archive_match *a, struct match *m,
- int mbs, const void *pn)
- {
- int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END;
- int r;
- if (mbs) {
- const char *p;
- r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
- if (r == 0)
- return (archive_pathmatch(p, (const char *)pn, flag));
- } else {
- const wchar_t *p;
- r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
- if (r == 0)
- return (archive_pathmatch_w(p, (const wchar_t *)pn,
- flag));
- }
- if (errno == ENOMEM)
- return (error_nomem(a));
- return (0);
- }
- /*
- * Again, mimic gtar: inclusions are always anchored (have to match
- * the beginning of the path) even though exclusions are not anchored.
- */
- static int
- match_path_inclusion(struct archive_match *a, struct match *m,
- int mbs, const void *pn)
- {
- int flag = PATHMATCH_NO_ANCHOR_END;
- int r;
- if (mbs) {
- const char *p;
- r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
- if (r == 0)
- return (archive_pathmatch(p, (const char *)pn, flag));
- } else {
- const wchar_t *p;
- r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
- if (r == 0)
- return (archive_pathmatch_w(p, (const wchar_t *)pn,
- flag));
- }
- if (errno == ENOMEM)
- return (error_nomem(a));
- return (0);
- }
- static void
- match_list_init(struct match_list *list)
- {
- list->first = NULL;
- list->last = &(list->first);
- list->count = 0;
- }
- static void
- match_list_free(struct match_list *list)
- {
- struct match *p, *q;
- for (p = list->first; p != NULL; ) {
- q = p;
- p = p->next;
- archive_mstring_clean(&(q->pattern));
- free(q);
- }
- }
- static void
- match_list_add(struct match_list *list, struct match *m)
- {
- *list->last = m;
- list->last = &(m->next);
- list->count++;
- list->unmatched_count++;
- }
- static int
- match_list_unmatched_inclusions_next(struct archive_match *a,
- struct match_list *list, int mbs, const void **vp)
- {
- struct match *m;
- *vp = NULL;
- if (list->unmatched_eof) {
- list->unmatched_eof = 0;
- return (ARCHIVE_EOF);
- }
- if (list->unmatched_next == NULL) {
- if (list->unmatched_count == 0)
- return (ARCHIVE_EOF);
- list->unmatched_next = list->first;
- }
- for (m = list->unmatched_next; m != NULL; m = m->next) {
- int r;
- if (m->matches)
- continue;
- if (mbs) {
- const char *p;
- r = archive_mstring_get_mbs(&(a->archive),
- &(m->pattern), &p);
- if (r < 0 && errno == ENOMEM)
- return (error_nomem(a));
- if (p == NULL)
- p = "";
- *vp = p;
- } else {
- const wchar_t *p;
- r = archive_mstring_get_wcs(&(a->archive),
- &(m->pattern), &p);
- if (r < 0 && errno == ENOMEM)
- return (error_nomem(a));
- if (p == NULL)
- p = L"";
- *vp = p;
- }
- list->unmatched_next = m->next;
- if (list->unmatched_next == NULL)
- /* To return EOF next time. */
- list->unmatched_eof = 1;
- return (ARCHIVE_OK);
- }
- list->unmatched_next = NULL;
- return (ARCHIVE_EOF);
- }
- /*
- * Utility functions to manage inclusion timestamps.
- */
- int
- archive_match_include_time(struct archive *_a, int flag, time_t sec,
- long nsec)
- {
- int r;
- r = validate_time_flag(_a, flag, "archive_match_include_time");
- if (r != ARCHIVE_OK)
- return (r);
- return set_timefilter((struct archive_match *)_a, flag,
- sec, nsec, sec, nsec);
- }
- int
- archive_match_include_date(struct archive *_a, int flag,
- const char *datestr)
- {
- int r;
- r = validate_time_flag(_a, flag, "archive_match_include_date");
- if (r != ARCHIVE_OK)
- return (r);
- return set_timefilter_date((struct archive_match *)_a, flag, datestr);
- }
- int
- archive_match_include_date_w(struct archive *_a, int flag,
- const wchar_t *datestr)
- {
- int r;
- r = validate_time_flag(_a, flag, "archive_match_include_date_w");
- if (r != ARCHIVE_OK)
- return (r);
- return set_timefilter_date_w((struct archive_match *)_a, flag, datestr);
- }
- int
- archive_match_include_file_time(struct archive *_a, int flag,
- const char *pathname)
- {
- int r;
- r = validate_time_flag(_a, flag, "archive_match_include_file_time");
- if (r != ARCHIVE_OK)
- return (r);
- return set_timefilter_pathname_mbs((struct archive_match *)_a,
- flag, pathname);
- }
- int
- archive_match_include_file_time_w(struct archive *_a, int flag,
- const wchar_t *pathname)
- {
- int r;
- r = validate_time_flag(_a, flag, "archive_match_include_file_time_w");
- if (r != ARCHIVE_OK)
- return (r);
- return set_timefilter_pathname_wcs((struct archive_match *)_a,
- flag, pathname);
- }
- int
- archive_match_exclude_entry(struct archive *_a, int flag,
- struct archive_entry *entry)
- {
- struct archive_match *a;
- int r;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_time_include_entry");
- a = (struct archive_match *)_a;
- if (entry == NULL) {
- archive_set_error(&(a->archive), EINVAL, "entry is NULL");
- return (ARCHIVE_FAILED);
- }
- r = validate_time_flag(_a, flag, "archive_match_exclude_entry");
- if (r != ARCHIVE_OK)
- return (r);
- return (add_entry(a, flag, entry));
- }
- /*
- * Test function for time stamps.
- *
- * Returns 1 if archive entry is excluded.
- * Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
- */
- int
- archive_match_time_excluded(struct archive *_a,
- struct archive_entry *entry)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae");
- a = (struct archive_match *)_a;
- if (entry == NULL) {
- archive_set_error(&(a->archive), EINVAL, "entry is NULL");
- return (ARCHIVE_FAILED);
- }
- /* If we don't have inclusion time set at all, the entry is always
- * not excluded. */
- if ((a->setflag & TIME_IS_SET) == 0)
- return (0);
- return (time_excluded(a, entry));
- }
- static int
- validate_time_flag(struct archive *_a, int flag, const char *_fn)
- {
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, _fn);
- /* Check a type of time. */
- if (flag &
- ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) {
- archive_set_error(_a, EINVAL, "Invalid time flag");
- return (ARCHIVE_FAILED);
- }
- if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) {
- archive_set_error(_a, EINVAL, "No time flag");
- return (ARCHIVE_FAILED);
- }
- /* Check a type of comparison. */
- if (flag &
- ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
- | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) {
- archive_set_error(_a, EINVAL, "Invalid comparison flag");
- return (ARCHIVE_FAILED);
- }
- if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
- | ARCHIVE_MATCH_EQUAL)) == 0) {
- archive_set_error(_a, EINVAL, "No comparison flag");
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
- }
- #define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\
- ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL)
- static int
- set_timefilter(struct archive_match *a, int timetype,
- time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec)
- {
- if (timetype & ARCHIVE_MATCH_MTIME) {
- if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
- a->newer_mtime_filter = timetype;
- a->newer_mtime_sec = mtime_sec;
- a->newer_mtime_nsec = mtime_nsec;
- a->setflag |= TIME_IS_SET;
- }
- if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
- a->older_mtime_filter = timetype;
- a->older_mtime_sec = mtime_sec;
- a->older_mtime_nsec = mtime_nsec;
- a->setflag |= TIME_IS_SET;
- }
- }
- if (timetype & ARCHIVE_MATCH_CTIME) {
- if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
- a->newer_ctime_filter = timetype;
- a->newer_ctime_sec = ctime_sec;
- a->newer_ctime_nsec = ctime_nsec;
- a->setflag |= TIME_IS_SET;
- }
- if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
- a->older_ctime_filter = timetype;
- a->older_ctime_sec = ctime_sec;
- a->older_ctime_nsec = ctime_nsec;
- a->setflag |= TIME_IS_SET;
- }
- }
- return (ARCHIVE_OK);
- }
- static int
- set_timefilter_date(struct archive_match *a, int timetype, const char *datestr)
- {
- time_t t;
- if (datestr == NULL || *datestr == '\0') {
- archive_set_error(&(a->archive), EINVAL, "date is empty");
- return (ARCHIVE_FAILED);
- }
- t = get_date(a->now, datestr);
- if (t == (time_t)-1) {
- archive_set_error(&(a->archive), EINVAL, "invalid date string");
- return (ARCHIVE_FAILED);
- }
- return set_timefilter(a, timetype, t, 0, t, 0);
- }
- static int
- set_timefilter_date_w(struct archive_match *a, int timetype,
- const wchar_t *datestr)
- {
- struct archive_string as;
- time_t t;
- if (datestr == NULL || *datestr == L'\0') {
- archive_set_error(&(a->archive), EINVAL, "date is empty");
- return (ARCHIVE_FAILED);
- }
- archive_string_init(&as);
- if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) {
- archive_string_free(&as);
- if (errno == ENOMEM)
- return (error_nomem(a));
- archive_set_error(&(a->archive), -1,
- "Failed to convert WCS to MBS");
- return (ARCHIVE_FAILED);
- }
- t = get_date(a->now, as.s);
- archive_string_free(&as);
- if (t == (time_t)-1) {
- archive_set_error(&(a->archive), EINVAL, "invalid date string");
- return (ARCHIVE_FAILED);
- }
- return set_timefilter(a, timetype, t, 0, t, 0);
- }
- #if defined(_WIN32) && !defined(__CYGWIN__)
- #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
- static int
- set_timefilter_find_data(struct archive_match *a, int timetype,
- DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime,
- DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime)
- {
- ULARGE_INTEGER utc;
- time_t ctime_sec, mtime_sec;
- long ctime_ns, mtime_ns;
- utc.HighPart = ftCreationTime_dwHighDateTime;
- utc.LowPart = ftCreationTime_dwLowDateTime;
- if (utc.QuadPart >= EPOC_TIME) {
- utc.QuadPart -= EPOC_TIME;
- ctime_sec = (time_t)(utc.QuadPart / 10000000);
- ctime_ns = (long)(utc.QuadPart % 10000000) * 100;
- } else {
- ctime_sec = 0;
- ctime_ns = 0;
- }
- utc.HighPart = ftLastWriteTime_dwHighDateTime;
- utc.LowPart = ftLastWriteTime_dwLowDateTime;
- if (utc.QuadPart >= EPOC_TIME) {
- utc.QuadPart -= EPOC_TIME;
- mtime_sec = (time_t)(utc.QuadPart / 10000000);
- mtime_ns = (long)(utc.QuadPart % 10000000) * 100;
- } else {
- mtime_sec = 0;
- mtime_ns = 0;
- }
- return set_timefilter(a, timetype,
- mtime_sec, mtime_ns, ctime_sec, ctime_ns);
- }
- static int
- set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
- const char *path)
- {
- /* NOTE: stat() on Windows cannot handle nano seconds. */
- HANDLE h;
- WIN32_FIND_DATAA d;
- if (path == NULL || *path == '\0') {
- archive_set_error(&(a->archive), EINVAL, "pathname is empty");
- return (ARCHIVE_FAILED);
- }
- h = FindFirstFileA(path, &d);
- if (h == INVALID_HANDLE_VALUE) {
- la_dosmaperr(GetLastError());
- archive_set_error(&(a->archive), errno,
- "Failed to FindFirstFileA");
- return (ARCHIVE_FAILED);
- }
- FindClose(h);
- return set_timefilter_find_data(a, timetype,
- d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
- d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
- }
- static int
- set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
- const wchar_t *path)
- {
- HANDLE h;
- WIN32_FIND_DATAW d;
- if (path == NULL || *path == L'\0') {
- archive_set_error(&(a->archive), EINVAL, "pathname is empty");
- return (ARCHIVE_FAILED);
- }
- h = FindFirstFileW(path, &d);
- if (h == INVALID_HANDLE_VALUE) {
- la_dosmaperr(GetLastError());
- archive_set_error(&(a->archive), errno,
- "Failed to FindFirstFile");
- return (ARCHIVE_FAILED);
- }
- FindClose(h);
- return set_timefilter_find_data(a, timetype,
- d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
- d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
- }
- #else /* _WIN32 && !__CYGWIN__ */
- static int
- set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st)
- {
- struct archive_entry *ae;
- time_t ctime_sec, mtime_sec;
- long ctime_ns, mtime_ns;
- ae = archive_entry_new();
- if (ae == NULL)
- return (error_nomem(a));
- archive_entry_copy_stat(ae, st);
- ctime_sec = archive_entry_ctime(ae);
- ctime_ns = archive_entry_ctime_nsec(ae);
- mtime_sec = archive_entry_mtime(ae);
- mtime_ns = archive_entry_mtime_nsec(ae);
- archive_entry_free(ae);
- return set_timefilter(a, timetype, mtime_sec, mtime_ns,
- ctime_sec, ctime_ns);
- }
- static int
- set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
- const char *path)
- {
- struct stat st;
- if (path == NULL || *path == '\0') {
- archive_set_error(&(a->archive), EINVAL, "pathname is empty");
- return (ARCHIVE_FAILED);
- }
- if (stat(path, &st) != 0) {
- archive_set_error(&(a->archive), errno, "Failed to stat()");
- return (ARCHIVE_FAILED);
- }
- return (set_timefilter_stat(a, timetype, &st));
- }
- static int
- set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
- const wchar_t *path)
- {
- struct archive_string as;
- int r;
- if (path == NULL || *path == L'\0') {
- archive_set_error(&(a->archive), EINVAL, "pathname is empty");
- return (ARCHIVE_FAILED);
- }
- /* Convert WCS filename to MBS filename. */
- archive_string_init(&as);
- if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) {
- archive_string_free(&as);
- if (errno == ENOMEM)
- return (error_nomem(a));
- archive_set_error(&(a->archive), -1,
- "Failed to convert WCS to MBS");
- return (ARCHIVE_FAILED);
- }
- r = set_timefilter_pathname_mbs(a, timetype, as.s);
- archive_string_free(&as);
- return (r);
- }
- #endif /* _WIN32 && !__CYGWIN__ */
- /*
- * Call back functions for archive_rb.
- */
- static int
- cmp_node_mbs(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
- {
- struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
- struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
- const char *p1, *p2;
- archive_mstring_get_mbs(NULL, &(f1->pathname), &p1);
- archive_mstring_get_mbs(NULL, &(f2->pathname), &p2);
- if (p1 == NULL)
- return (1);
- if (p2 == NULL)
- return (-1);
- return (strcmp(p1, p2));
- }
-
- static int
- cmp_key_mbs(const struct archive_rb_node *n, const void *key)
- {
- struct match_file *f = (struct match_file *)(uintptr_t)n;
- const char *p;
- archive_mstring_get_mbs(NULL, &(f->pathname), &p);
- if (p == NULL)
- return (-1);
- return (strcmp(p, (const char *)key));
- }
- static int
- cmp_node_wcs(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
- {
- struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
- struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
- const wchar_t *p1, *p2;
- archive_mstring_get_wcs(NULL, &(f1->pathname), &p1);
- archive_mstring_get_wcs(NULL, &(f2->pathname), &p2);
- if (p1 == NULL)
- return (1);
- if (p2 == NULL)
- return (-1);
- return (wcscmp(p1, p2));
- }
-
- static int
- cmp_key_wcs(const struct archive_rb_node *n, const void *key)
- {
- struct match_file *f = (struct match_file *)(uintptr_t)n;
- const wchar_t *p;
- archive_mstring_get_wcs(NULL, &(f->pathname), &p);
- if (p == NULL)
- return (-1);
- return (wcscmp(p, (const wchar_t *)key));
- }
- static void
- entry_list_init(struct entry_list *list)
- {
- list->first = NULL;
- list->last = &(list->first);
- list->count = 0;
- }
- static void
- entry_list_free(struct entry_list *list)
- {
- struct match_file *p, *q;
- for (p = list->first; p != NULL; ) {
- q = p;
- p = p->next;
- archive_mstring_clean(&(q->pathname));
- free(q);
- }
- }
- static void
- entry_list_add(struct entry_list *list, struct match_file *file)
- {
- *list->last = file;
- list->last = &(file->next);
- list->count++;
- }
- static int
- add_entry(struct archive_match *a, int flag,
- struct archive_entry *entry)
- {
- struct match_file *f;
- const void *pathname;
- int r;
- f = calloc(1, sizeof(*f));
- if (f == NULL)
- return (error_nomem(a));
- #if defined(_WIN32) && !defined(__CYGWIN__)
- pathname = archive_entry_pathname_w(entry);
- if (pathname == NULL) {
- free(f);
- archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
- return (ARCHIVE_FAILED);
- }
- archive_mstring_copy_wcs(&(f->pathname), pathname);
- a->exclusion_tree.rbt_ops = &rb_ops_wcs;
- #else
- (void)rb_ops_wcs;
- pathname = archive_entry_pathname(entry);
- if (pathname == NULL) {
- free(f);
- archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
- return (ARCHIVE_FAILED);
- }
- archive_mstring_copy_mbs(&(f->pathname), pathname);
- a->exclusion_tree.rbt_ops = &rb_ops_mbs;
- #endif
- f->flag = flag;
- f->mtime_sec = archive_entry_mtime(entry);
- f->mtime_nsec = archive_entry_mtime_nsec(entry);
- f->ctime_sec = archive_entry_ctime(entry);
- f->ctime_nsec = archive_entry_ctime_nsec(entry);
- r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node));
- if (!r) {
- struct match_file *f2;
- /* Get the duplicated file. */
- f2 = (struct match_file *)__archive_rb_tree_find_node(
- &(a->exclusion_tree), pathname);
- /*
- * We always overwrite comparison condition.
- * If you do not want to overwrite it, you should not
- * call archive_match_exclude_entry(). We cannot know
- * what behavior you really expect since overwriting
- * condition might be different with the flag.
- */
- if (f2 != NULL) {
- f2->flag = f->flag;
- f2->mtime_sec = f->mtime_sec;
- f2->mtime_nsec = f->mtime_nsec;
- f2->ctime_sec = f->ctime_sec;
- f2->ctime_nsec = f->ctime_nsec;
- }
- /* Release the duplicated file. */
- archive_mstring_clean(&(f->pathname));
- free(f);
- return (ARCHIVE_OK);
- }
- entry_list_add(&(a->exclusion_entry_list), f);
- a->setflag |= TIME_IS_SET;
- return (ARCHIVE_OK);
- }
- /*
- * Test if entry is excluded by its timestamp.
- */
- static int
- time_excluded(struct archive_match *a, struct archive_entry *entry)
- {
- struct match_file *f;
- const void *pathname;
- time_t sec;
- long nsec;
- /*
- * If this file/dir is excluded by a time comparison, skip it.
- */
- if (a->newer_ctime_filter) {
- /* If ctime is not set, use mtime instead. */
- if (archive_entry_ctime_is_set(entry))
- sec = archive_entry_ctime(entry);
- else
- sec = archive_entry_mtime(entry);
- if (sec < a->newer_ctime_sec)
- return (1); /* Too old, skip it. */
- if (sec == a->newer_ctime_sec) {
- if (archive_entry_ctime_is_set(entry))
- nsec = archive_entry_ctime_nsec(entry);
- else
- nsec = archive_entry_mtime_nsec(entry);
- if (nsec < a->newer_ctime_nsec)
- return (1); /* Too old, skip it. */
- if (nsec == a->newer_ctime_nsec &&
- (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL)
- == 0)
- return (1); /* Equal, skip it. */
- }
- }
- if (a->older_ctime_filter) {
- /* If ctime is not set, use mtime instead. */
- if (archive_entry_ctime_is_set(entry))
- sec = archive_entry_ctime(entry);
- else
- sec = archive_entry_mtime(entry);
- if (sec > a->older_ctime_sec)
- return (1); /* Too new, skip it. */
- if (sec == a->older_ctime_sec) {
- if (archive_entry_ctime_is_set(entry))
- nsec = archive_entry_ctime_nsec(entry);
- else
- nsec = archive_entry_mtime_nsec(entry);
- if (nsec > a->older_ctime_nsec)
- return (1); /* Too new, skip it. */
- if (nsec == a->older_ctime_nsec &&
- (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
- == 0)
- return (1); /* Equal, skip it. */
- }
- }
- if (a->newer_mtime_filter) {
- sec = archive_entry_mtime(entry);
- if (sec < a->newer_mtime_sec)
- return (1); /* Too old, skip it. */
- if (sec == a->newer_mtime_sec) {
- nsec = archive_entry_mtime_nsec(entry);
- if (nsec < a->newer_mtime_nsec)
- return (1); /* Too old, skip it. */
- if (nsec == a->newer_mtime_nsec &&
- (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL)
- == 0)
- return (1); /* Equal, skip it. */
- }
- }
- if (a->older_mtime_filter) {
- sec = archive_entry_mtime(entry);
- if (sec > a->older_mtime_sec)
- return (1); /* Too new, skip it. */
- nsec = archive_entry_mtime_nsec(entry);
- if (sec == a->older_mtime_sec) {
- if (nsec > a->older_mtime_nsec)
- return (1); /* Too new, skip it. */
- if (nsec == a->older_mtime_nsec &&
- (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL)
- == 0)
- return (1); /* Equal, skip it. */
- }
- }
- /* If there is no exclusion list, include the file. */
- if (a->exclusion_entry_list.count == 0)
- return (0);
- #if defined(_WIN32) && !defined(__CYGWIN__)
- pathname = archive_entry_pathname_w(entry);
- a->exclusion_tree.rbt_ops = &rb_ops_wcs;
- #else
- (void)rb_ops_wcs;
- pathname = archive_entry_pathname(entry);
- a->exclusion_tree.rbt_ops = &rb_ops_mbs;
- #endif
- if (pathname == NULL)
- return (0);
- f = (struct match_file *)__archive_rb_tree_find_node(
- &(a->exclusion_tree), pathname);
- /* If the file wasn't rejected, include it. */
- if (f == NULL)
- return (0);
- if (f->flag & ARCHIVE_MATCH_CTIME) {
- sec = archive_entry_ctime(entry);
- if (f->ctime_sec > sec) {
- if (f->flag & ARCHIVE_MATCH_OLDER)
- return (1);
- } else if (f->ctime_sec < sec) {
- if (f->flag & ARCHIVE_MATCH_NEWER)
- return (1);
- } else {
- nsec = archive_entry_ctime_nsec(entry);
- if (f->ctime_nsec > nsec) {
- if (f->flag & ARCHIVE_MATCH_OLDER)
- return (1);
- } else if (f->ctime_nsec < nsec) {
- if (f->flag & ARCHIVE_MATCH_NEWER)
- return (1);
- } else if (f->flag & ARCHIVE_MATCH_EQUAL)
- return (1);
- }
- }
- if (f->flag & ARCHIVE_MATCH_MTIME) {
- sec = archive_entry_mtime(entry);
- if (f->mtime_sec > sec) {
- if (f->flag & ARCHIVE_MATCH_OLDER)
- return (1);
- } else if (f->mtime_sec < sec) {
- if (f->flag & ARCHIVE_MATCH_NEWER)
- return (1);
- } else {
- nsec = archive_entry_mtime_nsec(entry);
- if (f->mtime_nsec > nsec) {
- if (f->flag & ARCHIVE_MATCH_OLDER)
- return (1);
- } else if (f->mtime_nsec < nsec) {
- if (f->flag & ARCHIVE_MATCH_NEWER)
- return (1);
- } else if (f->flag & ARCHIVE_MATCH_EQUAL)
- return (1);
- }
- }
- return (0);
- }
- /*
- * Utility functions to manage inclusion owners
- */
- int
- archive_match_include_uid(struct archive *_a, int64_t uid)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_uid");
- a = (struct archive_match *)_a;
- return (add_owner_id(a, &(a->inclusion_uids), uid));
- }
- int
- archive_match_include_gid(struct archive *_a, int64_t gid)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_gid");
- a = (struct archive_match *)_a;
- return (add_owner_id(a, &(a->inclusion_gids), gid));
- }
- int
- archive_match_include_uname(struct archive *_a, const char *uname)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_uname");
- a = (struct archive_match *)_a;
- return (add_owner_name(a, &(a->inclusion_unames), 1, uname));
- }
- int
- archive_match_include_uname_w(struct archive *_a, const wchar_t *uname)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_uname_w");
- a = (struct archive_match *)_a;
- return (add_owner_name(a, &(a->inclusion_unames), 0, uname));
- }
- int
- archive_match_include_gname(struct archive *_a, const char *gname)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_gname");
- a = (struct archive_match *)_a;
- return (add_owner_name(a, &(a->inclusion_gnames), 1, gname));
- }
- int
- archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_include_gname_w");
- a = (struct archive_match *)_a;
- return (add_owner_name(a, &(a->inclusion_gnames), 0, gname));
- }
- /*
- * Test function for owner(uid, gid, uname, gname).
- *
- * Returns 1 if archive entry is excluded.
- * Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
- */
- int
- archive_match_owner_excluded(struct archive *_a,
- struct archive_entry *entry)
- {
- struct archive_match *a;
- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
- ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae");
- a = (struct archive_match *)_a;
- if (entry == NULL) {
- archive_set_error(&(a->archive), EINVAL, "entry is NULL");
- return (ARCHIVE_FAILED);
- }
- /* If we don't have inclusion id set at all, the entry is always
- * not excluded. */
- if ((a->setflag & ID_IS_SET) == 0)
- return (0);
- return (owner_excluded(a, entry));
- }
- static int
- add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
- {
- unsigned i;
- if (ids->count + 1 >= ids->size) {
- void *p;
- if (ids->size == 0)
- ids->size = 8;
- else
- ids->size *= 2;
- p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
- if (p == NULL)
- return (error_nomem(a));
- ids->ids = (int64_t *)p;
- }
- /* Find an insert point. */
- for (i = 0; i < ids->count; i++) {
- if (ids->ids[i] >= id)
- break;
- }
- /* Add owner id. */
- if (i == ids->count)
- ids->ids[ids->count++] = id;
- else if (ids->ids[i] != id) {
- memmove(&(ids->ids[i+1]), &(ids->ids[i]),
- (ids->count - i) * sizeof(ids->ids[0]));
- ids->ids[i] = id;
- ids->count++;
- }
- a->setflag |= ID_IS_SET;
- return (ARCHIVE_OK);
- }
- static int
- match_owner_id(struct id_array *ids, int64_t id)
- {
- unsigned b, m, t;
- t = 0;
- b = (unsigned)ids->count;
- while (t < b) {
- m = (t + b)>>1;
- if (ids->ids[m] == id)
- return (1);
- if (ids->ids[m] < id)
- t = m + 1;
- else
- b = m;
- }
- return (0);
- }
- static int
- add_owner_name(struct archive_match *a, struct match_list *list,
- int mbs, const void *name)
- {
- struct match *match;
- match = calloc(1, sizeof(*match));
- if (match == NULL)
- return (error_nomem(a));
- if (mbs)
- archive_mstring_copy_mbs(&(match->pattern), name);
- else
- archive_mstring_copy_wcs(&(match->pattern), name);
- match_list_add(list, match);
- a->setflag |= ID_IS_SET;
- return (ARCHIVE_OK);
- }
- #if !defined(_WIN32) || defined(__CYGWIN__)
- static int
- match_owner_name_mbs(struct archive_match *a, struct match_list *list,
- const char *name)
- {
- struct match *m;
- const char *p;
- if (name == NULL || *name == '\0')
- return (0);
- for (m = list->first; m; m = m->next) {
- if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p)
- < 0 && errno == ENOMEM)
- return (error_nomem(a));
- if (p != NULL && strcmp(p, name) == 0) {
- m->matches++;
- return (1);
- }
- }
- return (0);
- }
- #else
- static int
- match_owner_name_wcs(struct archive_match *a, struct match_list *list,
- const wchar_t *name)
- {
- struct match *m;
- const wchar_t *p;
- if (name == NULL || *name == L'\0')
- return (0);
- for (m = list->first; m; m = m->next) {
- if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p)
- < 0 && errno == ENOMEM)
- return (error_nomem(a));
- if (p != NULL && wcscmp(p, name) == 0) {
- m->matches++;
- return (1);
- }
- }
- return (0);
- }
- #endif
- /*
- * Test if entry is excluded by uid, gid, uname or gname.
- */
- static int
- owner_excluded(struct archive_match *a, struct archive_entry *entry)
- {
- int r;
- if (a->inclusion_uids.count) {
- if (!match_owner_id(&(a->inclusion_uids),
- archive_entry_uid(entry)))
- return (1);
- }
- if (a->inclusion_gids.count) {
- if (!match_owner_id(&(a->inclusion_gids),
- archive_entry_gid(entry)))
- return (1);
- }
- if (a->inclusion_unames.count) {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- r = match_owner_name_wcs(a, &(a->inclusion_unames),
- archive_entry_uname_w(entry));
- #else
- r = match_owner_name_mbs(a, &(a->inclusion_unames),
- archive_entry_uname(entry));
- #endif
- if (!r)
- return (1);
- else if (r < 0)
- return (r);
- }
- if (a->inclusion_gnames.count) {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- r = match_owner_name_wcs(a, &(a->inclusion_gnames),
- archive_entry_gname_w(entry));
- #else
- r = match_owner_name_mbs(a, &(a->inclusion_gnames),
- archive_entry_gname(entry));
- #endif
- if (!r)
- return (1);
- else if (r < 0)
- return (r);
- }
- return (0);
- }
|