/src/samba/source3/lib/time.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | time handling functions |
4 | | |
5 | | Copyright (C) Andrew Tridgell 1992-2004 |
6 | | Copyright (C) Stefan (metze) Metzmacher 2002 |
7 | | Copyright (C) Jeremy Allison 2007 |
8 | | |
9 | | This program is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation; either version 3 of the License, or |
12 | | (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include "includes.h" |
24 | | |
25 | | /** |
26 | | * @file |
27 | | * @brief time handling functions |
28 | | */ |
29 | | |
30 | | |
31 | 0 | #define NTTIME_INFINITY (NTTIME)0x8000000000000000LL |
32 | | |
33 | | #define TIME_FIXUP_CONSTANT_INT INT64_C(11644473600) |
34 | | |
35 | | /************************************************************** |
36 | | Handle conversions between time_t and uint32, taking care to |
37 | | preserve the "special" values. |
38 | | **************************************************************/ |
39 | | |
40 | | uint32_t convert_time_t_to_uint32_t(time_t t) |
41 | 0 | { |
42 | 0 | #if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8)) |
43 | | /* time_t is 64-bit. */ |
44 | 0 | if (t == 0x8000000000000000LL) { |
45 | 0 | return 0x80000000; |
46 | 0 | } else if (t == 0x7FFFFFFFFFFFFFFFLL) { |
47 | 0 | return 0x7FFFFFFF; |
48 | 0 | } |
49 | 0 | #endif |
50 | 0 | return (uint32_t)t; |
51 | 0 | } |
52 | | |
53 | | time_t convert_uint32_t_to_time_t(uint32_t u) |
54 | 0 | { |
55 | 0 | #if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8)) |
56 | | /* time_t is 64-bit. */ |
57 | 0 | if (u == 0x80000000) { |
58 | 0 | return (time_t)0x8000000000000000LL; |
59 | 0 | } else if (u == 0x7FFFFFFF) { |
60 | 0 | return (time_t)0x7FFFFFFFFFFFFFFFLL; |
61 | 0 | } |
62 | 0 | #endif |
63 | 0 | return (time_t)u; |
64 | 0 | } |
65 | | |
66 | | /**************************************************************************** |
67 | | Check if NTTIME is 0. |
68 | | ****************************************************************************/ |
69 | | |
70 | | bool nt_time_is_zero(const NTTIME *nt) |
71 | 0 | { |
72 | 0 | return (*nt == 0); |
73 | 0 | } |
74 | | |
75 | | /**************************************************************************** |
76 | | Convert ASN.1 GeneralizedTime string to unix-time. |
77 | | Returns 0 on failure; Currently ignores timezone. |
78 | | ****************************************************************************/ |
79 | | |
80 | | time_t generalized_to_unix_time(const char *str) |
81 | 0 | { |
82 | 0 | struct tm tm; |
83 | |
|
84 | 0 | ZERO_STRUCT(tm); |
85 | |
|
86 | 0 | if (sscanf(str, "%4d%2d%2d%2d%2d%2d", |
87 | 0 | &tm.tm_year, &tm.tm_mon, &tm.tm_mday, |
88 | 0 | &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { |
89 | 0 | return 0; |
90 | 0 | } |
91 | 0 | tm.tm_year -= 1900; |
92 | 0 | tm.tm_mon -= 1; |
93 | |
|
94 | 0 | return timegm(&tm); |
95 | 0 | } |
96 | | |
97 | | /******************************************************************* |
98 | | Accessor function for the server time zone offset. |
99 | | set_server_zone_offset() must have been called first. |
100 | | ******************************************************************/ |
101 | | |
102 | | static int server_zone_offset; |
103 | | |
104 | | int get_server_zone_offset(void) |
105 | 0 | { |
106 | 0 | return server_zone_offset; |
107 | 0 | } |
108 | | |
109 | | /******************************************************************* |
110 | | Initialize the server time zone offset. Called when a client connects. |
111 | | ******************************************************************/ |
112 | | |
113 | | int set_server_zone_offset(time_t t) |
114 | 0 | { |
115 | 0 | server_zone_offset = get_time_zone(t); |
116 | 0 | return server_zone_offset; |
117 | 0 | } |
118 | | |
119 | | /*************************************************************************** |
120 | | Server versions of the above functions. |
121 | | ***************************************************************************/ |
122 | | |
123 | | void srv_put_dos_date(char *buf,int offset,time_t unixdate) |
124 | 0 | { |
125 | 0 | push_dos_date((uint8_t *)buf, offset, unixdate, server_zone_offset); |
126 | 0 | } |
127 | | |
128 | | void srv_put_dos_date2_ts(char *buf, int offset, struct timespec unix_ts) |
129 | 0 | { |
130 | 0 | time_t unixdate = convert_timespec_to_time_t(unix_ts); |
131 | 0 | push_dos_date2((uint8_t *)buf, offset, unixdate, server_zone_offset); |
132 | 0 | } |
133 | | |
134 | | void srv_put_dos_date3(char *buf,int offset,time_t unixdate) |
135 | 0 | { |
136 | 0 | push_dos_date3((uint8_t *)buf, offset, unixdate, server_zone_offset); |
137 | 0 | } |
138 | | |
139 | | void round_timespec(enum timestamp_set_resolution res, struct timespec *ts) |
140 | 0 | { |
141 | 0 | if (is_omit_timespec(ts)) { |
142 | 0 | return; |
143 | 0 | } |
144 | | |
145 | 0 | switch (res) { |
146 | 0 | case TIMESTAMP_SET_SECONDS: |
147 | 0 | round_timespec_to_sec(ts); |
148 | 0 | break; |
149 | 0 | case TIMESTAMP_SET_MSEC: |
150 | 0 | round_timespec_to_usec(ts); |
151 | 0 | break; |
152 | 0 | case TIMESTAMP_SET_NT_OR_BETTER: |
153 | | /* No rounding needed. */ |
154 | 0 | break; |
155 | 0 | } |
156 | 0 | } |
157 | | |
158 | | /**************************************************************************** |
159 | | Take a Unix time and convert to an NTTIME structure and place in buffer |
160 | | pointed to by p, rounded to the correct resolution. |
161 | | ****************************************************************************/ |
162 | | |
163 | | void put_long_date_timespec(enum timestamp_set_resolution res, char *p, struct timespec ts) |
164 | 0 | { |
165 | 0 | NTTIME nt; |
166 | 0 | round_timespec(res, &ts); |
167 | 0 | nt = unix_timespec_to_nt_time(ts); |
168 | 0 | SBVAL(p, 0, nt); |
169 | 0 | } |
170 | | |
171 | | void put_long_date_full_timespec(enum timestamp_set_resolution res, |
172 | | char *p, |
173 | | const struct timespec *_ts) |
174 | 0 | { |
175 | 0 | struct timespec ts = *_ts; |
176 | 0 | NTTIME nt; |
177 | |
|
178 | 0 | round_timespec(res, &ts); |
179 | 0 | nt = full_timespec_to_nt_time(&ts); |
180 | 0 | SBVAL(p, 0, nt); |
181 | 0 | } |
182 | | |
183 | | struct timespec pull_long_date_full_timespec(const char *p) |
184 | 0 | { |
185 | 0 | NTTIME nt = BVAL(p, 0); |
186 | |
|
187 | 0 | return nt_time_to_full_timespec(nt); |
188 | 0 | } |
189 | | |
190 | | void put_long_date(char *p, time_t t) |
191 | 0 | { |
192 | 0 | struct timespec ts; |
193 | 0 | ts.tv_sec = t; |
194 | 0 | ts.tv_nsec = 0; |
195 | 0 | put_long_date_timespec(TIMESTAMP_SET_SECONDS, p, ts); |
196 | 0 | } |
197 | | |
198 | | void dos_filetime_timespec(struct timespec *tsp) |
199 | 0 | { |
200 | 0 | tsp->tv_sec &= ~1; |
201 | 0 | tsp->tv_nsec = 0; |
202 | 0 | } |
203 | | |
204 | | /******************************************************************* |
205 | | Create a unix date (int GMT) from a dos date (which is actually in |
206 | | localtime). |
207 | | ********************************************************************/ |
208 | | |
209 | | time_t make_unix_date(const void *date_ptr, int zone_offset) |
210 | 0 | { |
211 | 0 | return pull_dos_date(date_ptr, zone_offset); |
212 | 0 | } |
213 | | |
214 | | /******************************************************************* |
215 | | Like make_unix_date() but the words are reversed. |
216 | | ********************************************************************/ |
217 | | |
218 | | time_t make_unix_date2(const void *date_ptr, int zone_offset) |
219 | 0 | { |
220 | 0 | return pull_dos_date2(date_ptr, zone_offset); |
221 | 0 | } |
222 | | |
223 | | /******************************************************************* |
224 | | Create a unix GMT date from a dos date in 32 bit "unix like" format |
225 | | these generally arrive as localtimes, with corresponding DST. |
226 | | ******************************************************************/ |
227 | | |
228 | | time_t make_unix_date3(const void *date_ptr, int zone_offset) |
229 | 0 | { |
230 | 0 | return pull_dos_date3(date_ptr, zone_offset); |
231 | 0 | } |
232 | | |
233 | | time_t srv_make_unix_date(const void *date_ptr) |
234 | 0 | { |
235 | 0 | return make_unix_date(date_ptr, server_zone_offset); |
236 | 0 | } |
237 | | |
238 | | time_t srv_make_unix_date2(const void *date_ptr) |
239 | 0 | { |
240 | 0 | return make_unix_date2(date_ptr, server_zone_offset); |
241 | 0 | } |
242 | | |
243 | | time_t srv_make_unix_date3(const void *date_ptr) |
244 | 0 | { |
245 | 0 | return make_unix_date3(date_ptr, server_zone_offset); |
246 | 0 | } |
247 | | |
248 | | /**************************************************************************** |
249 | | Interprets an nt time into a unix struct timespec. |
250 | | Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff |
251 | | will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case. |
252 | | ****************************************************************************/ |
253 | | |
254 | | struct timespec interpret_long_date(NTTIME nt) |
255 | 0 | { |
256 | 0 | if (nt == (uint64_t)-1) { |
257 | 0 | struct timespec ret; |
258 | 0 | ret.tv_sec = (time_t)-1; |
259 | 0 | ret.tv_nsec = 0; |
260 | 0 | return ret; |
261 | 0 | } |
262 | 0 | return nt_time_to_full_timespec(nt); |
263 | 0 | } |
264 | | |
265 | | /******************************************************************* |
266 | | Re-read the smb serverzone value. |
267 | | ******************************************************************/ |
268 | | |
269 | | static struct timeval start_time_hires; |
270 | | |
271 | | void TimeInit(void) |
272 | 0 | { |
273 | 0 | set_server_zone_offset(time(NULL)); |
274 | |
|
275 | 0 | DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset)); |
276 | | |
277 | | /* Save the start time of this process. */ |
278 | 0 | if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) { |
279 | 0 | GetTimeOfDay(&start_time_hires); |
280 | 0 | } |
281 | 0 | } |
282 | | |
283 | | /********************************************************************** |
284 | | Return a timeval struct of the uptime of this process. As TimeInit is |
285 | | done before a daemon fork then this is the start time from the parent |
286 | | daemon start. JRA. |
287 | | ***********************************************************************/ |
288 | | |
289 | | void get_process_uptime(struct timeval *ret_time) |
290 | 0 | { |
291 | 0 | struct timeval time_now_hires; |
292 | |
|
293 | 0 | GetTimeOfDay(&time_now_hires); |
294 | 0 | ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec; |
295 | 0 | if (time_now_hires.tv_usec < start_time_hires.tv_usec) { |
296 | 0 | ret_time->tv_sec -= 1; |
297 | 0 | ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec); |
298 | 0 | } else { |
299 | 0 | ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec; |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | /** |
304 | | * @brief Get the startup time of the server. |
305 | | * |
306 | | * @param[out] ret_time A pointer to a timveal structure to set the startup |
307 | | * time. |
308 | | */ |
309 | | void get_startup_time(struct timeval *ret_time) |
310 | 0 | { |
311 | 0 | ret_time->tv_sec = start_time_hires.tv_sec; |
312 | 0 | ret_time->tv_usec = start_time_hires.tv_usec; |
313 | 0 | } |
314 | | |
315 | | |
316 | | /**************************************************************************** |
317 | | Convert a NTTIME structure to a time_t. |
318 | | It's originally in "100ns units". |
319 | | |
320 | | This is an absolute version of the one above. |
321 | | By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970 |
322 | | if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM |
323 | | ****************************************************************************/ |
324 | | |
325 | | time_t nt_time_to_unix_abs(const NTTIME *nt) |
326 | 0 | { |
327 | 0 | uint64_t d; |
328 | |
|
329 | 0 | if (*nt == 0) { |
330 | 0 | return (time_t)0; |
331 | 0 | } |
332 | | |
333 | 0 | if (*nt == (uint64_t)-1) { |
334 | 0 | return (time_t)-1; |
335 | 0 | } |
336 | | |
337 | 0 | if (*nt == NTTIME_INFINITY) { |
338 | 0 | return (time_t)-1; |
339 | 0 | } |
340 | | |
341 | | /* reverse the time */ |
342 | | /* it's a negative value, turn it to positive */ |
343 | 0 | d=~*nt; |
344 | |
|
345 | 0 | d += 1000*1000*10/2; |
346 | 0 | d /= 1000*1000*10; |
347 | |
|
348 | 0 | if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) { |
349 | 0 | return (time_t)0; |
350 | 0 | } |
351 | | |
352 | 0 | return (time_t)d; |
353 | 0 | } |
354 | | |
355 | | /**************************************************************************** |
356 | | Convert a time_t to a NTTIME structure |
357 | | |
358 | | This is an absolute version of the one above. |
359 | | By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601 |
360 | | If the time_t was 5 seconds, the NTTIME is 5 seconds. JFM |
361 | | ****************************************************************************/ |
362 | | |
363 | | void unix_to_nt_time_abs(NTTIME *nt, time_t t) |
364 | 0 | { |
365 | 0 | double d; |
366 | |
|
367 | 0 | if (t==0) { |
368 | 0 | *nt = 0; |
369 | 0 | return; |
370 | 0 | } |
371 | | |
372 | 0 | if (t == TIME_T_MAX) { |
373 | 0 | *nt = 0x7fffffffffffffffLL; |
374 | 0 | return; |
375 | 0 | } |
376 | | |
377 | 0 | if (t == (time_t)-1) { |
378 | | /* that's what NT uses for infinite */ |
379 | 0 | *nt = NTTIME_INFINITY; |
380 | 0 | return; |
381 | 0 | } |
382 | | |
383 | 0 | d = (double)(t); |
384 | 0 | d *= 1.0e7; |
385 | |
|
386 | 0 | *nt = (NTTIME)d; |
387 | | |
388 | | /* convert to a negative value */ |
389 | 0 | *nt=~*nt; |
390 | 0 | } |
391 | | |
392 | | |
393 | | /**************************************************************************** |
394 | | Utility function that always returns a const string even if localtime |
395 | | and asctime fail. |
396 | | ****************************************************************************/ |
397 | | |
398 | | const char *time_to_asc(const time_t t) |
399 | 0 | { |
400 | 0 | const char *asct; |
401 | 0 | struct tm *lt = localtime(&t); |
402 | |
|
403 | 0 | if (!lt) { |
404 | 0 | return "unknown time\n"; |
405 | 0 | } |
406 | | |
407 | 0 | asct = asctime(lt); |
408 | 0 | if (!asct) { |
409 | 0 | return "unknown time\n"; |
410 | 0 | } |
411 | 0 | return asct; |
412 | 0 | } |
413 | | |
414 | | const char *display_time(NTTIME nttime) |
415 | 0 | { |
416 | 0 | float high; |
417 | 0 | float low; |
418 | 0 | int sec; |
419 | 0 | int days, hours, mins, secs; |
420 | |
|
421 | 0 | if (nttime==0) |
422 | 0 | return "Now"; |
423 | | |
424 | 0 | if (nttime==NTTIME_INFINITY) |
425 | 0 | return "Never"; |
426 | | |
427 | 0 | high = 65536; |
428 | 0 | high = high/10000; |
429 | 0 | high = high*65536; |
430 | 0 | high = high/1000; |
431 | 0 | high = high * (~(nttime >> 32)); |
432 | |
|
433 | 0 | low = ~(nttime & 0xFFFFFFFF); |
434 | 0 | low = low/(1000*1000*10); |
435 | |
|
436 | 0 | sec=(int)(high+low); |
437 | |
|
438 | 0 | days=sec/(60*60*24); |
439 | 0 | hours=(sec - (days*60*60*24)) / (60*60); |
440 | 0 | mins=(sec - (days*60*60*24) - (hours*60*60) ) / 60; |
441 | 0 | secs=sec - (days*60*60*24) - (hours*60*60) - (mins*60); |
442 | |
|
443 | 0 | return talloc_asprintf(talloc_tos(), "%u days, %u hours, %u minutes, " |
444 | 0 | "%u seconds", days, hours, mins, secs); |
445 | 0 | } |
446 | | |
447 | | bool nt_time_is_set(const NTTIME *nt) |
448 | 0 | { |
449 | 0 | if (*nt == 0x7FFFFFFFFFFFFFFFLL) { |
450 | 0 | return false; |
451 | 0 | } |
452 | | |
453 | 0 | if (*nt == NTTIME_INFINITY) { |
454 | 0 | return false; |
455 | 0 | } |
456 | | |
457 | 0 | return true; |
458 | 0 | } |