From: Eric Biggers Date: Thu, 24 Apr 2014 04:08:50 +0000 (-0500) Subject: Parse capture configuration file in library X-Git-Tag: v1.7.0~281 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=864db0e0929d60b33b8b0df35ccb68d43e7f8684 Parse capture configuration file in library --- diff --git a/Makefile.am b/Makefile.am index 2dc75281..a9206fdf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,7 @@ endif lib_LTLIBRARIES = libwim.la -libwim_la_LDFLAGS = -version-info 14:0:5 $(WINDOWS_LDFLAGS) +libwim_la_LDFLAGS = -version-info 15:0:0 $(WINDOWS_LDFLAGS) libwim_la_SOURCES = \ src/add_image.c \ @@ -65,6 +65,7 @@ libwim_la_SOURCES = \ src/split.c \ src/reparse.c \ src/template.c \ + src/textfile.c \ src/timestamp.c \ src/update_image.c \ src/util.c \ @@ -113,6 +114,7 @@ libwim_la_SOURCES = \ include/wimlib/security.h \ include/wimlib/security_descriptor.h \ include/wimlib/sha1.h \ + include/wimlib/textfile.h \ include/wimlib/timestamp.h \ include/wimlib/types.h \ include/wimlib/unix_data.h \ diff --git a/NEWS b/NEWS index c415e0a2..f48dc54c 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,12 @@ Version 1.6.3-BETA: archive. See the documentation for the new '--wimboot' option to wimcapture and wimapply, respectively, for more information. + The shared library version has been bumped up; however, there are only + small incompatibilities: + + - wimlib_capture_config has been removed. The library now takes + the configuration file directly. + Version 1.6.2: Case-insensitive comparisons of strings (e.g. filenames) containing UTF-16 codepoints above 32767 are now done correctly. diff --git a/include/wimlib.h b/include/wimlib.h index 31fab04d..e880182b 100644 --- a/include/wimlib.h +++ b/include/wimlib.h @@ -959,46 +959,6 @@ struct wimlib_capture_source { long reserved; }; -/** Structure that specifies a list of path patterns. */ -struct wimlib_pattern_list { - /** Array of patterns. The patterns may be modified by library code, - * but the @p pats pointer itself will not. See the man page for - * wimlib-imagex capture for more information about allowed - * patterns. */ - wimlib_tchar **pats; - - /** Number of patterns in the @p pats array. */ - size_t num_pats; - - /** Ignored; may be used by the calling code. */ - size_t num_allocated_pats; -}; - -/** A structure that contains lists of wildcards that match paths to treat - * specially when capturing a WIM image. */ -struct wimlib_capture_config { - /** Paths matching any pattern this list are excluded from being - * captured, except if the same path appears in @p - * exclusion_exception_pats. */ - struct wimlib_pattern_list exclusion_pats; - - /** Paths matching any pattern in this list are never excluded from - * being captured. */ - struct wimlib_pattern_list exclusion_exception_pats; - - /** Reserved for future capture configuration options. */ - struct wimlib_pattern_list reserved1; - - /** Reserved for future capture configuration options. */ - struct wimlib_pattern_list reserved2; - - /** Library internal use only. */ - wimlib_tchar *_prefix; - - /** Library internal use only. */ - size_t _prefix_num_tchars; -}; - /** Set or unset the WIM header flag that marks it read-only * (WIM_HDR_FLAG_READONLY in Microsoft's documentation), based on the * ::wimlib_wim_info.is_marked_readonly member of the @p info parameter. This @@ -1362,19 +1322,13 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour * such a file is encountered. */ #define WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE 0x00000400 -/** Automatically select a capture configuration appropriate for capturing - * filesystems containing Windows operating systems. When this flag is - * specified, the corresponding @p config parameter or member must be @c NULL. - * - * Currently, selecting this capture configuration will cause the following - * files and directories to be excluded from capture: +/** + * Automatically select a capture configuration appropriate for capturing + * filesystems containing Windows operating systems. For example, + * "pagefile.sys" and "System Volume Information" will be excluded. * - * - "\$ntfs.log" - * - "\hiberfil.sys" - * - "\pagefile.sys" - * - "\System Volume Information" - * - "\RECYCLER" - * - "\Windows\CSC" + * When this flag is specified, the corresponding @p config parameter or member + * must be @c NULL. * * Note that the default behavior--- that is, when this flag is not specified * and @p config is @c NULL--- is to use no capture configuration, meaning that @@ -1383,7 +1337,9 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour #define WIMLIB_ADD_FLAG_WINCONFIG 0x00000800 /** - * Capture image as WIMBoot compatible. + * Capture image as WIMBoot compatible. In addition, use the capture + * configuration file $SOURCE/Windows/System32/WimBootCompress.ini if it + * exists, where $SOURCE is the directory being captured. * * Note: this will not by itself change the compression type. Before writing * the WIM file, it's recommended to also do: @@ -1841,11 +1797,9 @@ struct wimlib_add_command { * WIM image. */ wimlib_tchar *wim_target_path; - /** Configuration for excluded files. @c NULL means - * exclude no files (use no configuration), unless - * ::WIMLIB_ADD_FLAG_WINCONFIG is specified in @p - * add_flags. */ - struct wimlib_capture_config *config; + /** Path to capture configuration file to use, or @c NULL for default. + */ + wimlib_tchar *config_file; /** Bitwise OR of WIMLIB_ADD_FLAG_* flags. */ int add_flags; @@ -2072,10 +2026,15 @@ wimlib_add_empty_image(WIMStruct *wim, * Name to give the new image. If @c NULL or empty, the new image is given * no name. If nonempty, it must specify a name that does not already * exist in @p wim. - * @param config - * Capture configuration that specifies files, directories, or path globs - * to exclude from being captured. If @c NULL, a dummy configuration where - * no paths are treated specially is used. + * @param config_file + * Path to capture configuration file, or @c NULL. This file may specify, + * among other things, which files to exclude from capture. See the man + * page for wimlib-imagex capture (--config option) for + * details of the file format. If @c NULL, the default capture + * configuration shall be used. Ordinarily, the default capture + * configuration will result in no files being excluded from capture purely + * based on name; however, the ::WIMLIB_ADD_FLAG_WINCONFIG and + * ::WIMLIB_ADD_FLAG_WIMBOOT flags modify the default. * @param add_flags * Bitwise OR of flags prefixed with WIMLIB_ADD_FLAG. * @param progress_func @@ -2099,7 +2058,7 @@ extern int wimlib_add_image(WIMStruct *wim, const wimlib_tchar *source, const wimlib_tchar *name, - const struct wimlib_capture_config *config, + const wimlib_tchar *config_file, int add_flags, wimlib_progress_func_t progress_func); @@ -2128,7 +2087,7 @@ wimlib_add_image_multisource(WIMStruct *wim, const struct wimlib_capture_source *sources, size_t num_sources, const wimlib_tchar *name, - const struct wimlib_capture_config *config, + const wimlib_tchar *config_file, int add_flags, wimlib_progress_func_t progress_func); diff --git a/include/wimlib/capture.h b/include/wimlib/capture.h index 7ff82db2..995a60f3 100644 --- a/include/wimlib/capture.h +++ b/include/wimlib/capture.h @@ -5,12 +5,21 @@ #include "wimlib/inode_table.h" #include "wimlib/list.h" #include "wimlib/security.h" +#include "wimlib/textfile.h" #include "wimlib/util.h" struct wim_lookup_table; struct wim_dentry; struct wim_inode; +struct capture_config { + struct string_set exclusion_pats; + struct string_set exclusion_exception_pats; + tchar *prefix; + size_t prefix_num_tchars; + tchar *buf; +}; + /* Common parameters to implementations of building an in-memory dentry tree * from an on-disk directory structure. */ struct add_image_params { @@ -28,9 +37,8 @@ struct add_image_params { * image so far. */ struct wim_sd_set sd_set; - /* Pointer to the capture configuration, which indicates whether any - * files should be excluded from capture or not. */ - struct wimlib_capture_config *config; + /* Pointer to the capture configuration. */ + struct capture_config *config; /* Flags that affect the capture operation (WIMLIB_ADD_FLAG_*) */ int add_flags; @@ -56,20 +64,17 @@ extern void do_capture_progress(struct add_image_params *params, int status, const struct wim_inode *inode); -extern bool -exclude_path(const tchar *path, size_t path_len, - const struct wimlib_capture_config *config, - bool exclude_prefix); - -extern struct wimlib_capture_config * -copy_capture_config(const struct wimlib_capture_config *config); - extern 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, tchar *buf, size_t buflen, + struct capture_config *config); extern void -free_capture_config(struct wimlib_capture_config *config); +destroy_capture_config(struct capture_config *config); + +extern bool +exclude_path(const tchar *path, size_t path_len, + const struct capture_config *config, + bool exclude_prefix); #ifdef WITH_NTFS_3G diff --git a/include/wimlib/textfile.h b/include/wimlib/textfile.h new file mode 100644 index 00000000..4c4d1227 --- /dev/null +++ b/include/wimlib/textfile.h @@ -0,0 +1,49 @@ +#ifndef _WIMLIB_TEXTFILE_H_ +#define _WIMLIB_TEXTFILE_H_ + +#include + +struct string_set { + tchar **strings; + size_t num_strings; + size_t num_alloc_strings; +}; + +#define STRING_SET_INITIALIZER \ + { .strings = NULL, .num_strings = 0, .num_alloc_strings = 0, } + +#define STRING_SET(_strings) \ + struct string_set _strings = STRING_SET_INITIALIZER + +typedef int (*line_mangle_t)(tchar *line, const tchar *filename, + unsigned long line_no); + +struct text_file_section { + const tchar *name; + struct string_set *strings; +}; + +extern int +do_load_text_file(const tchar *path, tchar *buf, size_t buflen, tchar **buf_ret, + const struct text_file_section *pos_sections, + int num_pos_sections, line_mangle_t mangle_line); + +static inline int +load_text_file(const tchar *path, tchar **buf_ret, + const struct text_file_section *pos_sections, + int num_pos_sections, line_mangle_t mangle_line) +{ + return do_load_text_file(path, NULL, 0, buf_ret, + pos_sections, num_pos_sections, mangle_line); +} + +static inline int +load_text_buffer(tchar *buf, size_t buflen, + const struct text_file_section *pos_sections, + int num_pos_sections, line_mangle_t mangle_line) +{ + return do_load_text_file(NULL, buf, buflen, &buf, + pos_sections, num_pos_sections, mangle_line); +} + +#endif /* _WIMLIB_TEXTFILE_H_ */ diff --git a/include/wimlib_tchar.h b/include/wimlib_tchar.h index ecaae5d5..519c425d 100644 --- a/include/wimlib_tchar.h +++ b/include/wimlib_tchar.h @@ -21,6 +21,7 @@ typedef wchar_t tchar; * with the "wide-character" functions. */ # define tmemchr wmemchr # define tmemcpy wmemcpy +# define tmemmove wmemmove # define tmempcpy wmempcpy # define tstrcpy wcscpy # define tprintf wprintf @@ -84,6 +85,7 @@ typedef char tchar; * string functions. */ # define tmemchr memchr # define tmemcpy memcpy +# define tmemmove memmove # define tmempcpy mempcpy # define tstrcpy strcpy # define tprintf printf diff --git a/programs/imagex.c b/programs/imagex.c index e80d3e6c..753206d5 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -417,17 +417,6 @@ imagex_error(const tchar *format, ...) va_end(va); } -static void _format_attribute(printf, 1, 2) -imagex_warning(const tchar *format, ...) -{ - va_list va; - va_start(va, format); - tfputs(T("WARNING: "), stderr); - tvfprintf(stderr, format, va); - tputc(T('\n'), stderr); - va_end(va); -} - /* Print formatted error message to stderr. */ static void _format_attribute(printf, 1, 2) imagex_error_with_errno(const tchar *format, ...) @@ -827,147 +816,6 @@ parse_source_list(tchar **source_list_contents_p, size_t source_list_nchars, return sources; } - -enum capture_config_section { - CAPTURE_CONFIG_NO_SECTION, - CAPTURE_CONFIG_EXCLUSION_SECTION, - CAPTURE_CONFIG_EXCLUSION_EXCEPTION_SECTION, - CAPTURE_CONFIG_IGNORE_SECTION, -}; - -enum { - CAPTURE_CONFIG_INVALID_SECTION, - CAPTURE_CONFIG_CHANGED_SECTION, - CAPTURE_CONFIG_SAME_SECTION, -}; - -static int -check_config_section(tchar *line, size_t len, - enum capture_config_section *cur_section) -{ - while (istspace(*line)) - line++; - - if (*line != T('[')) - return CAPTURE_CONFIG_SAME_SECTION; - - line++; - tchar *endbrace = tstrrchr(line, T(']')); - if (!endbrace) - return CAPTURE_CONFIG_SAME_SECTION; - - if (!tmemcmp(line, T("ExclusionList"), endbrace - line)) { - *cur_section = CAPTURE_CONFIG_EXCLUSION_SECTION; - } else if (!tmemcmp(line, T("ExclusionException"), endbrace - line)) { - *cur_section = CAPTURE_CONFIG_EXCLUSION_EXCEPTION_SECTION; - } else if (!tmemcmp(line, T("CompressionExclusionList"), endbrace - line)) { - *cur_section = CAPTURE_CONFIG_IGNORE_SECTION; - tfputs(T("WARNING: Ignoring [CompressionExclusionList] section " - "of capture config file\n"), - stderr); - } else if (!tmemcmp(line, T("AlignmentList"), endbrace - line)) { - *cur_section = CAPTURE_CONFIG_IGNORE_SECTION; - tfputs(T("WARNING: Ignoring [AlignmentList] section " - "of capture config file\n"), - stderr); - } else { - imagex_warning(T("Unknown capture config file section \"%"TS"\""), - line - 1); - return CAPTURE_CONFIG_INVALID_SECTION; - } - return CAPTURE_CONFIG_CHANGED_SECTION; -} - - -static bool -pattern_list_add_pattern(struct wimlib_pattern_list *pat_list, - tchar *pat) -{ - if (pat_list->num_pats == pat_list->num_allocated_pats) { - tchar **pats; - size_t num_allocated_pats = pat_list->num_pats + 8; - - pats = realloc(pat_list->pats, - num_allocated_pats * sizeof(pat_list->pats[0])); - if (!pats) { - imagex_error(T("Out of memory!")); - return false; - } - pat_list->pats = pats; - pat_list->num_allocated_pats = num_allocated_pats; - } - pat_list->pats[pat_list->num_pats++] = pat; - return true; -} - -static bool -parse_capture_config_line(tchar *line, size_t len, - enum capture_config_section *cur_section, - struct wimlib_capture_config *config) -{ - tchar *filename; - int ret; - - ret = check_config_section(line, len, cur_section); - if (ret == CAPTURE_CONFIG_CHANGED_SECTION || - ret == CAPTURE_CONFIG_INVALID_SECTION) - return true; - - switch (*cur_section) { - case CAPTURE_CONFIG_NO_SECTION: - imagex_error(T("Line \"%"TS"\" is not in a section " - "(such as [ExclusionList]"), line); - return false; - case CAPTURE_CONFIG_EXCLUSION_SECTION: - if (parse_string(&line, &len, &filename) != PARSE_STRING_SUCCESS) - return false; - return pattern_list_add_pattern(&config->exclusion_pats, - filename); - case CAPTURE_CONFIG_EXCLUSION_EXCEPTION_SECTION: - if (parse_string(&line, &len, &filename) != PARSE_STRING_SUCCESS) - return false; - return pattern_list_add_pattern(&config->exclusion_exception_pats, - filename); - case CAPTURE_CONFIG_IGNORE_SECTION: - return true; - } - return false; -} - -static int -parse_capture_config(tchar **contents_p, size_t nchars, - struct wimlib_capture_config *config) -{ - ssize_t nlines; - tchar *p; - size_t i; - enum capture_config_section cur_section; - - memset(config, 0, sizeof(*config)); - - nlines = text_file_count_lines(contents_p, &nchars); - if (nlines < 0) - return -1; - - cur_section = CAPTURE_CONFIG_NO_SECTION; - p = *contents_p; - for (i = 0; i < nlines; i++) { - tchar *endp = tmemchr(p, T('\n'), nchars); - size_t len = endp - p + 1; - *endp = T('\0'); - if (p != endp && *(endp - 1) == T('\r')) { - *(endp - 1) = '\0'; - len--; - } - if (!is_comment_line(p, len)) - if (!parse_capture_config_line(p, len, &cur_section, config)) - return -1; - p = endp + 1; - - } - return 0; -} - /* Reads the contents of a file into memory. */ static char * file_get_contents(const tchar *filename, size_t *len_ret) @@ -1842,8 +1690,6 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) tchar *source_copy; tchar *config_file = NULL; - tchar *config_str; - struct wimlib_capture_config *config; bool source_list = false; size_t source_list_nchars = 0; @@ -2002,26 +1848,6 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) if (compress_slow) set_compress_slow(); - /* Set default configuration file */ -#ifdef __WIN32__ - if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_WIMBOOT) && !config) { - struct stat st; - - config_file = alloca(wcslen(source) * sizeof(wchar_t) + 100); - swprintf(config_file, L"%ls\\%ls", - source, L"Windows\\System32\\WimBootCompress.ini"); - - if (tstat(config_file, &st)) { - imagex_printf(L"\"%ls\" does not exist; using " - "default configuration\n", - config_file); - config_file = NULL; - } else { - add_image_flags &= ~WIMLIB_ADD_IMAGE_FLAG_WINCONFIG; - } - } -#endif - if (!tstrcmp(wimfile, T("-"))) { /* Writing captured WIM to standard output. */ #if 0 @@ -2126,27 +1952,6 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) source_list_contents = NULL; } - if (config_file) { - /* Read and parse capture configuration file. */ - size_t config_len; - - config_str = file_get_text_contents(config_file, &config_len); - if (!config_str) { - ret = -1; - goto out_free_capture_sources; - } - - config = alloca(sizeof(*config)); - ret = parse_capture_config(&config_str, config_len, config); - if (ret) - goto out_free_config; - } else { - /* No capture configuration file specified; use default - * configuration for capturing Windows operating systems. */ - config = NULL; - add_image_flags |= WIMLIB_ADD_FLAG_WINCONFIG; - } - /* Open the existing WIM, or create a new one. */ if (cmd == CMD_APPEND) ret = wimlib_open_wim(wimfile, open_flags, &wim, @@ -2154,7 +1959,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) else ret = wimlib_create_new_wim(compression_type, &wim); if (ret) - goto out_free_config; + goto out_free_capture_sources; /* Set chunk size if non-default. */ if (chunk_size != UINT32_MAX) { @@ -2294,7 +2099,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) capture_sources, num_sources, name, - config, + config_file, add_image_flags, imagex_progress_func); if (ret) @@ -2364,12 +2169,6 @@ out_free_base_wims: free(base_wims); out_free_wim: wimlib_free(wim); -out_free_config: - if (config) { - free(config->exclusion_pats.pats); - free(config->exclusion_exception_pats.pats); - free(config_str); - } out_free_capture_sources: if (capture_sources_malloced) free(capture_sources); @@ -3863,7 +3662,8 @@ imagex_update(int argc, tchar **argv, int cmd) int write_flags = 0; int update_flags = WIMLIB_UPDATE_FLAG_SEND_PROGRESS; int default_add_flags = WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE | - WIMLIB_ADD_FLAG_VERBOSE; + WIMLIB_ADD_FLAG_VERBOSE | + WIMLIB_ADD_FLAG_WINCONFIG; int default_delete_flags = 0; unsigned num_threads = 0; int c; @@ -3872,10 +3672,7 @@ imagex_update(int argc, tchar **argv, int cmd) struct wimlib_update_command *cmds; size_t num_cmds; tchar *command_str = NULL; - - const tchar *config_file = NULL; - tchar *config_str; - struct wimlib_capture_config *config; + tchar *config_file = NULL; for_opt(c, update_options) { switch (c) { @@ -3973,25 +3770,6 @@ imagex_update(int argc, tchar **argv, int cmd) image = 1; } - /* Parse capture configuration file if specified */ - if (config_file) { - size_t config_len; - - config_str = file_get_text_contents(config_file, &config_len); - if (!config_str) { - ret = -1; - goto out_wimlib_free; - } - - config = alloca(sizeof(*config)); - ret = parse_capture_config(&config_str, config_len, config); - if (ret) - goto out_free_config; - } else { - config = NULL; - default_add_flags |= WIMLIB_ADD_FLAG_WINCONFIG; - } - /* Read update commands from standard input, or the command string if * specified. */ if (command_str) { @@ -4006,7 +3784,7 @@ imagex_update(int argc, tchar **argv, int cmd) cmd_file_contents = stdin_get_text_contents(&cmd_file_nchars); if (!cmd_file_contents) { ret = -1; - goto out_free_config; + goto out_wimlib_free; } /* Parse the update commands */ @@ -4023,7 +3801,7 @@ imagex_update(int argc, tchar **argv, int cmd) switch (cmds[i].op) { case WIMLIB_UPDATE_OP_ADD: cmds[i].add.add_flags |= default_add_flags; - cmds[i].add.config = config; + cmds[i].add.config_file = config_file; break; case WIMLIB_UPDATE_OP_DELETE: cmds[i].delete_.delete_flags |= default_delete_flags; @@ -4046,12 +3824,6 @@ out_free_cmds: free(cmds); out_free_cmd_file_contents: free(cmd_file_contents); -out_free_config: - if (config) { - free(config->exclusion_pats.pats); - free(config->exclusion_exception_pats.pats); - free(config_str); - } out_wimlib_free: wimlib_free(wim); out_free_command_str: diff --git a/src/add_image.c b/src/add_image.c index 1d826fb8..c8aeaa68 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -124,7 +124,7 @@ static struct wimlib_update_command * capture_sources_to_add_cmds(const struct wimlib_capture_source *sources, size_t num_sources, int add_flags, - const struct wimlib_capture_config *config) + const tchar *config_file) { struct wimlib_update_command *add_cmds; @@ -139,9 +139,8 @@ capture_sources_to_add_cmds(const struct wimlib_capture_source *sources, sources[i].fs_source_path, sources[i].wim_target_path); add_cmds[i].op = WIMLIB_UPDATE_OP_ADD; - add_cmds[i].add.add_flags = add_flags & ~(WIMLIB_ADD_FLAG_BOOT | - WIMLIB_ADD_FLAG_WIMBOOT); - add_cmds[i].add.config = (struct wimlib_capture_config*)config; + add_cmds[i].add.add_flags = add_flags & ~WIMLIB_ADD_FLAG_BOOT; + add_cmds[i].add.config_file = (tchar *)config_file; add_cmds[i].add.fs_source_path = sources[i].fs_source_path; add_cmds[i].add.wim_target_path = sources[i].wim_target_path; } @@ -155,7 +154,7 @@ wimlib_add_image_multisource(WIMStruct *wim, const struct wimlib_capture_source *sources, size_t num_sources, const tchar *name, - const struct wimlib_capture_config *config, + const tchar *config_file, int add_flags, wimlib_progress_func_t progress_func) { @@ -176,7 +175,7 @@ wimlib_add_image_multisource(WIMStruct *wim, /* Translate the "capture sources" into generic update commands. */ add_cmds = capture_sources_to_add_cmds(sources, num_sources, - add_flags, config); + add_flags, config_file); if (add_cmds == NULL) { ret = WIMLIB_ERR_NOMEM; goto out_delete_image; @@ -211,7 +210,7 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *wim, const tchar *source, const tchar *name, - const struct wimlib_capture_config *config, + const tchar *config_file, int add_flags, wimlib_progress_func_t progress_func) { @@ -223,6 +222,6 @@ wimlib_add_image(WIMStruct *wim, .reserved = 0, }; return wimlib_add_image_multisource(wim, &capture_src, 1, name, - config, add_flags, + config_file, add_flags, progress_func); } diff --git a/src/capture_common.c b/src/capture_common.c index 41978612..d955c368 100644 --- a/src/capture_common.c +++ b/src/capture_common.c @@ -31,15 +31,47 @@ #include "wimlib/error.h" #include "wimlib/lookup_table.h" #include "wimlib/paths.h" +#include "wimlib/textfile.h" #include "wimlib/wildcard.h" #include -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, + ¶ms->progress); + } +} +static 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(':')) { @@ -49,103 +81,66 @@ 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 path \"%"TS"\"; paths including " + "drive letters must be absolute!\n" + " Maybe try \"%"TC":\\%"TS"\"?", + path, line_no, pat, pat[0], &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++) + * preferred path separator. */ + for (tchar *p = 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], ©->pats[i]); - if (ret) - break; - } - return ret; -} - 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, tchar *buf, size_t buflen, + 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); + struct text_file_section sections[] = { + {T("ExclusionList"), + &config->exclusion_pats}, + {T("ExclusionException"), + &config->exclusion_exception_pats}, + }; + + ret = do_load_text_file(config_file, buf, buflen, &buf, + sections, ARRAY_LEN(sections), 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); + config->buf = buf; + 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) + const struct string_set *list) { - for (size_t i = 0; i < list->num_pats; i++) { + for (size_t i = 0; i < list->num_strings; i++) { - const tchar *pat = list->pats[i]; + const tchar *pat = list->strings[i]; const tchar *string; if (*pat == OS_PREFERRED_PATH_SEPARATOR) { @@ -176,39 +171,6 @@ match_pattern(const tchar *path, 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: - 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, - ¶ms->progress); - } -} - /* Return true if the image capture configuration file indicates we should * exclude the filename @path from capture. * @@ -220,17 +182,17 @@ do_capture_progress(struct add_image_params *params, int status, */ bool exclude_path(const tchar *path, size_t path_len, - const struct wimlib_capture_config *config, bool exclude_prefix) + const struct capture_config *config, bool exclude_prefix) { 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) + 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; + path += config->prefix_num_tchars; } } return match_pattern(path, basename, &config->exclusion_pats) && diff --git a/src/pathlist.c b/src/pathlist.c index e14c1877..c366ed7f 100644 --- a/src/pathlist.c +++ b/src/pathlist.c @@ -27,176 +27,28 @@ # include "config.h" #endif -#include "wimlib/encoding.h" -#include "wimlib/error.h" -#include "wimlib/file_io.h" #include "wimlib/pathlist.h" -#include "wimlib/util.h" - -#include -#include -#include -#include -#include -#include - -static int -read_file_contents(const tchar *path, char **buf_ret, size_t *bufsize_ret) -{ - int raw_fd; - struct filedes fd; - struct stat st; - void *buf; - int ret; - int errno_save; - - raw_fd = topen(path, O_RDONLY | O_BINARY); - if (raw_fd < 0) { - ERROR_WITH_ERRNO("Can't open \"%"TS"\"", path); - return WIMLIB_ERR_OPEN; - } - if (fstat(raw_fd, &st)) { - ERROR_WITH_ERRNO("Can't stat \"%"TS"\"", path); - close(raw_fd); - return WIMLIB_ERR_STAT; - } - if ((size_t)st.st_size != st.st_size || - (buf = MALLOC(st.st_size)) == NULL) - { - close(raw_fd); - ERROR("Not enough memory to read \"%"TS"\"", path); - return WIMLIB_ERR_NOMEM; - } - - filedes_init(&fd, raw_fd); - ret = full_read(&fd, buf, st.st_size); - errno_save = errno; - filedes_close(&fd); - errno = errno_save; - if (ret) { - ERROR_WITH_ERRNO("Error reading \"%"TS"\"", path); - FREE(buf); - return ret; - } - - *buf_ret = buf; - *bufsize_ret = st.st_size; - return 0; -} - -static int -read_utf8_file_contents(const tchar *path, tchar **buf_ret, size_t *buflen_ret) -{ - int ret; - char *buf_utf8; - size_t bufsize_utf8; - size_t offset_utf8; - tchar *buf_tstr; - size_t bufsize_tstr; - - ret = read_file_contents(path, &buf_utf8, &bufsize_utf8); - if (ret) - return ret; - - /* Ignore UTF-8 BOM. */ - if (bufsize_utf8 >= 3 && (u8)buf_utf8[0] == 0xef && - (u8)buf_utf8[1] == 0xbb && (u8)buf_utf8[2] == 0xbf) - offset_utf8 = 3; - else - offset_utf8 = 0; - - ret = utf8_to_tstr(buf_utf8 + offset_utf8, bufsize_utf8 - offset_utf8, - &buf_tstr, &bufsize_tstr); - FREE(buf_utf8); - if (ret) - return ret; - - *buf_ret = buf_tstr; - *buflen_ret = bufsize_tstr / sizeof(tchar); - return 0; -} - -static int -parse_path_list_file(tchar *buf, size_t buflen, - tchar ***paths_ret, size_t *num_paths_ret) -{ - tchar **paths = NULL; - size_t num_paths = 0; - size_t num_alloc_paths = 0; - tchar *nl; - tchar *p; - - for (p = buf; p != buf + buflen; p = nl + 1) { - tchar *line_begin, *line_end; - size_t line_len; - - nl = tmemchr(p, T('\n'), buf + buflen - p); - if (nl == NULL) - break; - - line_begin = p; - line_end = nl; - - /* Ignore leading whitespace. */ - while (line_begin < nl && istspace(*line_begin)) - line_begin++; - - /* Ignore trailing whitespace. */ - while (line_end > line_begin && istspace(*(line_end - 1))) - line_end--; - - line_len = line_end - line_begin; - - /* Ignore comments and empty lines. */ - if (line_len == 0 || *line_begin == T(';')) - continue; - - if (num_paths == num_alloc_paths) { - tchar **new_paths; - size_t new_num_alloc_paths = max(num_alloc_paths + 8, - num_alloc_paths * 3 / 2); - - new_paths = REALLOC(paths, new_num_alloc_paths * - sizeof(paths[0])); - if (new_paths == NULL) - goto oom; - paths = new_paths; - num_alloc_paths = new_num_alloc_paths; - } - - *line_end = T('\0'); - paths[num_paths++] = line_begin; - } - - *paths_ret = paths; - *num_paths_ret = num_paths; - return 0; - -oom: - FREE(paths); - return WIMLIB_ERR_NOMEM; -} +#include "wimlib/textfile.h" int read_path_list_file(const tchar *listfile, tchar ***paths_ret, size_t *num_paths_ret, void **mem_ret) { - int ret; + STRING_SET(paths); + struct text_file_section tmp = { + .name = T(""), + .strings = &paths, + }; tchar *buf; - size_t buflen; + int ret; - ret = read_utf8_file_contents(listfile, &buf, &buflen); + ret = load_text_file(listfile, &buf, &tmp, 1, NULL); if (ret) return ret; - buf[buflen++] = T('\n'); - - ret = parse_path_list_file(buf, buflen, paths_ret, num_paths_ret); - if (ret) { - FREE(buf); - return ret; - } - *mem_ret = buf; + *paths_ret = paths.strings; + *num_paths_ret = paths.num_strings; + *mem_ret = (void *)buf; return 0; } diff --git a/src/textfile.c b/src/textfile.c new file mode 100644 index 00000000..8e1bb6cc --- /dev/null +++ b/src/textfile.c @@ -0,0 +1,345 @@ +/* + * textfile.c + */ + +/* + * Copyright (C) 2014 Eric Biggers + * + * This file is part of wimlib, a library for working with WIM files. + * + * wimlib is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * + * wimlib 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with wimlib; if not, see http://www.gnu.org/licenses/. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wimlib/assert.h" +#include "wimlib/encoding.h" +#include "wimlib/error.h" +#include "wimlib/file_io.h" +#include "wimlib/textfile.h" +#include "wimlib/util.h" + +#include +#include +#include +#include +#include +#include + +static int +read_file_contents(const tchar *path, u8 **buf_ret, size_t *bufsize_ret) +{ + int raw_fd; + struct filedes fd; + struct stat st; + u8 *buf; + int ret; + int errno_save; + + if (!path || !*path) + return WIMLIB_ERR_INVALID_PARAM; + + raw_fd = topen(path, O_RDONLY | O_BINARY); + if (raw_fd < 0) { + ERROR_WITH_ERRNO("Can't open \"%"TS"\"", path); + return WIMLIB_ERR_OPEN; + } + if (fstat(raw_fd, &st)) { + ERROR_WITH_ERRNO("Can't stat \"%"TS"\"", path); + close(raw_fd); + return WIMLIB_ERR_STAT; + } + if ((size_t)st.st_size != st.st_size || + (buf = MALLOC(st.st_size)) == NULL) + { + close(raw_fd); + ERROR("Not enough memory to read \"%"TS"\"", path); + return WIMLIB_ERR_NOMEM; + } + + filedes_init(&fd, raw_fd); + ret = full_read(&fd, buf, st.st_size); + errno_save = errno; + filedes_close(&fd); + errno = errno_save; + if (ret) { + ERROR_WITH_ERRNO("Error reading \"%"TS"\"", path); + FREE(buf); + return ret; + } + + *buf_ret = buf; + *bufsize_ret = st.st_size; + return 0; +} + +static int +read_text_file_contents(const tchar *path, + tchar **buf_ret, size_t *buflen_ret) +{ + int ret; + u8 *buf_raw; + size_t bufsize_raw; + size_t offset_raw; + bool utf8; + tchar *buf_tstr; + size_t bufsize_tstr; + + ret = read_file_contents(path, &buf_raw, &bufsize_raw); + if (ret) + return ret; + + /* Guess the encoding: UTF-8 or UTF-16LE. (Something weirder and you're + * out of luck, sorry...) */ + if (bufsize_raw >= 2 && + buf_raw[0] == 0xFF && + buf_raw[1] == 0xFE) + { + utf8 = false; + offset_raw = 2; + } + else if (bufsize_raw >= 2 && + buf_raw[0] <= 0x7F && + buf_raw[1] == 0x00) + { + utf8 = false; + offset_raw = 0; + } + else if (bufsize_raw >= 3 && + buf_raw[0] == 0xEF && + buf_raw[1] == 0xBB && + buf_raw[2] == 0xBF) + { + utf8 = true; + offset_raw = 3; + } + else + { + utf8 = true; + offset_raw = 0; + } + + if (utf8) { + ret = utf8_to_tstr((const char *)(buf_raw + offset_raw), + bufsize_raw - offset_raw, + &buf_tstr, &bufsize_tstr); + } else { + #if TCHAR_IS_UTF16LE + bufsize_tstr = bufsize_raw - offset_raw; + buf_tstr = MALLOC(bufsize_tstr + 2); + if (buf_tstr) { + memcpy(buf_tstr, buf_raw + offset_raw, bufsize_tstr); + ((u8*)buf_tstr)[bufsize_tstr + 0] = 0; + ((u8*)buf_tstr)[bufsize_tstr + 1] = 0; + } else { + ret = WIMLIB_ERR_NOMEM; + } + #else + ret = utf16le_to_tstr((const utf16lechar *)(buf_raw + offset_raw), + bufsize_raw - offset_raw, + &buf_tstr, &bufsize_tstr); + #endif + } + FREE(buf_raw); + if (ret) + return ret; + + *buf_ret = buf_tstr; + *buflen_ret = bufsize_tstr / sizeof(tchar); + return 0; +} + +static int +string_set_append(struct string_set *set, tchar *str) +{ + size_t num_alloc_strings = set->num_alloc_strings; + + if (set->num_strings == num_alloc_strings) { + tchar **new_strings; + + num_alloc_strings = max(num_alloc_strings * 3 / 2, + num_alloc_strings + 4); + new_strings = REALLOC(set->strings, + sizeof(set->strings[0]) * num_alloc_strings); + if (!new_strings) + return WIMLIB_ERR_NOMEM; + set->strings = new_strings; + set->num_alloc_strings = num_alloc_strings; + } + set->strings[set->num_strings++] = str; + return 0; +} + +#define NOT_IN_SECTION -1 +#define IN_UNKNOWN_SECTION -2 + +static int +parse_text_file(const tchar *path, tchar *buf, size_t buflen, + const struct text_file_section *pos_sections, + int num_pos_sections, line_mangle_t mangle_line) +{ + int current_section = NOT_IN_SECTION; + bool have_named_sections = false; + tchar *p; + tchar *nl; + unsigned long line_no = 1; + + for (int i = 0; i < num_pos_sections; i++) { + if (*pos_sections[i].name) + have_named_sections = true; + else + current_section = i; + } + + for (p = buf; p != buf + buflen; p = nl + 1, line_no++) { + tchar *line_begin, *line_end; + size_t line_len; + int ret; + + nl = tmemchr(p, T('\n'), buf + buflen - p); + if (!nl) + break; + + line_begin = p; + line_end = nl; + + /* Ignore leading whitespace. */ + while (line_begin < nl && istspace(*line_begin)) + line_begin++; + + /* Ignore trailing whitespace. */ + while (line_end > line_begin && istspace(*(line_end - 1))) + line_end--; + + line_len = line_end - line_begin; + + /* Ignore comments and empty lines. */ + if (line_len == 0 || *line_begin == T(';') || *line_begin == T('#')) + continue; + + line_begin[line_len] = T('\0'); + + /* Check for beginning of new section. */ + if (line_begin[0] == T('[') && + line_begin[line_len - 1] == T(']') && + have_named_sections) + { + line_begin[line_len - 1] = T('\0'); + current_section = IN_UNKNOWN_SECTION; + for (int i = 0; i < num_pos_sections; i++) { + if (!tstrcmp(line_begin + 1, + pos_sections[i].name)) + { + current_section = i; + break; + } + } + line_begin[line_len - 1] = T(']'); + if (current_section < 0) + WARNING("%"TS":%lu: Unrecognized section \"%"TS"\"", + path, line_no, line_begin); + continue; + } + + if (current_section < 0) { + if (current_section == NOT_IN_SECTION) + WARNING("%"TS":%lu: Not in a bracketed section!", + path, line_no); + continue; + } + + if (mangle_line) { + ret = (*mangle_line)(line_begin, path, line_no); + if (ret) + return ret; + } + + ret = string_set_append(pos_sections[current_section].strings, + line_begin); + if (ret) + return ret; + } + return 0; +} + +/** + * do_load_text_file - + * + * Read and parse lines from a text file from an on-disk file or a buffer. + * The file may contain sections, like in an INI file. + * + * @path + * Path to the file on disk to read, or a dummy name for the buffer. + * @buf + * If NULL, the data will be read from the @path file. Otherwise the data + * will be read from this buffer, which must be newline-terminated. + * @buflen + * Length of buffer in 'tchars'; ignored if @buf is NULL. + * @buf_ret + * On success, a pointer to a buffer backing the parsed lines is stored + * here. If @buf is not NULL, this will be @buf. Otherwise, this will be + * an allocated buffer that must be freed when finished with the lines. + * @pos_sections + * Specifications of allowed sections in the file. Each such specification + * consists of the name of the section (e.g. [ExclusionList], like in the + * INI file format), along with a pointer to the list of lines parsed for + * that section. Use an empty name to indicate the destination of lines + * not in any section. + * @num_pos_sections + * Length of @pos_sections array. + * @mangle_line + * Optional callback to modify each line being read. + * + * Returns 0 on success or a positive error code on failure. + * + * Unknown sections are ignored (warning printed). + */ +int +do_load_text_file(const tchar *path, + tchar *buf, size_t buflen, + tchar **buf_ret, + const struct text_file_section *pos_sections, + int num_pos_sections, + line_mangle_t mangle_line) +{ + int ret; + bool pathmode = (buf == NULL); + + if (pathmode) { + ret = read_text_file_contents(path, &buf, &buflen); + if (ret) + return ret; + + /* Overwrite '\0' with '\n' to avoid special case of last line + * not terminated with '\n'. */ + buf[buflen++] = T('\n'); + } else { + wimlib_assert(buflen > 0 && buf[buflen - 1] == T('\n')); + } + + ret = parse_text_file(path, buf, buflen, pos_sections, + num_pos_sections, mangle_line); + if (ret) { + for (int i = 0; i < num_pos_sections; i++) + FREE(pos_sections[i].strings->strings); + if (pathmode) + FREE(buf); + return ret; + } + + *buf_ret = buf; + return 0; +} diff --git a/src/update_image.c b/src/update_image.c index 9e6262cf..82aac7ff 100644 --- a/src/update_image.c +++ b/src/update_image.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2013 Eric Biggers + * Copyright (C) 2013, 2014 Eric Biggers * * This file is part of wimlib, a library for working with WIM files. * @@ -37,6 +37,7 @@ #include "wimlib/xml.h" #include +#include /* Overlays @branch onto @target, both of which must be directories. */ static int @@ -164,6 +165,82 @@ attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch, } } +const tchar wincfg[] = +T( +"[ExclusionList]\n" +"/$ntfs.log\n" +"/hiberfil.sys\n" +"/pagefile.sys\n" +"/System Volume Information\n" +"/RECYCLER\n" +"/Windows/CSC\n" +); + +static int +get_capture_config(const tchar *config_file, struct capture_config *config, + int add_flags, const tchar *fs_source_path) +{ + int ret; + tchar *tmp_config_file = NULL; + + memset(config, 0, sizeof(*config)); + + /* For WIMBoot capture, check for default capture configuration file + * unless one was explicitly specified. */ + if (!config_file && (add_flags & WIMLIB_ADD_FLAG_WIMBOOT)) { + + /* XXX: Handle loading file correctly when in NTFS volume. */ + + const tchar *wimboot_cfgfile = + T("/Windows/System32/WimBootCompress.ini"); + size_t len = tstrlen(fs_source_path) + + tstrlen(wimboot_cfgfile); + tmp_config_file = MALLOC((len + 1) * sizeof(tchar)); + struct stat st; + + tsprintf(tmp_config_file, T("%"TS"%"TS), + fs_source_path, wimboot_cfgfile); + if (!tstat(tmp_config_file, &st)) { + config_file = tmp_config_file; + add_flags &= ~WIMLIB_ADD_FLAG_WINCONFIG; + } else { + WARNING("\"%"TS"\" does not exist.\n" + " Using default capture configuration!", + tmp_config_file); + } + } + + if (add_flags & WIMLIB_ADD_FLAG_WINCONFIG) { + + /* Use Windows default. */ + + tchar *wincfg_copy; + const size_t wincfg_len = ARRAY_LEN(wincfg) - 1; + + if (config_file) + return WIMLIB_ERR_INVALID_PARAM; + + wincfg_copy = memdup(wincfg, wincfg_len * sizeof(wincfg[0])); + if (!wincfg_copy) + return WIMLIB_ERR_NOMEM; + + ret = do_read_capture_config_file(T("wincfg"), wincfg_copy, + wincfg_len, config); + if (ret) + FREE(wincfg_copy); + } else if (config_file) { + /* Use the specified configuration file. */ + ret = do_read_capture_config_file(config_file, NULL, 0, config); + } else { + /* ... Or don't use any configuration file at all. No files + * will be excluded from capture, all files will be compressed, + * etc. */ + ret = 0; + } + FREE(tmp_config_file); + return ret; +} + static int execute_add_command(WIMStruct *wim, const struct wimlib_update_command *add_cmd, @@ -179,7 +256,8 @@ execute_add_command(WIMStruct *wim, int (*capture_tree)(struct wim_dentry **, const tchar *, struct add_image_params *); - struct wimlib_capture_config *config; + const tchar *config_file; + struct capture_config config; #ifdef WITH_NTFS_3G struct _ntfs_volume *ntfs_vol = NULL; #endif @@ -192,7 +270,8 @@ execute_add_command(WIMStruct *wim, add_flags = add_cmd->add.add_flags; fs_source_path = add_cmd->add.fs_source_path; wim_target_path = add_cmd->add.wim_target_path; - config = add_cmd->add.config; + config_file = add_cmd->add.config_file; + DEBUG("fs_source_path=\"%"TS"\", wim_target_path=\"%"TS"\", add_flags=%#x", fs_source_path, wim_target_path, add_flags); @@ -222,10 +301,14 @@ execute_add_command(WIMStruct *wim, extra_arg = NULL; } + ret = get_capture_config(config_file, &config, + add_flags, fs_source_path); + if (ret) + goto out; ret = init_inode_table(¶ms.inode_table, 9001); if (ret) - goto out; + goto out_destroy_config; ret = init_sd_set(¶ms.sd_set, imd->security_data); if (ret) @@ -234,7 +317,7 @@ execute_add_command(WIMStruct *wim, INIT_LIST_HEAD(&unhashed_streams); params.lookup_table = wim->lookup_table; params.unhashed_streams = &unhashed_streams; - params.config = config; + params.config = &config; params.add_flags = add_flags; params.extra_arg = extra_arg; @@ -243,10 +326,9 @@ execute_add_command(WIMStruct *wim, params.progress.scan.wim_target_path = wim_target_path; if (progress_func) progress_func(WIMLIB_PROGRESS_MSG_SCAN_BEGIN, ¶ms.progress); - if (config) { - config->_prefix = fs_source_path; - config->_prefix_num_tchars = tstrlen(fs_source_path); - } + + config.prefix = fs_source_path; + config.prefix_num_tchars = tstrlen(fs_source_path); if (wim_target_path[0] == T('\0')) params.add_flags |= WIMLIB_ADD_FLAG_ROOT; @@ -291,6 +373,8 @@ out_destroy_sd_set: destroy_sd_set(¶ms.sd_set, rollback_sd); out_destroy_inode_table: destroy_inode_table(¶ms.inode_table); +out_destroy_config: + destroy_capture_config(&config); out: return ret; } @@ -440,22 +524,6 @@ execute_update_commands(WIMStruct *wim, } -tchar *winpats[] = { - T("/$ntfs.log"), - T("/hiberfil.sys"), - T("/pagefile.sys"), - T("/System Volume Information"), - T("/RECYCLER"), - T("/Windows/CSC"), -}; - -static const struct wimlib_capture_config winconfig = { - .exclusion_pats = { - .num_pats = ARRAY_LEN(winpats), - .pats = winpats, - }, -}; - static int check_add_command(struct wimlib_update_command *cmd, const struct wim_header *hdr) @@ -465,10 +533,9 @@ check_add_command(struct wimlib_update_command *cmd, if (add_flags & ~(WIMLIB_ADD_FLAG_NTFS | WIMLIB_ADD_FLAG_DEREFERENCE | WIMLIB_ADD_FLAG_VERBOSE | - /* BOOT doesn't make sense for wimlib_update_image(). - * Same with WIMBOOT. */ + /* BOOT doesn't make sense for wimlib_update_image(). */ /*WIMLIB_ADD_FLAG_BOOT |*/ - /*WIMLIB_ADD_FLAG_WIMBOOT |*/ + WIMLIB_ADD_FLAG_WIMBOOT | WIMLIB_ADD_FLAG_UNIX_DATA | WIMLIB_ADD_FLAG_NO_ACLS | WIMLIB_ADD_FLAG_STRICT_ACLS | @@ -603,7 +670,7 @@ free_update_commands(struct wimlib_update_command *cmds, size_t num_cmds) case WIMLIB_UPDATE_OP_ADD: FREE(cmds[i].add.fs_source_path); FREE(cmds[i].add.wim_target_path); - free_capture_config(cmds[i].add.config); + FREE(cmds[i].add.config_file); break; case WIMLIB_UPDATE_OP_DELETE: FREE(cmds[i].delete_.wim_path); @@ -625,7 +692,6 @@ copy_update_commands(const struct wimlib_update_command *cmds, { int ret; struct wimlib_update_command *cmds_copy; - const struct wimlib_capture_config *config; cmds_copy = CALLOC(num_cmds, sizeof(cmds[0])); if (!cmds_copy) @@ -642,14 +708,10 @@ copy_update_commands(const struct wimlib_update_command *cmds, if (!cmds_copy[i].add.fs_source_path || !cmds_copy[i].add.wim_target_path) goto oom; - config = cmds[i].add.config; - if (cmds[i].add.add_flags & WIMLIB_ADD_FLAG_WINCONFIG) - config = &winconfig; - if (config) { - ret = copy_and_canonicalize_capture_config(config, - &cmds_copy[i].add.config); - if (ret) - goto err; + if (cmds[i].add.config_file) { + cmds_copy[i].add.config_file = TSTRDUP(cmds[i].add.config_file); + if (!cmds_copy[i].add.config_file) + goto oom; } cmds_copy[i].add.add_flags = cmds[i].add.add_flags; break; diff --git a/src/wimboot.c b/src/wimboot.c index beb4eab6..2d3ab08f 100644 --- a/src/wimboot.c +++ b/src/wimboot.c @@ -29,14 +29,13 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ -#ifndef __WIN32__ -# error "This file contains Windows code!" -#endif #ifdef HAVE_CONFIG_H # include "config.h" #endif +#ifdef __WIN32__ + #include "wimlib/win32_common.h" #include "wimlib/win32.h" #include "wimlib/assert.h" @@ -293,3 +292,5 @@ out_close_handle: out: return ret; } + +#endif /* __WIN32__ */ diff --git a/src/win32_capture.c b/src/win32_capture.c index cf5c65c9..6f748a36 100644 --- a/src/win32_capture.c +++ b/src/win32_capture.c @@ -1424,9 +1424,9 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, /* Update pattern prefix. */ if (params->config != NULL) { - params->config->_prefix = TSTRDUP(path); - params->config->_prefix_num_tchars = path_nchars; - if (params->config->_prefix == NULL) + params->config->prefix = TSTRDUP(path); + params->config->prefix_num_tchars = path_nchars; + if (params->config->prefix == NULL) { ret = WIMLIB_ERR_NOMEM; goto out_free_path; @@ -1438,7 +1438,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, path_nchars, params, &state, vol_flags); if (params->config != NULL) - FREE(params->config->_prefix); + FREE(params->config->prefix); out_free_path: FREE(path); if (ret == 0)