Signed-off-by: Darren Stahl <darst@microsoft.com>
Darren Stahl authored on 2015/10/02 02:45:32... | ... |
@@ -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 |
-} |