fix: 解决部分情况下 zip 文件压缩解压失败的问题 (#2565)

Refs https://github.com/1Panel-dev/1Panel/issues/1245
Refs https://github.com/1Panel-dev/1Panel/issues/263
This commit is contained in:
zhengkunwang 2023-10-16 03:34:15 -05:00 committed by GitHub
parent 90af56511c
commit c880caa770
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 63 deletions

View file

@ -144,9 +144,19 @@ func ExecScript(scriptPath, workDir string) (string, error) {
func ExecCmd(cmdStr string) error {
cmd := exec.Command("bash", "-c", cmdStr)
err := cmd.Run()
output, err := cmd.CombinedOutput()
if err != nil {
return err
return fmt.Errorf("error : %v, output: %s", err, output)
}
return nil
}
func ExecCmdWithDir(cmdStr, workDir string) error {
cmd := exec.Command("bash", "-c", cmdStr)
cmd.Dir = workDir
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error : %v, output: %s", err, output)
}
return nil
}

View file

@ -7,17 +7,22 @@ import (
)
type ShellArchiver interface {
Compress() error
Extract(dstDir string) error
Extract(filePath, dstDir string) error
Compress(sourcePaths []string, dstFile string) error
}
func NewShellArchiver(compressType CompressType) (*TarArchiver, error) {
func NewShellArchiver(compressType CompressType) (ShellArchiver, error) {
switch compressType {
case Tar:
if err := checkCmdAvailability("tar"); err != nil {
return nil, err
}
return NewTarArchiver(compressType), nil
case Zip:
if err := checkCmdAvailability("zip"); err != nil {
return nil, err
}
return NewZipArchiver(), nil
default:
return nil, buserr.New("unsupported compress type")
}

View file

@ -386,10 +386,7 @@ func (f FileOp) Compress(srcRiles []string, dst string, name string, cType Compr
switch cType {
case Zip:
if err := ZipFile(files, out); err != nil {
_ = f.DeleteFile(dstFile)
return err
}
return NewZipArchiver().Compress(srcRiles, dstFile)
default:
err = format.Archive(context.Background(), out, files)
if err != nil {
@ -415,13 +412,12 @@ func decodeGBK(input string) (string, error) {
func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error {
switch cType {
case Tar:
case Tar, Zip:
shellArchiver, err := NewShellArchiver(cType)
if err != nil {
return err
}
shellArchiver.FilePath = srcFile
return shellArchiver.Extract(dst)
return shellArchiver.Extract(srcFile, dst)
default:
format := getFormat(cType)
handler := func(ctx context.Context, archFile archiver.File) error {
@ -475,7 +471,6 @@ func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error
}
return format.Extract(context.Background(), input, nil, handler)
}
return nil
}
func (f FileOp) Backup(srcFile string) (string, error) {
@ -511,46 +506,3 @@ func (f FileOp) CopyAndBackup(src string) (string, error) {
}
return backupPath, nil
}
func ZipFile(files []archiver.File, dst afero.File) error {
zw := zip.NewWriter(dst)
defer zw.Close()
for _, file := range files {
hdr, err := zip.FileInfoHeader(file)
if err != nil {
return err
}
hdr.Name = file.NameInArchive
if file.IsDir() {
if !strings.HasSuffix(hdr.Name, "/") {
hdr.Name += "/"
}
hdr.Method = zip.Store
}
w, err := zw.CreateHeader(hdr)
if err != nil {
return err
}
if file.IsDir() {
continue
}
if file.LinkTarget != "" {
_, err = w.Write([]byte(filepath.ToSlash(file.LinkTarget)))
if err != nil {
return err
}
} else {
fileReader, err := file.Open()
if err != nil {
return err
}
_, err = io.Copy(w, fileReader)
if err != nil {
return err
}
}
}
return nil
}

View file

@ -3,28 +3,26 @@ package files
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"strings"
)
type TarArchiver struct {
Cmd string
FilePath string
CompressType CompressType
}
func NewTarArchiver(compressType CompressType) *TarArchiver {
func NewTarArchiver(compressType CompressType) ShellArchiver {
return &TarArchiver{
Cmd: "tar",
CompressType: compressType,
}
}
func (t TarArchiver) Compress(SourcePaths []string) error {
return cmd.ExecCmd(fmt.Sprintf("%s %s %s %s", t.Cmd, t.getOptionStr("compress"), t.FilePath, strings.Join(SourcePaths, " ")))
func (t TarArchiver) Extract(FilePath string, dstDir string) error {
return cmd.ExecCmd(fmt.Sprintf("%s %s %s -C %s", t.Cmd, t.getOptionStr("extract"), FilePath, dstDir))
}
func (t TarArchiver) Extract(dstDir string) error {
return cmd.ExecCmd(fmt.Sprintf("%s %s %s -C %s", t.Cmd, t.getOptionStr("extract"), t.FilePath, dstDir))
func (t TarArchiver) Compress(sourcePaths []string, dstFile string) error {
return nil
}
func (t TarArchiver) getOptionStr(Option string) string {

View file

@ -0,0 +1,43 @@
package files
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"path"
"strings"
"time"
)
type ZipArchiver struct {
}
func NewZipArchiver() ShellArchiver {
return &ZipArchiver{}
}
func (z ZipArchiver) Extract(filePath, dstDir string) error {
if err := checkCmdAvailability("unzip"); err != nil {
return err
}
return cmd.ExecCmd(fmt.Sprintf("unzip -qo %s -d %s", filePath, dstDir))
}
func (z ZipArchiver) Compress(sourcePaths []string, dstFile string) error {
tmpFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("%s%s.zip", common.RandStr(50), time.Now().Format("20060102150405")))
op := NewFileOp()
defer func() {
_ = op.DeleteFile(tmpFile)
}()
baseDir := path.Dir(sourcePaths[0])
relativePaths := make([]string, len(sourcePaths))
for i, sp := range sourcePaths {
relativePaths[i] = path.Base(sp)
}
cmdStr := fmt.Sprintf("zip -qr %s %s", tmpFile, strings.Join(relativePaths, " "))
if err := cmd.ExecCmdWithDir(cmdStr, baseDir); err != nil {
return err
}
return op.Rename(tmpFile, dstFile)
}