extractZip reads a ZIP archive at path and extracts its contents into destDir. It returns an error if the archive cannot be read, or if any file or directory within the archive cannot be created or written.
(path, destDir string)
| 370 | // It returns an error if the archive cannot be read, |
| 371 | // or if any file or directory within the archive cannot be created or written. |
| 372 | func extractZip(path, destDir string) error { |
| 373 | zipReader, err := zip.OpenReader(path) |
| 374 | if err != nil { |
| 375 | return fmt.Errorf("failed to open zip: %w", err) |
| 376 | } |
| 377 | defer zipReader.Close() |
| 378 | |
| 379 | absPath, err := safepaths.ParseAbsolute(destDir) |
| 380 | if err != nil { |
| 381 | return err |
| 382 | } |
| 383 | |
| 384 | // As of the time of writing, ghzip.ExtractZip will safely skip files that |
| 385 | // would result in path traversal. This is an issue for our use-case because |
| 386 | // we want to error out before extracting if there's any such file. |
| 387 | // To avoid breaking the shared ghzip.ExtractZip code that expects unsafe |
| 388 | // paths to be ignored and no error produced, we pre-validate here, |
| 389 | // producing an error if any such file is found. |
| 390 | for _, f := range zipReader.File { |
| 391 | _, err := absPath.Join(f.Name) |
| 392 | if err != nil { |
| 393 | return err |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | if err := ghzip.ExtractZip(&zipReader.Reader, absPath); err != nil { |
| 398 | return err |
| 399 | } |
| 400 | |
| 401 | return nil |
| 402 | } |
| 403 | |
| 404 | // extractTarGz reads a TAR.GZ archive from r and extracts its contents into destDir. |
| 405 | // It returns an error if the archive cannot be read, |