Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}