Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/chisel/cmd_debug_check_release_archives.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func computePathObservations(release *setup.Release, archives map[string]archive
if err != nil {
return nil, err
}
dataReader, err := deb.DataReader(pkgReader)
dataReader, err := deb.OpenTar(pkgReader)
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion internal/archive/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/canonical/chisel/internal/archive"
"github.com/canonical/chisel/internal/archive/testarchive"
"github.com/canonical/chisel/internal/deb"
"github.com/canonical/chisel/internal/tarball"
"github.com/canonical/chisel/internal/testutil"
)
Expand Down Expand Up @@ -1235,7 +1236,7 @@ func (s *S) testOpenArchiveArch(c *C, test realArchiveTest, arch string) {
c.Assert(info.Name, DeepEquals, test.pkg)
c.Assert(info.Arch, DeepEquals, arch)

err = tarball.Extract(pkg, &tarball.ExtractOptions{
err = tarball.Extract(pkg, deb.OpenTar, &tarball.ExtractOptions{
Package: test.pkg,
TargetDir: extractDir,
Extract: map[string][]tarball.ExtractInfo{
Expand Down
6 changes: 3 additions & 3 deletions internal/deb/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
"github.com/ulikunitz/xz"
)

// DataReader takes a Reader for the ar file belonging to a Debian package and
// returns a Reader to the inner tarball.
func DataReader(pkgReader io.ReadSeeker) (io.ReadCloser, error) {
// OpenTar takes a Reader for the ar file belonging to a Debian package and
// returns a Reader to the uncompressed inner tarball.
func OpenTar(pkgReader io.Reader) (io.ReadCloser, error) {
arReader := ar.NewReader(pkgReader)
var dataReader io.ReadCloser
for dataReader == nil {
Expand Down
3 changes: 2 additions & 1 deletion internal/slicer/slicer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/klauspost/compress/zstd"

"github.com/canonical/chisel/internal/archive"
"github.com/canonical/chisel/internal/deb"
"github.com/canonical/chisel/internal/fsutil"
"github.com/canonical/chisel/internal/manifestutil"
"github.com/canonical/chisel/internal/scripts"
Expand Down Expand Up @@ -239,7 +240,7 @@ func Run(options *RunOptions) error {
if reader == nil {
continue
}
err := tarball.Extract(reader, &tarball.ExtractOptions{
err := tarball.Extract(reader, deb.OpenTar, &tarball.ExtractOptions{
Package: slice.Package,
Extract: extract[slice.Package],
TargetDir: targetDir,
Expand Down
38 changes: 28 additions & 10 deletions internal/tarball/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,25 @@ import (
"strings"
"syscall"

"github.com/canonical/chisel/internal/deb"
"github.com/ulikunitz/xz"

"github.com/canonical/chisel/internal/fsutil"
"github.com/canonical/chisel/internal/strdist"
)

// TarOpener returns a reader over the uncompressed tar stream contained in
// its input, hiding the container and compression details from Extract.
type TarOpener func(pkgReader io.Reader) (io.ReadCloser, error)

// OpenXZTar returns a reader over the decompressed XZ stream.
func OpenXZTar(pkgReader io.Reader) (io.ReadCloser, error) {
xzReader, err := xz.NewReader(pkgReader)
if err != nil {
return nil, err
}
return io.NopCloser(xzReader), nil
}

type ExtractOptions struct {
Package string
TargetDir string
Expand Down Expand Up @@ -58,7 +72,7 @@ func getValidOptions(options *ExtractOptions) (*ExtractOptions, error) {
return options, nil
}

func Extract(pkgReader io.ReadSeeker, options *ExtractOptions) (err error) {
func Extract(pkgReader io.ReadSeeker, opener TarOpener, options *ExtractOptions) (err error) {
defer func() {
if err != nil {
err = fmt.Errorf("cannot extract from package %q: %w", options.Package, err)
Expand All @@ -67,6 +81,10 @@ func Extract(pkgReader io.ReadSeeker, options *ExtractOptions) (err error) {

logf("Extracting files from package %q...", options.Package)

if opener == nil {
return fmt.Errorf("internal error: no tar opener provided")
}

validOpts, err := getValidOptions(options)
if err != nil {
return err
Expand All @@ -79,11 +97,11 @@ func Extract(pkgReader io.ReadSeeker, options *ExtractOptions) (err error) {
return err
}

return extractData(pkgReader, validOpts)
return extractData(pkgReader, opener, validOpts)
}

func extractData(pkgReader io.ReadSeeker, options *ExtractOptions) error {
dataReader, err := deb.DataReader(pkgReader)
func extractData(pkgReader io.ReadSeeker, opener TarOpener, options *ExtractOptions) error {
dataReader, err := opener(pkgReader)
if err != nil {
return err
}
Expand Down Expand Up @@ -117,8 +135,8 @@ func extractData(pkgReader io.ReadSeeker, options *ExtractOptions) error {
// create them with the permissions defined in the tarball.
//
// The assumption is that the tar entries of the parent directories appear
// before the entry for the file itself. This is the case for .deb files but
// not for all tarballs.
// before the entry for the file itself. This is the case for the tarballs
// produced by common packaging tools but not for all tarballs.
tarDirMode := make(map[string]fs.FileMode)
tarReader := tar.NewReader(dataReader)
for {
Expand Down Expand Up @@ -265,7 +283,7 @@ func extractData(pkgReader io.ReadSeeker, options *ExtractOptions) error {
if err != nil {
return err
}
err = extractHardLinks(pkgReader, extractHardLinkOptions)
err = extractHardLinks(pkgReader, opener, extractHardLinkOptions)
if err != nil {
return err
}
Expand Down Expand Up @@ -299,8 +317,8 @@ type extractHardLinkOptions struct {

// extractHardLinks iterates through the tarball a second time to extract the
// hard links that were not extracted in the first pass.
func extractHardLinks(pkgReader io.ReadSeeker, opts *extractHardLinkOptions) error {
dataReader, err := deb.DataReader(pkgReader)
func extractHardLinks(pkgReader io.ReadSeeker, opener TarOpener, opts *extractHardLinkOptions) error {
dataReader, err := opener(pkgReader)
if err != nil {
return err
}
Expand Down
27 changes: 25 additions & 2 deletions internal/tarball/extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

. "gopkg.in/check.v1"

"github.com/canonical/chisel/internal/deb"
"github.com/canonical/chisel/internal/fsutil"
"github.com/canonical/chisel/internal/tarball"
"github.com/canonical/chisel/internal/testutil"
Expand All @@ -18,6 +19,7 @@ import (
type extractTest struct {
summary string
pkgdata []byte
openTar tarball.TarOpener
options tarball.ExtractOptions
hackopt func(c *C, o *tarball.ExtractOptions)
result map[string]string
Expand Down Expand Up @@ -511,7 +513,11 @@ func (s *S) TestExtract(c *C) {
test.hackopt(c, &options)
}

err := tarball.Extract(bytes.NewReader(test.pkgdata), &options)
openTar := test.openTar
if openTar == nil {
openTar = deb.OpenTar
}
err := tarball.Extract(bytes.NewReader(test.pkgdata), openTar, &options)
if test.error != "" {
c.Assert(err, ErrorMatches, test.error)
continue
Expand Down Expand Up @@ -539,6 +545,7 @@ func (s *S) TestExtract(c *C) {
var extractCreateCallbackTests = []struct {
summary string
pkgdata []byte
openTar tarball.TarOpener
options tarball.ExtractOptions
calls map[string][]tarball.ExtractInfo
}{{
Expand Down Expand Up @@ -622,9 +629,25 @@ func (s *S) TestExtractCreateCallback(c *C) {
return nil
}

err := tarball.Extract(bytes.NewReader(test.pkgdata), &options)
openTar := test.openTar
if openTar == nil {
openTar = deb.OpenTar
}
err := tarball.Extract(bytes.NewReader(test.pkgdata), openTar, &options)
c.Assert(err, IsNil)

c.Assert(createExtractInfos, DeepEquals, test.calls)
}
}

func (s *S) TestExtractMissingOpenTar(c *C) {
options := tarball.ExtractOptions{
Package: "test-package",
TargetDir: c.MkDir(),
Extract: map[string][]tarball.ExtractInfo{
"/dir/file": {{Path: "/dir/file"}},
},
}
err := tarball.Extract(bytes.NewReader(testutil.PackageData["test-package"]), nil, &options)
c.Assert(err, ErrorMatches, `cannot extract from package "test-package": internal error: no tar opener provided`)
}
Loading