fmf_core\scan/
volume_io.rs1use ntfs_reader::api::NtfsAttributeType;
5use ntfs_reader::errors::NtfsReaderError;
6use ntfs_reader::file::NtfsFile;
7use ntfs_reader::mft::Mft;
8use ntfs_reader::volume::Volume;
9
10const SECTOR: usize = 512;
11
12pub(super) struct RunMap {
14 pub(super) runs: Vec<(u64, u64, u64)>,
16}
17
18impl RunMap {
19 fn from_data_runs(runs: &[ntfs_reader::attribute::DataRun]) -> Self {
20 use ntfs_reader::attribute::DataRun;
21 let mut v = Vec::with_capacity(runs.len());
22 let mut logical = 0u64;
23 for r in runs {
24 match r {
25 DataRun::Data { lcn, length } => {
26 v.push((logical, *lcn, *length));
27 logical += length;
28 }
29 DataRun::Sparse { length } => logical += length,
30 }
31 }
32 Self { runs: v }
33 }
34
35 pub(super) fn physical(&self, logical: u64) -> Option<(u64, u64)> {
37 self.runs
39 .iter()
40 .find(|(ls, _, len)| logical >= *ls && logical < ls + len)
41 .map(|(ls, ph, len)| (ph + (logical - ls), ls + len - logical))
42 }
43}
44
45pub(super) fn open_raw_volume(volume_path: &str) -> std::io::Result<std::fs::File> {
46 use std::os::windows::fs::OpenOptionsExt;
47 const FILE_SHARE_READ: u32 = 0x1;
48 const FILE_SHARE_WRITE: u32 = 0x2;
49 const FILE_SHARE_DELETE: u32 = 0x4;
50 std::fs::OpenOptions::new()
51 .read(true)
52 .share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
53 .open(volume_path)
54}
55
56pub(super) fn apply_fixup(data: &mut [u8]) -> bool {
59 if data.len() < 48 {
60 return false;
61 }
62 let uso = u16::from_le_bytes([data[4], data[5]]) as usize;
63 let usl = u16::from_le_bytes([data[6], data[7]]) as usize;
64 if usl < 2 || uso + usl * 2 > data.len() {
65 return false;
66 }
67 let usn = [data[uso], data[uso + 1]];
68 let mut sector_off = SECTOR - 2;
69 for i in 1..usl {
70 let usa_off = uso + i * 2;
71 if sector_off + 2 > data.len() {
72 break;
73 }
74 if data[sector_off] != usn[0] || data[sector_off + 1] != usn[1] {
75 return false;
76 }
77 data[sector_off] = data[usa_off];
78 data[sector_off + 1] = data[usa_off + 1];
79 sector_off += SECTOR;
80 }
81 true
82}
83
84pub(super) fn mft_layout(volume_path: &str) -> Result<(usize, u64, RunMap), NtfsReaderError> {
87 let volume = Volume::new(volume_path)?;
88 let record_size = volume.file_record_size as usize;
89 let mut reader = ntfs_reader::aligned_reader::open_volume(std::path::Path::new(volume_path))
90 .map_err(NtfsReaderError::from)?;
91 let rec0 = Mft::get_record_fs(&mut reader, volume.file_record_size, volume.mft_position)?;
92 let f0 = NtfsFile::new(0, &rec0);
93 let data_attr = f0
94 .get_attribute(NtfsAttributeType::Data)
95 .ok_or_else(|| NtfsReaderError::MissingMftAttribute("Data".to_string()))?;
96 let (size, runs) = data_attr.get_nonresident_data_runs(&volume)?;
97 Ok((record_size, size, RunMap::from_data_runs(&runs)))
98}