forked from Velocidex/go-ntfs
/
model.go
122 lines (101 loc) · 2.97 KB
/
model.go
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
package parser
import (
"strings"
"time"
)
// This file defines a model for MFT entry.
type TimeStamps struct {
CreateTime time.Time
FileModifiedTime time.Time
MFTModifiedTime time.Time
AccessedTime time.Time
}
type FilenameInfo struct {
Times TimeStamps
Type string
Name string
ParentEntryNumber uint64
ParentSequenceNumber uint16
}
type Attribute struct {
Type string
TypeId uint64
Id uint64
Inode string
Size int64
Name string
}
// Describe a single MFT entry.
type NTFSFileInformation struct {
FullPath string
MFTID int64
SequenceNumber uint16
Size int64
Allocated bool
IsDir bool
SI_Times *TimeStamps
// If multiple filenames are given, we list them here.
Filenames []*FilenameInfo
Attributes []*Attribute
Hardlinks []string
}
func ModelMFTEntry(ntfs *NTFSContext, mft_entry *MFT_ENTRY) (*NTFSFileInformation, error) {
full_path := GetFullPath(ntfs, mft_entry)
mft_id := mft_entry.Record_number()
result := &NTFSFileInformation{
FullPath: full_path,
MFTID: int64(mft_id),
SequenceNumber: mft_entry.Sequence_value(),
Allocated: mft_entry.Flags().IsSet("ALLOCATED"),
IsDir: mft_entry.Flags().IsSet("DIRECTORY"),
}
si, err := mft_entry.StandardInformation(ntfs)
if err == nil {
result.SI_Times = &TimeStamps{
CreateTime: si.Create_time().Time,
FileModifiedTime: si.File_altered_time().Time,
MFTModifiedTime: si.Mft_altered_time().Time,
AccessedTime: si.File_accessed_time().Time,
}
}
for _, filename := range mft_entry.FileName(ntfs) {
result.Filenames = append(result.Filenames, &FilenameInfo{
Times: TimeStamps{
CreateTime: filename.Created().Time,
FileModifiedTime: filename.File_modified().Time,
MFTModifiedTime: filename.Mft_modified().Time,
AccessedTime: filename.File_accessed().Time,
},
ParentEntryNumber: filename.MftReference(),
ParentSequenceNumber: filename.Seq_num(),
Type: filename.NameType().Name,
Name: filename.Name(),
})
}
inode_formatter := InodeFormatter{}
for _, attr := range mft_entry.EnumerateAttributes(ntfs) {
attr_type := attr.Type()
attr_id := attr.Attribute_id()
if attr_type.Value == ATTR_TYPE_DATA && result.Size == 0 {
result.Size = attr.DataSize()
}
// Only show the first VCN - additional VCN are just
// part of the original stream.
if !attr.IsResident() && attr.Runlist_vcn_start() != 0 {
continue
}
name := attr.Name()
result.Attributes = append(result.Attributes, &Attribute{
Type: attr_type.Name,
TypeId: attr_type.Value,
Inode: inode_formatter.Inode(mft_id, attr_type.Value, attr_id, name),
Size: attr.DataSize(),
Id: uint64(attr_id),
Name: name,
})
}
for _, l := range GetHardLinks(ntfs, uint64(mft_id), DefaultMaxLinks) {
result.Hardlinks = append(result.Hardlinks, strings.Join(l, "\\"))
}
return result, nil
}