mft function rewrite
This commit is contained in:
parent
db9e96e4ed
commit
426a959d0d
@ -108,7 +108,7 @@ func main() {
|
|||||||
if v.Format == "NTFS" && v.Driver == `C:\` {
|
if v.Format == "NTFS" && v.Driver == `C:\` {
|
||||||
|
|
||||||
starlog.Infoln("开始获取NTFS USN日志,磁盘:", v.Driver)
|
starlog.Infoln("开始获取NTFS USN日志,磁盘:", v.Driver)
|
||||||
fileLists, err := wincmd.ListUsnFileFn(v.Driver, func(name string, typed uint8) bool {
|
fileLists, err := wincmd.ListUsnFileFn(v.Driver, func(name string, typed bool) bool {
|
||||||
return true
|
return true
|
||||||
if ok, _ := regexp.MatchString(`\.exe$`, name); ok {
|
if ok, _ := regexp.MatchString(`\.exe$`, name); ok {
|
||||||
return true
|
return true
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package wincmd
|
package mft
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"b612.me/win32api"
|
|
||||||
"b612.me/wincmd/ntfs/binutil"
|
"b612.me/wincmd/ntfs/binutil"
|
||||||
"b612.me/wincmd/ntfs/mft"
|
|
||||||
"b612.me/wincmd/ntfs/utf16"
|
"b612.me/wincmd/ntfs/utf16"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
@ -11,6 +9,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -24,11 +23,16 @@ type MFTFile struct {
|
|||||||
IsDir bool
|
IsDir bool
|
||||||
Node uint64
|
Node uint64
|
||||||
}
|
}
|
||||||
|
type FileEntry struct {
|
||||||
|
Name string
|
||||||
|
Parent uint64
|
||||||
|
}
|
||||||
|
|
||||||
func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile, error) {
|
func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile, error) {
|
||||||
var result []MFTFile
|
var result []MFTFile
|
||||||
fileMap := make(map[win32api.DWORDLONG]FileEntry)
|
extendMftRecord := make(map[uint64][]Attribute)
|
||||||
f, size, err := mft.GetMFTFile(driver)
|
fileMap := make(map[uint64]FileEntry)
|
||||||
|
f, size, err := GetMFTFile(driver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []MFTFile{}, err
|
return []MFTFile{}, err
|
||||||
}
|
}
|
||||||
@ -59,20 +63,41 @@ func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile,
|
|||||||
}
|
}
|
||||||
alreadyGot += int64(got)
|
alreadyGot += int64(got)
|
||||||
for j := int64(0); j < 1024*maxRecordSize; j += 1024 {
|
for j := int64(0); j < 1024*maxRecordSize; j += 1024 {
|
||||||
record, err := mft.ParseRecord(buf[j : j+1024])
|
record, err := ParseRecord(buf[j : j+1024])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if record.Flags&mft.RecordFlagInUse == 1 && record.Flags&mft.RecordFlagIsIndex == 0 {
|
if record.BaseRecordReference.ToUint64() != 0 {
|
||||||
|
val := extendMftRecord[record.BaseRecordReference.ToUint64()]
|
||||||
|
for _, v := range record.Attributes {
|
||||||
|
if v.Type == AttributeTypeData && v.ActualSize != 0 {
|
||||||
|
val = append(val, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(val) != 0 {
|
||||||
|
extendMftRecord[record.BaseRecordReference.ToUint64()] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if record.Flags&RecordFlagInUse == 1 && record.Flags&RecordFlagIsIndex == 0 {
|
||||||
var file MFTFile
|
var file MFTFile
|
||||||
file.IsDir = record.Flags&mft.RecordFlagIsDirectory != 0
|
file.IsDir = record.Flags&RecordFlagIsDirectory != 0
|
||||||
file.Node = record.FileReference.ToUint64()
|
file.Node = record.FileReference.ToUint64()
|
||||||
parent := uint64(0)
|
parent := uint64(0)
|
||||||
for _, v := range record.Attributes {
|
for _, v := range record.Attributes {
|
||||||
if v.Type == mft.AttributeTypeFileName {
|
if v.Type == AttributeTypeData {
|
||||||
|
file.Size = v.ActualSize
|
||||||
|
file.Aszie = v.AllocatedSize
|
||||||
|
}
|
||||||
|
if v.Type == AttributeTypeStandardInformation {
|
||||||
|
if len(v.Data) >= 48 {
|
||||||
|
r := binutil.NewLittleEndianReader(v.Data)
|
||||||
|
file.ModTime = ConvertFileTime(r.Uint64(0x08))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v.Type == AttributeTypeFileName {
|
||||||
name := utf16.DecodeString(v.Data[66:], binary.LittleEndian)
|
name := utf16.DecodeString(v.Data[66:], binary.LittleEndian)
|
||||||
if len(file.Name) < len(name) && len(name) > 0 {
|
if len(file.Name) < len(name) && len(name) > 0 {
|
||||||
if len(name) > 2 && name[len(name)-2] == '~' {
|
if len(file.Name) > 0 && !strings.Contains(file.Name, "~") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
file.Name = name
|
file.Name = name
|
||||||
@ -81,28 +106,17 @@ func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile,
|
|||||||
parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0)
|
parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v.Type == mft.AttributeTypeData {
|
|
||||||
file.Size = v.ActualSize
|
|
||||||
file.Aszie = v.AllocatedSize
|
|
||||||
}
|
|
||||||
if v.Type == mft.AttributeTypeStandardInformation {
|
|
||||||
if len(v.Data) < 48 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r := binutil.NewLittleEndianReader(v.Data)
|
|
||||||
file.ModTime = mft.ConvertFileTime(r.Uint64(0x08))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if file.Name != "" {
|
if file.Name != "" {
|
||||||
canAdd := fn(file.Name, file.IsDir)
|
canAdd := fn(file.Name, file.IsDir)
|
||||||
if canAdd {
|
if canAdd {
|
||||||
result = append(result, file)
|
result = append(result, file)
|
||||||
}
|
}
|
||||||
if canAdd || file.IsDir {
|
if canAdd || file.IsDir {
|
||||||
fileMap[win32api.DWORDLONG(file.Node)] = FileEntry{
|
fileMap[uint64(file.Node)] = FileEntry{
|
||||||
Name: file.Name,
|
Name: file.Name,
|
||||||
Parent: win32api.DWORDLONG(parent),
|
Parent: uint64(parent),
|
||||||
Type: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +126,18 @@ func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile,
|
|||||||
|
|
||||||
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result)
|
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result)
|
||||||
for k, v := range result {
|
for k, v := range result {
|
||||||
result[k].Path = GetFullUsnPath(driver, fileMap, win32api.DWORDLONG(v.Node))
|
if attrs, ok := extendMftRecord[v.Node]; ok {
|
||||||
|
if v.Aszie == 0 {
|
||||||
|
for _, v := range attrs {
|
||||||
|
if v.Type == AttributeTypeData && v.ActualSize != 0 {
|
||||||
|
result[k].Size = v.ActualSize
|
||||||
|
result[k].Aszie = v.AllocatedSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(extendMftRecord, v.Node)
|
||||||
|
}
|
||||||
|
result[k].Path = GetFullUsnPath(driver, fileMap, uint64(v.Node))
|
||||||
}
|
}
|
||||||
fileMap = nil
|
fileMap = nil
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
@ -125,7 +150,8 @@ func GetFileListsByMft(driver string) ([]MFTFile, error) {
|
|||||||
|
|
||||||
func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]MFTFile, error) {
|
func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]MFTFile, error) {
|
||||||
var result []MFTFile
|
var result []MFTFile
|
||||||
fileMap := make(map[win32api.DWORDLONG]FileEntry)
|
extendMftRecord := make(map[uint64][]Attribute)
|
||||||
|
fileMap := make(map[uint64]FileEntry)
|
||||||
f, err := os.Open(filepath)
|
f, err := os.Open(filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []MFTFile{}, err
|
return []MFTFile{}, err
|
||||||
@ -162,20 +188,41 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
|
|||||||
}
|
}
|
||||||
alreadyGot += int64(got)
|
alreadyGot += int64(got)
|
||||||
for j := int64(0); j < 1024*maxRecordSize; j += 1024 {
|
for j := int64(0); j < 1024*maxRecordSize; j += 1024 {
|
||||||
record, err := mft.ParseRecord(buf[j : j+1024])
|
record, err := ParseRecord(buf[j : j+1024])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if record.Flags&mft.RecordFlagInUse == 1 && record.Flags&mft.RecordFlagIsIndex == 0 {
|
if record.BaseRecordReference.ToUint64() != 0 {
|
||||||
|
val := extendMftRecord[record.BaseRecordReference.ToUint64()]
|
||||||
|
for _, v := range record.Attributes {
|
||||||
|
if v.Type == AttributeTypeData && v.ActualSize != 0 {
|
||||||
|
val = append(val, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(val) != 0 {
|
||||||
|
extendMftRecord[record.BaseRecordReference.ToUint64()] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if record.Flags&RecordFlagInUse == 1 && record.Flags&RecordFlagIsIndex == 0 {
|
||||||
var file MFTFile
|
var file MFTFile
|
||||||
file.IsDir = record.Flags&mft.RecordFlagIsDirectory != 0
|
file.IsDir = record.Flags&RecordFlagIsDirectory != 0
|
||||||
file.Node = record.FileReference.ToUint64()
|
file.Node = record.FileReference.ToUint64()
|
||||||
parent := uint64(0)
|
parent := uint64(0)
|
||||||
for _, v := range record.Attributes {
|
for _, v := range record.Attributes {
|
||||||
if v.Type == mft.AttributeTypeFileName {
|
if v.Type == AttributeTypeData {
|
||||||
|
file.Size = v.ActualSize
|
||||||
|
file.Aszie = v.AllocatedSize
|
||||||
|
}
|
||||||
|
if v.Type == AttributeTypeStandardInformation {
|
||||||
|
if len(v.Data) >= 48 {
|
||||||
|
r := binutil.NewLittleEndianReader(v.Data)
|
||||||
|
file.ModTime = ConvertFileTime(r.Uint64(0x08))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v.Type == AttributeTypeFileName {
|
||||||
name := utf16.DecodeString(v.Data[66:], binary.LittleEndian)
|
name := utf16.DecodeString(v.Data[66:], binary.LittleEndian)
|
||||||
if len(file.Name) < len(name) && len(name) > 0 {
|
if len(file.Name) < len(name) && len(name) > 0 {
|
||||||
if len(name) > 2 && name[len(name)-2] == '~' {
|
if len(file.Name) > 0 && !strings.Contains(file.Name, "~") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
file.Name = name
|
file.Name = name
|
||||||
@ -184,17 +231,6 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
|
|||||||
parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0)
|
parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v.Type == mft.AttributeTypeData {
|
|
||||||
file.Size = v.ActualSize
|
|
||||||
file.Aszie = v.AllocatedSize
|
|
||||||
}
|
|
||||||
if v.Type == mft.AttributeTypeStandardInformation {
|
|
||||||
if len(v.Data) < 48 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r := binutil.NewLittleEndianReader(v.Data)
|
|
||||||
file.ModTime = mft.ConvertFileTime(r.Uint64(0x08))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if file.Name != "" {
|
if file.Name != "" {
|
||||||
canAdd := fn(file.Name, file.IsDir)
|
canAdd := fn(file.Name, file.IsDir)
|
||||||
@ -202,10 +238,9 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
|
|||||||
result = append(result, file)
|
result = append(result, file)
|
||||||
}
|
}
|
||||||
if canAdd || file.IsDir {
|
if canAdd || file.IsDir {
|
||||||
fileMap[win32api.DWORDLONG(file.Node)] = FileEntry{
|
fileMap[uint64(file.Node)] = FileEntry{
|
||||||
Name: file.Name,
|
Name: file.Name,
|
||||||
Parent: win32api.DWORDLONG(parent),
|
Parent: uint64(parent),
|
||||||
Type: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +250,18 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
|
|||||||
|
|
||||||
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result)
|
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result)
|
||||||
for k, v := range result {
|
for k, v := range result {
|
||||||
result[k].Path = GetFullUsnPath(" ", fileMap, win32api.DWORDLONG(v.Node))
|
if attrs, ok := extendMftRecord[v.Node]; ok {
|
||||||
|
if v.Aszie == 0 {
|
||||||
|
for _, v := range attrs {
|
||||||
|
if v.Type == AttributeTypeData && v.ActualSize != 0 {
|
||||||
|
result[k].Size = v.ActualSize
|
||||||
|
result[k].Aszie = v.AllocatedSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(extendMftRecord, v.Node)
|
||||||
|
}
|
||||||
|
result[k].Path = GetFullUsnPath(" ", fileMap, uint64(v.Node))
|
||||||
}
|
}
|
||||||
fileMap = nil
|
fileMap = nil
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
@ -225,3 +271,21 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
|
|||||||
func GetFileListsFromMftFile(filepath string) ([]MFTFile, error) {
|
func GetFileListsFromMftFile(filepath string) ([]MFTFile, error) {
|
||||||
return GetFileListsFromMftFileFn(filepath, func(string, bool) bool { return true })
|
return GetFileListsFromMftFileFn(filepath, func(string, bool) bool { return true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetFullUsnPath(diskName string, fileMap map[uint64]FileEntry, id uint64) (name string) {
|
||||||
|
for id != 0 {
|
||||||
|
fe := fileMap[id]
|
||||||
|
if id == fe.Parent {
|
||||||
|
name = "\\" + name
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
name = fe.Name
|
||||||
|
} else {
|
||||||
|
name = fe.Name + "\\" + name
|
||||||
|
}
|
||||||
|
id = fe.Parent
|
||||||
|
}
|
||||||
|
name = diskName[:len(diskName)-1] + name
|
||||||
|
return
|
||||||
|
}
|
@ -5,7 +5,6 @@ import (
|
|||||||
"b612.me/wincmd/ntfs/fragment"
|
"b612.me/wincmd/ntfs/fragment"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/t9t/gomft/mft"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -13,7 +12,6 @@ import (
|
|||||||
|
|
||||||
const supportedOemId = "NTFS "
|
const supportedOemId = "NTFS "
|
||||||
|
|
||||||
|
|
||||||
const isWin = runtime.GOOS == "windows"
|
const isWin = runtime.GOOS == "windows"
|
||||||
|
|
||||||
func GetMFTFileBytes(volume string) ([]byte, error) {
|
func GetMFTFileBytes(volume string) ([]byte, error) {
|
||||||
@ -85,12 +83,12 @@ func GetMFTFile(volume string) (io.Reader, int64, error) {
|
|||||||
return nil, 0, fmt.Errorf("Unable to read $MFT record: %v\n", err)
|
return nil, 0, fmt.Errorf("Unable to read $MFT record: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
record, err := mft.ParseRecord(mftData)
|
record, err := ParseRecord(mftData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, fmt.Errorf("Unable to parse $MFT record: %v\n", err)
|
return nil, 0, fmt.Errorf("Unable to parse $MFT record: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dataAttributes := record.FindAttributes(mft.AttributeTypeData)
|
dataAttributes := record.FindAttributes(AttributeTypeData)
|
||||||
if len(dataAttributes) == 0 {
|
if len(dataAttributes) == 0 {
|
||||||
return nil, 0, fmt.Errorf("No $DATA attribute found in $MFT record\n")
|
return nil, 0, fmt.Errorf("No $DATA attribute found in $MFT record\n")
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package wincmd
|
package usn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"b612.me/win32api"
|
"b612.me/win32api"
|
@ -1,4 +1,4 @@
|
|||||||
package wincmd
|
package usn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -1,4 +1,4 @@
|
|||||||
package wincmd
|
package usn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"b612.me/stario"
|
"b612.me/stario"
|
Loading…
x
Reference in New Issue
Block a user