Compare commits

...

4 Commits

Author SHA1 Message Date
Grigoryev Ilya Alekseevich
03f2eeef09 add validation 2026-04-01 00:50:06 +05:00
Grigoryev Ilya Alekseevich
6745820f71 fix README 2026-04-01 00:18:17 +05:00
Grigoryev Ilya Alekseevich
a2b8c67064 fix README 2026-04-01 00:13:41 +05:00
Grigoryev Ilya Alekseevich
646e89dbee update gitignore 2026-04-01 00:11:46 +05:00
8 changed files with 120 additions and 6 deletions

BIN
.DS_Store vendored

Binary file not shown.

2
.gitignore vendored
View File

@@ -24,4 +24,4 @@ go.work.sum
# env file # env file
.env .env
.DS_Store

View File

@@ -1,15 +1,15 @@
# MFTECmd # MFTECmd
[![Golang](https://go.dev/)] [![Source](https://github.com/EricZimmerman/MFTECmd)] [![Golang](https://img.shields.io/badge/Golang-Go-00ADD8?logo=go&logoColor=white)](https://go.dev/) [![Source](https://img.shields.io/badge/Source-GitHub-181717?logo=github&logoColor=white)](https://github.com/EricZimmerman/MFTECmd)
Утилита является портированной под Linux версией утилиты [Эрика Циммермана](https://github.com/EricZimmerman). При портировании была пересмотрена структура флагов и для более простого взаимодействия с программой. Утилита является портированной под Linux версией утилиты [Эрика Циммермана](https://github.com/EricZimmerman). При портировании была пересмотрена структура флагов для более простого взаимодействия с программой.
--- ---
## Поддерживаемые форматы файлов ## Поддерживаемые форматы файлов
В качестве входных файлов утилита поддерживает: В качестве входных файлов утилита поддерживает:
- `$MFT` - системный файл в файловой системе NTFS, в котором хранится информация о содержимом тома. - `$MFT` - системный файл в файловой системе NTFS, в котором хранится информация о содержимом тома.
- `$J` (USN Journal) -системный файл в файловой системе NTFS, который хранит журнал изменений на томе. - `$J` (USN Journal) - системный файл в файловой системе NTFS, который хранит журнал изменений на томе.
- `$Boot` - системный файл в файловой системе NTFS, содержащий загрузочный сектор и код запуска. - `$Boot` - системный файл в файловой системе NTFS, содержащий загрузочный сектор и код запуска.
- `$SDS` - системный файл в файловой системе NTFS, содержит список дескрипторов безопасности для всех файлов и каталогов на томе. - `$SDS` - системный файл в файловой системе NTFS, содержит список дескрипторов безопасности для всех файлов и каталогов на томе.
- `$I30` - атрибут индекса размещения. Связан с каталогами и содержит информацию о файлах и подкаталогах, содержащихся в каталоге. - `$I30` - атрибут индекса размещения. Связан с каталогами и содержит информацию о файлах и подкаталогах, содержащихся в каталоге.

View File

@@ -1,7 +1,9 @@
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"reflect"
"strings" "strings"
) )
@@ -111,3 +113,99 @@ func ValidateLeaf(cmd any) error {
return nil return nil
} }
} }
// Валидация путей.
// Принимает на вход объект и при наличии метода Enabled производит валидацию
func ValidatePath(cmd any) error {
switch v := cmd.(type) {
case interface{ Enabled() error }:
return v.Enabled()
default:
return nil
}
}
// Проверяет, что у команды с output-блоками включён хотя бы один вывод.
func ValidateOutput(cmd any) error {
if cmd == nil {
return nil
}
v := reflect.ValueOf(cmd)
if v.Kind() == reflect.Pointer {
if v.IsNil() {
return nil
}
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return nil
}
var hasOutputBlocks bool
var hasEnabledOutput bool
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := v.Type().Field(i)
switch fieldType.Type {
case reflect.TypeOf(CSVOutput{}):
hasOutputBlocks = true
if enabled, ok := callEnabled(field); ok && enabled {
hasEnabledOutput = true
}
case reflect.TypeOf(JSONOutput{}):
hasOutputBlocks = true
if enabled, ok := callEnabled(field); ok && enabled {
hasEnabledOutput = true
}
case reflect.TypeOf(BodyOutput{}):
hasOutputBlocks = true
if enabled, ok := callEnabled(field); ok && enabled {
hasEnabledOutput = true
}
}
}
if hasOutputBlocks && !hasEnabledOutput {
return errors.New("you must specify at least one output path: --csv, --json or --body")
}
return nil
}
// Вызов Enabled у поля
// Возвращает результат Enabled() и флаг успешности поиска метода
func callEnabled(v reflect.Value) (bool, bool) {
if !v.IsValid() {
return false, false
}
// Пробуем метод у самого значения
if method := v.MethodByName("Enabled"); method.IsValid() {
if method.Type().NumIn() == 0 &&
method.Type().NumOut() == 1 &&
method.Type().Out(0).Kind() == reflect.Bool {
out := method.Call(nil)
return out[0].Bool(), true
}
}
// Пробуем метод у указателя
if v.CanAddr() {
if method := v.Addr().MethodByName("Enabled"); method.IsValid() {
if method.Type().NumIn() == 0 &&
method.Type().NumOut() == 1 &&
method.Type().Out(0).Kind() == reflect.Bool {
out := method.Call(nil)
return out[0].Bool(), true
}
}
}
return false, false
}

View File

@@ -20,7 +20,6 @@ func NewCLI() *CLI {
&c.cmd, &c.cmd,
kong.Name("mftecmd"), kong.Name("mftecmd"),
kong.Description("Utility for processing $MFT, $J, $LogFile, $Boot, $SDS, $I30"), kong.Description("Utility for processing $MFT, $J, $LogFile, $Boot, $SDS, $I30"),
kong.UsageOnError(),
) )
return c return c
@@ -28,8 +27,24 @@ func NewCLI() *CLI {
// Метод запуска CLI // Метод запуска CLI
func (c *CLI) Run() *CMD { func (c *CLI) Run() *CMD {
// Парсинг флагов и аргументов
ctx, err := c.parser.Parse(os.Args[1:]) ctx, err := c.parser.Parse(os.Args[1:])
c.parser.FatalIfErrorf(err) if err != nil {
c.parser.FatalIfErrorf(err)
}
// Валидируем команды
err = ValidateLeaf(c)
if err != nil {
c.parser.FatalIfErrorf(err)
}
// Валидируем путь вывода
err = ValidateOutput(c)
if err != nil {
c.parser.FatalIfErrorf(err)
}
_ = ctx _ = ctx
return &c.cmd return &c.cmd

View File

View File

@@ -0,0 +1 @@
package mft

View File