Exemple #1
0
/*
 * 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;
}
Exemple #2
0
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;
}
Exemple #3
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;

	}
Exemple #4
0
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(&params, 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,
			    &params.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, &params);
	if (ret)
		goto out_destroy_config;

	ret = call_progress(params.progfunc, WIMLIB_PROGRESS_MSG_SCAN_END,
			    &params.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, &params);
		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;
}
Exemple #5
0
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++;
	}