fix(format): apply the base address of files with a user block
A file may start with a user block (h5py userblock_size, h5jam), putting the superblock at 512, 1024, ...; every address in the file is then relative to the superblock. The signature search found it, but every reader passed the whole file to the parsers, so addresses landed userblock bytes early and the root group failed with InvalidObjectHeaderVersion (twithub.h5, twithub513.h5, h5clear_fsm_persist_user_*.h5). Readers now view the file from the superblock on, taking the signature's position as the base address as libhdf5 does: File (mmap, buffered, from_bytes), MmapFile, LazyFile, AsyncHDF5File, the VOL and MPI VOL readers, the HNSW loader and external VDS source files. File, MmapFile and LazyFile gain user_block_size(). The new signature::split_user_block returns the two parts, and Superblock::parse refuses a non-zero offset (UserBlockNotStripped) so a format-level caller cannot silently apply superblock-relative addresses to the whole file. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -268,28 +268,26 @@ impl AsyncHDF5File {
|
||||
///
|
||||
/// Reads the entire file into memory, then parses the superblock.
|
||||
pub async fn open<R: AsyncHDF5Read>(reader: &R) -> Result<Self, AsyncHDF5Error> {
|
||||
let data = reader.read_all().await?;
|
||||
let sig_offset = find_signature(&data)?;
|
||||
let superblock = Superblock::parse(&data, sig_offset)?;
|
||||
Ok(Self { data, superblock })
|
||||
Self::from_bytes(reader.read_all().await?)
|
||||
}
|
||||
|
||||
/// Open an HDF5 file asynchronously from a file path.
|
||||
pub async fn open_path<P: AsRef<Path>>(path: P) -> Result<Self, AsyncHDF5Error> {
|
||||
let data = tokio::fs::read(path).await?;
|
||||
let sig_offset = find_signature(&data)?;
|
||||
let superblock = Superblock::parse(&data, sig_offset)?;
|
||||
Ok(Self { data, superblock })
|
||||
Self::from_bytes(tokio::fs::read(path).await?)
|
||||
}
|
||||
|
||||
/// Open an HDF5 file from bytes already in memory.
|
||||
pub fn from_bytes(data: Vec<u8>) -> Result<Self, AsyncHDF5Error> {
|
||||
let sig_offset = find_signature(&data)?;
|
||||
let superblock = Superblock::parse(&data, sig_offset)?;
|
||||
pub fn from_bytes(mut data: Vec<u8>) -> Result<Self, AsyncHDF5Error> {
|
||||
// HDF5 addresses are relative to the superblock: drop any user block
|
||||
// so they index `data` directly.
|
||||
let user_block = find_signature(&data)?;
|
||||
data.drain(..user_block);
|
||||
let superblock = Superblock::parse(&data, 0)?;
|
||||
Ok(Self { data, superblock })
|
||||
}
|
||||
|
||||
/// Access the raw file bytes.
|
||||
/// Access the file bytes from the superblock on (any user block is
|
||||
/// dropped on open).
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user