diff options
Diffstat (limited to 'src/index_entry.rs')
-rw-r--r-- | src/index_entry.rs | 176 |
1 files changed, 142 insertions, 34 deletions
diff --git a/src/index_entry.rs b/src/index_entry.rs index a3e54f4..1c84768 100644 --- a/src/index_entry.rs +++ b/src/index_entry.rs @@ -2,11 +2,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later use crate::error::Result; -use crate::structured_values::NtfsStructuredValueFromSlice; +use crate::file_reference::NtfsFileReference; +use crate::indexes::{ + NtfsIndexEntryData, NtfsIndexEntryHasData, NtfsIndexEntryHasFileReference, NtfsIndexEntryKey, + NtfsIndexEntryType, +}; use crate::types::Vcn; use bitflags::bitflags; use byteorder::{ByteOrder, LittleEndian}; use core::iter::FusedIterator; +use core::marker::PhantomData; use core::mem; use core::ops::Range; use memoffset::offset_of; @@ -16,7 +21,14 @@ const INDEX_ENTRY_HEADER_SIZE: i64 = 16; #[repr(C, packed)] struct IndexEntryHeader { - file_ref: u64, + // The following three fields are used for the u64 file reference if the entry type + // has no data, but a file reference instead. + // This is indicated by the entry type implementing `NtfsIndexEntryHasFileReference`. + // Currently, only `NtfsFileNameIndex` has such a file reference. + data_offset: u16, + data_length: u16, + padding: u32, + index_entry_length: u16, key_length: u16, flags: u8, @@ -31,30 +43,99 @@ bitflags! { } } -pub(crate) struct IndexEntryRange { +pub(crate) struct IndexEntryRange<E> +where + E: NtfsIndexEntryType, +{ range: Range<usize>, position: u64, + entry_type: PhantomData<E>, } -impl IndexEntryRange { - pub(crate) const fn new(range: Range<usize>, position: u64) -> Self { - Self { range, position } +impl<E> IndexEntryRange<E> +where + E: NtfsIndexEntryType, +{ + pub(crate) fn new(range: Range<usize>, position: u64) -> Self { + let entry_type = PhantomData; + Self { + range, + position, + entry_type, + } } - pub(crate) fn to_entry<'s>(&self, slice: &'s [u8]) -> NtfsIndexEntry<'s> { + pub(crate) fn to_entry<'s>(&self, slice: &'s [u8]) -> NtfsIndexEntry<'s, E> { NtfsIndexEntry::new(&slice[self.range.clone()], self.position) } } #[derive(Clone, Debug)] -pub struct NtfsIndexEntry<'s> { +pub struct NtfsIndexEntry<'s, E> +where + E: NtfsIndexEntryType, +{ slice: &'s [u8], position: u64, + entry_type: PhantomData<E>, } -impl<'s> NtfsIndexEntry<'s> { - pub(crate) const fn new(slice: &'s [u8], position: u64) -> Self { - Self { slice, position } +impl<'s, E> NtfsIndexEntry<'s, E> +where + E: NtfsIndexEntryType, +{ + pub(crate) fn new(slice: &'s [u8], position: u64) -> Self { + let entry_type = PhantomData; + Self { + slice, + position, + entry_type, + } + } + + pub fn data(&self) -> Option<Result<E::DataType>> + where + E: NtfsIndexEntryHasData, + { + if self.data_offset() == 0 || self.data_length() == 0 { + return None; + } + + let start = self.data_offset() as usize; + let end = start + self.data_length() as usize; + let position = self.position + start as u64; + + let data = iter_try!(E::DataType::data_from_slice( + &self.slice[start..end], + position + )); + Some(Ok(data)) + } + + fn data_offset(&self) -> u16 + where + E: NtfsIndexEntryHasData, + { + let start = offset_of!(IndexEntryHeader, data_offset); + LittleEndian::read_u16(&self.slice[start..]) + } + + pub fn data_length(&self) -> u16 + where + E: NtfsIndexEntryHasData, + { + let start = offset_of!(IndexEntryHeader, data_length); + LittleEndian::read_u16(&self.slice[start..]) + } + + pub fn file_reference(&self) -> NtfsFileReference + where + E: NtfsIndexEntryHasFileReference, + { + // The "file_reference_data" is at the same position as the `data_offset`, `data_length`, and `padding` fields. + // There can either be extra data or a file reference! + let file_reference_data = LittleEndian::read_u64(self.slice); + NtfsFileReference::new(file_reference_data) } pub fn flags(&self) -> NtfsIndexEntryFlags { @@ -67,18 +148,10 @@ impl<'s> NtfsIndexEntry<'s> { LittleEndian::read_u16(&self.slice[start..]) } - pub fn key_length(&self) -> u16 { - let start = offset_of!(IndexEntryHeader, key_length); - LittleEndian::read_u16(&self.slice[start..]) - } - /// Returns the structured value of the key of this Index Entry, /// or `None` if this Index Entry has no key. /// The last Index Entry never has a key. - pub fn key_structured_value<K>(&self) -> Option<Result<K>> - where - K: NtfsStructuredValueFromSlice<'s>, - { + pub fn key(&self) -> Option<Result<E::KeyType>> { // The key/stream is only set when the last entry flag is not set. // https://flatcap.org/linux-ntfs/ntfs/concepts/index_entry.html if self.key_length() == 0 || self.flags().contains(NtfsIndexEntryFlags::LAST_ENTRY) { @@ -89,8 +162,16 @@ impl<'s> NtfsIndexEntry<'s> { let end = start + self.key_length() as usize; let position = self.position + start as u64; - let structured_value = iter_try!(K::from_slice(&self.slice[start..end], position)); - Some(Ok(structured_value)) + let key = iter_try!(E::KeyType::key_from_slice( + &self.slice[start..end], + position + )); + Some(Ok(key)) + } + + pub fn key_length(&self) -> u16 { + let start = offset_of!(IndexEntryHeader, key_length); + LittleEndian::read_u16(&self.slice[start..]) } /// Returns the Virtual Cluster Number (VCN) of the subnode of this Index Entry, @@ -108,20 +189,29 @@ impl<'s> NtfsIndexEntry<'s> { } } -pub(crate) struct IndexNodeEntryRanges { +pub(crate) struct IndexNodeEntryRanges<E> +where + E: NtfsIndexEntryType, +{ data: Vec<u8>, range: Range<usize>, position: u64, + entry_type: PhantomData<E>, } -impl IndexNodeEntryRanges { +impl<E> IndexNodeEntryRanges<E> +where + E: NtfsIndexEntryType, +{ pub(crate) fn new(data: Vec<u8>, range: Range<usize>, position: u64) -> Self { debug_assert!(range.end <= data.len()); + let entry_type = PhantomData; Self { data, range, position, + entry_type, } } @@ -130,8 +220,11 @@ impl IndexNodeEntryRanges { } } -impl Iterator for IndexNodeEntryRanges { - type Item = IndexEntryRange; +impl<E> Iterator for IndexNodeEntryRanges<E> +where + E: NtfsIndexEntryType, +{ + type Item = IndexEntryRange<E>; fn next(&mut self) -> Option<Self::Item> { if self.range.is_empty() { @@ -141,7 +234,7 @@ impl Iterator for IndexNodeEntryRanges { // Get the current entry. let start = self.range.start; let position = self.position + self.range.start as u64; - let entry = NtfsIndexEntry::new(&self.data[start..], position); + let entry = NtfsIndexEntry::<'_, E>::new(&self.data[start..], position); let end = start + entry.index_entry_length() as usize; if entry.flags().contains(NtfsIndexEntryFlags::LAST_ENTRY) { @@ -158,22 +251,37 @@ impl Iterator for IndexNodeEntryRanges { } } -impl FusedIterator for IndexNodeEntryRanges {} +impl<E> FusedIterator for IndexNodeEntryRanges<E> where E: NtfsIndexEntryType {} #[derive(Clone, Debug)] -pub struct NtfsIndexNodeEntries<'s> { +pub struct NtfsIndexNodeEntries<'s, E> +where + E: NtfsIndexEntryType, +{ slice: &'s [u8], position: u64, + entry_type: PhantomData<E>, } -impl<'s> NtfsIndexNodeEntries<'s> { +impl<'s, E> NtfsIndexNodeEntries<'s, E> +where + E: NtfsIndexEntryType, +{ pub(crate) fn new(slice: &'s [u8], position: u64) -> Self { - Self { slice, position } + let entry_type = PhantomData; + Self { + slice, + position, + entry_type, + } } } -impl<'s> Iterator for NtfsIndexNodeEntries<'s> { - type Item = NtfsIndexEntry<'s>; +impl<'s, E> Iterator for NtfsIndexNodeEntries<'s, E> +where + E: NtfsIndexEntryType, +{ + type Item = NtfsIndexEntry<'s, E>; fn next(&mut self) -> Option<Self::Item> { if self.slice.is_empty() { @@ -199,4 +307,4 @@ impl<'s> Iterator for NtfsIndexNodeEntries<'s> { } } -impl<'s> FusedIterator for NtfsIndexNodeEntries<'s> {} +impl<'s, E> FusedIterator for NtfsIndexNodeEntries<'s, E> where E: NtfsIndexEntryType {} |