package files import ( "context" "fmt" "os" "path" "path/filepath" "time" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" ) type TarGzArchiver struct { } func NewTarGzArchiver() ShellArchiver { return &TarGzArchiver{} } func (t TarGzArchiver) Extract(ctx context.Context, filePath, dstDir string, secret string) error { return t.ExtractWithOptions(ctx, filePath, dstDir, secret, false) } func (t TarGzArchiver) ExtractWithOptions(ctx context.Context, filePath, dstDir, secret string, preserveOwner bool) error { if err := os.MkdirAll(dstDir, 0755); err != nil { return fmt.Errorf("failed to create destination dir: %w", err) } cmdMgr := cmd.NewCommandMgr(cmd.WithContext(ctx)) if len(secret) != 0 { return runTarGzDecryptToDirWithOptions(cmdMgr, filePath, dstDir, secret, false, preserveOwner) } return runTarGzExtractToDirWithOptions(cmdMgr, filePath, dstDir, preserveOwner) } func (t TarGzArchiver) Compress(ctx context.Context, sourcePaths []string, dstFile string, secret string) error { tmpFile := path.Join(global.Dir.TmpDir, fmt.Sprintf("%s%s.tar.gz", common.RandStr(50), time.Now().Format("20060102150405"))) op := NewFileOp() var err error defer func() { _ = op.DeleteFile(tmpFile) if err != nil { _ = op.DeleteFile(dstFile) } }() var itemDirs []string for _, item := range sourcePaths { itemDirs = append(itemDirs, filepath.Base(item)) } aheadDir := filepath.Dir(sourcePaths[0]) if len(aheadDir) == 0 { aheadDir = "/" } if len(secret) != 0 { err = runTarGzEncryptToFile(cmd.NewCommandMgr(cmd.WithContext(ctx)), tmpFile, secret, append([]string{"-C", aheadDir}, itemDirs...)...) } else { err = runTarGzToFile(cmd.NewCommandMgr(cmd.WithContext(ctx)), tmpFile, append([]string{"-C", aheadDir}, itemDirs...)...) } if err != nil { return err } if err = op.Mv(tmpFile, dstFile); err != nil { return err } return nil } func runTarGzToFile(cmdMgr *cmd.CommandHelper, dst string, tarArgs ...string) error { args := append([]string{"-zcf", dst}, tarArgs...) return cmdMgr.Run("tar", args...) } func runTarGzEncryptToFile(cmdMgr *cmd.CommandHelper, dst, secret string, tarArgs ...string) error { args := append([]string{"-zcf", "-"}, tarArgs...) _, err := cmdMgr.RunPipe( cmd.PipeCommand{Name: "tar", Args: args}, cmd.PipeCommand{Name: "openssl", Args: []string{"enc", "-aes-256-cbc", "-salt", "-pass", "env:BACKUP_SECRET", "-out", dst}, Env: []string{"BACKUP_SECRET=" + secret}}, ) return err } func runTarGzExtractToDir(cmdMgr *cmd.CommandHelper, src, dst string) error { return runTarGzExtractToDirWithOptions(cmdMgr, src, dst, false) } func runTarGzExtractToDirWithOptions(cmdMgr *cmd.CommandHelper, src, dst string, preserveOwner bool) error { args := []string{"-zxvf", src, "-C", dst} if preserveOwner { args = append([]string{"--same-owner", "--same-permissions"}, args...) } return cmdMgr.Run("tar", args...) } func runTarGzDecryptToDir(cmdMgr *cmd.CommandHelper, src, dst, secret string, withSalt bool) error { return runTarGzDecryptToDirWithOptions(cmdMgr, src, dst, secret, withSalt, false) } func runTarGzDecryptToDirWithOptions(cmdMgr *cmd.CommandHelper, src, dst, secret string, withSalt, preserveOwner bool) error { opensslArgs := []string{"enc", "-d", "-aes-256-cbc"} if withSalt { opensslArgs = append(opensslArgs, "-salt") } opensslArgs = append(opensslArgs, "-pass", "env:BACKUP_SECRET", "-in", src) tarArgs := []string{"-zxf", "-", "-C", dst} if preserveOwner { tarArgs = append([]string{"--same-owner", "--same-permissions"}, tarArgs...) } _, err := cmdMgr.RunPipe( cmd.PipeCommand{Name: "openssl", Args: opensslArgs, Env: []string{"BACKUP_SECRET=" + secret}}, cmd.PipeCommand{Name: "tar", Args: tarArgs}, ) return err }