/src/dovecot/src/lib/utc-mktime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "utc-mktime.h" |
5 | | |
6 | | static int tm_cmp(const struct tm *tm1, const struct tm *tm2) |
7 | 0 | { |
8 | 0 | int diff; |
9 | |
|
10 | 0 | if ((diff = tm1->tm_year - tm2->tm_year) != 0) |
11 | 0 | return diff; |
12 | 0 | if ((diff = tm1->tm_mon - tm2->tm_mon) != 0) |
13 | 0 | return diff; |
14 | 0 | if ((diff = tm1->tm_mday - tm2->tm_mday) != 0) |
15 | 0 | return diff; |
16 | 0 | if ((diff = tm1->tm_hour - tm2->tm_hour) != 0) |
17 | 0 | return diff; |
18 | 0 | if ((diff = tm1->tm_min - tm2->tm_min) != 0) |
19 | 0 | return diff; |
20 | 0 | return tm1->tm_sec - tm2->tm_sec; |
21 | 0 | } |
22 | | |
23 | | static inline void adjust_leap_second(struct tm *tm) |
24 | 0 | { |
25 | 0 | if (tm->tm_sec == 60) |
26 | 0 | tm->tm_sec = 59; |
27 | 0 | } |
28 | | |
29 | | #ifdef HAVE_TIMEGM |
30 | | /* Normalization done by timegm is considered a failure here, since it means |
31 | | * the timestamp is not valid as-is. Leap second 60 is adjusted to 59 before |
32 | | * this though. */ |
33 | | time_t utc_mktime(const struct tm *tm) |
34 | 0 | { |
35 | 0 | struct tm leap_adj_tm = *tm; |
36 | 0 | adjust_leap_second(&leap_adj_tm); |
37 | 0 | struct tm tmp = leap_adj_tm; |
38 | 0 | time_t t; |
39 | |
|
40 | 0 | t = timegm(&tmp); |
41 | 0 | if (tm_cmp(&leap_adj_tm, &tmp) != 0) |
42 | 0 | return (time_t)-1; |
43 | 0 | return t; |
44 | 0 | } |
45 | | #else |
46 | | time_t utc_mktime(const struct tm *tm) |
47 | | { |
48 | | struct tm leap_adj_tm = *tm; |
49 | | adjust_leap_second(&leap_adj_tm); |
50 | | const struct tm *try_tm; |
51 | | time_t t; |
52 | | int bits, dir; |
53 | | |
54 | | /* we'll do a binary search across the entire valid time_t range. |
55 | | when gmtime()'s output matches the tm parameter, we've found the |
56 | | correct time_t value. this also means that if tm contains invalid |
57 | | values, -1 is returned. */ |
58 | | #ifdef TIME_T_SIGNED |
59 | | t = 0; |
60 | | #else |
61 | | t = (time_t)1 << (TIME_T_MAX_BITS - 1); |
62 | | #endif |
63 | | for (bits = TIME_T_MAX_BITS - 2;; bits--) { |
64 | | try_tm = gmtime(&t); |
65 | | dir = tm_cmp(&leap_adj_tm, try_tm); |
66 | | if (dir == 0) |
67 | | return t; |
68 | | if (bits < 0) |
69 | | break; |
70 | | |
71 | | if (dir < 0) |
72 | | t -= (time_t)1 << bits; |
73 | | else |
74 | | t += (time_t)1 << bits; |
75 | | } |
76 | | |
77 | | return (time_t)-1; |
78 | | } |
79 | | #endif |