X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fintegrity.c;h=12968bf91004a0b2e54d6b59c677c5e8c5f261c2;hb=9dffaa1a9f8a067ac9e9ac2bad19851b604f8545;hp=38a12ff59f046b88fff5730256ed9d8d918f0122;hpb=885632f08c75c1d7bb5d25436231c78f6ad7e0c0;p=wimlib diff --git a/src/integrity.c b/src/integrity.c index 38a12ff5..12968bf9 100644 --- a/src/integrity.c +++ b/src/integrity.c @@ -4,23 +4,25 @@ * 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. - * + */ + +/* * Copyright (C) 2012 Eric Biggers * - * wimlib - Library for working with WIM files + * This file is part of wimlib, a library for working with WIM files. * - * This library 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 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. * - * This library 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. + * 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 + * details. * - * You should have received a copy of the GNU Lesser General Public License along - * with this library; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the GNU Lesser General Public License + * along with wimlib; if not, see http://www.gnu.org/licenses/. */ #include "wimlib_internal.h" @@ -48,7 +50,7 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size, int *status) { char *chunk_buf; - u8 resblock[WIM_HASH_SIZE]; + u8 resblock[SHA1_HASH_SIZE]; u64 bytes_remaining; size_t bytes_to_read; uint percent_done; @@ -56,8 +58,8 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size, chunk_buf = MALLOC(chunk_size); if (!chunk_buf) { - ERROR("Failed to allocate %u byte buffer for integrity " - "chunks\n", chunk_size); + ERROR("Failed to allocate %u byte buffer for integrity chunks", + chunk_size); return WIMLIB_ERR_NOMEM; } bytes_remaining = num_bytes; @@ -74,20 +76,20 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size, if (fread(chunk_buf, 1, bytes_to_read, fp) != bytes_to_read) { if (feof(fp)) { ERROR("Unexpected EOF while verifying " - "integrity of WIM!\n"); + "integrity of WIM"); } else { - ERROR("File stream error while verifying " - "integrity of WIM: %m\n"); + ERROR_WITH_ERRNO("File stream error while " + "verifying integrity of WIM"); } ret = WIMLIB_ERR_READ; goto verify_integrity_error; } sha1_buffer(chunk_buf, bytes_to_read, resblock); - if (memcmp(resblock, sha1sums, WIM_HASH_SIZE) != 0) { + if (!hashes_equal(resblock, sha1sums)) { *status = WIM_INTEGRITY_NOT_OK; goto verify_integrity_done; } - sha1sums += WIM_HASH_SIZE; + sha1sums += SHA1_HASH_SIZE; bytes_remaining -= bytes_to_read; } *status = WIM_INTEGRITY_OK; @@ -129,33 +131,36 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status) res_entry = &w->hdr.integrity; if (res_entry->size == 0) { - DEBUG("No integrity information.\n"); + DEBUG("No integrity information."); *status = WIM_INTEGRITY_NONEXISTENT; return 0; } - ctype = wim_resource_compression_type(w, res_entry); if (res_entry->original_size < 12) { - ERROR("Integrity table resource is too short!\n"); + 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)!\n", - res_entry->original_size); + ERROR("Out of memory (needed %zu bytes for integrity table)", + res_entry->original_size); ret = WIMLIB_ERR_NOMEM; - goto check_integrity_error; + goto out; } - ret = read_full_resource(w->fp, res_entry->size, res_entry->original_size, - res_entry->offset, ctype, buf); + 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", ctype = %d\n", - (u64)res_entry->size, res_entry->original_size, - res_entry->offset, ctype); - goto check_integrity_error; + "original_size = %"PRIu64", offset = " + "%"PRIu64")", + (u64)res_entry->size, res_entry->original_size, + res_entry->offset); + goto out; } p = get_u32(buf, &integrity_table_size); @@ -167,27 +172,31 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status) /* 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\n", integrity_table_size, - res_entry->original_size); - + "bytes but resource entry says " + "%"PRIu64" bytes", + integrity_table_size, res_entry->original_size); ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE; - goto check_integrity_error; + goto out; } - DEBUG("integrity_table_size = %u, num_entries = %u, chunk_size = %u\n", - integrity_table_size, num_entries, chunk_size); + DEBUG("integrity_table_size = %u, num_entries = %u, chunk_size = %u", + integrity_table_size, num_entries, chunk_size); - expected_size = num_entries * WIM_HASH_SIZE + 12; + 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!\n", - integrity_table_size, - expected_size, num_entries); + "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 check_integrity_error; + goto out; } end_lookup_table_offset = w->hdr.lookup_table_res_entry.offset + @@ -195,34 +204,32 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status) bytes_to_check = end_lookup_table_offset - WIM_HEADER_DISK_SIZE; - expected_num_entries = bytes_to_check / chunk_size + - (bytes_to_check % chunk_size != 0); + expected_num_entries = (bytes_to_check + chunk_size - 1) / chunk_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\n" - "end of the lookup table with a chunk size of %u, but " - "there were only %u entries!\n", - expected_num_entries, bytes_to_check, chunk_size, - 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 check_integrity_error; + goto out; } /* The integrity checking starts after the header, so seek to the offset * in the WIM after the header. */ if (fseeko(w->fp, WIM_HEADER_DISK_SIZE, SEEK_SET) != 0) { - ERROR("Failed to seek to byte %u of WIM to check " - "integrity: %m\n", WIM_HEADER_DISK_SIZE); + ERROR_WITH_ERRNO("Failed to seek to byte %u of WIM to check " + "integrity", WIM_HEADER_DISK_SIZE); ret = WIMLIB_ERR_READ; - goto check_integrity_error; + 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); -check_integrity_error: +out: FREE(buf); return ret; } @@ -249,26 +256,25 @@ int write_integrity_table(FILE *out, u64 end_header_offset, u32 integrity_table_size; int ret; - DEBUG("Writing integrity table.\n"); + DEBUG("Writing integrity table"); if (fseeko(out, end_header_offset, SEEK_SET) != 0) { - ERROR("Failed to seek to byte %"PRIu64" of WIM " - "to calculate integrity data: %m\n", - end_header_offset); + ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" of WIM to " + "calculate integrity data", end_header_offset); return WIMLIB_ERR_WRITE; } 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 * WIM_HASH_SIZE + 3 * sizeof(u32); + integrity_table_size = num_entries * SHA1_HASH_SIZE + 3 * sizeof(u32); - DEBUG("integrity table size = %u\n", integrity_table_size); + DEBUG("integrity table size = %u", integrity_table_size); buf = MALLOC(integrity_table_size); if (!buf) { - ERROR("Failed to allocate %u bytes for integrity table!\n", - integrity_table_size); + ERROR("Failed to allocate %u bytes for integrity table", + integrity_table_size); return WIMLIB_ERR_NOMEM; } @@ -278,15 +284,15 @@ int write_integrity_table(FILE *out, u64 end_header_offset, chunk_buf = MALLOC(INTEGRITY_CHUNK_SIZE); if (!chunk_buf) { - ERROR("Failed to allocate %u bytes for integrity chunk " - "buffer!\n", INTEGRITY_CHUNK_SIZE); + ERROR("Failed to allocate %u bytes for integrity chunk buffer", + INTEGRITY_CHUNK_SIZE); ret = WIMLIB_ERR_NOMEM; goto err2; } bytes_remaining = bytes_to_check; - DEBUG("Bytes to check = %"PRIu64"\n", bytes_to_check); + DEBUG("Bytes to check = %"PRIu64, bytes_to_check); while (bytes_remaining != 0) { @@ -301,35 +307,40 @@ int write_integrity_table(FILE *out, u64 end_header_offset, 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!\n"); + "integrity checksums"); } else { - ERROR("File stream error while calculating " - "integrity checksums: %m\n"); + ERROR_WITH_ERRNO("File stream error while " + "calculating integrity " + "checksums"); } ret = WIMLIB_ERR_READ; goto err2; } sha1_buffer(chunk_buf, bytes_read, p); - p += WIM_HASH_SIZE; + p += SHA1_HASH_SIZE; bytes_remaining -= bytes_read; } if (show_progress) - putchar('\n'); + puts("Calculating integrity checksums for WIM " + "(0 bytes remaining, 100% done)" + " "); if (fseeko(out, 0, SEEK_END) != 0) { - ERROR("Failed to seek to end of WIM to write integrity " - "table: %m\n"); + 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("Failed to write integrity table to end of WIM: %m\n"); + ERROR_WITH_ERRNO("Failed to write integrity table to end of " + "WIM"); ret = WIMLIB_ERR_WRITE; goto err1; }