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-09-17 20:13:14 +0300
committerColin Finck <colin@reactos.org>2021-09-17 20:13:14 +0300
commitc45b7cc2af981f77d9f043bd92e1017c1fe3bb2e (patch)
tree9c1ee0d6f3c9bee8c5f28d9d550df8003040eff6
parentfb0551dfcd05a506e4bd86bcd364134841bd4cf4 (diff)
Fix `Ntfs::file` to support files outside the first MFT data run.
This change has notable negative performance implications, as the $MFT record is now read and fixed up on every file lookup. This needs to be fixed later via caching.
-rw-r--r--src/file.rs21
-rw-r--r--src/ntfs.rs23
2 files changed, 38 insertions, 6 deletions
diff --git a/src/file.rs b/src/file.rs
index 16f791c..f2dff53 100644
--- a/src/file.rs
+++ b/src/file.rs
@@ -56,10 +56,16 @@ bitflags! {
#[derive(Debug)]
pub struct NtfsFile<'n> {
record: Record<'n>,
+ file_record_number: u64,
}
impl<'n> NtfsFile<'n> {
- pub(crate) fn new<T>(ntfs: &'n Ntfs, fs: &mut T, position: u64) -> Result<Self>
+ pub(crate) fn new<T>(
+ ntfs: &'n Ntfs,
+ fs: &mut T,
+ position: u64,
+ file_record_number: u64,
+ ) -> Result<Self>
where
T: Read + Seek,
{
@@ -71,7 +77,10 @@ impl<'n> NtfsFile<'n> {
Self::validate_signature(&record)?;
record.fixup()?;
- let file = Self { record };
+ let file = Self {
+ record,
+ file_record_number,
+ };
file.validate_sizes()?;
Ok(file)
@@ -186,6 +195,14 @@ impl<'n> NtfsFile<'n> {
NtfsIndex::<NtfsFileNameIndex>::new(index_root, index_allocation)
}
+ /// Returns the NTFS file record number of this file.
+ ///
+ /// This number uniquely identifies this file and can be used to recreate this [`NtfsFile`]
+ /// object via [`Ntfs::file`].
+ pub fn file_record_number(&self) -> u64 {
+ self.file_record_number
+ }
+
pub(crate) fn first_attribute_offset(&self) -> u16 {
let start = offset_of!(FileRecordHeader, first_attribute_offset);
LittleEndian::read_u16(&self.record.data()[start..])
diff --git a/src/ntfs.rs b/src/ntfs.rs
index deaa546..bb99e92 100644
--- a/src/ntfs.rs
+++ b/src/ntfs.rs
@@ -6,6 +6,7 @@ use crate::boot_sector::BootSector;
use crate::error::{NtfsError, Result};
use crate::file::{KnownNtfsFileRecordNumber, NtfsFile};
use crate::structured_values::{NtfsVolumeInformation, NtfsVolumeName};
+use crate::traits::NtfsReadSeek;
use crate::upcase_table::UpcaseTable;
use binread::io::{Read, Seek, SeekFrom};
use binread::BinReaderExt;
@@ -77,17 +78,31 @@ impl Ntfs {
let offset = file_record_number
.checked_mul(self.file_record_size as u64)
.ok_or(NtfsError::InvalidFileRecordNumber { file_record_number })?;
- let position = self
- .mft_position
- .checked_add(offset)
+
+ let mft = NtfsFile::new(&self, fs, self.mft_position, 0)?;
+ let mft_data_attribute = mft.data("").ok_or(NtfsError::AttributeNotFound {
+ position: self.mft_position,
+ ty: NtfsAttributeType::Data,
+ })??;
+ let mut mft_data_value = mft_data_attribute.value()?;
+
+ mft_data_value.seek(fs, SeekFrom::Start(offset))?;
+ let position = mft_data_value
+ .data_position()
.ok_or(NtfsError::InvalidFileRecordNumber { file_record_number })?;
- NtfsFile::new(&self, fs, position)
+
+ NtfsFile::new(&self, fs, position, file_record_number)
}
pub fn file_record_size(&self) -> u32 {
self.file_record_size
}
+ /// Returns the absolute byte position of the Master File Table (MFT).
+ pub fn mft_position(&self) -> u64 {
+ self.mft_position
+ }
+
/// Reads the $UpCase file from the filesystem and stores it in this [`Ntfs`] object.
///
/// This function only needs to be called if case-insensitive comparisons are later performed