>From c0cff20d3c55adfa1e92b4cbbac4ec879bcab5ea Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 12 Jun 2017 20:24:31 -0700
Subject: [PATCH 1/4] Minor TZDIR improvements
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* localtime.c (tzdirslash): New constant.
(union local_stoage): Make it at least as large as tzdirslash,
plus an extra 1024 for zone names.  Although this is unlikely to
be needed, it doesn���t hurt.
(tzloadbody): Assume TZDIR is nonnull.  Look at its contents
just once when prepending it.
---
 localtime.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/localtime.c b/localtime.c
index cd4e80e..1f5bbb2 100644
--- a/localtime.c
+++ b/localtime.c
@@ -356,6 +356,9 @@ union input_buffer {
 	   + 4 * TZ_MAX_TIMES];
 };
 
+/* TZDIR with a trailing '/' rather than a trailing '\0'.  */
+static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
+
 /* Local storage needed for 'tzloadbody'.  */
 union local_storage {
   /* The results of analyzing the file's contents after it is opened.  */
@@ -368,7 +371,8 @@ union local_storage {
   } u;
 
   /* The file name to be opened.  */
-  char fullname[sizeof (struct file_analysis)];
+  char fullname[BIGGEST(sizeof (struct file_analysis),
+			sizeof tzdirslash + 1024)];
 };
 
 /* Load tz data from the file named NAME into *SP.  Read extended
@@ -398,14 +402,16 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 		++name;
 	doaccess = name[0] == '/';
 	if (!doaccess) {
-		char const *p = TZDIR;
-		if (! p)
-		  return EINVAL;
-		if (sizeof lsp->fullname - 1 <= strlen(p) + strlen(name))
+		size_t namelen = strlen(name);
+		if (sizeof lsp->fullname - sizeof tzdirslash <= namelen)
 		  return ENAMETOOLONG;
-		strcpy(lsp->fullname, p);
-		strcat(lsp->fullname, "/");
-		strcat(lsp->fullname, name);
+
+		/* Create a string "TZDIR/NAME".  Using sprintf here
+		   would pull in stdio (and would fail if the
+		   resulting string length exceeded INT_MAX!).  */
+		memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
+		strcpy(lsp->fullname + sizeof tzdirslash, name);
+
 		/* Set doaccess if '.' (as in "../") shows up in name.  */
 		if (strchr(name, '.'))
 			doaccess = true;
-- 
2.9.4

