1use livedisk::{Partition, PhysicalDisk};
9
10use crate::DiskReport;
11
12#[must_use]
16pub fn from_report(report: &DiskReport, name: &str, size_bytes: u64) -> PhysicalDisk {
17 let (sector, partitions) = match report {
18 DiskReport::Gpt(mbr) => gpt_partitions(mbr),
19 DiskReport::Mbr(mbr) => mbr_partitions(mbr),
20 DiskReport::Apm(apm) => apm_partitions(apm),
21 };
22 let extent = partitions
26 .iter()
27 .map(|p| p.start_offset + p.size_bytes)
28 .max()
29 .unwrap_or(0);
30 PhysicalDisk {
31 device_path: name.to_string(),
32 name: name.to_string(),
33 size_bytes: size_bytes.max(extent),
34 logical_sector_size: sector,
35 physical_sector_size: sector,
36 model: None,
37 serial: None,
38 removable: false,
39 read_only: false,
40 synthesized: false,
41 partitions,
42 }
43}
44
45fn part(name: String, start: u64, size: u64, ty: String, label: Option<String>) -> Partition {
46 Partition {
47 device_path: String::new(),
48 name,
49 start_offset: start,
50 size_bytes: size,
51 partition_type: (!ty.is_empty()).then_some(ty),
52 mount_point: None,
53 filesystem: None,
54 label,
55 }
56}
57
58fn gpt_partitions(mbr: &mbr_partition_forensic::MbrAnalysis) -> (u32, Vec<Partition>) {
59 let Some(gpt) = &mbr.gpt else {
60 return (512, Vec::new());
61 };
62 let sector = gpt.sector_size;
63 let parts = gpt
64 .partitions
65 .iter()
66 .enumerate()
67 .map(|(i, p)| {
68 let ty = p
69 .type_name()
70 .map_or_else(|| p.type_guid.to_string(), ToString::to_string);
71 let label = (!p.name.is_empty()).then(|| p.name.clone());
72 part(
73 format!("part{}", i + 1),
74 p.first_lba * sector,
75 (p.last_lba - p.first_lba + 1) * sector,
76 ty,
77 label,
78 )
79 })
80 .collect();
81 (sector as u32, parts)
82}
83
84fn mbr_partitions(mbr: &mbr_partition_forensic::MbrAnalysis) -> (u32, Vec<Partition>) {
85 const SECTOR: u64 = 512;
86 let parts = mbr
87 .partitions
88 .iter()
89 .map(|p| {
90 part(
91 format!("part{}", p.index),
92 p.lba_start * SECTOR,
93 (p.lba_end - p.lba_start + 1) * SECTOR,
94 p.declared_type.name().to_string(),
95 None,
96 )
97 })
98 .collect();
99 (SECTOR as u32, parts)
100}
101
102fn apm_partitions(apm: &apm_partition_forensic::ApmAnalysis) -> (u32, Vec<Partition>) {
103 let bs = apm.block_size as u64;
104 let parts = apm
105 .partitions
106 .iter()
107 .enumerate()
108 .map(|(i, p)| {
109 let name = if p.name.is_empty() {
110 format!("part{}", i + 1)
111 } else {
112 p.name.clone()
113 };
114 part(
115 name,
116 p.start_block as u64 * bs,
117 (p.end_block() as u64 - p.start_block as u64 + 1) * bs,
118 p.type_name.clone(),
119 None,
120 )
121 })
122 .collect();
123 (bs as u32, parts)
124}