Browse code

Ensure same atime, mtime after applying whiteouts

Michael Crosby authored on 2013/11/19 17:35:03
Showing 1 changed files
... ...
@@ -1,10 +1,11 @@
1 1
 package archive
2 2
 
3 3
 import (
4
-	"log"
5 4
 	"os"
6 5
 	"path/filepath"
7 6
 	"strings"
7
+	"syscall"
8
+	"time"
8 9
 )
9 10
 
10 11
 // ApplyLayer parses a diff in the standard layer format from `layer`, and
... ...
@@ -17,6 +18,20 @@ func ApplyLayer(dest string, layer Archive) error {
17 17
 		return err
18 18
 	}
19 19
 
20
+	modifiedDirs := make(map[string]*syscall.Stat_t)
21
+	addDir := func(file string) {
22
+		d := filepath.Dir(file)
23
+		if _, exists := modifiedDirs[d]; !exists {
24
+			if s, err := os.Lstat(d); err == nil {
25
+				if sys := s.Sys(); sys != nil {
26
+					if stat, ok := sys.(*syscall.Stat_t); ok {
27
+						modifiedDirs[d] = stat
28
+					}
29
+				}
30
+			}
31
+		}
32
+	}
33
+
20 34
 	// Step 2: walk for whiteouts and apply them, removing them in the process
21 35
 	err := filepath.Walk(dest, func(fullPath string, f os.FileInfo, err error) error {
22 36
 		if err != nil {
... ...
@@ -39,25 +54,42 @@ func ApplyLayer(dest string, layer Archive) error {
39 39
 		if matched, err := filepath.Match("/.wh..wh.*", path); err != nil {
40 40
 			return err
41 41
 		} else if matched {
42
-			log.Printf("Removing aufs metadata %s", fullPath)
43
-			_ = os.RemoveAll(fullPath)
42
+			addDir(fullPath)
43
+			if err := os.RemoveAll(fullPath); err != nil {
44
+				return err
45
+			}
44 46
 		}
45 47
 
46 48
 		filename := filepath.Base(path)
47 49
 		if strings.HasPrefix(filename, ".wh.") {
48 50
 			rmTargetName := filename[len(".wh."):]
49 51
 			rmTargetPath := filepath.Join(filepath.Dir(fullPath), rmTargetName)
52
+
50 53
 			// Remove the file targeted by the whiteout
51
-			log.Printf("Removing whiteout target %s", rmTargetPath)
52
-			_ = os.RemoveAll(rmTargetPath)
54
+			addDir(rmTargetPath)
55
+			if err := os.RemoveAll(rmTargetPath); err != nil {
56
+				return err
57
+			}
53 58
 			// Remove the whiteout itself
54
-			log.Printf("Removing whiteout %s", fullPath)
55
-			_ = os.RemoveAll(fullPath)
59
+			addDir(fullPath)
60
+			if err := os.RemoveAll(fullPath); err != nil {
61
+				return err
62
+			}
56 63
 		}
57 64
 		return nil
58 65
 	})
59 66
 	if err != nil {
60 67
 		return err
61 68
 	}
69
+
70
+	for k, v := range modifiedDirs {
71
+		aTime := time.Unix(v.Atim.Unix())
72
+		mTime := time.Unix(v.Mtim.Unix())
73
+
74
+		if err := os.Chtimes(k, aTime, mTime); err != nil {
75
+			return err
76
+		}
77
+	}
78
+
62 79
 	return nil
63 80
 }