1use anyhow::Result;
2use byteorder::{ReadBytesExt, WriteBytesExt, BE};
3use std::io::{Read, Seek, SeekFrom, Write};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct UdifChecksum {
7 pub r#type: u32,
8 pub size: u32,
9 pub data: [u8; 128],
10}
11
12impl Default for UdifChecksum {
13 fn default() -> Self {
14 Self {
15 r#type: 2,
16 size: 32,
17 data: [0; 128],
18 }
19 }
20}
21
22impl UdifChecksum {
23 pub fn new(crc32: u32) -> Self {
24 let mut data = [0; 128];
25 data[..4].copy_from_slice(&crc32.to_be_bytes());
26 Self {
27 data,
28 ..Default::default()
29 }
30 }
31
32 pub fn from_bytes(bytes: &[u8]) -> Self {
33 Self::new(crc32fast::hash(bytes))
34 }
35
36 pub fn read_from<R: Read>(r: &mut R) -> Result<Self> {
37 let r#type = r.read_u32::<BE>()?;
38 let size = r.read_u32::<BE>()?;
39 let mut data = [0; 128];
40 r.read_exact(&mut data)?;
41 Ok(Self { r#type, size, data })
42 }
43
44 pub fn write_to<W: Write>(&self, w: &mut W) -> Result<()> {
45 w.write_u32::<BE>(self.r#type)?;
46 w.write_u32::<BE>(self.size)?;
47 w.write_all(&self.data)?;
48 Ok(())
49 }
50}
51
52impl From<UdifChecksum> for u32 {
53 fn from(checksum: UdifChecksum) -> Self {
54 let mut data = [0; 4];
55 data.copy_from_slice(&checksum.data[..4]);
56 u32::from_be_bytes(data)
57 }
58}
59
60const KOLY_SIZE: i64 = 512;
61
62#[derive(Clone, Copy, Debug, Eq, PartialEq)]
66pub struct KolyTrailer {
67 pub version: u32,
69 pub flags: u32,
71 pub running_data_fork_offset: u64,
72 pub data_fork_offset: u64,
73 pub data_fork_length: u64,
74 pub rsrc_fork_offset: u64,
75 pub rsrc_fork_length: u64,
76 pub segment_number: u32,
77 pub segment_count: u32,
78 pub segment_id: [u8; 16],
79 pub data_fork_digest: UdifChecksum,
80 pub plist_offset: u64,
81 pub plist_length: u64,
82 pub reserved1: [u8; 64],
83 pub code_signature_offset: u64,
84 pub code_signature_size: u64,
85 pub reserved2: [u8; 40],
86 pub main_digest: UdifChecksum,
87 pub image_variant: u32,
88 pub sector_count: u64,
89 pub reserved3: [u8; 12],
90}
91
92impl Default for KolyTrailer {
93 fn default() -> Self {
94 Self {
95 version: 4,
96 flags: 1,
97 running_data_fork_offset: 0,
98 data_fork_offset: 0,
99 data_fork_length: 0,
100 rsrc_fork_offset: 0,
101 rsrc_fork_length: 0,
102 segment_number: 1,
103 segment_count: 1,
104 segment_id: [0; 16],
105 data_fork_digest: UdifChecksum::default(),
106 plist_offset: 0,
107 plist_length: 0,
108 reserved1: [0; 64],
109 code_signature_offset: 0,
110 code_signature_size: 0,
111 reserved2: [0; 40],
112 main_digest: UdifChecksum::default(),
113 image_variant: 1,
114 sector_count: 0,
115 reserved3: [0; 12],
116 }
117 }
118}
119
120impl KolyTrailer {
121 pub fn new(
122 bytes: u64,
123 sectors: u64,
124 plist_offset: u64,
125 plist_length: u64,
126 data_digest: u32,
127 main_digest: u32,
128 ) -> Self {
129 let mut segment_id = [0; 16];
130 getrandom::getrandom(&mut segment_id).unwrap();
131 Self {
132 data_fork_length: bytes,
133 sector_count: sectors,
134 plist_offset,
135 plist_length,
136 data_fork_digest: UdifChecksum::new(data_digest),
137 main_digest: UdifChecksum::new(main_digest),
138 segment_id,
139 ..Default::default()
140 }
141 }
142
143 pub fn read_from<R: Read + Seek>(r: &mut R) -> Result<Self> {
147 r.seek(SeekFrom::End(-KOLY_SIZE))?;
148
149 let mut signature = [0; 4];
150 r.read_exact(&mut signature)?;
151 anyhow::ensure!(&signature == b"koly");
152 let version = r.read_u32::<BE>()?;
153 let header_size = r.read_u32::<BE>()?;
154 anyhow::ensure!(header_size == 512);
155 let flags = r.read_u32::<BE>()?;
156 let running_data_fork_offset = r.read_u64::<BE>()?;
157 let data_fork_offset = r.read_u64::<BE>()?;
158 let data_fork_length = r.read_u64::<BE>()?;
159 let rsrc_fork_offset = r.read_u64::<BE>()?;
160 let rsrc_fork_length = r.read_u64::<BE>()?;
161 let segment_number = r.read_u32::<BE>()?;
162 let segment_count = r.read_u32::<BE>()?;
163 let mut segment_id = [0; 16];
164 r.read_exact(&mut segment_id)?;
165 let data_fork_digest = UdifChecksum::read_from(r)?;
166 let plist_offset = r.read_u64::<BE>()?;
167 let plist_length = r.read_u64::<BE>()?;
168 let mut reserved1 = [0; 64];
169 r.read_exact(&mut reserved1)?;
170 let code_signature_offset = r.read_u64::<BE>()?;
171 let code_signature_size = r.read_u64::<BE>()?;
172 let mut reserved2 = [0; 40];
173 r.read_exact(&mut reserved2)?;
174 let main_digest = UdifChecksum::read_from(r)?;
175 let image_variant = r.read_u32::<BE>()?;
176 let sector_count = r.read_u64::<BE>()?;
177 let mut reserved3 = [0; 12];
178 r.read_exact(&mut reserved3)?;
179 Ok(Self {
180 version,
181 flags,
182 running_data_fork_offset,
183 data_fork_offset,
184 data_fork_length,
185 rsrc_fork_offset,
186 rsrc_fork_length,
187 segment_number,
188 segment_count,
189 segment_id,
190 data_fork_digest,
191 plist_offset,
192 plist_length,
193 reserved1,
194 code_signature_offset,
195 code_signature_size,
196 reserved2,
197 main_digest,
198 image_variant,
199 sector_count,
200 reserved3,
201 })
202 }
203
204 pub fn write_to<W: Write>(&self, w: &mut W) -> Result<()> {
205 w.write_all(b"koly")?;
206 w.write_u32::<BE>(self.version)?;
207 w.write_u32::<BE>(KOLY_SIZE as u32)?;
208 w.write_u32::<BE>(self.flags)?;
209 w.write_u64::<BE>(self.running_data_fork_offset)?;
210 w.write_u64::<BE>(self.data_fork_offset)?;
211 w.write_u64::<BE>(self.data_fork_length)?;
212 w.write_u64::<BE>(self.rsrc_fork_offset)?;
213 w.write_u64::<BE>(self.rsrc_fork_length)?;
214 w.write_u32::<BE>(self.segment_number)?;
215 w.write_u32::<BE>(self.segment_count)?;
216 w.write_all(&self.segment_id)?;
217 self.data_fork_digest.write_to(w)?;
218 w.write_u64::<BE>(self.plist_offset)?;
219 w.write_u64::<BE>(self.plist_length)?;
220 w.write_all(&self.reserved1)?;
221 w.write_u64::<BE>(self.code_signature_offset)?;
222 w.write_u64::<BE>(self.code_signature_size)?;
223 w.write_all(&self.reserved2)?;
224 self.main_digest.write_to(w)?;
225 w.write_u32::<BE>(self.image_variant)?;
226 w.write_u64::<BE>(self.sector_count)?;
227 w.write_all(&self.reserved3)?;
228 Ok(())
229 }
230}