/* * Load the metadata for the specified WIM image into memory and set it * as the WIMStruct's currently selected image. * * @wim * The WIMStruct for the WIM. * @image * The 1-based index of the image in the WIM to select. * * On success, 0 will be returned, wim->current_image will be set to * @image, and wim_get_current_image_metadata() can be used to retrieve * metadata information for the image. * * On failure, WIMLIB_ERR_INVALID_IMAGE, WIMLIB_ERR_METADATA_NOT_FOUND, * or another error code will be returned. */ int select_wim_image(WIMStruct *wim, int image) { struct wim_image_metadata *imd; int ret; if (image == WIMLIB_NO_IMAGE) return WIMLIB_ERR_INVALID_IMAGE; if (image == wim->current_image) return 0; if (image < 1 || image > wim->hdr.image_count) return WIMLIB_ERR_INVALID_IMAGE; if (!wim_has_metadata(wim)) return WIMLIB_ERR_METADATA_NOT_FOUND; /* If a valid image is currently selected, its metadata can be freed if * it has not been modified. */ deselect_current_wim_image(wim); wim->current_image = image; imd = wim_get_current_image_metadata(wim); if (imd->root_dentry || imd->modified) { ret = 0; } else { ret = read_metadata_resource(imd); if (ret) wim->current_image = WIMLIB_NO_IMAGE; } return ret; }
void deselect_current_wim_image(WIMStruct *wim) { struct wim_image_metadata *imd; if (wim->current_image == WIMLIB_NO_IMAGE) return; imd = wim_get_current_image_metadata(wim); if (!imd->modified) { wimlib_assert(list_empty(&imd->unhashed_blobs)); destroy_image_metadata(imd, NULL, false); } wim->current_image = WIMLIB_NO_IMAGE; }
/* 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 execute_add_command(struct update_command_journal *j, WIMStruct *wim, const struct wimlib_update_command *add_cmd, struct wim_inode_table *inode_table, struct wim_sd_set *sd_set, struct list_head *unhashed_streams) { int ret; int add_flags; tchar *fs_source_path; tchar *wim_target_path; const tchar *config_file; struct capture_params params; struct capture_config config; capture_tree_t capture_tree = platform_default_capture_tree; #ifdef WITH_NTFS_3G struct _ntfs_volume *ntfs_vol = NULL; #endif void *extra_arg = NULL; struct wim_dentry *branch; add_flags = add_cmd->add.add_flags; fs_source_path = add_cmd->add.fs_source_path; wim_target_path = add_cmd->add.wim_target_path; config_file = add_cmd->add.config_file; DEBUG("fs_source_path=\"%"TS"\", wim_target_path=\"%"TS"\", add_flags=%#x", fs_source_path, wim_target_path, add_flags); memset(¶ms, 0, sizeof(params)); #ifdef WITH_NTFS_3G if (add_flags & WIMLIB_ADD_FLAG_NTFS) { capture_tree = build_dentry_tree_ntfs; extra_arg = &ntfs_vol; if (wim_get_current_image_metadata(wim)->ntfs_vol != NULL) { ERROR("NTFS volume already set"); ret = WIMLIB_ERR_INVALID_PARAM; goto out; } } #endif ret = get_capture_config(config_file, &config, add_flags, fs_source_path); if (ret) goto out; params.lookup_table = wim->lookup_table; params.unhashed_streams = unhashed_streams; params.inode_table = inode_table; params.sd_set = sd_set; params.config = &config; params.add_flags = add_flags; params.extra_arg = extra_arg; params.progfunc = wim->progfunc; params.progctx = wim->progctx; params.progress.scan.source = fs_source_path; params.progress.scan.wim_target_path = wim_target_path; ret = call_progress(params.progfunc, WIMLIB_PROGRESS_MSG_SCAN_BEGIN, ¶ms.progress, params.progctx); if (ret) goto out_destroy_config; if (WIMLIB_IS_WIM_ROOT_PATH(wim_target_path)) params.add_flags |= WIMLIB_ADD_FLAG_ROOT; ret = (*capture_tree)(&branch, fs_source_path, ¶ms); if (ret) goto out_destroy_config; ret = call_progress(params.progfunc, WIMLIB_PROGRESS_MSG_SCAN_END, ¶ms.progress, params.progctx); if (ret) { free_dentry_tree(branch, wim->lookup_table); goto out_cleanup_after_capture; } if (WIMLIB_IS_WIM_ROOT_PATH(wim_target_path) && branch && !dentry_is_directory(branch)) { ERROR("\"%"TS"\" is not a directory!", fs_source_path); ret = WIMLIB_ERR_NOTDIR; free_dentry_tree(branch, wim->lookup_table); goto out_cleanup_after_capture; } ret = attach_branch(branch, wim_target_path, j, add_flags, params.progfunc, params.progctx); if (ret) goto out_cleanup_after_capture; if (config_file && (add_flags & WIMLIB_ADD_FLAG_WIMBOOT) && WIMLIB_IS_WIM_ROOT_PATH(wim_target_path)) { params.add_flags = 0; params.progfunc = NULL; params.config = NULL; /* If a capture configuration file was explicitly specified when * capturing an image in WIMBoot mode, save it as * /Windows/System32/WimBootCompress.ini in the WIM image. */ ret = platform_default_capture_tree(&branch, config_file, ¶ms); if (ret) goto out_cleanup_after_capture; ret = attach_branch(branch, wimboot_cfgfile, j, 0, NULL, NULL); if (ret) goto out_cleanup_after_capture; } #ifdef WITH_NTFS_3G wim_get_current_image_metadata(wim)->ntfs_vol = ntfs_vol; #endif ret = 0; goto out_destroy_config; out_cleanup_after_capture: #ifdef WITH_NTFS_3G if (ntfs_vol) do_ntfs_umount(ntfs_vol); #endif out_destroy_config: destroy_capture_config(&config); out: return ret; }
static int execute_update_commands(WIMStruct *wim, const struct wimlib_update_command *cmds, size_t num_cmds, int update_flags) { struct wim_inode_table *inode_table; struct wim_sd_set *sd_set; struct list_head unhashed_streams; struct update_command_journal *j; union wimlib_progress_info info; int ret; if (have_command_type(cmds, num_cmds, WIMLIB_UPDATE_OP_ADD)) { /* If we have at least one "add" command, create the inode and * security descriptor tables to index new inodes and new * security descriptors, respectively. */ inode_table = alloca(sizeof(struct wim_inode_table)); sd_set = alloca(sizeof(struct wim_sd_set)); ret = init_inode_table(inode_table, 9001); if (ret) goto out; ret = init_sd_set(sd_set, wim_get_current_security_data(wim)); if (ret) goto out_destroy_inode_table; INIT_LIST_HEAD(&unhashed_streams); } else { inode_table = NULL; sd_set = NULL; } /* Start an in-memory journal to allow rollback if something goes wrong */ j = new_update_command_journal(num_cmds, &wim_get_current_image_metadata(wim)->root_dentry, wim->lookup_table); if (!j) { ret = WIMLIB_ERR_NOMEM; goto out_destroy_sd_set; } info.update.completed_commands = 0; info.update.total_commands = num_cmds; ret = 0; for (size_t i = 0; i < num_cmds; i++) { DEBUG("Executing update command %zu of %zu (op=%"TS")", i + 1, num_cmds, update_op_to_str(cmds[i].op)); info.update.command = &cmds[i]; if (update_flags & WIMLIB_UPDATE_FLAG_SEND_PROGRESS) { ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_UPDATE_BEGIN_COMMAND, &info, wim->progctx); if (ret) goto rollback; } switch (cmds[i].op) { case WIMLIB_UPDATE_OP_ADD: ret = execute_add_command(j, wim, &cmds[i], inode_table, sd_set, &unhashed_streams); break; case WIMLIB_UPDATE_OP_DELETE: ret = execute_delete_command(j, wim, &cmds[i]); break; case WIMLIB_UPDATE_OP_RENAME: ret = execute_rename_command(j, wim, &cmds[i]); break; } if (unlikely(ret)) goto rollback; info.update.completed_commands++; if (update_flags & WIMLIB_UPDATE_FLAG_SEND_PROGRESS) { ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_UPDATE_END_COMMAND, &info, wim->progctx); if (ret) goto rollback; } next_command(j); } commit_update(j); if (inode_table) { struct wim_image_metadata *imd; imd = wim_get_current_image_metadata(wim); list_splice_tail(&unhashed_streams, &imd->unhashed_streams); inode_table_prepare_inode_list(inode_table, &imd->inode_list); } goto out_destroy_sd_set; rollback: if (sd_set) rollback_new_security_descriptors(sd_set); rollback_update(j); out_destroy_sd_set: if (sd_set) destroy_sd_set(sd_set); out_destroy_inode_table: if (inode_table) destroy_inode_table(inode_table); out: return ret; }
/* 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++; }