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:
authorColin Finck <colin@reactos.org>2021-06-04 12:46:52 +0300
committerColin Finck <colin@reactos.org>2021-06-04 12:46:52 +0300
commitcba70d68b52025dda25d07e516d27ca7c73b607f (patch)
tree8e1b59d70ff04a8cf99e9f0be7406cc9ab47857f
parent98ffe4dec521551bb1b0ae904d730d360d3673eb (diff)
Make all structured values ready for indexes and non-resident attributes
This introduces a `NewNtfsStructuredValue` trait for the `new` function of all structured values. Indexes later need that to return the structured value specified by a type parameter. We also have to pass an explicit length and can't just rely on the end of the passed `NtfsAttributeValue`/`NtfsAttributeValueAttached`. For structured values of non-resident attributes, we have to store an `NtfsAttributeValue` instead of an absolute byte position, in order to let a structured value read additional data (e.g. the name of an `NtfsFileName`). The `NtfsAttributeValue` properly moves between data runs while reading.
-rw-r--r--src/attribute.rs36
-rw-r--r--src/attribute_value.rs63
-rw-r--r--src/error.rs14
-rw-r--r--src/lib.rs1
-rw-r--r--src/ntfs.rs4
-rw-r--r--src/string.rs39
-rw-r--r--src/structured_values/file_name.rs85
-rw-r--r--src/structured_values/index_root.rs19
-rw-r--r--src/structured_values/mod.rs15
-rw-r--r--src/structured_values/object_id.rs57
-rw-r--r--src/structured_values/standard_information.rs56
-rw-r--r--src/structured_values/volume_information.rs43
-rw-r--r--src/structured_values/volume_name.rs71
13 files changed, 271 insertions, 232 deletions
diff --git a/src/attribute.rs b/src/attribute.rs
index b6b8a55..a13e740 100644
--- a/src/attribute.rs
+++ b/src/attribute.rs
@@ -7,8 +7,8 @@ use crate::ntfs::Ntfs;
use crate::ntfs_file::NtfsFile;
use crate::string::NtfsString;
use crate::structured_values::{
- NtfsFileName, NtfsIndexRoot, NtfsObjectId, NtfsStandardInformation, NtfsStructuredValue,
- NtfsVolumeInformation, NtfsVolumeName,
+ NewNtfsStructuredValue, NtfsFileName, NtfsIndexRoot, NtfsObjectId, NtfsStandardInformation,
+ NtfsStructuredValue, NtfsVolumeInformation, NtfsVolumeName,
};
use binread::io::{Read, Seek, SeekFrom};
use binread::{BinRead, BinReaderExt};
@@ -220,40 +220,42 @@ impl<'n> NtfsAttribute<'n> {
T: Read + Seek,
{
let name_position = self.position + self.header.name_offset as u64;
- NtfsString::read_from_fs(fs, name_position, self.name_length(), buf)
+ fs.seek(SeekFrom::Start(name_position))?;
+ NtfsString::from_reader(fs, self.name_length(), buf)
}
- pub fn structured_value<T>(&self, fs: &mut T) -> Result<NtfsStructuredValue>
+ pub fn structured_value<T>(&self, fs: &mut T) -> Result<NtfsStructuredValue<'n>>
where
T: Read + Seek,
{
- let attached_value = self.value().attach(fs);
+ let value = self.value(fs)?;
+ let length = value.len();
match self.ty()? {
NtfsAttributeType::StandardInformation => {
- let inner = NtfsStandardInformation::new(self.position, attached_value)?;
+ let inner = NtfsStandardInformation::new(fs, value, length)?;
Ok(NtfsStructuredValue::StandardInformation(inner))
}
NtfsAttributeType::AttributeList => panic!("TODO"),
NtfsAttributeType::FileName => {
- let inner = NtfsFileName::new(self.position, attached_value)?;
+ let inner = NtfsFileName::new(fs, value, length)?;
Ok(NtfsStructuredValue::FileName(inner))
}
NtfsAttributeType::ObjectId => {
- let inner = NtfsObjectId::new(self.position, attached_value)?;
+ let inner = NtfsObjectId::new(fs, value, length)?;
Ok(NtfsStructuredValue::ObjectId(inner))
}
NtfsAttributeType::SecurityDescriptor => panic!("TODO"),
NtfsAttributeType::VolumeName => {
- let inner = NtfsVolumeName::new(self.position, attached_value)?;
+ let inner = NtfsVolumeName::new(fs, value, length)?;
Ok(NtfsStructuredValue::VolumeName(inner))
}
NtfsAttributeType::VolumeInformation => {
- let inner = NtfsVolumeInformation::new(self.position, attached_value)?;
+ let inner = NtfsVolumeInformation::new(fs, value, length)?;
Ok(NtfsStructuredValue::VolumeInformation(inner))
}
NtfsAttributeType::IndexRoot => {
- let inner = NtfsIndexRoot::new(self.position, attached_value)?;
+ let inner = NtfsIndexRoot::new(fs, value, length)?;
Ok(NtfsStructuredValue::IndexRoot(inner))
}
ty => Err(NtfsError::UnsupportedStructuredValue {
@@ -273,23 +275,27 @@ impl<'n> NtfsAttribute<'n> {
}
/// Returns an [`NtfsAttributeValue`] structure to read the value of this NTFS attribute.
- pub fn value(&self) -> NtfsAttributeValue {
+ pub fn value<T>(&self, fs: &mut T) -> Result<NtfsAttributeValue<'n>>
+ where
+ T: Read + Seek,
+ {
match &self.extra_header {
NtfsAttributeExtraHeader::Resident(resident_header) => {
let value_position = self.position + resident_header.value_offset as u64;
let value_length = resident_header.value_length as u64;
let value = NtfsDataRun::from_byte_info(value_position, value_length);
- NtfsAttributeValue::Resident(value)
+ Ok(NtfsAttributeValue::Resident(value))
}
NtfsAttributeExtraHeader::NonResident(non_resident_header) => {
let start = self.position + non_resident_header.data_runs_offset as u64;
let end = self.position + self.header.length as u64;
let value = NtfsAttributeNonResidentValue::new(
&self.ntfs,
+ fs,
start..end,
non_resident_header.data_size,
- );
- NtfsAttributeValue::NonResident(value)
+ )?;
+ Ok(NtfsAttributeValue::NonResident(value))
}
}
}
diff --git a/src/attribute_value.rs b/src/attribute_value.rs
index 9b9e107..740be77 100644
--- a/src/attribute_value.rs
+++ b/src/attribute_value.rs
@@ -25,17 +25,17 @@ impl<'n> NtfsAttributeValue<'n> {
NtfsAttributeValueAttached::new(fs, self)
}
- pub fn len(&self) -> u64 {
+ pub fn data_position(&self) -> Option<u64> {
match self {
- Self::Resident(inner) => inner.len(),
- Self::NonResident(inner) => inner.len(),
+ Self::Resident(inner) => Some(inner.data_position()),
+ Self::NonResident(inner) => inner.data_position(),
}
}
- pub fn position(&self) -> u64 {
+ pub fn len(&self) -> u64 {
match self {
- Self::Resident(inner) => inner.position(),
- Self::NonResident(inner) => inner.position(),
+ Self::Resident(inner) => inner.len(),
+ Self::NonResident(inner) => inner.len(),
}
}
}
@@ -82,6 +82,10 @@ where
Self { fs, value }
}
+ pub fn data_position(&self) -> Option<u64> {
+ self.value.data_position()
+ }
+
pub fn detach(self) -> NtfsAttributeValue<'n> {
self.value
}
@@ -89,10 +93,6 @@ where
pub fn len(&self) -> u64 {
self.value.len()
}
-
- pub fn position(&self) -> u64 {
- self.value.position()
- }
}
impl<'n, 'a, T> Read for NtfsAttributeValueAttached<'n, 'a, T>
@@ -138,12 +138,12 @@ impl NtfsDataRun {
Self::from_byte_info(position, length)
}
- pub fn len(&self) -> u64 {
- self.length
+ pub fn data_position(&self) -> u64 {
+ self.position + self.stream_position
}
- pub fn position(&self) -> u64 {
- self.position
+ pub fn len(&self) -> u64 {
+ self.length
}
}
@@ -340,17 +340,38 @@ pub struct NtfsAttributeNonResidentValue<'n> {
}
impl<'n> NtfsAttributeNonResidentValue<'n> {
- pub(crate) fn new(ntfs: &'n Ntfs, data_runs_range: Range<u64>, data_size: u64) -> Self {
- let stream_data_runs = NtfsDataRuns::new(ntfs, data_runs_range.clone());
+ pub(crate) fn new<T>(
+ ntfs: &'n Ntfs,
+ fs: &mut T,
+ data_runs_range: Range<u64>,
+ data_size: u64,
+ ) -> Result<Self>
+ where
+ T: Read + Seek,
+ {
+ let mut stream_data_runs = NtfsDataRuns::new(ntfs, data_runs_range.clone());
- Self {
+ // Get the first data run already here to let `data_position` return something meaningful.
+ let stream_data_run = match stream_data_runs.next(fs) {
+ Some(Ok(data_run)) => Some(data_run),
+ Some(Err(e)) => return Err(e),
+ None => None,
+ };
+
+ Ok(Self {
ntfs,
data_runs_range,
data_size,
stream_data_runs,
- stream_data_run: None,
+ stream_data_run,
stream_position: 0,
- }
+ })
+ }
+
+ pub fn data_position(&self) -> Option<u64> {
+ self.stream_data_run
+ .as_ref()
+ .map(|data_run| data_run.data_position())
}
pub fn data_runs(&self) -> NtfsDataRuns<'n> {
@@ -361,10 +382,6 @@ impl<'n> NtfsAttributeNonResidentValue<'n> {
self.data_size
}
- pub fn position(&self) -> u64 {
- self.data_runs_range.start
- }
-
fn do_seek<T>(&mut self, fs: &mut T, bytes_to_seek: SeekFrom) -> Result<u64>
where
T: Read + Seek,
diff --git a/src/error.rs b/src/error.rs
index 232fb4e..25dd00a 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -17,13 +17,6 @@ pub enum NtfsError {
},
/// The given buffer should have at least {expected} bytes, but it only has {actual} bytes
BufferTooSmall { expected: usize, actual: usize },
- /// The NTFS attribute at byte position {position:#010x} of type {ty:?} has {actual} bytes where {expected} bytes were expected
- InvalidAttributeSize {
- position: u64,
- ty: NtfsAttributeType,
- expected: u64,
- actual: u64,
- },
/// The header of an NTFS data run should indicate a maximum byte count of {expected},
/// but the header at byte position {position:#010x} indicates a byte count of {actual}
InvalidByteCountInDataRunHeader {
@@ -43,6 +36,13 @@ pub enum NtfsError {
InvalidNtfsTime,
/// A record size field in the BIOS Parameter Block denotes {size_info}, which is invalid considering the cluster size of {cluster_size} bytes
InvalidRecordSizeInfo { size_info: i8, cluster_size: u32 },
+ /// The NTFS structured value at byte position {position:#010x} of type {ty:?} has {actual} bytes where {expected} bytes were expected
+ InvalidStructuredValueSize {
+ position: u64,
+ ty: NtfsAttributeType,
+ expected: u64,
+ actual: u64,
+ },
/// The 2-byte signature field at byte position {position:#010x} should contain {expected:?}, but it contains {actual:?}
InvalidTwoByteSignature {
position: u64,
diff --git a/src/lib.rs b/src/lib.rs
index 0b7ee02..b6fed11 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -28,5 +28,6 @@ pub use crate::guid::*;
pub use crate::ntfs::*;
pub use crate::ntfs_file::*;
pub use crate::string::*;
+pub use crate::structured_values::*;
pub use crate::time::*;
pub use crate::traits::*;
diff --git a/src/ntfs.rs b/src/ntfs.rs
index 1453182..c14dc1f 100644
--- a/src/ntfs.rs
+++ b/src/ntfs.rs
@@ -68,7 +68,7 @@ impl Ntfs {
/// - Check if `n` can be u32 instead of u64.
/// - Check if `n` should be in a newtype, with easier conversion from
/// KnownNtfsFile.
- pub fn ntfs_file<T>(&self, fs: &mut T, n: u64) -> Result<NtfsFile>
+ pub fn ntfs_file<'n, T>(&'n self, fs: &mut T, n: u64) -> Result<NtfsFile<'n>>
where
T: Read + Seek,
{
@@ -132,7 +132,7 @@ impl Ntfs {
/// of this NTFS volume.
/// Note that a volume may also have no label, which is why the return value is further
/// encapsulated in an `Option`.
- pub fn volume_name<T>(&self, fs: &mut T) -> Option<Result<NtfsVolumeName>>
+ pub fn volume_name<'n, T>(&'n self, fs: &mut T) -> Option<Result<NtfsVolumeName<'n>>>
where
T: Read + Seek,
{
diff --git a/src/string.rs b/src/string.rs
index 1b226c8..fa2f76e 100644
--- a/src/string.rs
+++ b/src/string.rs
@@ -3,7 +3,7 @@
use crate::error::{NtfsError, Result};
use alloc::string::String;
-use binread::io::{Read, Seek, SeekFrom};
+use binread::io::Read;
use core::char;
use core::cmp::Ordering;
use core::convert::TryInto;
@@ -14,6 +14,21 @@ use core::fmt;
pub struct NtfsString<'a>(pub &'a [u8]);
impl<'a> NtfsString<'a> {
+ pub(crate) fn from_reader<T>(mut rdr: T, length: usize, buf: &'a mut [u8]) -> Result<Self>
+ where
+ T: Read,
+ {
+ if buf.len() < length {
+ return Err(NtfsError::BufferTooSmall {
+ expected: length,
+ actual: buf.len(),
+ });
+ }
+
+ rdr.read_exact(&mut buf[..length])?;
+ Ok(Self(&buf[..length]))
+ }
+
fn cmp_iter<TI, OI>(mut this_iter: TI, mut other_iter: OI) -> Ordering
where
TI: Iterator<Item = u16>,
@@ -67,28 +82,6 @@ impl<'a> NtfsString<'a> {
self.0.len()
}
- pub(crate) fn read_from_fs<T>(
- fs: &mut T,
- position: u64,
- length: usize,
- buf: &'a mut [u8],
- ) -> Result<Self>
- where
- T: Read + Seek,
- {
- if buf.len() < length {
- return Err(NtfsError::BufferTooSmall {
- expected: length,
- actual: buf.len(),
- });
- }
-
- fs.seek(SeekFrom::Start(position))?;
- fs.read_exact(&mut buf[..length])?;
-
- Ok(Self(&buf[..length]))
- }
-
/// Attempts to convert `self` to an owned `String`.
/// Returns `Some(String)` if all characters could be converted successfully or `None` if a decoding error occurred.
pub fn to_string_checked(&self) -> Option<String> {
diff --git a/src/structured_values/file_name.rs b/src/structured_values/file_name.rs
index 06e3d2a..963896c 100644
--- a/src/structured_values/file_name.rs
+++ b/src/structured_values/file_name.rs
@@ -2,21 +2,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use crate::attribute::NtfsAttributeType;
-use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
use crate::string::NtfsString;
-use crate::structured_values::NtfsFileAttributeFlags;
+use crate::structured_values::{NewNtfsStructuredValue, NtfsFileAttributeFlags};
use crate::time::NtfsTime;
-use binread::io::{Read, Seek};
+use binread::io::{Read, Seek, SeekFrom};
use binread::{BinRead, BinReaderExt};
use core::mem;
use enumn::N;
/// Size of all [`FileNameHeader`] fields.
-const FILE_NAME_HEADER_SIZE: u64 = 66;
+const FILE_NAME_HEADER_SIZE: i64 = 66;
/// The smallest FileName attribute has a name containing just a single character.
-const FILE_NAME_MIN_SIZE: u64 = FILE_NAME_HEADER_SIZE + mem::size_of::<u16>() as u64;
+const FILE_NAME_MIN_SIZE: u64 = FILE_NAME_HEADER_SIZE as u64 + mem::size_of::<u16>() as u64;
#[allow(unused)]
#[derive(BinRead, Clone, Debug)]
@@ -44,37 +44,12 @@ pub enum NtfsFileNamespace {
}
#[derive(Clone, Debug)]
-pub struct NtfsFileName {
+pub struct NtfsFileName<'n> {
header: FileNameHeader,
- name_position: u64,
+ value: NtfsAttributeValue<'n>,
}
-impl NtfsFileName {
- pub(crate) fn new<T>(
- attribute_position: u64,
- mut value_attached: NtfsAttributeValueAttached<'_, '_, T>,
- ) -> Result<Self>
- where
- T: Read + Seek,
- {
- if value_attached.len() < FILE_NAME_MIN_SIZE {
- return Err(NtfsError::InvalidAttributeSize {
- position: attribute_position,
- ty: NtfsAttributeType::FileName,
- expected: FILE_NAME_MIN_SIZE,
- actual: value_attached.len(),
- });
- }
-
- let header = value_attached.read_le::<FileNameHeader>()?;
- let name_position = value_attached.position() + FILE_NAME_HEADER_SIZE;
-
- Ok(Self {
- header,
- name_position,
- })
- }
-
+impl<'n> NtfsFileName<'n> {
pub fn access_time(&self) -> NtfsTime {
self.header.access_time
}
@@ -114,7 +89,7 @@ impl NtfsFileName {
/// if it's an unknown namespace.
pub fn namespace(&self) -> Result<NtfsFileNamespace> {
NtfsFileNamespace::n(self.header.namespace).ok_or(NtfsError::UnsupportedNtfsFileNamespace {
- position: self.name_position,
+ position: self.value.data_position().unwrap(),
actual: self.header.namespace,
})
}
@@ -125,7 +100,47 @@ impl NtfsFileName {
where
T: Read + Seek,
{
- NtfsString::read_from_fs(fs, self.name_position, self.name_length(), buf)
+ let mut value_attached = self.value.clone().attach(fs);
+ value_attached.seek(SeekFrom::Current(FILE_NAME_HEADER_SIZE))?;
+ NtfsString::from_reader(value_attached, self.name_length(), buf)
+ }
+
+ fn validate_name_length(&self, length: u64) -> Result<()> {
+ let total_size = FILE_NAME_HEADER_SIZE as u64 + self.name_length() as u64;
+
+ if total_size > length {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: self.value.data_position().unwrap(),
+ ty: NtfsAttributeType::FileName,
+ expected: length,
+ actual: total_size,
+ });
+ }
+
+ Ok(())
+ }
+}
+
+impl<'n> NewNtfsStructuredValue<'n> for NtfsFileName<'n> {
+ fn new<T>(fs: &mut T, value: NtfsAttributeValue<'n>, length: u64) -> Result<Self>
+ where
+ T: Read + Seek,
+ {
+ if length < FILE_NAME_MIN_SIZE {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: value.data_position().unwrap(),
+ ty: NtfsAttributeType::FileName,
+ expected: FILE_NAME_MIN_SIZE,
+ actual: length,
+ });
+ }
+
+ let mut value_attached = value.clone().attach(fs);
+ let header = value_attached.read_le::<FileNameHeader>()?;
+ let file_name = Self { header, value };
+ file_name.validate_name_length(length)?;
+
+ Ok(file_name)
}
}
diff --git a/src/structured_values/index_root.rs b/src/structured_values/index_root.rs
index 14873e2..26c7115 100644
--- a/src/structured_values/index_root.rs
+++ b/src/structured_values/index_root.rs
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use crate::attribute::NtfsAttributeType;
-use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
+use crate::structured_values::NewNtfsStructuredValue;
use binread::io::{Read, Seek};
use binread::{BinRead, BinReaderExt};
@@ -33,23 +34,21 @@ pub struct NtfsIndexRoot {
header: IndexRootHeader,
}
-impl NtfsIndexRoot {
- pub(crate) fn new<T>(
- attribute_position: u64,
- mut value_attached: NtfsAttributeValueAttached<'_, '_, T>,
- ) -> Result<Self>
+impl<'n> NewNtfsStructuredValue<'n> for NtfsIndexRoot<'n> {
+ fn new<T>(fs: &mut T, value: NtfsAttributeValue<'n>, _length: u64) -> Result<Self>
where
T: Read + Seek,
{
- if value_attached.len() < INDEX_ROOT_HEADER_SIZE {
- return Err(NtfsError::InvalidAttributeSize {
- position: attribute_position,
+ if value.len() < INDEX_ROOT_HEADER_SIZE {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: value.data_position().unwrap(),
ty: NtfsAttributeType::IndexRoot,
expected: INDEX_ROOT_HEADER_SIZE,
- actual: value_attached.len(),
+ actual: value.len(),
});
}
+ let mut value_attached = value.clone().attach(fs);
let header = value_attached.read_le::<IndexRootHeader>()?;
Ok(Self { header })
diff --git a/src/structured_values/mod.rs b/src/structured_values/mod.rs
index bc089bb..9fb743d 100644
--- a/src/structured_values/mod.rs
+++ b/src/structured_values/mod.rs
@@ -19,6 +19,9 @@ pub use standard_information::*;
pub use volume_information::*;
pub use volume_name::*;
+use crate::attribute_value::NtfsAttributeValue;
+use crate::error::Result;
+use binread::io::{Read, Seek};
use bitflags::bitflags;
bitflags! {
@@ -40,11 +43,17 @@ bitflags! {
}
#[derive(Clone, Debug)]
-pub enum NtfsStructuredValue {
+pub enum NtfsStructuredValue<'n> {
StandardInformation(NtfsStandardInformation),
- FileName(NtfsFileName),
+ FileName(NtfsFileName<'n>),
ObjectId(NtfsObjectId),
VolumeInformation(NtfsVolumeInformation),
- VolumeName(NtfsVolumeName),
+ VolumeName(NtfsVolumeName<'n>),
IndexRoot(NtfsIndexRoot),
}
+
+pub trait NewNtfsStructuredValue<'n>: Sized {
+ fn new<T>(fs: &mut T, value: NtfsAttributeValue<'n>, length: u64) -> Result<Self>
+ where
+ T: Read + Seek;
+}
diff --git a/src/structured_values/object_id.rs b/src/structured_values/object_id.rs
index 998536d..98785e6 100644
--- a/src/structured_values/object_id.rs
+++ b/src/structured_values/object_id.rs
@@ -2,9 +2,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use crate::attribute::NtfsAttributeType;
-use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
use crate::guid::{NtfsGuid, GUID_SIZE};
+use crate::structured_values::NewNtfsStructuredValue;
use binread::io::{Read, Seek};
use binread::BinReaderExt;
@@ -17,36 +18,52 @@ pub struct NtfsObjectId {
}
impl NtfsObjectId {
- pub(crate) fn new<T>(
- attribute_position: u64,
- mut value_attached: NtfsAttributeValueAttached<'_, '_, T>,
- ) -> Result<Self>
+ pub fn birth_object_id(&self) -> Option<&NtfsGuid> {
+ self.birth_object_id.as_ref()
+ }
+
+ pub fn birth_volume_id(&self) -> Option<&NtfsGuid> {
+ self.birth_volume_id.as_ref()
+ }
+
+ pub fn domain_id(&self) -> Option<&NtfsGuid> {
+ self.domain_id.as_ref()
+ }
+
+ pub fn object_id(&self) -> &NtfsGuid {
+ &self.object_id
+ }
+}
+
+impl<'n> NewNtfsStructuredValue<'n> for NtfsObjectId {
+ fn new<T>(fs: &mut T, value: NtfsAttributeValue<'n>, length: u64) -> Result<Self>
where
T: Read + Seek,
{
- if value_attached.len() < GUID_SIZE {
- return Err(NtfsError::InvalidAttributeSize {
- position: attribute_position,
+ if length < GUID_SIZE {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: value.data_position().unwrap(),
ty: NtfsAttributeType::ObjectId,
expected: GUID_SIZE,
- actual: value_attached.len(),
+ actual: length,
});
}
+ let mut value_attached = value.attach(fs);
let object_id = value_attached.read_le::<NtfsGuid>()?;
let mut birth_volume_id = None;
- if value_attached.len() >= 2 * GUID_SIZE {
+ if length >= 2 * GUID_SIZE {
birth_volume_id = Some(value_attached.read_le::<NtfsGuid>()?);
}
let mut birth_object_id = None;
- if value_attached.len() >= 3 * GUID_SIZE {
+ if length >= 3 * GUID_SIZE {
birth_object_id = Some(value_attached.read_le::<NtfsGuid>()?);
}
let mut domain_id = None;
- if value_attached.len() >= 4 * GUID_SIZE {
+ if length >= 4 * GUID_SIZE {
domain_id = Some(value_attached.read_le::<NtfsGuid>()?);
}
@@ -57,20 +74,4 @@ impl NtfsObjectId {
domain_id,
})
}
-
- pub fn birth_object_id(&self) -> Option<&NtfsGuid> {
- self.birth_object_id.as_ref()
- }
-
- pub fn birth_volume_id(&self) -> Option<&NtfsGuid> {
- self.birth_volume_id.as_ref()
- }
-
- pub fn domain_id(&self) -> Option<&NtfsGuid> {
- self.domain_id.as_ref()
- }
-
- pub fn object_id(&self) -> &NtfsGuid {
- &self.object_id
- }
}
diff --git a/src/structured_values/standard_information.rs b/src/structured_values/standard_information.rs
index 3975be5..a596d2c 100644
--- a/src/structured_values/standard_information.rs
+++ b/src/structured_values/standard_information.rs
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use crate::attribute::NtfsAttributeType;
-use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
-use crate::structured_values::NtfsFileAttributeFlags;
+use crate::structured_values::{NewNtfsStructuredValue, NtfsFileAttributeFlags};
use crate::time::NtfsTime;
use binread::io::{Read, Seek};
use binread::{BinRead, BinReaderExt};
@@ -42,32 +42,6 @@ pub struct NtfsStandardInformation {
}
impl NtfsStandardInformation {
- pub(crate) fn new<T>(
- attribute_position: u64,
- mut value_attached: NtfsAttributeValueAttached<'_, '_, T>,
- ) -> Result<Self>
- where
- T: Read + Seek,
- {
- if value_attached.len() < STANDARD_INFORMATION_SIZE_NTFS1 {
- return Err(NtfsError::InvalidAttributeSize {
- position: attribute_position,
- ty: NtfsAttributeType::StandardInformation,
- expected: STANDARD_INFORMATION_SIZE_NTFS1,
- actual: value_attached.len(),
- });
- }
-
- let data = value_attached.read_le::<StandardInformationData>()?;
-
- let mut ntfs3_data = None;
- if value_attached.len() >= STANDARD_INFORMATION_SIZE_NTFS3 {
- ntfs3_data = Some(value_attached.read_le::<StandardInformationDataNtfs3>()?);
- }
-
- Ok(Self { data, ntfs3_data })
- }
-
pub fn access_time(&self) -> NtfsTime {
self.data.access_time
}
@@ -117,6 +91,32 @@ impl NtfsStandardInformation {
}
}
+impl<'n> NewNtfsStructuredValue<'n> for NtfsStandardInformation {
+ fn new<T>(fs: &mut T, value: NtfsAttributeValue<'n>, length: u64) -> Result<Self>
+ where
+ T: Read + Seek,
+ {
+ if length < STANDARD_INFORMATION_SIZE_NTFS1 {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: value.data_position().unwrap(),
+ ty: NtfsAttributeType::StandardInformation,
+ expected: STANDARD_INFORMATION_SIZE_NTFS1,
+ actual: length,
+ });
+ }
+
+ let mut value_attached = value.attach(fs);
+ let data = value_attached.read_le::<StandardInformationData>()?;
+
+ let mut ntfs3_data = None;
+ if length >= STANDARD_INFORMATION_SIZE_NTFS3 {
+ ntfs3_data = Some(value_attached.read_le::<StandardInformationDataNtfs3>()?);
+ }
+
+ Ok(Self { data, ntfs3_data })
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/structured_values/volume_information.rs b/src/structured_values/volume_information.rs
index 4dc3cb1..9efd1c6 100644
--- a/src/structured_values/volume_information.rs
+++ b/src/structured_values/volume_information.rs
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use crate::attribute::NtfsAttributeType;
-use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
+use crate::structured_values::NewNtfsStructuredValue;
use binread::io::{Read, Seek};
use binread::{BinRead, BinReaderExt};
use bitflags::bitflags;
@@ -39,36 +40,36 @@ pub struct NtfsVolumeInformation {
}
impl NtfsVolumeInformation {
- pub(crate) fn new<T>(
- attribute_position: u64,
- mut value_attached: NtfsAttributeValueAttached<'_, '_, T>,
- ) -> Result<Self>
+ pub fn flags(&self) -> NtfsVolumeFlags {
+ NtfsVolumeFlags::from_bits_truncate(self.data.flags)
+ }
+
+ pub fn major_version(&self) -> u8 {
+ self.data.major_version
+ }
+
+ pub fn minor_version(&self) -> u8 {
+ self.data.minor_version
+ }
+}
+
+impl<'n> NewNtfsStructuredValue<'n> for NtfsVolumeInformation {
+ fn new<T>(fs: &mut T, value: NtfsAttributeValue<'n>, length: u64) -> Result<Self>
where
T: Read + Seek,
{
- if value_attached.len() < VOLUME_INFORMATION_SIZE {
- return Err(NtfsError::InvalidAttributeSize {
- position: attribute_position,
+ if length < VOLUME_INFORMATION_SIZE {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: value.data_position().unwrap(),
ty: NtfsAttributeType::StandardInformation,
expected: VOLUME_INFORMATION_SIZE,
- actual: value_attached.len(),
+ actual: length,
});
}
+ let mut value_attached = value.attach(fs);
let data = value_attached.read_le::<VolumeInformationData>()?;
Ok(Self { data })
}
-
- pub fn flags(&self) -> NtfsVolumeFlags {
- NtfsVolumeFlags::from_bits_truncate(self.data.flags)
- }
-
- pub fn major_version(&self) -> u8 {
- self.data.major_version
- }
-
- pub fn minor_version(&self) -> u8 {
- self.data.minor_version
- }
}
diff --git a/src/structured_values/volume_name.rs b/src/structured_values/volume_name.rs
index 9633f78..ba126e4 100644
--- a/src/structured_values/volume_name.rs
+++ b/src/structured_values/volume_name.rs
@@ -2,9 +2,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use crate::attribute::NtfsAttributeType;
-use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
use crate::string::NtfsString;
+use crate::structured_values::NewNtfsStructuredValue;
use binread::io::{Read, Seek};
use core::mem;
@@ -15,44 +16,12 @@ const VOLUME_NAME_MIN_SIZE: u64 = mem::size_of::<u16>() as u64;
const VOLUME_NAME_MAX_SIZE: u64 = 128 * mem::size_of::<u16>() as u64;
#[derive(Clone, Debug)]
-pub struct NtfsVolumeName {
- name_position: u64,
+pub struct NtfsVolumeName<'n> {
+ value: NtfsAttributeValue<'n>,
name_length: u16,
}
-impl NtfsVolumeName {
- pub(crate) fn new<T>(
- attribute_position: u64,
- value_attached: NtfsAttributeValueAttached<'_, '_, T>,
- ) -> Result<Self>
- where
- T: Read + Seek,
- {
- if value_attached.len() < VOLUME_NAME_MIN_SIZE {
- return Err(NtfsError::InvalidAttributeSize {
- position: attribute_position,
- ty: NtfsAttributeType::VolumeName,
- expected: VOLUME_NAME_MIN_SIZE,
- actual: value_attached.len(),
- });
- } else if value_attached.len() > VOLUME_NAME_MAX_SIZE {
- return Err(NtfsError::InvalidAttributeSize {
- position: attribute_position,
- ty: NtfsAttributeType::VolumeName,
- expected: VOLUME_NAME_MAX_SIZE,
- actual: value_attached.len(),
- });
- }
-
- let name_position = value_attached.position();
- let name_length = value_attached.len() as u16;
-
- Ok(Self {
- name_position,
- name_length,
- })
- }
-
+impl<'n> NtfsVolumeName<'n> {
/// Returns the volume name length, in bytes.
///
/// A volume name has a maximum length of 128 UTF-16 code points (256 bytes).
@@ -66,6 +35,34 @@ impl NtfsVolumeName {
where
T: Read + Seek,
{
- NtfsString::read_from_fs(fs, self.name_position, self.name_length(), buf)
+ let value_attached = self.value.clone().attach(fs);
+ NtfsString::from_reader(value_attached, self.name_length(), buf)
+ }
+}
+
+impl<'n> NewNtfsStructuredValue<'n> for NtfsVolumeName<'n> {
+ fn new<T>(_fs: &mut T, value: NtfsAttributeValue<'n>, length: u64) -> Result<Self>
+ where
+ T: Read + Seek,
+ {
+ if length < VOLUME_NAME_MIN_SIZE {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: value.data_position().unwrap(),
+ ty: NtfsAttributeType::VolumeName,
+ expected: VOLUME_NAME_MIN_SIZE,
+ actual: length,
+ });
+ } else if length > VOLUME_NAME_MAX_SIZE {
+ return Err(NtfsError::InvalidStructuredValueSize {
+ position: value.data_position().unwrap(),
+ ty: NtfsAttributeType::VolumeName,
+ expected: VOLUME_NAME_MAX_SIZE,
+ actual: length,
+ });
+ }
+
+ let name_length = length as u16;
+
+ Ok(Self { value, name_length })
}
}