1use core::mem;
5
6use arrayvec::ArrayVec;
7use binrw::io::{Cursor, Read, Seek, SeekFrom};
8use binrw::{BinRead, BinReaderExt};
9use nt_string::u16strle::U16StrLe;
10
11use crate::attribute::{NtfsAttribute, NtfsAttributeType};
12use crate::attribute_value::{NtfsAttributeValue, NtfsNonResidentAttributeValue};
13use crate::error::{NtfsError, Result};
14use crate::file::NtfsFile;
15use crate::file_reference::NtfsFileReference;
16use crate::ntfs::Ntfs;
17use crate::structured_values::NtfsStructuredValue;
18use crate::traits::NtfsReadSeek;
19use crate::types::{NtfsPosition, Vcn};
20
21const ATTRIBUTE_LIST_ENTRY_HEADER_SIZE: usize = 26;
23
24const NAME_MAX_SIZE: usize = (u8::MAX as usize) * mem::size_of::<u16>();
27
28#[allow(unused)]
29#[derive(BinRead, Clone, Debug)]
30struct AttributeListEntryHeader {
31 ty: u32,
33 list_entry_length: u16,
35 name_length: u8,
37 name_offset: u8,
39 lowest_vcn: Vcn,
43 base_file_reference: NtfsFileReference,
45 instance: u16,
47}
48
49#[derive(Clone, Debug)]
61pub enum NtfsAttributeList<'n, 'f> {
62 Resident(&'f [u8], NtfsPosition),
64 NonResident(NtfsNonResidentAttributeValue<'n, 'f>),
66}
67
68impl<'n, 'f> NtfsAttributeList<'n, 'f> {
69 pub fn entries(&self) -> NtfsAttributeListEntries<'n, 'f> {
71 NtfsAttributeListEntries::new(self.clone())
72 }
73
74 pub fn position(&self) -> NtfsPosition {
76 match self {
77 Self::Resident(_slice, position) => *position,
78 Self::NonResident(value) => value.data_position(),
79 }
80 }
81}
82
83impl<'n, 'f> NtfsStructuredValue<'n, 'f> for NtfsAttributeList<'n, 'f> {
84 const TY: NtfsAttributeType = NtfsAttributeType::AttributeList;
85
86 fn from_attribute_value<T>(_fs: &mut T, value: NtfsAttributeValue<'n, 'f>) -> Result<Self>
87 where
88 T: Read + Seek,
89 {
90 match value {
91 NtfsAttributeValue::Resident(value) => {
92 let slice = value.data();
93 let position = value.data_position();
94 Ok(Self::Resident(slice, position))
95 }
96 NtfsAttributeValue::NonResident(value) => Ok(Self::NonResident(value)),
97 NtfsAttributeValue::AttributeListNonResident(value) => {
98 let position = value.data_position();
101 Err(NtfsError::UnexpectedAttributeListAttribute { position })
102 }
103 }
104 }
105}
106
107#[derive(Clone, Debug)]
113pub struct NtfsAttributeListEntries<'n, 'f> {
114 attribute_list: NtfsAttributeList<'n, 'f>,
115}
116
117impl<'n, 'f> NtfsAttributeListEntries<'n, 'f> {
118 fn new(attribute_list: NtfsAttributeList<'n, 'f>) -> Self {
119 Self { attribute_list }
120 }
121
122 pub fn next<T>(&mut self, fs: &mut T) -> Option<Result<NtfsAttributeListEntry>>
124 where
125 T: Read + Seek,
126 {
127 match &mut self.attribute_list {
128 NtfsAttributeList::Resident(slice, position) => Self::next_resident(slice, position),
129 NtfsAttributeList::NonResident(value) => Self::next_non_resident(fs, value),
130 }
131 }
132
133 fn next_non_resident<T>(
134 fs: &mut T,
135 value: &mut NtfsNonResidentAttributeValue<'n, 'f>,
136 ) -> Option<Result<NtfsAttributeListEntry>>
137 where
138 T: Read + Seek,
139 {
140 if value.stream_position() >= value.len() {
141 return None;
142 }
143
144 let mut value_attached = value.clone().attach(fs);
146 let position = value.data_position();
147 let entry = iter_try!(NtfsAttributeListEntry::new(&mut value_attached, position));
148
149 iter_try!(value.seek(fs, SeekFrom::Current(entry.list_entry_length() as i64)));
151
152 Some(Ok(entry))
153 }
154
155 fn next_resident(
156 slice: &mut &'f [u8],
157 position: &mut NtfsPosition,
158 ) -> Option<Result<NtfsAttributeListEntry>> {
159 if slice.is_empty() {
160 return None;
161 }
162
163 let mut cursor = Cursor::new(*slice);
165 let entry = iter_try!(NtfsAttributeListEntry::new(&mut cursor, *position));
166
167 let bytes_to_advance = entry.list_entry_length() as usize;
169 *slice = slice.get(bytes_to_advance..)?;
170 *position += bytes_to_advance;
171 Some(Ok(entry))
172 }
173}
174
175#[derive(Clone, Debug)]
177pub struct NtfsAttributeListEntry {
178 header: AttributeListEntryHeader,
179 name: ArrayVec<u8, NAME_MAX_SIZE>,
180 position: NtfsPosition,
181}
182
183impl NtfsAttributeListEntry {
184 fn new<T>(r: &mut T, position: NtfsPosition) -> Result<Self>
185 where
186 T: Read + Seek,
187 {
188 let header = r.read_le::<AttributeListEntryHeader>()?;
189
190 let mut entry = Self {
191 header,
192 name: ArrayVec::from([0u8; NAME_MAX_SIZE]),
193 position,
194 };
195 entry.validate_entry_and_name_length()?;
196 entry.read_name(r)?;
197
198 Ok(entry)
199 }
200
201 pub fn base_file_reference(&self) -> NtfsFileReference {
203 self.header.base_file_reference
204 }
205
206 pub fn instance(&self) -> u16 {
213 self.header.instance
214 }
215
216 pub fn list_entry_length(&self) -> u16 {
218 self.header.list_entry_length
219 }
220
221 pub fn lowest_vcn(&self) -> Vcn {
228 self.header.lowest_vcn
229 }
230
231 pub fn name(&self) -> U16StrLe {
233 U16StrLe(&self.name)
234 }
235
236 pub fn name_length(&self) -> usize {
240 self.header.name_length as usize * mem::size_of::<u16>()
241 }
242
243 pub fn position(&self) -> NtfsPosition {
245 self.position
246 }
247
248 fn read_name<T>(&mut self, r: &mut T) -> Result<()>
249 where
250 T: Read + Seek,
251 {
252 debug_assert_eq!(self.name.len(), NAME_MAX_SIZE);
253
254 let name_length = self.name_length();
255 r.read_exact(&mut self.name[..name_length])?;
256 self.name.truncate(name_length);
257
258 Ok(())
259 }
260
261 pub fn to_attribute<'n, 'f>(&self, file: &'f NtfsFile<'n>) -> Result<NtfsAttribute<'n, 'f>> {
269 let file_record_number = self.base_file_reference().file_record_number();
270 assert_eq!(
271 file.file_record_number(),
272 file_record_number,
273 "The given NtfsFile's record number does not match the expected record number. \
274 Always use NtfsAttributeListEntry::to_file to retrieve the correct NtfsFile."
275 );
276
277 let instance = self.instance();
278 let ty = self.ty()?;
279
280 file.find_resident_attribute(ty, None, Some(instance))
281 }
282
283 pub fn to_file<'n, T>(&self, ntfs: &'n Ntfs, fs: &mut T) -> Result<NtfsFile<'n>>
285 where
286 T: Read + Seek,
287 {
288 let file_record_number = self.base_file_reference().file_record_number();
289 ntfs.file(fs, file_record_number)
290 }
291
292 pub fn ty(&self) -> Result<NtfsAttributeType> {
295 NtfsAttributeType::n(self.header.ty).ok_or(NtfsError::UnsupportedAttributeType {
296 position: self.position(),
297 actual: self.header.ty,
298 })
299 }
300
301 fn validate_entry_and_name_length(&self) -> Result<()> {
302 let total_size = ATTRIBUTE_LIST_ENTRY_HEADER_SIZE + self.name_length();
303
304 if total_size > self.list_entry_length() as usize {
305 return Err(NtfsError::InvalidStructuredValueSize {
306 position: self.position(),
307 ty: NtfsAttributeType::AttributeList,
308 expected: self.list_entry_length() as u64,
309 actual: total_size as u64,
310 });
311 }
312
313 Ok(())
314 }
315}