1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /*++ |
6 | |
7 | |
8 | |
9 | Module Name: |
10 | |
11 | filetime.cpp |
12 | |
13 | Abstract: |
14 | |
15 | Implementation of the file WIN API related to file time. |
16 | |
17 | Notes: |
18 | |
19 | One very important thing to note is that on BSD systems, the stat structure |
20 | stores nanoseconds for the time-related fields. This is implemented by |
21 | replacing the time_t fields st_atime, st_mtime, and st_ctime by timespec |
22 | structures, instead named st_atimespec, st_mtimespec, and st_ctimespec. |
23 | |
24 | However, if _POSIX_SOURCE is defined, the fields are time_t values and use |
25 | their POSIX names. For compatibility purposes, when _POSIX_SOURCE is NOT |
26 | defined, the time-related fields are defined in sys/stat.h as: |
27 | |
28 | #ifndef _POSIX_SOURCE |
29 | #define st_atime st_atimespec.tv_sec |
30 | #define st_mtime st_mtimespec.tv_sec |
31 | #define st_ctime st_ctimespec.tv_sec |
32 | #endif |
33 | |
34 | Furthermore, if _POSIX_SOURCE is defined, the structure still has |
35 | additional fields for nanoseconds, named st_atimensec, st_mtimensec, and |
36 | st_ctimensec. |
37 | |
38 | In the PAL, there is a configure check to see if the system supports |
39 | nanoseconds for the time-related fields. This source file also sets macros |
40 | so that STAT_ATIME_NSEC etc. will always refer to the appropriate field |
41 | if it exists, and are defined as 0 otherwise. |
42 | |
43 | -- |
44 | |
45 | Also note that there is no analog to "creation time" on Linux systems. |
46 | Instead, we use the inode change time, which is set to the current time |
47 | whenever mtime changes or when chmod, chown, etc. syscalls modify the |
48 | file status; or mtime if older. Ideally we would use birthtime when |
49 | available. |
50 | |
51 | |
52 | --*/ |
53 | |
54 | #include "pal/corunix.hpp" |
55 | #include "pal/dbgmsg.h" |
56 | #include "pal/filetime.h" |
57 | #include "pal/thread.hpp" |
58 | #include "pal/file.hpp" |
59 | |
60 | #include <sys/types.h> |
61 | #include <sys/stat.h> |
62 | #include <utime.h> |
63 | #include <time.h> |
64 | |
65 | #if HAVE_SYS_TIME_H |
66 | #include <sys/time.h> |
67 | #endif // HAVE_SYS_TIME_H |
68 | |
69 | using namespace CorUnix; |
70 | |
71 | SET_DEFAULT_DEBUG_CHANNEL(FILE); |
72 | |
73 | // In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable |
74 | // defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement |
75 | // should be placed after the SET_DEFAULT_DEBUG_CHANNEL(FILE) |
76 | #include <safemath.h> |
77 | |
78 | /* Magic number explanation: |
79 | |
80 | To 1970: |
81 | Both epochs are Gregorian. 1970 - 1601 = 369. Assuming a leap |
82 | year every four years, 369 / 4 = 92. However, 1700, 1800, and 1900 |
83 | were NOT leap years, so 89 leap years, 280 non-leap years. |
84 | 89 * 366 + 280 * 365 = 134774 days between epochs. Of course |
85 | 60 * 60 * 24 = 86400 seconds per day, so 134774 * 86400 = |
86 | 11644473600 = SECS_BETWEEN_1601_AND_1970_EPOCHS. |
87 | |
88 | To 2001: |
89 | Again, both epochs are Gregorian. 2001 - 1601 = 400. Assuming a leap |
90 | year every four years, 400 / 4 = 100. However, 1700, 1800, and 1900 |
91 | were NOT leap years (2000 was because it was divisible by 400), so |
92 | 97 leap years, 303 non-leap years. |
93 | 97 * 366 + 303 * 365 = 146097 days between epochs. 146097 * 86400 = |
94 | 12622780800 = SECS_BETWEEN_1601_AND_2001_EPOCHS. |
95 | |
96 | This result is also confirmed in the MSDN documentation on how |
97 | to convert a time_t value to a win32 FILETIME. |
98 | */ |
99 | static const __int64 SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL; |
100 | static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */ |
101 | |
102 | #ifdef __APPLE__ |
103 | static const __int64 SECS_BETWEEN_1601_AND_2001_EPOCHS = 12622780800LL; |
104 | #endif // __APPLE__ |
105 | |
106 | /*++ |
107 | Function: |
108 | CompareFileTime |
109 | |
110 | See MSDN doc. |
111 | --*/ |
112 | LONG |
113 | PALAPI |
114 | CompareFileTime( |
115 | IN CONST FILETIME *lpFileTime1, |
116 | IN CONST FILETIME *lpFileTime2) |
117 | { |
118 | __int64 First; |
119 | __int64 Second; |
120 | |
121 | long Ret; |
122 | |
123 | PERF_ENTRY(CompareFileTime); |
124 | ENTRY("CompareFileTime(lpFileTime1=%p lpFileTime2=%p)\n" , |
125 | lpFileTime1, lpFileTime2); |
126 | |
127 | First = ((__int64)lpFileTime1->dwHighDateTime << 32) + |
128 | lpFileTime1->dwLowDateTime; |
129 | Second = ((__int64)lpFileTime2->dwHighDateTime << 32) + |
130 | lpFileTime2->dwLowDateTime; |
131 | |
132 | if ( First < Second ) |
133 | { |
134 | Ret = -1; |
135 | } |
136 | else if ( First > Second ) |
137 | { |
138 | Ret = 1; |
139 | } |
140 | else |
141 | { |
142 | Ret = 0; |
143 | } |
144 | |
145 | LOGEXIT("CompareFileTime returns LONG %ld\n" , Ret); |
146 | PERF_EXIT(CompareFileTime); |
147 | return Ret; |
148 | } |
149 | |
150 | |
151 | /*++ |
152 | Function: |
153 | GetSystemTimeAsFileTime |
154 | |
155 | See MSDN doc. |
156 | --*/ |
157 | VOID |
158 | PALAPI |
159 | GetSystemTimeAsFileTime( |
160 | OUT LPFILETIME lpSystemTimeAsFileTime) |
161 | { |
162 | PERF_ENTRY(GetSystemTimeAsFileTime); |
163 | ENTRY("GetSystemTimeAsFileTime(lpSystemTimeAsFileTime=%p)\n" , |
164 | lpSystemTimeAsFileTime); |
165 | |
166 | #if HAVE_WORKING_CLOCK_GETTIME |
167 | struct timespec Time; |
168 | if (clock_gettime(CLOCK_REALTIME, &Time) == 0) |
169 | { |
170 | *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( Time.tv_sec, Time.tv_nsec ); |
171 | } |
172 | #else |
173 | struct timeval Time; |
174 | if (gettimeofday(&Time, NULL) == 0) |
175 | { |
176 | /* use (tv_usec * 1000) because 2nd arg is in nanoseconds */ |
177 | *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( Time.tv_sec, Time.tv_usec * 1000); |
178 | } |
179 | #endif |
180 | else |
181 | { |
182 | /* no way to indicate failure, so set time to zero */ |
183 | ASSERT("clock_gettime or gettimeofday failed" ); |
184 | *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( 0, 0 ); |
185 | } |
186 | |
187 | LOGEXIT("GetSystemTimeAsFileTime returns.\n" ); |
188 | PERF_EXIT(GetSystemTimeAsFileTime); |
189 | } |
190 | |
191 | |
192 | #ifdef __APPLE__ |
193 | /*++ |
194 | Function: |
195 | FILECFAbsoluteTimeToFileTime |
196 | |
197 | Convert a CFAbsoluteTime value to a win32 FILETIME structure, as described |
198 | in MSDN documentation. CFAbsoluteTime is the number of seconds elapsed since |
199 | 00:00 01 January 2001 UTC (Mac OS X epoch), while FILETIME represents a |
200 | 64-bit number of 100-nanosecond intervals that have passed since 00:00 |
201 | 01 January 1601 UTC (win32 epoch). |
202 | --*/ |
203 | FILETIME FILECFAbsoluteTimeToFileTime( CFAbsoluteTime sec ) |
204 | { |
205 | __int64 Result; |
206 | FILETIME Ret; |
207 | |
208 | Result = ((__int64)sec + SECS_BETWEEN_1601_AND_2001_EPOCHS) * SECS_TO_100NS; |
209 | |
210 | Ret.dwLowDateTime = (DWORD)Result; |
211 | Ret.dwHighDateTime = (DWORD)(Result >> 32); |
212 | |
213 | TRACE("CFAbsoluteTime = [%9f] converts to Win32 FILETIME = [%#x:%#x]\n" , |
214 | sec, Ret.dwHighDateTime, Ret.dwLowDateTime); |
215 | |
216 | return Ret; |
217 | } |
218 | #endif // __APPLE__ |
219 | |
220 | |
221 | /*++ |
222 | Function: |
223 | FILEUnixTimeToFileTime |
224 | |
225 | Convert a time_t value to a win32 FILETIME structure, as described in |
226 | MSDN documentation. time_t is the number of seconds elapsed since |
227 | 00:00 01 January 1970 UTC (Unix epoch), while FILETIME represents a |
228 | 64-bit number of 100-nanosecond intervals that have passed since 00:00 |
229 | 01 January 1601 UTC (win32 epoch). |
230 | --*/ |
231 | FILETIME FILEUnixTimeToFileTime( time_t sec, long nsec ) |
232 | { |
233 | __int64 Result; |
234 | FILETIME Ret; |
235 | |
236 | Result = ((__int64)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS + |
237 | (nsec / 100); |
238 | |
239 | Ret.dwLowDateTime = (DWORD)Result; |
240 | Ret.dwHighDateTime = (DWORD)(Result >> 32); |
241 | |
242 | TRACE("Unix time = [%ld.%09ld] converts to Win32 FILETIME = [%#x:%#x]\n" , |
243 | sec, nsec, Ret.dwHighDateTime, Ret.dwLowDateTime); |
244 | |
245 | return Ret; |
246 | } |
247 | |
248 | |
249 | /*++ |
250 | Function: |
251 | FILEFileTimeToUnixTime |
252 | |
253 | See FILEUnixTimeToFileTime above. |
254 | |
255 | This function takes a win32 FILETIME structures, returns the equivalent |
256 | time_t value, and, if the nsec parameter is non-null, also returns the |
257 | nanoseconds. |
258 | |
259 | NOTE: a 32-bit time_t is only capable of representing dates between |
260 | 13 December 1901 and 19 January 2038. This function will calculate the |
261 | number of seconds (positive or negative) since the Unix epoch, however if |
262 | this value is outside of the range of 32-bit numbers, the result will be |
263 | truncated on systems with a 32-bit time_t. |
264 | --*/ |
265 | time_t FILEFileTimeToUnixTime( FILETIME FileTime, long *nsec ) |
266 | { |
267 | __int64 UnixTime; |
268 | |
269 | /* get the full win32 value, in 100ns */ |
270 | UnixTime = ((__int64)FileTime.dwHighDateTime << 32) + |
271 | FileTime.dwLowDateTime; |
272 | |
273 | /* convert to the Unix epoch */ |
274 | UnixTime -= (SECS_BETWEEN_1601_AND_1970_EPOCHS * SECS_TO_100NS); |
275 | |
276 | TRACE("nsec=%p\n" , nsec); |
277 | |
278 | if ( nsec ) |
279 | { |
280 | /* get the number of 100ns, convert to ns */ |
281 | *nsec = (UnixTime % SECS_TO_100NS) * 100; |
282 | } |
283 | |
284 | UnixTime /= SECS_TO_100NS; /* now convert to seconds */ |
285 | |
286 | if ( (time_t)UnixTime != UnixTime ) |
287 | { |
288 | WARN("Resulting value is too big for a time_t value\n" ); |
289 | } |
290 | |
291 | TRACE("Win32 FILETIME = [%#x:%#x] converts to Unix time = [%ld.%09ld]\n" , |
292 | FileTime.dwHighDateTime, FileTime.dwLowDateTime ,(long) UnixTime, |
293 | nsec?*nsec:0L); |
294 | |
295 | return (time_t)UnixTime; |
296 | } |
297 | |
298 | |
299 | |
300 | /** |
301 | Function |
302 | |
303 | FileTimeToSystemTime() |
304 | |
305 | Helper function for FileTimeToDosTime. |
306 | Converts the necessary file time attibutes to system time, for |
307 | easier manipulation in FileTimeToDosTime. |
308 | |
309 | --*/ |
310 | BOOL PALAPI FileTimeToSystemTime( CONST FILETIME * lpFileTime, |
311 | LPSYSTEMTIME lpSystemTime ) |
312 | { |
313 | UINT64 FileTime = 0; |
314 | time_t UnixFileTime = 0; |
315 | struct tm * UnixSystemTime = 0; |
316 | |
317 | /* Combine the file time. */ |
318 | FileTime = lpFileTime->dwHighDateTime; |
319 | FileTime <<= 32; |
320 | FileTime |= (UINT)lpFileTime->dwLowDateTime; |
321 | bool isSafe = ClrSafeInt<UINT64>::subtraction( |
322 | FileTime, |
323 | SECS_BETWEEN_1601_AND_1970_EPOCHS * SECS_TO_100NS, |
324 | FileTime); |
325 | |
326 | if (isSafe == true) |
327 | { |
328 | #if HAVE_GMTIME_R |
329 | struct tm timeBuf; |
330 | #endif /* HAVE_GMTIME_R */ |
331 | /* Convert file time to unix time. */ |
332 | if (((INT64)FileTime) < 0) |
333 | { |
334 | UnixFileTime = -1 - ( ( -FileTime - 1 ) / 10000000 ); |
335 | } |
336 | else |
337 | { |
338 | UnixFileTime = FileTime / 10000000; |
339 | } |
340 | |
341 | /* Convert unix file time to Unix System time. */ |
342 | #if HAVE_GMTIME_R |
343 | UnixSystemTime = gmtime_r( &UnixFileTime, &timeBuf ); |
344 | #else /* HAVE_GMTIME_R */ |
345 | UnixSystemTime = gmtime( &UnixFileTime ); |
346 | #endif /* HAVE_GMTIME_R */ |
347 | |
348 | /* Convert unix system time to Windows system time. */ |
349 | lpSystemTime->wDay = UnixSystemTime->tm_mday; |
350 | |
351 | /* Unix time counts January as a 0, under Windows it is 1*/ |
352 | lpSystemTime->wMonth = UnixSystemTime->tm_mon + 1; |
353 | /* Unix time returns the year - 1900, Windows returns the current year*/ |
354 | lpSystemTime->wYear = UnixSystemTime->tm_year + 1900; |
355 | |
356 | lpSystemTime->wSecond = UnixSystemTime->tm_sec; |
357 | lpSystemTime->wMinute = UnixSystemTime->tm_min; |
358 | lpSystemTime->wHour = UnixSystemTime->tm_hour; |
359 | return TRUE; |
360 | } |
361 | else |
362 | { |
363 | ERROR( "The file time is to large.\n" ); |
364 | SetLastError(ERROR_INVALID_PARAMETER); |
365 | return FALSE; |
366 | } |
367 | } |
368 | |
369 | |