rs_car_sync/
car_header.rs1use std::io::Read;
2
3use crate::{
4 carv1_header::{decode_carv1_header, CarV1Header},
5 carv2_header::{decode_carv2_header, CarV2Header, CARV2_HEADER_SIZE, CARV2_PRAGMA_SIZE},
6 error::CarDecodeError,
7 varint::read_varint_u64,
8 Cid,
9};
10
11const MAX_HEADER_LEN: u64 = 1048576;
13const MAX_PADDING_LEN: usize = 1073741824;
15
16#[derive(Debug, PartialEq)]
17pub(crate) enum StreamEnd {
18 AfterNBytes(usize),
19 OnBlockEOF,
20}
21
22#[derive(Debug, PartialEq, Clone, Copy)]
23pub enum CarVersion {
24 V1 = 1,
25 V2 = 2,
26}
27
28#[derive(Debug)]
29pub struct CarHeader {
30 pub version: CarVersion,
31 pub roots: Vec<Cid>,
32 pub characteristics_v2: Option<u128>,
33 pub(crate) eof_stream: StreamEnd,
34}
35
36impl CarHeader {}
37
38pub(crate) fn read_car_header<R: Read>(r: &mut R) -> Result<CarHeader, CarDecodeError> {
39 let (header, _) = read_carv1_header(r)?;
40
41 match header.version {
42 1 => Ok(CarHeader {
43 version: CarVersion::V1,
44 roots: header.roots.ok_or(CarDecodeError::InvalidCarV1Header(
45 "v1 header has not roots".to_owned(),
46 ))?,
47 characteristics_v2: None,
48 eof_stream: StreamEnd::OnBlockEOF,
49 }),
50 2 => {
51 let (header_v2, (header_v1, header_v1_len)) = read_carv2_header(r)?;
52 let blocks_len = header_v2.data_size as usize - header_v1_len;
53 Ok(CarHeader {
54 version: CarVersion::V2,
55 roots: header_v1.roots.ok_or(CarDecodeError::InvalidCarV1Header(
56 "v1 header has not roots".to_owned(),
57 ))?,
58 characteristics_v2: Some(header_v2.characteristics),
59 eof_stream: StreamEnd::AfterNBytes(blocks_len),
60 })
61 }
62 _ => Err(CarDecodeError::UnsupportedCarVersion {
63 version: header.version,
64 }),
65 }
66}
67
68fn read_carv1_header<R: Read>(src: &mut R) -> Result<(CarV1Header, usize), CarDecodeError> {
72 let (header_len, varint_len) = read_varint_u64(src)?.ok_or(
74 CarDecodeError::InvalidCarV1Header("invalid header varint".to_string()),
75 )?;
76
77 if header_len > MAX_HEADER_LEN {
78 return Err(CarDecodeError::InvalidCarV1Header(format!(
79 "header len too big {}",
80 header_len
81 )));
82 }
83
84 let mut header_buf = vec![0u8; header_len as usize];
85 src.read_exact(&mut header_buf)?;
86
87 let header = decode_carv1_header(&header_buf)?;
88
89 Ok((header, header_len as usize + varint_len))
90}
91
92fn read_carv2_header<R: Read>(
93 r: &mut R,
94) -> Result<(CarV2Header, (CarV1Header, usize)), CarDecodeError> {
95 let mut header_buf = [0u8; CARV2_HEADER_SIZE];
96 r.read_exact(&mut header_buf)?;
97
98 let header_v2 = decode_carv2_header(&header_buf)?;
99
100 let padding_len = header_v2.data_offset as usize - CARV2_PRAGMA_SIZE - CARV2_HEADER_SIZE;
102 if padding_len > 0 {
103 if padding_len > MAX_PADDING_LEN {
104 return Err(CarDecodeError::InvalidCarV1Header(format!(
105 "padding len too big {}",
106 padding_len
107 )));
108 }
109 let mut padding_buf = vec![0u8; padding_len];
110 r.read_exact(&mut padding_buf)?;
111 }
112
113 let header_v1 = read_carv1_header(r)?;
115
116 Ok((header_v2, header_v1))
117}
118
119#[cfg(test)]
120mod tests {
121
122 use std::io::Cursor;
123
124 use super::*;
125 use crate::{
126 carv1_header::CarV1Header,
127 carv2_header::{CARV2_PRAGMA, CARV2_PRAGMA_SIZE},
128 };
129
130 #[test]
131 fn read_carv1_header_v2_pragma() {
132 assert_eq!(
133 read_carv1_header(&mut Cursor::new(&CARV2_PRAGMA)).unwrap(),
134 (
135 CarV1Header {
136 version: 2,
137 roots: None
138 },
139 CARV2_PRAGMA_SIZE
140 )
141 )
142 }
143}