// 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 }
// DiffSize calculates the changes between the specified layer // and its parent and returns the size in bytes of the changes // relative to its base filesystem directory. func (gdw *naiveDiffDriver) DiffSize(id, parent string) (bytes int64, err error) { driver := gdw.ProtoDriver changes, err := gdw.Changes(id, parent) if err != nil { return } layerFs, err := driver.Get(id, "") if err != nil { return } defer driver.Put(id) return archive.ChangesSize(layerFs, changes), nil }
// 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 }
// GetSize, return real size, virtual size func (container *Container) GetSize() (int64, int64) { var ( sizeRw, sizeRootfs int64 err error driver = container.daemon.driver ) if err := container.Mount(); err != nil { utils.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err) return sizeRw, sizeRootfs } defer container.Unmount() if differ, ok := container.daemon.driver.(graphdriver.Differ); ok { sizeRw, err = differ.DiffSize(container.ID) if err != nil { utils.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err) // FIXME: GetSize should return an error. Not changing it now in case // there is a side-effect. sizeRw = -1 } } else { changes, _ := container.Changes() if changes != nil { sizeRw = archive.ChangesSize(container.basefs, changes) } else { sizeRw = -1 } } if _, err = os.Stat(container.basefs); err != nil { if sizeRootfs, err = utils.TreeSize(container.basefs); err != nil { sizeRootfs = -1 } } return sizeRw, sizeRootfs }
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 }