]> wimlib.net Git - wimlib/blobdiff - src/export_image.c
Refactor headers
[wimlib] / src / export_image.c
index a01928012bb1c92494eb74a70081408a481564cc..455baa9152bbd2050b4d98f118667013c86138e8 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (C) 2012 Eric Biggers
+ * Copyright (C) 2012, 2013 Eric Biggers
  *
  * This file is part of wimlib, a library for working with WIM files.
  *
  * along with wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
-#include "wimlib_internal.h"
-#include "dentry.h"
-#include "lookup_table.h"
-#include "xml.h"
-
-struct wim_pair {
-       WIMStruct *src_wim;
-       WIMStruct *dest_wim;
-       struct list_head lte_list_head;
-};
-
-static int allocate_lte_if_needed(struct dentry *dentry, void *arg)
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "wimlib.h"
+#include "wimlib/dentry.h"
+#include "wimlib/error.h"
+#include "wimlib/lookup_table.h"
+#include "wimlib/metadata.h"
+#include "wimlib/swm.h"
+#include "wimlib/xml.h"
+
+static int
+inode_allocate_needed_ltes(struct wim_inode *inode,
+                          struct wim_lookup_table *src_lookup_table,
+                          struct wim_lookup_table *dest_lookup_table,
+                          struct list_head *lte_list_head)
 {
-       const WIMStruct *src_wim, *dest_wim;
-       struct list_head *lte_list_head;
-       struct inode *inode;
-
-       src_wim = ((struct wim_pair*)arg)->src_wim;
-       dest_wim = ((struct wim_pair*)arg)->dest_wim;
-       lte_list_head = &((struct wim_pair*)arg)->lte_list_head;
-       inode = dentry->d_inode;
-
-       wimlib_assert(!inode->resolved);
+       struct wim_lookup_table_entry *src_lte, *dest_lte;
+       unsigned i;
 
-       for (unsigned i = 0; i <= inode->num_ads; i++) {
-               struct lookup_table_entry *src_lte, *dest_lte;
+       inode_unresolve_ltes(inode);
+       for (i = 0; i <= inode->i_num_ads; i++) {
                src_lte = inode_stream_lte_unresolved(inode, i,
-                                                     src_wim->lookup_table);
-
-               if (src_lte && ++src_lte->out_refcnt == 1) {
+                                                     src_lookup_table);
+               if (src_lte && src_lte->out_refcnt == 0) {
+                       src_lte->out_refcnt = 1;
                        dest_lte = inode_stream_lte_unresolved(inode, i,
-                                                              dest_wim->lookup_table);
-
+                                                              dest_lookup_table);
                        if (!dest_lte) {
                                dest_lte = clone_lookup_table_entry(src_lte);
                                if (!dest_lte)
                                        return WIMLIB_ERR_NOMEM;
-                               list_add_tail(&dest_lte->staging_list, lte_list_head);
+                               list_add_tail(&dest_lte->export_stream_list,
+                                             lte_list_head);
                        }
                }
        }
        return 0;
 }
 
-/*
- * This function takes in a dentry that was previously located only in image(s)
- * in @src_wim, but now is being added to @dest_wim.  For each stream associated
- * with the dentry, if there is already a lookup table entry for that stream in
- * the lookup table of the destination WIM file, its reference count is
- * incrementej.  Otherwise, a new lookup table entry is created that points back
- * to the stream in the source WIM file (through the @hash field combined with
- * the @wim field of the lookup table entry.)
- */
-static int add_lte_to_dest_wim(struct dentry *dentry, void *arg)
+static void
+inode_move_ltes_to_table(struct wim_inode *inode,
+                        struct wim_lookup_table *src_lookup_table,
+                        struct wim_lookup_table *dest_lookup_table,
+                        struct list_head *lte_list_head)
 {
-       WIMStruct *src_wim, *dest_wim;
-       struct inode *inode;
-
-       src_wim = ((struct wim_pair*)arg)->src_wim;
-       dest_wim = ((struct wim_pair*)arg)->dest_wim;
-       inode = dentry->d_inode;
-
-       wimlib_assert(!inode->resolved);
-
-       for (unsigned i = 0; i <= inode->num_ads; i++) {
-               struct lookup_table_entry *src_lte, *dest_lte;
-               src_lte = inode_stream_lte_unresolved(inode, i,
-                                                     src_wim->lookup_table);
-
-               if (!src_lte) /* Empty or nonexistent stream. */
-                       continue;
-
-               dest_lte = inode_stream_lte_unresolved(inode, i,
-                                                      dest_wim->lookup_table);
-               if (dest_lte) {
-                       dest_lte->refcnt++;
-               } else {
-                       struct list_head *lte_list_head;
-                       struct list_head *next;
-
-                       lte_list_head = &((struct wim_pair*)arg)->lte_list_head;
-                       wimlib_assert(!list_empty(lte_list_head));
+       struct wim_lookup_table_entry *src_lte, *dest_lte;
+       unsigned i;
 
-                       next = lte_list_head->next;
-                       list_del(next);
-                       dest_lte = container_of(next, struct lookup_table_entry,
-                                               staging_list);
-                       dest_lte->part_number = 1;
-                       dest_lte->refcnt = 1;
-                       wimlib_assert(hashes_equal(dest_lte->hash, src_lte->hash));
-
-                       lookup_table_insert(dest_wim->lookup_table, dest_lte);
+       for (i = 0; i <= inode->i_num_ads; i++) {
+               src_lte = inode_stream_lte_unresolved(inode, i, src_lookup_table);
+               if (src_lte) {
+                       dest_lte = inode_stream_lte_unresolved(inode, i,
+                                                              dest_lookup_table);
+                       if (!dest_lte) {
+                               struct list_head *next;
+
+                               wimlib_assert(!list_empty(lte_list_head));
+                               next = lte_list_head->next;
+                               list_del(next);
+                               dest_lte = container_of(next,
+                                                       struct wim_lookup_table_entry,
+                                                       export_stream_list);
+                               dest_lte->part_number = 1;
+                               dest_lte->refcnt = 0;
+                               wimlib_assert(hashes_equal(dest_lte->hash, src_lte->hash));
+                               lookup_table_insert(dest_lookup_table, dest_lte);
+                       }
+                       dest_lte->refcnt += inode->i_nlink;
                }
        }
-       return 0;
 }
 
 /*
- * Copies an image, or all the images, from a WIM file, into another WIM file.
+ * Exports an image, or all the images, from a WIM file, into another WIM file.
  */
-WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
-                                 int src_image,
-                                 WIMStruct *dest_wim,
-                                 const char *dest_name,
-                                 const char *dest_description,
-                                 int export_flags,
-                                 WIMStruct **additional_swms,
-                                 unsigned num_additional_swms,
-                                 wimlib_progress_func_t progress_func)
+WIMLIBAPI int
+wimlib_export_image(WIMStruct *src_wim,
+                   int src_image,
+                   WIMStruct *dest_wim,
+                   const tchar *dest_name,
+                   const tchar *dest_description,
+                   int export_flags,
+                   WIMStruct **additional_swms,
+                   unsigned num_additional_swms,
+                   wimlib_progress_func_t progress_func)
 {
-       int i;
        int ret;
-       struct dentry *root;
-       struct wim_pair wims;
-       struct wim_security_data *sd;
-       struct lookup_table *joined_tab, *src_wim_tab_save;
+       struct wim_image_metadata *src_imd;
+       struct list_head lte_list_head;
+       struct wim_inode *inode;
 
        if (dest_wim->hdr.total_parts != 1) {
                ERROR("Exporting an image to a split WIM is "
@@ -168,7 +144,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                      "multiple images");
                                return WIMLIB_ERR_INVALID_PARAM;
                        }
-                       for (i = 1; i <= src_wim->hdr.image_count; i++) {
+                       for (int i = 1; i <= src_wim->hdr.image_count; i++) {
                                int new_flags = export_flags;
 
                                if (i != src_wim->hdr.boot_idx)
@@ -180,7 +156,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                                          additional_swms,
                                                          num_additional_swms,
                                                          progress_func);
-                               if (ret != 0)
+                               if (ret)
                                        return ret;
                        }
                        return 0;
@@ -193,42 +169,42 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
 
        if (!dest_name) {
                dest_name = wimlib_get_image_name(src_wim, src_image);
-               DEBUG("Using name `%s' for source image %d",
+               DEBUG("Using name `%"TS"' for source image %d",
                      dest_name, src_image);
        }
 
        if (!dest_description) {
                dest_description = wimlib_get_image_description(src_wim,
                                                                src_image);
-               DEBUG("Using description `%s' for source image %d",
+               DEBUG("Using description `%"TS"' for source image %d",
                      dest_description, src_image);
        }
 
-       DEBUG("Exporting image %d from `%s'", src_image, src_wim->filename);
+       DEBUG("Exporting image %d from `%"TS"'", src_image, src_wim->filename);
 
        if (wimlib_image_name_in_use(dest_wim, dest_name)) {
-               ERROR("There is already an image named `%s' in the "
+               ERROR("There is already an image named `%"TS"' in the "
                      "destination WIM", dest_name);
                return WIMLIB_ERR_IMAGE_NAME_COLLISION;
        }
 
        ret = verify_swm_set(src_wim, additional_swms, num_additional_swms);
-       if (ret != 0)
+       if (ret)
                return ret;
 
-       if (num_additional_swms) {
-               ret = new_joined_lookup_table(src_wim, additional_swms,
-                                             num_additional_swms,
-                                             &joined_tab);
-               if (ret != 0)
-                       return ret;
-               src_wim_tab_save = src_wim->lookup_table;
-               src_wim->lookup_table = joined_tab;
-       }
+       ret = wim_checksum_unhashed_streams(src_wim);
+       if (ret)
+               return ret;
+       ret = wim_checksum_unhashed_streams(dest_wim);
+       if (ret)
+               return ret;
+
+       if (num_additional_swms)
+               merge_lookup_tables(src_wim, additional_swms, num_additional_swms);
 
        ret = select_wim_image(src_wim, src_image);
-       if (ret != 0) {
-               ERROR("Could not select image %d from the WIM `%s' "
+       if (ret) {
+               ERROR("Could not select image %d from the WIM `%"TS"' "
                      "to export it", src_image, src_wim->filename);
                goto out;
        }
@@ -236,57 +212,63 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        /* Pre-allocate the new lookup table entries that will be needed.  This
         * way, it's not possible to run out of memory part-way through
         * modifying the lookup table of the destination WIM. */
-       wims.src_wim = src_wim;
-       wims.dest_wim = dest_wim;
-       INIT_LIST_HEAD(&wims.lte_list_head);
        for_lookup_table_entry(src_wim->lookup_table, lte_zero_out_refcnt, NULL);
-       root = wim_root_dentry(src_wim);
-       for_dentry_in_tree(root, dentry_unresolve_ltes, NULL);
-       ret = for_dentry_in_tree(root, allocate_lte_if_needed, &wims);
-       if (ret != 0)
-               goto out_free_ltes;
+       src_imd = wim_get_current_image_metadata(src_wim);
+       INIT_LIST_HEAD(&lte_list_head);
+       image_for_each_inode(inode, src_imd) {
+               ret = inode_allocate_needed_ltes(inode,
+                                                src_wim->lookup_table,
+                                                dest_wim->lookup_table,
+                                                &lte_list_head);
+               if (ret)
+                       goto out_free_ltes;
+       }
 
        ret = xml_export_image(src_wim->wim_info, src_image,
-                              &dest_wim->wim_info, dest_name, dest_description);
-       if (ret != 0)
+                              &dest_wim->wim_info, dest_name,
+                              dest_description);
+       if (ret)
                goto out_free_ltes;
 
-       sd = wim_security_data(src_wim);
-       ret = add_new_dentry_tree(dest_wim, root, sd);
-       if (ret != 0)
+       ret = append_image_metadata(dest_wim, src_imd);
+       if (ret)
                goto out_xml_delete_image;
 
+       /* The `struct image_metadata' is now referenced by both the @src_wim
+        * and the @dest_wim. */
+       src_imd->refcnt++;
+       src_imd->modified = 1;
 
        /* All memory allocations have been taken care of, so it's no longer
-        * possible for this function to fail.  Go ahead and increment the
-        * reference counts of the dentry tree and security data, then update
-        * the lookup table of the destination WIM and the boot index, if
-        * needed. */
-       for_dentry_in_tree(root, increment_dentry_refcnt, NULL);
-       sd->refcnt++;
-       for_dentry_in_tree(root, add_lte_to_dest_wim, &wims);
-       wimlib_assert(list_empty(&wims.lte_list_head));
+        * possible for this function to fail.  Go ahead and update the lookup
+        * table of the destination WIM and the boot index, if needed. */
+       image_for_each_inode(inode, src_imd) {
+               inode_move_ltes_to_table(inode,
+                                        src_wim->lookup_table,
+                                        dest_wim->lookup_table,
+                                        &lte_list_head);
+       }
 
-       if (export_flags & WIMLIB_EXPORT_FLAG_BOOT) {
-               DEBUG("Setting boot_idx to %d", dest_wim->hdr.image_count);
-               wimlib_set_boot_idx(dest_wim, dest_wim->hdr.image_count);
+       if (export_flags & WIMLIB_EXPORT_FLAG_BOOT)
+               dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
+       if (src_wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
+       {
+               /* Set the reparse point fixup flag on the destination WIM if
+                * the flag is set on the source WIM. */
+               dest_wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
        }
        ret = 0;
        goto out;
-
 out_xml_delete_image:
-       xml_delete_image(&dest_wim->wim_info, dest_wim->hdr.image_count);
+       xml_delete_image(&dest_wim->wim_info, dest_wim->hdr.image_count + 1);
 out_free_ltes:
        {
-               struct lookup_table_entry *lte, *tmp;
-               list_for_each_entry_safe(lte, tmp, &wims.lte_list_head, staging_list)
+               struct wim_lookup_table_entry *lte, *tmp;
+               list_for_each_entry_safe(lte, tmp, &lte_list_head, export_stream_list)
                        free_lookup_table_entry(lte);
        }
-
 out:
-       if (num_additional_swms) {
-               free_lookup_table(src_wim->lookup_table);
-               src_wim->lookup_table = src_wim_tab_save;
-       }
+       if (num_additional_swms)
+               unmerge_lookup_table(src_wim);
        return ret;
 }