Merge pull request #20130 from Microsoft/sjw/windows_save_fix

Fixing 'docker save' on Windows.
This commit is contained in:
David Calavera 2016-02-09 07:47:58 -08:00
commit 01a1925792
7 changed files with 57 additions and 73 deletions

View file

@ -6,7 +6,6 @@ import (
"crypto/sha512"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@ -501,10 +500,6 @@ func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPat
if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil {
return
}
err = copySysFiles(tempFolder, filepath.Join(d.info.HomeDir, "sysfile-backups", id))
if err != nil {
return
}
logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
@ -602,69 +597,9 @@ func (d *Driver) DiffPath(id string) (path string, release func() error, err err
return
}
err = copySysFiles(filepath.Join(d.info.HomeDir, "sysfile-backups", id), tempFolder)
if err != nil {
return
}
return tempFolder, func() error {
// TODO: activate layers and release here?
_, folderName := filepath.Split(tempFolder)
return hcsshim.DestroyLayer(d.info, folderName)
}, nil
}
var sysFileWhiteList = []string{
"Hives\\*",
"Files\\BOOTNXT",
"tombstones.txt",
}
// note this only handles files
func copySysFiles(src string, dest string) error {
if err := os.MkdirAll(dest, 0700); err != nil {
return err
}
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
rel, err := filepath.Rel(src, path)
if err != nil {
return err
}
for _, sysfile := range sysFileWhiteList {
if matches, err := filepath.Match(sysfile, rel); err != nil || !matches {
continue
}
fi, err := os.Lstat(path)
if err != nil {
return err
}
if !fi.Mode().IsRegular() {
continue
}
targetPath := filepath.Join(dest, rel)
if err = os.MkdirAll(filepath.Dir(targetPath), 0700); err != nil {
return err
}
in, err := os.Open(path)
if err != nil {
return err
}
out, err := os.Create(targetPath)
if err != nil {
in.Close()
return err
}
_, err = io.Copy(out, in)
in.Close()
out.Close()
if err != nil {
return err
}
}
return nil
})
}

View file

@ -14,6 +14,7 @@ import (
"github.com/docker/docker/image/v1"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/reference"
)
@ -160,7 +161,7 @@ func (s *saveSession) save(outStream io.Writer) error {
if err := f.Close(); err != nil {
return err
}
if err := os.Chtimes(reposFile, time.Unix(0, 0), time.Unix(0, 0)); err != nil {
if err := system.Chtimes(reposFile, time.Unix(0, 0), time.Unix(0, 0)); err != nil {
return err
}
}
@ -177,7 +178,7 @@ func (s *saveSession) save(outStream io.Writer) error {
if err := f.Close(); err != nil {
return err
}
if err := os.Chtimes(manifestFileName, time.Unix(0, 0), time.Unix(0, 0)); err != nil {
if err := system.Chtimes(manifestFileName, time.Unix(0, 0), time.Unix(0, 0)); err != nil {
return err
}
@ -233,7 +234,7 @@ func (s *saveSession) saveImage(id image.ID) error {
if err := ioutil.WriteFile(configFile, img.RawJSON(), 0644); err != nil {
return err
}
if err := os.Chtimes(configFile, img.Created, img.Created); err != nil {
if err := system.Chtimes(configFile, img.Created, img.Created); err != nil {
return err
}
@ -290,7 +291,7 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
// todo: maybe save layer created timestamp?
if err := os.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
return err
}
}

View file

@ -8,6 +8,8 @@ import (
"sort"
"testing"
"time"
"github.com/docker/docker/pkg/system"
)
func max(x, y int) int {
@ -87,7 +89,7 @@ func createSampleDir(t *testing.T, root string) {
if info.filetype != Symlink {
// Set a consistent ctime, atime for all files and dirs
if err := os.Chtimes(p, now, now); err != nil {
if err := system.Chtimes(p, now, now); err != nil {
t.Fatal(err)
}
}
@ -289,7 +291,7 @@ func mutateSampleDir(t *testing.T, root string) {
}
// Touch file
if err := os.Chtimes(path.Join(root, "file4"), time.Now().Add(time.Second), time.Now().Add(time.Second)); err != nil {
if err := system.Chtimes(path.Join(root, "file4"), time.Now().Add(time.Second), time.Now().Add(time.Second)); err != nil {
t.Fatal(err)
}
@ -333,7 +335,7 @@ func mutateSampleDir(t *testing.T, root string) {
}
// Touch dir
if err := os.Chtimes(path.Join(root, "dir3"), time.Now().Add(time.Second), time.Now().Add(time.Second)); err != nil {
if err := system.Chtimes(path.Join(root, "dir3"), time.Now().Add(time.Second), time.Now().Add(time.Second)); err != nil {
t.Fatal(err)
}
}

View file

@ -43,5 +43,10 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error {
return err
}
// Take platform specific action for setting create time.
if err := setCTime(name, mtime); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,14 @@
// +build !windows
package system
import (
"time"
)
//setCTime will set the create time on a file. On Unix, the create
//time is updated as a side effect of setting the modified time, so
//no action is required.
func setCTime(path string, ctime time.Time) error {
return nil
}

View file

@ -1,4 +1,4 @@
// +build linux freebsd
// +build !windows
package system

View file

@ -0,0 +1,27 @@
// +build windows
package system
import (
"syscall"
"time"
)
//setCTime will set the create time on a file. On Windows, this requires
//calling SetFileTime and explicitly including the create time.
func setCTime(path string, ctime time.Time) error {
ctimespec := syscall.NsecToTimespec(ctime.UnixNano())
pathp, e := syscall.UTF16PtrFromString(path)
if e != nil {
return e
}
h, e := syscall.CreateFile(pathp,
syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil,
syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil {
return e
}
defer syscall.Close(h)
c := syscall.NsecToFiletime(syscall.TimespecToNsec(ctimespec))
return syscall.SetFileTime(h, &c, nil, nil)
}