Line data Source code
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 : #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 310959 : uint32_t convert_time_t_to_uint32_t(time_t t)
41 : {
42 : #if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
43 : /* time_t is 64-bit. */
44 310959 : if (t == 0x8000000000000000LL) {
45 0 : return 0x80000000;
46 310959 : } else if (t == 0x7FFFFFFFFFFFFFFFLL) {
47 0 : return 0x7FFFFFFF;
48 : }
49 : #endif
50 310959 : return (uint32_t)t;
51 : }
52 :
53 564256 : time_t convert_uint32_t_to_time_t(uint32_t u)
54 : {
55 : #if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
56 : /* time_t is 64-bit. */
57 564256 : if (u == 0x80000000) {
58 0 : return (time_t)0x8000000000000000LL;
59 564256 : } else if (u == 0x7FFFFFFF) {
60 0 : return (time_t)0x7FFFFFFFFFFFFFFFLL;
61 : }
62 : #endif
63 564188 : return (time_t)u;
64 : }
65 :
66 : /****************************************************************************
67 : Check if NTTIME is 0.
68 : ****************************************************************************/
69 :
70 0 : bool nt_time_is_zero(const NTTIME *nt)
71 : {
72 0 : return (*nt == 0);
73 : }
74 :
75 : /****************************************************************************
76 : Convert ASN.1 GeneralizedTime string to unix-time.
77 : Returns 0 on failure; Currently ignores timezone.
78 : ****************************************************************************/
79 :
80 0 : time_t generalized_to_unix_time(const char *str)
81 : {
82 0 : struct tm tm;
83 :
84 0 : ZERO_STRUCT(tm);
85 :
86 0 : if (sscanf(str, "%4d%2d%2d%2d%2d%2d",
87 : &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
88 : &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
89 0 : return 0;
90 : }
91 0 : tm.tm_year -= 1900;
92 0 : tm.tm_mon -= 1;
93 :
94 0 : return timegm(&tm);
95 : }
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 0 : int get_server_zone_offset(void)
105 : {
106 0 : return server_zone_offset;
107 : }
108 :
109 : /*******************************************************************
110 : Initialize the server time zone offset. Called when a client connects.
111 : ******************************************************************/
112 :
113 11692 : int set_server_zone_offset(time_t t)
114 : {
115 11692 : server_zone_offset = get_time_zone(t);
116 11692 : return server_zone_offset;
117 : }
118 :
119 : /***************************************************************************
120 : Server versions of the above functions.
121 : ***************************************************************************/
122 :
123 20749 : void srv_put_dos_date(char *buf,int offset,time_t unixdate)
124 : {
125 20749 : push_dos_date((uint8_t *)buf, offset, unixdate, server_zone_offset);
126 20749 : }
127 :
128 345232 : void srv_put_dos_date2_ts(char *buf, int offset, struct timespec unix_ts)
129 : {
130 345232 : time_t unixdate = convert_timespec_to_time_t(unix_ts);
131 345232 : push_dos_date2((uint8_t *)buf, offset, unixdate, server_zone_offset);
132 345232 : }
133 :
134 20050 : void srv_put_dos_date3(char *buf,int offset,time_t unixdate)
135 : {
136 20050 : push_dos_date3((uint8_t *)buf, offset, unixdate, server_zone_offset);
137 20050 : }
138 :
139 5738390 : void round_timespec(enum timestamp_set_resolution res, struct timespec *ts)
140 : {
141 5738390 : if (is_omit_timespec(ts)) {
142 1508220 : return;
143 : }
144 :
145 4227815 : switch (res) {
146 66128 : case TIMESTAMP_SET_SECONDS:
147 66128 : round_timespec_to_sec(ts);
148 66128 : break;
149 0 : case TIMESTAMP_SET_MSEC:
150 0 : round_timespec_to_usec(ts);
151 0 : break;
152 4157829 : case TIMESTAMP_SET_NT_OR_BETTER:
153 : /* No rounding needed. */
154 4157829 : break;
155 : }
156 : }
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 92 : void put_long_date_timespec(enum timestamp_set_resolution res, char *p, struct timespec ts)
164 : {
165 0 : NTTIME nt;
166 92 : round_timespec(res, &ts);
167 92 : nt = unix_timespec_to_nt_time(ts);
168 92 : SBVAL(p, 0, nt);
169 92 : }
170 :
171 5694098 : void put_long_date_full_timespec(enum timestamp_set_resolution res,
172 : char *p,
173 : const struct timespec *_ts)
174 : {
175 5694098 : struct timespec ts = *_ts;
176 8233 : NTTIME nt;
177 :
178 5694098 : round_timespec(res, &ts);
179 5694098 : nt = full_timespec_to_nt_time(&ts);
180 5694098 : SBVAL(p, 0, nt);
181 5694098 : }
182 :
183 11564 : struct timespec pull_long_date_full_timespec(const char *p)
184 : {
185 11564 : NTTIME nt = BVAL(p, 0);
186 :
187 11564 : return nt_time_to_full_timespec(nt);
188 : }
189 :
190 92 : void put_long_date(char *p, time_t t)
191 : {
192 0 : struct timespec ts;
193 92 : ts.tv_sec = t;
194 92 : ts.tv_nsec = 0;
195 92 : put_long_date_timespec(TIMESTAMP_SET_SECONDS, p, ts);
196 92 : }
197 :
198 0 : void dos_filetime_timespec(struct timespec *tsp)
199 : {
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 131 : time_t make_unix_date(const void *date_ptr, int zone_offset)
210 : {
211 131 : return pull_dos_date(date_ptr, zone_offset);
212 : }
213 :
214 : /*******************************************************************
215 : Like make_unix_date() but the words are reversed.
216 : ********************************************************************/
217 :
218 39 : time_t make_unix_date2(const void *date_ptr, int zone_offset)
219 : {
220 39 : return pull_dos_date2(date_ptr, zone_offset);
221 : }
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 33679 : time_t make_unix_date3(const void *date_ptr, int zone_offset)
229 : {
230 33679 : return pull_dos_date3(date_ptr, zone_offset);
231 : }
232 :
233 0 : time_t srv_make_unix_date(const void *date_ptr)
234 : {
235 0 : return make_unix_date(date_ptr, server_zone_offset);
236 : }
237 :
238 24 : time_t srv_make_unix_date2(const void *date_ptr)
239 : {
240 24 : return make_unix_date2(date_ptr, server_zone_offset);
241 : }
242 :
243 32590 : time_t srv_make_unix_date3(const void *date_ptr)
244 : {
245 32590 : return make_unix_date3(date_ptr, server_zone_offset);
246 : }
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 278437 : struct timespec interpret_long_date(NTTIME nt)
255 : {
256 278437 : 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 : }
262 278437 : return nt_time_to_full_timespec(nt);
263 : }
264 :
265 : /*******************************************************************
266 : Re-read the smb serverzone value.
267 : ******************************************************************/
268 :
269 : static struct timeval start_time_hires;
270 :
271 138 : void TimeInit(void)
272 : {
273 138 : set_server_zone_offset(time(NULL));
274 :
275 138 : DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset));
276 :
277 : /* Save the start time of this process. */
278 138 : if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) {
279 138 : GetTimeOfDay(&start_time_hires);
280 : }
281 138 : }
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 3610 : void get_process_uptime(struct timeval *ret_time)
290 : {
291 0 : struct timeval time_now_hires;
292 :
293 3610 : GetTimeOfDay(&time_now_hires);
294 3610 : ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
295 3610 : 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 : } else {
299 3610 : ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
300 : }
301 3610 : }
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 276 : void get_startup_time(struct timeval *ret_time)
310 : {
311 276 : ret_time->tv_sec = start_time_hires.tv_sec;
312 276 : ret_time->tv_usec = start_time_hires.tv_usec;
313 276 : }
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 11 : time_t nt_time_to_unix_abs(const NTTIME *nt)
326 : {
327 0 : uint64_t d;
328 :
329 11 : if (*nt == 0) {
330 0 : return (time_t)0;
331 : }
332 :
333 11 : if (*nt == (uint64_t)-1) {
334 0 : return (time_t)-1;
335 : }
336 :
337 11 : if (*nt == NTTIME_INFINITY) {
338 2 : return (time_t)-1;
339 : }
340 :
341 : /* reverse the time */
342 : /* it's a negative value, turn it to positive */
343 9 : d=~*nt;
344 :
345 9 : d += 1000*1000*10/2;
346 9 : d /= 1000*1000*10;
347 :
348 9 : if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) {
349 0 : return (time_t)0;
350 : }
351 :
352 9 : return (time_t)d;
353 : }
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 65 : void unix_to_nt_time_abs(NTTIME *nt, time_t t)
364 : {
365 0 : double d;
366 :
367 65 : if (t==0) {
368 12 : *nt = 0;
369 12 : return;
370 : }
371 :
372 53 : if (t == TIME_T_MAX) {
373 24 : *nt = 0x7fffffffffffffffLL;
374 24 : return;
375 : }
376 :
377 29 : if (t == (time_t)-1) {
378 : /* that's what NT uses for infinite */
379 0 : *nt = NTTIME_INFINITY;
380 0 : return;
381 : }
382 :
383 29 : d = (double)(t);
384 29 : d *= 1.0e7;
385 :
386 29 : *nt = (NTTIME)d;
387 :
388 : /* convert to a negative value */
389 29 : *nt=~*nt;
390 : }
391 :
392 :
393 : /****************************************************************************
394 : Utility function that always returns a const string even if localtime
395 : and asctime fail.
396 : ****************************************************************************/
397 :
398 37509 : const char *time_to_asc(const time_t t)
399 : {
400 0 : const char *asct;
401 37509 : struct tm *lt = localtime(&t);
402 :
403 37509 : if (!lt) {
404 0 : return "unknown time\n";
405 : }
406 :
407 37509 : asct = asctime(lt);
408 37509 : if (!asct) {
409 0 : return "unknown time\n";
410 : }
411 37509 : return asct;
412 : }
413 :
414 0 : const char *display_time(NTTIME nttime)
415 : {
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 : "%u seconds", days, hours, mins, secs);
445 : }
446 :
447 0 : bool nt_time_is_set(const NTTIME *nt)
448 : {
449 0 : if (*nt == 0x7FFFFFFFFFFFFFFFLL) {
450 0 : return false;
451 : }
452 :
453 0 : if (*nt == NTTIME_INFINITY) {
454 0 : return false;
455 : }
456 :
457 0 : return true;
458 : }
|