1use crate::attribute::{AttributeDataFlags, MftAttributeType};
2use crate::err::{Error, Result};
3use crate::utils::read_utf16_string;
4
5use byteorder::{LittleEndian, ReadBytesExt};
6use num_traits::FromPrimitive;
7use serde::Serialize;
8use std::io::{Read, Seek, SeekFrom};
9
10#[derive(Serialize, Clone, Debug)]
13pub struct MftAttributeHeader {
14 pub type_code: MftAttributeType,
15 pub record_length: u32,
18 pub form_code: u8,
21 pub residential_header: ResidentialHeader,
22 pub name_size: u8,
25 pub name_offset: Option<u16>,
28 pub data_flags: AttributeDataFlags,
29 pub instance: u16,
31 pub name: String,
32}
33
34#[derive(Serialize, Clone, Debug)]
35#[serde(untagged)]
36pub enum ResidentialHeader {
37 Resident(ResidentHeader),
38 NonResident(NonResidentHeader),
39}
40
41impl MftAttributeHeader {
42 pub fn from_stream<S: Read + Seek>(stream: &mut S) -> Result<Option<MftAttributeHeader>> {
45 let attribute_header_start_offset = stream.stream_position()?;
46
47 let type_code_value = stream.read_u32::<LittleEndian>()?;
48
49 if type_code_value == 0xFFFF_FFFF {
50 return Ok(None);
51 }
52
53 let type_code = match MftAttributeType::from_u32(type_code_value) {
54 Some(attribute_type) => attribute_type,
55 None => {
56 return Err(Error::UnknownAttributeType {
57 attribute_type: type_code_value,
58 })
59 }
60 };
61
62 let attribute_size = stream.read_u32::<LittleEndian>()?;
63 let resident_flag = stream.read_u8()?;
64 let name_size = stream.read_u8()?;
65 let name_offset = {
66 let value = stream.read_u16::<LittleEndian>()?;
68 if name_size > 0 {
69 Some(value)
70 } else {
71 None
72 }
73 };
74
75 let data_flags = AttributeDataFlags::from_bits_truncate(stream.read_u16::<LittleEndian>()?);
76 let id = stream.read_u16::<LittleEndian>()?;
77
78 let residential_header = match resident_flag {
79 0 => ResidentialHeader::Resident(ResidentHeader::from_stream(stream)?),
80 1 => ResidentialHeader::NonResident(NonResidentHeader::from_stream(stream)?),
81 _ => {
82 return Err(Error::UnhandledResidentFlag {
83 flag: resident_flag,
84 offset: stream.stream_position()?,
85 })
86 }
87 };
88
89 let name = if name_size > 0 {
91 stream.seek(SeekFrom::Start(
92 attribute_header_start_offset
93 + u64::from(name_offset.expect("name_size > 0 is invariant")),
94 ))?;
95 read_utf16_string(stream, Some(name_size as usize))?
96 } else {
97 String::new()
98 };
99
100 Ok(Some(MftAttributeHeader {
101 type_code,
102 record_length: attribute_size,
103 form_code: resident_flag,
104 name_size,
105 name_offset,
106 data_flags,
107 instance: id,
108 name,
109 residential_header,
110 }))
111 }
112}
113
114#[derive(Serialize, Clone, Debug)]
115pub struct ResidentHeader {
116 #[serde(skip_serializing)]
117 pub data_size: u32,
119 #[serde(skip_serializing)]
120 pub data_offset: u16,
122 pub index_flag: u8,
123 #[serde(skip_serializing)]
124 pub padding: u8,
125}
126
127impl ResidentHeader {
128 pub fn from_stream<R: Read>(reader: &mut R) -> Result<ResidentHeader> {
129 Ok(ResidentHeader {
130 data_size: reader.read_u32::<LittleEndian>()?,
131 data_offset: reader.read_u16::<LittleEndian>()?,
132 index_flag: reader.read_u8()?,
133 padding: reader.read_u8()?,
134 })
135 }
136}
137
138#[derive(Serialize, Clone, Debug)]
139pub struct NonResidentHeader {
140 pub vnc_first: u64,
142 pub vnc_last: u64,
144 #[serde(skip_serializing)]
145 pub datarun_offset: u16,
147 pub unit_compression_size: u16,
149 #[serde(skip_serializing)]
150 pub padding: u32,
151
152 pub allocated_length: u64,
156 pub file_size: u64,
157 pub valid_data_length: u64,
160 pub total_allocated: Option<u64>,
161}
162
163impl NonResidentHeader {
164 pub fn from_stream<R: Read>(reader: &mut R) -> Result<NonResidentHeader> {
165 let vnc_first = reader.read_u64::<LittleEndian>()?;
166 let vnc_last = reader.read_u64::<LittleEndian>()?;
167 let datarun_offset = reader.read_u16::<LittleEndian>()?;
168 let unit_compression_size = reader.read_u16::<LittleEndian>()?;
169 let padding = reader.read_u32::<LittleEndian>()?;
170 let allocated_length = reader.read_u64::<LittleEndian>()?;
171 let file_size = reader.read_u64::<LittleEndian>()?;
172 let valid_data_length = reader.read_u64::<LittleEndian>()?;
173
174 let total_allocated = if unit_compression_size > 0 {
175 Some(reader.read_u64::<LittleEndian>()?)
176 } else {
177 None
178 };
179
180 Ok(NonResidentHeader {
181 vnc_first,
182 vnc_last,
183 datarun_offset,
184 unit_compression_size,
185 padding,
186 allocated_length,
187 file_size,
188 valid_data_length,
189 total_allocated,
190 })
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::MftAttributeHeader;
197 use crate::attribute::MftAttributeType;
198 use std::io::Cursor;
199
200 #[test]
201 fn attribute_test_01_resident() {
202 let raw: &[u8] = &[
203 0x10, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
205 ];
206
207 let mut cursor = Cursor::new(raw);
208
209 let attribute_header = MftAttributeHeader::from_stream(&mut cursor)
210 .expect("Should not be $End")
211 .expect("Shold parse correctly");
212
213 assert_eq!(
214 attribute_header.type_code,
215 MftAttributeType::StandardInformation
216 );
217 assert_eq!(attribute_header.record_length, 96);
218 assert_eq!(attribute_header.form_code, 0);
219 assert_eq!(attribute_header.name_size, 0);
220 assert_eq!(attribute_header.name_offset, None);
221 }
222
223 #[test]
224 fn attribute_test_01_nonresident() {
225 let raw: &[u8] = &[
226 0x80, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00,
227 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x1E, 0x01, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0xEC, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x11, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0xEC, 0x11, 0x00, 0x00, 0x00, 0x00, 0x33, 0x20, 0xC8, 0x00, 0x00, 0x00,
231 0x0C, 0x32, 0xA0, 0x56, 0xE3, 0xE6, 0x24, 0x00, 0xFF, 0xFF,
232 ];
233
234 let mut cursor = Cursor::new(raw);
235
236 let attribute_header = MftAttributeHeader::from_stream(&mut cursor)
237 .expect("Should not be $End")
238 .expect("Shold parse correctly");
239
240 assert_eq!(attribute_header.type_code, MftAttributeType::DATA);
241 assert_eq!(attribute_header.record_length, 80);
242 assert_eq!(attribute_header.form_code, 1);
243 assert_eq!(attribute_header.name_size, 0);
244 assert_eq!(attribute_header.name_offset, None);
245 }
246}