Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/RustyMft.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatthew seyer <matthew.seyer@gmail.com>2017-05-22 05:15:58 +0300
committermatthew seyer <matthew.seyer@gmail.com>2017-05-22 05:15:58 +0300
commitc4a9a22cd06f59ea5060481df99f5a7b09db8e26 (patch)
tree5a22f8bb4125c366bc8c5a0a3f43bb3dbe5aea37
parenta65d3af5a8314b0b65e5ea34d76abb76058c2764 (diff)
Changed Attribute Naming standards and now storing attributes as an array.
-rw-r--r--src/attr_x10.rs14
-rw-r--r--src/attr_x30.rs14
-rw-r--r--src/attribute.rs47
-rw-r--r--src/entry.rs148
-rw-r--r--src/main.rs1
-rw-r--r--src/mft.rs6
6 files changed, 158 insertions, 72 deletions
diff --git a/src/attr_x10.rs b/src/attr_x10.rs
index aeaa771..c3982bc 100644
--- a/src/attr_x10.rs
+++ b/src/attr_x10.rs
@@ -5,8 +5,8 @@ use byteorder::{ReadBytesExt, LittleEndian};
use std::io::Read;
use std::mem;
-#[derive(Serialize, Debug)]
-pub struct StandardInformationAttribute {
+#[derive(Serialize, Clone, Debug)]
+pub struct StandardInfoAttr {
pub created: WinTimestamp,
pub modified: WinTimestamp,
pub mft_modified: WinTimestamp,
@@ -22,9 +22,9 @@ pub struct StandardInformationAttribute {
#[serde(serialize_with = "serialize_u64")]
pub usn: u64
}
-impl StandardInformationAttribute {
- pub fn new<R: Read>(mut reader: R) -> Result<StandardInformationAttribute,MftError> {
- let mut attribute: StandardInformationAttribute = unsafe {
+impl StandardInfoAttr {
+ pub fn new<R: Read>(mut reader: R) -> Result<StandardInfoAttr,MftError> {
+ let mut attribute: StandardInfoAttr = unsafe {
mem::zeroed()
};
@@ -47,7 +47,7 @@ impl StandardInformationAttribute {
#[cfg(test)]
mod tests {
- use super::StandardInformationAttribute;
+ use super::StandardInfoAttr;
#[test]
fn si_attribute_test_01() {
@@ -59,7 +59,7 @@ mod tests {
0x68,0x58,0xA0,0x0A,0x02,0x00,0x00,0x00
];
- let attribute = match StandardInformationAttribute::new(attribute_buffer) {
+ let attribute = match StandardInfoAttr::new(attribute_buffer) {
Ok(attribute) => attribute,
Err(error) => panic!(error)
};
diff --git a/src/attr_x30.rs b/src/attr_x30.rs
index 8b99e1e..9218156 100644
--- a/src/attr_x30.rs
+++ b/src/attr_x30.rs
@@ -8,8 +8,8 @@ use encoding::all::UTF_16LE;
use std::io::Read;
use std::mem;
-#[derive(Serialize, Debug)]
-pub struct FileNameAttribute {
+#[derive(Serialize, Clone, Debug)]
+pub struct FileNameAttr {
pub parent: MftReference,
pub created: WinTimestamp,
pub modified: WinTimestamp,
@@ -26,9 +26,9 @@ pub struct FileNameAttribute {
pub name: String,
pub fullname: Option<String>
}
-impl FileNameAttribute {
- pub fn new<R: Read>(mut reader: R) -> Result<FileNameAttribute,MftError> {
- let mut attribute: FileNameAttribute = unsafe {
+impl FileNameAttr {
+ pub fn new<R: Read>(mut reader: R) -> Result<FileNameAttr,MftError> {
+ let mut attribute: FileNameAttr = unsafe {
mem::zeroed()
};
@@ -62,7 +62,7 @@ impl FileNameAttribute {
#[cfg(test)]
mod tests {
- use super::FileNameAttribute;
+ use super::FileNameAttr;
#[test]
fn fn_attribute_test_01() {
@@ -75,7 +75,7 @@ mod tests {
0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00
];
- let attribute = match FileNameAttribute::new(attribute_buffer) {
+ let attribute = match FileNameAttr::new(attribute_buffer) {
Ok(attribute) => attribute,
Err(error) => panic!(error)
};
diff --git a/src/attribute.rs b/src/attribute.rs
index 4a2ad08..8d662db 100644
--- a/src/attribute.rs
+++ b/src/attribute.rs
@@ -1,4 +1,7 @@
use errors::{MftError};
+use utils;
+use attr_x10::{StandardInfoAttr};
+use attr_x30::{FileNameAttr};
use rwinstructs::serialize::{serialize_u64};
use byteorder::{ReadBytesExt, LittleEndian};
use encoding::{Encoding, DecoderTrap};
@@ -9,6 +12,30 @@ use std::io::Seek;
use std::io::SeekFrom;
use std::mem;
+#[derive(Clone, Debug)]
+pub struct RawAttribute(
+ pub Vec<u8>
+);
+impl ser::Serialize for RawAttribute {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where S: ser::Serializer
+ {
+ serializer.serialize_str(
+ &format!("{}",
+ utils::to_hex_string(&self.0))
+ )
+ }
+}
+
+#[derive(Serialize, Clone, Debug)]
+#[serde(untagged)]
+pub enum AttributeContent {
+ Raw(RawAttribute),
+ AttrX10(StandardInfoAttr),
+ AttrX30(FileNameAttr),
+ None
+}
+
bitflags! {
pub flags AttributeDataFlags: u16 {
const IS_COMPRESSED = 0x0001,
@@ -24,7 +51,7 @@ pub fn serialize_attr_data_flags<S>(&item: &AttributeDataFlags, serializer: S)
serializer.serialize_str(&format!("{:?}", item))
}
-#[derive(Serialize, Debug)]
+#[derive(Serialize, Clone, Debug)]
pub struct AttributeHeader {
pub attribute_type: u32,
pub attribute_size: u32,
@@ -73,7 +100,11 @@ impl AttributeHeader {
)?
);
} else {
- panic!("Unhandled resident flag: {}",attribute_header.resident_flag);
+ panic!(
+ "Unhandled resident flag: {} (offet: {})",
+ attribute_header.resident_flag,
+ current_offset
+ );
}
if attribute_header.name_size > 0 {
@@ -101,7 +132,7 @@ impl AttributeHeader {
}
}
-#[derive(Serialize, Debug)]
+#[derive(Serialize, Clone, Debug)]
#[serde(untagged)]
pub enum ResidentialHeader{
None,
@@ -109,7 +140,7 @@ pub enum ResidentialHeader{
NonResident(NonResidentHeader)
}
-#[derive(Serialize, Debug)]
+#[derive(Serialize, Clone, Debug)]
pub struct ResidentHeader{
pub data_size: u32,
pub data_offset: u16,
@@ -131,7 +162,7 @@ impl ResidentHeader {
}
}
-#[derive(Serialize, Debug)]
+#[derive(Serialize, Clone, Debug)]
pub struct NonResidentHeader{
#[serde(serialize_with = "serialize_u64")]
pub vnc_first: u64,
@@ -171,6 +202,12 @@ impl NonResidentHeader {
}
}
+#[derive(Serialize, Clone, Debug)]
+pub struct MftAttribute{
+ pub header: AttributeHeader,
+ pub content: AttributeContent
+}
+
#[cfg(test)]
mod tests {
use std::io::Cursor;
diff --git a/src/entry.rs b/src/entry.rs
index ec9978b..b2f3dac 100644
--- a/src/entry.rs
+++ b/src/entry.rs
@@ -1,10 +1,10 @@
use errors::{MftError};
-use enumerator::{PathEnumerator,PathMapping};
+use enumerator::{PathMapping};
use mft::{MftHandler};
use attribute;
+use attr_x10::{StandardInfoAttr};
+use attr_x30::{FileNameAttr};
use utils;
-use attr_x10;
-use attr_x30;
use rwinstructs::reference::{MftReference};
use rwinstructs::serialize::{serialize_u64};
use byteorder::{ReadBytesExt, LittleEndian};
@@ -108,8 +108,7 @@ impl EntryHeader{
#[derive(Serialize, Debug)]
pub struct MftEntry{
pub header: EntryHeader,
- pub attr_standard_info: Option<Vec<attr_x10::StandardInformationAttribute>>,
- pub attr_filename: Option<Vec<attr_x30::FileNameAttribute>>
+ pub attributes: Vec<attribute::MftAttribute>
}
impl MftEntry{
pub fn new(mut buffer: Vec<u8>, entry: Option<u64>) -> Result<MftEntry,MftError> {
@@ -152,20 +151,22 @@ impl MftEntry{
}
pub fn get_pathmap(&self) -> Option<PathMapping> {
- match self.attr_filename {
- Some(ref attributes) => {
- for attribute in attributes {
- if attribute.namespace != 2 {
- return Some(
- PathMapping {
- name: attribute.name.clone(),
- parent: MftReference(attribute.parent.0)
- }
- );
+ for attribute in self.attributes.iter() {
+ if attribute.header.attribute_type == 0x30 {
+ match attribute.content {
+ attribute::AttributeContent::AttrX30(ref attrib) => {
+ if attrib.namespace != 2 {
+ return Some(
+ PathMapping {
+ name: attrib.name.clone(),
+ parent: MftReference(attrib.parent.0)
+ }
+ );
+ }
}
+ _ => {}
}
- },
- _ => {}
+ }
}
None
@@ -188,6 +189,7 @@ impl MftEntry{
let mut current_offset = buffer.seek(
SeekFrom::Start(self.header.fst_attr_offset as u64)
)?;
+
let attr_count: u32 = 0;
loop {
@@ -195,34 +197,73 @@ impl MftEntry{
&mut buffer
)?;
- match attribute_header.attribute_type {
- 0x10 => {
- let si_attr = attr_x10::StandardInformationAttribute::new(&mut buffer)?;
+ if attribute_header.attribute_type == 0xFFFFFFFF {
+ break;
+ }
- if self.attr_standard_info.is_none(){
- self.attr_standard_info = Some(Vec::new());
- }
+ match attribute_header.residential_header {
+ attribute::ResidentialHeader::Resident(ref header) => {
+ // Create buffer for raw attribute content
+ let mut content_buffer = vec![0;header.data_size as usize];
- self.attr_standard_info.as_mut().unwrap().push(si_attr);
- },
- 0x30 => {
- let fn_attr = attr_x30::FileNameAttribute::new(&mut buffer)?;
- if self.attr_filename.is_none(){
- self.attr_filename = Some(Vec::new());
+ // read into content buffer
+ buffer.read_exact(
+ &mut content_buffer
+ ).unwrap();
+
+ // Create attribute content to parse buffer into
+ let mut attr_content: attribute::AttributeContent = unsafe {
+ mem::zeroed()
+ };
+
+ // Get attribute contents
+ match attribute_header.attribute_type {
+ 0x10 => {
+ let attr = StandardInfoAttr::new(
+ content_buffer.as_slice()
+ )?;
+
+ attr_content = attribute::AttributeContent::AttrX10(
+ attr
+ );
+ },
+ 0x30 => {
+ let attr = FileNameAttr::new(
+ content_buffer.as_slice()
+ )?;
+
+ attr_content = attribute::AttributeContent::AttrX30(
+ attr
+ );
+ },
+ _ => {
+ attr_content = attribute::AttributeContent::Raw(
+ attribute::RawAttribute(
+ content_buffer
+ )
+ );
+ }
}
- self.attr_filename.as_mut().unwrap().push(fn_attr);
+ // push attribute into attributes
+ self.attributes.push(
+ attribute::MftAttribute {
+ header: attribute_header.clone(),
+ content: attr_content
+ }
+ );
},
- 0xFFFFFFFF => {
- // println!("END OF ATTRIBUTES");
- break;
+ attribute::ResidentialHeader::NonResident(_) => {
+ // No content, so push header into attributes
+ self.attributes.push(
+ attribute::MftAttribute {
+ header: attribute_header.clone(),
+ content: attribute::AttributeContent::None
+ }
+ );
},
- _ => {
- // println!(
- // "UNHANDLED ATTRIBUTE: 0x{:04X} at offset {}",
- // attribute_header.attribute_type,
- // current_offset
- // );
+ attribute::ResidentialHeader::None => {
+ // Not sure about this...
}
}
@@ -230,21 +271,30 @@ impl MftEntry{
SeekFrom::Start(current_offset + attribute_header.attribute_size as u64)
)?;
}
+
Ok(attr_count)
}
pub fn set_fullnames(&mut self, mft_handler: &mut MftHandler){
- match self.attr_filename {
- Some(ref mut attributes) => {
- for attribute in attributes {
- let fullpath = mft_handler.get_fullpath(
- attribute.parent
- );
- let fullname = fullpath + "/" + attribute.name.as_str();
- attribute.fullname = Some(fullname);
+ // Iterate through each MFT attribute with mutable reference
+ for attribute in self.attributes.iter_mut() {
+ // If attribute is type 0x30
+ if attribute.header.attribute_type == 0x30 {
+ // Check if resident content
+ match attribute.content {
+ attribute::AttributeContent::AttrX30(ref mut attrib) => {
+ // Get fullpath
+ let fullpath = mft_handler.get_fullpath(
+ attrib.parent
+ );
+ // Set fullname
+ let fullname = fullpath + "/" + attrib.name.as_str();
+ // Set attribute to fullname
+ attrib.fullname = Some(fullname);
+ }
+ _ => {}
}
- },
- _ => {}
+ }
}
}
}
diff --git a/src/main.rs b/src/main.rs
index 7d24845..c4c68d5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -29,7 +29,6 @@ fn process_directory<S>(directory: &str, serializer: S) where S: serde::Serializ
}
fn process_file<S: serde::ser::SerializeSeq>(filename: &str, serializer: &mut S) -> bool {
- // Check if file is a prefetch file
let mut mft_handler = match MftHandler::new(filename) {
Ok(mft_handler) => mft_handler,
Err(error) => {
diff --git a/src/mft.rs b/src/mft.rs
index 802f381..888f8fb 100644
--- a/src/mft.rs
+++ b/src/mft.rs
@@ -151,14 +151,14 @@ impl MftHandler{
fn get_mapping_from_entry(&mut self, entry: u64) -> Option<PathMapping>{
self.filehandle.seek(
SeekFrom::Start(entry * self._entry_size as u64)
- );
+ ).unwrap();
let mut entry_buffer = vec![0; self._entry_size as usize];
self.filehandle.read_exact(
&mut entry_buffer
- );
+ ).unwrap();
- let mut mft_entry = self.entry_from_buffer(
+ let mft_entry = self.entry_from_buffer(
entry_buffer,
entry
);