2 * capture_common.c - Mostly code to handle excluding paths from capture.
6 * Copyright (C) 2013 Eric Biggers
8 * This file is part of wimlib, a library for working with WIM files.
10 * wimlib is free software; you can redistribute it and/or modify it under the
11 * terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option)
15 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 * A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with wimlib; if not, see http://www.gnu.org/licenses/.
28 #include "wimlib/assert.h"
29 #include "wimlib/capture.h"
30 #include "wimlib/dentry.h"
31 #include "wimlib/error.h"
32 #include "wimlib/lookup_table.h"
33 #include "wimlib/paths.h"
36 # include "wimlib/win32.h" /* for fnmatch() equivalent */
44 canonicalize_pattern(const tchar *pat, tchar **canonical_pat_ret)
48 if (!is_any_path_separator(pat[0]) &&
49 pat[0] != T('\0') && pat[1] == T(':'))
51 /* Pattern begins with drive letter */
52 if (!is_any_path_separator(pat[2])) {
53 /* Something like c:file, which is actually a path
54 * relative to the current working directory on the c:
55 * drive. We require paths with drive letters to be
57 ERROR("Invalid path \"%"TS"\"; paths including drive letters "
58 "must be absolute!", pat);
59 ERROR("Maybe try \"%"TC":\\%"TS"\"?",
61 return WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
64 WARNING("Pattern \"%"TS"\" starts with a drive letter, which is "
65 "being removed.", pat);
66 /* Strip the drive letter */
69 canonical_pat = canonicalize_fs_path(pat);
71 return WIMLIB_ERR_NOMEM;
73 /* Translate all possible path separators into the operating system's
74 * preferred path separator. */
75 for (tchar *p = canonical_pat; *p; p++)
76 if (is_any_path_separator(*p))
77 *p = OS_PREFERRED_PATH_SEPARATOR;
78 *canonical_pat_ret = canonical_pat;
83 copy_and_canonicalize_pattern_list(const struct wimlib_pattern_list *list,
84 struct wimlib_pattern_list *copy)
88 copy->pats = CALLOC(list->num_pats, sizeof(list->pats[0]));
90 return WIMLIB_ERR_NOMEM;
91 copy->num_pats = list->num_pats;
92 for (size_t i = 0; i < list->num_pats; i++) {
93 ret = canonicalize_pattern(list->pats[i], ©->pats[i]);
101 copy_and_canonicalize_capture_config(const struct wimlib_capture_config *config,
102 struct wimlib_capture_config **config_copy_ret)
104 struct wimlib_capture_config *config_copy;
107 config_copy = CALLOC(1, sizeof(struct wimlib_capture_config));
109 ret = WIMLIB_ERR_NOMEM;
110 goto out_free_capture_config;
112 ret = copy_and_canonicalize_pattern_list(&config->exclusion_pats,
113 &config_copy->exclusion_pats);
115 goto out_free_capture_config;
116 ret = copy_and_canonicalize_pattern_list(&config->exclusion_exception_pats,
117 &config_copy->exclusion_exception_pats);
119 goto out_free_capture_config;
120 *config_copy_ret = config_copy;
122 out_free_capture_config:
123 free_capture_config(config_copy);
129 destroy_pattern_list(struct wimlib_pattern_list *list)
131 for (size_t i = 0; i < list->num_pats; i++)
137 free_capture_config(struct wimlib_capture_config *config)
140 destroy_pattern_list(&config->exclusion_pats);
141 destroy_pattern_list(&config->exclusion_exception_pats);
147 match_pattern(const tchar *path,
148 const tchar *path_basename,
149 const struct wimlib_pattern_list *list)
151 for (size_t i = 0; i < list->num_pats; i++) {
153 const tchar *pat = list->pats[i];
156 if (*pat == OS_PREFERRED_PATH_SEPARATOR) {
157 /* Absolute path from root of capture */
160 if (tstrchr(pat, OS_PREFERRED_PATH_SEPARATOR))
161 /* Relative path from root of capture */
164 /* A file name pattern */
165 string = path_basename;
168 /* Warning: on Windows native builds, fnmatch() calls the
169 * replacement function in win32.c. */
170 if (fnmatch(pat, string, FNM_PATHNAME | FNM_NOESCAPE
176 DEBUG("\"%"TS"\" matches the pattern \"%"TS"\"",
180 DEBUG("\"%"TS"\" does not match the pattern \"%"TS"\"",
188 do_capture_progress(struct add_image_params *params, int status,
189 const struct wim_inode *inode)
192 case WIMLIB_SCAN_DENTRY_OK:
193 if (!(params->add_flags & WIMLIB_ADD_FLAG_VERBOSE))
195 case WIMLIB_SCAN_DENTRY_UNSUPPORTED:
196 case WIMLIB_SCAN_DENTRY_EXCLUDED:
197 if (!(params->add_flags & WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE))
200 params->progress.scan.status = status;
201 if (status == WIMLIB_SCAN_DENTRY_OK && inode->i_nlink == 1) {
202 const struct wim_lookup_table_entry *lte;
203 for (unsigned i = 0; i <= inode->i_num_ads; i++) {
204 lte = inode_stream_lte_resolved(inode, i);
206 params->progress.scan.num_bytes_scanned += lte->size;
208 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
209 params->progress.scan.num_dirs_scanned++;
211 params->progress.scan.num_nondirs_scanned++;
213 if (params->progress_func) {
214 params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY,
219 /* Return true if the image capture configuration file indicates we should
220 * exclude the filename @path from capture.
222 * If @exclude_prefix is %true, the part of the path up and including the name
223 * of the directory being captured is not included in the path for matching
224 * purposes. This allows, for example, a pattern like /hiberfil.sys to match a
225 * file /mnt/windows7/hiberfil.sys if we are capturing the /mnt/windows7
229 exclude_path(const tchar *path, size_t path_len,
230 const struct wimlib_capture_config *config, bool exclude_prefix)
234 const tchar *basename = path_basename_with_len(path, path_len);
235 if (exclude_prefix) {
236 wimlib_assert(path_len >= config->_prefix_num_tchars);
237 if (!tmemcmp(config->_prefix, path, config->_prefix_num_tchars) &&
238 path[config->_prefix_num_tchars] == OS_PREFERRED_PATH_SEPARATOR)
240 path += config->_prefix_num_tchars;
243 return match_pattern(path, basename, &config->exclusion_pats) &&
244 !match_pattern(path, basename, &config->exclusion_exception_pats);