]> wimlib.net Git - wimlib/blobdiff - src/capture_common.c
A couple cleanups from last commits
[wimlib] / src / capture_common.c
index c45ae152345e7ecba77c983ded9d3d2a81ea5b39..7db7c5cfed2c616104f25c2da452f5b941f64270 100644 (file)
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/paths.h"
+#include "wimlib/textfile.h"
+#include "wimlib/wildcard.h"
 
-#ifdef __WIN32__
-#  include "wimlib/win32.h" /* for fnmatch() equivalent */
-#else
-#  include <fnmatch.h>
-#endif
 #include <string.h>
 
-
-static int
-canonicalize_pattern(const tchar *pat, tchar **canonical_pat_ret)
+void
+do_capture_progress(struct add_image_params *params, int status,
+                   const struct wim_inode *inode)
 {
-       tchar *canonical_pat;
+       switch (status) {
+       case WIMLIB_SCAN_DENTRY_OK:
+               if (!(params->add_flags & WIMLIB_ADD_FLAG_VERBOSE))
+                       return;
+       case WIMLIB_SCAN_DENTRY_UNSUPPORTED:
+       case WIMLIB_SCAN_DENTRY_EXCLUDED:
+       case WIMLIB_SCAN_DENTRY_EXCLUDED_SYMLINK:
+               if (!(params->add_flags & WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE))
+                       return;
+       }
+       params->progress.scan.status = status;
+       if (status == WIMLIB_SCAN_DENTRY_OK && inode->i_nlink == 1) {
+               const struct wim_lookup_table_entry *lte;
+               for (unsigned i = 0; i <= inode->i_num_ads; i++) {
+                       lte = inode_stream_lte_resolved(inode, i);
+                       if (lte != NULL)
+                               params->progress.scan.num_bytes_scanned += lte->size;
+               }
+               if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+                       params->progress.scan.num_dirs_scanned++;
+               else
+                       params->progress.scan.num_nondirs_scanned++;
+       }
+       if (params->progress_func) {
+               params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY,
+                                     &params->progress);
+       }
+}
 
+int
+mangle_pat(tchar *pat, const tchar *path, unsigned long line_no)
+{
        if (!is_any_path_separator(pat[0]) &&
            pat[0] != T('\0') && pat[1] == T(':'))
        {
@@ -54,193 +81,128 @@ canonicalize_pattern(const tchar *pat, tchar **canonical_pat_ret)
                         * relative to the current working directory on the c:
                         * drive.  We require paths with drive letters to be
                         * absolute. */
-                       ERROR("Invalid path \"%"TS"\"; paths including drive letters "
-                             "must be absolute!", pat);
-                       ERROR("Maybe try \"%"TC":\\%"TS"\"?",
-                             pat[0], pat + 2);
+                       ERROR("%"TS":%lu: Invalid pattern \"%"TS"\":\n"
+                             "        Patterns including drive letters must be absolute!\n"
+                             "        Maybe try \"%"TC":%"TC"%"TS"\"?\n",
+                             path, line_no, pat,
+                             pat[0], OS_PREFERRED_PATH_SEPARATOR, &pat[2]);
                        return WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
                }
 
-               WARNING("Pattern \"%"TS"\" starts with a drive letter, which is "
-                       "being removed.", pat);
-               /* Strip the drive letter */
-               pat += 2;
+               WARNING("%"TS":%lu: Pattern \"%"TS"\" starts with a drive "
+                       "letter, which is being removed.",
+                       path, line_no, pat);
+
+               /* Strip the drive letter.  */
+               tmemmove(pat, pat + 2, tstrlen(pat + 2) + 1);
        }
-       canonical_pat = canonicalize_fs_path(pat);
-       if (!canonical_pat)
-               return WIMLIB_ERR_NOMEM;
-
-       /* Translate all possible path separators into the operating system's
-        * preferred path separator. */
-       for (tchar *p = canonical_pat; *p; p++)
-               if (is_any_path_separator(*p))
-                       *p = OS_PREFERRED_PATH_SEPARATOR;
-       *canonical_pat_ret = canonical_pat;
-       return 0;
-}
 
-static int
-copy_and_canonicalize_pattern_list(const struct wimlib_pattern_list *list,
-                                  struct wimlib_pattern_list *copy)
-{
-       int ret = 0;
-
-       copy->pats = CALLOC(list->num_pats, sizeof(list->pats[0]));
-       if (!copy->pats)
-               return WIMLIB_ERR_NOMEM;
-       copy->num_pats = list->num_pats;
-       for (size_t i = 0; i < list->num_pats; i++) {
-               ret = canonicalize_pattern(list->pats[i], &copy->pats[i]);
-               if (ret)
-                       break;
+       /* Collapse and translate path separators.
+        *
+        * Note: we require that this works for filesystem paths and WIM paths,
+        * so the desired path separators must be the same.  */
+       BUILD_BUG_ON(OS_PREFERRED_PATH_SEPARATOR != WIM_PATH_SEPARATOR);
+       do_canonicalize_path(pat, pat);
+
+       /* Relative patterns can only match file names.  */
+       if (pat[0] != OS_PREFERRED_PATH_SEPARATOR &&
+           tstrchr(pat, OS_PREFERRED_PATH_SEPARATOR))
+       {
+               ERROR("%"TS":%lu: Invalid path \"%"TS"\":\n"
+                     "        Relative patterns can only include one path component!\n"
+                     "        Maybe try \"%"TC"%"TS"\"?",
+                     path, line_no, pat, OS_PREFERRED_PATH_SEPARATOR, pat);
+               return WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
        }
-       return ret;
+
+       return 0;
 }
 
 int
-copy_and_canonicalize_capture_config(const struct wimlib_capture_config *config,
-                                    struct wimlib_capture_config **config_copy_ret)
+do_read_capture_config_file(const tchar *config_file, const void *buf,
+                           size_t bufsize, struct capture_config *config)
 {
-       struct wimlib_capture_config *config_copy;
        int ret;
 
-       config_copy = CALLOC(1, sizeof(struct wimlib_capture_config));
-       if (!config_copy) {
-               ret = WIMLIB_ERR_NOMEM;
-               goto out_free_capture_config;
-       }
-       ret = copy_and_canonicalize_pattern_list(&config->exclusion_pats,
-                                                &config_copy->exclusion_pats);
-       if (ret)
-               goto out_free_capture_config;
-       ret = copy_and_canonicalize_pattern_list(&config->exclusion_exception_pats,
-                                                &config_copy->exclusion_exception_pats);
+       /* [PrepopulateList] is used for apply, not capture.  But since we do
+        * understand it, recognize it (avoiding unrecognized section warning)
+        * and discard the strings.  */
+       STRING_SET(prepopulate_pats);
+
+       struct text_file_section sections[] = {
+               {T("ExclusionList"),
+                       &config->exclusion_pats},
+               {T("ExclusionException"),
+                       &config->exclusion_exception_pats},
+               {T("PrepopulateList"),
+                       &prepopulate_pats},
+       };
+       void *mem;
+
+       ret = do_load_text_file(config_file, buf, bufsize, &mem,
+                               sections, ARRAY_LEN(sections),
+                               LOAD_TEXT_FILE_REMOVE_QUOTES, mangle_pat);
        if (ret)
-               goto out_free_capture_config;
-       *config_copy_ret = config_copy;
-       goto out;
-out_free_capture_config:
-       free_capture_config(config_copy);
-out:
-       return ret;
-}
+               return ret;
 
-static void
-destroy_pattern_list(struct wimlib_pattern_list *list)
-{
-       for (size_t i = 0; i < list->num_pats; i++)
-               FREE(list->pats[i]);
-       FREE(list->pats);
+       FREE(prepopulate_pats.strings);
+
+       config->buf = mem;
+       return 0;
 }
 
 void
-free_capture_config(struct wimlib_capture_config *config)
+destroy_capture_config(struct capture_config *config)
 {
-       if (config) {
-               destroy_pattern_list(&config->exclusion_pats);
-               destroy_pattern_list(&config->exclusion_exception_pats);
-               FREE(config);
-       }
+       FREE(config->exclusion_pats.strings);
+       FREE(config->exclusion_exception_pats.strings);
+       FREE(config->buf);
 }
 
-static bool
-match_pattern(const tchar *path,
-             const tchar *path_basename,
-             const struct wimlib_pattern_list *list)
+bool
+match_pattern_list(const tchar *path, size_t path_len,
+                  const struct string_set *list)
 {
-       for (size_t i = 0; i < list->num_pats; i++) {
-
-               const tchar *pat = list->pats[i];
-               const tchar *string;
-
-               if (*pat == OS_PREFERRED_PATH_SEPARATOR) {
-                       /* Absolute path from root of capture */
-                       string = path;
-               } else {
-                       if (tstrchr(pat, OS_PREFERRED_PATH_SEPARATOR))
-                               /* Relative path from root of capture */
-                               string = path + 1;
-                       else
-                               /* A file name pattern */
-                               string = path_basename;
-               }
-
-               /* Warning: on Windows native builds, fnmatch() calls the
-                * replacement function in win32.c. */
-               if (fnmatch(pat, string, FNM_PATHNAME | FNM_NOESCAPE
-                               #ifdef FNM_CASEFOLD
-                                       | FNM_CASEFOLD
-                               #endif
-                           ) == 0)
-               {
-                       DEBUG("\"%"TS"\" matches the pattern \"%"TS"\"",
-                             string, pat);
+       for (size_t i = 0; i < list->num_strings; i++)
+               if (match_path(path, path_len, list->strings[i],
+                              OS_PREFERRED_PATH_SEPARATOR, true))
                        return true;
-               } else {
-                       DEBUG2("\"%"TS"\" does not match the pattern \"%"TS"\"",
-                              string, pat);
-               }
-       }
        return false;
 }
 
-void
-do_capture_progress(struct add_image_params *params, int status,
-                   const struct wim_inode *inode)
-{
-       switch (status) {
-       case WIMLIB_SCAN_DENTRY_OK:
-               if (!(params->add_flags & WIMLIB_ADD_FLAG_VERBOSE))
-                       return;
-       case WIMLIB_SCAN_DENTRY_UNSUPPORTED:
-       case WIMLIB_SCAN_DENTRY_EXCLUDED:
-               if (!(params->add_flags & WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE))
-                       return;
-       }
-       params->progress.scan.status = status;
-       if (status == WIMLIB_SCAN_DENTRY_OK && inode->i_nlink == 1) {
-               const struct wim_lookup_table_entry *lte;
-               for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-                       lte = inode_stream_lte_resolved(inode, i);
-                       if (lte != NULL)
-                               params->progress.scan.num_bytes_scanned += lte->size;
-               }
-               if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
-                       params->progress.scan.num_dirs_scanned++;
-               else
-                       params->progress.scan.num_nondirs_scanned++;
-       }
-       if (params->progress_func) {
-               params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY,
-                                     &params->progress);
-       }
-}
-
-/* Return true if the image capture configuration file indicates we should
+/*
+ * Return true if the image capture configuration file indicates we should
  * exclude the filename @path from capture.
  *
- * If @exclude_prefix is %true, the part of the path up and including the name
- * of the directory being captured is not included in the path for matching
- * purposes.  This allows, for example, a pattern like /hiberfil.sys to match a
- * file /mnt/windows7/hiberfil.sys if we are capturing the /mnt/windows7
- * directory.
+ * The passed in @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, and
+ * there cannot be trailing slashes.
+ *
+ * As a special case, the empty string will be interpreted as a single path
+ * separator.
  */
 bool
-exclude_path(const tchar *path, size_t path_len,
-            const struct wimlib_capture_config *config, bool exclude_prefix)
+exclude_path(const tchar *path, size_t path_nchars,
+            const struct capture_config *config)
 {
+       tchar dummy[2];
+
        if (!config)
                return false;
-       const tchar *basename = path_basename_with_len(path, path_len);
-       if (exclude_prefix) {
-               wimlib_assert(path_len >= config->_prefix_num_tchars);
-               if (!tmemcmp(config->_prefix, path, config->_prefix_num_tchars) &&
-                   path[config->_prefix_num_tchars] == OS_PREFERRED_PATH_SEPARATOR)
-               {
-                       path += config->_prefix_num_tchars;
-               }
+
+       if (!*path) {
+               dummy[0] = OS_PREFERRED_PATH_SEPARATOR;
+               dummy[1] = T('\0');
+               path = dummy;
+               path_nchars = 1;
        }
-       return match_pattern(path, basename, &config->exclusion_pats) &&
-               !match_pattern(path, basename, &config->exclusion_exception_pats);
+
+       return match_pattern_list(path, path_nchars, &config->exclusion_pats) &&
+             !match_pattern_list(path, path_nchars, &config->exclusion_exception_pats);
 
 }