Fri Oct 7 19:47:16 2016 UTC ()
Patch 0001 from upstream to tzcode2016g to restore full functionality
of zic -l


(kre)
diff -r1.63 -r1.64 src/lib/libc/time/zic.c

cvs diff -r1.63 -r1.64 src/lib/libc/time/zic.c (expand / switch to context diff)
--- src/lib/libc/time/zic.c 2016/10/07 15:29:42 1.63
+++ src/lib/libc/time/zic.c 2016/10/07 19:47:16 1.64
@@ -1,4 +1,4 @@
-/*	$NetBSD: zic.c,v 1.63 2016/10/07 15:29:42 christos Exp $	*/
+/*	$NetBSD: zic.c,v 1.64 2016/10/07 19:47:16 kre Exp $	*/
 /*
 ** This file is in the public domain, so clarified as of
 ** 2006-07-17 by Arthur David Olson.
@@ -10,7 +10,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: zic.c,v 1.63 2016/10/07 15:29:42 christos Exp $");
+__RCSID("$NetBSD: zic.c,v 1.64 2016/10/07 19:47:16 kre Exp $");
 #endif /* !defined lint */
 
 #include "private.h"
@@ -776,6 +776,44 @@
 	return componentcheck(name, component, cp);
 }
 
+/* Create symlink contents suitable for symlinking FROM to TO, as a
+   freshly allocated string.  FROM should be a relative file name, and
+   is relative to the global variable DIRECTORY.  TO can be either
+   relative or absolute.  */
+static char *
+relname(char const *from, char const *to)
+{
+  size_t i, taillen, dotdotetcsize;
+  size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
+  char const *f = from;
+  char *result = NULL;
+  if (*to == '/') {
+    /* Make F absolute too.  */
+    size_t len = strlen(directory);
+    bool needslash = len && directory[len - 1] != '/';
+    linksize = len + needslash + strlen(from) + 1;
+    f = result = emalloc(linksize);
+    strcpy(result, directory);
+    result[len] = '/';
+    strcpy(result + len + needslash, from);
+  }
+  for (i = 0; f[i] && f[i] == to[i]; i++)
+    if (f[i] == '/')
+      dir_len = i + 1;
+  for (; f[i]; i++)
+    dotdots += f[i] == '/' && f[i - 1] != '/';
+  taillen = i - dir_len;
+  dotdotetcsize = 3 * dotdots + taillen + 1;
+  if (dotdotetcsize <= linksize) {
+    if (!result)
+      result = emalloc(dotdotetcsize);
+    for (i = 0; i < dotdots; i++)
+      memcpy(result + 3 * i, "../", 3);
+    memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
+  }
+  return result;
+}
+
 static void
 dolink(char const *fromfield, char const *tofield, bool staysymlink)
 {
@@ -812,30 +850,15 @@
 	  link_errno = link(fromfield, tofield) == 0 ? 0 : errno;
 	}
 	if (link_errno != 0) {
-	  const char *s = fromfield;
-	  const char *t;
-	  char *p;
-	  size_t dotdots = 0;
-	  char *symlinkcontents;
-	  int symlink_errno;
-
-	  do
-	    t = s;
-	  while ((s = strchr(s, '/'))
-		 && strncmp(fromfield, tofield, ++s - fromfield) == 0);
-
-	  for (s = tofield + (t - fromfield); *s; s++)
-	    dotdots += *s == '/';
-	  symlinkcontents = emalloc(3 * dotdots + strlen(t) + 1);
-	  for (p = symlinkcontents; dotdots-- != 0; p += 3)
-	    memcpy(p, "../", 3);
-	  strcpy(p, t);
-	  symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno;
+	  bool absolute = *fromfield == '/';
+	  char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
+	  char const *contents = absolute ? fromfield : linkalloc;
+	  int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
 	  if (symlink_errno == ENOENT && !todirs_made) {
 	    mkdirs(tofield, true);
-	    symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno;
+	    symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
 	  }
-	  free(symlinkcontents);
+	  free(linkalloc);
 	  if (symlink_errno == 0) {
 	    if (link_errno != ENOTSUP)
 	      warning(_("symbolic link used because hard link failed: %s"),