diff options
author | Colin Finck <colin@reactos.org> | 2021-06-04 12:46:52 +0300 |
---|---|---|
committer | Colin Finck <colin@reactos.org> | 2021-06-04 12:46:52 +0300 |
commit | cba70d68b52025dda25d07e516d27ca7c73b607f (patch) | |
tree | 8e1b59d70ff04a8cf99e9f0be7406cc9ab47857f | |
parent | 98ffe4dec521551bb1b0ae904d730d360d3673eb (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.rs | 36 | ||||
-rw-r--r-- | src/attribute_value.rs | 63 | ||||
-rw-r--r-- | src/error.rs | 14 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/ntfs.rs | 4 | ||||
-rw-r--r-- | src/string.rs | 39 | ||||
-rw-r--r-- | src/structured_values/file_name.rs | 85 | ||||
-rw-r--r-- | src/structured_values/index_root.rs | 19 | ||||
-rw-r--r-- | src/structured_values/mod.rs | 15 | ||||
-rw-r--r-- | src/structured_values/object_id.rs | 57 | ||||
-rw-r--r-- | src/structured_values/standard_information.rs | 56 | ||||
-rw-r--r-- | src/structured_values/volume_information.rs | 43 | ||||
-rw-r--r-- | src/structured_values/volume_name.rs | 71 |
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, @@ -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 }) } } |