// Changes produces a list of changes between the specified layer // and its parent layer. If parent is "", then all changes will be ADD changes. // The layer should be mounted when calling this function func (d *Driver) Changes(id, parent string) ([]archive.Change, error) { rID, err := d.resolveID(id) if err != nil { return nil, err } parentChain, err := d.getLayerChain(rID) if err != nil { return nil, err } // this is assuming that the layer is unmounted if err := hcsshim.UnprepareLayer(d.info, rID); err != nil { return nil, err } defer func() { if err := hcsshim.PrepareLayer(d.info, rID, parentChain); err != nil { logrus.Warnf("Failed to Deactivate %s: %s", rID, err) } }() var changes []archive.Change err = winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error { r, err := hcsshim.NewLayerReader(d.info, id, parentChain) if err != nil { return err } defer r.Close() for { name, _, fileInfo, err := r.Next() if err == io.EOF { return nil } if err != nil { return err } name = filepath.ToSlash(name) if fileInfo == nil { changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete}) } else { // Currently there is no way to tell between an add and a modify. changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify}) } } }) if err != nil { return nil, err } return changes, nil }
// exportLayer generates an archive from a layer based on the given ID. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) { if hcsshim.IsTP4() { // Export in TP4 format to maintain compatibility with existing images and // because ExportLayer is somewhat broken on TP4 and can't work with the new // scheme. tempFolder, err := ioutil.TempDir("", "hcs") if err != nil { return nil, err } defer func() { if err != nil { os.RemoveAll(tempFolder) } }() if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { return nil, err } archive, err := archive.Tar(tempFolder, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() os.RemoveAll(tempFolder) return err }), nil } var r hcsshim.LayerReader r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths) if err != nil { return nil, err } archive, w := io.Pipe() go func() { err := writeTarFromLayer(r, w) cerr := r.Close() if err == nil { err = cerr } w.CloseWithError(err) }() return archive, nil }
// exportLayer generates an archive from a layer based on the given ID. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) { var r hcsshim.LayerReader r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths) if err != nil { return nil, err } archive, w := io.Pipe() go func() { err := writeTarFromLayer(r, w) cerr := r.Close() if err == nil { err = cerr } w.CloseWithError(err) }() return archive, nil }
// exportLayer generates an archive from a layer based on the given ID. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) { archive, w := io.Pipe() go func() { err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error { r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths) if err != nil { return err } err = writeTarFromLayer(r, w) cerr := r.Close() if err == nil { err = cerr } return err }) w.CloseWithError(err) }() return archive, 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 (d *Driver) Changes(id, parent string) ([]archive.Change, error) { rID, err := d.resolveID(id) if err != nil { return nil, err } parentChain, err := d.getLayerChain(rID) if err != nil { return nil, err } d.Lock() if d.info.Flavour == filterDriver { if d.active[rID] == 0 { if err = hcsshim.ActivateLayer(d.info, rID); err != nil { d.Unlock() return nil, err } defer func() { if err := hcsshim.DeactivateLayer(d.info, rID); err != nil { logrus.Warnf("Failed to Deactivate %s: %s", rID, err) } }() } else { if err = hcsshim.UnprepareLayer(d.info, rID); err != nil { d.Unlock() return nil, err } defer func() { if err := hcsshim.PrepareLayer(d.info, rID, parentChain); err != nil { logrus.Warnf("Failed to re-PrepareLayer %s: %s", rID, err) } }() } } d.Unlock() r, err := hcsshim.NewLayerReader(d.info, id, parentChain) if err != nil { return nil, err } defer r.Close() var changes []archive.Change for { name, _, fileInfo, err := r.Next() if err == io.EOF { break } if err != nil { return nil, err } name = filepath.ToSlash(name) if fileInfo == nil { changes = append(changes, archive.Change{name, archive.ChangeDelete}) } else { // Currently there is no way to tell between an add and a modify. changes = append(changes, archive.Change{name, archive.ChangeModify}) } } return changes, nil }