]> wimlib.net Git - wimlib/blobdiff - src/integrity.c
Rewritten functions for reading and writing resources
[wimlib] / src / integrity.c
index ce05906a133f2637dccd40676a5ed67aad4c5e5b..12968bf91004a0b2e54d6b59c677c5e8c5f261c2 100644 (file)
@@ -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) {
 
@@ -307,16 +313,17 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
                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)
@@ -325,14 +332,15 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
                                "                       ");
 
        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;
        }