mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-21 21:47:32 +02:00
102 lines
1.9 KiB
Go
102 lines
1.9 KiB
Go
package getter
|
|
|
|
import (
|
|
"archive/zip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// ZipDecompressor is an implementation of Decompressor that can
|
|
// decompress tar.gzip files.
|
|
type ZipDecompressor struct{}
|
|
|
|
func (d *ZipDecompressor) Decompress(dst, src string, dir bool) error {
|
|
// If we're going into a directory we should make that first
|
|
mkdir := dst
|
|
if !dir {
|
|
mkdir = filepath.Dir(dst)
|
|
}
|
|
if err := os.MkdirAll(mkdir, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Open the zip
|
|
zipR, err := zip.OpenReader(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer zipR.Close()
|
|
|
|
// Check the zip integrity
|
|
if len(zipR.File) == 0 {
|
|
// Empty archive
|
|
return fmt.Errorf("empty archive: %s", src)
|
|
}
|
|
if !dir && len(zipR.File) > 1 {
|
|
return fmt.Errorf("expected a single file: %s", src)
|
|
}
|
|
|
|
// Go through and unarchive
|
|
for _, f := range zipR.File {
|
|
path := dst
|
|
if dir {
|
|
// Disallow parent traversal
|
|
if containsDotDot(f.Name) {
|
|
return fmt.Errorf("entry contains '..': %s", f.Name)
|
|
}
|
|
|
|
path = filepath.Join(path, f.Name)
|
|
}
|
|
|
|
if f.FileInfo().IsDir() {
|
|
if !dir {
|
|
return fmt.Errorf("expected a single file: %s", src)
|
|
}
|
|
|
|
// A directory, just make the directory and continue unarchiving...
|
|
if err := os.MkdirAll(path, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
// Create the enclosing directories if we must. ZIP files aren't
|
|
// required to contain entries for just the directories so this
|
|
// can happen.
|
|
if dir {
|
|
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Open the file for reading
|
|
srcF, err := f.Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Open the file for writing
|
|
dstF, err := os.Create(path)
|
|
if err != nil {
|
|
srcF.Close()
|
|
return err
|
|
}
|
|
_, err = io.Copy(dstF, srcF)
|
|
srcF.Close()
|
|
dstF.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Chmod the file
|
|
if err := os.Chmod(path, f.Mode()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|