diff --git a/deb/deb.go b/deb/deb.go index 26db3a1df..929407c4e 100644 --- a/deb/deb.go +++ b/deb/deb.go @@ -37,21 +37,46 @@ func GetControlFileFromDeb(packageFile string) (Stanza, error) { library := ar.NewReader(file) for { header, err := library.Next() + if err == io.EOF { - return nil, fmt.Errorf("unable to find control.tar.gz part in package %s", packageFile) + return nil, fmt.Errorf("unable to find control.tar.* part in package %s", packageFile) } if err != nil { return nil, fmt.Errorf("unable to read .deb archive %s: %s", packageFile, err) } - if header.Name == "control.tar.gz" { - ungzip, err := gzip.NewReader(library) - if err != nil { - return nil, fmt.Errorf("unable to ungzip control file from %s. Error: %s", packageFile, err) + // As per deb(5) version 1.19.0.4 the control file may be: + // - control.tar (since 1.17.6) + // - control.tar.gz + // - control.tar.xz (since 1.17.6) + // Look for all of the above and uncompress as necessary. + if strings.HasPrefix(header.Name, "control.tar") { + bufReader := bufio.NewReader(library) + + var tarInput io.Reader + + switch header.Name { + case "control.tar": + tarInput = bufReader + case "control.tar.gz": + ungzip, err := gzip.NewReader(bufReader) + if err != nil { + return nil, errors.Wrapf(err, "unable to ungzip %s from %s", header.Name, packageFile) + } + defer ungzip.Close() + tarInput = ungzip + case "control.tar.xz": + unxz, err := xz.NewReader(bufReader) + if err != nil { + return nil, errors.Wrapf(err, "unable to unxz %s from %s", header.Name, packageFile) + } + defer unxz.Close() + tarInput = unxz + default: + return nil, fmt.Errorf("unsupported tar compression in %s: %s", packageFile, header.Name) } - defer ungzip.Close() - untar := tar.NewReader(ungzip) + untar := tar.NewReader(tarInput) for { tarHeader, err := untar.Next() if err == io.EOF { diff --git a/deb/deb_test.go b/deb/deb_test.go index 9ffd74c75..d2d6dd38d 100644 --- a/deb/deb_test.go +++ b/deb/deb_test.go @@ -11,7 +11,7 @@ import ( ) type DebSuite struct { - debFile, debFile2, dscFile, dscFileNoSign string + debFile, debFile2, debFileWithXzControl, dscFile, dscFileNoSign string } var _ = Suite(&DebSuite{}) @@ -20,6 +20,7 @@ func (s *DebSuite) SetUpSuite(c *C) { _, _File, _, _ := runtime.Caller(0) s.debFile = filepath.Join(filepath.Dir(_File), "../system/files/libboost-program-options-dev_1.49.0.1_i386.deb") s.debFile2 = filepath.Join(filepath.Dir(_File), "../system/changes/hardlink_0.2.1_amd64.deb") + s.debFileWithXzControl = filepath.Join(filepath.Dir(_File), "../system/changes/libqt5concurrent5-dbgsym_5.9.1+dfsg-2+18.04+bionic+build4_amd64.ddeb") s.dscFile = filepath.Join(filepath.Dir(_File), "../system/files/pyspi_0.6.1-1.3.dsc") s.dscFileNoSign = filepath.Join(filepath.Dir(_File), "../system/files/pyspi-0.6.1-1.3.stripped.dsc") } @@ -38,6 +39,14 @@ func (s *DebSuite) TestGetControlFileFromDeb(c *C) { c.Check(st["Package"], Equals, "libboost-program-options-dev") } +func (s *DebSuite) TestGetControlFileFromDebWithXzControl(c *C) { + // Has control.tar.xz archive inside. + st, err := GetControlFileFromDeb(s.debFileWithXzControl) + c.Check(err, IsNil) + c.Check(st["Version"], Equals, "5.9.1+dfsg-2+18.04+bionic+build4") + c.Check(st["Package"], Equals, "libqt5concurrent5-dbgsym") +} + func (s *DebSuite) TestGetControlFileFromDsc(c *C) { verifier := &pgp.GoVerifier{} diff --git a/system/changes/libqt5concurrent5-dbgsym_5.9.1+dfsg-2+18.04+bionic+build4_amd64.ddeb b/system/changes/libqt5concurrent5-dbgsym_5.9.1+dfsg-2+18.04+bionic+build4_amd64.ddeb new file mode 100644 index 000000000..77d6946ac Binary files /dev/null and b/system/changes/libqt5concurrent5-dbgsym_5.9.1+dfsg-2+18.04+bionic+build4_amd64.ddeb differ