WIM update fixes
authorEric Biggers <ebiggers3@gmail.com>
Sun, 12 May 2013 01:32:12 +0000 (20:32 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 12 May 2013 01:32:12 +0000 (20:32 -0500)
programs/imagex.c
src/capture_common.c
src/update_image.c
src/wimlib.h
src/wimlib_internal.h

index 4d0c2ff..407967f 100644 (file)
@@ -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;
index ef4fa5d..431a468 100644 (file)
 #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], &copy->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(&copy->exclusion_pats, &config->exclusion_pats))
-               goto oom;
-       if (!copy_pattern_list(&copy->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
index 49ac602..9658392 100644 (file)
@@ -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);
index a50c0ed..a433a9b 100644 (file)
@@ -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,
index c0da1ab..55fcd8f 100644 (file)
@@ -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);