diff options
Diffstat (limited to 'src/structured_values')
-rw-r--r-- | src/structured_values/index_allocation.rs | 111 | ||||
-rw-r--r-- | src/structured_values/index_root.rs | 77 | ||||
-rw-r--r-- | src/structured_values/mod.rs | 5 |
3 files changed, 173 insertions, 20 deletions
diff --git a/src/structured_values/index_allocation.rs b/src/structured_values/index_allocation.rs new file mode 100644 index 0000000..24d9e27 --- /dev/null +++ b/src/structured_values/index_allocation.rs @@ -0,0 +1,111 @@ +// Copyright 2021 Colin Finck <colin@reactos.org> +// SPDX-License-Identifier: GPL-2.0-or-later + +use crate::attribute_value::NtfsAttributeValue; +use crate::error::Result; +use crate::index_record::NtfsIndexRecord; +use crate::structured_values::index_root::NtfsIndexRoot; +use crate::structured_values::NewNtfsStructuredValue; +use crate::traits::NtfsReadSeek; +use binread::io::{Read, Seek, SeekFrom}; +use core::iter::FusedIterator; + +#[derive(Clone, Debug)] +pub struct NtfsIndexAllocation<'n> { + value: NtfsAttributeValue<'n>, +} + +impl<'n> NtfsIndexAllocation<'n> { + pub fn iter(&self, index_root: &NtfsIndexRoot) -> NtfsIndexRecords<'n> { + let index_record_size = index_root.index_record_size(); + NtfsIndexRecords::new(self.value.clone(), index_record_size) + } +} + +impl<'n> NewNtfsStructuredValue<'n> for NtfsIndexAllocation<'n> { + fn new<T>(_fs: &mut T, value: NtfsAttributeValue<'n>, _length: u64) -> Result<Self> + where + T: Read + Seek, + { + Ok(Self { value }) + } +} + +#[derive(Clone, Debug)] +pub struct NtfsIndexRecords<'n> { + value: NtfsAttributeValue<'n>, + index_record_size: u32, +} + +impl<'n> NtfsIndexRecords<'n> { + fn new(value: NtfsAttributeValue<'n>, index_record_size: u32) -> Self { + Self { + value, + index_record_size, + } + } + + pub fn attach<'a, T>(self, fs: &'a mut T) -> NtfsIndexRecordsAttached<'n, 'a, T> + where + T: Read + Seek, + { + NtfsIndexRecordsAttached::new(fs, self) + } + + pub fn next<T>(&mut self, fs: &mut T) -> Option<Result<NtfsIndexRecord<'n>>> + where + T: Read + Seek, + { + if self.value.stream_position() >= self.value.len() { + return None; + } + + // Get the current record. + let record = iter_try!(NtfsIndexRecord::new( + fs, + self.value.clone(), + self.index_record_size + )); + + // Advance our iterator to the next record. + iter_try!(self + .value + .seek(fs, SeekFrom::Current(self.index_record_size as i64))); + + Some(Ok(record)) + } +} + +pub struct NtfsIndexRecordsAttached<'n, 'a, T> +where + T: Read + Seek, +{ + fs: &'a mut T, + index_records: NtfsIndexRecords<'n>, +} + +impl<'n, 'a, T> NtfsIndexRecordsAttached<'n, 'a, T> +where + T: Read + Seek, +{ + fn new(fs: &'a mut T, index_records: NtfsIndexRecords<'n>) -> Self { + Self { fs, index_records } + } + + pub fn detach(self) -> NtfsIndexRecords<'n> { + self.index_records + } +} + +impl<'n, 'a, T> Iterator for NtfsIndexRecordsAttached<'n, 'a, T> +where + T: Read + Seek, +{ + type Item = Result<NtfsIndexRecord<'n>>; + + fn next(&mut self) -> Option<Self::Item> { + self.index_records.next(self.fs) + } +} + +impl<'n, 'a, T> FusedIterator for NtfsIndexRecordsAttached<'n, 'a, T> where T: Read + Seek {} diff --git a/src/structured_values/index_root.rs b/src/structured_values/index_root.rs index 26c7115..5a97cda 100644 --- a/src/structured_values/index_root.rs +++ b/src/structured_values/index_root.rs @@ -4,34 +4,67 @@ use crate::attribute::NtfsAttributeType; use crate::attribute_value::NtfsAttributeValue; use crate::error::{NtfsError, Result}; +use crate::index_entry::NtfsIndexEntries; +use crate::index_record::{IndexNodeHeader, INDEX_NODE_HEADER_SIZE}; use crate::structured_values::NewNtfsStructuredValue; -use binread::io::{Read, Seek}; +use crate::traits::NtfsReadSeek; +use binread::io::{Read, Seek, SeekFrom}; use binread::{BinRead, BinReaderExt}; /// Size of all [`IndexRootHeader`] fields plus some reserved bytes. -const INDEX_ROOT_HEADER_SIZE: u64 = 32; - -#[derive(BinRead, Clone, Debug)] -struct IndexHeader { - entries_offset: u32, - index_size: u32, - allocated_size: u32, - flags: u8, -} +const INDEX_ROOT_HEADER_SIZE: u64 = 16; #[derive(BinRead, Clone, Debug)] struct IndexRootHeader { ty: u32, collation_rule: u32, - index_block_size: u32, - clusters_per_index_block: i8, - reserved: [u8; 3], - index: IndexHeader, + index_record_size: u32, + clusters_per_index_record: i8, } #[derive(Clone, Debug)] -pub struct NtfsIndexRoot { - header: IndexRootHeader, +pub struct NtfsIndexRoot<'n> { + value: NtfsAttributeValue<'n>, + index_root_header: IndexRootHeader, + index_node_header: IndexNodeHeader, +} + +const LARGE_INDEX_FLAG: u8 = 0x01; + +impl<'n> NtfsIndexRoot<'n> { + pub fn index_allocated_size(&self) -> u32 { + self.index_node_header.allocated_size + } + + pub fn entries<K, T>(&self, fs: &mut T) -> Result<NtfsIndexEntries<'n, K>> + where + K: NewNtfsStructuredValue<'n>, + T: Read + Seek, + { + let offset = self.value.stream_position() + INDEX_ROOT_HEADER_SIZE as u64; + let start = offset + self.index_node_header.entries_offset as u64; + let end = offset + self.index_used_size() as u64; + + let mut value = self.value.clone(); + value.seek(fs, SeekFrom::Start(start))?; + + Ok(NtfsIndexEntries::new(value, end)) + } + + pub fn index_record_size(&self) -> u32 { + self.index_root_header.index_record_size + } + + pub fn index_used_size(&self) -> u32 { + self.index_node_header.index_size + } + + /// Returns whether the index belonging to this Index Root is large enough + /// to need an extra Index Allocation attribute. + /// Otherwise, the entire index information is stored in this Index Root. + pub fn is_large_index(&self) -> bool { + (self.index_node_header.flags & LARGE_INDEX_FLAG) != 0 + } } impl<'n> NewNtfsStructuredValue<'n> for NtfsIndexRoot<'n> { @@ -39,7 +72,7 @@ impl<'n> NewNtfsStructuredValue<'n> for NtfsIndexRoot<'n> { where T: Read + Seek, { - if value.len() < INDEX_ROOT_HEADER_SIZE { + if value.len() < INDEX_ROOT_HEADER_SIZE + INDEX_NODE_HEADER_SIZE { return Err(NtfsError::InvalidStructuredValueSize { position: value.data_position().unwrap(), ty: NtfsAttributeType::IndexRoot, @@ -49,8 +82,14 @@ impl<'n> NewNtfsStructuredValue<'n> for NtfsIndexRoot<'n> { } let mut value_attached = value.clone().attach(fs); - let header = value_attached.read_le::<IndexRootHeader>()?; + let index_root_header = value_attached.read_le::<IndexRootHeader>()?; + value_attached.seek(SeekFrom::Start(INDEX_ROOT_HEADER_SIZE))?; + let index_node_header = value_attached.read_le::<IndexNodeHeader>()?; - Ok(Self { header }) + Ok(Self { + value, + index_root_header, + index_node_header, + }) } } diff --git a/src/structured_values/mod.rs b/src/structured_values/mod.rs index 9fb743d..b61f24b 100644 --- a/src/structured_values/mod.rs +++ b/src/structured_values/mod.rs @@ -3,6 +3,7 @@ mod attribute_list; mod file_name; +mod index_allocation; mod index_root; mod object_id; mod security_descriptor; @@ -12,6 +13,7 @@ mod volume_name; pub use attribute_list::*; pub use file_name::*; +pub use index_allocation::*; pub use index_root::*; pub use object_id::*; pub use security_descriptor::*; @@ -49,7 +51,8 @@ pub enum NtfsStructuredValue<'n> { ObjectId(NtfsObjectId), VolumeInformation(NtfsVolumeInformation), VolumeName(NtfsVolumeName<'n>), - IndexRoot(NtfsIndexRoot), + IndexRoot(NtfsIndexRoot<'n>), + IndexAllocation(NtfsIndexAllocation<'n>), } pub trait NewNtfsStructuredValue<'n>: Sized { |