diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2023-03-02 16:21:52 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2023-03-02 16:21:52 +0000 |
commit | 8c77d188a64ef31059fc9d87859aba8a228cc9c5 (patch) | |
tree | f0b2d273c69e56f2ca0b8d1ff43600cfd9cce2ff | |
parent | e49912572cfc5c5c5177956a7207931db8cf0a67 (diff) |
When parsing %s, the result should be in the local time zone.
Based on a patch from enh@google. OK tb@
-rw-r--r-- | lib/libc/time/strptime.c | 60 |
1 files changed, 29 insertions, 31 deletions
diff --git a/lib/libc/time/strptime.c b/lib/libc/time/strptime.c index 02017880457..2fae1f49220 100644 --- a/lib/libc/time/strptime.c +++ b/lib/libc/time/strptime.c @@ -1,4 +1,4 @@ -/* $OpenBSD: strptime.c,v 1.30 2019/05/12 12:49:52 schwarze Exp $ */ +/* $OpenBSD: strptime.c,v 1.31 2023/03/02 16:21:51 millert Exp $ */ /* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */ /*- * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. @@ -29,8 +29,10 @@ */ #include <ctype.h> +#include <errno.h> +#include <limits.h> #include <locale.h> -#include <stdint.h> +#include <stdlib.h> #include <string.h> #include <time.h> @@ -72,8 +74,8 @@ static const int mon_lengths[2][MONSPERYEAR] = { { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; -static int _conv_num64(const unsigned char **, int64_t *, int64_t, int64_t); static int _conv_num(const unsigned char **, int *, int, int); +static int epoch_to_tm(const unsigned char **, struct tm *); static int leaps_thru_end_of(const int y); static char *_strptime(const char *, const char *, struct tm *, int); static const u_char *_find_string(const u_char *, int *, const char * const *, @@ -338,15 +340,10 @@ literal: if (!(_conv_num(&bp, &tm->tm_sec, 0, 60))) return (NULL); break; - case 's': /* Seconds since epoch */ - { - int64_t i64; - if (!(_conv_num64(&bp, &i64, 0, INT64_MAX))) - return (NULL); - if (!gmtime_r(&i64, tm)) - return (NULL); - fields = 0xffff; /* everything */ - } + case 's': /* Seconds since epoch. */ + if (!(epoch_to_tm(&bp, tm))) + return (NULL); + fields = 0xffff; /* everything */ break; case 'U': /* The week of year, beginning on sunday. */ case 'W': /* The week of year, beginning on monday. */ @@ -610,26 +607,27 @@ _conv_num(const unsigned char **buf, int *dest, int llim, int ulim) } static int -_conv_num64(const unsigned char **buf, int64_t *dest, int64_t llim, int64_t ulim) +epoch_to_tm(const unsigned char **buf, struct tm *tm) { - int result = 0; - int64_t rulim = ulim; - - if (**buf < '0' || **buf > '9') - return (0); - - /* we use rulim to break out of the loop when we run out of digits */ - do { - result *= 10; - result += *(*buf)++ - '0'; - rulim /= 10; - } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9'); - - if (result < llim || result > ulim) - return (0); - - *dest = result; - return (1); + int saved_errno = errno; + int ret = 0; + time_t secs; + char *ep; + + errno = 0; + secs = strtoll(*buf, &ep, 10); + if (*buf == (unsigned char *)ep) + goto done; + if (secs < 0 || + secs == LLONG_MAX && errno == ERANGE) + goto done; + if (localtime_r(&secs, tm) == NULL) + goto done; + ret = 1; +done: + *buf = ep; + errno = saved_errno; + return (ret); } static const u_char * |