Skip to main content

zipatch_rs/chunk/
afsp.rs

1use binrw::BinRead;
2use std::io::Cursor;
3
4/// `APFS` chunk: free-space book-keeping; ignored at apply time.
5#[derive(BinRead, Debug, Clone, PartialEq, Eq)]
6#[br(big)]
7pub struct ApplyFreeSpace {
8    /// First 8-byte value (purpose undocumented in the wire format).
9    #[br(map = |x: u64| x as i64)]
10    pub unknown_a: i64,
11    /// Second 8-byte value (purpose undocumented in the wire format).
12    #[br(map = |x: u64| x as i64)]
13    pub unknown_b: i64,
14}
15
16pub(crate) fn parse(body: &[u8]) -> crate::Result<ApplyFreeSpace> {
17    Ok(ApplyFreeSpace::read_be(&mut Cursor::new(body))?)
18}
19
20#[cfg(test)]
21mod tests {
22    use super::parse;
23
24    #[test]
25    fn parses_apply_free_space() {
26        let mut body = Vec::new();
27        body.extend_from_slice(&0x8000000000000000u64.to_be_bytes()); // high bit → i64::MIN
28        body.extend_from_slice(&1u64.to_be_bytes());
29        let cmd = parse(&body).unwrap();
30        assert_eq!(cmd.unknown_a, i64::MIN);
31        assert_eq!(cmd.unknown_b, 1);
32    }
33
34    #[test]
35    fn rejects_truncated_body() {
36        // 16-byte body needed (two u64); supply only 8 to trigger the `?` error arm.
37        assert!(parse(&[0u8; 8]).is_err());
38    }
39}