func unzip()

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
}