diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
commit | 0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch) | |
tree | 3f3789daa2f6db22da6e55e92bee0062a7d613fe /src/lib/utc-mktime.c | |
parent | Initial commit. (diff) | |
download | dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.tar.xz dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.zip |
Adding upstream version 1:2.3.21+dfsg1.upstream/1%2.3.21+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/utc-mktime.c')
-rw-r--r-- | src/lib/utc-mktime.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/lib/utc-mktime.c b/src/lib/utc-mktime.c new file mode 100644 index 0000000..e67c687 --- /dev/null +++ b/src/lib/utc-mktime.c @@ -0,0 +1,79 @@ +/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "utc-mktime.h" + +static int tm_cmp(const struct tm *tm1, const struct tm *tm2) +{ + int diff; + + if ((diff = tm1->tm_year - tm2->tm_year) != 0) + return diff; + if ((diff = tm1->tm_mon - tm2->tm_mon) != 0) + return diff; + if ((diff = tm1->tm_mday - tm2->tm_mday) != 0) + return diff; + if ((diff = tm1->tm_hour - tm2->tm_hour) != 0) + return diff; + if ((diff = tm1->tm_min - tm2->tm_min) != 0) + return diff; + return tm1->tm_sec - tm2->tm_sec; +} + +static inline void adjust_leap_second(struct tm *tm) +{ + if (tm->tm_sec == 60) + tm->tm_sec = 59; +} + +#ifdef HAVE_TIMEGM +/* Normalization done by timegm is considered a failure here, since it means + * the timestamp is not valid as-is. Leap second 60 is adjusted to 59 before + * this though. */ +time_t utc_mktime(const struct tm *tm) +{ + struct tm leap_adj_tm = *tm; + adjust_leap_second(&leap_adj_tm); + struct tm tmp = leap_adj_tm; + time_t t; + + t = timegm(&tmp); + if (tm_cmp(&leap_adj_tm, &tmp) != 0) + return (time_t)-1; + return t; +} +#else +time_t utc_mktime(const struct tm *tm) +{ + struct tm leap_adj_tm = *tm; + adjust_leap_second(&leap_adj_tm); + const struct tm *try_tm; + time_t t; + int bits, dir; + + /* we'll do a binary search across the entire valid time_t range. + when gmtime()'s output matches the tm parameter, we've found the + correct time_t value. this also means that if tm contains invalid + values, -1 is returned. */ +#ifdef TIME_T_SIGNED + t = 0; +#else + t = (time_t)1 << (TIME_T_MAX_BITS - 1); +#endif + for (bits = TIME_T_MAX_BITS - 2;; bits--) { + try_tm = gmtime(&t); + dir = tm_cmp(&leap_adj_tm, try_tm); + if (dir == 0) + return t; + if (bits < 0) + break; + + if (dir < 0) + t -= (time_t)1 << bits; + else + t += (time_t)1 << bits; + } + + return (time_t)-1; +} +#endif |