Esempio n. 1
0
File: wim.c Progetto: twwbond/wimlib
/*
 * 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;
}
Esempio n. 2
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;
}
Esempio n. 3
0
/* 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;
}
Esempio n. 4
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;

	}
Esempio n. 5
0
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;
}
Esempio n. 6
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++;
	}