diff --git a/src/db/car/any.rs b/src/db/car/any.rs index 97fa3e60c874..2c3627a04324 100644 --- a/src/db/car/any.rs +++ b/src/db/car/any.rs @@ -34,8 +34,10 @@ impl AnyCar { /// `.forest.car.zst`. This call may block for an indeterminate amount of /// time while data is decoded and indexed. pub fn new(reader: ReaderT) -> Result { - if super::ForestCar::is_valid(&reader) { - return Ok(AnyCar::Forest(super::ForestCar::new(reader)?)); + if let Ok(validation_result) = super::ForestCar::validate_car(&reader) { + return Ok( + super::ForestCar::new_from_validation_result(reader, validation_result)?.into(), + ); } // Maybe use a tempfile for this in the future. @@ -46,7 +48,7 @@ impl AnyCar { } if let Ok(plain_car) = super::PlainCar::new(reader) { - return Ok(AnyCar::Plain(plain_car)); + return Ok(plain_car.into()); } Err(Error::new( ErrorKind::InvalidData, diff --git a/src/db/car/forest.rs b/src/db/car/forest.rs index 28512d926a40..fb4191f58fd7 100644 --- a/src/db/car/forest.rs +++ b/src/db/car/forest.rs @@ -104,7 +104,14 @@ pub struct ForestCar { impl ForestCar { pub fn new(reader: ReaderT) -> io::Result> { - let (header, index_start_pos, index_size_bytes) = Self::validate_car(&reader)?; + let validation_result = Self::validate_car(&reader)?; + Self::new_from_validation_result(reader, validation_result) + } + + pub(super) fn new_from_validation_result( + reader: ReaderT, + (header, index_start_pos, index_size_bytes): (CarV1Header, u64, u64), + ) -> io::Result> { let indexed = index::Reader::new(index::ZstdSkipFramesEncodedDataReader::new( positioned_io::Slice::new(reader, index_start_pos, Some(index_size_bytes)), )?)?; @@ -138,7 +145,7 @@ impl ForestCar { Self::validate_car(reader).is_ok() } - fn validate_car(reader: &ReaderT) -> io::Result<(CarV1Header, u64, u64)> { + pub(super) fn validate_car(reader: &ReaderT) -> io::Result<(CarV1Header, u64, u64)> { let mut cursor = SizeCursor::new(&reader); cursor.seek(SeekFrom::End(-(ForestCarFooter::SIZE as i64)))?; let index_end_pos = cursor.position(); diff --git a/src/db/car/many.rs b/src/db/car/many.rs index 28184d03bebe..6a2f54484292 100644 --- a/src/db/car/many.rs +++ b/src/db/car/many.rs @@ -26,6 +26,7 @@ use fvm_ipld_blockstore::Blockstore; use parking_lot::RwLock; use std::cmp::Ord; use std::collections::BinaryHeap; +use std::path::Path; use std::{path::PathBuf, sync::Arc}; struct WithHeaviestEpoch { @@ -124,12 +125,20 @@ impl ManyCar { pub fn read_only_files(&self, files: impl Iterator) -> anyhow::Result<()> { for file in files { - self.read_only(AnyCar::new(EitherMmapOrRandomAccessFile::open(file)?)?)?; + self.read_only_file(file)?; } - Ok(()) } + pub fn read_only_file(&self, file: impl AsRef) -> anyhow::Result<()> { + (|| { + self.read_only(AnyCar::new(EitherMmapOrRandomAccessFile::open( + file.as_ref(), + )?)?) + })() + .map_err(|e| anyhow::anyhow!("failed to load CAR at {}: {e}", file.as_ref().display())) + } + pub fn heaviest_tipset_key(&self) -> anyhow::Result> { Ok(self .read_only diff --git a/tests/tool_tests.rs b/tests/tool_tests.rs index a48ce16345f0..3168bf020d06 100644 --- a/tests/tool_tests.rs +++ b/tests/tool_tests.rs @@ -21,8 +21,8 @@ fn export_empty_archive() { .arg(&temp_file) .assert() .failure() - .stderr(predicate::eq( - "Error: input not recognized as any kind of CAR data (.car, .car.zst, .forest.car)\n", + .stderr(predicate::str::contains( + "input not recognized as any kind of CAR data (.car, .car.zst, .forest.car)", )); }