package utils import ( "archive/tar" "archive/zip" "compress/gzip" "io" "os" "path/filepath" "strings" ) func ExtractZip(src, dest string) error { r, err := zip.OpenReader(src) if err != nil { return err } defer r.Close() for _, f := range r.File { fpath := filepath.Join(dest, f.Name) // 安全检查:防止路径遍历 (ZipSlip) rel, err := filepath.Rel(dest, fpath) if err != nil || strings.HasPrefix(rel, ".."+string(filepath.Separator)) || rel == ".." { continue } if f.FileInfo().IsDir() { os.MkdirAll(fpath, 0755) continue } if err := os.MkdirAll(filepath.Dir(fpath), 0755); err != nil { return err } outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) if err != nil { return err } rc, err := f.Open() if err != nil { outFile.Close() return err } _, err = io.Copy(outFile, rc) outFile.Close() rc.Close() if err != nil { return err } } return nil } func ExtractTar(src, dest string) error { file, err := os.Open(src) if err != nil { return err } defer file.Close() return extractTarReader(tar.NewReader(file), dest) } func ExtractTarGz(src, dest string) error { file, err := os.Open(src) if err != nil { return err } defer file.Close() gzr, err := gzip.NewReader(file) if err != nil { return err } defer gzr.Close() return extractTarReader(tar.NewReader(gzr), dest) } func extractTarReader(tr *tar.Reader, dest string) error { for { header, err := tr.Next() if err == io.EOF { break } if err != nil { return err } fpath := filepath.Join(dest, header.Name) // 安全检查:防止路径遍历 rel, err := filepath.Rel(dest, fpath) if err != nil || strings.HasPrefix(rel, ".."+string(filepath.Separator)) || rel == ".." { continue } switch header.Typeflag { case tar.TypeDir: os.MkdirAll(fpath, 0755) case tar.TypeReg: if err := os.MkdirAll(filepath.Dir(fpath), 0755); err != nil { return err } outFile, err := os.Create(fpath) if err != nil { return err } if _, err := io.Copy(outFile, tr); err != nil { outFile.Close() return err } outFile.Close() os.Chmod(fpath, os.FileMode(header.Mode)) } } return nil }