Skip to content

Commit 845a8ea

Browse files
committed
Sync our copy of the timezone library with IANA release tzcode2016h.
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.
1 parent 80ba149 commit 845a8ea

File tree

1 file changed

+56
-20
lines changed

1 file changed

+56
-20
lines changed

src/timezone/zic.c

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,56 @@ namecheck(const char *name)
789789
return componentcheck(name, component, cp);
790790
}
791791

792+
/*
793+
* Create symlink contents suitable for symlinking FROM to TO, as a
794+
* freshly allocated string. FROM should be a relative file name, and
795+
* is relative to the global variable DIRECTORY. TO can be either
796+
* relative or absolute.
797+
*/
798+
#ifdef HAVE_SYMLINK
799+
static char *
800+
relname(char const * from, char const * to)
801+
{
802+
size_t i,
803+
taillen,
804+
dotdotetcsize;
805+
size_t dir_len = 0,
806+
dotdots = 0,
807+
linksize = SIZE_MAX;
808+
char const *f = from;
809+
char *result = NULL;
810+
811+
if (*to == '/')
812+
{
813+
/* Make F absolute too. */
814+
size_t len = strlen(directory);
815+
bool needslash = len && directory[len - 1] != '/';
816+
817+
linksize = len + needslash + strlen(from) + 1;
818+
f = result = emalloc(linksize);
819+
strcpy(result, directory);
820+
result[len] = '/';
821+
strcpy(result + len + needslash, from);
822+
}
823+
for (i = 0; f[i] && f[i] == to[i]; i++)
824+
if (f[i] == '/')
825+
dir_len = i + 1;
826+
for (; f[i]; i++)
827+
dotdots += f[i] == '/' && f[i - 1] != '/';
828+
taillen = i - dir_len;
829+
dotdotetcsize = 3 * dotdots + taillen + 1;
830+
if (dotdotetcsize <= linksize)
831+
{
832+
if (!result)
833+
result = emalloc(dotdotetcsize);
834+
for (i = 0; i < dotdots; i++)
835+
memcpy(result + 3 * i, "../", 3);
836+
memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
837+
}
838+
return result;
839+
}
840+
#endif /* HAVE_SYMLINK */
841+
792842
static void
793843
dolink(char const * fromfield, char const * tofield, bool staysymlink)
794844
{
@@ -832,31 +882,17 @@ dolink(char const * fromfield, char const * tofield, bool staysymlink)
832882
if (link_errno != 0)
833883
{
834884
#ifdef HAVE_SYMLINK
835-
const char *s = fromfield;
836-
const char *t;
837-
char *p;
838-
size_t dotdots = 0;
839-
char *symlinkcontents;
840-
int symlink_errno;
885+
bool absolute = *fromfield == '/';
886+
char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
887+
char const *contents = absolute ? fromfield : linkalloc;
888+
int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
841889

842-
do
843-
t = s;
844-
while ((s = strchr(s, '/'))
845-
&& strncmp(fromfield, tofield, ++s - fromfield) == 0);
846-
847-
for (s = tofield + (t - fromfield); *s; s++)
848-
dotdots += *s == '/';
849-
symlinkcontents = emalloc(3 * dotdots + strlen(t) + 1);
850-
for (p = symlinkcontents; dotdots-- != 0; p += 3)
851-
memcpy(p, "../", 3);
852-
strcpy(p, t);
853-
symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno;
854890
if (symlink_errno == ENOENT && !todirs_made)
855891
{
856892
mkdirs(tofield, true);
857-
symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno;
893+
symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
858894
}
859-
free(symlinkcontents);
895+
free(linkalloc);
860896
if (symlink_errno == 0)
861897
{
862898
if (link_errno != ENOTSUP)

0 commit comments

Comments
 (0)