From 5e2f9715d5c0e1f1c3fc30a53d14df69a8bdae4a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 11 May 2013 20:32:12 -0500 Subject: [PATCH] WIM update fixes --- programs/imagex.c | 2 +- src/capture_common.c | 90 +++++++++++++++++++------------------------ src/update_image.c | 44 +++++++++++++++------ src/wimlib.h | 23 ++++++++++- src/wimlib_internal.h | 3 +- 5 files changed, 98 insertions(+), 64 deletions(-) diff --git a/programs/imagex.c b/programs/imagex.c index 4d0c2ff3..407967fa 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -2894,7 +2894,7 @@ imagex_update(int argc, tchar **argv) int open_flags = 0; int write_flags = WIMLIB_WRITE_FLAG_SOFT_DELETE; int update_flags = 0; - int default_add_flags = 0; + int default_add_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE; int default_delete_flags = 0; unsigned num_threads = 0; int c; diff --git a/src/capture_common.c b/src/capture_common.c index ef4fa5d6..431a4681 100644 --- a/src/capture_common.c +++ b/src/capture_common.c @@ -28,16 +28,15 @@ #endif static int -canonicalize_pat(tchar **pat_p) +canonicalize_pattern(const tchar *pat, tchar **canonical_pat_ret) { - tchar *pat = *pat_p; + tchar *canonical_pat; - /* Turn all backslashes in the pattern into forward slashes. */ - zap_backslashes(pat); - - if (*pat != T('/') && *pat != T('\0') && *(pat + 1) == T(':')) { + if (pat[0] != T('/') && pat[0] != T('\\') && + pat[0] != T('\0') && pat[1] == T(':')) + { /* Pattern begins with drive letter */ - if (*(pat + 2) != T('/')) { + if (pat[2] != T('/') && pat[2] != T('\\')) { /* Something like c:file, which is actually a path * relative to the current working directory on the c: * drive. We require paths with drive letters to be @@ -45,7 +44,7 @@ canonicalize_pat(tchar **pat_p) ERROR("Invalid path \"%"TS"\"; paths including drive letters " "must be absolute!", pat); ERROR("Maybe try \"%"TC":/%"TS"\"?", - *pat, pat + 2); + pat[0], pat + 2); return WIMLIB_ERR_INVALID_CAPTURE_CONFIG; } @@ -53,17 +52,26 @@ canonicalize_pat(tchar **pat_p) "being removed.", pat); /* Strip the drive letter */ pat += 2; - *pat_p = pat; } + canonical_pat = canonicalize_fs_path(pat); + if (!canonical_pat) + return WIMLIB_ERR_NOMEM; + *canonical_pat_ret = canonical_pat; return 0; } static int -canonicalize_pat_list(struct wimlib_pattern_list *pat_list) +copy_and_canonicalize_pattern_list(const struct wimlib_pattern_list *list, + struct wimlib_pattern_list *copy) { int ret = 0; - for (size_t i = 0; i < pat_list->num_pats; i++) { - ret = canonicalize_pat(&pat_list->pats[i]); + + 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; } @@ -71,49 +79,31 @@ canonicalize_pat_list(struct wimlib_pattern_list *pat_list) } int -canonicalize_capture_config(struct wimlib_capture_config *config) +copy_and_canonicalize_capture_config(const struct wimlib_capture_config *config, + struct wimlib_capture_config **config_copy_ret) { - int ret = canonicalize_pat_list(&config->exclusion_pats); - if (ret) - return ret; - return canonicalize_pat_list(&config->exclusion_exception_pats); -} + struct wimlib_capture_config *config_copy; + int ret; -static bool -copy_pattern_list(struct wimlib_pattern_list *copy, - const struct wimlib_pattern_list *list) -{ - copy->pats = CALLOC(list->num_pats, sizeof(list->pats[0])); - if (!copy->pats) - return false; - copy->num_pats = list->num_pats; - for (size_t i = 0; i < list->num_pats; i++) { - copy->pats[i] = TSTRDUP(list->pats[i]); - if (!copy->pats[i]) - return false; + config_copy = CALLOC(1, sizeof(struct wimlib_capture_config)); + if (!config_copy) { + ret = WIMLIB_ERR_NOMEM; + goto out_free_capture_config; } - return true; -} - -struct wimlib_capture_config * -copy_capture_config(const struct wimlib_capture_config *config) -{ - struct wimlib_capture_config *copy; - - copy = CALLOC(1, sizeof(struct wimlib_capture_config)); - if (!copy) - goto oom; - if (!copy_pattern_list(©->exclusion_pats, &config->exclusion_pats)) - goto oom; - if (!copy_pattern_list(©->exclusion_exception_pats, - &config->exclusion_exception_pats)) - goto oom; + 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); + if (ret) + goto out_free_capture_config; + *config_copy_ret = config_copy; goto out; -oom: - free_capture_config(copy); - copy = NULL; +out_free_capture_config: + free_capture_config(config_copy); out: - return copy; + return ret; } static void diff --git a/src/update_image.c b/src/update_image.c index 49ac6021..96583927 100644 --- a/src/update_image.c +++ b/src/update_image.c @@ -492,9 +492,16 @@ check_add_command(struct wimlib_update_command *cmd, const struct wim_header *hdr) { int add_flags = cmd->add.add_flags; + + /* Are we adding the entire image or not? An empty wim_target_path + * indicates that the tree we're adding is to be placed in the root of + * the image. We consider this to be capturing the entire image, + * although it could potentially be an overlay on an existing root as + * well. */ bool is_entire_image = cmd->add.wim_target_path[0] == T('\0'); - int ret; + #ifdef __WIN32__ + /* Check for flags not supported on Windows */ if (add_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) { ERROR("wimlib was compiled without support for NTFS-3g, so"); ERROR("we cannot capture a WIM image directly from a NTFS volume"); @@ -510,9 +517,11 @@ check_add_command(struct wimlib_update_command *cmd, } #endif + /* VERBOSE implies EXCLUDE_VERBOSE */ if (add_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) add_flags |= WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE; + /* Check for contradictory reparse point fixup flags */ if ((add_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX | WIMLIB_ADD_IMAGE_FLAG_NORPFIX)) == (WIMLIB_ADD_IMAGE_FLAG_RPFIX | @@ -523,6 +532,7 @@ check_add_command(struct wimlib_update_command *cmd, return WIMLIB_ERR_INVALID_PARAM; } + /* Set default behavior on reparse point fixups if requested */ if ((add_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX | WIMLIB_ADD_IMAGE_FLAG_NORPFIX)) == 0) { @@ -547,9 +557,6 @@ check_add_command(struct wimlib_update_command *cmd, return WIMLIB_ERR_INVALID_PARAM; } } - ret = canonicalize_capture_config(cmd->add.config); - if (ret) - return ret; cmd->add.add_flags = add_flags; return 0; } @@ -630,10 +637,10 @@ copy_update_commands(const struct wimlib_update_command *cmds, !cmds_copy[i].add.wim_target_path) goto oom; if (cmds[i].add.config) { - cmds_copy[i].add.config = - copy_capture_config(cmds[i].add.config); - if (!cmds_copy[i].add.config) - goto oom; + ret = copy_and_canonicalize_capture_config(cmds[i].add.config, + &cmds_copy[i].add.config); + if (ret) + goto err; } cmds_copy[i].add.add_flags = cmds[i].add.add_flags; break; @@ -670,6 +677,9 @@ err: goto out; } +/* + * Entry point for making a series of updates to a WIM image. + */ WIMLIBAPI int wimlib_update_image(WIMStruct *wim, int image, @@ -683,36 +693,48 @@ wimlib_update_image(WIMStruct *wim, DEBUG("Updating image %d with %zu commands", image, num_cmds); + /* Refuse to update a split WIM. */ if (wim->hdr.total_parts != 1) { ERROR("Cannot update a split WIM!"); ret = WIMLIB_ERR_SPLIT_UNSUPPORTED; goto out; } + /* Load the metadata for the image to modify (if not loaded already) */ ret = select_wim_image(wim, image); if (ret) goto out; - DEBUG("Selected image %d for update", image); - + /* Short circuit a successful return if no commands were specified. + * Avoids problems with trying to allocate 0 bytes of memory. */ if (num_cmds == 0) goto out; DEBUG("Preparing %zu update commands", num_cmds); + /* Make a copy of the update commands, in the process doing certain + * canonicalizations on paths (e.g. translating backslashes to forward + * slashes). This is done to avoid modifying the caller's copy of the + * commands. */ ret = copy_update_commands(cmds, num_cmds, &cmds_copy); if (ret) goto out; + /* Perform additional checks on the update commands before we execute + * them. */ ret = check_update_commands(cmds_copy, num_cmds, &wim->hdr); if (ret) goto out_free_cmds_copy; + /* Actually execute the update commands. */ DEBUG("Executing %zu update commands", num_cmds); - ret = execute_update_commands(wim, cmds_copy, num_cmds, progress_func); if (ret) goto out_free_cmds_copy; + + /* Statistics about the WIM image, such as the numbers of files and + * directories, may have changed. Call xml_update_image_info() to + * recalculate these statistics. */ xml_update_image_info(wim, wim->current_image); out_free_cmds_copy: free_update_commands(cmds_copy, num_cmds); diff --git a/src/wimlib.h b/src/wimlib.h index a50c0ede..a433a9bc 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -2526,7 +2526,28 @@ wimlib_unmount_image(const wimlib_tchar *dir, int unmount_flags, wimlib_progress_func_t progress_func); -/** XXX */ +/** + * Update a WIM image by adding, deleting, and/or renaming files or directories. + * + * @param wim + * Pointer to the ::WIMStruct for the WIM file to update. + * @param image + * The 1-based index of the image in the WIM to update. It cannot be + * ::WIMLIB_ALL_IMAGES. + * @param cmds + * An array of ::wimlib_update_command's that specify the update operations + * to perform. + * @param num_cmds + * Number of commands in @a cmds. + * @param update_flags + * Reserved; must be 0. + * @param progress_func + * If non-NULL, a function that will be called periodically with the + * progress of the current operation. + * + * @return 0 on success; nonzero on error. There are many possible error codes + * (TODO: document them.) + */ extern int wimlib_update_image(WIMStruct *wim, int image, diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index c0da1ab9..55fcd8f3 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -463,7 +463,8 @@ extern struct wimlib_capture_config * copy_capture_config(const struct wimlib_capture_config *config); extern int -canonicalize_capture_config(struct wimlib_capture_config *config); +copy_and_canonicalize_capture_config(const struct wimlib_capture_config *config, + struct wimlib_capture_config **config_copy_ret); extern void free_capture_config(struct wimlib_capture_config *config); -- 2.43.0