浏览代码

Merge pull request #20130 from Microsoft/sjw/windows_save_fix

Fixing 'docker save' on Windows.
David Calavera 9 年之前
父节点
当前提交
01a1925792

+ 0 - 65
daemon/graphdriver/windows/windows.go

@@ -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
-	})
-}

+ 5 - 4
image/tarexport/save.go

@@ -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
 		}
 	}

+ 5 - 3
pkg/archive/changes_test.go

@@ -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)
 	}
 }

+ 5 - 0
pkg/system/chtimes.go

@@ -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
 }

+ 14 - 0
pkg/system/chtimes_unix.go

@@ -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
+}

+ 1 - 1
pkg/system/chtimes_unix_test.go

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

+ 27 - 0
pkg/system/chtimes_windows.go

@@ -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)
+}