pub mod data_run;
pub mod header;
pub mod non_resident_attr;
pub mod raw;
pub mod x10;
pub mod x20;
pub mod x30;
pub mod x40;
pub mod x80;
pub mod x90;
use crate::err::Result;
use crate::impl_serialize_for_bitflags;
use std::io::{Cursor, Read, Seek};
use bitflags::bitflags;
use crate::attribute::raw::RawAttribute;
use crate::attribute::x10::StandardInfoAttr;
use crate::attribute::x20::AttributeListAttr;
use crate::attribute::x30::FileNameAttr;
use crate::attribute::header::{MftAttributeHeader, NonResidentHeader, ResidentHeader};
use crate::attribute::non_resident_attr::NonResidentAttr;
use crate::attribute::x40::ObjectIdAttr;
use crate::attribute::x80::DataAttr;
use crate::attribute::x90::IndexRootAttr;
use serde::Serialize;
#[derive(Serialize, Clone, Debug)]
pub struct MftAttribute {
pub header: MftAttributeHeader,
pub data: MftAttributeContent,
}
impl MftAttributeContent {
pub fn from_stream_non_resident<S: Read + Seek>(
stream: &mut S,
header: &MftAttributeHeader,
resident: &NonResidentHeader,
) -> Result<Self> {
Ok(MftAttributeContent::DataRun(NonResidentAttr::from_stream(
stream, header, resident,
)?))
}
pub fn from_stream_resident<S: Read + Seek>(
stream: &mut S,
header: &MftAttributeHeader,
resident: &ResidentHeader,
) -> Result<Self> {
match header.type_code {
MftAttributeType::StandardInformation => Ok(MftAttributeContent::AttrX10(
StandardInfoAttr::from_reader(stream)?,
)),
MftAttributeType::AttributeList => {
let content_size = resident.data_size;
let mut attribute_buffer = vec![0; content_size as usize];
stream.read_exact(&mut attribute_buffer)?;
let mut new_stream = Cursor::new(attribute_buffer);
let attr_list =
AttributeListAttr::from_stream(&mut new_stream, Some(content_size as u64))?;
Ok(MftAttributeContent::AttrX20(attr_list))
}
MftAttributeType::FileName => Ok(MftAttributeContent::AttrX30(
FileNameAttr::from_stream(stream)?,
)),
MftAttributeType::DATA => Ok(MftAttributeContent::AttrX80(DataAttr::from_stream(
stream,
resident.data_size as usize,
)?)),
MftAttributeType::ObjectId => Ok(MftAttributeContent::AttrX40(
ObjectIdAttr::from_stream(stream, resident.data_size as usize)?,
)),
MftAttributeType::IndexRoot => Ok(MftAttributeContent::AttrX90(
IndexRootAttr::from_stream(stream)?,
)),
_ => Ok(MftAttributeContent::Raw(RawAttribute::from_stream(
stream,
header.type_code.clone(),
resident.data_size as usize,
)?)),
}
}
pub fn into_attribute_list(self) -> Option<AttributeListAttr> {
match self {
MftAttributeContent::AttrX20(content) => Some(content),
_ => None,
}
}
pub fn into_index_root(self) -> Option<IndexRootAttr> {
match self {
MftAttributeContent::AttrX90(content) => Some(content),
_ => None,
}
}
pub fn into_object_id(self) -> Option<ObjectIdAttr> {
match self {
MftAttributeContent::AttrX40(content) => Some(content),
_ => None,
}
}
pub fn into_standard_info(self) -> Option<StandardInfoAttr> {
match self {
MftAttributeContent::AttrX10(content) => Some(content),
_ => None,
}
}
pub fn into_data(self) -> Option<DataAttr> {
match self {
MftAttributeContent::AttrX80(content) => Some(content),
_ => None,
}
}
pub fn into_file_name(self) -> Option<FileNameAttr> {
match self {
MftAttributeContent::AttrX30(content) => Some(content),
_ => None,
}
}
pub fn into_data_runs(self) -> Option<NonResidentAttr> {
match self {
MftAttributeContent::DataRun(content) => Some(content),
_ => None,
}
}
}
#[derive(Serialize, Clone, Debug)]
#[serde(untagged)]
pub enum MftAttributeContent {
Raw(RawAttribute),
AttrX10(StandardInfoAttr),
AttrX20(AttributeListAttr),
AttrX30(FileNameAttr),
AttrX40(ObjectIdAttr),
AttrX80(DataAttr),
AttrX90(IndexRootAttr),
DataRun(NonResidentAttr),
None,
}
#[derive(Serialize, Debug, Clone, FromPrimitive, ToPrimitive, PartialOrd, PartialEq)]
#[repr(u32)]
pub enum MftAttributeType {
StandardInformation = 0x10_u32,
AttributeList = 0x20_u32,
FileName = 0x30_u32,
ObjectId = 0x40_u32,
SecurityDescriptor = 0x50_u32,
VolumeName = 0x60_u32,
VolumeInformation = 0x70_u32,
DATA = 0x80_u32,
IndexRoot = 0x90_u32,
IndexAllocation = 0xA0_u32,
BITMAP = 0xB0_u32,
ReparsePoint = 0xC0_u32,
EaInformation = 0xD0_u32,
EA = 0xE0_u32,
LoggedUtilityStream = 0x100_u32,
}
bitflags! {
#[derive(Clone, Debug, PartialEq)]
pub struct FileAttributeFlags: u32 {
const FILE_ATTRIBUTE_READONLY = 0x0000_0001;
const FILE_ATTRIBUTE_HIDDEN = 0x0000_0002;
const FILE_ATTRIBUTE_SYSTEM = 0x0000_0004;
const FILE_ATTRIBUTE_DIRECTORY = 0x0000_0010;
const FILE_ATTRIBUTE_ARCHIVE = 0x0000_0020;
const FILE_ATTRIBUTE_DEVICE = 0x0000_0040;
const FILE_ATTRIBUTE_NORMAL = 0x0000_0080;
const FILE_ATTRIBUTE_TEMPORARY = 0x0000_0100;
const FILE_ATTRIBUTE_SPARSE_FILE = 0x0000_0200;
const FILE_ATTRIBUTE_REPARSE_POINT = 0x0000_0400;
const FILE_ATTRIBUTE_COMPRESSED = 0x0000_0800;
const FILE_ATTRIBUTE_OFFLINE = 0x0000_1000;
const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x0000_2000;
const FILE_ATTRIBUTE_ENCRYPTED = 0x0000_4000;
const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x0000_8000;
const FILE_ATTRIBUTE_VIRTUAL = 0x0001_0000;
const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x0002_0000;
const FILE_ATTRIBUTE_EA = 0x0004_0000;
const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x0004_0000;
const FILE_ATTRIBUTE_HAS_EA = 0x0004_0000;
const FILE_ATTRIBUTE_PINNED = 0x0008_0000;
const FILE_ATTRIBUTE_UNPINNED = 0x0010_0000;
const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x0040_0000;
const FILE_ATTRIBUTE_IS_DIRECTORY = 0x1000_0000;
const FILE_ATTRIBUTE_INDEX_VIEW = 0x2000_0000;
}
}
impl_serialize_for_bitflags! {FileAttributeFlags}
bitflags! {
#[derive(Default, Clone, Debug, PartialEq)]
pub struct AttributeDataFlags: u16 {
const IS_COMPRESSED = 0x0001;
const COMPRESSION_MASK = 0x00FF;
const ENCRYPTED = 0x4000;
const SPARSE = 0x8000;
}
}
impl_serialize_for_bitflags! {AttributeDataFlags}