helpers/archives/zip_extract.go (89 lines of code) (raw):

package archives import ( "archive/zip" "io" "io/ioutil" "os" "path/filepath" "github.com/Sirupsen/logrus" ) func extractZipDirectoryEntry(file *zip.File) (err error) { err = os.Mkdir(file.Name, file.Mode().Perm()) // The error that directory does exists is not a error for us if os.IsExist(err) { err = nil } return } func extractZipSymlinkEntry(file *zip.File) (err error) { var data []byte in, err := file.Open() if err != nil { return err } defer in.Close() data, err = ioutil.ReadAll(in) if err != nil { return err } // Remove symlink before creating a new one, otherwise we can error that file does exist os.Remove(file.Name) err = os.Symlink(string(data), file.Name) return } func extractZipFileEntry(file *zip.File) (err error) { var out *os.File in, err := file.Open() if err != nil { return err } defer in.Close() // Remove file before creating a new one, otherwise we can error that file does exist os.Remove(file.Name) out, err = os.OpenFile(file.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode().Perm()) if err != nil { return err } defer out.Close() _, err = io.Copy(out, in) return } func extractZipFile(file *zip.File) (err error) { // Create all parents to extract the file os.MkdirAll(filepath.Dir(file.Name), 0777) switch file.Mode() & os.ModeType { case os.ModeDir: err = extractZipDirectoryEntry(file) case os.ModeSymlink: err = extractZipSymlinkEntry(file) case os.ModeNamedPipe, os.ModeSocket, os.ModeDevice: // Ignore the files that of these types logrus.Warningln("File ignored: %q", file.Name) default: err = extractZipFileEntry(file) } return } func ExtractZipArchive(archive *zip.Reader) error { tracker := newPathErrorTracker() for _, file := range archive.File { if err := errorIfGitDirectory(file.Name); tracker.actionable(err) { printGitArchiveWarning("extract") } if err := extractZipFile(file); tracker.actionable(err) { logrus.Warningf("%s: %s (suppressing repeats)", file.Name, err) } } for _, file := range archive.File { // Update file permissions if err := os.Chmod(file.Name, file.Mode().Perm()); tracker.actionable(err) { logrus.Warningf("%s: %s (suppressing repeats)", file.Name, err) } // Process zip metadata if err := processZipExtra(&file.FileHeader); tracker.actionable(err) { logrus.Warningf("%s: %s (suppressing repeats)", file.Name, err) } } return nil } func ExtractZipFile(fileName string) error { archive, err := zip.OpenReader(fileName) if err != nil { return err } defer archive.Close() return ExtractZipArchive(&archive.Reader) }