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"
34 #include "wimlib/textfile.h"
35 #include "wimlib/wildcard.h"
40 do_capture_progress(struct add_image_params *params, int status,
41 const struct wim_inode *inode)
44 case WIMLIB_SCAN_DENTRY_OK:
45 if (!(params->add_flags & WIMLIB_ADD_FLAG_VERBOSE))
47 case WIMLIB_SCAN_DENTRY_UNSUPPORTED:
48 case WIMLIB_SCAN_DENTRY_EXCLUDED:
49 case WIMLIB_SCAN_DENTRY_EXCLUDED_SYMLINK:
50 if (!(params->add_flags & WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE))
53 params->progress.scan.status = status;
54 if (status == WIMLIB_SCAN_DENTRY_OK && inode->i_nlink == 1) {
55 const struct wim_lookup_table_entry *lte;
56 for (unsigned i = 0; i <= inode->i_num_ads; i++) {
57 lte = inode_stream_lte_resolved(inode, i);
59 params->progress.scan.num_bytes_scanned += lte->size;
61 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
62 params->progress.scan.num_dirs_scanned++;
64 params->progress.scan.num_nondirs_scanned++;
66 if (params->progress_func) {
67 params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY,
73 mangle_pat(tchar *pat, const tchar *path, unsigned long line_no)
76 if (pat[0] == T('"') || pat[0] == T('\'')) {
78 tchar *last = pat + tstrlen(pat) - 1;
79 if (last > pat && *last == quote) {
80 tmemmove(pat, pat + 1, last - (pat + 1));
81 *(last - 1) = T('\0');
85 if (!is_any_path_separator(pat[0]) &&
86 pat[0] != T('\0') && pat[1] == T(':'))
88 /* Pattern begins with drive letter */
89 if (!is_any_path_separator(pat[2])) {
90 /* Something like c:file, which is actually a path
91 * relative to the current working directory on the c:
92 * drive. We require paths with drive letters to be
94 ERROR("%"TS":%lu: Invalid path \"%"TS"\"; paths including "
95 "drive letters must be absolute!\n"
96 " Maybe try \"%"TC":\\%"TS"\"?",
97 path, line_no, pat, pat[0], &pat[2]);
98 return WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
101 WARNING("%"TS":%lu: Pattern \"%"TS"\" starts with a drive "
102 "letter, which is being removed.",
105 /* Strip the drive letter. */
106 tmemmove(pat, pat + 2, tstrlen(pat + 2) + 1);
109 /* Translate all possible path separators into the operating system's
110 * preferred path separator. */
111 for (tchar *p = pat; *p; p++)
112 if (is_any_path_separator(*p))
113 *p = OS_PREFERRED_PATH_SEPARATOR;
118 do_read_capture_config_file(const tchar *config_file, tchar *buf, size_t buflen,
119 struct capture_config *config)
122 struct text_file_section sections[] = {
124 &config->exclusion_pats},
125 {T("ExclusionException"),
126 &config->exclusion_exception_pats},
129 ret = do_load_text_file(config_file, buf, buflen, &buf,
130 sections, ARRAY_LEN(sections), mangle_pat);
139 destroy_capture_config(struct capture_config *config)
141 FREE(config->exclusion_pats.strings);
142 FREE(config->exclusion_exception_pats.strings);
147 match_pattern(const tchar *path,
148 const tchar *path_basename,
149 const struct string_set *list)
151 for (size_t i = 0; i < list->num_strings; i++) {
153 const tchar *pat = list->strings[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"\"",
184 /* Return true if the image capture configuration file indicates we should
185 * exclude the filename @path from capture.
187 * If @exclude_prefix is %true, the part of the path up and including the name
188 * of the directory being captured is not included in the path for matching
189 * purposes. This allows, for example, a pattern like /hiberfil.sys to match a
190 * file /mnt/windows7/hiberfil.sys if we are capturing the /mnt/windows7
194 exclude_path(const tchar *path, size_t path_len,
195 const struct capture_config *config, bool exclude_prefix)
199 const tchar *basename = path_basename_with_len(path, path_len);
200 if (exclude_prefix) {
201 wimlib_assert(path_len >= config->prefix_num_tchars);
202 if (!tmemcmp(config->prefix, path, config->prefix_num_tchars) &&
203 path[config->prefix_num_tchars] == OS_PREFERRED_PATH_SEPARATOR)
205 path += config->prefix_num_tchars;
208 return match_pattern(path, basename, &config->exclusion_pats) &&
209 !match_pattern(path, basename, &config->exclusion_exception_pats);