/* * Calls a function on images in the WIM. If @image is WIMLIB_ALL_IMAGES, * @visitor is called on the WIM once for each image, with each image selected * as the current image in turn. If @image is a certain image, @visitor is * called on the WIM only once, with that image selected. */ int for_image(WIMStruct *wim, int image, int (*visitor)(WIMStruct *)) { int ret; int start; int end; int i; if (image == WIMLIB_ALL_IMAGES) { start = 1; end = wim->hdr.image_count; } else if (image >= 1 && image <= wim->hdr.image_count) { start = image; end = image; } else { return WIMLIB_ERR_INVALID_IMAGE; } for (i = start; i <= end; i++) { ret = select_wim_image(wim, i); if (ret != 0) return ret; ret = visitor(wim); if (ret != 0) return ret; } return 0; }
/* API function documented in wimlib.h */ WIMLIBAPI int wimlib_update_image(WIMStruct *wim, int image, const struct wimlib_update_command *cmds, size_t num_cmds, int update_flags) { int ret; struct wimlib_update_command *cmds_copy; if (update_flags & ~WIMLIB_UPDATE_FLAG_SEND_PROGRESS) return WIMLIB_ERR_INVALID_PARAM; DEBUG("Updating image %d with %zu commands", image, num_cmds); /* Load the metadata for the image to modify (if not loaded already) */ ret = select_wim_image(wim, image); if (ret) 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, update_flags); if (ret) goto out_free_cmds_copy; wim->image_metadata[image - 1]->modified = 1; /* 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, image); for (size_t i = 0; i < num_cmds; i++) if (cmds_copy[i].op == WIMLIB_UPDATE_OP_ADD && cmds_copy[i].add.add_flags & WIMLIB_ADD_FLAG_RPFIX) wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX; out_free_cmds_copy: free_update_commands(cmds_copy, num_cmds); out: return ret; }
/* Internal method for single-image deletion. This doesn't set the * image_deletion_occurred' flag on the WIMStruct. */ int delete_wim_image(WIMStruct *wim, int image) { int ret; /* Load the metadata for the image to be deleted. This is necessary * because streams referenced by files in the image need to have their * reference counts decremented. */ ret = select_wim_image(wim, image); if (ret) return ret; /* Release the reference to the image metadata and decrement reference * counts on the streams referenced by files in the image. */ put_image_metadata(wim->image_metadata[image - 1], wim->lookup_table); /* Remove the empty slot from the image metadata array. */ memmove(&wim->image_metadata[image - 1], &wim->image_metadata[image], (wim->hdr.image_count - image) * sizeof(wim->image_metadata[0])); /* Decrement the image count. */ --wim->hdr.image_count; /* Remove the image from the XML information. */ xml_delete_image(&wim->wim_info, image); /* Fix the boot index. */ if (wim->hdr.boot_idx == image) wim->hdr.boot_idx = 0; else if (wim->hdr.boot_idx > image) wim->hdr.boot_idx--; /* The image is no longer valid. */ wim->current_image = WIMLIB_NO_IMAGE; return 0; }
/* API function documented in wimlib.h */ 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) { int ret; int start_src_image; int end_src_image; int orig_dest_image_count; int image; bool all_images = (src_image == WIMLIB_ALL_IMAGES); /* Check for sane parameters. */ if (export_flags & ~(WIMLIB_EXPORT_FLAG_BOOT | WIMLIB_EXPORT_FLAG_NO_NAMES | WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS | WIMLIB_EXPORT_FLAG_GIFT | WIMLIB_EXPORT_FLAG_WIMBOOT)) return WIMLIB_ERR_INVALID_PARAM; if (src_wim == NULL || dest_wim == NULL) return WIMLIB_ERR_INVALID_PARAM; if (!wim_has_metadata(src_wim) || !wim_has_metadata(dest_wim)) return WIMLIB_ERR_METADATA_NOT_FOUND; if (all_images) { /* Multi-image export. */ if ((!(export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) && dest_name) || (!(export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) && dest_description)) { ERROR("Image name and description must be " "left NULL for multi-image export"); return WIMLIB_ERR_INVALID_PARAM; } start_src_image = 1; end_src_image = src_wim->hdr.image_count; } else { start_src_image = src_image; end_src_image = src_image; } orig_dest_image_count = dest_wim->hdr.image_count; /* Stream checksums must be known before proceeding. */ ret = wim_checksum_unhashed_streams(src_wim); if (ret) return ret; ret = wim_checksum_unhashed_streams(dest_wim); if (ret) return ret; /* Enable rollbacks */ for_lookup_table_entry(dest_wim->lookup_table, lte_set_not_exported, NULL); /* Export each requested image. */ for (src_image = start_src_image; src_image <= end_src_image; src_image++) { const tchar *next_dest_name, *next_dest_description; struct wim_image_metadata *src_imd; struct wim_inode *inode; /* Determine destination image name and description. */ if (export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) next_dest_name = T(""); else if (dest_name) next_dest_name = dest_name; else next_dest_name = wimlib_get_image_name(src_wim, src_image); if (export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) next_dest_description = T(""); else if (dest_description) next_dest_description = dest_description; else next_dest_description = wimlib_get_image_description(src_wim, src_image); /* Check for name conflict. */ if (wimlib_image_name_in_use(dest_wim, next_dest_name)) { ERROR("There is already an image named \"%"TS"\" " "in the destination WIM", next_dest_name); ret = WIMLIB_ERR_IMAGE_NAME_COLLISION; goto out_rollback; } /* Load metadata for source image into memory. */ ret = select_wim_image(src_wim, src_image); if (ret) goto out_rollback; src_imd = wim_get_current_image_metadata(src_wim); /* Iterate through inodes in the source image and export their * streams into the destination WIM. */ image_for_each_inode(inode, src_imd) { ret = inode_export_streams(inode, src_wim->lookup_table, dest_wim->lookup_table, export_flags & WIMLIB_EXPORT_FLAG_GIFT); if (ret) goto out_rollback; } /* Export XML information into the destination WIM. */ ret = xml_export_image(src_wim->wim_info, src_image, &dest_wim->wim_info, next_dest_name, next_dest_description); if (ret) goto out_rollback; /* Reference the source image metadata from the destination WIM. */ ret = append_image_metadata(dest_wim, src_imd); if (ret) goto out_rollback; src_imd->refcnt++; /* Lock the metadata into memory. XXX: need better solution for * this. */ src_imd->modified = 1; }
static int prepare_metadata_resource(WIMStruct *wim, int image, u8 **buf_ret, size_t *len_ret) { u8 *buf; u8 *p; int ret; u64 subdir_offset; struct wim_dentry *root; size_t len; struct wim_security_data *sd; struct wim_image_metadata *imd; ret = select_wim_image(wim, image); if (ret) return ret; imd = wim->image_metadata[image - 1]; root = imd->root_dentry; sd = imd->security_data; if (!root) { /* Empty image; create a dummy root. */ ret = new_filler_directory(&root); if (ret) return ret; imd->root_dentry = root; } /* The offset of the first child of the root dentry is equal to the * total length of the security data, plus the total length of the root * dentry, plus 8 bytes for an end-of-directory entry following the root * dentry (shouldn't really be needed, but just in case...) */ recalculate_security_data_length(sd); subdir_offset = sd->total_length + dentry_out_total_length(root) + 8; /* Calculate the subdirectory offsets for the entire dentry tree. */ calculate_subdir_offsets(root, &subdir_offset); /* Total length of the metadata resource (uncompressed). */ len = subdir_offset; /* Allocate a buffer to contain the uncompressed metadata resource. */ buf = NULL; if (likely(len == subdir_offset)) buf = MALLOC(len); if (!buf) { ERROR("Failed to allocate %"PRIu64" bytes for " "metadata resource", subdir_offset); return WIMLIB_ERR_NOMEM; } /* Write the security data into the resource buffer. */ p = write_wim_security_data(sd, buf); /* Write the dentry tree into the resource buffer. */ p = write_dentry_tree(root, p); /* We MUST have exactly filled the buffer; otherwise we calculated its * size incorrectly or wrote the data incorrectly. */ wimlib_assert(p - buf == len); *buf_ret = buf; *len_ret = len; return 0; }
/* API function documented in wimlib.h */ 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) { int ret; int start_src_image; int end_src_image; int orig_dest_image_count; int image; bool all_images = (src_image == WIMLIB_ALL_IMAGES); /* Check for sane parameters. */ if (export_flags & ~(WIMLIB_EXPORT_FLAG_BOOT | WIMLIB_EXPORT_FLAG_NO_NAMES | WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS | WIMLIB_EXPORT_FLAG_GIFT | WIMLIB_EXPORT_FLAG_WIMBOOT)) return WIMLIB_ERR_INVALID_PARAM; if (!src_wim || !dest_wim) return WIMLIB_ERR_INVALID_PARAM; if (!wim_has_metadata(src_wim) || !wim_has_metadata(dest_wim)) return WIMLIB_ERR_METADATA_NOT_FOUND; if (all_images) { /* Multi-image export. */ if ((!(export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) && dest_name) || (!(export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) && dest_description)) { ERROR("Image name and description must be " "left NULL for multi-image export"); return WIMLIB_ERR_INVALID_PARAM; } start_src_image = 1; end_src_image = src_wim->hdr.image_count; } else { start_src_image = src_image; end_src_image = src_image; } orig_dest_image_count = dest_wim->hdr.image_count; /* We don't yet support having a single WIMStruct contain duplicate * 'image_metadata' structures, so we must forbid this from happening. * A duplication is possible if 'src_wim == dest_wim', if the same image * is exported to the same destination WIMStruct multiple times, or if * an image is exported in an A => B => A manner. */ for (src_image = start_src_image; src_image <= end_src_image; src_image++) { const struct wim_image_metadata *src_imd = src_wim->image_metadata[src_image - 1]; for (int i = 0; i < dest_wim->hdr.image_count; i++) if (dest_wim->image_metadata[i] == src_imd) return WIMLIB_ERR_DUPLICATE_EXPORTED_IMAGE; } /* Blob checksums must be known before proceeding. */ ret = wim_checksum_unhashed_blobs(src_wim); if (ret) return ret; ret = wim_checksum_unhashed_blobs(dest_wim); if (ret) return ret; /* Enable rollbacks */ for_blob_in_table(dest_wim->blob_table, blob_set_not_exported, NULL); /* Export each requested image. */ for (src_image = start_src_image; src_image <= end_src_image; src_image++) { const tchar *next_dest_name, *next_dest_description; struct wim_image_metadata *src_imd; struct wim_inode *inode; /* Determine destination image name and description. */ if (export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) next_dest_name = NULL; else if (dest_name) next_dest_name = dest_name; else next_dest_name = wimlib_get_image_name(src_wim, src_image); if (export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) next_dest_description = NULL; else if (dest_description) next_dest_description = dest_description; else next_dest_description = wimlib_get_image_description(src_wim, src_image); /* Check for name conflict. */ if (wimlib_image_name_in_use(dest_wim, next_dest_name)) { ERROR("There is already an image named \"%"TS"\" " "in the destination WIM", next_dest_name); ret = WIMLIB_ERR_IMAGE_NAME_COLLISION; goto out_rollback; } /* Load metadata for source image into memory. */ ret = select_wim_image(src_wim, src_image); if (ret) goto out_rollback; src_imd = wim_get_current_image_metadata(src_wim); /* Iterate through inodes in the source image and export their * blobs into the destination WIM. */ image_for_each_inode(inode, src_imd) { ret = inode_export_blobs(inode, src_wim->blob_table, dest_wim->blob_table, export_flags & WIMLIB_EXPORT_FLAG_GIFT); if (ret) goto out_rollback; } /* Export XML information into the destination WIM. */ ret = xml_export_image(src_wim->xml_info, src_image, dest_wim->xml_info, next_dest_name, next_dest_description, export_flags & WIMLIB_EXPORT_FLAG_WIMBOOT); if (ret) goto out_rollback; /* Reference the source image metadata from the destination WIM. */ ret = append_image_metadata(dest_wim, src_imd); if (ret) goto out_rollback; src_imd->refcnt++; }