1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use std::io::{Read, Seek};
use crate::attribute::FileAttributeFlags;
use crate::err::Result;
use byteorder::{LittleEndian, ReadBytesExt};
use jiff::Timestamp;
use log::trace;
use serde::Serialize;
#[derive(Serialize, Debug, Clone)]
pub struct StandardInfoAttr {
#[serde(serialize_with = "crate::utils::serialize_timestamp_chrono_compat")]
pub created: Timestamp,
#[serde(serialize_with = "crate::utils::serialize_timestamp_chrono_compat")]
pub modified: Timestamp,
#[serde(serialize_with = "crate::utils::serialize_timestamp_chrono_compat")]
pub mft_modified: Timestamp,
#[serde(serialize_with = "crate::utils::serialize_timestamp_chrono_compat")]
pub accessed: Timestamp,
/// DOS File Permissions
pub file_flags: FileAttributeFlags,
pub max_version: u32,
pub version: u32,
pub class_id: u32,
pub owner_id: u32,
pub security_id: u32,
pub quota: u64,
pub usn: u64,
}
impl StandardInfoAttr {
/// Parse a Standard Information attrbiute buffer.
///
/// # Example
///
/// Parse a raw buffer.
///
/// ```
/// use mft::attribute::x10::StandardInfoAttr;
/// use mft::attribute::FileAttributeFlags;
/// # use std::io::Cursor;
/// let attribute_buffer: &[u8] = &[
/// 0x2F,0x6D,0xB6,0x6F,0x0C,0x97,0xCE,0x01,0x56,0xCD,0x1A,0x75,0x73,0xB5,0xCE,0x01,
/// 0x56,0xCD,0x1A,0x75,0x73,0xB5,0xCE,0x01,0x56,0xCD,0x1A,0x75,0x73,0xB5,0xCE,0x01,
/// 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/// 0x00,0x00,0x00,0x00,0xB0,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/// 0x68,0x58,0xA0,0x0A,0x02,0x00,0x00,0x00
/// ];
///
/// let attribute = StandardInfoAttr::from_reader(&mut Cursor::new(attribute_buffer)).unwrap();
///
/// assert_eq!(attribute.created.as_second(), 1376278290);
/// assert_eq!(attribute.modified.as_second(), 1379621073);
/// assert_eq!(attribute.mft_modified.as_second(), 1379621073);
/// assert_eq!(attribute.accessed.as_second(), 1379621073);
/// assert_eq!(attribute.file_flags.bits(), 32);
/// assert_eq!(attribute.max_version, 0);
/// assert_eq!(attribute.version, 0);
/// assert_eq!(attribute.class_id, 0);
/// assert_eq!(attribute.security_id, 1456);
/// assert_eq!(attribute.quota, 0);
/// assert_eq!(attribute.usn, 8768215144);
/// ```
pub fn from_reader<S: Read + Seek>(reader: &mut S) -> Result<StandardInfoAttr> {
trace!("Offset {}: StandardInfoAttr", reader.stream_position()?);
// Timestamps are stored as Windows FILETIME (100ns since 1601-01-01 UTC).
let created =
crate::utils::windows_filetime_to_timestamp(reader.read_u64::<LittleEndian>()?)?;
let modified =
crate::utils::windows_filetime_to_timestamp(reader.read_u64::<LittleEndian>()?)?;
let mft_modified =
crate::utils::windows_filetime_to_timestamp(reader.read_u64::<LittleEndian>()?)?;
let accessed =
crate::utils::windows_filetime_to_timestamp(reader.read_u64::<LittleEndian>()?)?;
Ok(StandardInfoAttr {
created,
modified,
mft_modified,
accessed,
file_flags: FileAttributeFlags::from_bits_truncate(reader.read_u32::<LittleEndian>()?),
max_version: reader.read_u32::<LittleEndian>()?,
version: reader.read_u32::<LittleEndian>()?,
class_id: reader.read_u32::<LittleEndian>()?,
owner_id: reader.read_u32::<LittleEndian>()?,
security_id: reader.read_u32::<LittleEndian>()?,
quota: reader.read_u64::<LittleEndian>()?,
usn: reader.read_u64::<LittleEndian>()?,
})
}
}