Simplify wildcard pattern expansion
authorEric Biggers <ebiggers3@gmail.com>
Sun, 31 May 2015 22:28:04 +0000 (17:28 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 5 Jun 2015 03:45:35 +0000 (22:45 -0500)
12 files changed:
Makefile.am
include/wimlib/capture.h
include/wimlib/pattern.h [new file with mode: 0644]
include/wimlib/wildcard.h [deleted file]
src/capture_common.c
src/extract.c
src/ntfs-3g_capture.c
src/pattern.c [new file with mode: 0644]
src/unix_capture.c
src/wildcard.c [deleted file]
src/win32_apply.c
src/win32_capture.c

index 206a0c2..647521e 100644 (file)
@@ -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            \
index 9ab48f7..7372c05 100644 (file)
@@ -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 (file)
index 0000000..67c2073
--- /dev/null
@@ -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 (file)
index 4cf21ee..0000000
+++ /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  */
index e544b7c..e088afc 100644 (file)
@@ -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, &params->config->exclusion_pats) &&
+                   !match_pattern_list(path, &params->config->exclusion_exception_pats))
+                       return -1;
+       }
 
        if (unlikely(params->add_flags & WIMLIB_ADD_FLAG_TEST_FILE_EXCLUSION)) {
                union wimlib_progress_info info;
index 625224b..b200e18 100644 (file)
 #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;
index 0180a48..066d384 100644 (file)
@@ -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 (file)
index 0000000..b83db42
--- /dev/null
@@ -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 <ctype.h>
+
+#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;
+}
index 6c57a72..f7dd507 100644 (file)
@@ -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 (file)
index 2bc9c6b..0000000
+++ /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 <ctype.h>
-
-#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;
-}
index 1155b2a..289db30 100644 (file)
 #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;
index 95d8770..96b3736 100644 (file)
@@ -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.  */