]> granicus.if.org Git - postgresql/commitdiff
Sync our copy of the timezone library with IANA release tzcode2016h.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 20 Oct 2016 19:40:07 +0000 (15:40 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 20 Oct 2016 19:40:34 +0000 (15:40 -0400)
This absorbs a fix for a symlink-manipulation bug in zic that was
introduced in 2016g.  It probably isn't interesting for our use-case,
but I'm not quite sure, so let's update while we're at it.

src/timezone/zic.c

index 4ff819931a7f6256a23bb0f653bcbb77d998b1ce..612133772eb7ed41bdab1f4cde9d82d751532e83 100644 (file)
@@ -801,6 +801,56 @@ namecheck(const char *name)
        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.
+ */
+#ifdef HAVE_SYMLINK
+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;
+}
+#endif   /* HAVE_SYMLINK */
+
 static void
 dolink(char const * fromfield, char const * tofield, bool staysymlink)
 {
@@ -844,31 +894,17 @@ dolink(char const * fromfield, char const * tofield, bool staysymlink)
        if (link_errno != 0)
        {
 #ifdef HAVE_SYMLINK
-               const char *s = fromfield;
-               const char *t;
-               char       *p;
-               size_t          dotdots = 0;
-               char       *symlinkcontents;
-               int                     symlink_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;
 
-               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;
                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)