Browse code

Fixed file modified time not changing on Windows

Signed-off-by: Darren Stahl <darst@microsoft.com>

Darren Stahl authored on 2015/10/02 02:45:32
Showing 20 changed files
... ...
@@ -16,7 +16,6 @@ import (
16 16
 	"runtime"
17 17
 	"sort"
18 18
 	"strings"
19
-	"syscall"
20 19
 	"time"
21 20
 
22 21
 	"github.com/Sirupsen/logrus"
... ...
@@ -337,23 +336,19 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
337 337
 
338 338
 		// Set the mtime to the Last-Modified header value if present
339 339
 		// Otherwise just remove atime and mtime
340
-		times := make([]syscall.Timespec, 2)
340
+		mTime := time.Time{}
341 341
 
342 342
 		lastMod := resp.Header.Get("Last-Modified")
343 343
 		if lastMod != "" {
344
-			mTime, err := http.ParseTime(lastMod)
345 344
 			// If we can't parse it then just let it default to 'zero'
346 345
 			// otherwise use the parsed time value
347
-			if err == nil {
348
-				times[1] = syscall.NsecToTimespec(mTime.UnixNano())
346
+			if parsedMTime, err := http.ParseTime(lastMod); err == nil {
347
+				mTime = parsedMTime
349 348
 			}
350 349
 		}
351 350
 
352
-		// Windows does not support UtimesNano.
353
-		if runtime.GOOS != "windows" {
354
-			if err := system.UtimesNano(tmpFileName, times); err != nil {
355
-				return err
356
-			}
351
+		if err := system.Chtimes(tmpFileName, time.Time{}, mTime); err != nil {
352
+			return err
357 353
 		}
358 354
 
359 355
 		ci.origPath = filepath.Join(filepath.Base(tmpDirName), filepath.Base(tmpFileName))
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"os"
9 9
 	"path/filepath"
10 10
 	"syscall"
11
+	"time"
11 12
 
12 13
 	"github.com/docker/docker/pkg/system"
13 14
 )
... ...
@@ -149,13 +150,15 @@ func copyDir(srcDir, dstDir string, flags copyFlags) error {
149 149
 			}
150 150
 		}
151 151
 
152
-		ts := []syscall.Timespec{stat.Atim, stat.Mtim}
153
-		// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
152
+		// system.Chtimes doesn't support a NOFOLLOW flag atm
154 153
 		if !isSymlink {
155
-			if err := system.UtimesNano(dstPath, ts); err != nil {
154
+			aTime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
155
+			mTime := time.Unix(int64(stat.Mtim.Sec), int64(stat.Mtim.Nsec))
156
+			if err := system.Chtimes(dstPath, aTime, mTime); err != nil {
156 157
 				return err
157 158
 			}
158 159
 		} else {
160
+			ts := []syscall.Timespec{stat.Atim, stat.Mtim}
159 161
 			if err := system.LUtimesNano(dstPath, ts); err != nil {
160 162
 				return err
161 163
 			}
... ...
@@ -375,19 +375,19 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
375 375
 		return err
376 376
 	}
377 377
 
378
-	ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
379
-	// syscall.UtimesNano doesn't support a NOFOLLOW flag atm
378
+	// system.Chtimes doesn't support a NOFOLLOW flag atm
380 379
 	if hdr.Typeflag == tar.TypeLink {
381 380
 		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
382
-			if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
381
+			if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
383 382
 				return err
384 383
 			}
385 384
 		}
386 385
 	} else if hdr.Typeflag != tar.TypeSymlink {
387
-		if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
386
+		if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
388 387
 			return err
389 388
 		}
390 389
 	} else {
390
+		ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
391 391
 		if err := system.LUtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
392 392
 			return err
393 393
 		}
... ...
@@ -644,8 +644,8 @@ loop:
644 644
 
645 645
 	for _, hdr := range dirs {
646 646
 		path := filepath.Join(dest, hdr.Name)
647
-		ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
648
-		if err := syscall.UtimesNano(path, ts); err != nil {
647
+
648
+		if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
649 649
 			return err
650 650
 		}
651 651
 	}
... ...
@@ -9,7 +9,6 @@ import (
9 9
 	"path/filepath"
10 10
 	"runtime"
11 11
 	"strings"
12
-	"syscall"
13 12
 
14 13
 	"github.com/Sirupsen/logrus"
15 14
 	"github.com/docker/docker/pkg/pools"
... ...
@@ -167,8 +166,7 @@ func UnpackLayer(dest string, layer Reader) (size int64, err error) {
167 167
 
168 168
 	for _, hdr := range dirs {
169 169
 		path := filepath.Join(dest, hdr.Name)
170
-		ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
171
-		if err := syscall.UtimesNano(path, ts); err != nil {
170
+		if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
172 171
 			return 0, err
173 172
 		}
174 173
 	}
175 174
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+package system
1
+
2
+import (
3
+	"os"
4
+	"time"
5
+)
6
+
7
+// Chtimes changes the access time and modified time of a file at the given path
8
+func Chtimes(name string, atime time.Time, mtime time.Time) error {
9
+	unixMinTime := time.Unix(0, 0)
10
+	// The max Unix time is 33 bits set
11
+	unixMaxTime := unixMinTime.Add((1<<33 - 1) * time.Second)
12
+
13
+	// If the modified time is prior to the Unix Epoch, or after the
14
+	// end of Unix Time, os.Chtimes has undefined behavior
15
+	// default to Unix Epoch in this case, just in case
16
+
17
+	if atime.Before(unixMinTime) || atime.After(unixMaxTime) {
18
+		atime = unixMinTime
19
+	}
20
+
21
+	if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) {
22
+		mtime = unixMinTime
23
+	}
24
+
25
+	if err := os.Chtimes(name, atime, mtime); err != nil {
26
+		return err
27
+	}
28
+
29
+	return nil
30
+}
0 31
new file mode 100644
... ...
@@ -0,0 +1,120 @@
0
+package system
1
+
2
+import (
3
+	"io/ioutil"
4
+	"os"
5
+	"path/filepath"
6
+	"testing"
7
+	"time"
8
+)
9
+
10
+// prepareTempFile creates a temporary file in a temporary directory.
11
+func prepareTempFile(t *testing.T) (string, string) {
12
+	dir, err := ioutil.TempDir("", "docker-system-test")
13
+	if err != nil {
14
+		t.Fatal(err)
15
+	}
16
+
17
+	file := filepath.Join(dir, "exist")
18
+	if err := ioutil.WriteFile(file, []byte("hello"), 0644); err != nil {
19
+		t.Fatal(err)
20
+	}
21
+	return file, dir
22
+}
23
+
24
+// TestChtimes tests Chtimes on a tempfile. Test only mTime, because aTime is OS dependent
25
+func TestChtimes(t *testing.T) {
26
+	file, dir := prepareTempFile(t)
27
+	defer os.RemoveAll(dir)
28
+
29
+	beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
30
+	unixEpochTime := time.Unix(0, 0)
31
+	afterUnixEpochTime := time.Unix(100, 0)
32
+	// The max Unix time is 33 bits set
33
+	unixMaxTime := unixEpochTime.Add((1<<33 - 1) * time.Second)
34
+	afterUnixMaxTime := unixMaxTime.Add(100 * time.Second)
35
+
36
+	// Test both aTime and mTime set to Unix Epoch
37
+	Chtimes(file, unixEpochTime, unixEpochTime)
38
+
39
+	f, err := os.Stat(file)
40
+	if err != nil {
41
+		t.Fatal(err)
42
+	}
43
+
44
+	if f.ModTime() != unixEpochTime {
45
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
46
+	}
47
+
48
+	// Test aTime before Unix Epoch and mTime set to Unix Epoch
49
+	Chtimes(file, beforeUnixEpochTime, unixEpochTime)
50
+
51
+	f, err = os.Stat(file)
52
+	if err != nil {
53
+		t.Fatal(err)
54
+	}
55
+
56
+	if f.ModTime() != unixEpochTime {
57
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
58
+	}
59
+
60
+	// Test aTime set to Unix Epoch and mTime before Unix Epoch
61
+	Chtimes(file, unixEpochTime, beforeUnixEpochTime)
62
+
63
+	f, err = os.Stat(file)
64
+	if err != nil {
65
+		t.Fatal(err)
66
+	}
67
+
68
+	if f.ModTime() != unixEpochTime {
69
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
70
+	}
71
+
72
+	// Test both aTime and mTime set to after Unix Epoch (valid time)
73
+	Chtimes(file, afterUnixEpochTime, afterUnixEpochTime)
74
+
75
+	f, err = os.Stat(file)
76
+	if err != nil {
77
+		t.Fatal(err)
78
+	}
79
+
80
+	if f.ModTime() != afterUnixEpochTime {
81
+		t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, f.ModTime())
82
+	}
83
+
84
+	// Test both aTime and mTime set to Unix max time
85
+	Chtimes(file, unixMaxTime, unixMaxTime)
86
+
87
+	f, err = os.Stat(file)
88
+	if err != nil {
89
+		t.Fatal(err)
90
+	}
91
+
92
+	if f.ModTime() != unixMaxTime {
93
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime, f.ModTime())
94
+	}
95
+
96
+	// Test aTime after Unix max time and mTime set to Unix max time
97
+	Chtimes(file, afterUnixMaxTime, unixMaxTime)
98
+
99
+	f, err = os.Stat(file)
100
+	if err != nil {
101
+		t.Fatal(err)
102
+	}
103
+
104
+	if f.ModTime() != unixMaxTime {
105
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime, f.ModTime())
106
+	}
107
+
108
+	// Test aTime set to Unix Epoch and mTime before Unix Epoch
109
+	Chtimes(file, unixMaxTime, afterUnixMaxTime)
110
+
111
+	f, err = os.Stat(file)
112
+	if err != nil {
113
+		t.Fatal(err)
114
+	}
115
+
116
+	if f.ModTime() != unixEpochTime {
117
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
118
+	}
119
+}
0 120
new file mode 100644
... ...
@@ -0,0 +1,121 @@
0
+// +build linux freebsd
1
+
2
+package system
3
+
4
+import (
5
+	"os"
6
+	"syscall"
7
+	"testing"
8
+	"time"
9
+)
10
+
11
+// TestChtimes tests Chtimes access time on a tempfile on Linux
12
+func TestChtimesLinux(t *testing.T) {
13
+	file, dir := prepareTempFile(t)
14
+	defer os.RemoveAll(dir)
15
+
16
+	beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
17
+	unixEpochTime := time.Unix(0, 0)
18
+	afterUnixEpochTime := time.Unix(100, 0)
19
+	// The max Unix time is 33 bits set
20
+	unixMaxTime := unixEpochTime.Add((1<<33 - 1) * time.Second)
21
+	afterUnixMaxTime := unixMaxTime.Add(100 * time.Second)
22
+
23
+	// Test both aTime and mTime set to Unix Epoch
24
+	Chtimes(file, unixEpochTime, unixEpochTime)
25
+
26
+	f, err := os.Stat(file)
27
+	if err != nil {
28
+		t.Fatal(err)
29
+	}
30
+
31
+	stat := f.Sys().(*syscall.Stat_t)
32
+	aTime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
33
+	if aTime != unixEpochTime {
34
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
35
+	}
36
+
37
+	// Test aTime before Unix Epoch and mTime set to Unix Epoch
38
+	Chtimes(file, beforeUnixEpochTime, unixEpochTime)
39
+
40
+	f, err = os.Stat(file)
41
+	if err != nil {
42
+		t.Fatal(err)
43
+	}
44
+
45
+	stat = f.Sys().(*syscall.Stat_t)
46
+	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
47
+	if aTime != unixEpochTime {
48
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
49
+	}
50
+
51
+	// Test aTime set to Unix Epoch and mTime before Unix Epoch
52
+	Chtimes(file, unixEpochTime, beforeUnixEpochTime)
53
+
54
+	f, err = os.Stat(file)
55
+	if err != nil {
56
+		t.Fatal(err)
57
+	}
58
+
59
+	stat = f.Sys().(*syscall.Stat_t)
60
+	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
61
+	if aTime != unixEpochTime {
62
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
63
+	}
64
+
65
+	// Test both aTime and mTime set to after Unix Epoch (valid time)
66
+	Chtimes(file, afterUnixEpochTime, afterUnixEpochTime)
67
+
68
+	f, err = os.Stat(file)
69
+	if err != nil {
70
+		t.Fatal(err)
71
+	}
72
+
73
+	stat = f.Sys().(*syscall.Stat_t)
74
+	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
75
+	if aTime != afterUnixEpochTime {
76
+		t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime)
77
+	}
78
+
79
+	// Test both aTime and mTime set to Unix max time
80
+	Chtimes(file, unixMaxTime, unixMaxTime)
81
+
82
+	f, err = os.Stat(file)
83
+	if err != nil {
84
+		t.Fatal(err)
85
+	}
86
+
87
+	stat = f.Sys().(*syscall.Stat_t)
88
+	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
89
+	if aTime != unixMaxTime {
90
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
91
+	}
92
+
93
+	// Test aTime after Unix max time and mTime set to Unix max time
94
+	Chtimes(file, afterUnixMaxTime, unixMaxTime)
95
+
96
+	f, err = os.Stat(file)
97
+	if err != nil {
98
+		t.Fatal(err)
99
+	}
100
+
101
+	stat = f.Sys().(*syscall.Stat_t)
102
+	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
103
+	if aTime != unixEpochTime {
104
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
105
+	}
106
+
107
+	// Test aTime set to Unix Epoch and mTime before Unix Epoch
108
+	Chtimes(file, unixMaxTime, afterUnixMaxTime)
109
+
110
+	f, err = os.Stat(file)
111
+	if err != nil {
112
+		t.Fatal(err)
113
+	}
114
+
115
+	stat = f.Sys().(*syscall.Stat_t)
116
+	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
117
+	if aTime != unixMaxTime {
118
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
119
+	}
120
+}
0 121
new file mode 100644
... ...
@@ -0,0 +1,114 @@
0
+// +build windows
1
+
2
+package system
3
+
4
+import (
5
+	"os"
6
+	"syscall"
7
+	"testing"
8
+	"time"
9
+)
10
+
11
+// TestChtimes tests Chtimes access time on a tempfile on Windows
12
+func TestChtimesWindows(t *testing.T) {
13
+	file, dir := prepareTempFile(t)
14
+	defer os.RemoveAll(dir)
15
+
16
+	beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
17
+	unixEpochTime := time.Unix(0, 0)
18
+	afterUnixEpochTime := time.Unix(100, 0)
19
+	// The max Unix time is 33 bits set
20
+	unixMaxTime := unixEpochTime.Add((1<<33 - 1) * time.Second)
21
+	afterUnixMaxTime := unixMaxTime.Add(100 * time.Second)
22
+
23
+	// Test both aTime and mTime set to Unix Epoch
24
+	Chtimes(file, unixEpochTime, unixEpochTime)
25
+
26
+	f, err := os.Stat(file)
27
+	if err != nil {
28
+		t.Fatal(err)
29
+	}
30
+
31
+	aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
32
+	if aTime != unixEpochTime {
33
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
34
+	}
35
+
36
+	// Test aTime before Unix Epoch and mTime set to Unix Epoch
37
+	Chtimes(file, beforeUnixEpochTime, unixEpochTime)
38
+
39
+	f, err = os.Stat(file)
40
+	if err != nil {
41
+		t.Fatal(err)
42
+	}
43
+
44
+	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
45
+	if aTime != unixEpochTime {
46
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
47
+	}
48
+
49
+	// Test aTime set to Unix Epoch and mTime before Unix Epoch
50
+	Chtimes(file, unixEpochTime, beforeUnixEpochTime)
51
+
52
+	f, err = os.Stat(file)
53
+	if err != nil {
54
+		t.Fatal(err)
55
+	}
56
+
57
+	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
58
+	if aTime != unixEpochTime {
59
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
60
+	}
61
+
62
+	// Test both aTime and mTime set to after Unix Epoch (valid time)
63
+	Chtimes(file, afterUnixEpochTime, afterUnixEpochTime)
64
+
65
+	f, err = os.Stat(file)
66
+	if err != nil {
67
+		t.Fatal(err)
68
+	}
69
+
70
+	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
71
+	if aTime != afterUnixEpochTime {
72
+		t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime)
73
+	}
74
+
75
+	// Test both aTime and mTime set to Unix max time
76
+	Chtimes(file, unixMaxTime, unixMaxTime)
77
+
78
+	f, err = os.Stat(file)
79
+	if err != nil {
80
+		t.Fatal(err)
81
+	}
82
+
83
+	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
84
+	if aTime != unixMaxTime {
85
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
86
+	}
87
+
88
+	// Test aTime after Unix max time and mTime set to Unix max time
89
+	Chtimes(file, afterUnixMaxTime, unixMaxTime)
90
+
91
+	f, err = os.Stat(file)
92
+	if err != nil {
93
+		t.Fatal(err)
94
+	}
95
+
96
+	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
97
+	if aTime != unixEpochTime {
98
+		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
99
+	}
100
+
101
+	// Test aTime set to Unix Epoch and mTime before Unix Epoch
102
+	Chtimes(file, unixMaxTime, afterUnixMaxTime)
103
+
104
+	f, err = os.Stat(file)
105
+	if err != nil {
106
+		t.Fatal(err)
107
+	}
108
+
109
+	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
110
+	if aTime != unixMaxTime {
111
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
112
+	}
113
+}
0 114
deleted file mode 100644
... ...
@@ -1,28 +0,0 @@
1
-package system
2
-
3
-import (
4
-	"os"
5
-	"testing"
6
-)
7
-
8
-// TestLstat tests Lstat for existing and non existing files
9
-func TestLstat(t *testing.T) {
10
-	file, invalid, _, dir := prepareFiles(t)
11
-	defer os.RemoveAll(dir)
12
-
13
-	statFile, err := Lstat(file)
14
-	if err != nil {
15
-		t.Fatal(err)
16
-	}
17
-	if statFile == nil {
18
-		t.Fatal("returned empty stat for existing file")
19
-	}
20
-
21
-	statInvalid, err := Lstat(invalid)
22
-	if err == nil {
23
-		t.Fatal("did not return error for non-existing file")
24
-	}
25
-	if statInvalid != nil {
26
-		t.Fatal("returned non-nil stat for non-existing file")
27
-	}
28
-}
29 1
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+// +build linux freebsd
1
+
2
+package system
3
+
4
+import (
5
+	"os"
6
+	"testing"
7
+)
8
+
9
+// TestLstat tests Lstat for existing and non existing files
10
+func TestLstat(t *testing.T) {
11
+	file, invalid, _, dir := prepareFiles(t)
12
+	defer os.RemoveAll(dir)
13
+
14
+	statFile, err := Lstat(file)
15
+	if err != nil {
16
+		t.Fatal(err)
17
+	}
18
+	if statFile == nil {
19
+		t.Fatal("returned empty stat for existing file")
20
+	}
21
+
22
+	statInvalid, err := Lstat(invalid)
23
+	if err == nil {
24
+		t.Fatal("did not return error for non-existing file")
25
+	}
26
+	if statInvalid != nil {
27
+		t.Fatal("returned non-nil stat for non-existing file")
28
+	}
29
+}
0 30
deleted file mode 100644
... ...
@@ -1,38 +0,0 @@
1
-package system
2
-
3
-import (
4
-	"strings"
5
-	"testing"
6
-
7
-	"github.com/docker/docker/pkg/units"
8
-)
9
-
10
-// TestMemInfo tests parseMemInfo with a static meminfo string
11
-func TestMemInfo(t *testing.T) {
12
-	const input = `
13
-	MemTotal:      1 kB
14
-	MemFree:       2 kB
15
-	SwapTotal:     3 kB
16
-	SwapFree:      4 kB
17
-	Malformed1:
18
-	Malformed2:    1
19
-	Malformed3:    2 MB
20
-	Malformed4:    X kB
21
-	`
22
-	meminfo, err := parseMemInfo(strings.NewReader(input))
23
-	if err != nil {
24
-		t.Fatal(err)
25
-	}
26
-	if meminfo.MemTotal != 1*units.KiB {
27
-		t.Fatalf("Unexpected MemTotal: %d", meminfo.MemTotal)
28
-	}
29
-	if meminfo.MemFree != 2*units.KiB {
30
-		t.Fatalf("Unexpected MemFree: %d", meminfo.MemFree)
31
-	}
32
-	if meminfo.SwapTotal != 3*units.KiB {
33
-		t.Fatalf("Unexpected SwapTotal: %d", meminfo.SwapTotal)
34
-	}
35
-	if meminfo.SwapFree != 4*units.KiB {
36
-		t.Fatalf("Unexpected SwapFree: %d", meminfo.SwapFree)
37
-	}
38
-}
39 1
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// +build linux freebsd
1
+
2
+package system
3
+
4
+import (
5
+	"strings"
6
+	"testing"
7
+
8
+	"github.com/docker/docker/pkg/units"
9
+)
10
+
11
+// TestMemInfo tests parseMemInfo with a static meminfo string
12
+func TestMemInfo(t *testing.T) {
13
+	const input = `
14
+	MemTotal:      1 kB
15
+	MemFree:       2 kB
16
+	SwapTotal:     3 kB
17
+	SwapFree:      4 kB
18
+	Malformed1:
19
+	Malformed2:    1
20
+	Malformed3:    2 MB
21
+	Malformed4:    X kB
22
+	`
23
+	meminfo, err := parseMemInfo(strings.NewReader(input))
24
+	if err != nil {
25
+		t.Fatal(err)
26
+	}
27
+	if meminfo.MemTotal != 1*units.KiB {
28
+		t.Fatalf("Unexpected MemTotal: %d", meminfo.MemTotal)
29
+	}
30
+	if meminfo.MemFree != 2*units.KiB {
31
+		t.Fatalf("Unexpected MemFree: %d", meminfo.MemFree)
32
+	}
33
+	if meminfo.SwapTotal != 3*units.KiB {
34
+		t.Fatalf("Unexpected SwapTotal: %d", meminfo.SwapTotal)
35
+	}
36
+	if meminfo.SwapFree != 4*units.KiB {
37
+		t.Fatalf("Unexpected SwapFree: %d", meminfo.SwapFree)
38
+	}
39
+}
0 40
deleted file mode 100644
... ...
@@ -1,37 +0,0 @@
1
-package system
2
-
3
-import (
4
-	"os"
5
-	"syscall"
6
-	"testing"
7
-)
8
-
9
-// TestFromStatT tests fromStatT for a tempfile
10
-func TestFromStatT(t *testing.T) {
11
-	file, _, _, dir := prepareFiles(t)
12
-	defer os.RemoveAll(dir)
13
-
14
-	stat := &syscall.Stat_t{}
15
-	err := syscall.Lstat(file, stat)
16
-
17
-	s, err := fromStatT(stat)
18
-	if err != nil {
19
-		t.Fatal(err)
20
-	}
21
-
22
-	if stat.Mode != s.Mode() {
23
-		t.Fatal("got invalid mode")
24
-	}
25
-	if stat.Uid != s.UID() {
26
-		t.Fatal("got invalid uid")
27
-	}
28
-	if stat.Gid != s.Gid() {
29
-		t.Fatal("got invalid gid")
30
-	}
31
-	if stat.Rdev != s.Rdev() {
32
-		t.Fatal("got invalid rdev")
33
-	}
34
-	if stat.Mtim != s.Mtim() {
35
-		t.Fatal("got invalid mtim")
36
-	}
37
-}
38 1
new file mode 100644
... ...
@@ -0,0 +1,39 @@
0
+// +build linux freebsd
1
+
2
+package system
3
+
4
+import (
5
+	"os"
6
+	"syscall"
7
+	"testing"
8
+)
9
+
10
+// TestFromStatT tests fromStatT for a tempfile
11
+func TestFromStatT(t *testing.T) {
12
+	file, _, _, dir := prepareFiles(t)
13
+	defer os.RemoveAll(dir)
14
+
15
+	stat := &syscall.Stat_t{}
16
+	err := syscall.Lstat(file, stat)
17
+
18
+	s, err := fromStatT(stat)
19
+	if err != nil {
20
+		t.Fatal(err)
21
+	}
22
+
23
+	if stat.Mode != s.Mode() {
24
+		t.Fatal("got invalid mode")
25
+	}
26
+	if stat.Uid != s.UID() {
27
+		t.Fatal("got invalid uid")
28
+	}
29
+	if stat.Gid != s.Gid() {
30
+		t.Fatal("got invalid gid")
31
+	}
32
+	if stat.Rdev != s.Rdev() {
33
+		t.Fatal("got invalid rdev")
34
+	}
35
+	if stat.Mtim != s.Mtim() {
36
+		t.Fatal("got invalid mtim")
37
+	}
38
+}
... ...
@@ -6,9 +6,3 @@ import "syscall"
6 6
 func LUtimesNano(path string, ts []syscall.Timespec) error {
7 7
 	return ErrNotSupportedPlatform
8 8
 }
9
-
10
-// UtimesNano is used to change access and modification time of path.
11
-// it can't be used for symbol link file.
12
-func UtimesNano(path string, ts []syscall.Timespec) error {
13
-	return syscall.UtimesNano(path, ts)
14
-}
... ...
@@ -20,9 +20,3 @@ func LUtimesNano(path string, ts []syscall.Timespec) error {
20 20
 
21 21
 	return nil
22 22
 }
23
-
24
-// UtimesNano is used to change access and modification time of the specified path.
25
-// It can't be used for symbol link file.
26
-func UtimesNano(path string, ts []syscall.Timespec) error {
27
-	return syscall.UtimesNano(path, ts)
28
-}
... ...
@@ -24,9 +24,3 @@ func LUtimesNano(path string, ts []syscall.Timespec) error {
24 24
 
25 25
 	return nil
26 26
 }
27
-
28
-// UtimesNano is used to change access and modification time of the specified path.
29
-// It can't be used for symbol link file.
30
-func UtimesNano(path string, ts []syscall.Timespec) error {
31
-	return syscall.UtimesNano(path, ts)
32
-}
33 27
deleted file mode 100644
... ...
@@ -1,66 +0,0 @@
1
-package system
2
-
3
-import (
4
-	"io/ioutil"
5
-	"os"
6
-	"path/filepath"
7
-	"syscall"
8
-	"testing"
9
-)
10
-
11
-// prepareFiles creates files for testing in the temp directory
12
-func prepareFiles(t *testing.T) (string, string, string, string) {
13
-	dir, err := ioutil.TempDir("", "docker-system-test")
14
-	if err != nil {
15
-		t.Fatal(err)
16
-	}
17
-
18
-	file := filepath.Join(dir, "exist")
19
-	if err := ioutil.WriteFile(file, []byte("hello"), 0644); err != nil {
20
-		t.Fatal(err)
21
-	}
22
-
23
-	invalid := filepath.Join(dir, "doesnt-exist")
24
-
25
-	symlink := filepath.Join(dir, "symlink")
26
-	if err := os.Symlink(file, symlink); err != nil {
27
-		t.Fatal(err)
28
-	}
29
-
30
-	return file, invalid, symlink, dir
31
-}
32
-
33
-func TestLUtimesNano(t *testing.T) {
34
-	file, invalid, symlink, dir := prepareFiles(t)
35
-	defer os.RemoveAll(dir)
36
-
37
-	before, err := os.Stat(file)
38
-	if err != nil {
39
-		t.Fatal(err)
40
-	}
41
-
42
-	ts := []syscall.Timespec{{0, 0}, {0, 0}}
43
-	if err := LUtimesNano(symlink, ts); err != nil {
44
-		t.Fatal(err)
45
-	}
46
-
47
-	symlinkInfo, err := os.Lstat(symlink)
48
-	if err != nil {
49
-		t.Fatal(err)
50
-	}
51
-	if before.ModTime().Unix() == symlinkInfo.ModTime().Unix() {
52
-		t.Fatal("The modification time of the symlink should be different")
53
-	}
54
-
55
-	fileInfo, err := os.Stat(file)
56
-	if err != nil {
57
-		t.Fatal(err)
58
-	}
59
-	if before.ModTime().Unix() != fileInfo.ModTime().Unix() {
60
-		t.Fatal("The modification time of the file should be same")
61
-	}
62
-
63
-	if err := LUtimesNano(invalid, ts); err == nil {
64
-		t.Fatal("Doesn't return an error on a non-existing file")
65
-	}
66
-}
67 1
new file mode 100644
... ...
@@ -0,0 +1,68 @@
0
+// +build linux freebsd
1
+
2
+package system
3
+
4
+import (
5
+	"io/ioutil"
6
+	"os"
7
+	"path/filepath"
8
+	"syscall"
9
+	"testing"
10
+)
11
+
12
+// prepareFiles creates files for testing in the temp directory
13
+func prepareFiles(t *testing.T) (string, string, string, string) {
14
+	dir, err := ioutil.TempDir("", "docker-system-test")
15
+	if err != nil {
16
+		t.Fatal(err)
17
+	}
18
+
19
+	file := filepath.Join(dir, "exist")
20
+	if err := ioutil.WriteFile(file, []byte("hello"), 0644); err != nil {
21
+		t.Fatal(err)
22
+	}
23
+
24
+	invalid := filepath.Join(dir, "doesnt-exist")
25
+
26
+	symlink := filepath.Join(dir, "symlink")
27
+	if err := os.Symlink(file, symlink); err != nil {
28
+		t.Fatal(err)
29
+	}
30
+
31
+	return file, invalid, symlink, dir
32
+}
33
+
34
+func TestLUtimesNano(t *testing.T) {
35
+	file, invalid, symlink, dir := prepareFiles(t)
36
+	defer os.RemoveAll(dir)
37
+
38
+	before, err := os.Stat(file)
39
+	if err != nil {
40
+		t.Fatal(err)
41
+	}
42
+
43
+	ts := []syscall.Timespec{{0, 0}, {0, 0}}
44
+	if err := LUtimesNano(symlink, ts); err != nil {
45
+		t.Fatal(err)
46
+	}
47
+
48
+	symlinkInfo, err := os.Lstat(symlink)
49
+	if err != nil {
50
+		t.Fatal(err)
51
+	}
52
+	if before.ModTime().Unix() == symlinkInfo.ModTime().Unix() {
53
+		t.Fatal("The modification time of the symlink should be different")
54
+	}
55
+
56
+	fileInfo, err := os.Stat(file)
57
+	if err != nil {
58
+		t.Fatal(err)
59
+	}
60
+	if before.ModTime().Unix() != fileInfo.ModTime().Unix() {
61
+		t.Fatal("The modification time of the file should be same")
62
+	}
63
+
64
+	if err := LUtimesNano(invalid, ts); err == nil {
65
+		t.Fatal("Doesn't return an error on a non-existing file")
66
+	}
67
+}
... ...
@@ -8,8 +8,3 @@ import "syscall"
8 8
 func LUtimesNano(path string, ts []syscall.Timespec) error {
9 9
 	return ErrNotSupportedPlatform
10 10
 }
11
-
12
-// UtimesNano is not supported on platforms other than linux, freebsd and darwin.
13
-func UtimesNano(path string, ts []syscall.Timespec) error {
14
-	return ErrNotSupportedPlatform
15
-}