From: Eric Biggers Date: Sun, 31 May 2015 22:28:04 +0000 (-0500) Subject: Simplify wildcard pattern expansion X-Git-Tag: v1.8.2~73 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=d5a64bb4299105c93b4e9a95e97b579c6f9254af Simplify wildcard pattern expansion --- diff --git a/Makefile.am b/Makefile.am index 206a0c22..647521e0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -70,6 +70,7 @@ libwim_la_SOURCES = \ src/mount_image.c \ src/pathlist.c \ src/paths.c \ + src/pattern.c \ src/progress.c \ src/resource.c \ src/reference.c \ @@ -85,7 +86,6 @@ libwim_la_SOURCES = \ src/update_image.c \ src/util.c \ src/verify.c \ - src/wildcard.c \ src/wim.c \ src/write.c \ src/xml.c \ @@ -134,6 +134,7 @@ libwim_la_SOURCES = \ include/wimlib/metadata.h \ include/wimlib/pathlist.h \ include/wimlib/paths.h \ + include/wimlib/pattern.h \ include/wimlib/progress.h \ include/wimlib/reparse.h \ include/wimlib/resource.h \ @@ -147,7 +148,6 @@ libwim_la_SOURCES = \ include/wimlib/unaligned.h \ include/wimlib/unix_data.h \ include/wimlib/util.h \ - include/wimlib/wildcard.h \ include/wimlib/wim.h \ include/wimlib/write.h \ include/wimlib/xml.h \ diff --git a/include/wimlib/capture.h b/include/wimlib/capture.h index 9ab48f73..7372c052 100644 --- a/include/wimlib/capture.h +++ b/include/wimlib/capture.h @@ -76,12 +76,10 @@ extern void destroy_capture_config(struct capture_config *config); extern bool -match_pattern_list(const tchar *path, size_t path_nchars, - const struct string_set *list); +match_pattern_list(const tchar *path, const struct string_set *list); extern int -try_exclude(const tchar *full_path, size_t full_path_nchars, - const struct capture_params *params); +try_exclude(const tchar *full_path, const struct capture_params *params); typedef int (*capture_tree_t)(struct wim_dentry **, const tchar *, struct capture_params *); diff --git a/include/wimlib/pattern.h b/include/wimlib/pattern.h new file mode 100644 index 00000000..67c20730 --- /dev/null +++ b/include/wimlib/pattern.h @@ -0,0 +1,16 @@ +#ifndef _WIMLIB_PATTERN_H +#define _WIMLIB_PATTERN_H + +#include "wimlib/types.h" + +struct wim_dentry; + +extern bool +match_path(const tchar *path, const tchar *pattern, bool prefix_ok); + +extern int +expand_path_pattern(struct wim_dentry *root, const tchar *pattern, + int (*consume_dentry)(struct wim_dentry *, void *), + void *ctx); + +#endif /* _WIMLIB_PATTERN_H */ diff --git a/include/wimlib/wildcard.h b/include/wimlib/wildcard.h deleted file mode 100644 index 4cf21eef..00000000 --- a/include/wimlib/wildcard.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _WIMLIB_WILDCARD_H -#define _WIMLIB_WILDCARD_H - -#include "wimlib/types.h" - -struct wim_dentry; - -#define WILDCARD_FLAG_WARN_IF_NO_MATCH 0x00000001 -#define WILDCARD_FLAG_ERROR_IF_NO_MATCH 0x00000002 -#define WILDCARD_FLAG_CASE_INSENSITIVE 0x00000004 - -extern int -expand_wildcard(WIMStruct *wim, - const tchar *wildcard_path, - int (*consume_dentry)(struct wim_dentry *, void *), - void *consume_dentry_ctx, - u32 flags); - -extern bool -match_path(const tchar *path, size_t path_nchars, - const tchar *wildcard, tchar path_sep, bool prefix_ok); - -#endif /* _WIMLIB_WILDCARD_H */ diff --git a/src/capture_common.c b/src/capture_common.c index e544b7c1..e088afcb 100644 --- a/src/capture_common.c +++ b/src/capture_common.c @@ -30,9 +30,9 @@ #include "wimlib/dentry.h" #include "wimlib/error.h" #include "wimlib/paths.h" +#include "wimlib/pattern.h" #include "wimlib/progress.h" #include "wimlib/textfile.h" -#include "wimlib/wildcard.h" /* * Tally a file (or directory) that has been scanned for a capture operation, @@ -240,62 +240,22 @@ destroy_capture_config(struct capture_config *config) } /* - * Determine whether a path matches any wildcard pattern in a list. - * - * Special rules apply about what form @path must be in; see match_path(). + * Determine whether @path, or any ancestor directory of @path, matches any of + * the patterns in @list. Path separators in @path must be WIM_PATH_SEPARATOR. */ bool -match_pattern_list(const tchar *path, size_t path_nchars, - const struct string_set *list) +match_pattern_list(const tchar *path, const struct string_set *list) { for (size_t i = 0; i < list->num_strings; i++) - if (match_path(path, path_nchars, list->strings[i], - OS_PREFERRED_PATH_SEPARATOR, true)) + if (match_path(path, list->strings[i], true)) return true; return false; } -/* - * Determine whether the filesystem @path should be excluded from capture, based - * on the current capture configuration file. - * - * The @path must be given relative to the root of the capture, but with a - * leading path separator. For example, if the file "in/file" is being tested - * and the library user ran wimlib_add_image(wim, "in", ...), then the directory - * "in" is the root of the capture and the path should be specified as "/file". - * - * Also, all path separators in @path must be OS_PREFERRED_PATH_SEPARATOR, there - * cannot be trailing slashes, and there cannot be consecutive path separators. - * - * As a special case, the empty string will be interpreted as a single path - * separator (which means the root of capture itself). - */ -static bool -should_exclude_path(const tchar *path, size_t path_nchars, - const struct capture_config *config) -{ - tchar dummy[2]; - - if (!config) - return false; - - if (!*path) { - dummy[0] = OS_PREFERRED_PATH_SEPARATOR; - dummy[1] = T('\0'); - path = dummy; - path_nchars = 1; - } - - return match_pattern_list(path, path_nchars, &config->exclusion_pats) && - !match_pattern_list(path, path_nchars, &config->exclusion_exception_pats); - -} - /* * Determine if a file should be excluded from capture. * - * This function tests exclusions from both of the two possible sources of - * exclusions: + * This function tests exclusions from both possible sources of exclusions: * * (1) The capture configuration file * (2) The user-provided progress function @@ -304,9 +264,8 @@ should_exclude_path(const tchar *path, size_t path_nchars, * appropriate value. Example for UNIX: if the capture root directory is * "foobar/subdir", then all paths will be provided starting with * "foobar/subdir", so params->capture_root_nchars must be set to - * strlen("foobar/subdir") so that try_exclude() can use the appropriate suffix - * when it calls should_exclude_path(). - * + * strlen("foobar/subdir") so that the appropriate path can be matched against + * the patterns in the exclusion list. * * Returns: * < 0 if excluded @@ -314,15 +273,16 @@ should_exclude_path(const tchar *path, size_t path_nchars, * > 0 (wimlib error code) if error */ int -try_exclude(const tchar *full_path, size_t full_path_nchars, - const struct capture_params *params) +try_exclude(const tchar *full_path, const struct capture_params *params) { int ret; - if (should_exclude_path(full_path + params->capture_root_nchars, - full_path_nchars - params->capture_root_nchars, - params->config)) - return -1; + if (params->config) { + const tchar *path = full_path + params->capture_root_nchars; + if (match_pattern_list(path, ¶ms->config->exclusion_pats) && + !match_pattern_list(path, ¶ms->config->exclusion_exception_pats)) + return -1; + } if (unlikely(params->add_flags & WIMLIB_ADD_FLAG_TEST_FILE_EXCLUSION)) { union wimlib_progress_info info; diff --git a/src/extract.c b/src/extract.c index 625224b3..b200e18c 100644 --- a/src/extract.c +++ b/src/extract.c @@ -54,11 +54,11 @@ #include "wimlib/metadata.h" #include "wimlib/pathlist.h" #include "wimlib/paths.h" +#include "wimlib/pattern.h" #include "wimlib/reparse.h" #include "wimlib/resource.h" #include "wimlib/security.h" #include "wimlib/unix_data.h" -#include "wimlib/wildcard.h" #include "wimlib/wim.h" #include "wimlib/win32.h" /* for realpath() equivalent */ #include "wimlib/xml.h" @@ -1525,22 +1525,6 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p) return 0; } -static u32 -get_wildcard_flags(int extract_flags) -{ - u32 wildcard_flags = 0; - - if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB) - wildcard_flags |= WILDCARD_FLAG_ERROR_IF_NO_MATCH; - else - wildcard_flags |= WILDCARD_FLAG_WARN_IF_NO_MATCH; - - if (default_ignore_case) - wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE; - - return wildcard_flags; -} - struct append_dentry_ctx { struct wim_dentry **dentries; size_t num_dentries; @@ -1569,6 +1553,31 @@ append_dentry_cb(struct wim_dentry *dentry, void *_ctx) return 0; } +/* Append dentries matched by a path which can contain wildcard characters. */ +static int +append_matched_dentries(WIMStruct *wim, const tchar *orig_pattern, + int extract_flags, struct append_dentry_ctx *ctx) +{ + const size_t count_before = ctx->num_dentries; + tchar *pattern; + int ret; + + pattern = canonicalize_wim_path(orig_pattern); + if (!pattern) + return WIMLIB_ERR_NOMEM; + ret = expand_path_pattern(wim_get_current_root_dentry(wim), pattern, + append_dentry_cb, ctx); + FREE(pattern); + if (ret || ctx->num_dentries > count_before) + return ret; + if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB) { + ERROR("No matches for path pattern \"%"TS"\"", orig_pattern); + return WIMLIB_ERR_PATH_DOES_NOT_EXIST; + } + WARNING("No matches for path pattern \"%"TS"\"", orig_pattern); + return 0; +} + static int do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target, const tchar * const *paths, size_t num_paths, @@ -1611,20 +1620,10 @@ do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target, .num_alloc_dentries = 0, }; - u32 wildcard_flags = get_wildcard_flags(extract_flags); - for (size_t i = 0; i < num_paths; i++) { - tchar *path = canonicalize_wim_path(paths[i]); - if (path == NULL) { - ret = WIMLIB_ERR_NOMEM; - trees = append_dentry_ctx.dentries; - goto out_free_trees; - } - ret = expand_wildcard(wim, path, - append_dentry_cb, - &append_dentry_ctx, - wildcard_flags); - FREE(path); + ret = append_matched_dentries(wim, paths[i], + extract_flags, + &append_dentry_ctx); if (ret) { trees = append_dentry_ctx.dentries; goto out_free_trees; diff --git a/src/ntfs-3g_capture.c b/src/ntfs-3g_capture.c index 0180a488..066d3848 100644 --- a/src/ntfs-3g_capture.c +++ b/src/ntfs-3g_capture.c @@ -675,10 +675,10 @@ ntfs_3g_build_dentry_tree_recursive(struct wim_dentry **root_ret, struct wim_inode *inode = NULL; ntfs_inode *ni = NULL; - ret = try_exclude(path, path_len, params); - if (ret < 0) /* Excluded? */ + ret = try_exclude(path, params); + if (unlikely(ret < 0)) /* Excluded? */ goto out_progress; - if (ret > 0) /* Error? */ + if (unlikely(ret > 0)) /* Error? */ goto out; ni = ntfs_inode_open(volume->vol, mref); diff --git a/src/pattern.c b/src/pattern.c new file mode 100644 index 00000000..b83db42b --- /dev/null +++ b/src/pattern.c @@ -0,0 +1,197 @@ +/* + * pattern.c + * + * Wildcard pattern matching functions. + */ + +/* + * Copyright (C) 2013, 2015 Eric Biggers + * + * This file is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + * + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "wimlib/dentry.h" +#include "wimlib/encoding.h" +#include "wimlib/paths.h" +#include "wimlib/pattern.h" + +static bool +string_matches_pattern(const tchar *string, const tchar * const string_end, + const tchar *pattern, const tchar * const pattern_end) +{ + for (; string != string_end; string++, pattern++) { + if (pattern == pattern_end) + return false; + if (*pattern == T('*')) { + return string_matches_pattern(string, string_end, + pattern + 1, pattern_end) || + string_matches_pattern(string + 1, string_end, + pattern, pattern_end); + } + if (*string != *pattern && *pattern != T('?') && + !(default_ignore_case && + totlower(*string) == totlower(*pattern))) + return false; + } + + while (pattern != pattern_end && *pattern == T('*')) + pattern++; + return pattern == pattern_end; +} + +/* Advance past zero or more path separators. */ +static const tchar * +advance_to_next_component(const tchar *p) +{ + while (*p == WIM_PATH_SEPARATOR) + p++; + return p; +} + +/* Advance past a nonempty path component. */ +static const tchar * +advance_through_component(const tchar *p) +{ + do { + p++; + } while (*p && *p != WIM_PATH_SEPARATOR); + return p; +} + +/* + * Determine whether a path matches a wildcard pattern. + * + * @path + * The null-terminated path string to match. + * @pattern + * The null-terminated wildcard pattern to match. It can contain the + * wildcard characters '*' (which matches zero or more characters) and '?' + * (which matches any single character). If there is no leading path + * separator, then the match is attempted with the filename component of + * @path only; otherwise, the match is attempted with the entire @path. + * @prefix_ok + * If %true, also allow a prefix of @path terminated by a path separator + * (a.k.a. an ancestor directory) to match the pattern. + * + * @path and @pattern can both contain path separators (character + * WIM_PATH_SEPARATOR). Leading and trailing path separators are not + * significant, except when determining whether to match only the filename + * component as noted above. The lengths of interior path separator sequences + * are not significant. The '*' and '?' characters act within a single path + * component only (they do not match path separators). + * + * Matching is done with the default case sensitivity behavior. + * + * Returns %true iff the path matched the pattern. + */ +bool +match_path(const tchar *path, const tchar *pattern, bool prefix_ok) +{ + /* Filename only? */ + if (*pattern != WIM_PATH_SEPARATOR) + path = path_basename(path); + + for (;;) { + const tchar *path_component_end; + const tchar *pattern_component_end; + + path = advance_to_next_component(path); + pattern = advance_to_next_component(pattern); + + /* Is the pattern exhausted? */ + if (!*pattern) + return !*path || prefix_ok; + + /* Is the path exhausted (but not the pattern)? */ + if (!*path) + return false; + + path_component_end = advance_through_component(path); + pattern_component_end = advance_through_component(pattern); + + /* Do the components match? */ + if (!string_matches_pattern(path, path_component_end, + pattern, pattern_component_end)) + return false; + + path = path_component_end; + pattern = pattern_component_end; + } +} + +/* + * Expand a path pattern in an in-memory tree of dentries. + * + * @root + * The root of the directory tree in which to expand the pattern. + * @pattern + * The path pattern to expand, which may contain the '*' and '?' wildcard + * characters. Path separators must be WIM_PATH_SEPARATOR. Leading and + * trailing path separators are ignored. The default case sensitivity + * behavior is used. + * @consume_dentry + * A callback function which will receive each matched directory entry. + * @ctx + * Opaque context argument for @consume_dentry. + * + * @return 0 on success; a positive error code on failure; or the first nonzero + * value returned by @consume_dentry. + */ +int +expand_path_pattern(struct wim_dentry *root, const tchar *pattern, + int (*consume_dentry)(struct wim_dentry *, void *), + void *ctx) +{ + const tchar *pattern_component_end; + struct wim_dentry *child; + + if (!root) + return 0; + + pattern = advance_to_next_component(pattern); + + /* If there are no more components, then 'root' is matched. */ + if (!*pattern) + return (*consume_dentry)(root, ctx); + + pattern_component_end = advance_through_component(pattern); + + /* For each child dentry that matches the current pattern component, + * recurse with the remainder of the pattern. */ + for_dentry_child(child, root) { + const tchar *name; + size_t name_nbytes; + int ret; + + ret = utf16le_get_tstr(child->d_name, child->d_name_nbytes, + &name, &name_nbytes); + if (ret) + return ret; + + if (string_matches_pattern(name, &name[name_nbytes / sizeof(tchar)], + pattern, pattern_component_end)) + ret = expand_path_pattern(child, pattern_component_end, + consume_dentry, ctx); + utf16le_put_tstr(name); + if (ret) + return ret; + } + return 0; +} diff --git a/src/unix_capture.c b/src/unix_capture.c index 6c57a720..f7dd5074 100644 --- a/src/unix_capture.c +++ b/src/unix_capture.c @@ -348,10 +348,10 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret, struct stat stbuf; int stat_flags; - ret = try_exclude(full_path, full_path_len, params); - if (ret < 0) /* Excluded? */ + ret = try_exclude(full_path, params); + if (unlikely(ret < 0)) /* Excluded? */ goto out_progress; - if (ret > 0) /* Error? */ + if (unlikely(ret > 0)) /* Error? */ goto out; if (params->add_flags & (WIMLIB_ADD_FLAG_DEREFERENCE | diff --git a/src/wildcard.c b/src/wildcard.c deleted file mode 100644 index 2bc9c6b8..00000000 --- a/src/wildcard.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * wildcard.c - * - * Wildcard matching functions. - */ - -/* - * Copyright (C) 2013 Eric Biggers - * - * This file is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This file is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this file; if not, see http://www.gnu.org/licenses/. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "wimlib/dentry.h" -#include "wimlib/encoding.h" -#include "wimlib/error.h" -#include "wimlib/metadata.h" -#include "wimlib/paths.h" -#include "wimlib/wildcard.h" - -struct match_dentry_ctx { - int (*consume_dentry)(struct wim_dentry *, void *); - void *consume_dentry_ctx; - size_t consume_dentry_count; - tchar *wildcard_path; - size_t cur_component_offset; - size_t cur_component_len; - bool case_insensitive; -}; - -static bool -do_match_wildcard(const tchar *string, size_t string_len, - const tchar *wildcard, size_t wildcard_len, - bool ignore_case) -{ - for (;;) { - if (string_len == 0) { - while (wildcard_len != 0 && *wildcard == T('*')) { - wildcard++; - wildcard_len--; - } - return (wildcard_len == 0); - } else if (wildcard_len == 0) { - return false; - } else if (*string == *wildcard || *wildcard == T('?') || - (ignore_case && totlower(*string) == totlower(*wildcard))) - { - string++; - string_len--; - wildcard_len--; - wildcard++; - continue; - } else if (*wildcard == T('*')) { - return do_match_wildcard(string, string_len, - wildcard + 1, wildcard_len - 1, - ignore_case) || - do_match_wildcard(string + 1, string_len - 1, - wildcard, wildcard_len, - ignore_case); - } else { - return false; - } - } -} - -static bool -match_wildcard(const tchar *string, const tchar *wildcard, - size_t wildcard_len, bool ignore_case) -{ - return do_match_wildcard(string, tstrlen(string), - wildcard, wildcard_len, ignore_case); -} - -/* - * Determines whether a path matches a wildcard pattern. - * - * @path - * The path to match. Assumptions: All path separators must be @path_sep, - * there cannot be consecutive path separators, there cannot be a trailing - * path separator, and there must be exactly one leading path separator. - * - * @path_nchars - * Number of characters in @path. - * - * @wildcard - * The wildcard pattern to match. It can contain the wildcard characters - * '*' and '?'. The former matches zero or more characters except - * @path_sep, and the latter matches any character except @path_sep. All - * path separators in the pattern must be @path_sep, and there cannot be - * consecutive path separators, and there cannot be a trailing path - * separator. If there is a leading path separator, the match is attempted - * with the filename only; otherwise, the match is attempted with the whole - * path. - * - * @path_sep - * Path separator character used in @path and @wildcard. - * - * @prefix_ok - * If %true, allow a prefix of @path, terminated by a path separator, to - * match the pattern, in addition to @path itself. In other words, return - * %true if the pattern actually matches one of the ancestor directories of - * @path. - * - * Returns %true if there was a match; %false if there was not. - */ -bool -match_path(const tchar *path, size_t path_nchars, - const tchar *wildcard, tchar path_sep, bool prefix_ok) -{ - if (*wildcard != path_sep) { - /* Pattern doesn't begin with path separator. Try to match the - * file name only. */ - return match_wildcard(path_basename_with_len(path, path_nchars), - wildcard, tstrlen(wildcard), - default_ignore_case); - } else { - /* Pattern begins with path separator. Try to match the whole - * path. */ - do { - if (!*wildcard) { - /* Path has more components than pattern */ - return prefix_ok; - } - - size_t path_component_len = 0; - size_t wildcard_component_len = 0; - - do { - path_component_len++; - } while (path[path_component_len] != path_sep && - path[path_component_len] != T('\0')); - do { - wildcard_component_len++; - } while (wildcard[wildcard_component_len] != path_sep && - wildcard[wildcard_component_len] != T('\0')); - if (!do_match_wildcard(path, path_component_len, - wildcard, wildcard_component_len, - default_ignore_case)) - return false; - path += path_component_len; - wildcard += wildcard_component_len; - } while (*path); - - return (*wildcard == '\0'); - } -} - -static int -expand_wildcard_recursive(struct wim_dentry *cur_dentry, - struct match_dentry_ctx *ctx); - -enum { - WILDCARD_STATUS_DONE_FULLY, - WILDCARD_STATUS_DONE_TRAILING_SLASHES, - WILDCARD_STATUS_NOT_DONE, -}; - -static int -wildcard_status(const tchar *wildcard) -{ - if (*wildcard == T('\0')) - return WILDCARD_STATUS_DONE_FULLY; - while (*wildcard == WIM_PATH_SEPARATOR) - wildcard++; - if (*wildcard == T('\0')) - return WILDCARD_STATUS_DONE_TRAILING_SLASHES; - - return WILDCARD_STATUS_NOT_DONE; -} - -static int -match_dentry(struct wim_dentry *cur_dentry, struct match_dentry_ctx *ctx) -{ - const tchar *name; - size_t name_nchars; - int ret; - - if (cur_dentry->d_name_nbytes == 0) - return 0; - - ret = utf16le_get_tstr(cur_dentry->d_name, - cur_dentry->d_name_nbytes, - &name, &name_nchars); - if (ret) - return ret; - name_nchars /= sizeof(tchar); - - if (do_match_wildcard(name, - name_nchars, - &ctx->wildcard_path[ctx->cur_component_offset], - ctx->cur_component_len, - ctx->case_insensitive)) - { - switch (wildcard_status(&ctx->wildcard_path[ - ctx->cur_component_offset + - ctx->cur_component_len])) - { - case WILDCARD_STATUS_DONE_TRAILING_SLASHES: - if (!dentry_is_directory(cur_dentry)) { - ret = 0; - break; - } - /* Fall through */ - case WILDCARD_STATUS_DONE_FULLY: - ret = (*ctx->consume_dentry)(cur_dentry, - ctx->consume_dentry_ctx); - ctx->consume_dentry_count++; - break; - case WILDCARD_STATUS_NOT_DONE: - ret = expand_wildcard_recursive(cur_dentry, ctx); - break; - } - } else { - ret = 0; - } - - utf16le_put_tstr(name); - - return ret; -} - -static int -expand_wildcard_recursive(struct wim_dentry *cur_dentry, - struct match_dentry_ctx *ctx) -{ - tchar *w; - size_t begin; - size_t end; - size_t len; - size_t offset_save; - size_t len_save; - int ret; - struct wim_dentry *child; - - w = ctx->wildcard_path; - - begin = ctx->cur_component_offset + ctx->cur_component_len; - while (w[begin] == WIM_PATH_SEPARATOR) - begin++; - - end = begin; - - while (w[end] != T('\0') && w[end] != WIM_PATH_SEPARATOR) - end++; - - len = end - begin; - - if (len == 0) - return 0; - - offset_save = ctx->cur_component_offset; - len_save = ctx->cur_component_len; - - ctx->cur_component_offset = begin; - ctx->cur_component_len = len; - - ret = 0; - for_dentry_child(child, cur_dentry) { - ret = match_dentry(child, ctx); - if (ret) - break; - } - - ctx->cur_component_len = len_save; - ctx->cur_component_offset = offset_save; - - return ret; -} - -/* Expand a wildcard relative to the current WIM image. - * - * @wim - * WIMStruct whose currently selected image is searched to expand the - * wildcard. - * @wildcard_path - * Wildcard path to expand, which may contain the '?' and '*' characters. - * Path separators must be WIM_PATH_SEPARATOR. Leading path separators are - * ignored, whereas one or more trailing path separators indicate that the - * wildcard path can only match directories (and not reparse points). - * @consume_dentry - * Callback function which will receive each directory entry matched by the - * wildcard. - * @consume_dentry_ctx - * Argument to pass to @consume_dentry. - * @flags - * Zero or more of the following flags: - * - * WILDCARD_FLAG_WARN_IF_NO_MATCH: - * Issue a warning if the wildcard does not match any dentries. - * - * WILDCARD_FLAG_ERROR_IF_NO_MATCH: - * Issue an error and return WIMLIB_ERR_PATH_DOES_NOT_EXIST if the - * wildcard does not match any dentries. - * - * WILDCARD_FLAG_CASE_INSENSITIVE: - * Perform the matching case insensitively. Note that this may - * cause @wildcard to match multiple dentries, even if it does not - * contain wildcard characters. - * - * @return 0 on success; a positive error code on error; or the first nonzero - * value returned by @consume_dentry. - */ -int -expand_wildcard(WIMStruct *wim, - const tchar *wildcard_path, - int (*consume_dentry)(struct wim_dentry *, void *), - void *consume_dentry_ctx, - u32 flags) -{ - struct wim_dentry *root; - int ret; - - root = wim_get_current_root_dentry(wim); - if (root == NULL) - goto no_match; - - struct match_dentry_ctx ctx = { - .consume_dentry = consume_dentry, - .consume_dentry_ctx = consume_dentry_ctx, - .consume_dentry_count = 0, - .wildcard_path = TSTRDUP(wildcard_path), - .cur_component_offset = 0, - .cur_component_len = 0, - .case_insensitive = ((flags & WILDCARD_FLAG_CASE_INSENSITIVE) != 0), - }; - - if (ctx.wildcard_path == NULL) - return WIMLIB_ERR_NOMEM; - - ret = expand_wildcard_recursive(root, &ctx); - FREE(ctx.wildcard_path); - if (ret == 0 && ctx.consume_dentry_count == 0) - goto no_match; - return ret; - -no_match: - ret = 0; - if (flags & WILDCARD_FLAG_WARN_IF_NO_MATCH) - WARNING("No matches for wildcard path \"%"TS"\"", wildcard_path); - - if (flags & WILDCARD_FLAG_ERROR_IF_NO_MATCH) { - ERROR("No matches for wildcard path \"%"TS"\"", wildcard_path); - ret = WIMLIB_ERR_PATH_DOES_NOT_EXIST; - } - return ret; -} diff --git a/src/win32_apply.c b/src/win32_apply.c index 1155b2a5..289db30b 100644 --- a/src/win32_apply.c +++ b/src/win32_apply.c @@ -36,10 +36,10 @@ #include "wimlib/error.h" #include "wimlib/metadata.h" #include "wimlib/paths.h" +#include "wimlib/pattern.h" #include "wimlib/reparse.h" #include "wimlib/textfile.h" #include "wimlib/xml.h" -#include "wimlib/wildcard.h" #include "wimlib/wimboot.h" struct win32_apply_ctx { @@ -341,28 +341,15 @@ load_prepopulate_pats(struct win32_apply_ctx *ctx) return 0; } -/* Returns %true if the specified absolute path to a file in the WIM image - * matches a pattern in [PrepopulateList] of WimBootCompress.ini. Otherwise - * returns %false. */ -static bool -in_prepopulate_list(const wchar_t *path, size_t path_nchars, - const struct win32_apply_ctx *ctx) -{ - const struct string_set *pats = ctx->wimboot.prepopulate_pats; - - if (!pats || !pats->num_strings) - return false; - - return match_pattern_list(path, path_nchars, pats); -} - /* Returns %true if the specified absolute path to a file in the WIM image can * be subject to external backing when extracted. Otherwise returns %false. */ static bool -can_externally_back_path(const wchar_t *path, size_t path_nchars, - const struct win32_apply_ctx *ctx) +can_externally_back_path(const wchar_t *path, const struct win32_apply_ctx *ctx) { - if (in_prepopulate_list(path, path_nchars, ctx)) + /* Does the path match a pattern given in the [PrepopulateList] section + * of WimBootCompress.ini? */ + if (ctx->wimboot.prepopulate_pats && + match_pattern_list(path, ctx->wimboot.prepopulate_pats)) return false; /* Since we attempt to modify the SYSTEM registry after it's extracted @@ -374,8 +361,7 @@ can_externally_back_path(const wchar_t *path, size_t path_nchars, * However, a WIM that wasn't specifically captured in "WIMBoot mode" * may contain SYSTEM.* files. So to make things "just work", hard-code * the pattern. */ - if (match_path(path, path_nchars, L"\\Windows\\System32\\config\\SYSTEM*", - OS_PREFERRED_PATH_SEPARATOR, false)) + if (match_path(path, L"\\Windows\\System32\\config\\SYSTEM*", false)) return false; return true; @@ -492,9 +478,7 @@ will_externally_back_inode(struct wim_inode *inode, struct win32_apply_ctx *ctx, if (ret) return ret; - if (!can_externally_back_path(dentry->d_full_path, - wcslen(dentry->d_full_path), ctx)) - { + if (!can_externally_back_path(dentry->d_full_path, ctx)) { if (excluded_dentry_ret) *excluded_dentry_ret = dentry; return WIM_BACKING_EXCLUDED; diff --git a/src/win32_capture.c b/src/win32_capture.c index 95d87700..96b37360 100644 --- a/src/win32_capture.c +++ b/src/win32_capture.c @@ -1208,10 +1208,10 @@ winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret, ACCESS_MASK requestedPerms; u64 sort_key; - ret = try_exclude(full_path, full_path_nchars, params); - if (ret < 0) /* Excluded? */ + ret = try_exclude(full_path, params); + if (unlikely(ret < 0)) /* Excluded? */ goto out_progress; - if (ret > 0) /* Error? */ + if (unlikely(ret > 0)) /* Error? */ goto out; /* Open the file. */