Module Name: src
Committed By: christos
Date: Thu Oct 27 14:48:00 UTC 2011
Modified Files:
src/lib/libc/time: ctime.3 localtime.c
Log Message:
Change mktime*(3) so that it does not always return EOVERFLOW when it cannot
perform the conversion, but returns EINVAL when the time requested would fall
in the DST gap, or is not representable in the timezone requested, and document
this.
To generate a diff of this commit:
cvs rdiff -u -r1.43 -r1.44 src/lib/libc/time/ctime.3
cvs rdiff -u -r1.59 -r1.60 src/lib/libc/time/localtime.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libc/time/ctime.3
diff -u src/lib/libc/time/ctime.3:1.43 src/lib/libc/time/ctime.3:1.44
--- src/lib/libc/time/ctime.3:1.43 Sun Oct 16 13:59:32 2011
+++ src/lib/libc/time/ctime.3 Thu Oct 27 10:47:59 2011
@@ -1,8 +1,8 @@
-.\" $NetBSD: ctime.3,v 1.43 2011/10/16 17:59:32 christos Exp $
+.\" $NetBSD: ctime.3,v 1.44 2011/10/27 14:47:59 christos Exp $
.\"
-.\" XXX: Lincense missing?
+.\" XXX: License missing?
.\"
-.Dd October 16, 2011
+.Dd October 27, 2011
.Dt CTIME 3
.Os
.Sh NAME
@@ -401,9 +401,12 @@ is absent, UTC leap seconds are loaded f
The described functions may fail with
.Bl -tag -width Er
.It Bq Er EINVAL
-The result cannot be represented.
+The result cannot be represented because a parameter is incorrect, or
+the conversion failed because no such time exists (for example a time
+in the DST gap).
.It Bq Er EOVERFLOW
-The result cannot be represented.
+The result cannot be represented because the time requested is out of bounds
+and the time calculation resulted in overflow.
.El
.Pp
All functions that return values, except their
Index: src/lib/libc/time/localtime.c
diff -u src/lib/libc/time/localtime.c:1.59 src/lib/libc/time/localtime.c:1.60
--- src/lib/libc/time/localtime.c:1.59 Sun Oct 16 13:59:32 2011
+++ src/lib/libc/time/localtime.c Thu Oct 27 10:48:00 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: localtime.c,v 1.59 2011/10/16 17:59:32 christos Exp $ */
+/* $NetBSD: localtime.c,v 1.60 2011/10/27 14:48:00 christos Exp $ */
/*
** This file is in the public domain, so clarified as of
@@ -10,7 +10,7 @@
#if 0
static char elsieid[] = "@(#)localtime.c 8.17";
#else
-__RCSID("$NetBSD: localtime.c,v 1.59 2011/10/16 17:59:32 christos Exp $");
+__RCSID("$NetBSD: localtime.c,v 1.60 2011/10/27 14:48:00 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@@ -1801,25 +1801,25 @@ time2sub(const timezone_t sp, struct tm
yourtm = *tmp;
if (do_norm_secs) {
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
- SECSPERMIN))
- return WRONG;
+ SECSPERMIN))
+ goto overflow;
}
if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
- return WRONG;
+ goto overflow;
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
- return WRONG;
+ goto overflow;
y = yourtm.tm_year;
if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
- return WRONG;
+ goto overflow;
/*
** Turn y into an actual year number for now.
** It is converted back to an offset from TM_YEAR_BASE later.
*/
if (long_increment_overflow(&y, TM_YEAR_BASE))
- return WRONG;
+ goto overflow;
while (yourtm.tm_mday <= 0) {
if (long_increment_overflow(&y, -1))
- return WRONG;
+ goto overflow;
li = y + (1 < yourtm.tm_mon);
yourtm.tm_mday += year_lengths[isleap(li)];
}
@@ -1827,7 +1827,7 @@ time2sub(const timezone_t sp, struct tm
li = y + (1 < yourtm.tm_mon);
yourtm.tm_mday -= year_lengths[isleap(li)];
if (long_increment_overflow(&y, 1))
- return WRONG;
+ goto overflow;
}
for ( ; ; ) {
i = mon_lengths[isleap(y)][yourtm.tm_mon];
@@ -1837,14 +1837,14 @@ time2sub(const timezone_t sp, struct tm
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
if (long_increment_overflow(&y, 1))
- return WRONG;
+ goto overflow;
}
}
if (long_increment_overflow(&y, -TM_YEAR_BASE))
- return WRONG;
+ goto overflow;
yourtm.tm_year = y;
if (yourtm.tm_year != y)
- return WRONG;
+ goto overflow;
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
saved_seconds = 0;
else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
@@ -1857,7 +1857,7 @@ time2sub(const timezone_t sp, struct tm
** which is a safer assumption than using 58 would be.
*/
if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
- return WRONG;
+ goto overflow;
saved_seconds = yourtm.tm_sec;
yourtm.tm_sec = SECSPERMIN - 1;
} else {
@@ -1904,12 +1904,12 @@ time2sub(const timezone_t sp, struct tm
if (t == lo) {
++t;
if (t <= lo)
- return WRONG;
+ goto overflow;
++lo;
} else if (t == hi) {
--t;
if (t >= hi)
- return WRONG;
+ goto overflow;
--hi;
}
#ifdef NO_ERROR_IN_DST_GAP
@@ -1934,7 +1934,7 @@ time2sub(const timezone_t sp, struct tm
}
#endif
if (lo > hi)
- return WRONG;
+ goto invalid;
if (dir > 0)
hi = t;
else lo = t;
@@ -1949,7 +1949,7 @@ time2sub(const timezone_t sp, struct tm
** gets checked.
*/
if (sp == NULL)
- return WRONG;
+ goto invalid;
for (i = sp->typecnt - 1; i >= 0; --i) {
if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
continue;
@@ -1971,18 +1971,23 @@ time2sub(const timezone_t sp, struct tm
goto label;
}
}
- return WRONG;
+ goto invalid;
}
label:
newt = t + saved_seconds;
if ((newt < t) != (saved_seconds < 0))
- return WRONG;
+ goto overflow;
t = newt;
if ((*funcp)(sp, &t, offset, tmp)) {
*okayp = TRUE;
return t;
- } else
- return WRONG;
+ }
+overflow:
+ errno = EOVERFLOW;
+ return WRONG;
+invalid:
+ errno = EINVAL;
+ return WRONG;
}
static time_t
@@ -2039,8 +2044,10 @@ time1(const timezone_t sp, struct tm *co
** We try to divine the type they started from and adjust to the
** type they need.
*/
- if (sp == NULL)
+ if (sp == NULL) {
+ errno = EINVAL;
return WRONG;
+ }
for (i = 0; i < sp->typecnt; ++i)
seen[i] = FALSE;
nseen = 0;
@@ -2068,6 +2075,7 @@ time1(const timezone_t sp, struct tm *co
tmp->tm_isdst = !tmp->tm_isdst;
}
}
+ errno = EOVERFLOW;
return WRONG;
}
@@ -2079,8 +2087,6 @@ mktime_z(const timezone_t sp, struct tm
t = time1(NULL, tmp, gmtsub, 0L);
else
t = time1(sp, tmp, localsub, 0L);
- if (t == WRONG)
- errno = EOVERFLOW;
return t;
}