Example #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;
}
Example #2
0
/*
 * Determine if a file should be excluded from capture.
 *
 * This function tests exclusions from both of the two possible sources of
 * exclusions:
 *
 *	(1) The capture configuration file
 *	(2) The user-provided progress function
 *
 * The capture implementation must have set params->capture_root_nchars to an
 * appropriate value.  Example for UNIX:  if the capture root directory is
 * "foobar/subdir", then all paths will be provided starting with
 * "foobar/subdir", so params->capture_root_nchars must be set to
 * strlen("foobar/subdir") so that try_exclude() can use the appropriate suffix
 * when it calls should_exclude_path().
 *
 *
 * Returns:
 *	< 0 if excluded
 *	= 0 if not excluded and no error
 *	> 0 (wimlib error code) if error
 */
int
try_exclude(const tchar *full_path, size_t full_path_nchars,
	    const struct capture_params *params)
{
	int ret;

	if (should_exclude_path(full_path + params->capture_root_nchars,
				full_path_nchars - params->capture_root_nchars,
				params->config))
		return -1;

	if (unlikely(params->add_flags & WIMLIB_ADD_FLAG_TEST_FILE_EXCLUSION)) {
		union wimlib_progress_info info;

		info.test_file_exclusion.path = full_path;
		info.test_file_exclusion.will_exclude = false;

	#ifdef __WIN32__
		/* Hack for Windows...  */

		wchar_t *p_question_mark = NULL;

		if (!wcsncmp(full_path, L"\\??\\", 4)) {
			/* Trivial transformation:  NT namespace => Win32 namespace  */
			p_question_mark = (wchar_t *)&full_path[1];
			*p_question_mark = L'\\';
		}
	#endif

		ret = call_progress(params->progfunc, WIMLIB_PROGRESS_MSG_TEST_FILE_EXCLUSION,
				    &info, params->progctx);

	#ifdef __WIN32__
		if (p_question_mark)
			*p_question_mark = L'?';
	#endif

		if (ret)
			return ret;
		if (info.test_file_exclusion.will_exclude)
			return -1;
	}

	return 0;
}
Example #3
0
static int
end_verify_stream(struct wim_lookup_table_entry *lte, int status, void *_ctx)
{
	struct verify_stream_list_ctx *ctx = _ctx;
	union wimlib_progress_info *progress = ctx->progress;

	if (status)
		return status;

	progress->verify_streams.completed_streams++;
	progress->verify_streams.completed_bytes += lte->size;

	/* Handle rate-limiting of progress messages  */

	if (progress->verify_streams.completed_bytes < ctx->next_progress)
		return 0;

	/* Time for another progress message.  */

	status = call_progress(ctx->progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
			       progress, ctx->progctx);
	if (status)
		return status;

	if (ctx->next_progress == progress->verify_streams.total_bytes) {
		ctx->next_progress = ~(uint64_t)0;
		return 0;
	}

	/* Send new message as soon as another 1/128 of the total has
	 * been verified.  (Arbitrary number.)  */
	ctx->next_progress = progress->verify_streams.completed_bytes +
			     progress->verify_streams.total_bytes / 128;

	/* ... Unless that would be more than 5000000 bytes, in which case send
	 * the next after the next 5000000 bytes. (Another arbitrary number.) */
	if (progress->verify_streams.completed_bytes + 5000000 < ctx->next_progress)
		ctx->next_progress = progress->verify_streams.completed_bytes + 5000000;

	/* ... But always send a message as soon as we're completely
	 * done.  */
	if (progress->verify_streams.total_bytes < ctx->next_progress)
		ctx->next_progress = progress->verify_streams.total_bytes;
	return 0;
}
Example #4
0
/*
 * Tally a file (or directory) that has been scanned for a capture operation,
 * and possibly call the progress function provided by the library user.
 *
 * @params
 *	Flags, optional progress function, and progress data for the capture
 *	operation.
 * @status
 *	Status of the scanned file.
 * @inode
 *	If @status is WIMLIB_SCAN_DENTRY_OK, this is a pointer to the WIM inode
 *	that has been created for the scanned file.  The first time the file is
 *	seen, inode->i_nlink will be 1.  On subsequent visits of the same inode
 *	via additional hard links, inode->i_nlink will be greater than 1.
 */
int
do_capture_progress(struct capture_params *params, int status,
		    const struct wim_inode *inode)
{
	switch (status) {
	case WIMLIB_SCAN_DENTRY_OK:
		if (!(params->add_flags & WIMLIB_ADD_FLAG_VERBOSE))
			return 0;
		break;
	case WIMLIB_SCAN_DENTRY_UNSUPPORTED:
	case WIMLIB_SCAN_DENTRY_EXCLUDED:
	case WIMLIB_SCAN_DENTRY_FIXED_SYMLINK:
	case WIMLIB_SCAN_DENTRY_NOT_FIXED_SYMLINK:
		if (!(params->add_flags & WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE))
			return 0;
		break;
	}
	params->progress.scan.status = status;
	if (status == WIMLIB_SCAN_DENTRY_OK && inode->i_nlink == 1) {

		/* Successful scan, and visiting inode for the first time  */

		/* Tally size of all data streams.  */
		const struct wim_lookup_table_entry *lte;
		for (unsigned i = 0; i <= inode->i_num_ads; i++) {
			lte = inode_stream_lte_resolved(inode, i);
			if (lte)
				params->progress.scan.num_bytes_scanned += lte->size;
		}

		/* Tally the file itself.  */
		if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
			params->progress.scan.num_dirs_scanned++;
		else
			params->progress.scan.num_nondirs_scanned++;
	}

	/* Call the user-provided progress function.  */
	return call_progress(params->progfunc, WIMLIB_PROGRESS_MSG_SCAN_DENTRY,
			     &params->progress, params->progctx);
}
Example #5
0
static int
write_split_wim(WIMStruct *orig_wim, const tchar *swm_name,
		struct swm_info *swm_info, int write_flags)
{
	size_t swm_name_len;
	tchar *swm_name_buf;
	const tchar *dot;
	tchar *swm_suffix;
	size_t swm_base_name_len;

	union wimlib_progress_info progress;
	unsigned part_number;
	int ret;
	u8 guid[GUID_SIZE];

	swm_name_len = tstrlen(swm_name);
	swm_name_buf = alloca((swm_name_len + 20) * sizeof(tchar));
	tstrcpy(swm_name_buf, swm_name);
	dot = tstrchr(swm_name_buf, T('.'));
	if (dot) {
		swm_base_name_len = dot - swm_name_buf;
		swm_suffix = alloca((tstrlen(dot) + 1) * sizeof(tchar));
		tstrcpy(swm_suffix, dot);
	} else {
		swm_base_name_len = swm_name_len;
		swm_suffix = alloca(1 * sizeof(tchar));
		swm_suffix[0] = T('\0');
	}

	progress.split.completed_bytes = 0;
	progress.split.total_bytes = 0;
	for (part_number = 1; part_number <= swm_info->num_parts; part_number++)
		progress.split.total_bytes += swm_info->parts[part_number - 1].size;
	progress.split.total_parts = swm_info->num_parts;

	generate_guid(guid);

	for (part_number = 1; part_number <= swm_info->num_parts; part_number++) {
		int part_write_flags;
		wimlib_progress_func_t progfunc;

		if (part_number != 1) {
			tsprintf(swm_name_buf + swm_base_name_len,
				 T("%u%"TS), part_number, swm_suffix);
		}

		progress.split.cur_part_number = part_number;
		progress.split.part_name = swm_name_buf;

		ret = call_progress(orig_wim->progfunc,
				    WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
				    &progress,
				    orig_wim->progctx);
		if (ret)
			return ret;

		part_write_flags = write_flags;
		part_write_flags |= WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES;
		if (part_number != 1)
			part_write_flags |= WIMLIB_WRITE_FLAG_NO_METADATA;

		progfunc = orig_wim->progfunc;
		orig_wim->progfunc = NULL;
		ret = write_wim_part(orig_wim,
				     progress.split.part_name,
				     WIMLIB_ALL_IMAGES,
				     part_write_flags,
				     1,
				     part_number,
				     swm_info->num_parts,
				     &swm_info->parts[part_number - 1].blob_list,
				     guid);
		orig_wim->progfunc = progfunc;
		if (ret)
			return ret;

		progress.split.completed_bytes += swm_info->parts[part_number - 1].size;

		ret = call_progress(orig_wim->progfunc,
				    WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
				    &progress,
				    orig_wim->progctx);
		if (ret)
			return ret;
	}
	return 0;
}
Example #6
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 #7
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);
	}
}
Example #8
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;
}
Example #9
0
static void call_event_handler(struct call *call, enum call_event ev,
			       const char *str, void *arg)
{
	struct ua *ua = arg;
	const char *peeruri;
	struct call *call2 = NULL;
	int err;

	MAGIC_CHECK(ua);

	peeruri = call_peeruri(call);

	/* stop any ringtones */
	ua->play = mem_deref(ua->play);

	switch (ev) {

	case CALL_EVENT_INCOMING:

		if (contact_block_access(peeruri)) {

			info("ua: blocked access: \"%s\"\n", peeruri);

			ua_event(ua, UA_EVENT_CALL_CLOSED, call, str);
			mem_deref(call);
			break;
		}

		switch (ua->acc->answermode) {

		case ANSWERMODE_EARLY:
			(void)call_progress(call);
			break;

		case ANSWERMODE_AUTO:
			(void)call_answer(call, 200);
			break;

		case ANSWERMODE_MANUAL:
		default:
			if (list_count(&ua->calls) > 1) {
				(void)play_file(&ua->play,
						    "callwaiting.wav", 3);
			}
			else {
				/* Alert user */
				(void)play_file(&ua->play, "ring.wav", -1);
			}

			ua_event(ua, UA_EVENT_CALL_INCOMING, call, peeruri);
			break;
		}
		break;

	case CALL_EVENT_RINGING:
		(void)play_file(&ua->play, "ringback.wav", -1);

		ua_event(ua, UA_EVENT_CALL_RINGING, call, peeruri);
		break;

	case CALL_EVENT_PROGRESS:
		ua_printf(ua, "Call in-progress: %s\n", peeruri);
		ua_event(ua, UA_EVENT_CALL_PROGRESS, call, peeruri);
		break;

	case CALL_EVENT_ESTABLISHED:
		ua_printf(ua, "Call established: %s\n", peeruri);
		ua_event(ua, UA_EVENT_CALL_ESTABLISHED, call, peeruri);
		break;

	case CALL_EVENT_CLOSED:
		if (call_scode(call)) {
			const char *tone;
			tone = translate_errorcode(call_scode(call));
			if (tone)
				(void)play_file(&ua->play, tone, 1);
		}
		ua_event(ua, UA_EVENT_CALL_CLOSED, call, str);
		mem_deref(call);
		break;

	case CALL_EVENT_TRANSFER:

		/*
		 * Create a new call to transfer target.
		 *
		 * NOTE: we will automatically connect a new call to the
		 *       transfer target
		 */

		ua_printf(ua, "transferring call to %s\n", str);

		err = ua_call_alloc(&call2, ua, VIDMODE_ON, NULL, call,
				    call_localuri(call));
		if (!err) {
			struct pl pl;

			pl_set_str(&pl, str);

			err = call_connect(call2, &pl);
			if (err) {
				warning("ua: transfer: connect error: %m\n",
					err);
			}
		}

		if (err) {
			(void)call_notify_sipfrag(call, 500, "Call Error");
			mem_deref(call2);
		}
		break;

	case CALL_EVENT_TRANSFER_FAILED:
		ua_event(ua, UA_EVENT_CALL_TRANSFER_FAILED, call, str);
		break;
	}
}
Example #10
0
/*
 * calculate_integrity_table():
 *
 * Calculates an integrity table for the data in a file beginning at offset 208
 * (WIM_HEADER_DISK_SIZE).
 *
 * @in_fd:
 *	File descriptor for the file to be checked, opened for reading.  Does
 *	not need to be at any specific location in the file.
 *
 * @new_check_end:
 *	Offset of byte after the last byte to be checked.
 *
 * @old_table:
 *	If non-NULL, a pointer to the table containing the previously calculated
 *	integrity data for a prefix of this file.
 *
 * @old_check_end:
 *	If @old_table is non-NULL, the byte after the last byte that was checked
 *	in the old table.  Must be less than or equal to new_check_end.
 *
 * @integrity_table_ret:
 *	On success, a pointer to the calculated integrity table is written into
 *	this location.
 *
 * Return values:
 *	WIMLIB_ERR_SUCCESS (0)
 *	WIMLIB_ERR_NOMEM
 *	WIMLIB_ERR_READ
 *	WIMLIB_ERR_UNEXPECTED_END_OF_FILE
 */
static int
calculate_integrity_table(struct filedes *in_fd,
			  off_t new_check_end,
			  const struct integrity_table *old_table,
			  off_t old_check_end,
			  struct integrity_table **integrity_table_ret,
			  wimlib_progress_func_t progfunc,
			  void *progctx)
{
	int ret;
	size_t chunk_size = INTEGRITY_CHUNK_SIZE;

	/* If an old table is provided, set the chunk size to be compatible with
	 * the old chunk size, unless the old chunk size was weird. */
	if (old_table != NULL) {
		if (old_table->num_entries == 0 ||
		    old_table->chunk_size < INTEGRITY_MIN_CHUNK_SIZE ||
		    old_table->chunk_size > INTEGRITY_MAX_CHUNK_SIZE)
			old_table = NULL;
		else
			chunk_size = old_table->chunk_size;
	}


	u64 old_check_bytes = old_check_end - WIM_HEADER_DISK_SIZE;
	u64 new_check_bytes = new_check_end - WIM_HEADER_DISK_SIZE;

	u32 old_num_chunks = DIV_ROUND_UP(old_check_bytes, chunk_size);
	u32 new_num_chunks = DIV_ROUND_UP(new_check_bytes, chunk_size);

	size_t old_last_chunk_size = MODULO_NONZERO(old_check_bytes, chunk_size);
	size_t new_last_chunk_size = MODULO_NONZERO(new_check_bytes, chunk_size);

	size_t new_table_size = 12 + new_num_chunks * SHA1_HASH_SIZE;

	struct integrity_table *new_table = MALLOC(new_table_size);
	if (!new_table)
		return WIMLIB_ERR_NOMEM;
	new_table->num_entries = new_num_chunks;
	new_table->size = new_table_size;
	new_table->chunk_size = chunk_size;

	u64 offset = WIM_HEADER_DISK_SIZE;
	union wimlib_progress_info progress;

	progress.integrity.total_bytes      = new_check_bytes;
	progress.integrity.total_chunks     = new_num_chunks;
	progress.integrity.completed_chunks = 0;
	progress.integrity.completed_bytes  = 0;
	progress.integrity.chunk_size       = chunk_size;
	progress.integrity.filename         = NULL;

	ret = call_progress(progfunc, WIMLIB_PROGRESS_MSG_CALC_INTEGRITY,
			    &progress, progctx);
	if (ret)
		goto out_free_new_table;

	for (u32 i = 0; i < new_num_chunks; i++) {
		size_t this_chunk_size;
		if (i == new_num_chunks - 1)
			this_chunk_size = new_last_chunk_size;
		else
			this_chunk_size = chunk_size;
		if (old_table &&
		    ((this_chunk_size == chunk_size && i < old_num_chunks - 1) ||
		      (i == old_num_chunks - 1 && this_chunk_size == old_last_chunk_size)))
		{
			/* Can use SHA1 message digest from old integrity table
			 * */
			copy_hash(new_table->sha1sums[i], old_table->sha1sums[i]);
		} else {
			/* Calculate the SHA1 message digest of this chunk */
			ret = calculate_chunk_sha1(in_fd, this_chunk_size,
						   offset, new_table->sha1sums[i]);
			if (ret)
				goto out_free_new_table;
		}
		offset += this_chunk_size;

		progress.integrity.completed_chunks++;
		progress.integrity.completed_bytes += this_chunk_size;
		ret = call_progress(progfunc, WIMLIB_PROGRESS_MSG_CALC_INTEGRITY,
				    &progress, progctx);
		if (ret)
			goto out_free_new_table;
	}
	*integrity_table_ret = new_table;
	return 0;

out_free_new_table:
	FREE(new_table);
	return ret;
}