1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
package deb
import (
"archive/tar"
"bufio"
"compress/bzip2"
"compress/gzip"
"fmt"
"io"
"os"
"strings"
"github.com/h2non/filetype/matchers"
ar "github.com/mkrautz/goar"
"github.com/pkg/errors"
"github.com/aptly-dev/aptly/pgp"
"github.com/kjk/lzma"
"github.com/klauspost/compress/zstd"
xz "github.com/smira/go-xz"
)
// Source kinds
const (
SourceSnapshot = "snapshot"
SourceLocalRepo = "local"
SourceRemoteRepo = "repo"
)
type parseQuery func(string) (PackageQuery, error)
// GetControlFileFromDeb reads control file from deb package
func GetControlFileFromDeb(packageFile string) (Stanza, error) {
file, err := os.Open(packageFile)
if err != nil {
return nil, err
}
defer func() { _ = file.Close() }()
library := ar.NewReader(file)
for {
header, err := library.Next()
if err == io.EOF {
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)
}
// 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 func() { _ = 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 func() { _ = unxz.Close() }()
tarInput = unxz
case "control.tar.zst":
unzstd, err := zstd.NewReader(bufReader)
if err != nil {
return nil, errors.Wrapf(err, "unable to unzstd %s from %s", header.Name, packageFile)
}
defer unzstd.Close()
tarInput = unzstd
default:
return nil, fmt.Errorf("unsupported tar compression in %s: %s", packageFile, header.Name)
}
untar := tar.NewReader(tarInput)
for {
tarHeader, err := untar.Next()
if err == io.EOF {
return nil, fmt.Errorf("unable to find control file in %s", packageFile)
}
if err != nil {
return nil, fmt.Errorf("unable to read .tar archive from %s. Error: %s", packageFile, err)
}
if tarHeader.Name == "./control" || tarHeader.Name == "control" {
reader := NewControlFileReader(untar, false, false)
stanza, err := reader.ReadStanza()
if err != nil {
return nil, err
}
return stanza, nil
}
}
}
}
}
// GetControlFileFromDsc reads control file from dsc package
func GetControlFileFromDsc(dscFile string, verifier pgp.Verifier) (Stanza, error) {
file, err := os.Open(dscFile)
if err != nil {
return nil, err
}
defer func() { _ = file.Close() }()
isClearSigned, err := verifier.IsClearSigned(file)
_, _ = file.Seek(0, 0)
if err != nil {
return nil, err
}
var text io.ReadCloser
if isClearSigned {
text, err = verifier.ExtractClearsigned(file)
if err != nil {
return nil, err
}
defer func() { _ = text.Close() }()
} else {
text = file
}
reader := NewControlFileReader(text, false, false)
stanza, err := reader.ReadStanza()
if err != nil {
return nil, err
}
return stanza, nil
}
// GetContentsFromDeb returns list of files installed by .deb package
func GetContentsFromDeb(file io.Reader, packageFile string) ([]string, error) {
library := ar.NewReader(file)
for {
header, err := library.Next()
if err == io.EOF {
return nil, fmt.Errorf("unable to find data.tar.* part in %s", packageFile)
}
if err != nil {
return nil, errors.Wrapf(err, "unable to read .deb archive from %s", packageFile)
}
if strings.HasPrefix(header.Name, "data.tar") {
bufReader := bufio.NewReader(library)
signature, err := bufReader.Peek(270)
var isTar bool
if err == nil {
isTar = matchers.Tar(signature)
}
var tarInput io.Reader
switch header.Name {
case "data.tar":
tarInput = bufReader
case "data.tar.gz":
if isTar {
tarInput = bufReader
} else {
ungzip, err := gzip.NewReader(bufReader)
if err != nil {
return nil, errors.Wrapf(err, "unable to ungzip data.tar.gz from %s", packageFile)
}
defer func() { _ = ungzip.Close() }()
tarInput = ungzip
}
case "data.tar.bz2":
tarInput = bzip2.NewReader(bufReader)
case "data.tar.xz":
unxz, err := xz.NewReader(bufReader)
if err != nil {
return nil, errors.Wrapf(err, "unable to unxz data.tar.xz from %s", packageFile)
}
defer func() { _ = unxz.Close() }()
tarInput = unxz
case "data.tar.lzma":
unlzma := lzma.NewReader(bufReader)
defer func() { _ = unlzma.Close() }()
tarInput = unlzma
case "data.tar.zst":
unzstd, err := zstd.NewReader(bufReader)
if err != nil {
return nil, errors.Wrapf(err, "unable to unzstd %s from %s", header.Name, packageFile)
}
defer unzstd.Close()
tarInput = unzstd
default:
return nil, fmt.Errorf("unsupported tar compression in %s: %s", packageFile, header.Name)
}
untar := tar.NewReader(tarInput)
var results []string
for {
tarHeader, err := untar.Next()
if err == io.EOF {
return results, nil
}
if err != nil {
return nil, errors.Wrapf(err, "unable to read .tar archive from %s", packageFile)
}
if tarHeader.Typeflag == tar.TypeDir {
continue
}
tarHeader.Name = strings.TrimPrefix(tarHeader.Name[2:], "./")
results = append(results, tarHeader.Name)
}
}
}
}
|