/* * 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; }
/* * 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; }
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; }
/* * 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, ¶ms->progress, params->progctx); }
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; }
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(¶ms, 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, ¶ms.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, ¶ms); if (ret) goto out_destroy_config; ret = call_progress(params.progfunc, WIMLIB_PROGRESS_MSG_SCAN_END, ¶ms.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, ¶ms); 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; }
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); } }
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; }
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; } }
/* * 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; }