Files
MFTECmd-for-Linux/internal/cmd/cmd.go
Grigoryev Ilya Alekseevich 03f2eeef09 add validation
2026-04-01 00:50:06 +05:00

212 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cmd
import (
"errors"
"fmt"
"reflect"
"strings"
)
// Проверка пути на пустое значение
// Принимает на вход экземпляр bodyOutput и возвращает флаг, означающий непустой путь
func (o CSVOutput) Enabled() bool {
return strings.TrimSpace(o.CSVPath) != ""
}
// Проверка пути на пустое значение
// Принимает на вход экземпляр bodyOutput и возвращает флаг, означающий непустой путь
func (o JSONOutput) Enabled() bool {
return strings.TrimSpace(o.JSONPath) != ""
}
// Проверка пути на пустое значение.
// Принимает на вход экземпляр bodyOutput и возвращает флаг, означающий непустой путь
func (o BodyOutput) Enabled() bool {
return strings.TrimSpace(o.BodyPath) != ""
}
// Валидация флагов
// Принимает на вход указатель на экземпляр mftParseCmd и возвращает ошибку
func (c *MFTParseCmd) Validate() error {
if !c.CSVOutput.Enabled() && !c.JSONOutput.Enabled() && !c.BodyOutput.Enabled() {
return fmt.Errorf("mft parse requires at least one output: --csv, --json, or --body") // Проверка на наличие флага формата файла вывода
}
if c.BodyOutput.Enabled() && strings.TrimSpace(c.DriveLetter) == "" {
return fmt.Errorf("--drive-letter is required when using --body") // Проверка наличия буквы диска в Bodyfile
}
if c.FileList && !c.CSVOutput.Enabled() {
return fmt.Errorf("--file-list requires --csv") // Проверка CSV вывода для листинга файлов
}
if (c.DumpResidentFiles || c.IncludeResidentData) && !c.CSVOutput.Enabled() && !c.JSONOutput.Enabled() {
return fmt.Errorf("--dump-resident-files and --include-resident-data require --csv or --json") // Проверка CSV или JSON вывода для резидентных файлов
}
if c.ResidentMaxBytes <= 0 || c.ResidentMaxBytes > MaxResidentDataBytes {
return fmt.Errorf("--resident-max-bytes must be between 1 and %d", MaxResidentDataBytes) // Проверка максимального значения размера резидентных файлов
}
return nil
}
// Валидация флагов
// Принимает на вход указатель на экземпляр mftShowCmd и возвращает ошибку
func (c *MFTShowCmd) Validate() error {
return nil
}
// Валидация флагов
// Принимает на вход указатель на экземпляр mftExportRecordCmd и возвращает ошибку
func (c *MFTExportRecordCmd) Validate() error {
return nil
}
// Валидация флагов
// Принимает на вход указатель на экземпляр journalParseCmd и возвращает ошибку
func (c *JournalParseCmd) Validate() error {
if !c.CSVOutput.Enabled() && !c.JSONOutput.Enabled() {
return fmt.Errorf("j parse requires at least one output: --csv or --json") // Проверка вывода
}
return nil
}
// Валидация флагов
// Принимает на вход указатель на экземпляр bootParseCmd и возвращает ошибку
func (c *BootParseCmd) Validate() error {
return nil
}
// Валидация флагов
// Принимает на вход указатель на экземпляр sdsParseCmd и возвращает ошибку
func (c *SDSParseCmd) Validate() error {
if !c.CSVOutput.Enabled() {
return fmt.Errorf("sds parse requires --csv") // Проверка вывода в CSV
}
return nil
}
// Валидация флагов
// Принимает на вход указатель на экземпляр sdsShowCmd и возвращает ошибку
func (c *SDSShowCmd) Validate() error {
return nil
}
// Валидация флагов
// Принимает на вход указатель на экземпляр i30ParseCmd и возвращает ошибку
func (c *I30ParseCmd) Validate() error {
if !c.CSVOutput.Enabled() {
return fmt.Errorf("i30 parse requires --csv") // Проверка вывода в CSV
}
return nil
}
// Валидация флагов.
// Принимает на вход указатель на экземпляр logFileParseCmd и возвращает ошибку
func (c *LogFileParseCmd) Validate() error {
return nil
}
// Валидация команд.
// Принимает на вход объект и при наличии метода Validate производит валидацию
func ValidateLeaf(cmd any) error {
switch v := cmd.(type) {
case interface{ Validate() error }:
return v.Validate()
default:
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
}