diff options
author | Omer Ben-Amram <omerbenamram@gmail.com> | 2019-05-15 23:28:59 +0300 |
---|---|---|
committer | Omer Ben-Amram <omerbenamram@gmail.com> | 2019-05-15 23:28:59 +0300 |
commit | 6a3c23feadc5290b20a4e6f55775f0a4ac91e662 (patch) | |
tree | e2a64f2b462c0b6fa7f89cbeb8343952b13a1515 | |
parent | 93551bb9acce8d71004f5485ffd7e896292c87a4 (diff) |
Implement get full pathget-full-path
-rw-r--r-- | src/entry.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/mft.rs | 65 | ||||
-rw-r--r-- | src/tests/fixtures.rs | 13 | ||||
-rw-r--r-- | src/tests/mod.rs | 1 |
5 files changed, 61 insertions, 25 deletions
diff --git a/src/entry.rs b/src/entry.rs index afe19d7..a19cad6 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -25,7 +25,7 @@ use std::io::{Cursor, Seek}; const SEQUENCE_NUMBER_STRIDE: usize = 512; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MftEntry { pub header: EntryHeader, pub data: Vec<u8>, @@ -46,7 +46,7 @@ impl ser::Serialize for MftEntry { /// https://docs.microsoft.com/en-us/windows/desktop/devnotes/file-record-segment-header /// The MFT entry can be filled entirely with 0-byte values. -#[derive(Serialize, Debug)] +#[derive(Serialize, Debug, Clone)] pub struct EntryHeader { /// MULTI_SECTOR_HEADER /// The signature. This value is a convenience to the user. @@ -18,6 +18,9 @@ pub mod mft; pub(crate) mod macros; pub(crate) mod utils; +#[cfg(test)] +pub(crate) mod tests; + pub trait ReadSeek: Read + Seek { fn tell(&mut self) -> io::Result<u64> { self.seek(SeekFrom::Current(0)) @@ -2,7 +2,7 @@ use crate::entry::MftEntry; use crate::err::{self, Result}; use crate::{EntryHeader, ReadSeek}; -use log::debug; +use log::{debug, trace}; use snafu::ResultExt; use crate::attribute::MftAttributeContent::AttrX30; @@ -93,28 +93,43 @@ impl<T: ReadSeek> MftParser<T> { } /// Gets the full path for an entry. + /// Cached computations. pub fn get_full_path_for_entry(&mut self, entry: &MftEntry) -> Result<Option<PathBuf>> { + let entry_id = entry.header.entry_reference.entry; + for attribute in entry.iter_attributes().filter_map(|a| a.ok()) { if let AttrX30(filename_header) = attribute.data { let parent_entry_id = filename_header.parent.entry; - if parent_entry_id > 0 { - // If my parent path is known, then my path is parent's path + my name. - // Else, look and cache my parent's path. - let parent_entry = self.get_entry(parent_entry_id).ok(); - let parent_path = - self.entries_cache - .entry(parent_entry_id) - .or_insert_with(|| match parent_entry { - Some(e) => self - .get_full_path_for_entry(&e) - .expect("We've checked that parent_entry > 0") - .unwrap(), + if parent_entry_id > 0 { + // If i'm my own parent, I'm the root path. + if parent_entry_id == entry_id { + return Ok(Some(PathBuf::from(filename_header.name))); + } - None => PathBuf::from("[Unknown]"), - }); + let cached_entry = self.entries_cache.get(&parent_entry_id); - return Ok(Some(parent_path.clone().join(filename_header.name))); + // If my parent path is known, then my path is parent's path + my name. + // Else, look and cache my parent's path. + if let Some(cached_parent_path) = cached_entry { + return Ok(Some(cached_parent_path.clone().join(filename_header.name))); + } else { + let path = match self.get_entry(parent_entry_id).ok() { + Some(parent) => self + .get_full_path_for_entry(&parent) + .expect("We've checked that parent_entry > 0") + .unwrap(), + None => PathBuf::from("[Unknown]"), + }; + + self.entries_cache.insert(parent_entry_id, path.clone()); + return Ok(Some(path.join(filename_header.name))); + } + } else { + let root = PathBuf::from(filename_header.name); + self.entries_cache + .insert(entry.header.entry_reference.entry, root.clone()); + return Ok(Some(root)); } } } @@ -125,19 +140,14 @@ impl<T: ReadSeek> MftParser<T> { #[cfg(test)] mod tests { + use crate::tests::fixtures::mft_sample; use crate::MftParser; use std::path::PathBuf; // entrypoint for clion profiler. #[test] fn test_process_90_mft_entries() { - let sample = PathBuf::from(file!()) - .parent() - .unwrap() - .parent() - .unwrap() - .join("samples") - .join("MFT"); + let sample = mft_sample(); let mut parser = MftParser::from_path(sample).unwrap(); @@ -148,4 +158,13 @@ mod tests { } } } + + #[test] + fn test_get_full_name() { + let sample = mft_sample(); + let mut parser = MftParser::from_path(sample).unwrap(); + + let e = parser.get_entry(5).unwrap(); + parser.get_full_path_for_entry(&e).unwrap(); + } } diff --git a/src/tests/fixtures.rs b/src/tests/fixtures.rs new file mode 100644 index 0000000..38e338f --- /dev/null +++ b/src/tests/fixtures.rs @@ -0,0 +1,13 @@ +use std::path::PathBuf; + +pub fn mft_sample() -> PathBuf { + PathBuf::from(file!()) + .parent() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .join("samples") + .join("MFT") +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs new file mode 100644 index 0000000..d066349 --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1 @@ +pub mod fixtures; |