From cf7944bf6f64c844b74ad937a79d66dafaf99673 Mon Sep 17 00:00:00 2001 From: John Starks Date: Tue, 29 Mar 2016 09:53:00 -0700 Subject: [PATCH] Windows: Support ApplyDiff on a base layer This adds support to the Windows graph driver for ApplyDiff on a base layer. It also adds support for hard links, which are needed because the Windows base layers double in size without hard link support. Signed-off-by: John Starks --- daemon/graphdriver/windows/windows.go | 62 ++++++++++++++++----------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/daemon/graphdriver/windows/windows.go b/daemon/graphdriver/windows/windows.go index 0d51d43f74..d4317165d0 100644 --- a/daemon/graphdriver/windows/windows.go +++ b/daemon/graphdriver/windows/windows.go @@ -26,6 +26,7 @@ import ( "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/ioutils" + "github.com/docker/docker/pkg/longpath" "github.com/vbatts/tar-split/tar/storage" ) @@ -319,10 +320,10 @@ func (d *Driver) Changes(id, parent string) ([]archive.Change, error) { } name = filepath.ToSlash(name) if fileInfo == nil { - changes = append(changes, archive.Change{name, archive.ChangeDelete}) + 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{name, archive.ChangeModify}) + changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify}) } } return changes, nil @@ -332,45 +333,49 @@ func (d *Driver) Changes(id, parent string) ([]archive.Change, error) { // layer with the specified id and parent, returning the size of the // new layer in bytes. // The layer should not be mounted when calling this function -func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) { - rPId, err := d.resolveID(parent) - if err != nil { - return - } - +func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (int64, error) { if d.info.Flavour == diffDriver { start := time.Now().UTC() logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer") destination := d.dir(id) destination = filepath.Dir(destination) - if size, err = chrootarchive.ApplyUncompressedLayer(destination, diff, nil); err != nil { - return + size, err := chrootarchive.ApplyUncompressedLayer(destination, diff, nil) + if err != nil { + return 0, err } logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) - return + return size, nil } - parentChain, err := d.getLayerChain(rPId) - if err != nil { - return + var layerChain []string + if parent != "" { + rPId, err := d.resolveID(parent) + if err != nil { + return 0, err + } + parentChain, err := d.getLayerChain(rPId) + if err != nil { + return 0, err + } + parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId) + if err != nil { + return 0, err + } + layerChain = append(layerChain, parentPath) + layerChain = append(layerChain, parentChain...) } - parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId) - if err != nil { - return - } - layerChain := []string{parentPath} - layerChain = append(layerChain, parentChain...) - if size, err = d.importLayer(id, diff, layerChain); err != nil { - return + size, err := d.importLayer(id, diff, layerChain) + if err != nil { + return 0, err } if err = d.setLayerChain(id, layerChain); err != nil { - return + return 0, err } - return + return size, nil } // DiffSize calculates the changes between the specified layer @@ -539,6 +544,12 @@ func writeLayerFromTar(r archive.Reader, w hcsshim.LayerWriter) (int64, error) { return 0, err } hdr, err = t.Next() + } else if hdr.Typeflag == tar.TypeLink { + err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname)) + if err != nil { + return 0, err + } + hdr, err = t.Next() } else { var ( name string @@ -575,7 +586,6 @@ func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPat if err != nil { return } - size, err = writeLayerFromTar(layerData, w) if err != nil { w.Close() @@ -653,7 +663,7 @@ func (fg *fileGetCloserWithBackupPrivileges) Get(filename string) (io.ReadCloser // file can be opened even if the caller does not actually have access to it according // to the security descriptor. err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error { - path := filepath.Join(fg.path, filename) + path := longpath.AddPrefix(filepath.Join(fg.path, filename)) p, err := syscall.UTF16FromString(path) if err != nil { return err