Browse Source

Merge pull request #48 from crosbymichael/reset-mtime

Ensure same atime, mtime after applying whiteouts
Guillaume J. Charmes 11 years ago
parent
commit
91330243b5
1 changed files with 39 additions and 7 deletions
  1. 39 7
      archive/diff.go

+ 39 - 7
archive/diff.go

@@ -1,10 +1,11 @@
 package archive
 
 import (
-	"log"
 	"os"
 	"path/filepath"
 	"strings"
+	"syscall"
+	"time"
 )
 
 // ApplyLayer parses a diff in the standard layer format from `layer`, and
@@ -17,6 +18,20 @@ func ApplyLayer(dest string, layer Archive) error {
 		return err
 	}
 
+	modifiedDirs := make(map[string]*syscall.Stat_t)
+	addDir := func(file string) {
+		d := filepath.Dir(file)
+		if _, exists := modifiedDirs[d]; !exists {
+			if s, err := os.Lstat(d); err == nil {
+				if sys := s.Sys(); sys != nil {
+					if stat, ok := sys.(*syscall.Stat_t); ok {
+						modifiedDirs[d] = stat
+					}
+				}
+			}
+		}
+	}
+
 	// Step 2: walk for whiteouts and apply them, removing them in the process
 	err := filepath.Walk(dest, func(fullPath string, f os.FileInfo, err error) error {
 		if err != nil {
@@ -39,25 +54,42 @@ func ApplyLayer(dest string, layer Archive) error {
 		if matched, err := filepath.Match("/.wh..wh.*", path); err != nil {
 			return err
 		} else if matched {
-			log.Printf("Removing aufs metadata %s", fullPath)
-			_ = os.RemoveAll(fullPath)
+			addDir(fullPath)
+			if err := os.RemoveAll(fullPath); err != nil {
+				return err
+			}
 		}
 
 		filename := filepath.Base(path)
 		if strings.HasPrefix(filename, ".wh.") {
 			rmTargetName := filename[len(".wh."):]
 			rmTargetPath := filepath.Join(filepath.Dir(fullPath), rmTargetName)
+
 			// Remove the file targeted by the whiteout
-			log.Printf("Removing whiteout target %s", rmTargetPath)
-			_ = os.RemoveAll(rmTargetPath)
+			addDir(rmTargetPath)
+			if err := os.RemoveAll(rmTargetPath); err != nil {
+				return err
+			}
 			// Remove the whiteout itself
-			log.Printf("Removing whiteout %s", fullPath)
-			_ = os.RemoveAll(fullPath)
+			addDir(fullPath)
+			if err := os.RemoveAll(fullPath); err != nil {
+				return err
+			}
 		}
 		return nil
 	})
 	if err != nil {
 		return err
 	}
+
+	for k, v := range modifiedDirs {
+		aTime := time.Unix(v.Atim.Unix())
+		mTime := time.Unix(v.Mtim.Unix())
+
+		if err := os.Chtimes(k, aTime, mTime); err != nil {
+			return err
+		}
+	}
+
 	return nil
 }