Browse code

This fixes Chtimes on systems with 32 bit Timespec

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

Darren Stahl authored on 2015/11/04 07:49:50
Showing 4 changed files
... ...
@@ -2,14 +2,30 @@ package system
2 2
 
3 3
 import (
4 4
 	"os"
5
+	"syscall"
5 6
 	"time"
7
+	"unsafe"
6 8
 )
7 9
 
10
+var (
11
+	maxTime time.Time
12
+)
13
+
14
+func init() {
15
+	if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 {
16
+		// This is a 64 bit timespec
17
+		// os.Chtimes limits time to the following
18
+		maxTime = time.Unix(0, 1<<63-1)
19
+	} else {
20
+		// This is a 32 bit timespec
21
+		maxTime = time.Unix(1<<31-1, 0)
22
+	}
23
+}
24
+
8 25
 // Chtimes changes the access time and modified time of a file at the given path
9 26
 func Chtimes(name string, atime time.Time, mtime time.Time) error {
10 27
 	unixMinTime := time.Unix(0, 0)
11
-	// The max Unix time is 33 bits set
12
-	unixMaxTime := unixMinTime.Add((1<<33 - 1) * time.Second)
28
+	unixMaxTime := maxTime
13 29
 
14 30
 	// If the modified time is prior to the Unix Epoch, or after the
15 31
 	// end of Unix Time, os.Chtimes has undefined behavior
... ...
@@ -30,9 +30,7 @@ func TestChtimes(t *testing.T) {
30 30
 	beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
31 31
 	unixEpochTime := time.Unix(0, 0)
32 32
 	afterUnixEpochTime := time.Unix(100, 0)
33
-	// The max Unix time is 33 bits set
34
-	unixMaxTime := unixEpochTime.Add((1<<33 - 1) * time.Second)
35
-	afterUnixMaxTime := unixMaxTime.Add(100 * time.Second)
33
+	unixMaxTime := maxTime
36 34
 
37 35
 	// Test both aTime and mTime set to Unix Epoch
38 36
 	Chtimes(file, unixEpochTime, unixEpochTime)
... ...
@@ -90,31 +88,7 @@ func TestChtimes(t *testing.T) {
90 90
 		t.Fatal(err)
91 91
 	}
92 92
 
93
-	if f.ModTime() != unixMaxTime {
94
-		t.Fatalf("Expected: %s, got: %s", unixMaxTime, f.ModTime())
95
-	}
96
-
97
-	// Test aTime after Unix max time and mTime set to Unix max time
98
-	Chtimes(file, afterUnixMaxTime, unixMaxTime)
99
-
100
-	f, err = os.Stat(file)
101
-	if err != nil {
102
-		t.Fatal(err)
103
-	}
104
-
105
-	if f.ModTime() != unixMaxTime {
106
-		t.Fatalf("Expected: %s, got: %s", unixMaxTime, f.ModTime())
107
-	}
108
-
109
-	// Test aTime set to Unix Epoch and mTime before Unix Epoch
110
-	Chtimes(file, unixMaxTime, afterUnixMaxTime)
111
-
112
-	f, err = os.Stat(file)
113
-	if err != nil {
114
-		t.Fatal(err)
115
-	}
116
-
117
-	if f.ModTime() != unixEpochTime {
118
-		t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
93
+	if f.ModTime().Truncate(time.Second) != unixMaxTime.Truncate(time.Second) {
94
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), f.ModTime().Truncate(time.Second))
119 95
 	}
120 96
 }
... ...
@@ -17,9 +17,7 @@ func TestChtimesLinux(t *testing.T) {
17 17
 	beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
18 18
 	unixEpochTime := time.Unix(0, 0)
19 19
 	afterUnixEpochTime := time.Unix(100, 0)
20
-	// The max Unix time is 33 bits set
21
-	unixMaxTime := unixEpochTime.Add((1<<33 - 1) * time.Second)
22
-	afterUnixMaxTime := unixMaxTime.Add(100 * time.Second)
20
+	unixMaxTime := maxTime
23 21
 
24 22
 	// Test both aTime and mTime set to Unix Epoch
25 23
 	Chtimes(file, unixEpochTime, unixEpochTime)
... ...
@@ -87,35 +85,7 @@ func TestChtimesLinux(t *testing.T) {
87 87
 
88 88
 	stat = f.Sys().(*syscall.Stat_t)
89 89
 	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
90
-	if aTime != unixMaxTime {
91
-		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
92
-	}
93
-
94
-	// Test aTime after Unix max time and mTime set to Unix max time
95
-	Chtimes(file, afterUnixMaxTime, unixMaxTime)
96
-
97
-	f, err = os.Stat(file)
98
-	if err != nil {
99
-		t.Fatal(err)
100
-	}
101
-
102
-	stat = f.Sys().(*syscall.Stat_t)
103
-	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
104
-	if aTime != unixEpochTime {
105
-		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
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
-	stat = f.Sys().(*syscall.Stat_t)
117
-	aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
118
-	if aTime != unixMaxTime {
119
-		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
90
+	if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) {
91
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second))
120 92
 	}
121 93
 }
... ...
@@ -17,9 +17,7 @@ func TestChtimesWindows(t *testing.T) {
17 17
 	beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
18 18
 	unixEpochTime := time.Unix(0, 0)
19 19
 	afterUnixEpochTime := time.Unix(100, 0)
20
-	// The max Unix time is 33 bits set
21
-	unixMaxTime := unixEpochTime.Add((1<<33 - 1) * time.Second)
22
-	afterUnixMaxTime := unixMaxTime.Add(100 * time.Second)
20
+	unixMaxTime := maxTime
23 21
 
24 22
 	// Test both aTime and mTime set to Unix Epoch
25 23
 	Chtimes(file, unixEpochTime, unixEpochTime)
... ...
@@ -82,33 +80,7 @@ func TestChtimesWindows(t *testing.T) {
82 82
 	}
83 83
 
84 84
 	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
85
-	if aTime != unixMaxTime {
86
-		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
87
-	}
88
-
89
-	// Test aTime after Unix max time and mTime set to Unix max time
90
-	Chtimes(file, afterUnixMaxTime, unixMaxTime)
91
-
92
-	f, err = os.Stat(file)
93
-	if err != nil {
94
-		t.Fatal(err)
95
-	}
96
-
97
-	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
98
-	if aTime != unixEpochTime {
99
-		t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
100
-	}
101
-
102
-	// Test aTime set to Unix Epoch and mTime before Unix Epoch
103
-	Chtimes(file, unixMaxTime, afterUnixMaxTime)
104
-
105
-	f, err = os.Stat(file)
106
-	if err != nil {
107
-		t.Fatal(err)
108
-	}
109
-
110
-	aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
111
-	if aTime != unixMaxTime {
112
-		t.Fatalf("Expected: %s, got: %s", unixMaxTime, aTime)
85
+	if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) {
86
+		t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second))
113 87
 	}
114 88
 }