X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fintegrity.c;h=0054c40219a381f954a36bd08c31becb3d924394;hp=12968bf91004a0b2e54d6b59c677c5e8c5f261c2;hb=21da2526eff64cdb8e3cb509d34af182d764c701;hpb=21a83b1b20f5ae138bc4bb9bdedd80a2a2d92c0a;ds=inline diff --git a/src/integrity.c b/src/integrity.c index 12968bf9..0054c402 100644 --- a/src/integrity.c +++ b/src/integrity.c @@ -1,353 +1,454 @@ /* * integrity.c * - * WIM files can optionally contain an array of SHA1 message digests at the end, - * one digest for each 1 MB of the file. This file implements the checking of - * the digests, and the writing of the digests for new WIM files. + * WIM files can optionally contain a table of SHA1 message digests at the end, + * one digest for each chunk of the file of some specified size (often 10 MB). + * This file implements the checking and writing of this table. */ /* - * Copyright (C) 2012 Eric Biggers + * Copyright (C) 2012, 2013 Eric Biggers * - * This file is part of wimlib, a library for working with WIM files. + * This file is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. * - * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License - * along with wimlib; if not, see http://www.gnu.org/licenses/. + * along with this file; if not, see http://www.gnu.org/licenses/. */ -#include "wimlib_internal.h" -#include "io.h" -#include "sha1.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wimlib/assert.h" +#include "wimlib/endianness.h" +#include "wimlib/error.h" +#include "wimlib/file_io.h" +#include "wimlib/integrity.h" +#include "wimlib/progress.h" +#include "wimlib/resource.h" +#include "wimlib/sha1.h" +#include "wimlib/wim.h" +#include "wimlib/write.h" /* Size, in bytes, of each SHA1-summed chunk, when wimlib writes integrity * information. */ #define INTEGRITY_CHUNK_SIZE 10485760 -/* - * Verifies the integrity of a WIM. - * - * @fp: FILE* of the WIM, currently positioned at the end of the header. - * @num_bytes: Number of bytes to verify the integrity of. - * @chunk_size: Chunk size per SHA1 message digest. - * @sha1sums: Array of SHA1 message digests; 20 bytes each, one per chunk. - * @show_progress: Nonzero if the percent complete is to be printed after every - * chunk. - * @status: On success, set to WIM_INTEGRITY_OK or WIM_INTEGRITY_NOT_OK - * based on whether the WIM is intact or not. - */ -static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size, - const u8 *sha1sums, int show_progress, - int *status) +/* Only use a different chunk size for compatibility with an existing integrity + * table if the chunk size is between these two numbers. */ +#define INTEGRITY_MIN_CHUNK_SIZE 4096 +#define INTEGRITY_MAX_CHUNK_SIZE 134217728 + +struct integrity_table { + u32 size; + u32 num_entries; + u32 chunk_size; + u8 sha1sums[][20]; +} _packed_attribute; + +static int +calculate_chunk_sha1(struct filedes *in_fd, size_t this_chunk_size, + off_t offset, u8 sha1_md[]) { - char *chunk_buf; - u8 resblock[SHA1_HASH_SIZE]; - u64 bytes_remaining; + u8 buf[BUFFER_SIZE]; + SHA_CTX ctx; + size_t bytes_remaining; size_t bytes_to_read; - uint percent_done; - int ret; + int ret; - chunk_buf = MALLOC(chunk_size); - if (!chunk_buf) { - ERROR("Failed to allocate %u byte buffer for integrity chunks", - chunk_size); - return WIMLIB_ERR_NOMEM; - } - bytes_remaining = num_bytes; - while (bytes_remaining != 0) { - if (show_progress) { - percent_done = (num_bytes - bytes_remaining) * 100 / - num_bytes; - printf("Verifying integrity of WIM (%"PRIu64" bytes " - "remaining, %u%% done) \r", - bytes_remaining, percent_done); - fflush(stdout); - } - bytes_to_read = min(chunk_size, bytes_remaining); - if (fread(chunk_buf, 1, bytes_to_read, fp) != bytes_to_read) { - if (feof(fp)) { - ERROR("Unexpected EOF while verifying " - "integrity of WIM"); - } else { - ERROR_WITH_ERRNO("File stream error while " - "verifying integrity of WIM"); - } - ret = WIMLIB_ERR_READ; - goto verify_integrity_error; + bytes_remaining = this_chunk_size; + sha1_init(&ctx); + do { + bytes_to_read = min(bytes_remaining, sizeof(buf)); + ret = full_pread(in_fd, buf, bytes_to_read, offset); + if (ret) { + ERROR_WITH_ERRNO("Read error while calculating " + "integrity checksums"); + return ret; } - sha1_buffer(chunk_buf, bytes_to_read, resblock); - if (!hashes_equal(resblock, sha1sums)) { - *status = WIM_INTEGRITY_NOT_OK; - goto verify_integrity_done; - } - sha1sums += SHA1_HASH_SIZE; + sha1_update(&ctx, buf, bytes_to_read); bytes_remaining -= bytes_to_read; - } - *status = WIM_INTEGRITY_OK; -verify_integrity_done: - ret = 0; -verify_integrity_error: - FREE(chunk_buf); - if (show_progress) - putchar('\n'); - return ret; + offset += bytes_to_read; + } while (bytes_remaining); + sha1_final(sha1_md, &ctx); + return 0; } + /* - * Verifies the integrity of the WIM. + * read_integrity_table: - Reads the integrity table from a WIM file. + * + * @wim: + * WIMStruct for the WIM file; @wim->hdr.integrity_table_reshdr specifies + * the location of the integrity table. @wim->in_fd is expected to be a + * seekable file descriptor to the WIM file opened for reading. + * + * @num_checked_bytes: + * Number of bytes of data that should be checked by the integrity table. * - * @show_progress: Nonzero if the percent complete is to be printed after every - * chunk. - * @status: On success, set to WIM_INTEGRITY_OK, WIM_INTEGRITY_NOT_OK, - * or WIM_INTEGRITY_NONEXISTENT. + * @table_ret: + * On success, a pointer to an in-memory structure containing the integrity + * information is written to this location. * - * Returns: 0, WIMLIB_ERR_INVALID_INTEGRITY_TABLE, WIMLIB_ERR_NOMEM, or - * WIMLIB_ERR_READ. If nonzero, the boolean pointed to by @ok is not changed. + * Return values: + * WIMLIB_ERR_SUCCESS (0) + * WIMLIB_ERR_INVALID_INTEGRITY_TABLE + * WIMLIB_ERR_NOMEM + * WIMLIB_ERR_READ + * WIMLIB_ERR_UNEXPECTED_END_OF_FILE */ -int check_wim_integrity(WIMStruct *w, int show_progress, int *status) +int +read_integrity_table(WIMStruct *wim, u64 num_checked_bytes, + struct integrity_table **table_ret) { - - struct resource_entry *res_entry; - int ctype; - u8 *buf = NULL; + void *buf; + struct integrity_table *table; int ret; - u32 integrity_table_size; - u32 num_entries; - u32 chunk_size; - const u8 *p; - u64 expected_size; - u64 end_lookup_table_offset; - u64 bytes_to_check; - u64 expected_num_entries; - - res_entry = &w->hdr.integrity; - if (res_entry->size == 0) { - DEBUG("No integrity information."); - *status = WIM_INTEGRITY_NONEXISTENT; - return 0; - } - if (res_entry->original_size < 12) { - ERROR("Integrity table is too short"); - return WIMLIB_ERR_INVALID_INTEGRITY_TABLE; - } - if (res_entry->flags & WIM_RESHDR_FLAG_COMPRESSED) { - ERROR("Didn't expect a compressed integrity table"); - return WIMLIB_ERR_INVALID_INTEGRITY_TABLE; - } - /* Read the integrity table into memory. */ - buf = MALLOC(res_entry->original_size); - if (!buf) { - ERROR("Out of memory (needed %zu bytes for integrity table)", - res_entry->original_size); - ret = WIMLIB_ERR_NOMEM; - goto out; - } - ret = read_uncompressed_resource(w->fp, res_entry->offset, - res_entry->original_size, buf); - if (ret != 0) { - ERROR("Failed to read integrity table (size = %"PRIu64", " - "original_size = %"PRIu64", offset = " - "%"PRIu64")", - (u64)res_entry->size, res_entry->original_size, - res_entry->offset); - goto out; + if (wim->hdr.integrity_table_reshdr.uncompressed_size < 8) + goto invalid; + + ret = wim_reshdr_to_data(&wim->hdr.integrity_table_reshdr, wim, &buf); + if (ret) + return ret; + table = buf; + + table->size = le32_to_cpu(table->size); + table->num_entries = le32_to_cpu(table->num_entries); + table->chunk_size = le32_to_cpu(table->chunk_size); + + if (table->size != wim->hdr.integrity_table_reshdr.uncompressed_size || + table->size != (u64)table->num_entries * SHA1_HASH_SIZE + 12 || + table->chunk_size == 0 || + table->num_entries != DIV_ROUND_UP(num_checked_bytes, table->chunk_size)) + { + FREE(table); + goto invalid; } - p = get_u32(buf, &integrity_table_size); - p = get_u32(p, &num_entries); - p = get_u32(p, &chunk_size); + *table_ret = table; + return 0; - /* p now points to the array of SHA1 message digests for the WIM. */ +invalid: + return WIMLIB_ERR_INVALID_INTEGRITY_TABLE; +} - /* Make sure the integrity table is the right size. */ - if (integrity_table_size != res_entry->original_size) { - ERROR("Inconsistent integrity table sizes: header says %u " - "bytes but resource entry says " - "%"PRIu64" bytes", - integrity_table_size, res_entry->original_size); - ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE; - goto out; +/* + * 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; } - DEBUG("integrity_table_size = %u, num_entries = %u, chunk_size = %u", - integrity_table_size, num_entries, chunk_size); + u64 old_check_bytes = old_check_end - WIM_HEADER_DISK_SIZE; + u64 new_check_bytes = new_check_end - WIM_HEADER_DISK_SIZE; - expected_size = num_entries * SHA1_HASH_SIZE + 12; - - if (integrity_table_size != expected_size) { - ERROR("Integrity table is %u bytes, but expected %"PRIu64" " - "bytes to hold %u entries", - integrity_table_size, expected_size, num_entries); - ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE; - goto out; - } - - if (chunk_size == 0) { - ERROR("Cannot use integrity chunk size of 0"); - ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE; - goto out; - } - - end_lookup_table_offset = w->hdr.lookup_table_res_entry.offset + - w->hdr.lookup_table_res_entry.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); - bytes_to_check = end_lookup_table_offset - WIM_HEADER_DISK_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); - expected_num_entries = (bytes_to_check + chunk_size - 1) / chunk_size; + size_t new_table_size = 12 + new_num_chunks * SHA1_HASH_SIZE; - if (num_entries != expected_num_entries) { - ERROR("%"PRIu64" entries would be required to checksum " - "the %"PRIu64" bytes from the end of the header to the", - expected_num_entries, bytes_to_check); - ERROR("end of the lookup table with a chunk size of %u, but " - "there were only %u entries", chunk_size, num_entries); - ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE; - goto out; + 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; - /* The integrity checking starts after the header, so seek to the offset - * in the WIM after the header. */ +out_free_new_table: + FREE(new_table); + return ret; +} - if (fseeko(w->fp, WIM_HEADER_DISK_SIZE, SEEK_SET) != 0) { - ERROR_WITH_ERRNO("Failed to seek to byte %u of WIM to check " - "integrity", WIM_HEADER_DISK_SIZE); - ret = WIMLIB_ERR_READ; - goto out; - } - /* call verify_integrity(), which does the actual checking of the SHA1 - * message digests. */ - ret = verify_integrity(w->fp, bytes_to_check, chunk_size, p, - show_progress, status); -out: - FREE(buf); +/* + * write_integrity_table(): + * + * Writes a WIM integrity table (a list of SHA1 message digests of raw 10 MiB + * chunks of the file). + * + * This function can optionally re-use entries from an older integrity table. + * To do this, specify old_blob_table_end and old_table. + * + * On success, @wim->out_hdr.integrity_table_reshdr will be filled in with + * information about the integrity table that was written. + * + * @wim: + * WIMStruct for the WIM file. @wim->out_fd must be a seekable descriptor + * to the new WIM file, opened read-write, positioned at the location at + * which the integrity table is to be written. + * + * @new_blob_table_end: + * The offset of the byte directly following the blob table in the WIM + * being written. + * + * @old_blob_table_end: + * If nonzero, the offset of the byte directly following the old blob table + * in the WIM. + * + * @old_table + * Pointer to the old integrity table read into memory, or NULL if not + * specified. + */ +int +write_integrity_table(WIMStruct *wim, + off_t new_blob_table_end, + off_t old_blob_table_end, + struct integrity_table *old_table) +{ + struct integrity_table *new_table; + int ret; + u32 new_table_size; + + wimlib_assert(old_blob_table_end <= new_blob_table_end); + + ret = calculate_integrity_table(&wim->out_fd, new_blob_table_end, + old_table, old_blob_table_end, + &new_table, wim->progfunc, wim->progctx); + if (ret) + return ret; + + new_table_size = new_table->size; + + new_table->size = cpu_to_le32(new_table->size); + new_table->num_entries = cpu_to_le32(new_table->num_entries); + new_table->chunk_size = cpu_to_le32(new_table->chunk_size); + + ret = write_wim_resource_from_buffer(new_table, + new_table_size, + false, + &wim->out_fd, + WIMLIB_COMPRESSION_TYPE_NONE, + 0, + &wim->out_hdr.integrity_table_reshdr, + NULL, + 0); + FREE(new_table); return ret; } -/* - * Writes integrity information to the output stream for a WIM file being - * written. +/* + * verify_integrity(): + * + * Checks a WIM for consistency with the integrity table. * - * @end_header_offset is the offset of the byte after the header, which is the - * beginning of the region that is checksummed. + * @in_fd: + * File descriptor to the WIM file, opened for reading. * - * @end_lookup_table_offset is the offset of the byte after the lookup table, - * which is the end of the region that is checksummed. + * @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 + * blob 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. */ -int write_integrity_table(FILE *out, u64 end_header_offset, - u64 end_lookup_table_offset, int show_progress) +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) { - u64 bytes_to_check; - u64 bytes_remaining; - u8 *buf; - u8 *p; - char *chunk_buf; - u32 num_entries; - u32 integrity_table_size; - int ret; - - DEBUG("Writing integrity table"); - if (fseeko(out, end_header_offset, SEEK_SET) != 0) { - ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" of WIM to " - "calculate integrity data", end_header_offset); - return WIMLIB_ERR_WRITE; + 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; +} - bytes_to_check = end_lookup_table_offset - end_header_offset; - num_entries = bytes_to_check / INTEGRITY_CHUNK_SIZE + - (bytes_to_check % INTEGRITY_CHUNK_SIZE != 0); - integrity_table_size = num_entries * SHA1_HASH_SIZE + 3 * sizeof(u32); - - DEBUG("integrity table size = %u", integrity_table_size); +/* + * check_wim_integrity(): + * + * Verifies the integrity of the WIM by making sure the SHA1 message digests of + * ~10 MiB chunks of the WIM match up with the values given in the integrity + * table. + * + * @wim: + * The WIM, opened for reading. + * + * Returns: + * > 0 (WIMLIB_ERR_INVALID_INTEGRITY_TABLE, 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. + * -2 (WIM_INTEGRITY_NONEXISTENT) if the WIM contains no integrity + * information. + */ +int +check_wim_integrity(WIMStruct *wim) +{ + int ret; + u64 bytes_to_check; + struct integrity_table *table; + u64 end_blob_table_offset; - buf = MALLOC(integrity_table_size); - if (!buf) { - ERROR("Failed to allocate %u bytes for integrity table", - integrity_table_size); - return WIMLIB_ERR_NOMEM; - } + if (!wim_has_integrity_table(wim)) + return WIM_INTEGRITY_NONEXISTENT; - p = put_u32(buf, integrity_table_size); - p = put_u32(p, num_entries); - p = put_u32(p, INTEGRITY_CHUNK_SIZE); + end_blob_table_offset = wim->hdr.blob_table_reshdr.offset_in_wim + + wim->hdr.blob_table_reshdr.size_in_wim; - chunk_buf = MALLOC(INTEGRITY_CHUNK_SIZE); - if (!chunk_buf) { - ERROR("Failed to allocate %u bytes for integrity chunk buffer", - INTEGRITY_CHUNK_SIZE); - ret = WIMLIB_ERR_NOMEM; - goto err2; + if (end_blob_table_offset < WIM_HEADER_DISK_SIZE) { + ERROR("WIM blob table ends before WIM header ends!"); + return WIMLIB_ERR_INVALID_INTEGRITY_TABLE; } - bytes_remaining = bytes_to_check; + bytes_to_check = end_blob_table_offset - WIM_HEADER_DISK_SIZE; - DEBUG("Bytes to check = %"PRIu64, bytes_to_check); - - while (bytes_remaining != 0) { - - uint percent_done = (bytes_to_check - bytes_remaining) * - 100 / bytes_to_check; - - if (show_progress) { - printf("Calculating integrity checksums for WIM " - "(%"PRIu64" bytes remaining, %u%% " - "done) \r", - bytes_remaining, percent_done); - fflush(stdout); - } - - - size_t bytes_to_read = min(INTEGRITY_CHUNK_SIZE, bytes_remaining); - size_t bytes_read = fread(chunk_buf, 1, bytes_to_read, out); - if (bytes_read != bytes_to_read) { - if (feof(out)) { - ERROR("Unexpected EOF while calculating " - "integrity checksums"); - } else { - ERROR_WITH_ERRNO("File stream error while " - "calculating integrity " - "checksums"); - } - ret = WIMLIB_ERR_READ; - goto err2; - } - sha1_buffer(chunk_buf, bytes_read, p); - p += SHA1_HASH_SIZE; - bytes_remaining -= bytes_read; - } - if (show_progress) - puts("Calculating integrity checksums for WIM " - "(0 bytes remaining, 100% done)" - " "); - - if (fseeko(out, 0, SEEK_END) != 0) { - ERROR_WITH_ERRNO("Failed to seek to end of WIM to write " - "integrity table"); - ret = WIMLIB_ERR_WRITE; - goto err1; - } - - if (fwrite(buf, 1, integrity_table_size, out) != integrity_table_size) { - ERROR_WITH_ERRNO("Failed to write integrity table to end of " - "WIM"); - ret = WIMLIB_ERR_WRITE; - goto err1; - } - ret = 0; -err1: - FREE(chunk_buf); -err2: - FREE(buf); + ret = read_integrity_table(wim, bytes_to_check, &table); + if (ret) + return ret; + ret = verify_integrity(&wim->in_fd, wim->filename, table, + bytes_to_check, wim->progfunc, wim->progctx); + FREE(table); return ret; }