1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Fixing 'docker save' on Windows.

Save was failing file integrity checksums due to bugs in both
Windows and Docker. This commit includes fixes to file time handling
in tarexport and system.chtimes that are necessary along with
the Windows platform fixes to correctly support save. With this
change, sysfile_backups for windowsfilter driver are no longer
needed, so that code is removed.

Signed-off-by: Stefan J. Wernli <swernli@microsoft.com>
This commit is contained in:
Stefan J. Wernli 2016-02-08 15:40:12 -08:00
parent ac9d1b7b47
commit 041a9510c6
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)
}