You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.2 KiB
Go

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
}