Skip to content

Commit

Permalink
Fix export of symlinks from archives & OCI images (#209)
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanjli authored May 15, 2024
1 parent c5e2b33 commit 045ded6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 18 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.7.2-alpha.5 - 2024-05-15

### Fixed

- (cli) Symlinks are now handled correctly when they need to be exported from downloaded archives or OCI images.

## 0.7.2-alpha.4 - 2024-05-15

### Fixed
Expand Down
54 changes: 36 additions & 18 deletions internal/app/forklift/bundles.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,10 @@ func determineFileType(
return filetype.MatchReader(archiveFile)
}

func extractFile(tarReader *tar.Reader, sourcePath string, exportPath string) error {
func extractFile(tarReader *tar.Reader, sourcePath, exportPath string) error {
if sourcePath == "/" || sourcePath == "." {
sourcePath = ""
}
fmt.Printf("exporting into %s...\n", exportPath)
for {
header, err := tarReader.Next()
if err == io.EOF {
Expand All @@ -391,34 +390,53 @@ func extractFile(tarReader *tar.Reader, sourcePath string, exportPath string) er
case tar.TypeDir:
if err = EnsureExists(filepath.FromSlash(targetPath)); err != nil {
return errors.Wrapf(
err, "couldn't export %s from archive to %s", header.Name, targetPath,
err, "couldn't export directory %s from archive to %s", header.Name, targetPath,
)
}
case tar.TypeReg:
targetFile, err := os.OpenFile(
filepath.FromSlash(targetPath), os.O_RDWR|os.O_CREATE|os.O_TRUNC,
fs.FileMode(header.Mode&int64(fs.ModePerm)),
)
if err != nil {
return errors.Wrapf(err, "couldn't create export file at %s", targetPath)
if err = extractRegularFile(header, tarReader, sourcePath, targetPath); err != nil {
return errors.Wrapf(
err, "couldn't export regular file %s from archive to %s", header.Name, targetPath,
)
}
defer func(file fs.File, filePath string) {
if err := file.Close(); err != nil {
// FIXME: handle this error better
fmt.Printf("Error: couldn't close export file %s\n", filePath)
}
}(targetFile, targetPath)

if _, err = io.Copy(targetFile, tarReader); err != nil {
case tar.TypeSymlink:
if err = os.Symlink(
filepath.FromSlash(header.Linkname), filepath.FromSlash(targetPath),
); err != nil {
return errors.Wrapf(
err, "couldn't copy file %s in tar archive to %s", sourcePath, targetPath,
err, "couldn't export symlink %s from archive to %s", header.Name, targetPath,
)
}
}
}
return nil
}

func extractRegularFile(
header *tar.Header, tarReader *tar.Reader, sourcePath, targetPath string,
) error {
targetFile, err := os.OpenFile(
filepath.FromSlash(targetPath), os.O_RDWR|os.O_CREATE|os.O_TRUNC,
fs.FileMode(header.Mode&int64(fs.ModePerm)),
)
if err != nil {
return errors.Wrapf(err, "couldn't create export file at %s", targetPath)
}
defer func(file fs.File, filePath string) {
if err := file.Close(); err != nil {
// FIXME: handle this error better
fmt.Printf("Error: couldn't close export file %s\n", filePath)
}
}(targetFile, targetPath)

if _, err = io.Copy(targetFile, tarReader); err != nil {
return errors.Wrapf(
err, "couldn't copy file %s in tar archive to %s", sourcePath, targetPath,
)
}
return nil
}

// FSBundle: FSRepoLoader

func (b *FSBundle) LoadFSRepo(repoPath string, version string) (*core.FSRepo, error) {
Expand Down

0 comments on commit 045ded6

Please sign in to comment.