func (ms *conversionStore) WriteACI(path string) (string, error) { f, err := os.Open(path) if err != nil { return "", err } defer f.Close() cr, err := aci.NewCompressedReader(f) if err != nil { return "", err } defer cr.Close() h := sha512.New() r := io.TeeReader(cr, h) // read the file so we can get the hash if _, err := io.Copy(ioutil.Discard, r); err != nil { return "", fmt.Errorf("error reading ACI: %v", err) } im, err := aci.ManifestFromImage(f) if err != nil { return "", err } key := ms.HashToKey(h) ms.acis[key] = &aciInfo{path: path, key: key, ImageManifest: im} return key, nil }
// ExtractImage will extract the contents of the image at path to the directory // at dst. If fileMap is set, only files in it will be extracted. func ExtractImage(path, dst string, fileMap map[string]struct{}) error { dst, err := filepath.Abs(dst) if err != nil { return err } file, err := os.Open(path) if err != nil { return err } defer file.Close() dr, err := aci.NewCompressedReader(file) if err != nil { return fmt.Errorf("error decompressing image: %v", err) } defer dr.Close() uidRange := user.NewBlankUidRange() if os.Geteuid() == 0 { return rkttar.ExtractTar(dr, dst, true, uidRange, fileMap) } editor, err := rkttar.NewUidShiftingFilePermEditor(uidRange) if err != nil { return fmt.Errorf("error determining current user: %v", err) } return rkttar.ExtractTarInsecure(tar.NewReader(dr), dst, true, fileMap, editor) }
func (ms *conversionStore) ReadStream(key string) (io.ReadCloser, error) { img, ok := ms.acis[key] if !ok { return nil, fmt.Errorf("stream for key: %s not found", key) } f, err := os.Open(img.path) if err != nil { return nil, fmt.Errorf("error opening aci: %s", img.path) } tr, err := aci.NewCompressedReader(f) if err != nil { return nil, err } return tr, nil }
// WriteACI takes an ACI encapsulated in an io.Reader, decompresses it if // necessary, and then stores it in the store under a key based on the image ID // (i.e. the hash of the uncompressed ACI) // latest defines if the aci has to be marked as the latest. For example an ACI // discovered without asking for a specific version (latest pattern). func (s *Store) WriteACI(r io.ReadSeeker, fetchInfo ACIFetchInfo) (string, error) { // We need to allow the store's setgid bits (if any) to propagate, so // disable umask um := syscall.Umask(0) defer syscall.Umask(um) dr, err := aci.NewCompressedReader(r) if err != nil { return "", errwrap.Wrap(errors.New("error decompressing image"), err) } defer dr.Close() // Write the decompressed image (tar) to a temporary file on disk, and // tee so we can generate the hash h := sha512.New() tr := io.TeeReader(dr, h) fh, err := s.TmpFile() if err != nil { return "", errwrap.Wrap(errors.New("error creating image"), err) } sz, err := io.Copy(fh, tr) if err != nil { return "", errwrap.Wrap(errors.New("error copying image"), err) } im, err := aci.ManifestFromImage(fh) if err != nil { return "", errwrap.Wrap(errors.New("error extracting image manifest"), err) } if err := fh.Close(); err != nil { return "", errwrap.Wrap(errors.New("error closing image"), err) } // Import the uncompressed image into the store at the real key key := s.HashToKey(h) keyLock, err := lock.ExclusiveKeyLock(s.imageLockDir, key) if err != nil { return "", errwrap.Wrap(errors.New("error locking image"), err) } defer keyLock.Close() if err = s.stores[blobType].Import(fh.Name(), key, true); err != nil { return "", errwrap.Wrap(errors.New("error importing image"), err) } // Save the imagemanifest using the same key used for the image imj, err := json.Marshal(im) if err != nil { return "", errwrap.Wrap(errors.New("error marshalling image manifest"), err) } if err := s.stores[imageManifestType].Write(key, imj); err != nil { return "", errwrap.Wrap(errors.New("error importing image manifest"), err) } // Save aciinfo if err = s.db.Do(func(tx *sql.Tx) error { aciinfo := &ACIInfo{ BlobKey: key, Name: im.Name.String(), ImportTime: time.Now(), LastUsed: time.Now(), Latest: fetchInfo.Latest, Size: sz, } return WriteACIInfo(tx, aciinfo) }); err != nil { return "", errwrap.Wrap(errors.New("error writing ACI Info"), err) } return key, nil }