fix(io): refuse truncated files in the VOL, async and MPI readers
The truncated-file check and the end-of-file clamp reached File, LazyFile and MmapFile but not clawhdf5-io's readers, which still opened truncated files and read past the recorded end of file. NativeVol (open, and read_dataset for from_bytes), AsyncHDF5File::from_bytes and MpiVol's collective read now view the file through the new vol::hdf5_view: from the superblock to Superblock::data_end, refusing a file shorter than that. MpiVol's read is compiled only with the mpi-io feature, which needs an MPI installation; it was not built here. The edit there only swaps its two-line superblock setup for hdf5_view. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -281,8 +281,13 @@ impl AsyncHDF5File {
|
||||
// HDF5 addresses are relative to the superblock: drop any user block
|
||||
// so they index `data` directly.
|
||||
let user_block = find_signature(&data)?;
|
||||
let whole_len = data.len() as u64;
|
||||
data.drain(..user_block);
|
||||
let superblock = Superblock::parse(&data, 0)?;
|
||||
// Refuse a truncated file, and keep nothing past the end of file the
|
||||
// superblock records, as libhdf5 does.
|
||||
let end = superblock.data_end(user_block as u64, whole_len)?;
|
||||
data.truncate(end as usize);
|
||||
Ok(Self { data, superblock })
|
||||
}
|
||||
|
||||
@@ -605,6 +610,28 @@ mod tests {
|
||||
tokio::fs::remove_file(&path).await.ok();
|
||||
}
|
||||
|
||||
/// As libhdf5 does: a truncated file is refused, and bytes past the end
|
||||
/// of file the superblock records are dropped.
|
||||
#[tokio::test]
|
||||
async fn async_refuses_truncated_files_and_drops_trailing_bytes() {
|
||||
let bytes = make_test_hdf5_f64("v", &[1.0, 2.0]);
|
||||
let truncated = bytes[..bytes.len() - 8].to_vec();
|
||||
let err = AsyncHDF5File::from_bytes(truncated).err().unwrap();
|
||||
assert!(
|
||||
matches!(
|
||||
err,
|
||||
AsyncHDF5Error::Format(FormatError::TruncatedFile { .. })
|
||||
),
|
||||
"{err}"
|
||||
);
|
||||
|
||||
let mut appended = bytes.clone();
|
||||
appended.extend_from_slice(&[0xAB; 64]);
|
||||
let file = AsyncHDF5File::from_bytes(appended).unwrap();
|
||||
assert_eq!(file.as_bytes().len(), bytes.len());
|
||||
assert_eq!(file.read_f64("v").await.unwrap(), vec![1.0, 2.0]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn async_error_display() {
|
||||
let io_err = AsyncHDF5Error::Io(io::Error::new(io::ErrorKind::NotFound, "gone"));
|
||||
|
||||
Reference in New Issue
Block a user