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_entry.rs')
-rw-r--r--src/index_entry.rs176
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 {}