squashfs/
fragment.rs

1use super::*;
2use byteorder::{ByteOrder, LittleEndian};
3use std::io::{Read, Result, SeekFrom};
4use std::mem;
5
6///
7#[derive(Default, Debug)]
8pub struct FragmentsTab {
9  pub entries: Vec<FragmentEntry>,
10}
11
12#[derive(Default, Debug)]
13pub struct FragmentEntry {
14  pub start: u64,
15  pub size: u32,
16  pub compressed: bool,
17}
18
19#[repr(C)]
20#[derive(Default, Debug)]
21struct FragmentEntryInternal {
22  start: u64,
23  size: u32,
24  _padding: u32,
25}
26
27impl_converter!(FragmentEntryInternal);
28
29pub const FRAGMENT_SIZE: usize = mem::size_of::<FragmentEntryInternal>();
30pub const UNCOMPRESSED_FRAGMENT_FLAG: u32 = 0x1000_000;
31
32pub fn read_fragment_table(r: &mut SqsIoReader, sb: Superblock) -> Result<FragmentsTab> {
33  let mut blocks = sb.fragment_entry_count / 512;
34  if sb.fragment_entry_count % 512 > 0 {
35    blocks += 1;
36  }
37
38  let mut tab = FragmentsTab::default();
39  r.seek(SeekFrom::Start(sb.fragment_table_start))?;
40  let mut buf = [0u8; 8];
41  while blocks > 0 {
42    r.read_exact(&mut buf)?;
43
44    trace!("block={} buf={:?}", blocks, buf);
45
46    let offset = LittleEndian::read_u64(&buf);
47    let (metadata, _) = read_meta_block(r, sb.compressor, offset)?;
48
49    let total = metadata.len() / FRAGMENT_SIZE;
50    let mut idx = 0;
51    while idx < total {
52      let start = idx * FRAGMENT_SIZE;
53      let end = (idx + 1) * FRAGMENT_SIZE;
54      let fragment = parse_fragment(&mut &metadata[start..end])?;
55      tab.entries.push(fragment);
56      idx = idx + 1;
57    }
58
59    debug!(
60      "[read_fragment_table] total={}, parsed={}",
61      total,
62      tab.entries.len()
63    );
64
65    trace!("[read_fragment_table] parsed.fragment={:?}", tab.entries);
66
67    blocks -= 1;
68  }
69
70  Ok(tab)
71}
72
73fn is_uncompressed_fragment(s: u32) -> bool {
74  s & UNCOMPRESSED_FRAGMENT_FLAG == UNCOMPRESSED_FRAGMENT_FLAG
75}
76
77fn parse_fragment(metadata: &mut &[u8]) -> Result<FragmentEntry> {
78  if metadata.len() != FRAGMENT_SIZE {
79    return Err(invalid_error!("invalid fragment data, should has 16 bytes"));
80  }
81  trace!("[parse_fragment] bytes={:x?}, {:x?}", metadata, 1 << 24);
82  let mut internal = FragmentEntryInternal::default();
83  metadata.read_exact(&mut internal.as_mut())?;
84
85  Ok(FragmentEntry {
86    start: internal.start,
87    size: internal.size,
88    compressed: !is_uncompressed_fragment(internal.size),
89  })
90}
91
92#[cfg(test)]
93mod tests {
94  use crate::tests::*;
95  use crate::*;
96  use std::io::Result;
97
98  #[test]
99  #[cfg_attr(not(feature = "gzip-sqs"), ignore)]
100  fn test_read_fragment_table() -> Result<()> {
101    prepare_tests()?;
102    let (mut reader, sb) = prepare_tests()?;
103    read_fragment_table(&mut reader, sb)?;
104
105    Ok(())
106  }
107}