// ApplyDiff extracts the changeset from the given diff into the // layer with the specified id and parent, returning the size of the // new layer in bytes. func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) { driver := gdw.ProtoDriver // Mount the root filesystem so we can apply the diff/layer. layerFs, err := driver.Get(id, "") if err != nil { return } defer driver.Put(id) start := time.Now().UTC() log.Debugf("Start untar layer") if err = archive.ApplyLayer(layerFs, diff); err != nil { return } log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) if parent == "" { return utils.TreeSize(layerFs) } parentFs, err := driver.Get(parent, "") if err != nil { err = fmt.Errorf("Driver %s failed to get image parent %s: %s", driver, parent, err) return } defer driver.Put(parent) changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return } return archive.ChangesSize(layerFs, changes), nil }
// TarLayer returns a tar archive of the image's filesystem layer. func (img *Image) TarLayer() (arch archive.Archive, err error) { if img.graph == nil { return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID) } driver := img.graph.Driver() if differ, ok := driver.(graphdriver.Differ); ok { return differ.Diff(img.ID) } imgFs, err := driver.Get(img.ID, "") if err != nil { return nil, err } defer func() { if err != nil { driver.Put(img.ID) } }() if img.Parent == "" { archive, err := archive.Tar(imgFs, archive.Uncompressed) if err != nil { return nil, err } return utils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(img.ID) return err }), nil } parentFs, err := driver.Get(img.Parent, "") if err != nil { return nil, err } defer driver.Put(img.Parent) changes, err := archive.ChangesDirs(imgFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(imgFs, changes) if err != nil { return nil, err } return utils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(img.ID) return err }), nil }
// Diff produces an archive of the changes between the specified // layer and its parent layer which may be "". func (gdw *naiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") if err != nil { return nil, err } defer func() { if err != nil { driver.Put(id) } }() if parent == "" { archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil } parentFs, err := driver.Get(parent, "") if err != nil { return nil, err } defer driver.Put(parent) changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(layerFs, changes) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil }
func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) { if differ, ok := daemon.driver.(graphdriver.Differ); ok { return differ.Changes(container.ID) } cDir, err := daemon.driver.Get(container.ID, "") if err != nil { return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err) } defer daemon.driver.Put(container.ID) initDir, err := daemon.driver.Get(container.ID+"-init", "") if err != nil { return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err) } defer daemon.driver.Put(container.ID + "-init") return archive.ChangesDirs(cDir, initDir) }
// Get returns the image with the given id, or an error if the image doesn't exist. func (graph *Graph) Get(name string) (*image.Image, error) { id, err := graph.idIndex.Get(name) if err != nil { return nil, err } // FIXME: return nil when the image doesn't exist, instead of an error img, err := image.LoadImage(graph.ImageRoot(id)) if err != nil { return nil, err } if img.ID != id { return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID) } img.SetGraph(graph) if img.Size < 0 { rootfs, err := graph.driver.Get(img.ID, "") if err != nil { return nil, fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err) } defer graph.driver.Put(img.ID) var size int64 if img.Parent == "" { if size, err = utils.TreeSize(rootfs); err != nil { return nil, err } } else { parentFs, err := graph.driver.Get(img.Parent, "") if err != nil { return nil, err } changes, err := archive.ChangesDirs(rootfs, parentFs) if err != nil { return nil, err } size = archive.ChangesSize(rootfs, changes) } img.Size = size if err := img.SaveSize(graph.ImageRoot(id)); err != nil { return nil, err } } return img, nil }
// Changes produces a list of changes between the specified layer // and its parent layer. If parent is "", then all changes will be ADD changes. func (gdw *naiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) { driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") if err != nil { return nil, err } defer driver.Put(id) parentFs := "" if parent != "" { parentFs, err = driver.Get(parent, "") if err != nil { return nil, err } defer driver.Put(parent) } return archive.ChangesDirs(layerFs, parentFs) }
func StoreImage(img *Image, jsonData []byte, layerData archive.ArchiveReader, root, layer string) error { // Store the layer var ( size int64 err error driver = img.graph.Driver() ) if err := os.MkdirAll(layer, 0755); err != nil { return err } // If layerData is not nil, unpack it into the new layer if layerData != nil { if differ, ok := driver.(graphdriver.Differ); ok { if err := differ.ApplyDiff(img.ID, layerData); err != nil { return err } if size, err = differ.DiffSize(img.ID); err != nil { return err } } else { start := time.Now().UTC() log.Debugf("Start untar layer") if err := archive.ApplyLayer(layer, layerData); err != nil { return err } log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) if img.Parent == "" { if size, err = utils.TreeSize(layer); err != nil { return err } } else { parent, err := driver.Get(img.Parent, "") if err != nil { return err } defer driver.Put(img.Parent) changes, err := archive.ChangesDirs(layer, parent) if err != nil { return err } size = archive.ChangesSize(layer, changes) } } } img.Size = size if err := img.SaveSize(root); err != nil { return err } // If raw json is provided, then use it if jsonData != nil { if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil { return err } } else { if jsonData, err = json.Marshal(img); err != nil { return err } if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil { return err } } return nil }