示例#1
0
/*
 * verify_integrity():
 *
 * Checks a WIM for consistency with the integrity table.
 *
 * @in_fd:
 *	File descriptor to the WIM file, opened for reading.
 *
 * @table:
 *	The integrity table for the WIM, read into memory.
 *
 * @bytes_to_check:
 *	Number of bytes in the WIM that need to be checked (offset of end of the
 *	lookup table minus offset of end of the header).
 *
 * Returns:
 *	> 0 (WIMLIB_ERR_READ, WIMLIB_ERR_UNEXPECTED_END_OF_FILE) on error
 *	0 (WIM_INTEGRITY_OK) if the integrity was checked successfully and there
 *	were no inconsistencies.
 *	-1 (WIM_INTEGRITY_NOT_OK) if the WIM failed the integrity check.
 */
static int
verify_integrity(struct filedes *in_fd, const tchar *filename,
		 const struct integrity_table *table,
		 u64 bytes_to_check,
		 wimlib_progress_func_t progfunc, void *progctx)
{
	int ret;
	u64 offset = WIM_HEADER_DISK_SIZE;
	u8 sha1_md[SHA1_HASH_SIZE];
	union wimlib_progress_info progress;

	progress.integrity.total_bytes      = bytes_to_check;
	progress.integrity.total_chunks     = table->num_entries;
	progress.integrity.completed_chunks = 0;
	progress.integrity.completed_bytes  = 0;
	progress.integrity.chunk_size       = table->chunk_size;
	progress.integrity.filename         = filename;

	ret = call_progress(progfunc, WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY,
			    &progress, progctx);
	if (ret)
		return ret;

	for (u32 i = 0; i < table->num_entries; i++) {
		size_t this_chunk_size;
		if (i == table->num_entries - 1)
			this_chunk_size = MODULO_NONZERO(bytes_to_check,
							 table->chunk_size);
		else
			this_chunk_size = table->chunk_size;

		ret = calculate_chunk_sha1(in_fd, this_chunk_size, offset, sha1_md);
		if (ret)
			return ret;

		if (!hashes_equal(sha1_md, table->sha1sums[i]))
			return WIM_INTEGRITY_NOT_OK;

		offset += this_chunk_size;
		progress.integrity.completed_chunks++;
		progress.integrity.completed_bytes += this_chunk_size;

		ret = call_progress(progfunc, WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY,
				    &progress, progctx);
		if (ret)
			return ret;
	}
	return WIM_INTEGRITY_OK;
}
/*
 * 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;
}