func (dm *downloadManager) Download(ctx context.Context, initialRootFS image.RootFS, layers []xfer.DownloadDescriptor, progressOutput progress.Output) (image.RootFS, func(), error) { for _, l := range layers { b, err := dm.blobStore.New() if err != nil { return initialRootFS, nil, err } defer b.Close() rc, _, err := l.Download(ctx, progressOutput) if err != nil { return initialRootFS, nil, errors.Wrap(err, "failed to download") } defer rc.Close() r := io.TeeReader(rc, b) inflatedLayerData, err := archive.DecompressStream(r) if err != nil { return initialRootFS, nil, err } digester := digest.Canonical.New() if _, err := archive.ApplyLayer(dm.tmpDir, io.TeeReader(inflatedLayerData, digester.Hash())); err != nil { return initialRootFS, nil, err } initialRootFS.Append(layer.DiffID(digester.Digest())) d, err := b.Commit() if err != nil { return initialRootFS, nil, err } dm.blobs = append(dm.blobs, d) } return initialRootFS, nil, nil }
func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool) error { var ( sf = streamformatter.NewJSONStreamFormatter() progressOutput progress.Output ) if !quiet { progressOutput = sf.NewProgressOutput(outStream, false) outStream = &streamformatter.StdoutFormatter{Writer: outStream, StreamFormatter: streamformatter.NewJSONStreamFormatter()} } tmpDir, err := ioutil.TempDir("", "docker-import-") if err != nil { return err } defer os.RemoveAll(tmpDir) if err := chrootarchive.Untar(inTar, tmpDir, nil); err != nil { return err } // read manifest, if no file then load in legacy mode manifestPath, err := safePath(tmpDir, manifestFileName) if err != nil { return err } manifestFile, err := os.Open(manifestPath) if err != nil { if os.IsNotExist(err) { return l.legacyLoad(tmpDir, outStream, progressOutput) } return manifestFile.Close() } defer manifestFile.Close() var manifest []manifestItem if err := json.NewDecoder(manifestFile).Decode(&manifest); err != nil { return err } var parentLinks []parentLink for _, m := range manifest { configPath, err := safePath(tmpDir, m.Config) if err != nil { return err } config, err := ioutil.ReadFile(configPath) if err != nil { return err } img, err := image.NewFromJSON(config) if err != nil { return err } var rootFS image.RootFS rootFS = *img.RootFS rootFS.DiffIDs = nil if expected, actual := len(m.Layers), len(img.RootFS.DiffIDs); expected != actual { return fmt.Errorf("invalid manifest, layers length mismatch: expected %q, got %q", expected, actual) } for i, diffID := range img.RootFS.DiffIDs { layerPath, err := safePath(tmpDir, m.Layers[i]) if err != nil { return err } r := rootFS r.Append(diffID) newLayer, err := l.ls.Get(r.ChainID()) if err != nil { newLayer, err = l.loadLayer(layerPath, rootFS, diffID.String(), progressOutput) if err != nil { return err } } defer layer.ReleaseAndLog(l.ls, newLayer) if expected, actual := diffID, newLayer.DiffID(); expected != actual { return fmt.Errorf("invalid diffID for layer %d: expected %q, got %q", i, expected, actual) } rootFS.Append(diffID) } imgID, err := l.is.Create(config) if err != nil { return err } for _, repoTag := range m.RepoTags { named, err := reference.ParseNamed(repoTag) if err != nil { return err } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid tag %q", repoTag) } l.setLoadedTag(ref, imgID, outStream) } parentLinks = append(parentLinks, parentLink{imgID, m.Parent}) l.loggerImgEvent.LogImageEvent(imgID.String(), imgID.String(), "load") } for _, p := range validatedParentLinks(parentLinks) { if p.parentID != "" { if err := l.setParentID(p.id, p.parentID); err != nil { return err } } } return nil }
func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error { tmpDir, err := ioutil.TempDir("", "docker-import-") if err != nil { return err } defer os.RemoveAll(tmpDir) if err := chrootarchive.Untar(inTar, tmpDir, nil); err != nil { return err } // read manifest, if no file then load in legacy mode manifestPath, err := safePath(tmpDir, manifestFileName) if err != nil { return err } manifestFile, err := os.Open(manifestPath) if err != nil { if os.IsNotExist(err) { return l.legacyLoad(tmpDir, outStream) } return manifestFile.Close() } defer manifestFile.Close() var manifest []manifestItem if err := json.NewDecoder(manifestFile).Decode(&manifest); err != nil { return err } for _, m := range manifest { configPath, err := safePath(tmpDir, m.Config) if err != nil { return err } config, err := ioutil.ReadFile(configPath) if err != nil { return err } img, err := image.NewFromJSON(config) if err != nil { return err } var rootFS image.RootFS rootFS = *img.RootFS rootFS.DiffIDs = nil if expected, actual := len(m.Layers), len(img.RootFS.DiffIDs); expected != actual { return fmt.Errorf("invalid manifest, layers length mismatch: expected %q, got %q", expected, actual) } for i, diffID := range img.RootFS.DiffIDs { layerPath, err := safePath(tmpDir, m.Layers[i]) if err != nil { return err } newLayer, err := l.loadLayer(layerPath, rootFS) if err != nil { return err } defer layer.ReleaseAndLog(l.ls, newLayer) if expected, actual := diffID, newLayer.DiffID(); expected != actual { return fmt.Errorf("invalid diffID for layer %d: expected %q, got %q", i, expected, actual) } rootFS.Append(diffID) } imgID, err := l.is.Create(config) if err != nil { return err } for _, repoTag := range m.RepoTags { named, err := reference.ParseNamed(repoTag) if err != nil { return err } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid tag %q", repoTag) } l.setLoadedTag(ref, imgID, outStream) } } return nil }