blockless_car/
reader.rs

1use cid::Cid;
2use ipld::raw::RawCodec;
3
4mod reader_v1;
5use crate::{error::CarError, header::CarHeader, section::Section, unixfs::UnixFs, Ipld};
6use integer_encoding::VarIntReader;
7use std::{
8    collections::VecDeque,
9    io::{self, Read, Seek},
10};
11
12pub(crate) use reader_v1::CarReaderV1;
13
14const MAX_ALLOWED_SECTION_SIZE: usize = 32 << 20;
15
16pub fn read_block<R>(mut reader: R) -> Result<Option<Vec<u8>>, CarError>
17where
18    R: std::io::Read,
19{
20    let l: usize = match reader.read_varint() {
21        Ok(i) => i,
22        Err(e) => {
23            if e.kind() == std::io::ErrorKind::UnexpectedEof {
24                return Ok(None);
25            }
26            return Err(CarError::IO(e));
27        }
28    };
29    if l > MAX_ALLOWED_SECTION_SIZE {
30        return Err(CarError::TooLargeSection(l));
31    }
32    let mut data = vec![0u8; l];
33    reader.read_exact(&mut data[..])?;
34    Ok(Some(data))
35}
36
37pub(crate) fn read_section<R>(mut reader: R) -> Result<Option<Section>, CarError>
38where
39    R: io::Read + io::Seek,
40{
41    let len: usize = match reader.read_varint() {
42        Ok(i) => i,
43        Err(e) => {
44            if e.kind() == io::ErrorKind::UnexpectedEof {
45                return Ok(None);
46            }
47            return Err(CarError::IO(e));
48        }
49    };
50    let start = reader.stream_position()?;
51    if len > MAX_ALLOWED_SECTION_SIZE {
52        return Err(CarError::TooLargeSection(len));
53    }
54    let cid = Cid::read_bytes(&mut reader).map_err(|e| CarError::Parsing(e.to_string()))?;
55    let pos = reader.stream_position()?;
56    let l = len - ((pos - start) as usize);
57    reader.seek(io::SeekFrom::Current(l as _))?;
58    Ok(Some(Section::new(cid, pos, l)))
59}
60
61pub trait CarReader {
62    fn header(&self) -> &CarHeader;
63
64    fn sections(&self) -> Vec<Section>;
65
66    fn read_section_data(&mut self, cid: &Cid) -> Result<Vec<u8>, CarError>;
67
68    fn ipld(&mut self, cid: &Cid) -> Result<Ipld, CarError>;
69
70    #[inline(always)]
71    fn unixfs(&mut self, cid: &Cid) -> Result<UnixFs, CarError> {
72        let fs_ipld = self.ipld(cid)?;
73        (*cid, fs_ipld).try_into()
74    }
75
76    fn search_file_cid_inner(
77        &mut self,
78        searchq: &mut VecDeque<Cid>,
79        f: &str,
80    ) -> Result<Cid, CarError> {
81        let raw_code: u64 = RawCodec.into();
82        while let Some(root_cid) = searchq.pop_front() {
83            let codec = root_cid.codec();
84            if codec == raw_code {
85                continue;
86            }
87            let fs_ipld = self.ipld(&root_cid)?;
88            if matches!(fs_ipld, Ipld::Map(_)) {
89                let unixfs: UnixFs = (root_cid, fs_ipld).try_into()?;
90                for ufs in unixfs.links() {
91                    if ufs.name == f {
92                        return Ok(ufs.hash);
93                    }
94                    searchq.push_back(ufs.hash);
95                }
96            }
97        }
98        Err(CarError::NotFound(format!("search {f} fail.")))
99    }
100
101    #[inline]
102    fn search_file_cid(&mut self, f: &str) -> Result<Cid, CarError> {
103        let roots = self.header().roots();
104        let mut searchq = VecDeque::new();
105        for root in roots.into_iter() {
106            searchq.push_back(root);
107            match self.search_file_cid_inner(&mut searchq, f) {
108                Ok(o) => return Ok(o),
109                Err(CarError::NotFound(_)) => continue,
110                Err(e) => return Err(e),
111            }
112        }
113        Err(CarError::NotFound(format!("search {f} fail.")))
114    }
115}
116
117#[inline(always)]
118pub fn new_v1<R>(inner: R) -> Result<impl CarReader, CarError>
119where
120    R: Read + Seek,
121{
122    CarReaderV1::new(inner)
123}