func readZip()

in commands/job/artifact/logic.go [39:114]


func readZip(artifact *bytes.Reader, path string, zipReadLimit int64, zipFileLimit int) error {
	zipReader, err := zip.NewReader(artifact, artifact.Size())
	if err != nil {
		return err
	}

	if !config.CheckPathExists(path) {
		if err := os.Mkdir(path, 0o755); err != nil {
			return err
		}
	}

	if !strings.HasSuffix(path, "/") {
		path = path + "/"
	}

	var written int64 = 0
	if len(zipReader.File) > zipFileLimit {
		return fmt.Errorf("zip archive includes too many files: limit is %d files", zipFileLimit)
	}

	for _, v := range zipReader.File {
		sanitizedAssetName := utils.SanitizePathName(v.Name)

		destDir, err := filepath.Abs(path)
		if err != nil {
			return fmt.Errorf("resolving absolute download directory path: %v", err)
		}
		destPath := filepath.Join(destDir, sanitizedAssetName)
		if !strings.HasPrefix(destPath, destDir) {
			return fmt.Errorf("invalid file path name")
		}

		dbg.Debug("Writing:", destPath)

		if v.FileInfo().IsDir() {
			if err := os.MkdirAll(destPath, v.Mode()); err != nil {
				return err
			}
		} else {
			srcFile, err := zipReader.Open(v.Name)
			if err != nil {
				return err
			}
			defer srcFile.Close()

			limitedReader := io.LimitReader(srcFile, zipReadLimit)

			err = ensurePathIsCreated(destPath)
			if err != nil {
				return err
			}

			symlinkCheck, _ := os.Lstat(destPath)

			if symlinkCheck != nil && symlinkCheck.Mode()&os.ModeSymlink != 0 {
				return fmt.Errorf("can't extract. A file in the artifact would overwrite a symbolic link.")
			}

			dstFile, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, v.Mode())
			if err != nil {
				return err
			}
			var writtenPerFile int64
			if writtenPerFile, err = io.Copy(dstFile, limitedReader); err != nil {
				return err
			}

			written += writtenPerFile
			if written >= zipReadLimit {
				return fmt.Errorf("extracted zip too large: limit is %d bytes", zipReadLimit)
			}
		}
	}
	return nil
}