ntfs_reader/
attribute.rs

1// Copyright (c) 2022, Matteo Bernacchia <dev@kikijiki.com>. All rights reserved.
2// This project is dual licensed under the Apache License 2.0 and the MIT license.
3// See the LICENSE files in the project root for details.
4
5use 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            // How many bytes to read for each value.
77            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            // Read cluster_count
85            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            // Read cluster_offset (and fix sign bits)
91            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}