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/index_record.rs')
-rw-r--r--src/index_record.rs141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/index_record.rs b/src/index_record.rs
new file mode 100644
index 0000000..fec6e09
--- /dev/null
+++ b/src/index_record.rs
@@ -0,0 +1,141 @@
+// Copyright 2021 Colin Finck <colin@reactos.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use crate::attribute_value::NtfsAttributeValue;
+use crate::error::{NtfsError, Result};
+use crate::index_entry::NtfsIndexEntries;
+use crate::record::RecordHeader;
+use crate::structured_values::NewNtfsStructuredValue;
+use crate::traits::NtfsReadSeek;
+use binread::io::{Read, Seek, SeekFrom};
+use binread::{BinRead, BinReaderExt};
+
+/// Size of all [`IndexRecordHeader`] fields.
+const INDEX_RECORD_HEADER_SIZE: u32 = 24;
+
+#[allow(unused)]
+#[derive(BinRead, Clone, Debug)]
+struct IndexRecordHeader {
+ record_header: RecordHeader,
+ vcn: u64,
+}
+
+/// Size of all [`IndexNodeHeader`] fields plus some reserved bytes.
+pub(crate) const INDEX_NODE_HEADER_SIZE: u64 = 16;
+
+#[derive(BinRead, Clone, Debug)]
+pub(crate) struct IndexNodeHeader {
+ pub(crate) entries_offset: u32,
+ pub(crate) index_size: u32,
+ pub(crate) allocated_size: u32,
+ pub(crate) flags: u8,
+}
+
+#[derive(Clone, Debug)]
+pub struct NtfsIndexRecord<'n> {
+ value: NtfsAttributeValue<'n>,
+ index_record_header: IndexRecordHeader,
+ index_node_header: IndexNodeHeader,
+}
+
+const HAS_SUBNODES_FLAG: u8 = 0x01;
+
+impl<'n> NtfsIndexRecord<'n> {
+ pub(crate) fn new<T>(
+ fs: &mut T,
+ value: NtfsAttributeValue<'n>,
+ index_record_size: u32,
+ ) -> Result<Self>
+ where
+ T: Read + Seek,
+ {
+ let mut value_attached = value.clone().attach(fs);
+ let index_record_header = value_attached.read_le::<IndexRecordHeader>()?;
+ let index_node_header = value_attached.read_le::<IndexNodeHeader>()?;
+
+ let index_record = Self {
+ value,
+ index_record_header,
+ index_node_header,
+ };
+ index_record.validate_signature()?;
+ index_record.validate_sizes(index_record_size)?;
+
+ Ok(index_record)
+ }
+
+ 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_RECORD_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))
+ }
+
+ /// Returns whether this index node has sub-nodes.
+ /// Otherwise, this index node is a leaf node.
+ pub fn has_subnodes(&self) -> bool {
+ (self.index_node_header.flags & HAS_SUBNODES_FLAG) != 0
+ }
+
+ pub fn index_allocated_size(&self) -> u32 {
+ self.index_node_header.allocated_size
+ }
+
+ pub fn index_used_size(&self) -> u32 {
+ self.index_node_header.index_size
+ }
+
+ fn validate_signature(&self) -> Result<()> {
+ let signature = &self.index_record_header.record_header.signature;
+ let expected = b"INDX";
+
+ if signature == expected {
+ Ok(())
+ } else {
+ Err(NtfsError::InvalidNtfsIndexSignature {
+ position: self.value.data_position().unwrap(),
+ expected,
+ actual: *signature,
+ })
+ }
+ }
+
+ fn validate_sizes(&self, index_record_size: u32) -> Result<()> {
+ // The total size allocated for this index record must not be larger than
+ // the size defined for all index records of this index.
+ let total_allocated_size = INDEX_RECORD_HEADER_SIZE + self.index_allocated_size();
+ if total_allocated_size > index_record_size {
+ return Err(NtfsError::InvalidNtfsIndexSize {
+ position: self.value.data_position().unwrap(),
+ expected: index_record_size,
+ actual: total_allocated_size,
+ });
+ }
+
+ // Furthermore, the total used size for this index record must not be
+ // larger than the total allocated size.
+ let total_used_size = INDEX_RECORD_HEADER_SIZE
+ + self
+ .index_record_header
+ .record_header
+ .update_sequence_array_size()
+ + self.index_used_size();
+ if total_used_size > total_allocated_size {
+ return Err(NtfsError::InvalidNtfsIndexSize {
+ position: self.value.data_position().unwrap(),
+ expected: total_allocated_size,
+ actual: total_used_size,
+ });
+ }
+
+ Ok(())
+ }
+}