func maybeDecompress(rs io.ReadSeeker) (io.Reader, error) { // TODO(jonboulle): this is a bit redundant with detectValType typ, err := aci.DetectFileType(rs) if err != nil { return nil, err } if _, err := rs.Seek(0, 0); err != nil { return nil, err } var r io.Reader switch typ { case aci.TypeGzip: r, err = gzip.NewReader(rs) if err != nil { return nil, fmt.Errorf("error reading gzip: %v", err) } case aci.TypeBzip2: r = bzip2.NewReader(rs) case aci.TypeXz: r = aci.XzReader(rs) case aci.TypeTar: r = rs case aci.TypeUnknown: return nil, errors.New("unknown filetype") default: // should never happen panic(fmt.Sprintf("bad type returned from DetectFileType: %v", typ)) } return r, nil }
// unpackRootfs unpacks a stage1 rootfs (compressed file, pointed to by rfs) // into dir, returning any error encountered func unpackRootfs(rfs string, dir string) error { fh, err := os.Open(rfs) if err != nil { return fmt.Errorf("error opening stage1 rootfs: %v", err) } typ, err := aci.DetectFileType(fh) if err != nil { return fmt.Errorf("error detecting image type: %v", err) } if _, err := fh.Seek(0, 0); err != nil { return fmt.Errorf("error seeking image: %v", err) } var r io.Reader switch typ { case aci.TypeGzip: r, err = gzip.NewReader(fh) if err != nil { return fmt.Errorf("error reading gzip: %v", err) } case aci.TypeBzip2: r = bzip2.NewReader(fh) case aci.TypeXz: r = aci.XzReader(fh) case aci.TypeTar: r = fh case aci.TypeUnknown: return fmt.Errorf("error: unknown image filetype") default: // should never happen panic("no type returned from DetectFileType?") } return untarRootfs(r, dir) }
func (ds Store) WriteACI(tmpKey string, orig io.Reader) (string, error) { // We initially write the ACI into the store using a temporary key, // teeing a header so we can detect the filetype for decompression hdr := &bytes.Buffer{} hw := &pkgio.LimitedWriter{ W: hdr, N: 512, } tr := io.TeeReader(orig, hw) err := ds.stores[tmpType].WriteStream(tmpKey, tr, true) if err != nil { return "", err } // Now detect the filetype so we can choose the appropriate decompressor typ, err := aci.DetectFileType(hdr) if err != nil { return "", err } // Read the image back out of the store to generate the hash of the decompressed tar rs, err := ds.stores[tmpType].ReadStream(tmpKey, false) if err != nil { return "", err } defer rs.Close() dr, err := decompress(rs, typ) if err != nil { return "", err } hash := sha256.New() _, err = io.Copy(hash, dr) if err != nil { return "", err } // Store the decompressed tar using the hash as the real key rs, err = ds.stores[tmpType].ReadStream(tmpKey, false) if err != nil { return "", err } defer rs.Close() dr, err = decompress(rs, typ) if err != nil { return "", err } key := fmt.Sprintf("sha256-%x", hash.Sum(nil)) err = ds.stores[blobType].WriteStream(key, dr, true) if err != nil { return "", err } ds.stores[tmpType].Erase(tmpKey) return key, nil }
func detectValType(file *os.File) (string, error) { typ, err := aci.DetectFileType(file) if err != nil { return "", err } if _, err := file.Seek(0, 0); err != nil { return "", err } switch typ { case aci.TypeXz, aci.TypeGzip, aci.TypeBzip2, aci.TypeTar: return typeAppImage, nil case aci.TypeText: return typeManifest, nil default: return "", nil } }