+ struct hasher_context *ctx = _ctx;
+
+ sha1_update(&ctx->sha_ctx, chunk, size);
+
+ return call_continue_blob(blob, offset, chunk, size, &ctx->cbs);
+}
+
+static int
+report_sha1_mismatch_error(const struct blob_descriptor *blob,
+ const u8 actual_hash[SHA1_HASH_SIZE])
+{
+ tchar expected_hashstr[SHA1_HASH_SIZE * 2 + 1];
+ tchar actual_hashstr[SHA1_HASH_SIZE * 2 + 1];
+
+ wimlib_assert(blob->blob_location != BLOB_NONEXISTENT);
+ wimlib_assert(blob->blob_location != BLOB_IN_ATTACHED_BUFFER);
+
+ sprint_hash(blob->hash, expected_hashstr);
+ sprint_hash(actual_hash, actual_hashstr);
+
+ if (blob_is_in_file(blob)) {
+ ERROR("A file was concurrently modified!\n"
+ " Path: \"%"TS"\"\n"
+ " Expected SHA-1: %"TS"\n"
+ " Actual SHA-1: %"TS"\n",
+ blob_file_path(blob), expected_hashstr, actual_hashstr);
+ return WIMLIB_ERR_CONCURRENT_MODIFICATION_DETECTED;
+ } else if (blob->blob_location == BLOB_IN_WIM) {
+ const struct wim_resource_descriptor *rdesc = blob->rdesc;
+ ERROR("A WIM resource is corrupted!\n"
+ " WIM file: \"%"TS"\"\n"
+ " Blob uncompressed size: %"PRIu64"\n"
+ " Resource offset in WIM: %"PRIu64"\n"
+ " Resource uncompressed size: %"PRIu64"\n"
+ " Resource size in WIM: %"PRIu64"\n"
+ " Resource flags: 0x%x%"TS"\n"
+ " Resource compression type: %"TS"\n"
+ " Resource compression chunk size: %"PRIu32"\n"
+ " Expected SHA-1: %"TS"\n"
+ " Actual SHA-1: %"TS"\n",
+ rdesc->wim->filename,
+ blob->size,
+ rdesc->offset_in_wim,
+ rdesc->uncompressed_size,
+ rdesc->size_in_wim,
+ (unsigned int)rdesc->flags,
+ (rdesc->is_pipable ? T(", pipable") : T("")),
+ wimlib_get_compression_type_string(
+ rdesc->compression_type),
+ rdesc->chunk_size,
+ expected_hashstr, actual_hashstr);
+ return WIMLIB_ERR_INVALID_RESOURCE_HASH;
+ } else {
+ ERROR("File data was concurrently modified!\n"
+ " Location ID: %d\n"
+ " Expected SHA-1: %"TS"\n"
+ " Actual SHA-1: %"TS"\n",
+ (int)blob->blob_location,
+ expected_hashstr, actual_hashstr);
+ return WIMLIB_ERR_CONCURRENT_MODIFICATION_DETECTED;
+ }
+}
+
+/* Callback for finishing reading a blob while calculating its SHA-1 message
+ * digest. */
+static int
+hasher_end_blob(struct blob_descriptor *blob, int status, void *_ctx)
+{
+ struct hasher_context *ctx = _ctx;
+ u8 hash[SHA1_HASH_SIZE];