]> wimlib.net Git - wimlib/blobdiff - src/integrity.c
Cleanup WIM writing
[wimlib] / src / integrity.c
index 55d950a6da62782bc2dce35434ccf1d13b4602f3..f1e208f17d2a4a1fc26363ddba8580a8aae55b90 100644 (file)
  * This file is part of wimlib, a library for working with WIM files.
  *
  * 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)
+ * terms of the GNU 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 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
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
  *
- * You should have received a copy of the GNU Lesser General Public License
+ * You should have received a copy of the GNU General Public License
  * along with wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
 #define INTEGRITY_CHUNK_SIZE 10485760
 
 /*
- * Verifies the integrity of a WIM. 
+ * Verifies the integrity of a WIM.
  *
- * @fp:                   FILE* of the WIM, currently positioned at the end of the header. 
+ * @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 
+ * @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, 
+static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size,
                            const u8 *sha1sums, int show_progress,
                            int *status)
 {
-       char  *chunk_buf;
-       u8     resblock[WIM_HASH_SIZE];
+       u8    *chunk_buf;
+       u8     resblock[SHA1_HASH_SIZE];
        u64    bytes_remaining;
        size_t bytes_to_read;
        uint   percent_done;
@@ -65,10 +65,10 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size,
        bytes_remaining = num_bytes;
        while (bytes_remaining != 0) {
                if (show_progress) {
-                       percent_done = (num_bytes - bytes_remaining) * 100 / 
+                       percent_done = (num_bytes - bytes_remaining) * 100 /
                                        num_bytes;
                        printf("Verifying integrity of WIM (%"PRIu64" bytes "
-                                       "remaining, %u%% done)       \r", 
+                                       "remaining, %u%% done)       \r",
                                        bytes_remaining, percent_done);
                        fflush(stdout);
                }
@@ -85,11 +85,11 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size,
                        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;
@@ -103,7 +103,7 @@ verify_integrity_error:
 }
 
 /*
- * Verifies the integrity of the WIM. 
+ * Verifies the integrity of the WIM.
  *
  * @show_progress: Nonzero if the percent complete is to be printed after every
  *                     chunk.
@@ -117,7 +117,6 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
 {
 
        struct resource_entry *res_entry;
-       int ctype;
        u8 *buf = NULL;
        int ret;
        u32 integrity_table_size;
@@ -135,11 +134,14 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
                *status = WIM_INTEGRITY_NONEXISTENT;
                return 0;
        }
-       ctype = wim_resource_compression_type(w, res_entry);
        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);
@@ -149,15 +151,14 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
                ret = WIMLIB_ERR_NOMEM;
                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",
+                     "%"PRIu64")",
                      (u64)res_entry->size, res_entry->original_size,
-                     res_entry->offset, ctype);
+                     res_entry->offset);
                goto out;
        }
 
@@ -181,11 +182,11 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
              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", 
+                     "bytes to hold %u entries",
                      integrity_table_size, expected_size, num_entries);
                ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
                goto out;
@@ -200,6 +201,12 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
        end_lookup_table_offset = w->hdr.lookup_table_res_entry.offset +
                                  w->hdr.lookup_table_res_entry.size;
 
+       if (end_lookup_table_offset < WIM_HEADER_DISK_SIZE) {
+               ERROR("WIM lookup table ends before WIM header ends???");
+               ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
+               goto out;
+       }
+
        bytes_to_check = end_lookup_table_offset - WIM_HEADER_DISK_SIZE;
 
        expected_num_entries = (bytes_to_check + chunk_size - 1) / chunk_size;
@@ -225,36 +232,36 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
        }
        /* call verify_integrity(), which does the actual checking of the SHA1
         * message digests. */
-       ret = verify_integrity(w->fp, bytes_to_check, chunk_size, p, 
+       ret = verify_integrity(w->fp, bytes_to_check, chunk_size, p,
                               show_progress, status);
 out:
        FREE(buf);
        return ret;
 }
 
-/* 
+/*
  * Writes integrity information to the output stream for a WIM file being
- * written. 
+ * written.
  *
  * @end_header_offset is the offset of the byte after the header, which is the
  *     beginning of the region that is checksummed.
  *
  * @end_lookup_table_offset is the offset of the byte after the lookup table,
- *     which is the end of the region that is checksummed. 
+ *     which is the end of the region that is checksummed.
  */
-int write_integrity_table(FILE *out, u64 end_header_offset, 
+int write_integrity_table(FILE *out, u64 end_header_offset,
                          u64 end_lookup_table_offset, int show_progress)
 {
-       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");
+       u64  bytes_to_check;
+       u64  bytes_remaining;
+       u8  *buf;
+       u8  *p;
+       u8  *chunk_buf;
+       u32  num_entries;
+       u32  integrity_table_size;
+       int  ret;
+
+       DEBUG("Calculating 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);
@@ -262,12 +269,11 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
        }
 
        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);
-
-       DEBUG("integrity table size = %u", integrity_table_size);
+       num_entries = (bytes_to_check + INTEGRITY_CHUNK_SIZE - 1) /
+                       INTEGRITY_CHUNK_SIZE;
+       integrity_table_size = num_entries * SHA1_HASH_SIZE + 3 * sizeof(u32);
 
+       DEBUG("integrity_table_size = %u", integrity_table_size);
 
        buf = MALLOC(integrity_table_size);
        if (!buf) {
@@ -285,7 +291,7 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
                ERROR("Failed to allocate %u bytes for integrity chunk buffer",
                      INTEGRITY_CHUNK_SIZE);
                ret = WIMLIB_ERR_NOMEM;
-               goto err2;
+               goto out_free_buf;
        }
 
        bytes_remaining = bytes_to_check;
@@ -294,13 +300,13 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
 
        while (bytes_remaining != 0) {
 
-               uint percent_done = (bytes_to_check - bytes_remaining) * 
+               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", 
+                                       "done)      \r",
                                        bytes_remaining, percent_done);
                        fflush(stdout);
                }
@@ -318,10 +324,10 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
                                                 "checksums");
                        }
                        ret = WIMLIB_ERR_READ;
-                       goto err2;
+                       goto out_free_chunk_buf;
                }
                sha1_buffer(chunk_buf, bytes_read, p);
-               p += WIM_HASH_SIZE;
+               p += SHA1_HASH_SIZE;
                bytes_remaining -= bytes_read;
        }
        if (show_progress)
@@ -333,19 +339,19 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
                ERROR_WITH_ERRNO("Failed to seek to end of WIM to write "
                                 "integrity table");
                ret = WIMLIB_ERR_WRITE;
-               goto err1;
+               goto out_free_chunk_buf;
        }
 
        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;
+               goto out_free_chunk_buf;
        }
        ret = 0;
-err1:
+out_free_chunk_buf:
        FREE(chunk_buf);
-err2:
+out_free_buf:
        FREE(buf);
        return ret;
 }