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