1use std::io::{Read, Seek, SeekFrom};
6use std::mem::size_of;
7
8use crate::{
9 aligned_reader::open_volume,
10 api::*,
11 attribute::{DataRun, NtfsAttribute},
12 errors::{NtfsReaderError, NtfsReaderResult},
13 file::NtfsFile,
14 volume::Volume,
15};
16
17pub struct Mft {
18 pub volume: Volume,
19 pub data: Vec<u8>,
20 pub bitmap: Vec<u8>,
21 pub max_record: u64,
22}
23
24impl Mft {
25 pub fn new(volume: Volume) -> NtfsReaderResult<Self> {
26 let mut reader = open_volume(&volume.path)?;
27
28 let mft_record =
29 Self::get_record_fs(&mut reader, volume.file_record_size, volume.mft_position)?;
30
31 let mut data =
32 Self::read_data_fs(&volume, &mut reader, &mft_record, NtfsAttributeType::Data)?
33 .ok_or_else(|| NtfsReaderError::MissingMftAttribute("Data".to_string()))?;
34 let bitmap =
35 Self::read_data_fs(&volume, &mut reader, &mft_record, NtfsAttributeType::Bitmap)?
36 .ok_or_else(|| NtfsReaderError::MissingMftAttribute("Bitmap".to_string()))?;
37
38 let max_record = data.len() as u64 / volume.file_record_size;
39
40 for number in 0..max_record {
42 let start = number * volume.file_record_size;
43 let end = start + volume.file_record_size;
44 let (start, end) = (start as usize, end as usize);
45 let data = &mut data[start..end];
46 Self::fixup_record(number, data)?;
47 }
48
49 Ok(Mft {
50 volume,
51 data,
52 bitmap,
53 max_record,
54 })
55 }
56
57 pub fn record_exists(&self, number: u64) -> bool {
58 if number >= self.max_record {
59 return false;
60 }
61
62 let bitmap_idx = number / 8;
63 let bitmap_off = (number % 8) as u8;
64
65 if bitmap_idx >= self.bitmap.len() as u64 {
66 return false;
67 }
68
69 let bit = self.bitmap[bitmap_idx as usize];
70 (bit & (1u8 << bitmap_off)) != 0
71 }
72
73 pub fn files(&self) -> impl Iterator<Item = NtfsFile<'_>> {
74 (FIRST_NORMAL_RECORD..self.max_record)
75 .filter(|&n| self.record_exists(n))
76 .filter_map(|n| self.get_record(n))
77 .filter(|f| f.is_used())
78 }
79
80 #[deprecated(since = "0.4.5", note = "use `files()` iterator instead")]
81 pub fn iterate_files<F>(&self, mut f: F)
82 where
83 F: FnMut(&NtfsFile),
84 {
85 for file in self.files() {
86 f(&file);
87 }
88 }
89
90 fn get_record_data(&self, number: u64) -> &[u8] {
91 let start = number * self.volume.file_record_size;
92 let end = start + self.volume.file_record_size;
93 &self.data[start as usize..end as usize]
94 }
95
96 pub fn get_record(&self, number: u64) -> Option<NtfsFile<'_>> {
97 if number >= self.max_record {
98 return None;
99 }
100 let data = self.get_record_data(number);
101
102 if NtfsFile::is_valid(data) {
103 return Some(NtfsFile::new(number, data));
104 }
105
106 None
107 }
108
109 pub fn get_record_fs<R>(
110 fs: &mut R,
111 file_record_size: u64,
112 position: u64,
113 ) -> NtfsReaderResult<Vec<u8>>
114 where
115 R: Seek + Read,
116 {
117 let mut data = vec![0; file_record_size as usize];
118 fs.seek(SeekFrom::Start(position))?;
119 fs.read_exact(&mut data)?;
120
121 if !NtfsFile::is_valid(&data) {
122 return Err(NtfsReaderError::InvalidMftRecord { position });
123 }
124 Self::fixup_record(0, &mut data)?;
125 Ok(data)
126 }
127
128 pub fn read_data_fs<R>(
129 volume: &Volume,
130 reader: &mut R,
131 record: &[u8],
132 attribute_type: NtfsAttributeType,
133 ) -> NtfsReaderResult<Option<Vec<u8>>>
134 where
135 R: Seek + Read,
136 {
137 let header = unsafe { &*(record.as_ptr() as *const NtfsFileRecordHeader) };
138 let mut att_offset = header.attributes_offset as usize;
139 let used = usize::min(header.used_size as usize, record.len());
140
141 while att_offset < used {
143 let slice = &record[att_offset..used];
144 let attr = match NtfsAttribute::new(slice) {
145 Some(attr) => attr,
146 None => break,
147 };
148
149 if attr.header.type_id == NtfsAttributeType::End as u32 {
150 break;
151 }
152
153 if attr.header.type_id == attribute_type as u32 {
154 return Ok(Some(Self::read_attribute_data(reader, &attr, volume)?));
155 }
156
157 let attr_len = attr.len();
158 if attr_len == 0 {
159 break;
160 }
161 att_offset = match att_offset.checked_add(attr_len) {
162 Some(next) if next <= used => next,
163 _ => break,
164 };
165 }
166
167 att_offset = header.attributes_offset as usize;
169 while att_offset < used {
170 let slice = &record[att_offset..used];
171 let attr = match NtfsAttribute::new(slice) {
172 Some(attr) => attr,
173 None => break,
174 };
175
176 if attr.header.type_id == NtfsAttributeType::End as u32 {
177 break;
178 }
179
180 if attr.header.type_id == NtfsAttributeType::AttributeList as u32 {
181 let att_list_data = if attr.header.is_non_resident != 0 {
182 Self::read_attribute_data(reader, &attr, volume)?
183 } else {
184 match attr.as_resident_data() {
185 Some(data) => data.to_vec(),
186 None => break,
187 }
188 };
189
190 let mut list_offset = 0usize;
191
192 while list_offset < att_list_data.len() {
193 let entry_slice = &att_list_data[list_offset..];
194 let entry = match parse_attribute_list_entry(entry_slice) {
195 Some(entry) => entry,
196 None => break,
197 };
198
199 let type_id = entry.type_id;
200 let reference = entry.reference();
201 let entry_len = entry.length as usize;
202
203 if type_id == attribute_type as u32 {
204 let record_position =
205 volume.mft_position + (reference * volume.file_record_size);
206 if let Ok(target_record) =
207 Self::get_record_fs(reader, volume.file_record_size, record_position)
208 {
209 let target_header = unsafe {
210 &*(target_record.as_ptr() as *const NtfsFileRecordHeader)
211 };
212 let mut target_offset = target_header.attributes_offset as usize;
213 let target_used =
214 usize::min(target_header.used_size as usize, target_record.len());
215
216 while target_offset < target_used {
217 let target_slice = &target_record[target_offset..target_used];
218 let target_attr = match NtfsAttribute::new(target_slice) {
219 Some(attr) => attr,
220 None => break,
221 };
222
223 if target_attr.header.type_id == NtfsAttributeType::End as u32 {
224 break;
225 }
226
227 if target_attr.header.type_id == attribute_type as u32 {
228 return Ok(Some(Self::read_attribute_data(
229 reader,
230 &target_attr,
231 volume,
232 )?));
233 }
234
235 let len = target_attr.len();
236 if len == 0 {
237 break;
238 }
239 target_offset = match target_offset.checked_add(len) {
240 Some(next) if next <= target_used => next,
241 _ => break,
242 };
243 }
244 }
245 }
246
247 if entry_len == 0 {
248 break;
249 }
250 list_offset = match list_offset.checked_add(entry_len) {
251 Some(next) if next <= att_list_data.len() => next,
252 _ => break,
253 };
254 let align = (8 - (list_offset % 8)) % 8;
255 list_offset = match list_offset.checked_add(align) {
256 Some(next) if next <= att_list_data.len() => next,
257 _ => break,
258 };
259 }
260 }
261
262 let attr_len = attr.len();
263 if attr_len == 0 {
264 break;
265 }
266 att_offset = match att_offset.checked_add(attr_len) {
267 Some(next) if next <= used => next,
268 _ => break,
269 };
270 }
271
272 Ok(None)
273 }
274
275 fn read_attribute_data<R>(
276 reader: &mut R,
277 att: &NtfsAttribute,
278 volume: &Volume,
279 ) -> NtfsReaderResult<Vec<u8>>
280 where
281 R: Seek + Read,
282 {
283 if att.header.is_non_resident == 0 {
284 let data = att
285 .as_resident_data()
286 .ok_or(NtfsReaderError::InvalidDataRun {
287 details: "resident attribute missing value",
288 })?;
289 Ok(data.to_vec())
290 } else {
291 let (size, runs) = att.get_nonresident_data_runs(volume)?;
292 let total_size =
293 usize::try_from(size).map_err(|_| NtfsReaderError::AllocationTooLarge { size })?;
294
295 let mut data = Vec::new();
296 data.try_reserve(total_size)
297 .map_err(|_| NtfsReaderError::AllocationTooLarge { size })?;
298 let mut copied = 0u64;
299
300 for run in runs.iter() {
301 if copied >= size {
302 break;
303 }
304
305 let buf_size = match run {
306 DataRun::Data { lcn, length } => {
307 let buf_size = u64::min(*length, size - copied);
308 let start = data.len();
309 data.resize(start + buf_size as usize, 0u8);
310
311 reader.seek(SeekFrom::Start(*lcn))?;
312 reader.read_exact(&mut data[start..])?;
313 buf_size
314 }
315 DataRun::Sparse { length } => {
316 let buf_size = u64::min(*length, size - copied);
317 data.resize(data.len() + buf_size as usize, 0);
318 buf_size
319 }
320 };
321 copied += buf_size;
322 }
323
324 Ok(data)
325 }
326 }
327
328 fn fixup_record(record_number: u64, data: &mut [u8]) -> NtfsReaderResult<()> {
329 if data.len() < core::mem::size_of::<NtfsFileRecordHeader>() {
330 return Err(NtfsReaderError::CorruptMftRecord {
331 number: record_number,
332 });
333 }
334 let header =
335 unsafe { core::ptr::read_unaligned(data.as_ptr() as *const NtfsFileRecordHeader) };
336
337 let usn_start = header.update_sequence_offset as usize;
338 if usn_start + 2 > data.len() {
339 return Err(NtfsReaderError::CorruptMftRecord {
340 number: record_number,
341 });
342 }
343 let usa_start = usn_start + 2;
344 let usa_end =
345 usn_start.saturating_add((header.update_sequence_length as usize).saturating_mul(2));
346 if usa_end > data.len() {
347 return Err(NtfsReaderError::CorruptMftRecord {
348 number: record_number,
349 });
350 }
351
352 let usn0 = data[usn_start];
353 let usn1 = data[usn_start + 1];
354
355 let mut sector_off = SECTOR_SIZE - 2;
356 for usa_off in (usa_start..usa_end).step_by(2) {
357 if sector_off + 2 > data.len() {
358 break;
359 }
360
361 let mut usa = [0u8; 2];
362 usa.copy_from_slice(&data[usa_off..usa_off + 2]);
363
364 let d0 = data[sector_off];
365 let d1 = data[sector_off + 1];
366 if d0 != usn0 || d1 != usn1 {
367 return Err(NtfsReaderError::CorruptMftRecord {
368 number: record_number,
369 });
370 }
371
372 data[sector_off..sector_off + 2].copy_from_slice(&usa);
373 sector_off += SECTOR_SIZE;
374 }
375 Ok(())
376 }
377}
378
379fn parse_attribute_list_entry(data: &[u8]) -> Option<&NtfsAttributeListEntry> {
380 if data.len() < size_of::<NtfsAttributeListEntry>() {
381 return None;
382 }
383 let entry = unsafe { &*(data.as_ptr() as *const NtfsAttributeListEntry) };
384 let length = entry.length as usize;
385 if length < size_of::<NtfsAttributeListEntry>() || length > data.len() {
386 return None;
387 }
388 Some(entry)
389}