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-04-21 22:41:28 +0300
committerColin Finck <colin@reactos.org>2021-04-21 22:41:28 +0300
commita724f9775f268ef313982c73c712b389d3faf186 (patch)
treea0c16358af9470319077e8264b58556fd46137e6
parent11be5cf34e0b455a4677c3eb8cf72032ac97fbe6 (diff)
Implement `NtfsVolumeInformation` and `NtfsVolumeName` structured values
-rw-r--r--src/attribute.rs13
-rw-r--r--src/structured_values/mod.rs2
-rw-r--r--src/structured_values/volume_information.rs73
-rw-r--r--src/structured_values/volume_name.rs81
4 files changed, 167 insertions, 2 deletions
diff --git a/src/attribute.rs b/src/attribute.rs
index 9be8ebe..37d5582 100644
--- a/src/attribute.rs
+++ b/src/attribute.rs
@@ -7,6 +7,7 @@ use crate::ntfs_file::NtfsFile;
use crate::string::NtfsString;
use crate::structured_values::{
NtfsFileName, NtfsObjectId, NtfsStandardInformation, NtfsStructuredValue,
+ NtfsVolumeInformation, NtfsVolumeName,
};
use binread::io::{Read, Seek, SeekFrom};
use binread::{BinRead, BinReaderExt};
@@ -253,8 +254,16 @@ impl NtfsAttribute {
Ok(NtfsStructuredValue::ObjectId(inner))
}
NtfsAttributeType::SecurityDescriptor => panic!("TODO"),
- NtfsAttributeType::VolumeName => panic!("TODO"),
- NtfsAttributeType::VolumeInformation => panic!("TODO"),
+ NtfsAttributeType::VolumeName => {
+ let inner =
+ NtfsVolumeName::new(self.position, attached_value, self.value_length())?;
+ Ok(NtfsStructuredValue::VolumeName(inner))
+ }
+ NtfsAttributeType::VolumeInformation => {
+ let inner =
+ NtfsVolumeInformation::new(self.position, attached_value, self.value_length())?;
+ Ok(NtfsStructuredValue::VolumeInformation(inner))
+ }
ty => Err(NtfsError::UnsupportedStructuredValue {
position: self.position,
ty,
diff --git a/src/structured_values/mod.rs b/src/structured_values/mod.rs
index 4a18d91..99b3cee 100644
--- a/src/structured_values/mod.rs
+++ b/src/structured_values/mod.rs
@@ -42,4 +42,6 @@ pub enum NtfsStructuredValue {
StandardInformation(NtfsStandardInformation),
FileName(NtfsFileName),
ObjectId(NtfsObjectId),
+ VolumeInformation(NtfsVolumeInformation),
+ VolumeName(NtfsVolumeName),
}
diff --git a/src/structured_values/volume_information.rs b/src/structured_values/volume_information.rs
index 53769a7..57243ce 100644
--- a/src/structured_values/volume_information.rs
+++ b/src/structured_values/volume_information.rs
@@ -1,2 +1,75 @@
// Copyright 2021 Colin Finck <colin@reactos.org>
// SPDX-License-Identifier: GPL-2.0-or-later
+
+use crate::attribute::NtfsAttributeType;
+use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::error::{NtfsError, Result};
+use binread::io::{Read, Seek};
+use binread::{BinRead, BinReaderExt};
+use bitflags::bitflags;
+
+/// Size of all [`VolumeInformationData`] fields.
+const VOLUME_INFORMATION_SIZE: u64 = 12;
+
+#[derive(BinRead, Clone, Debug)]
+struct VolumeInformationData {
+ reserved: u64,
+ major_version: u8,
+ minor_version: u8,
+ flags: u16,
+}
+
+bitflags! {
+ pub struct NtfsVolumeFlags: u16 {
+ /// The volume needs to be checked by `chkdsk`.
+ const IS_DIRTY = 0x0001;
+ const RESIZE_LOG_FILE = 0x0002;
+ const UPGRADE_ON_MOUNT = 0x0004;
+ const MOUNTED_ON_NT4 = 0x0008;
+ const DELETE_USN_UNDERWAY = 0x0010;
+ const REPAIR_OBJECT_ID = 0x0020;
+ const CHKDSK_UNDERWAY = 0x4000;
+ const MODIFIED_BY_CHKDSK = 0x8000;
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct NtfsVolumeInformation {
+ data: VolumeInformationData,
+}
+
+impl NtfsVolumeInformation {
+ pub(crate) fn new<T>(
+ attribute_position: u64,
+ mut value_attached: NtfsAttributeValueAttached<'_, T>,
+ value_length: u64,
+ ) -> Result<Self>
+ where
+ T: Read + Seek,
+ {
+ if value_length < VOLUME_INFORMATION_SIZE {
+ return Err(NtfsError::InvalidAttributeSize {
+ position: attribute_position,
+ ty: NtfsAttributeType::StandardInformation,
+ expected: VOLUME_INFORMATION_SIZE,
+ actual: value_length,
+ });
+ }
+
+ 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 53769a7..72bd3bc 100644
--- a/src/structured_values/volume_name.rs
+++ b/src/structured_values/volume_name.rs
@@ -1,2 +1,83 @@
// Copyright 2021 Colin Finck <colin@reactos.org>
// SPDX-License-Identifier: GPL-2.0-or-later
+
+use crate::attribute::NtfsAttributeType;
+use crate::attribute_value::NtfsAttributeValueAttached;
+use crate::error::{NtfsError, Result};
+use crate::string::NtfsString;
+use binread::io::{Read, Seek, SeekFrom};
+use core::mem;
+
+/// The smallest VolumeName attribute has a name containing just a single character.
+const VOLUME_NAME_MIN_SIZE: u64 = mem::size_of::<u16>() as u64;
+
+/// The largest VolumeName attribute has a name containing 128 UTF-16 code points (256 bytes).
+const VOLUME_NAME_MAX_SIZE: u64 = 128 * mem::size_of::<u16>() as u64;
+
+#[derive(Clone, Debug)]
+pub struct NtfsVolumeName {
+ name_position: u64,
+ name_length: u16,
+}
+
+impl NtfsVolumeName {
+ pub(crate) fn new<T>(
+ attribute_position: u64,
+ value_attached: NtfsAttributeValueAttached<'_, T>,
+ value_length: u64,
+ ) -> Result<Self>
+ where
+ T: Read + Seek,
+ {
+ if value_length < VOLUME_NAME_MIN_SIZE {
+ return Err(NtfsError::InvalidAttributeSize {
+ position: attribute_position,
+ ty: NtfsAttributeType::VolumeName,
+ expected: VOLUME_NAME_MIN_SIZE,
+ actual: value_length,
+ });
+ } else if value_length > VOLUME_NAME_MAX_SIZE {
+ return Err(NtfsError::InvalidAttributeSize {
+ position: attribute_position,
+ ty: NtfsAttributeType::VolumeName,
+ expected: VOLUME_NAME_MAX_SIZE,
+ actual: value_length,
+ });
+ }
+
+ let name_position = value_attached.position();
+ let name_length = value_length as u16;
+
+ Ok(Self {
+ name_position,
+ name_length,
+ })
+ }
+
+ /// Returns the volume name length, in bytes.
+ ///
+ /// A volume name has a maximum length of 128 UTF-16 code points (256 bytes).
+ pub fn name_length(&self) -> usize {
+ self.name_length as usize
+ }
+
+ /// Reads the volume name into the given buffer, and returns an
+ /// [`NtfsString`] wrapping that buffer.
+ pub fn read_name<'a, T>(&self, fs: &mut T, buf: &'a mut [u8]) -> Result<NtfsString<'a>>
+ where
+ T: Read + Seek,
+ {
+ let name_length = self.name_length();
+ if buf.len() < name_length {
+ return Err(NtfsError::BufferTooSmall {
+ expected: name_length,
+ actual: buf.len(),
+ });
+ }
+
+ fs.seek(SeekFrom::Start(self.name_position))?;
+ fs.read_exact(&mut buf[..name_length])?;
+
+ Ok(NtfsString(&buf[..name_length]))
+ }
+}