package commands import ( "archive/tar" "bytes" "encoding/hex" "errors" "fmt" "io" "os" "git.cheetah.cat/cheetah/moto-flash-data/flashpart" "github.com/rs/zerolog/log" ) type MparPaxInsertCommand struct { InputFilename string `long:"mpar" short:"m" required:"true" description:"Source Partition File"` OutputFilename string `long:"output" short:"o" required:"true" description:"Target Partition File"` InsertFilename string `long:"insertfile" short:"i" required:"true" description:"Source File for Insert-Action"` } func (command *MparPaxInsertCommand) Execute(args []string) error { inputFile, err := os.Open(command.InputFilename) if err != nil { return err } defer inputFile.Close() insertFile, err := os.Open(command.InsertFilename) if err != nil { return err } defer insertFile.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) temporaryPaxFile, _ := os.CreateTemp("", "pax-insert.tar") defer temporaryPaxFile.Close() tarWriter := tar.NewWriter(temporaryPaxFile) defer tarWriter.Close() for { header, err := tarReader.Next() if err == io.EOF { break } if err != nil { log.Error().Err(err) return err } log.Info().Str("fileName", header.Name).Int64("fileSize", header.Size).Msg("copying base-file") tarWriter.WriteHeader(header) content, err := io.ReadAll(tarReader) if err != nil { log.Error().Err(err) } tarWriter.Write(content) } { // insert insertFileStat, err := insertFile.Stat() if err != nil { return err } insertHeader := &tar.Header{ Typeflag: tar.TypeReg, Size: insertFileStat.Size(), ModTime: insertFileStat.ModTime(), Name: insertFileStat.Name(), Format: tar.FormatGNU, } tarWriter.WriteHeader(insertHeader) content, err := io.ReadAll(insertFile) if err != nil { log.Error().Err(err) } tarWriter.Write(content) } //log.Error().Msg("no file replaced") // create new mpar with same header base _, err = temporaryPaxFile.Seek(0, 0) if err != nil { return err } temporaryPaxFileStat, err := temporaryPaxFile.Stat() if err != nil { return err } rawData := make([]byte, temporaryPaxFileStat.Size()) _, err = io.ReadFull(temporaryPaxFile, rawData) if err != nil { return err } outputFile, err := os.Create(command.OutputFilename) if err != nil { return err } defer outputFile.Close() fpHeader.AdjustRawSize(uint32(len(rawData))) log.Info().Msg( fmt.Sprintf("New-Full-Header-Hex: %s", hex.EncodeToString(fpHeader.GetBytes())), ) fpHeaderNew := flashpart.ParseFlashPartHeader(fpHeader.GetBytes()) log.Info().Msg( fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s", fpHeaderNew.MediaID, fpHeaderNew.TotalSize, fpHeaderNew.TotalSize, fpHeaderNew.VersionText, ), ) _, err = outputFile.Write(fpHeaderNew.GetBytes()) if err != nil { return err } _, err = outputFile.Write(rawData) if err != nil { return err } return nil }