Example #1
0
/*
 * Place the directory entry tree @branch at the path @target_tstr in the WIM
 * image.
 *
 * @target_tstr cannot contain trailing slashes, and all path separators must be
 * WIM_PATH_SEPARATOR.
 *
 * On success, @branch is committed to the journal @j.
 * Otherwise @branch is freed.
 *
 * The relevant @add_flags are WIMLIB_ADD_FLAG_NO_REPLACE and
 * WIMLIB_ADD_FLAG_VERBOSE.
 */
static int
attach_branch(struct wim_dentry *branch, const tchar *target_tstr,
	      struct update_command_journal *j, int add_flags,
	      wimlib_progress_func_t progfunc, void *progctx)
{
	int ret;
	const utf16lechar *target;

	ret = 0;
	if (unlikely(!branch))
		goto out;

	ret = tstr_get_utf16le(target_tstr, &target);
	if (ret)
		goto out_free_branch;

	BUILD_BUG_ON(WIM_PATH_SEPARATOR != OS_PREFERRED_PATH_SEPARATOR);
	ret = dentry_set_name(branch, path_basename(target_tstr));
	if (ret)
		goto out_free_target;

	ret = do_attach_branch(branch, target, j, add_flags, progfunc, progctx);
	if (ret)
		goto out_free_target;
	/* branch was successfully committed to the journal  */
	branch = NULL;
out_free_target:
	tstr_put_utf16le(target);
out_free_branch:
	free_dentry_tree(branch, j->lookup_table);
out:
	return ret;
}
Example #2
0
/* Don't call this directly; use commit_update() or rollback_update() instead.
 */
static void
free_update_command_journal(struct update_command_journal *j)
{
	struct wim_dentry *orphan;

	/* Free orphaned dentry trees  */
	while (!list_empty(&j->orphans)) {
		orphan = list_first_entry(&j->orphans,
					  struct wim_dentry, tmp_list);
		list_del(&orphan->tmp_list);
		free_dentry_tree(orphan, j->lookup_table);
	}

	for (size_t i = 0; i < j->num_cmds; i++)
		if (j->cmd_prims[i].entries != j->cmd_prims[i].inline_entries)
			FREE(j->cmd_prims[i].entries);
	FREE(j);
}
Example #3
0
File: wim.c Project: twwbond/wimlib
static void
destroy_image_metadata(struct wim_image_metadata *imd,
                       struct blob_table *table,
                       bool free_metadata_blob_descriptor)
{
    free_dentry_tree(imd->root_dentry, table);
    imd->root_dentry = NULL;
    free_wim_security_data(imd->security_data);
    imd->security_data = NULL;

    if (free_metadata_blob_descriptor) {
        free_blob_descriptor(imd->metadata_blob);
        imd->metadata_blob = NULL;
    }
    if (!table) {
        struct blob_descriptor *blob, *tmp;
        list_for_each_entry_safe(blob, tmp, &imd->unhashed_blobs, unhashed_list)
        free_blob_descriptor(blob);
    }
    INIT_LIST_HEAD(&imd->unhashed_blobs);
    INIT_HLIST_HEAD(&imd->inode_list);
}
Example #4
0
/* Rename a file or directory in the WIM.
 *
 * This returns a -errno value.
 *
 * The journal @j is optional.
 */
int
rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to,
		CASE_SENSITIVITY_TYPE case_type,
		struct update_command_journal *j)
{
	struct wim_dentry *src;
	struct wim_dentry *dst;
	struct wim_dentry *parent_of_dst;
	int ret;

	/* This rename() implementation currently only supports actual files
	 * (not alternate data streams) */

	src = get_dentry(wim, from, case_type);
	if (!src)
		return -errno;

	dst = get_dentry(wim, to, case_type);

	if (dst) {
		/* Destination file exists */

		if (src == dst) /* Same file */
			return 0;

		if (!dentry_is_directory(src)) {
			/* Cannot rename non-directory to directory. */
			if (dentry_is_directory(dst))
				return -EISDIR;
		} else {
			/* Cannot rename directory to a non-directory or a non-empty
			 * directory */
			if (!dentry_is_directory(dst))
				return -ENOTDIR;
			if (dentry_has_children(dst))
				return -ENOTEMPTY;
		}
		parent_of_dst = dst->d_parent;
	} else {
		/* Destination does not exist */
		parent_of_dst = get_parent_dentry(wim, to, case_type);
		if (!parent_of_dst)
			return -errno;

		if (!dentry_is_directory(parent_of_dst))
			return -ENOTDIR;
	}

	/* @src can't be an ancestor of @dst.  Otherwise we're unlinking @src
	 * from the tree and creating a loop...  */
	if (is_ancestor(src, parent_of_dst))
		return -EBUSY;

	if (j) {
		if (dst)
			if (journaled_unlink(j, dst))
				return -ENOMEM;
		if (journaled_unlink(j, src))
			return -ENOMEM;
		if (journaled_change_name(j, src, path_basename(to)))
			return -ENOMEM;
		if (journaled_link(j, src, parent_of_dst))
			return -ENOMEM;
	} else {
		ret = dentry_set_name(src, path_basename(to));
		if (ret)
			return -ENOMEM;
		if (dst) {
			unlink_dentry(dst);
			free_dentry_tree(dst, wim->lookup_table);
		}
		unlink_dentry(src);
		dentry_add_child(parent_of_dst, src);
	}
	if (src->_full_path)
		for_dentry_in_tree(src, free_dentry_full_path, NULL);
	return 0;
}
Example #5
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;
}
Example #6
0
static int
handle_conflict(struct wim_dentry *branch, struct wim_dentry *existing,
		struct update_command_journal *j,
		int add_flags,
		wimlib_progress_func_t progfunc, void *progctx)
{
	bool branch_is_dir = dentry_is_directory(branch);
	bool existing_is_dir = dentry_is_directory(existing);

	if (branch_is_dir != existing_is_dir) {
		if (existing_is_dir)  {
			ERROR("\"%"TS"\" is a directory!\n"
			      "        Specify the path at which "
			      "to place the file inside this directory.",
			      dentry_full_path(existing));
			return WIMLIB_ERR_IS_DIRECTORY;
		} else {
			ERROR("Can't place directory at \"%"TS"\" because "
			      "a nondirectory file already exists there!",
			      dentry_full_path(existing));
			return WIMLIB_ERR_NOTDIR;
		}
	}

	if (branch_is_dir) {
		/* Directory overlay  */
		while (dentry_has_children(branch)) {
			struct wim_dentry *new_child;
			struct wim_dentry *existing_child;
			int ret;

			new_child = dentry_any_child(branch);

			existing_child =
				get_dentry_child_with_utf16le_name(existing,
								   new_child->file_name,
								   new_child->file_name_nbytes,
								   WIMLIB_CASE_PLATFORM_DEFAULT);
			unlink_dentry(new_child);
			if (existing_child) {
				ret = handle_conflict(new_child, existing_child,
						      j, add_flags,
						      progfunc, progctx);
			} else {
				ret = journaled_link(j, new_child, existing);
			}
			if (ret) {
				dentry_add_child(branch, new_child);
				return ret;
			}
		}
		free_dentry_tree(branch, j->lookup_table);
		return 0;
	} else if (add_flags & WIMLIB_ADD_FLAG_NO_REPLACE) {
		/* Can't replace nondirectory file  */
		ERROR("Refusing to overwrite nondirectory file \"%"TS"\"",
		      dentry_full_path(existing));
		return WIMLIB_ERR_INVALID_OVERLAY;
	} else {
		/* Replace nondirectory file  */
		struct wim_dentry *parent;
		int ret;

		parent = existing->d_parent;

		ret = calculate_dentry_full_path(existing);
		if (ret)
			return ret;

		if (add_flags & WIMLIB_ADD_FLAG_VERBOSE) {
			union wimlib_progress_info info;

			info.replace.path_in_wim = existing->_full_path;
			ret = call_progress(progfunc,
					    WIMLIB_PROGRESS_MSG_REPLACE_FILE_IN_WIM,
					    &info, progctx);
			if (ret)
				return ret;
		}

		ret = journaled_unlink(j, existing);
		if (ret)
			return ret;

		return journaled_link(j, branch, parent);
	}
}
/*
 * Reads and parses a metadata resource for an image in the WIM file.
 *
 * @imd:
 *	Pointer to the image metadata structure for the image whose metadata
 *	resource we are reading.  Its `metadata_blob' member specifies the blob
 *	table entry for the metadata resource.  The rest of the image metadata
 *	entry will be filled in by this function.
 *
 * Return values:
 *	WIMLIB_ERR_SUCCESS (0)
 *	WIMLIB_ERR_INVALID_METADATA_RESOURCE
 *	WIMLIB_ERR_NOMEM
 *	WIMLIB_ERR_READ
 *	WIMLIB_ERR_UNEXPECTED_END_OF_FILE
 *	WIMLIB_ERR_DECOMPRESSION
 */
int
read_metadata_resource(struct wim_image_metadata *imd)
{
	const struct blob_descriptor *metadata_blob;
	void *buf;
	int ret;
	u8 hash[SHA1_HASH_SIZE];
	struct wim_security_data *sd;
	struct wim_dentry *root;

	metadata_blob = imd->metadata_blob;

	/* Read the metadata resource into memory.  (It may be compressed.)  */
	ret = read_blob_into_alloc_buf(metadata_blob, &buf);
	if (ret)
		return ret;

	/* Checksum the metadata resource.  */
	sha1_buffer(buf, metadata_blob->size, hash);
	if (!hashes_equal(metadata_blob->hash, hash)) {
		ERROR("Metadata resource is corrupted "
		      "(invalid SHA-1 message digest)!");
		ret = WIMLIB_ERR_INVALID_METADATA_RESOURCE;
		goto out_free_buf;
	}

	/* Parse the metadata resource.
	 *
	 * Notes: The metadata resource consists of the security data, followed
	 * by the directory entry for the root directory, followed by all the
	 * other directory entries in the filesystem.  The subdir offset field
	 * of each directory entry gives the start of its child entries from the
	 * beginning of the metadata resource.  An end-of-directory is signaled
	 * by a directory entry of length '0', really of length 8, because
	 * that's how long the 'length' field is.  */

	ret = read_wim_security_data(buf, metadata_blob->size, &sd);
	if (ret)
		goto out_free_buf;

	ret = read_dentry_tree(buf, metadata_blob->size, sd->total_length, &root);
	if (ret)
		goto out_free_security_data;

	/* We have everything we need from the buffer now.  */
	FREE(buf);
	buf = NULL;

	/* Calculate and validate inodes.  */

	ret = dentry_tree_fix_inodes(root, &imd->inode_list);
	if (ret)
		goto out_free_dentry_tree;

	fix_security_ids(imd, sd->num_entries);

	/* Success; fill in the image_metadata structure.  */
	imd->root_dentry = root;
	imd->security_data = sd;
	INIT_LIST_HEAD(&imd->unhashed_blobs);
	return 0;

out_free_dentry_tree:
	free_dentry_tree(root, NULL);
out_free_security_data:
	free_wim_security_data(sd);
out_free_buf:
	FREE(buf);
	return ret;
}