A couple cleanups from last commits
[wimlib] / src / wildcard.c
index 90efbd33207296046928b5c5f87c845fdc9dc751..2619f47b59fe445f84d2e31012d2e6f90828464e 100644 (file)
@@ -32,6 +32,7 @@
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"
 #include "wimlib/metadata.h"
+#include "wimlib/paths.h"
 #include "wimlib/wildcard.h"
 
 struct match_dentry_ctx {
@@ -44,16 +45,6 @@ struct match_dentry_ctx {
        bool case_insensitive;
 };
 
-#define PLATFORM_SUPPORTS_FNMATCH
-
-#ifdef __WIN32__
-/* PathMatchSpec() could provide a fnmatch() alternative, but it isn't
- * documented properly, nor does it work properly.  For example, it returns that
- * any name matches *.* even if that name doesn't actually contain a period.  */
-#  undef PLATFORM_SUPPORTS_FNMATCH
-#endif
-
-#ifndef PLATFORM_SUPPORTS_FNMATCH
 static bool
 do_match_wildcard(const tchar *string, size_t string_len,
                  const tchar *wildcard, size_t wildcard_len,
@@ -88,30 +79,87 @@ do_match_wildcard(const tchar *string, size_t string_len,
                }
        }
 }
-#endif /* ! PLATFORM_SUPPORTS_FNMATCH  */
 
 static bool
-match_wildcard(const tchar *string, tchar *wildcard,
+match_wildcard(const tchar *string, const tchar *wildcard,
               size_t wildcard_len, bool ignore_case)
 {
-#ifdef PLATFORM_SUPPORTS_FNMATCH
-       char orig;
-       int ret;
-       int flags = FNM_NOESCAPE;
-       if (ignore_case)
-               flags |= FNM_CASEFOLD;
-
-       orig = wildcard[wildcard_len];
-       wildcard[wildcard_len] = T('\0');
-
-       ret = fnmatch(wildcard, string, flags);
-
-       wildcard[wildcard_len] = orig;
-       return (ret == 0);
-#else
        return do_match_wildcard(string, tstrlen(string),
                                 wildcard, wildcard_len, ignore_case);
-#endif
+}
+
+/*
+ * 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
@@ -138,9 +186,8 @@ wildcard_status(const tchar *wildcard)
 }
 
 static int
-match_dentry(struct wim_dentry *cur_dentry, void *_ctx)
+match_dentry(struct wim_dentry *cur_dentry, struct match_dentry_ctx *ctx)
 {
-       struct match_dentry_ctx *ctx = _ctx;
        tchar *name;
        size_t name_len;
        int ret;
@@ -205,6 +252,7 @@ expand_wildcard_recursive(struct wim_dentry *cur_dentry,
        size_t offset_save;
        size_t len_save;
        int ret;
+       struct wim_dentry *child;
 
        w = ctx->wildcard_path;
 
@@ -228,7 +276,12 @@ expand_wildcard_recursive(struct wim_dentry *cur_dentry,
        ctx->cur_component_offset = begin;
        ctx->cur_component_len = len;
 
-       ret = for_dentry_child(cur_dentry, match_dentry, ctx);
+       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;
@@ -268,9 +321,6 @@ expand_wildcard_recursive(struct wim_dentry *cur_dentry,
  *
  * @return 0 on success; a positive error code on error; or the first nonzero
  * value returned by @consume_dentry.
- *
- * Note: this function uses the @tmp_list field of dentries it attempts to
- * match.
  */
 int
 expand_wildcard(WIMStruct *wim,