/src/dovecot/src/lib/utc-mktime.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level 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 | | t = 0; |
59 | | for (bits = TIME_T_MAX_BITS - 2;; bits--) { |
60 | | try_tm = gmtime(&t); |
61 | | dir = tm_cmp(&leap_adj_tm, try_tm); |
62 | | if (dir == 0) |
63 | | return t; |
64 | | if (bits < 0) |
65 | | break; |
66 | | |
67 | | if (dir < 0) |
68 | | t -= (time_t)1 << bits; |
69 | | else |
70 | | t += (time_t)1 << bits; |
71 | | } |
72 | | |
73 | | return (time_t)-1; |
74 | | } |
75 | | #endif |