* localtime.c (tzloadbody): For a TZif file that is not regular or
that has a bad format, fail with errno set to EFTYPE, not EINVAL.
This fits better with BSD tradition going back to 4.4BSD and
Berkeley DB in the early 1990s, and is what NetBSD already does
when the file is not a regular file. This changes user-visible
behavior only for the value of errno just after tzalloc fails.
* private.h (EFTYPE): Default to EINVAL, so that behavior does not
change on platforms lacking EFTYPE.
---
localtime.c | 30 +++++++++++++++---------------
private.h | 3 +++
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/localtime.c b/localtime.c
index e3b8bb94..158f0150 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1025,7 +1025,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
< 0)
return errno;
if (!S_ISREG(st.st_mode))
- return EINVAL;
+ return EFTYPE;
}
fid = OPENAT_TZDIR ? openat(dd, relname, oflags) : open(name, oflags);
err = errno;
@@ -1049,7 +1049,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
}
up = &lsp->u.u;
nread = read(fid, up->buf, sizeof up->buf);
- err = tzheadsize <= nread ? 0 : nread < 0 ? errno : EINVAL;
+ err = tzheadsize <= nread ? 0 : nread < 0 ? errno : EFTYPE;
}
close(fid);
if (err)
@@ -1077,7 +1077,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
&& 0 <= charcnt && charcnt <= TZ_MAX_CHARS
&& 0 <= ttisstdcnt && ttisstdcnt <= TZ_MAX_TYPES
&& 0 <= ttisutcnt && ttisutcnt <= TZ_MAX_TYPES))
- return EINVAL;
+ return EFTYPE;
datablock_size
= (timecnt * stored /* ats */
+ timecnt /* types */
@@ -1087,12 +1087,12 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
+ ttisstdcnt /* ttisstds */
+ ttisutcnt); /* ttisuts */
if (nread < tzheadsize + datablock_size)
- return EINVAL;
+ return EFTYPE;
if (skip_datablock)
p += datablock_size;
else if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
&& (ttisutcnt == typecnt || ttisutcnt == 0)))
- return EINVAL;
+ return EFTYPE;
else {
int_fast64_t prevtr = -1;
int_fast32_2s prevcorr;
@@ -1115,7 +1115,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
? TIME_T_MIN : at);
if (timecnt && attime <= sp->ats[timecnt - 1]) {
if (attime < sp->ats[timecnt - 1])
- return EINVAL;
+ return EFTYPE;
sp->types[i - 1] = 0;
timecnt--;
}
@@ -1128,7 +1128,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
for (i = 0; i < sp->timecnt; ++i) {
unsigned char typ = *p++;
if (sp->typecnt <= typ)
- return EINVAL;
+ return EFTYPE;
if (sp->types[i])
sp->types[timecnt++] = typ;
}
@@ -1142,18 +1142,18 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
cause trouble both in this file and in callers.
Also, it violates RFC 9636 section 3.2. */
if (utoff < -TWO_31_MINUS_1)
- return EINVAL;
+ return EFTYPE;
ttisp = &sp->ttis[i];
ttisp->tt_utoff = utoff;
p += 4;
isdst = *p++;
if (! (isdst < 2))
- return EINVAL;
+ return EFTYPE;
ttisp->tt_isdst = isdst;
desigidx = *p++;
if (! (desigidx < sp->charcnt))
- return EINVAL;
+ return EFTYPE;
ttisp->tt_desigidx = desigidx;
}
for (i = 0; i < sp->charcnt; ++i)
@@ -1172,7 +1172,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
/* Leap seconds cannot occur before the Epoch,
or out of order. */
if (tr <= prevtr)
- return EINVAL;
+ return EFTYPE;
/* To avoid other botches in this code, each leap second's
correction must differ from the previous one's by 1
@@ -1184,7 +1184,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
? corr == prevcorr + 1
: (corr == prevcorr
|| corr == prevcorr - 1))))
- return EINVAL;
+ return EFTYPE;
prevtr = tr;
prevcorr = corr;
@@ -1206,7 +1206,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
ttisp->tt_ttisstd = false;
else {
if (*p != true && *p != false)
- return EINVAL;
+ return EFTYPE;
ttisp->tt_ttisstd = *p++;
}
}
@@ -1218,7 +1218,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
ttisp->tt_ttisut = false;
else {
if (*p != true && *p != false)
- return EINVAL;
+ return EFTYPE;
ttisp->tt_ttisut = *p++;
}
}
@@ -1303,7 +1303,7 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
}
}
if (sp->typecnt == 0)
- return EINVAL;
+ return EFTYPE;
return 0;
}
diff --git a/private.h b/private.h
index 1e6db08c..b0faaeb9 100644
--- a/private.h
+++ b/private.h
@@ -243,6 +243,9 @@ strnlen (char const *s, size_t maxlen)
# define EINVAL ERANGE
#endif
+#ifndef EFTYPE
+# define EFTYPE EINVAL
+#endif
#ifndef ELOOP
# define ELOOP EINVAL
#endif
--
2.54.0