1use std::ops::Range;
6
7use crate::{api::*, volume::Volume};
8
9pub struct NtfsAttribute<'a> {
10 pub data: &'a [u8],
11 pub header: &'a NtfsAttributeHeader,
12 pub header_res: &'a NtfsResidentAttributeHeader,
13 pub header_nonres: &'a NtfsNonResidentAttributeHeader,
14}
15
16impl<'a> NtfsAttribute<'a> {
17 pub fn new(data: &'a [u8]) -> Self {
18 unsafe {
19 NtfsAttribute {
20 data,
21 header: &*(data.as_ptr() as *const NtfsAttributeHeader),
22 header_res: &*(data.as_ptr() as *const NtfsResidentAttributeHeader),
23 header_nonres: &*(data.as_ptr() as *const NtfsNonResidentAttributeHeader),
24 }
25 }
26 }
27
28 pub fn get_resident(&self) -> &'a [u8] {
29 assert!(self.header.is_non_resident == 0);
30 let start = self.header_res.value_offset as usize;
31 let end = start + self.header_res.value_length as usize;
32 &self.data[start..end]
33 }
34
35 pub fn as_standard_info(&self) -> &'a NtfsStandardInformation {
36 assert!(self.header.type_id == NtfsAttributeType::StandardInformation as u32);
37 let slice = self.get_resident();
38 unsafe { &*(slice.as_ptr() as *const NtfsStandardInformation) }
39 }
40
41 pub fn as_name(&self) -> &'a NtfsFileName {
42 assert!(self.header.type_id == NtfsAttributeType::FileName as u32);
43 let slice = self.get_resident();
44 unsafe { &*(slice.as_ptr() as *const NtfsFileName) }
45 }
46
47 pub fn as_resident_data(&self) -> &'a [u8] {
48 assert!(self.header.type_id == NtfsAttributeType::Data as u32);
49 self.get_resident()
50 }
51
52 pub fn get_nonresident_data_runs(&self, volume: &Volume) -> (usize, Vec<Range<usize>>) {
53 let mut out = Vec::new();
54
55 let total_size = self.header_nonres.data_size as usize;
56 if total_size == 0 {
57 return (total_size, out);
58 }
59
60 let runs_data = {
61 let start = self.header_nonres.data_runs_offset as usize;
62 let end = start + self.header.length as usize;
63 &self.data[start..end]
64 };
65
66 let cluster_size = volume.cluster_size as usize;
67 const BUF_SIZE: usize = 8;
68
69 let mut cursor = 0usize;
70 let mut prev_run = 0usize;
71 loop {
72 if runs_data[cursor] == 0 {
73 break;
74 }
75
76 let cluster_count_b = (runs_data[cursor] & 0x0f) as usize;
78 let cluster_offset_b = ((runs_data[cursor] & 0xf0) >> 4) as usize;
79 assert!(cluster_count_b > 0 && cluster_count_b <= BUF_SIZE);
80 assert!(cluster_offset_b > 0 && cluster_offset_b <= BUF_SIZE);
81
82 cursor += 1;
83
84 let mut buf = [0u8; BUF_SIZE];
86 buf[..cluster_count_b].copy_from_slice(&runs_data[cursor..cursor + cluster_count_b]);
87 let cluster_count = u64::from_le_bytes(buf) as usize;
88 cursor += cluster_count_b;
89
90 let mut buf = [0u8; BUF_SIZE];
92 buf[..cluster_offset_b].copy_from_slice(&runs_data[cursor..cursor + cluster_offset_b]);
93 let cluster_offset = i64::from_le_bytes(buf);
94 let empty_bits = (BUF_SIZE - cluster_offset_b) * 8;
95 let cluster_offset = (cluster_offset << empty_bits) >> empty_bits;
96 cursor += cluster_offset_b;
97
98 let start = if cluster_offset >= 0 {
99 prev_run + (cluster_offset as usize) * cluster_size
100 } else {
101 prev_run - (cluster_offset.wrapping_neg() as usize) * cluster_size
102 };
103
104 let end = start + cluster_count * cluster_size;
105 prev_run = start;
106
107 out.push(start..end);
108 }
109
110 (total_size, out)
111 }
112}