Skip to content

Commit 776ea71

Browse files
authored
Added pbs parser for disk info (#24)
* refactoring reader * added pbs parser * fixing clippy
1 parent 2f7ebd3 commit 776ea71

File tree

3 files changed

+199
-31
lines changed

3 files changed

+199
-31
lines changed

Diff for: src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod cli;
1212
mod errors;
1313
mod reader;
1414
mod undelete_entry;
15+
mod util;
1516

1617
fn main() -> Result<()> {
1718
env_logger::builder()

Diff for: src/reader.rs

+34-31
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
use log::info;
12
use mft::{
23
attribute::{
34
non_resident_attr::NonResidentAttr, x80::DataAttr, MftAttributeContent, MftAttributeType,
45
},
56
MftEntry,
67
};
78

8-
use crate::errors::Result;
9+
use crate::{
10+
errors::Result,
11+
util::{detect_file_system, FileSystems},
12+
};
913
use std::{
1014
fs::File,
1115
io::{BufRead, BufReader, Read, Seek, SeekFrom},
@@ -15,14 +19,6 @@ use std::{
1519
#[derive(Debug)]
1620
pub struct Reader {
1721
path: PathBuf,
18-
reader_type: ReaderType,
19-
}
20-
21-
#[derive(Debug)]
22-
enum ReaderType {
23-
Directory,
24-
Image,
25-
BlockDevice,
2622
}
2723

2824
const CLUSTER_SIZE: usize = 4096; // 4 KiB
@@ -31,31 +27,48 @@ const SIGNATURES: [&[u8]; 3] = [b"FILE", b"BAAD", b"0000"];
3127

3228
impl Reader {
3329
pub fn from_path(path: PathBuf) -> Result<Self> {
34-
let reader_type = if path.is_dir() {
35-
ReaderType::Directory
30+
let path = if path.is_dir() {
31+
let configued_path =
32+
find_block_device(&path)?.ok_or_else(|| crate::errors::Error::Any {
33+
detail: "Couldn't find block device for directory".to_string(),
34+
})?;
35+
info!(
36+
"Running in dir mode, will map to block device: {}",
37+
configued_path.display()
38+
);
39+
configued_path
3640
} else if path.is_file() {
37-
ReaderType::Image
41+
info!("Running in image mode");
42+
path
3843
} else if path.starts_with("/dev/") {
39-
ReaderType::BlockDevice
44+
info!("Running in block mode");
45+
path
4046
} else {
4147
return Err(crate::errors::Error::FailedToOpenFile {
4248
path,
4349
source: std::io::Error::new(std::io::ErrorKind::NotFound, "File not found"),
4450
});
4551
};
4652

47-
Ok(Self { path, reader_type })
53+
let boot_sector = match detect_file_system(&path)? {
54+
FileSystems::Ntfs(boot_sector) => boot_sector,
55+
fs => {
56+
return Err(crate::errors::Error::Any {
57+
detail: format!("Detected an unsupported file system: {}", fs),
58+
})
59+
}
60+
};
61+
62+
info!("Parsed boot sector: \n{:#?}", boot_sector);
63+
64+
Ok(Self { path })
4865
}
4966

5067
pub fn read_mft(&self) -> Result<Vec<u8>> {
51-
match self.reader_type {
52-
ReaderType::Directory => self.read_mft_dir(),
53-
ReaderType::Image => self.read_mft_bytes(),
54-
ReaderType::BlockDevice => self.read_mft_bytes(),
55-
}
68+
self.read_mft_bytes()
5669
}
5770

58-
fn read_mft_dir(&self) -> Result<Vec<u8>> {
71+
fn _read_mft_dir(&self) -> Result<Vec<u8>> {
5972
let path = self.path.join("$MFT");
6073

6174
if !path.exists() {
@@ -115,17 +128,7 @@ impl Reader {
115128
}
116129

117130
fn read_from_data_run(&self, data: NonResidentAttr) -> Result<Vec<u8>> {
118-
let mut file = match self.reader_type {
119-
ReaderType::Directory => {
120-
let block_device = find_block_device(&self.path)?;
121-
let block_device = block_device.ok_or_else(|| crate::errors::Error::Any {
122-
detail: "Couldn't find block device for directory".to_string(),
123-
})?;
124-
125-
File::open(block_device)?
126-
}
127-
_ => File::open(&self.path)?,
128-
};
131+
let mut file = File::open(&self.path)?;
129132
let mut bytes = vec![];
130133
for dr in data.data_runs {
131134
let mut cluster = vec![0; dr.lcn_length as usize * CLUSTER_SIZE];

Diff for: src/util.rs

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use crate::errors::Result;
2+
use std::{
3+
fmt::Display,
4+
fs::File,
5+
io::{Read, Seek},
6+
path::Path,
7+
};
8+
#[derive(PartialEq, Clone)]
9+
pub enum FileSystems {
10+
Ntfs(NtfsBootSector),
11+
Fat,
12+
Ext,
13+
Iso9660,
14+
Hfs,
15+
Unknown,
16+
}
17+
18+
impl From<FileSystems> for &str {
19+
fn from(value: FileSystems) -> Self {
20+
match value {
21+
FileSystems::Ntfs(_) => "Ntfs",
22+
FileSystems::Fat => "Fat",
23+
FileSystems::Ext => "Ext",
24+
FileSystems::Iso9660 => "Iso9660",
25+
FileSystems::Hfs => "Hfs",
26+
FileSystems::Unknown => "Unknown",
27+
}
28+
}
29+
}
30+
31+
impl Display for FileSystems {
32+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33+
f.write_str(self.clone().into())
34+
}
35+
}
36+
37+
pub fn detect_file_system<P>(path: P) -> Result<FileSystems>
38+
where
39+
P: AsRef<Path>,
40+
{
41+
let mut file = File::open(path)?;
42+
let mut boot_sector = [0u8; 512];
43+
44+
file.read_exact(&mut boot_sector)?;
45+
46+
if &boot_sector[3..7] == b"Ntfs" {
47+
return Ok(FileSystems::Ntfs(NtfsBootSector::from_bytes(&boot_sector)?));
48+
}
49+
50+
if &boot_sector[36..39] == b"Fat" {
51+
return Ok(FileSystems::Fat);
52+
}
53+
54+
if &boot_sector[0..2] == b"H+" || &boot_sector[0..4] == b"HfsJ" || &boot_sector[0..4] == b"Hfs+"
55+
{
56+
return Ok(FileSystems::Hfs);
57+
}
58+
59+
if &boot_sector[56..58] == b"\x53\xEF" {
60+
return Ok(FileSystems::Ext);
61+
}
62+
63+
let mut iso_buffer = [0u8; 5];
64+
file.seek(std::io::SeekFrom::Start(32769))?;
65+
file.read_exact(&mut iso_buffer)?;
66+
67+
if &iso_buffer[..] == b"CD001" {
68+
return Ok(FileSystems::Iso9660);
69+
}
70+
71+
Ok(FileSystems::Unknown)
72+
}
73+
74+
#[derive(Debug, Clone, PartialEq)]
75+
pub struct NtfsBootSector {
76+
oem_id: String,
77+
bytes_per_sector: u16,
78+
sectors_per_cluster: u8,
79+
reserved_sectors: u16,
80+
media_descriptor: u8,
81+
sectors_per_track: u16,
82+
num_heads: u16,
83+
hidden_sectors: u32,
84+
total_sectors: u64,
85+
logical_cluster_mft: u64,
86+
logical_cluster_mft_mirror: u64,
87+
clusters_per_file_record_segment: u32,
88+
clusters_per_index_buffer: u8,
89+
volume_serial_number: u64,
90+
checksum: u32,
91+
}
92+
93+
impl NtfsBootSector {
94+
fn from_bytes(boot_sector_data: &[u8]) -> Result<Self> {
95+
Ok(Self {
96+
oem_id: String::from_utf8_lossy(&boot_sector_data[3..11]).to_string(),
97+
bytes_per_sector: u16::from_le_bytes([boot_sector_data[0x0B], boot_sector_data[0x0C]]),
98+
sectors_per_cluster: boot_sector_data[0x0D],
99+
reserved_sectors: u16::from_le_bytes([boot_sector_data[0x0E], boot_sector_data[0x0F]]),
100+
media_descriptor: boot_sector_data[0x15],
101+
sectors_per_track: u16::from_le_bytes([boot_sector_data[0x18], boot_sector_data[0x19]]),
102+
num_heads: u16::from_le_bytes([boot_sector_data[0x1A], boot_sector_data[0x1B]]),
103+
hidden_sectors: u32::from_le_bytes([
104+
boot_sector_data[0x1C],
105+
boot_sector_data[0x1D],
106+
boot_sector_data[0x1E],
107+
boot_sector_data[0x1F],
108+
]),
109+
total_sectors: u64::from_le_bytes([
110+
boot_sector_data[0x28],
111+
boot_sector_data[0x29],
112+
boot_sector_data[0x2A],
113+
boot_sector_data[0x2B],
114+
boot_sector_data[0x2C],
115+
boot_sector_data[0x2D],
116+
boot_sector_data[0x2E],
117+
boot_sector_data[0x2F],
118+
]),
119+
logical_cluster_mft: u64::from_le_bytes([
120+
boot_sector_data[0x30],
121+
boot_sector_data[0x31],
122+
boot_sector_data[0x32],
123+
boot_sector_data[0x33],
124+
boot_sector_data[0x34],
125+
boot_sector_data[0x35],
126+
boot_sector_data[0x36],
127+
boot_sector_data[0x37],
128+
]),
129+
logical_cluster_mft_mirror: u64::from_le_bytes([
130+
boot_sector_data[0x38],
131+
boot_sector_data[0x39],
132+
boot_sector_data[0x3A],
133+
boot_sector_data[0x3B],
134+
boot_sector_data[0x3C],
135+
boot_sector_data[0x3D],
136+
boot_sector_data[0x3E],
137+
boot_sector_data[0x3F],
138+
]),
139+
clusters_per_file_record_segment: u32::from_le_bytes([
140+
boot_sector_data[0x40],
141+
boot_sector_data[0x41],
142+
boot_sector_data[0x42],
143+
boot_sector_data[0x43],
144+
]),
145+
clusters_per_index_buffer: boot_sector_data[0x44],
146+
volume_serial_number: u64::from_le_bytes([
147+
boot_sector_data[0x48],
148+
boot_sector_data[0x49],
149+
boot_sector_data[0x4A],
150+
boot_sector_data[0x4B],
151+
boot_sector_data[0x4C],
152+
boot_sector_data[0x4D],
153+
boot_sector_data[0x4E],
154+
boot_sector_data[0x4F],
155+
]),
156+
checksum: u32::from_le_bytes([
157+
boot_sector_data[0x50],
158+
boot_sector_data[0x51],
159+
boot_sector_data[0x52],
160+
boot_sector_data[0x53],
161+
]),
162+
})
163+
}
164+
}

0 commit comments

Comments
 (0)