* data in nonempty chunks into the cbs->consume_chunk() function. */
static int
read_raw_file_data(struct filedes *in_fd, u64 offset, u64 size,
- const struct read_blob_callbacks *cbs)
+ const struct read_blob_callbacks *cbs,
+ const tchar *filename)
{
u8 buf[BUFFER_SIZE];
size_t bytes_to_read;
while (size) {
bytes_to_read = min(sizeof(buf), size);
ret = full_pread(in_fd, buf, bytes_to_read, offset);
- if (unlikely(ret)) {
- ERROR_WITH_ERRNO("Read error");
- return ret;
- }
+ if (unlikely(ret))
+ goto read_error;
ret = call_consume_chunk(buf, bytes_to_read, cbs);
if (unlikely(ret))
return ret;
offset += bytes_to_read;
}
return 0;
+
+read_error:
+ if (!filename) {
+ ERROR_WITH_ERRNO("Error reading data from WIM file");
+ } else if (ret == WIMLIB_ERR_UNEXPECTED_END_OF_FILE) {
+ ERROR("\"%"TS"\": File was concurrently truncated", filename);
+ ret = WIMLIB_ERR_CONCURRENT_MODIFICATION_DETECTED;
+ } else {
+ ERROR_WITH_ERRNO("\"%"TS"\": Error reading data", filename);
+ }
+ return ret;
}
/* A consume_chunk() implementation that simply concatenates all chunks into an
/* Uncompressed resource */
return read_raw_file_data(&rdesc->wim->in_fd,
rdesc->offset_in_wim + offset,
- size, cbs);
+ size, cbs, NULL);
}
/* Read the specified range of uncompressed data from the specified blob, which
return WIMLIB_ERR_OPEN;
}
filedes_init(&fd, raw_fd);
- ret = read_raw_file_data(&fd, 0, size, cbs);
+ ret = read_raw_file_data(&fd, 0, size, cbs, blob->file_on_disk);
filedes_close(&fd);
return ret;
}
return WIMLIB_ERR_OPEN;
}
filedes_init(&fd, raw_fd);
- ret = read_raw_file_data(&fd, 0, size, cbs);
+ ret = read_raw_file_data(&fd, 0, size, cbs, blob->staging_file_name);
filedes_close(&fd);
return ret;
}
return call_consume_chunk(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_on_disk, 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
} else if ((ctx->flags & VERIFY_BLOB_HASHES) &&
unlikely(!hashes_equal(hash, blob->hash)))
{
- if (wimlib_print_errors) {
- tchar expected_hashstr[SHA1_HASH_SIZE * 2 + 1];
- tchar actual_hashstr[SHA1_HASH_SIZE * 2 + 1];
- sprint_hash(blob->hash, expected_hashstr);
- sprint_hash(hash, actual_hashstr);
- ERROR("The data is corrupted!\n"
- " (Expected SHA-1=%"TS", got SHA-1=%"TS")",
- expected_hashstr, actual_hashstr);
- }
- ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
+ ret = report_sha1_mismatch_error(blob, hash);
goto out_next_cb;
}
ret = 0;