* Use mholt/archives instead of mholt/archiver * Fix validations * Fix iszip function * Fix directory * Add better path sanitization * ensure safe dir is passed * Fix file permissions * Fix config path * Sanitize builder source path --------- Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
121 lines
3.0 KiB
Go
121 lines
3.0 KiB
Go
package utils
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/mholt/archives"
|
|
)
|
|
|
|
func IsZip(ctx context.Context, filename string) (bool, error) {
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
result, err := archives.Zip{}.Match(ctx, filename, f)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if result.ByName || result.ByStream {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func MakeZipArchiveWithGlobs(ctx context.Context, targetName string, globs ...string) (string, error) {
|
|
globFiles, err := FindAllGlobs(globs...)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(globFiles) == 0 {
|
|
return "", fmt.Errorf("no files found for globs: %v", globs)
|
|
}
|
|
files := make(map[string]string, len(globFiles))
|
|
for _, file := range globFiles {
|
|
files[file] = ""
|
|
}
|
|
|
|
archiveFiles, err := archives.FilesFromDisk(ctx, nil, files)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to read files from disk: %w", err)
|
|
}
|
|
out, err := os.Create(targetName)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to create archive file: %w", err)
|
|
}
|
|
defer out.Close()
|
|
zip := archives.CompressedArchive{
|
|
Archival: archives.Zip{},
|
|
}
|
|
if err := zip.Archive(ctx, out, archiveFiles); err != nil {
|
|
return "", fmt.Errorf("failed to create archive: %w", err)
|
|
}
|
|
return filepath.Abs(targetName)
|
|
}
|
|
|
|
// Archive zips the contents of directory at src into a new zip file
|
|
// at dst (note that the contents are zipped, not the directory itself).
|
|
func Archive(ctx context.Context, src string, dst string) error {
|
|
srcInfo, err := os.Stat(src)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get source directory info: %w", err)
|
|
}
|
|
if srcInfo.IsDir() {
|
|
src = src + "/*"
|
|
}
|
|
_, err = MakeZipArchiveWithGlobs(ctx, dst, src)
|
|
return err
|
|
}
|
|
|
|
// Unarchive is a function that unzips a zip file to destination
|
|
func Unarchive(ctx context.Context, src string, dst string) error {
|
|
var format archives.Zip
|
|
file, err := os.Open(src)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open file: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
return format.Extract(ctx, file, func(ctx context.Context, f archives.FileInfo) error {
|
|
destPath := filepath.Join(dst, f.NameInArchive)
|
|
// check if the file is a directory
|
|
if f.IsDir() {
|
|
return os.MkdirAll(destPath, f.Mode())
|
|
}
|
|
|
|
// check if parent directory exists for the file
|
|
if err := os.MkdirAll(filepath.Dir(destPath), os.ModeDir|0755); err != nil {
|
|
return fmt.Errorf("failed to create parent directory: %w", err)
|
|
}
|
|
|
|
// Open file in archive
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open file in archive: %w", err)
|
|
}
|
|
defer rc.Close()
|
|
|
|
// Create file in destination
|
|
destFile, err := os.Create(destPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create file in destination: %w", err)
|
|
}
|
|
defer destFile.Close()
|
|
err = destFile.Chmod(f.Mode())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to set file permissions: %w", err)
|
|
}
|
|
|
|
// Copy file contents
|
|
_, err = io.Copy(destFile, rc)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to copy file contents: %w", err)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|