|
6 | 6 |
|
7 | 7 | use crate::{Error, Kind, Superblock}; |
8 | 8 | use log; |
9 | | -use std::{ |
10 | | - io::{self, Read}, |
11 | | - slice, |
12 | | -}; |
| 9 | +use std::io::{self, Read}; |
13 | 10 | use uuid::Uuid; |
| 11 | +use zerocopy::*; |
14 | 12 |
|
15 | 13 | /// EXT4 Superblock definition (as seen in the kernel) |
16 | | -#[derive(Debug)] |
| 14 | +#[derive(Debug, FromBytes)] |
17 | 15 | #[repr(C)] |
18 | 16 | pub struct Ext4 { |
19 | | - inodes_count: u32, |
20 | | - block_counts_lo: u32, |
21 | | - r_blocks_count_lo: u32, |
22 | | - free_blocks_count_lo: u32, |
23 | | - free_inodes_count: u32, |
24 | | - first_data_block: u32, |
25 | | - log_block_size: u32, |
26 | | - log_cluster_size: u32, |
27 | | - blocks_per_group: u32, |
28 | | - clusters_per_group: u32, |
29 | | - inodes_per_group: u32, |
30 | | - m_time: u32, |
31 | | - w_time: u32, |
32 | | - mnt_count: u16, |
33 | | - max_mnt_count: u16, |
34 | | - magic: u16, |
35 | | - state: u16, |
36 | | - errors: u16, |
37 | | - minor_rev_level: u16, |
38 | | - lastcheck: u32, |
39 | | - checkinterval: u32, |
40 | | - creator_os: u32, |
41 | | - rev_level: u32, |
42 | | - def_resuid: u16, |
43 | | - def_resgid: u16, |
44 | | - first_ino: u32, |
45 | | - inode_size: u16, |
46 | | - block_group_nr: u16, |
47 | | - feature_compat: u32, |
48 | | - feature_incompat: u32, |
49 | | - feature_ro_compat: u32, |
| 17 | + inodes_count: U32<LittleEndian>, |
| 18 | + block_counts_lo: U32<LittleEndian>, |
| 19 | + r_blocks_count_lo: U32<LittleEndian>, |
| 20 | + free_blocks_count_lo: U32<LittleEndian>, |
| 21 | + free_inodes_count: U32<LittleEndian>, |
| 22 | + first_data_block: U32<LittleEndian>, |
| 23 | + log_block_size: U32<LittleEndian>, |
| 24 | + log_cluster_size: U32<LittleEndian>, |
| 25 | + blocks_per_group: U32<LittleEndian>, |
| 26 | + clusters_per_group: U32<LittleEndian>, |
| 27 | + inodes_per_group: U32<LittleEndian>, |
| 28 | + m_time: U32<LittleEndian>, |
| 29 | + w_time: U32<LittleEndian>, |
| 30 | + mnt_count: U16<LittleEndian>, |
| 31 | + max_mnt_count: U16<LittleEndian>, |
| 32 | + magic: U16<LittleEndian>, |
| 33 | + state: U16<LittleEndian>, |
| 34 | + errors: U16<LittleEndian>, |
| 35 | + minor_rev_level: U16<LittleEndian>, |
| 36 | + lastcheck: U32<LittleEndian>, |
| 37 | + checkinterval: U32<LittleEndian>, |
| 38 | + creator_os: U32<LittleEndian>, |
| 39 | + rev_level: U32<LittleEndian>, |
| 40 | + def_resuid: U16<LittleEndian>, |
| 41 | + def_resgid: U16<LittleEndian>, |
| 42 | + first_ino: U32<LittleEndian>, |
| 43 | + inode_size: U16<LittleEndian>, |
| 44 | + block_group_nr: U16<LittleEndian>, |
| 45 | + feature_compat: U32<LittleEndian>, |
| 46 | + feature_incompat: U32<LittleEndian>, |
| 47 | + feature_ro_compat: U32<LittleEndian>, |
50 | 48 | uuid: [u8; 16], |
51 | 49 | volume_name: [u8; 16], |
52 | 50 | last_mounted: [u8; 64], |
53 | | - algorithm_usage_bitmap: u32, |
| 51 | + algorithm_usage_bitmap: U32<LittleEndian>, |
54 | 52 | prealloc_blocks: u8, |
55 | 53 | prealloc_dir_blocks: u8, |
56 | | - reserved_gdt_blocks: u16, |
| 54 | + reserved_gdt_blocks: U16<LittleEndian>, |
57 | 55 | journal_uuid: [u8; 16], |
58 | | - journal_inum: u32, |
59 | | - journal_dev: u32, |
60 | | - last_orphan: u32, |
61 | | - hash_seed: [u32; 4], |
| 56 | + journal_inum: U32<LittleEndian>, |
| 57 | + journal_dev: U32<LittleEndian>, |
| 58 | + last_orphan: U32<LittleEndian>, |
| 59 | + hash_seed: [U32<LittleEndian>; 4], |
62 | 60 | def_hash_version: u8, |
63 | 61 | jnl_backup_type: u8, |
64 | | - desc_size: u16, |
65 | | - default_mount_opts: u32, |
66 | | - first_meta_bg: u32, |
67 | | - mkfs_time: u32, |
68 | | - jnl_blocks: [u32; 17], |
69 | | - blocks_count_hi: u32, |
70 | | - free_blocks_count_hi: u32, |
71 | | - min_extra_isize: u16, |
72 | | - want_extra_isize: u16, |
73 | | - flags: u32, |
74 | | - raid_stride: u16, |
75 | | - mmp_update_interval: u16, |
76 | | - mmp_block: u64, |
77 | | - raid_stripe_width: u32, |
| 62 | + desc_size: U16<LittleEndian>, |
| 63 | + default_mount_opts: U32<LittleEndian>, |
| 64 | + first_meta_bg: U32<LittleEndian>, |
| 65 | + mkfs_time: U32<LittleEndian>, |
| 66 | + jnl_blocks: [U32<LittleEndian>; 17], |
| 67 | + blocks_count_hi: U32<LittleEndian>, |
| 68 | + free_blocks_count_hi: U32<LittleEndian>, |
| 69 | + min_extra_isize: U16<LittleEndian>, |
| 70 | + want_extra_isize: U16<LittleEndian>, |
| 71 | + flags: U32<LittleEndian>, |
| 72 | + raid_stride: U16<LittleEndian>, |
| 73 | + mmp_update_interval: U16<LittleEndian>, |
| 74 | + mmp_block: U64<LittleEndian>, |
| 75 | + raid_stripe_width: U32<LittleEndian>, |
78 | 76 | log_groups_per_flex: u8, |
79 | 77 | checksum_type: u8, |
80 | | - reserved_pad: u16, |
81 | | - kbytes_written: u64, |
82 | | - snapshot_inum: u32, |
83 | | - snapshot_id: u32, |
84 | | - snapshot_r_blocks_count: u64, |
85 | | - snapshot_list: u32, |
86 | | - error_count: u32, |
87 | | - first_error_time: u32, |
88 | | - first_error_inod: u32, |
89 | | - first_error_block: u64, |
| 78 | + reserved_pad: U16<LittleEndian>, |
| 79 | + kbytes_written: U64<LittleEndian>, |
| 80 | + snapshot_inum: U32<LittleEndian>, |
| 81 | + snapshot_id: U32<LittleEndian>, |
| 82 | + snapshot_r_blocks_count: U64<LittleEndian>, |
| 83 | + snapshot_list: U32<LittleEndian>, |
| 84 | + error_count: U32<LittleEndian>, |
| 85 | + first_error_time: U32<LittleEndian>, |
| 86 | + first_error_inod: U32<LittleEndian>, |
| 87 | + first_error_block: U64<LittleEndian>, |
90 | 88 | first_error_func: [u8; 32], |
91 | | - first_error_line: u32, |
92 | | - last_error_time: u32, |
93 | | - last_error_inod: u32, |
94 | | - last_error_line: u32, |
95 | | - last_error_block: u64, |
| 89 | + first_error_line: U32<LittleEndian>, |
| 90 | + last_error_time: U32<LittleEndian>, |
| 91 | + last_error_inod: U32<LittleEndian>, |
| 92 | + last_error_line: U32<LittleEndian>, |
| 93 | + last_error_block: U64<LittleEndian>, |
96 | 94 | last_error_func: [u8; 32], |
97 | 95 | mount_opts: [u8; 64], |
98 | | - usr_quota_inum: u32, |
99 | | - grp_quota_inum: u32, |
100 | | - overhead_clusters: u32, |
101 | | - reserved: [u32; 108], |
102 | | - checksum: u32, |
| 96 | + usr_quota_inum: U32<LittleEndian>, |
| 97 | + grp_quota_inum: U32<LittleEndian>, |
| 98 | + overhead_clusters: U32<LittleEndian>, |
| 99 | + reserved: [U32<LittleEndian>; 108], |
| 100 | + checksum: U32<LittleEndian>, |
103 | 101 | } |
104 | 102 |
|
105 | | -const MAGIC: u16 = 0xEF53; |
| 103 | +const MAGIC: U16<LittleEndian> = U16::new(0xEF53); |
106 | 104 | const START_POSITION: u64 = 1024; |
107 | 105 |
|
108 | 106 | /// Attempt to decode the Superblock from the given read stream |
109 | 107 | pub fn from_reader<R: Read>(reader: &mut R) -> Result<Ext4, Error> { |
110 | | - const SIZE: usize = std::mem::size_of::<Ext4>(); |
111 | | - let mut data: Ext4 = unsafe { std::mem::zeroed() }; |
112 | | - let data_sliced = unsafe { slice::from_raw_parts_mut(&mut data as *mut _ as *mut u8, SIZE) }; |
113 | | - |
114 | 108 | // Drop unwanted bytes (Seek not possible with zstd streamed inputs) |
115 | 109 | io::copy(&mut reader.by_ref().take(START_POSITION), &mut io::sink())?; |
116 | | - reader.read_exact(data_sliced)?; |
| 110 | + |
| 111 | + let data = Ext4::read_from_io(reader).map_err(|_| Error::InvalidSuperblock)?; |
117 | 112 |
|
118 | 113 | if data.magic != MAGIC { |
119 | 114 | Err(Error::InvalidMagic) |
@@ -150,7 +145,7 @@ mod tests { |
150 | 145 |
|
151 | 146 | use crate::{ext4::from_reader, Superblock}; |
152 | 147 |
|
153 | | - #[test] |
| 148 | + #[test_log::test] |
154 | 149 | fn test_basic() { |
155 | 150 | let mut fi = fs::File::open("tests/ext4.img.zst").expect("cannot open ext4 img"); |
156 | 151 | let mut stream = zstd::stream::Decoder::new(&mut fi).expect("Unable to decode stream"); |
|
0 commit comments