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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use std::io::{Read, Seek};
use crate::attribute::FileAttributeFlags;
use crate::err::{Error, Result};
use log::trace;
use byteorder::{LittleEndian, ReadBytesExt};
use encoding::all::UTF_16LE;
use encoding::{DecoderTrap, Encoding};
use chrono::{DateTime, Utc};
use num_traits::FromPrimitive;
use serde::Serialize;
use winstructs::ntfs::mft_reference::MftReference;
use winstructs::timestamp::WinTimestamp;
#[derive(FromPrimitive, Serialize, Clone, Debug, PartialOrd, PartialEq)]
#[repr(u8)]
pub enum FileNamespace {
POSIX = 0,
Win32 = 1,
DOS = 2,
Win32AndDos = 3,
}
#[derive(Serialize, Clone, Debug)]
pub struct FileNameAttr {
pub parent: MftReference,
pub created: DateTime<Utc>,
pub modified: DateTime<Utc>,
pub mft_modified: DateTime<Utc>,
pub accessed: DateTime<Utc>,
pub logical_size: u64,
pub physical_size: u64,
pub flags: FileAttributeFlags,
pub reparse_value: u32,
pub name_length: u8,
pub namespace: FileNamespace,
pub name: String,
}
impl FileNameAttr {
pub fn from_stream<S: Read + Seek>(stream: &mut S) -> Result<FileNameAttr> {
trace!("Offset {}: FilenameAttr", stream.stream_position()?);
let parent =
MftReference::from_reader(stream).map_err(Error::failed_to_read_mft_reference)?;
let created = WinTimestamp::from_reader(stream)
.map_err(Error::failed_to_read_windows_time)?
.to_datetime();
let modified = WinTimestamp::from_reader(stream)
.map_err(Error::failed_to_read_windows_time)?
.to_datetime();
let mft_modified = WinTimestamp::from_reader(stream)
.map_err(Error::failed_to_read_windows_time)?
.to_datetime();
let accessed = WinTimestamp::from_reader(stream)
.map_err(Error::failed_to_read_windows_time)?
.to_datetime();
let logical_size = stream.read_u64::<LittleEndian>()?;
let physical_size = stream.read_u64::<LittleEndian>()?;
let flags = FileAttributeFlags::from_bits_truncate(stream.read_u32::<LittleEndian>()?);
let reparse_value = stream.read_u32::<LittleEndian>()?;
let name_length = stream.read_u8()?;
let namespace = stream.read_u8()?;
let namespace =
FileNamespace::from_u8(namespace).ok_or(Error::UnknownNamespace { namespace })?;
let mut name_buffer = vec![0; name_length as usize * 2];
stream.read_exact(&mut name_buffer)?;
let name = match UTF_16LE.decode(&name_buffer, DecoderTrap::Ignore) {
Ok(s) => s,
Err(_e) => return Err(Error::InvalidFilename {}),
};
Ok(FileNameAttr {
parent,
created,
modified,
mft_modified,
accessed,
logical_size,
physical_size,
flags,
reparse_value,
name_length,
namespace,
name,
})
}
}