func skipToArMember(arReader *ar.Reader, memberPrefix string) (io.Reader, error) { var err error // find the right ar member var header *ar.Header for { header, err = arReader.Next() if err != nil { return nil, err } if strings.HasPrefix(header.Name, memberPrefix) { break } } // figure out what compression to use var dataReader io.Reader switch { case strings.HasSuffix(header.Name, ".gz"): dataReader, err = gzip.NewReader(arReader) if err != nil { return nil, err } case strings.HasSuffix(header.Name, ".bz2"): dataReader = bzip2.NewReader(arReader) case strings.HasSuffix(header.Name, ".xz"): dataReader = xzPipeReader(arReader) default: return nil, fmt.Errorf("Can not handle %s", header.Name) } return dataReader, nil }
// extract 'control' file from 'reader'. the contents of a 'control' file // is a set of key-value pairs as described in // https://www.debian.org/doc/debian-policy/ch-controlfields.html func extractControlFromIpk(reader io.Reader) (string, error) { var ( arReader *ar.Reader tarReader *tar.Reader gzReader *gzip.Reader ) arReader = ar.NewReader(reader) for { header, err := arReader.Next() if err != nil && err != io.EOF { return "", fmt.Errorf("extracting contents: %v", err) } else if header == nil { break } // NOTE: strangeley the name of the files end with a "/" ... content error? if header.Name == "control.tar.gz/" || header.Name == "control.tar.gz" { gzReader, err = gzip.NewReader(arReader) if err != nil { return "", fmt.Errorf("analyzing control.tar.gz: %v", err) } break } } if gzReader == nil { return "", fmt.Errorf("missing control.tar.gz entry") } defer gzReader.Close() buffer := bytes.NewBuffer(nil) tarReader = tar.NewReader(gzReader) for { header, err := tarReader.Next() if err != nil && err != io.EOF { return "", fmt.Errorf("extracting control.tar.gz: %v", err) } else if header == nil { break } if header.Name != "./control" { continue } io.Copy(buffer, tarReader) break } if buffer.Len() == 0 { return "", fmt.Errorf("missing or empty 'control' file inside 'control.tar.gz'") } return buffer.String(), nil }