mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-30 19:00:29 +08:00
Sync our copy of the timezone library with IANA release tzcode2016g.
This is mostly to absorb some corner-case fixes in zic for year-2037 timestamps. The other changes that have been made are unlikely to affect our usage, but nonetheless we may as well take 'em.
This commit is contained in:
parent
a3215431ab
commit
f3094920a5
@ -1280,9 +1280,8 @@ gmtsub(pg_time_t const * timep, int32 offset, struct pg_tm * tmp)
|
|||||||
result = timesub(timep, offset, gmtptr, tmp);
|
result = timesub(timep, offset, gmtptr, tmp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Could get fancy here and deliver something such as "UT+xxxx" or
|
* Could get fancy here and deliver something such as "+xx" or "-xx" if
|
||||||
* "UT-xxxx" if offset is non-zero, but this is no time for a treasure
|
* offset is non-zero, but this is no time for a treasure hunt.
|
||||||
* hunt.
|
|
||||||
*/
|
*/
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
tmp->tm_zone = wildabbr;
|
tmp->tm_zone = wildabbr;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "pgtime.h"
|
#include "pgtime.h"
|
||||||
|
|
||||||
|
/* This string was in the Factory zone through version 2016f. */
|
||||||
#define GRANDPARENTED "Local time zone must be set--see zic manual page"
|
#define GRANDPARENTED "Local time zone must be set--see zic manual page"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -128,7 +128,7 @@ pg_strftime(char *s, size_t maxsize, const char *format,
|
|||||||
int warn;
|
int warn;
|
||||||
|
|
||||||
warn = IN_NONE;
|
warn = IN_NONE;
|
||||||
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
|
p = _fmt(format, t, s, s + maxsize, &warn);
|
||||||
if (p == s + maxsize)
|
if (p == s + maxsize)
|
||||||
return 0;
|
return 0;
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
@ -105,7 +105,7 @@ static int addtype(zic_t, char const *, bool, bool, bool);
|
|||||||
static void leapadd(zic_t, bool, int, int);
|
static void leapadd(zic_t, bool, int, int);
|
||||||
static void adjleap(void);
|
static void adjleap(void);
|
||||||
static void associate(void);
|
static void associate(void);
|
||||||
static void dolink(const char *fromfield, const char *tofield);
|
static void dolink(const char *, const char *, bool);
|
||||||
static char **getfields(char *buf);
|
static char **getfields(char *buf);
|
||||||
static zic_t gethms(const char *string, const char *errstring,
|
static zic_t gethms(const char *string, const char *errstring,
|
||||||
bool);
|
bool);
|
||||||
@ -119,7 +119,7 @@ static bool inzsub(char **, int, bool);
|
|||||||
static int itsdir(const char *name);
|
static int itsdir(const char *name);
|
||||||
static bool is_alpha(char a);
|
static bool is_alpha(char a);
|
||||||
static char lowerit(char);
|
static char lowerit(char);
|
||||||
static bool mkdirs(char *);
|
static void mkdirs(char const *, bool);
|
||||||
static void newabbr(const char *abbr);
|
static void newabbr(const char *abbr);
|
||||||
static zic_t oadd(zic_t t1, zic_t t2);
|
static zic_t oadd(zic_t t1, zic_t t2);
|
||||||
static void outzone(const struct zone * zp, int ntzones);
|
static void outzone(const struct zone * zp, int ntzones);
|
||||||
@ -136,6 +136,15 @@ enum
|
|||||||
{
|
{
|
||||||
PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
|
PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
|
||||||
|
|
||||||
|
/* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
|
||||||
|
tz binary files whose POSIX-TZ-style strings contain '<'; see
|
||||||
|
QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
|
||||||
|
workaround will no longer be needed when Qt 5.6.1 and earlier are
|
||||||
|
obsolete, say in the year 2021. */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
WORK_AROUND_QTBUG_53071 = true};
|
||||||
|
|
||||||
static int charcnt;
|
static int charcnt;
|
||||||
static bool errors;
|
static bool errors;
|
||||||
static bool warnings;
|
static bool warnings;
|
||||||
@ -346,6 +355,7 @@ static const int len_years[2] = {
|
|||||||
static struct attype
|
static struct attype
|
||||||
{
|
{
|
||||||
zic_t at;
|
zic_t at;
|
||||||
|
bool dontmerge;
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
} *attypes;
|
} *attypes;
|
||||||
static zic_t gmtoffs[TZ_MAX_TYPES];
|
static zic_t gmtoffs[TZ_MAX_TYPES];
|
||||||
@ -410,7 +420,8 @@ growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
|
|||||||
return ptr;
|
return ptr;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX;
|
int nitems_max = INT_MAX - WORK_AROUND_QTBUG_53071;
|
||||||
|
int amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
|
||||||
|
|
||||||
if ((amax - 1) / 3 * 2 < *nitems_alloc)
|
if ((amax - 1) / 3 * 2 < *nitems_alloc)
|
||||||
memory_exhausted(_("int overflow"));
|
memory_exhausted(_("int overflow"));
|
||||||
@ -478,17 +489,17 @@ warning(const char *string,...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
close_file(FILE *stream, char const * name)
|
close_file(FILE *stream, char const * dir, char const * name)
|
||||||
{
|
{
|
||||||
char const *e = (ferror(stream) ? _("I/O error")
|
char const *e = (ferror(stream) ? _("I/O error")
|
||||||
: fclose(stream) != 0 ? strerror(errno) : NULL);
|
: fclose(stream) != 0 ? strerror(errno) : NULL);
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: ", progname);
|
fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
|
||||||
if (name)
|
dir ? dir : "", dir ? "/" : "",
|
||||||
fprintf(stderr, "%s: ", name);
|
name ? name : "", name ? ": " : "",
|
||||||
fprintf(stderr, "%s\n", e);
|
e);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,10 +514,34 @@ usage(FILE *stream, int status)
|
|||||||
"Report bugs to %s.\n"),
|
"Report bugs to %s.\n"),
|
||||||
progname, progname, PACKAGE_BUGREPORT);
|
progname, progname, PACKAGE_BUGREPORT);
|
||||||
if (status == EXIT_SUCCESS)
|
if (status == EXIT_SUCCESS)
|
||||||
close_file(stream, NULL);
|
close_file(stream, NULL, NULL);
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Change the working directory to DIR, possibly creating DIR and its
|
||||||
|
ancestors. After this is done, all files are accessed with names
|
||||||
|
relative to DIR. */
|
||||||
|
static void
|
||||||
|
change_directory(char const * dir)
|
||||||
|
{
|
||||||
|
if (chdir(dir) != 0)
|
||||||
|
{
|
||||||
|
int chdir_errno = errno;
|
||||||
|
|
||||||
|
if (chdir_errno == ENOENT)
|
||||||
|
{
|
||||||
|
mkdirs(dir, false);
|
||||||
|
chdir_errno = chdir(dir) == 0 ? 0 : errno;
|
||||||
|
}
|
||||||
|
if (chdir_errno != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
|
||||||
|
progname, dir, strerror(chdir_errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char *psxrules;
|
static const char *psxrules;
|
||||||
static const char *lcltime;
|
static const char *lcltime;
|
||||||
static const char *directory;
|
static const char *directory;
|
||||||
@ -534,7 +569,7 @@ main(int argc, char *argv[])
|
|||||||
if (strcmp(argv[i], "--version") == 0)
|
if (strcmp(argv[i], "--version") == 0)
|
||||||
{
|
{
|
||||||
printf("zic %s\n", PG_VERSION);
|
printf("zic %s\n", PG_VERSION);
|
||||||
close_file(stdout, NULL);
|
close_file(stdout, NULL, NULL);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "--help") == 0)
|
else if (strcmp(argv[i], "--help") == 0)
|
||||||
@ -630,6 +665,7 @@ main(int argc, char *argv[])
|
|||||||
if (errors)
|
if (errors)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
associate();
|
associate();
|
||||||
|
change_directory(directory);
|
||||||
for (i = 0; i < nzones; i = j)
|
for (i = 0; i < nzones; i = j)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -646,7 +682,7 @@ main(int argc, char *argv[])
|
|||||||
for (i = 0; i < nlinks; ++i)
|
for (i = 0; i < nlinks; ++i)
|
||||||
{
|
{
|
||||||
eat(links[i].l_filename, links[i].l_linenum);
|
eat(links[i].l_filename, links[i].l_linenum);
|
||||||
dolink(links[i].l_from, links[i].l_to);
|
dolink(links[i].l_from, links[i].l_to, false);
|
||||||
if (noise)
|
if (noise)
|
||||||
for (j = 0; j < nlinks; ++j)
|
for (j = 0; j < nlinks; ++j)
|
||||||
if (strcmp(links[i].l_to,
|
if (strcmp(links[i].l_to,
|
||||||
@ -656,12 +692,12 @@ main(int argc, char *argv[])
|
|||||||
if (lcltime != NULL)
|
if (lcltime != NULL)
|
||||||
{
|
{
|
||||||
eat(_("command line"), 1);
|
eat(_("command line"), 1);
|
||||||
dolink(lcltime, TZDEFAULT);
|
dolink(lcltime, TZDEFAULT, true);
|
||||||
}
|
}
|
||||||
if (psxrules != NULL)
|
if (psxrules != NULL)
|
||||||
{
|
{
|
||||||
eat(_("command line"), 1);
|
eat(_("command line"), 1);
|
||||||
dolink(psxrules, TZDEFRULES);
|
dolink(psxrules, TZDEFRULES, true);
|
||||||
}
|
}
|
||||||
if (warnings && (ferror(stderr) || fclose(stderr) != 0))
|
if (warnings && (ferror(stderr) || fclose(stderr) != 0))
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -751,63 +787,46 @@ namecheck(const char *name)
|
|||||||
return componentcheck(name, component, cp);
|
return componentcheck(name, component, cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
|
||||||
relname(char const * dir, char const * base)
|
|
||||||
{
|
|
||||||
if (*base == '/')
|
|
||||||
return ecpyalloc(base);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t dir_len = strlen(dir);
|
|
||||||
bool needs_slash = dir_len && dir[dir_len - 1] != '/';
|
|
||||||
char *result = emalloc(dir_len + needs_slash + strlen(base) + 1);
|
|
||||||
|
|
||||||
result[dir_len] = '/';
|
|
||||||
strcpy(result + dir_len + needs_slash, base);
|
|
||||||
return memcpy(result, dir, dir_len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dolink(char const * fromfield, char const * tofield)
|
dolink(char const * fromfield, char const * tofield, bool staysymlink)
|
||||||
{
|
{
|
||||||
char *fromname;
|
|
||||||
char *toname;
|
|
||||||
int fromisdir;
|
int fromisdir;
|
||||||
|
bool todirs_made = false;
|
||||||
fromname = relname(directory, fromfield);
|
int link_errno;
|
||||||
toname = relname(directory, tofield);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We get to be careful here since there's a fair chance of root running
|
* We get to be careful here since there's a fair chance of root running
|
||||||
* us.
|
* us.
|
||||||
*/
|
*/
|
||||||
fromisdir = itsdir(fromname);
|
fromisdir = itsdir(fromfield);
|
||||||
if (fromisdir)
|
if (fromisdir)
|
||||||
{
|
{
|
||||||
char const *e = strerror(fromisdir < 0 ? errno : EPERM);
|
char const *e = strerror(fromisdir < 0 ? errno : EPERM);
|
||||||
|
|
||||||
fprintf(stderr, _("%s: link from %s failed: %s"),
|
fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
|
||||||
progname, fromname, e);
|
progname, directory, fromfield, e);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (link(fromname, toname) != 0)
|
if (staysymlink)
|
||||||
|
staysymlink = itsdir(tofield) == 2;
|
||||||
|
if (remove(tofield) == 0)
|
||||||
|
todirs_made = true;
|
||||||
|
else if (errno != ENOENT)
|
||||||
{
|
{
|
||||||
int link_errno = errno;
|
char const *e = strerror(errno);
|
||||||
bool retry_if_link_supported = false;
|
|
||||||
|
|
||||||
if (link_errno == ENOENT || link_errno == ENOTSUP)
|
fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
|
||||||
{
|
progname, directory, tofield, e);
|
||||||
if (!mkdirs(toname))
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
retry_if_link_supported = true;
|
|
||||||
}
|
}
|
||||||
if ((link_errno == EEXIST || link_errno == ENOTSUP)
|
link_errno = (staysymlink ? ENOTSUP
|
||||||
&& itsdir(toname) == 0
|
: link(fromfield, tofield) == 0 ? 0 : errno);
|
||||||
&& (remove(toname) == 0 || errno == ENOENT))
|
if (link_errno == ENOENT && !todirs_made)
|
||||||
retry_if_link_supported = true;
|
{
|
||||||
if (retry_if_link_supported && link_errno != ENOTSUP)
|
mkdirs(tofield, true);
|
||||||
link_errno = link(fromname, toname) == 0 ? 0 : errno;
|
todirs_made = true;
|
||||||
|
link_errno = link(fromfield, tofield) == 0 ? 0 : errno;
|
||||||
|
}
|
||||||
if (link_errno != 0)
|
if (link_errno != 0)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SYMLINK
|
#ifdef HAVE_SYMLINK
|
||||||
@ -816,7 +835,7 @@ dolink(char const * fromfield, char const * tofield)
|
|||||||
char *p;
|
char *p;
|
||||||
size_t dotdots = 0;
|
size_t dotdots = 0;
|
||||||
char *symlinkcontents;
|
char *symlinkcontents;
|
||||||
int symlink_result;
|
int symlink_errno;
|
||||||
|
|
||||||
do
|
do
|
||||||
t = s;
|
t = s;
|
||||||
@ -829,9 +848,14 @@ dolink(char const * fromfield, char const * tofield)
|
|||||||
for (p = symlinkcontents; dotdots-- != 0; p += 3)
|
for (p = symlinkcontents; dotdots-- != 0; p += 3)
|
||||||
memcpy(p, "../", 3);
|
memcpy(p, "../", 3);
|
||||||
strcpy(p, t);
|
strcpy(p, t);
|
||||||
symlink_result = symlink(symlinkcontents, toname);
|
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;
|
||||||
|
}
|
||||||
free(symlinkcontents);
|
free(symlinkcontents);
|
||||||
if (symlink_result == 0)
|
if (symlink_errno == 0)
|
||||||
{
|
{
|
||||||
if (link_errno != ENOTSUP)
|
if (link_errno != ENOTSUP)
|
||||||
warning(_("symbolic link used because hard link failed: %s"),
|
warning(_("symbolic link used because hard link failed: %s"),
|
||||||
@ -844,39 +868,37 @@ dolink(char const * fromfield, char const * tofield)
|
|||||||
*tp;
|
*tp;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
fp = fopen(fromname, "rb");
|
fp = fopen(fromfield, "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
const char *e = strerror(errno);
|
char const *e = strerror(errno);
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
|
||||||
_("%s: Can't read %s: %s\n"),
|
progname, directory, fromfield, e);
|
||||||
progname, fromname, e);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
tp = fopen(toname, "wb");
|
tp = fopen(tofield, "wb");
|
||||||
if (!tp)
|
if (!tp)
|
||||||
{
|
{
|
||||||
const char *e = strerror(errno);
|
char const *e = strerror(errno);
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
|
||||||
_("%s: Can't create %s: %s\n"),
|
progname, directory, tofield, e);
|
||||||
progname, toname, e);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
while ((c = getc(fp)) != EOF)
|
while ((c = getc(fp)) != EOF)
|
||||||
putc(c, tp);
|
putc(c, tp);
|
||||||
close_file(fp, fromname);
|
close_file(fp, directory, fromfield);
|
||||||
close_file(tp, toname);
|
close_file(tp, directory, tofield);
|
||||||
if (link_errno != ENOTSUP)
|
if (link_errno != ENOTSUP)
|
||||||
warning(_("copy used because hard link failed: %s"),
|
warning(_("copy used because hard link failed: %s"),
|
||||||
strerror(link_errno));
|
strerror(link_errno));
|
||||||
|
else if (symlink_errno != ENOTSUP)
|
||||||
|
warning(_("copy used because symbolic link failed: %s"),
|
||||||
|
strerror(symlink_errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(fromname);
|
|
||||||
free(toname);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TIME_T_BITS_IN_FILE 64
|
#define TIME_T_BITS_IN_FILE 64
|
||||||
|
|
||||||
@ -888,10 +910,6 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
|
|||||||
* rounded downward to the negation of a power of two that is
|
* rounded downward to the negation of a power of two that is
|
||||||
* comfortably outside the error bounds.
|
* comfortably outside the error bounds.
|
||||||
*
|
*
|
||||||
* zic does not output time stamps before this, partly because they
|
|
||||||
* are physically suspect, and partly because GNOME mishandles them; see
|
|
||||||
* GNOME bug 730332 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>.
|
|
||||||
*
|
|
||||||
* For the time of the Big Bang, see:
|
* For the time of the Big Bang, see:
|
||||||
*
|
*
|
||||||
* Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
|
* Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
|
||||||
@ -913,26 +931,45 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
|
|||||||
#define BIG_BANG (- (((zic_t) 1) << 59))
|
#define BIG_BANG (- (((zic_t) 1) << 59))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const zic_t big_bang_time = BIG_BANG;
|
/* If true, work around GNOME bug 730332
|
||||||
|
<https://bugzilla.gnome.org/show_bug.cgi?id=730332>
|
||||||
|
by refusing to output time stamps before BIG_BANG.
|
||||||
|
Such time stamps are physically suspect anyway.
|
||||||
|
|
||||||
/* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
|
The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
|
||||||
|
this workaround will no longer be needed when GNOME 3.21 and
|
||||||
|
earlier are obsolete, say in the year 2021. */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
WORK_AROUND_GNOME_BUG_730332 = true};
|
||||||
|
|
||||||
|
static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332
|
||||||
|
? BIG_BANG
|
||||||
|
: MINVAL(zic_t, TIME_T_BITS_IN_FILE));
|
||||||
|
|
||||||
|
/* Return 1 if NAME is a directory, 2 if a symbolic link, 0 if
|
||||||
|
something else, -1 (setting errno) if trouble. */
|
||||||
static int
|
static int
|
||||||
itsdir(char const * name)
|
itsdir(char const * name)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int res = stat(name, &st);
|
int res = lstat(name, &st);
|
||||||
|
|
||||||
#ifdef S_ISDIR
|
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
return S_ISDIR(st.st_mode) != 0;
|
|
||||||
#endif
|
|
||||||
if (res == 0 || errno == EOVERFLOW)
|
|
||||||
{
|
{
|
||||||
char *nameslashdot = relname(name, ".");
|
#ifdef S_ISDIR
|
||||||
bool dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
|
return S_ISDIR(st.st_mode) ? 1 : S_ISLNK(st.st_mode) ? 2 : 0;
|
||||||
|
#else
|
||||||
|
size_t n = strlen(name);
|
||||||
|
char *nameslashdot = emalloc(n + 3);
|
||||||
|
bool dir;
|
||||||
|
|
||||||
|
memcpy(nameslashdot, name, n);
|
||||||
|
strcpy(&nameslashdot[n], &"/."[!(n && name[n - 1] != '/')]);
|
||||||
|
dir = lstat(nameslashdot, &st) == 0;
|
||||||
free(nameslashdot);
|
free(nameslashdot);
|
||||||
return dir;
|
return dir;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1129,7 +1166,7 @@ infile(const char *name)
|
|||||||
}
|
}
|
||||||
free(fields);
|
free(fields);
|
||||||
}
|
}
|
||||||
close_file(fp, filename);
|
close_file(fp, NULL, filename);
|
||||||
if (wantcont)
|
if (wantcont)
|
||||||
error(_("expected continuation line not found"));
|
error(_("expected continuation line not found"));
|
||||||
}
|
}
|
||||||
@ -1313,7 +1350,7 @@ inzsub(char **fields, int nfields, bool iscont)
|
|||||||
z.z_filename = filename;
|
z.z_filename = filename;
|
||||||
z.z_linenum = linenum;
|
z.z_linenum = linenum;
|
||||||
z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
|
z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
|
||||||
if ((cp = strchr(fields[i_format], '%')) != 0)
|
if ((cp = strchr(fields[i_format], '%')) != NULL)
|
||||||
{
|
{
|
||||||
if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
|
if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
|
||||||
|| strchr(fields[i_format], '/'))
|
|| strchr(fields[i_format], '/'))
|
||||||
@ -1491,7 +1528,7 @@ inleap(char **fields, int nfields)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t = tadd(t, tod);
|
t = tadd(t, tod);
|
||||||
if (t < big_bang_time)
|
if (t < early_time)
|
||||||
{
|
{
|
||||||
error(_("leap second precedes Big Bang"));
|
error(_("leap second precedes Big Bang"));
|
||||||
return;
|
return;
|
||||||
@ -1764,11 +1801,14 @@ writezone(const char *const name, const char *const string, char version)
|
|||||||
int timecnt32,
|
int timecnt32,
|
||||||
timei32;
|
timei32;
|
||||||
int pass;
|
int pass;
|
||||||
char *fullname;
|
|
||||||
static const struct tzhead tzh0;
|
static const struct tzhead tzh0;
|
||||||
static struct tzhead tzh;
|
static struct tzhead tzh;
|
||||||
zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1));
|
bool dir_checked = false;
|
||||||
void *typesptr = ats + timecnt;
|
zic_t one = 1;
|
||||||
|
zic_t y2038_boundary = one << 31;
|
||||||
|
int nats = timecnt + WORK_AROUND_QTBUG_53071;
|
||||||
|
zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1));
|
||||||
|
void *typesptr = ats + nats;
|
||||||
unsigned char *types = typesptr;
|
unsigned char *types = typesptr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1786,7 +1826,7 @@ writezone(const char *const name, const char *const string, char version)
|
|||||||
|
|
||||||
toi = 0;
|
toi = 0;
|
||||||
fromi = 0;
|
fromi = 0;
|
||||||
while (fromi < timecnt && attypes[fromi].at < big_bang_time)
|
while (fromi < timecnt && attypes[fromi].at < early_time)
|
||||||
++fromi;
|
++fromi;
|
||||||
for (; fromi < timecnt; ++fromi)
|
for (; fromi < timecnt; ++fromi)
|
||||||
{
|
{
|
||||||
@ -1799,8 +1839,9 @@ writezone(const char *const name, const char *const string, char version)
|
|||||||
attypes[fromi].type;
|
attypes[fromi].type;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (toi == 0 ||
|
if (toi == 0
|
||||||
attypes[toi - 1].type != attypes[fromi].type)
|
|| attypes[fromi].dontmerge
|
||||||
|
|| attypes[toi - 1].type != attypes[fromi].type)
|
||||||
attypes[toi++] = attypes[fromi];
|
attypes[toi++] = attypes[fromi];
|
||||||
}
|
}
|
||||||
timecnt = toi;
|
timecnt = toi;
|
||||||
@ -1818,6 +1859,20 @@ writezone(const char *const name, const char *const string, char version)
|
|||||||
types[i] = attypes[i].type;
|
types[i] = attypes[i].type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
|
||||||
|
* by inserting a no-op transition at time y2038_boundary - 1. This works
|
||||||
|
* only for timestamps before the boundary, which should be good enough in
|
||||||
|
* practice as QTBUG-53071 should be long-dead by 2038.
|
||||||
|
*/
|
||||||
|
if (WORK_AROUND_QTBUG_53071 && timecnt != 0
|
||||||
|
&& ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<'))
|
||||||
|
{
|
||||||
|
ats[timecnt] = y2038_boundary - 1;
|
||||||
|
types[timecnt] = types[timecnt - 1];
|
||||||
|
timecnt++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Correct for leap seconds.
|
* Correct for leap seconds.
|
||||||
*/
|
*/
|
||||||
@ -1862,29 +1917,35 @@ writezone(const char *const name, const char *const string, char version)
|
|||||||
--leapcnt32;
|
--leapcnt32;
|
||||||
++leapi32;
|
++leapi32;
|
||||||
}
|
}
|
||||||
fullname = relname(directory, name);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove old file, if any, to snap links.
|
* Remove old file, if any, to snap links.
|
||||||
*/
|
*/
|
||||||
if (itsdir(fullname) == 0 && remove(fullname) != 0 && errno != ENOENT)
|
if (remove(name) == 0)
|
||||||
|
dir_checked = true;
|
||||||
|
else if (errno != ENOENT)
|
||||||
{
|
{
|
||||||
const char *e = strerror(errno);
|
const char *e = strerror(errno);
|
||||||
|
|
||||||
fprintf(stderr, _("%s: Cannot remove %s: %s\n"),
|
fprintf(stderr, _("%s: Cannot remove %s/%s: %s\n"),
|
||||||
progname, fullname, e);
|
progname, directory, name, e);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if ((fp = fopen(fullname, "wb")) == NULL)
|
fp = fopen(name, "wb");
|
||||||
|
if (!fp)
|
||||||
{
|
{
|
||||||
if (!mkdirs(fullname))
|
int fopen_errno = errno;
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
if ((fp = fopen(fullname, "wb")) == NULL)
|
|
||||||
{
|
|
||||||
const char *e = strerror(errno);
|
|
||||||
|
|
||||||
fprintf(stderr, _("%s: Cannot create %s: %s\n"),
|
if (fopen_errno == ENOENT && !dir_checked)
|
||||||
progname, fullname, e);
|
{
|
||||||
|
mkdirs(name, true);
|
||||||
|
fp = fopen(name, "wb");
|
||||||
|
fopen_errno = errno;
|
||||||
|
}
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: Cannot create %s/%s: %s\n"),
|
||||||
|
progname, directory, name, strerror(fopen_errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2130,9 +2191,8 @@ writezone(const char *const name, const char *const string, char version)
|
|||||||
putc(ttisgmts[i], fp);
|
putc(ttisgmts[i], fp);
|
||||||
}
|
}
|
||||||
fprintf(fp, "\n%s\n", string);
|
fprintf(fp, "\n%s\n", string);
|
||||||
close_file(fp, fullname);
|
close_file(fp, directory, name);
|
||||||
free(ats);
|
free(ats);
|
||||||
free(fullname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char const *
|
static char const *
|
||||||
@ -2527,6 +2587,7 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||||||
int compat;
|
int compat;
|
||||||
bool do_extend;
|
bool do_extend;
|
||||||
char version;
|
char version;
|
||||||
|
int lastatmax = -1;
|
||||||
|
|
||||||
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
||||||
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
||||||
@ -2649,9 +2710,9 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||||||
*/
|
*/
|
||||||
stdoff = 0;
|
stdoff = 0;
|
||||||
zp = &zpfirst[i];
|
zp = &zpfirst[i];
|
||||||
usestart = i > 0 && (zp - 1)->z_untiltime > big_bang_time;
|
usestart = i > 0 && (zp - 1)->z_untiltime > early_time;
|
||||||
useuntil = i < (zonecount - 1);
|
useuntil = i < (zonecount - 1);
|
||||||
if (useuntil && zp->z_untiltime <= big_bang_time)
|
if (useuntil && zp->z_untiltime <= early_time)
|
||||||
continue;
|
continue;
|
||||||
gmtoff = zp->z_gmtoff;
|
gmtoff = zp->z_gmtoff;
|
||||||
eat(zp->z_filename, zp->z_linenum);
|
eat(zp->z_filename, zp->z_linenum);
|
||||||
@ -2670,7 +2731,7 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||||||
usestart = false;
|
usestart = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
addtt(big_bang_time, type);
|
addtt(early_time, type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for (year = min_year; year <= max_year; ++year)
|
for (year = min_year; year <= max_year; ++year)
|
||||||
@ -2792,6 +2853,10 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||||||
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
|
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
|
||||||
type = addtype(offset, ab, rp->r_stdoff != 0,
|
type = addtype(offset, ab, rp->r_stdoff != 0,
|
||||||
rp->r_todisstd, rp->r_todisgmt);
|
rp->r_todisstd, rp->r_todisgmt);
|
||||||
|
if (rp->r_hiyear == ZIC_MAX
|
||||||
|
&& !(0 <= lastatmax
|
||||||
|
&& ktime < attypes[lastatmax].at))
|
||||||
|
lastatmax = timecnt;
|
||||||
addtt(ktime, type);
|
addtt(ktime, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2827,6 +2892,8 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||||||
starttime = tadd(starttime, -gmtoff);
|
starttime = tadd(starttime, -gmtoff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (0 <= lastatmax)
|
||||||
|
attypes[lastatmax].dontmerge = true;
|
||||||
if (do_extend)
|
if (do_extend)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2850,22 +2917,8 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||||||
lastat = &attypes[i];
|
lastat = &attypes[i];
|
||||||
if (lastat->at < rpytime(&xr, max_year - 1))
|
if (lastat->at < rpytime(&xr, max_year - 1))
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Create new type code for the redundant entry, to prevent it
|
|
||||||
* being optimized away.
|
|
||||||
*/
|
|
||||||
if (typecnt >= TZ_MAX_TYPES)
|
|
||||||
{
|
|
||||||
error(_("too many local time types"));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
gmtoffs[typecnt] = gmtoffs[lastat->type];
|
|
||||||
isdsts[typecnt] = isdsts[lastat->type];
|
|
||||||
ttisstds[typecnt] = ttisstds[lastat->type];
|
|
||||||
ttisgmts[typecnt] = ttisgmts[lastat->type];
|
|
||||||
abbrinds[typecnt] = abbrinds[lastat->type];
|
|
||||||
++typecnt;
|
|
||||||
addtt(rpytime(&xr, max_year + 1), typecnt - 1);
|
addtt(rpytime(&xr, max_year + 1), typecnt - 1);
|
||||||
|
attypes[timecnt - 1].dontmerge = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writezone(zpfirst->z_name, envvar, version);
|
writezone(zpfirst->z_name, envvar, version);
|
||||||
@ -2877,8 +2930,8 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||||||
static void
|
static void
|
||||||
addtt(zic_t starttime, int type)
|
addtt(zic_t starttime, int type)
|
||||||
{
|
{
|
||||||
if (starttime <= big_bang_time ||
|
if (starttime <= early_time
|
||||||
(timecnt == 1 && attypes[0].at < big_bang_time))
|
|| (timecnt == 1 && attypes[0].at < early_time))
|
||||||
{
|
{
|
||||||
gmtoffs[0] = gmtoffs[type];
|
gmtoffs[0] = gmtoffs[type];
|
||||||
isdsts[0] = isdsts[type];
|
isdsts[0] = isdsts[type];
|
||||||
@ -2894,6 +2947,7 @@ addtt(zic_t starttime, int type)
|
|||||||
}
|
}
|
||||||
attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
|
attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
|
||||||
attypes[timecnt].at = starttime;
|
attypes[timecnt].at = starttime;
|
||||||
|
attypes[timecnt].dontmerge = false;
|
||||||
attypes[timecnt].type = type;
|
attypes[timecnt].type = type;
|
||||||
++timecnt;
|
++timecnt;
|
||||||
}
|
}
|
||||||
@ -3441,53 +3495,51 @@ newabbr(const char *string)
|
|||||||
charcnt += i;
|
charcnt += i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
/* Ensure that the directories of ARGNAME exist, by making any missing
|
||||||
mkdirs(char *argname)
|
ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
|
||||||
|
do it for ARGNAME too. Exit with failure if there is trouble. */
|
||||||
|
static void
|
||||||
|
mkdirs(char const * argname, bool ancestors)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
if (argname == NULL || *argname == '\0')
|
|
||||||
return true;
|
|
||||||
cp = name = ecpyalloc(argname);
|
cp = name = ecpyalloc(argname);
|
||||||
while ((cp = strchr(cp + 1, '/')) != NULL)
|
|
||||||
{
|
|
||||||
*cp = '\0';
|
|
||||||
#ifdef WIN32
|
|
||||||
|
|
||||||
/*
|
/* Do not mkdir a root directory, as it must exist. */
|
||||||
* DOS drive specifier?
|
#ifdef WIN32
|
||||||
*/
|
if (is_alpha(name[0]) && name[1] == ':')
|
||||||
if (is_alpha(name[0]) && name[1] == ':' && name[2] == '\0')
|
cp += 2;
|
||||||
|
#endif
|
||||||
|
while (*cp == '/')
|
||||||
|
cp++;
|
||||||
|
|
||||||
|
while (cp && ((cp = strchr(cp, '/')) || !ancestors))
|
||||||
{
|
{
|
||||||
*cp = '/';
|
if (cp)
|
||||||
continue;
|
*cp = '\0';
|
||||||
}
|
|
||||||
#endif /* WIN32 */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to create it. It's OK if creation fails because the directory
|
* Try to create it. It's OK if creation fails because the directory
|
||||||
* already exists, perhaps because some other process just created it.
|
* already exists, perhaps because some other process just created it.
|
||||||
|
* For simplicity do not check first whether it already exists, as
|
||||||
|
* that is checked anyway if the mkdir fails.
|
||||||
*/
|
*/
|
||||||
if (mkdir(name, MKDIR_UMASK) != 0)
|
if (mkdir(name, MKDIR_UMASK) != 0)
|
||||||
{
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
if (itsdir(name) <= 0)
|
if (err != EEXIST && itsdir(name) < 0)
|
||||||
{
|
{
|
||||||
char const *e = strerror(err);
|
error(_("%s: Cannot create directory %s: %s"),
|
||||||
|
progname, name, strerror(err));
|
||||||
warning(_("%s: Can't create directory"
|
exit(EXIT_FAILURE);
|
||||||
" %s: %s"),
|
|
||||||
progname, name, e);
|
|
||||||
free(name);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*cp = '/';
|
if (cp)
|
||||||
|
*cp++ = '/';
|
||||||
}
|
}
|
||||||
free(name);
|
free(name);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user