in gcs-fetcher/pkg/fetcher/fetcher.go [764:832]
func unzip(zipfile, dest string) (numFiles int, err error) {
zipReader, err := zip.OpenReader(zipfile)
if err != nil {
return 0, fmt.Errorf("opening archive %s: %v", zipfile, err)
}
defer func() {
if cerr := zipReader.Close(); cerr != nil {
err = fmt.Errorf("closing archive %s: %v", zipfile, cerr)
}
}()
numFiles = 0
for _, file := range zipReader.File {
target := filepath.Join(dest, file.Name)
if file.FileInfo().IsDir() {
// Create directory with appropriate permissions if it doesn't exist.
if _, err := os.Stat(target); os.IsNotExist(err) {
if err := os.MkdirAll(target, file.Mode()); err != nil {
return 0, fmt.Errorf("making directory %s: %v", target, err)
}
continue
} else if err != nil {
return 0, fmt.Errorf("checking existence on %s: %v", target, err)
}
// If directory already exists, it may have been created below as a
// parent directory when processing a file. In this case, we must
// set the directory's permissions correctly.
if err := os.Chmod(target, file.Mode()); err != nil {
return 0, fmt.Errorf("setting permissions on %s: %v", target, err)
}
continue
}
// Create parent directories with full access. This only matters if the
// file comes from zipReader before the directory. In this case, the
// file permissions will be set to the correct value when the directory
// itself is processed above.
if err := os.MkdirAll(filepath.Dir(target), 0777); err != nil {
return 0, fmt.Errorf("making parent directories for %s: %v", target, err)
}
// Actually copy the bytes, using func to get early defer calls
// (important for large numbers of files).
numFiles++
reader, err := file.Open()
if err != nil {
return 0, fmt.Errorf("opening file in %s: %v", target, err)
}
if err := func() (ferr error) {
writer, err := os.OpenFile(target, os.O_WRONLY|os.O_CREATE, file.Mode())
if err != nil {
return fmt.Errorf("opening target file %s: %v", target, err)
}
defer func() {
if cerr := writer.Close(); cerr != nil {
ferr = fmt.Errorf("closing target file %s: %v", target, cerr)
}
}()
if _, err := io.Copy(writer, reader); err != nil {
return fmt.Errorf("copying %s to %s: %v", file.Name, target, err)
}
return nil
}(); err != nil {
return 0, err
}
}
return numFiles, nil
}