*/
/*
- * 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;
+ struct wim_lookup_table_entry *src_lte, *dest_lte;
+ unsigned i;
- wimlib_assert(!inode->resolved);
-
- 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);
+ struct wim_lookup_table_entry *src_lte, *dest_lte;
+ unsigned i;
- 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));
-
- 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 "
"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)
additional_swms,
num_additional_swms,
progress_func);
- if (ret != 0)
+ if (ret)
return ret;
}
return 0;
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;
}
/* 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(<e_list_head);
+ image_for_each_inode(inode, src_imd) {
+ ret = inode_allocate_needed_ltes(inode,
+ src_wim->lookup_table,
+ dest_wim->lookup_table,
+ <e_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,
+ <e_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, <e_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;
- }
- return ret;
-}
-
-static int image_run_full_verifications(WIMStruct *w)
-{
- return for_dentry_in_tree(wim_root_dentry(w), verify_dentry, w);
-}
-
-static int lte_fix_refcnt(struct lookup_table_entry *lte, void *ctr)
-{
- if (lte->refcnt != lte->real_refcnt) {
- WARNING("The following lookup table entry has a reference "
- "count of %u, but", lte->refcnt);
- WARNING("We found %u references to it",
- lte->real_refcnt);
- print_lookup_table_entry(lte);
- lte->refcnt = lte->real_refcnt;
- ++*(unsigned long *)ctr;
- }
- return 0;
-}
-
-/* Ideally this would be unnecessary... however, the WIMs for Windows 8 are
- * screwed up because some lookup table entries are referenced more times than
- * their stated reference counts. So theoretically, if we delete all the
- * references to a stream and then remove it, it might still be referenced
- * somewhere else, making a file be missing from the WIM... So, work around this
- * problem by looking at ALL the images to re-calculate the reference count of
- * EVERY lookup table entry. This only absolutely has to be done before an image
- * is deleted or before an image is mounted read-write. */
-int wim_run_full_verifications(WIMStruct *w)
-{
- int ret;
-
- for_lookup_table_entry(w->lookup_table, lte_zero_real_refcnt, NULL);
- w->all_images_verified = true;
- w->full_verification_in_progress = true;
- ret = for_image(w, WIMLIB_ALL_IMAGES, image_run_full_verifications);
- w->full_verification_in_progress = false;
- if (ret == 0) {
- unsigned long num_ltes_with_bogus_refcnt = 0;
- for (int i = 0; i < w->hdr.image_count; i++)
- w->image_metadata[i].metadata_lte->real_refcnt++;
- for_lookup_table_entry(w->lookup_table, lte_fix_refcnt,
- &num_ltes_with_bogus_refcnt);
- if (num_ltes_with_bogus_refcnt != 0) {
- WARNING("A total of %lu entries in the WIM's stream "
- "lookup table had to have\n"
- " their reference counts fixed.",
- num_ltes_with_bogus_refcnt);
- }
- } else {
- w->all_images_verified = false;
- }
+ if (num_additional_swms)
+ unmerge_lookup_table(src_wim);
return ret;
}