Fixed file modified time not changing on windows
| ... | ... |
@@ -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" |
| ... | ... |
@@ -342,23 +341,19 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri |
| 342 | 342 |
|
| 343 | 343 |
// Set the mtime to the Last-Modified header value if present |
| 344 | 344 |
// Otherwise just remove atime and mtime |
| 345 |
- times := make([]syscall.Timespec, 2) |
|
| 345 |
+ mTime := time.Time{}
|
|
| 346 | 346 |
|
| 347 | 347 |
lastMod := resp.Header.Get("Last-Modified")
|
| 348 | 348 |
if lastMod != "" {
|
| 349 |
- mTime, err := http.ParseTime(lastMod) |
|
| 350 | 349 |
// If we can't parse it then just let it default to 'zero' |
| 351 | 350 |
// otherwise use the parsed time value |
| 352 |
- if err == nil {
|
|
| 353 |
- times[1] = syscall.NsecToTimespec(mTime.UnixNano()) |
|
| 351 |
+ if parsedMTime, err := http.ParseTime(lastMod); err == nil {
|
|
| 352 |
+ mTime = parsedMTime |
|
| 354 | 353 |
} |
| 355 | 354 |
} |
| 356 | 355 |
|
| 357 |
- // Windows does not support UtimesNano. |
|
| 358 |
- if runtime.GOOS != "windows" {
|
|
| 359 |
- if err := system.UtimesNano(tmpFileName, times); err != nil {
|
|
| 360 |
- return err |
|
| 361 |
- } |
|
| 356 |
+ if err := system.Chtimes(tmpFileName, time.Time{}, mTime); err != nil {
|
|
| 357 |
+ return err |
|
| 362 | 358 |
} |
| 363 | 359 |
|
| 364 | 360 |
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" |
| ... | ... |
@@ -184,8 +183,7 @@ func UnpackLayer(dest string, layer Reader) (size int64, err error) {
|
| 184 | 184 |
|
| 185 | 185 |
for _, hdr := range dirs {
|
| 186 | 186 |
path := filepath.Join(dest, hdr.Name) |
| 187 |
- ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
|
|
| 188 |
- if err := syscall.UtimesNano(path, ts); err != nil {
|
|
| 187 |
+ if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
|
| 189 | 188 |
return 0, err |
| 190 | 189 |
} |
| 191 | 190 |
} |
| 192 | 191 |
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 |
-} |