Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/ntfs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/structured_values')
-rw-r--r--src/structured_values/index_allocation.rs111
-rw-r--r--src/structured_values/index_root.rs77
-rw-r--r--src/structured_values/mod.rs5
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 {