X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fexport_image.c;h=784938e9c5b34d52670e83b7aa93336e42f412ee;hp=9b9304ceed04369426a13a3624729cc72cfc5d12;hb=062465170ddb4520ca6fbc64a0f6e27e786de101;hpb=40beb80283a2df7af88c8359ca41adb814585e9a diff --git a/src/export_image.c b/src/export_image.c index 9b9304ce..784938e9 100644 --- a/src/export_image.c +++ b/src/export_image.c @@ -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. * @@ -26,34 +26,23 @@ #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) +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) @@ -65,78 +54,58 @@ static int allocate_lte_if_needed(struct dentry *dentry, void *arg) 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)); - - 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)); + struct wim_lookup_table_entry *src_lte, *dest_lte; + unsigned i; - 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, + staging_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_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 +137,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 +149,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 +162,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) + if (ret) return ret; src_wim_tab_save = src_wim->lookup_table; src_wim->lookup_table = joined_tab; } 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,53 +205,54 @@ 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(<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++; /* 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)); - - 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); + * 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) + dest_wim->hdr.boot_idx = dest_wim->hdr.image_count; 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, staging_list) free_lookup_table_entry(lte); } - out: if (num_additional_swms) { free_lookup_table(src_wim->lookup_table); @@ -290,57 +260,3 @@ out: } 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; - } - return ret; -}