package commands import ( "archive/tar" "bytes" "encoding/hex" "errors" "fmt" "io" "os" "strings" "git.cheetah.cat/cheetah/moto-flash-data/flashpart" "github.com/rs/zerolog/log" ) type MparPaxExtractCommand struct { InputFilename string `long:"mpar" short:"m" required:"true" description:"input-filename"` TargetFileName string `long:"file" short:"f" required:"true" description:"output-filename"` } func (command *MparPaxExtractCommand) Execute(args []string) error { inputFile, err := os.Open(command.InputFilename) if err != nil { return err } defer inputFile.Close() inputFileStat, err := inputFile.Stat() if err != nil { return err } log.Info().Int64("fileSize", inputFileStat.Size()).Msg("Reading raw file...") pdata := make([]byte, inputFileStat.Size()) _, err = io.ReadFull(inputFile, pdata) if err != nil { return err } fpHeader := flashpart.ParseFlashPartHeader(pdata[:32]) log.Info().Msg( fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s", fpHeader.MediaID, fpHeader.TotalSize, fpHeader.TotalSize, fpHeader.VersionText, ), ) log.Info().Msg( fmt.Sprintf("Original-Full-Header-Hex: %s", hex.EncodeToString(pdata[:32])), ) if len(pdata[32:]) != len(pdata)-32 { return errors.New("something doesnt add up") } if len(pdata[32:]) != int(fpHeader.TotalSize)-32 { log.Error().Uint32("header ts", fpHeader.TotalSize).Uint32("len pdata", uint32(len(pdata))).Msg("size mismatch") return nil } breader := bytes.NewReader(pdata[32:]) tarReader := tar.NewReader(breader) for { header, err := tarReader.Next() if err == io.EOF { break } if err != nil { log.Error().Err(err) } if header.Typeflag == tar.TypeReg && !strings.Contains(header.Name, "._") && header.Name == command.TargetFileName { content, err := io.ReadAll(tarReader) if err != nil { log.Error().Err(err) } outputFile, err := os.Create(command.TargetFileName) if err != nil { return err } defer outputFile.Close() _, err = outputFile.Write(content) if err != nil { return err } log.Info().Str("fileName", header.Name).Int64("fileSize", header.Size).Msg("extracted file") return nil } } log.Error().Msg("no file extracted") return nil }