mirror of https://github.com/postgres/postgres
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);
|
||||
|
||||
/*
|
||||
* Could get fancy here and deliver something such as "UT+xxxx" or
|
||||
* "UT-xxxx" if offset is non-zero, but this is no time for a treasure
|
||||
* hunt.
|
||||
* Could get fancy here and deliver something such as "+xx" or "-xx" if
|
||||
* offset is non-zero, but this is no time for a treasure hunt.
|
||||
*/
|
||||
if (offset != 0)
|
||||
tmp->tm_zone = wildabbr;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#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"
|
||||
|
||||
/*
|
||||
|
|
|
@ -128,7 +128,7 @@ pg_strftime(char *s, size_t maxsize, const char *format,
|
|||
int warn;
|
||||
|
||||
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)
|
||||
return 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 adjleap(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 zic_t gethms(const char *string, const char *errstring,
|
||||
bool);
|
||||
|
@ -119,7 +119,7 @@ static bool inzsub(char **, int, bool);
|
|||
static int itsdir(const char *name);
|
||||
static bool is_alpha(char a);
|
||||
static char lowerit(char);
|
||||
static bool mkdirs(char *);
|
||||
static void mkdirs(char const *, bool);
|
||||
static void newabbr(const char *abbr);
|
||||
static zic_t oadd(zic_t t1, zic_t t2);
|
||||
static void outzone(const struct zone * zp, int ntzones);
|
||||
|
@ -136,6 +136,15 @@ enum
|
|||
{
|
||||
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 bool errors;
|
||||
static bool warnings;
|
||||
|
@ -346,6 +355,7 @@ static const int len_years[2] = {
|
|||
static struct attype
|
||||
{
|
||||
zic_t at;
|
||||
bool dontmerge;
|
||||
unsigned char type;
|
||||
} *attypes;
|
||||
static zic_t gmtoffs[TZ_MAX_TYPES];
|
||||
|
@ -410,7 +420,8 @@ growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
|
|||
return ptr;
|
||||
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)
|
||||
memory_exhausted(_("int overflow"));
|
||||
|
@ -478,17 +489,17 @@ warning(const char *string,...)
|
|||
}
|
||||
|
||||
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")
|
||||
: fclose(stream) != 0 ? strerror(errno) : NULL);
|
||||
|
||||
if (e)
|
||||
{
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
if (name)
|
||||
fprintf(stderr, "%s: ", name);
|
||||
fprintf(stderr, "%s\n", e);
|
||||
fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
|
||||
dir ? dir : "", dir ? "/" : "",
|
||||
name ? name : "", name ? ": " : "",
|
||||
e);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
@ -503,10 +514,34 @@ usage(FILE *stream, int status)
|
|||
"Report bugs to %s.\n"),
|
||||
progname, progname, PACKAGE_BUGREPORT);
|
||||
if (status == EXIT_SUCCESS)
|
||||
close_file(stream, NULL);
|
||||
close_file(stream, NULL, NULL);
|
||||
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 *lcltime;
|
||||
static const char *directory;
|
||||
|
@ -534,7 +569,7 @@ main(int argc, char *argv[])
|
|||
if (strcmp(argv[i], "--version") == 0)
|
||||
{
|
||||
printf("zic %s\n", PG_VERSION);
|
||||
close_file(stdout, NULL);
|
||||
close_file(stdout, NULL, NULL);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
else if (strcmp(argv[i], "--help") == 0)
|
||||
|
@ -630,6 +665,7 @@ main(int argc, char *argv[])
|
|||
if (errors)
|
||||
return EXIT_FAILURE;
|
||||
associate();
|
||||
change_directory(directory);
|
||||
for (i = 0; i < nzones; i = j)
|
||||
{
|
||||
/*
|
||||
|
@ -646,7 +682,7 @@ main(int argc, char *argv[])
|
|||
for (i = 0; i < nlinks; ++i)
|
||||
{
|
||||
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)
|
||||
for (j = 0; j < nlinks; ++j)
|
||||
if (strcmp(links[i].l_to,
|
||||
|
@ -656,12 +692,12 @@ main(int argc, char *argv[])
|
|||
if (lcltime != NULL)
|
||||
{
|
||||
eat(_("command line"), 1);
|
||||
dolink(lcltime, TZDEFAULT);
|
||||
dolink(lcltime, TZDEFAULT, true);
|
||||
}
|
||||
if (psxrules != NULL)
|
||||
{
|
||||
eat(_("command line"), 1);
|
||||
dolink(psxrules, TZDEFRULES);
|
||||
dolink(psxrules, TZDEFRULES, true);
|
||||
}
|
||||
if (warnings && (ferror(stderr) || fclose(stderr) != 0))
|
||||
return EXIT_FAILURE;
|
||||
|
@ -751,63 +787,46 @@ namecheck(const char *name)
|
|||
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
|
||||
dolink(char const * fromfield, char const * tofield)
|
||||
dolink(char const * fromfield, char const * tofield, bool staysymlink)
|
||||
{
|
||||
char *fromname;
|
||||
char *toname;
|
||||
int fromisdir;
|
||||
|
||||
fromname = relname(directory, fromfield);
|
||||
toname = relname(directory, tofield);
|
||||
bool todirs_made = false;
|
||||
int link_errno;
|
||||
|
||||
/*
|
||||
* We get to be careful here since there's a fair chance of root running
|
||||
* us.
|
||||
*/
|
||||
fromisdir = itsdir(fromname);
|
||||
fromisdir = itsdir(fromfield);
|
||||
if (fromisdir)
|
||||
{
|
||||
char const *e = strerror(fromisdir < 0 ? errno : EPERM);
|
||||
|
||||
fprintf(stderr, _("%s: link from %s failed: %s"),
|
||||
progname, fromname, e);
|
||||
fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
|
||||
progname, directory, fromfield, e);
|
||||
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;
|
||||
bool retry_if_link_supported = false;
|
||||
char const *e = strerror(errno);
|
||||
|
||||
if (link_errno == ENOENT || link_errno == ENOTSUP)
|
||||
{
|
||||
if (!mkdirs(toname))
|
||||
fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
|
||||
progname, directory, tofield, e);
|
||||
exit(EXIT_FAILURE);
|
||||
retry_if_link_supported = true;
|
||||
}
|
||||
if ((link_errno == EEXIST || link_errno == ENOTSUP)
|
||||
&& itsdir(toname) == 0
|
||||
&& (remove(toname) == 0 || errno == ENOENT))
|
||||
retry_if_link_supported = true;
|
||||
if (retry_if_link_supported && link_errno != ENOTSUP)
|
||||
link_errno = link(fromname, toname) == 0 ? 0 : errno;
|
||||
link_errno = (staysymlink ? ENOTSUP
|
||||
: link(fromfield, tofield) == 0 ? 0 : errno);
|
||||
if (link_errno == ENOENT && !todirs_made)
|
||||
{
|
||||
mkdirs(tofield, true);
|
||||
todirs_made = true;
|
||||
link_errno = link(fromfield, tofield) == 0 ? 0 : errno;
|
||||
}
|
||||
if (link_errno != 0)
|
||||
{
|
||||
#ifdef HAVE_SYMLINK
|
||||
|
@ -816,7 +835,7 @@ dolink(char const * fromfield, char const * tofield)
|
|||
char *p;
|
||||
size_t dotdots = 0;
|
||||
char *symlinkcontents;
|
||||
int symlink_result;
|
||||
int symlink_errno;
|
||||
|
||||
do
|
||||
t = s;
|
||||
|
@ -829,9 +848,14 @@ dolink(char const * fromfield, char const * tofield)
|
|||
for (p = symlinkcontents; dotdots-- != 0; p += 3)
|
||||
memcpy(p, "../", 3);
|
||||
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);
|
||||
if (symlink_result == 0)
|
||||
if (symlink_errno == 0)
|
||||
{
|
||||
if (link_errno != ENOTSUP)
|
||||
warning(_("symbolic link used because hard link failed: %s"),
|
||||
|
@ -844,38 +868,36 @@ dolink(char const * fromfield, char const * tofield)
|
|||
*tp;
|
||||
int c;
|
||||
|
||||
fp = fopen(fromname, "rb");
|
||||
fp = fopen(fromfield, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
const char *e = strerror(errno);
|
||||
char const *e = strerror(errno);
|
||||
|
||||
fprintf(stderr,
|
||||
_("%s: Can't read %s: %s\n"),
|
||||
progname, fromname, e);
|
||||
fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
|
||||
progname, directory, fromfield, e);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
tp = fopen(toname, "wb");
|
||||
tp = fopen(tofield, "wb");
|
||||
if (!tp)
|
||||
{
|
||||
const char *e = strerror(errno);
|
||||
char const *e = strerror(errno);
|
||||
|
||||
fprintf(stderr,
|
||||
_("%s: Can't create %s: %s\n"),
|
||||
progname, toname, e);
|
||||
fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
|
||||
progname, directory, tofield, e);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while ((c = getc(fp)) != EOF)
|
||||
putc(c, tp);
|
||||
close_file(fp, fromname);
|
||||
close_file(tp, toname);
|
||||
close_file(fp, directory, fromfield);
|
||||
close_file(tp, directory, tofield);
|
||||
if (link_errno != ENOTSUP)
|
||||
warning(_("copy used because hard link failed: %s"),
|
||||
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
|
||||
|
@ -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
|
||||
* 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:
|
||||
*
|
||||
* 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))
|
||||
#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
|
||||
itsdir(char const * name)
|
||||
{
|
||||
struct stat st;
|
||||
int res = stat(name, &st);
|
||||
int res = lstat(name, &st);
|
||||
|
||||
#ifdef S_ISDIR
|
||||
if (res == 0)
|
||||
return S_ISDIR(st.st_mode) != 0;
|
||||
#endif
|
||||
if (res == 0 || errno == EOVERFLOW)
|
||||
{
|
||||
char *nameslashdot = relname(name, ".");
|
||||
bool dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
|
||||
#ifdef S_ISDIR
|
||||
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);
|
||||
return dir;
|
||||
#endif
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -1129,7 +1166,7 @@ infile(const char *name)
|
|||
}
|
||||
free(fields);
|
||||
}
|
||||
close_file(fp, filename);
|
||||
close_file(fp, NULL, filename);
|
||||
if (wantcont)
|
||||
error(_("expected continuation line not found"));
|
||||
}
|
||||
|
@ -1313,7 +1350,7 @@ inzsub(char **fields, int nfields, bool iscont)
|
|||
z.z_filename = filename;
|
||||
z.z_linenum = linenum;
|
||||
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, '%')
|
||||
|| strchr(fields[i_format], '/'))
|
||||
|
@ -1491,7 +1528,7 @@ inleap(char **fields, int nfields)
|
|||
return;
|
||||
}
|
||||
t = tadd(t, tod);
|
||||
if (t < big_bang_time)
|
||||
if (t < early_time)
|
||||
{
|
||||
error(_("leap second precedes Big Bang"));
|
||||
return;
|
||||
|
@ -1764,11 +1801,14 @@ writezone(const char *const name, const char *const string, char version)
|
|||
int timecnt32,
|
||||
timei32;
|
||||
int pass;
|
||||
char *fullname;
|
||||
static const struct tzhead tzh0;
|
||||
static struct tzhead tzh;
|
||||
zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1));
|
||||
void *typesptr = ats + timecnt;
|
||||
bool dir_checked = false;
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -1786,7 +1826,7 @@ writezone(const char *const name, const char *const string, char version)
|
|||
|
||||
toi = 0;
|
||||
fromi = 0;
|
||||
while (fromi < timecnt && attypes[fromi].at < big_bang_time)
|
||||
while (fromi < timecnt && attypes[fromi].at < early_time)
|
||||
++fromi;
|
||||
for (; fromi < timecnt; ++fromi)
|
||||
{
|
||||
|
@ -1799,8 +1839,9 @@ writezone(const char *const name, const char *const string, char version)
|
|||
attypes[fromi].type;
|
||||
continue;
|
||||
}
|
||||
if (toi == 0 ||
|
||||
attypes[toi - 1].type != attypes[fromi].type)
|
||||
if (toi == 0
|
||||
|| attypes[fromi].dontmerge
|
||||
|| attypes[toi - 1].type != attypes[fromi].type)
|
||||
attypes[toi++] = attypes[fromi];
|
||||
}
|
||||
timecnt = toi;
|
||||
|
@ -1818,6 +1859,20 @@ writezone(const char *const name, const char *const string, char version)
|
|||
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.
|
||||
*/
|
||||
|
@ -1862,29 +1917,35 @@ writezone(const char *const name, const char *const string, char version)
|
|||
--leapcnt32;
|
||||
++leapi32;
|
||||
}
|
||||
fullname = relname(directory, name);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
fprintf(stderr, _("%s: Cannot remove %s: %s\n"),
|
||||
progname, fullname, e);
|
||||
fprintf(stderr, _("%s: Cannot remove %s/%s: %s\n"),
|
||||
progname, directory, name, e);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ((fp = fopen(fullname, "wb")) == NULL)
|
||||
fp = fopen(name, "wb");
|
||||
if (!fp)
|
||||
{
|
||||
if (!mkdirs(fullname))
|
||||
exit(EXIT_FAILURE);
|
||||
if ((fp = fopen(fullname, "wb")) == NULL)
|
||||
{
|
||||
const char *e = strerror(errno);
|
||||
int fopen_errno = errno;
|
||||
|
||||
fprintf(stderr, _("%s: Cannot create %s: %s\n"),
|
||||
progname, fullname, e);
|
||||
if (fopen_errno == ENOENT && !dir_checked)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -2130,9 +2191,8 @@ writezone(const char *const name, const char *const string, char version)
|
|||
putc(ttisgmts[i], fp);
|
||||
}
|
||||
fprintf(fp, "\n%s\n", string);
|
||||
close_file(fp, fullname);
|
||||
close_file(fp, directory, name);
|
||||
free(ats);
|
||||
free(fullname);
|
||||
}
|
||||
|
||||
static char const *
|
||||
|
@ -2527,6 +2587,7 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||
int compat;
|
||||
bool do_extend;
|
||||
char version;
|
||||
int lastatmax = -1;
|
||||
|
||||
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
||||
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
||||
|
@ -2649,9 +2710,9 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||
*/
|
||||
stdoff = 0;
|
||||
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);
|
||||
if (useuntil && zp->z_untiltime <= big_bang_time)
|
||||
if (useuntil && zp->z_untiltime <= early_time)
|
||||
continue;
|
||||
gmtoff = zp->z_gmtoff;
|
||||
eat(zp->z_filename, zp->z_linenum);
|
||||
|
@ -2670,7 +2731,7 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||
usestart = false;
|
||||
}
|
||||
else
|
||||
addtt(big_bang_time, type);
|
||||
addtt(early_time, type);
|
||||
}
|
||||
else
|
||||
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);
|
||||
type = addtype(offset, ab, rp->r_stdoff != 0,
|
||||
rp->r_todisstd, rp->r_todisgmt);
|
||||
if (rp->r_hiyear == ZIC_MAX
|
||||
&& !(0 <= lastatmax
|
||||
&& ktime < attypes[lastatmax].at))
|
||||
lastatmax = timecnt;
|
||||
addtt(ktime, type);
|
||||
}
|
||||
}
|
||||
|
@ -2827,6 +2892,8 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||
starttime = tadd(starttime, -gmtoff);
|
||||
}
|
||||
}
|
||||
if (0 <= lastatmax)
|
||||
attypes[lastatmax].dontmerge = true;
|
||||
if (do_extend)
|
||||
{
|
||||
/*
|
||||
|
@ -2850,22 +2917,8 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||
lastat = &attypes[i];
|
||||
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);
|
||||
attypes[timecnt - 1].dontmerge = true;
|
||||
}
|
||||
}
|
||||
writezone(zpfirst->z_name, envvar, version);
|
||||
|
@ -2877,8 +2930,8 @@ outzone(const struct zone * zpfirst, int zonecount)
|
|||
static void
|
||||
addtt(zic_t starttime, int type)
|
||||
{
|
||||
if (starttime <= big_bang_time ||
|
||||
(timecnt == 1 && attypes[0].at < big_bang_time))
|
||||
if (starttime <= early_time
|
||||
|| (timecnt == 1 && attypes[0].at < early_time))
|
||||
{
|
||||
gmtoffs[0] = gmtoffs[type];
|
||||
isdsts[0] = isdsts[type];
|
||||
|
@ -2894,6 +2947,7 @@ addtt(zic_t starttime, int type)
|
|||
}
|
||||
attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
|
||||
attypes[timecnt].at = starttime;
|
||||
attypes[timecnt].dontmerge = false;
|
||||
attypes[timecnt].type = type;
|
||||
++timecnt;
|
||||
}
|
||||
|
@ -3441,53 +3495,51 @@ newabbr(const char *string)
|
|||
charcnt += i;
|
||||
}
|
||||
|
||||
static bool
|
||||
mkdirs(char *argname)
|
||||
/* Ensure that the directories of ARGNAME exist, by making any missing
|
||||
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 *cp;
|
||||
|
||||
if (argname == NULL || *argname == '\0')
|
||||
return true;
|
||||
cp = name = ecpyalloc(argname);
|
||||
while ((cp = strchr(cp + 1, '/')) != NULL)
|
||||
{
|
||||
*cp = '\0';
|
||||
#ifdef WIN32
|
||||
|
||||
/*
|
||||
* DOS drive specifier?
|
||||
*/
|
||||
if (is_alpha(name[0]) && name[1] == ':' && name[2] == '\0')
|
||||
/* Do not mkdir a root directory, as it must exist. */
|
||||
#ifdef WIN32
|
||||
if (is_alpha(name[0]) && name[1] == ':')
|
||||
cp += 2;
|
||||
#endif
|
||||
while (*cp == '/')
|
||||
cp++;
|
||||
|
||||
while (cp && ((cp = strchr(cp, '/')) || !ancestors))
|
||||
{
|
||||
*cp = '/';
|
||||
continue;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
if (cp)
|
||||
*cp = '\0';
|
||||
|
||||
/*
|
||||
* Try to create it. It's OK if creation fails because the directory
|
||||
* 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)
|
||||
{
|
||||
int err = errno;
|
||||
|
||||
if (itsdir(name) <= 0)
|
||||
if (err != EEXIST && itsdir(name) < 0)
|
||||
{
|
||||
char const *e = strerror(err);
|
||||
|
||||
warning(_("%s: Can't create directory"
|
||||
" %s: %s"),
|
||||
progname, name, e);
|
||||
free(name);
|
||||
return false;
|
||||
error(_("%s: Cannot create directory %s: %s"),
|
||||
progname, name, strerror(err));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
*cp = '/';
|
||||
if (cp)
|
||||
*cp++ = '/';
|
||||
}
|
||||
free(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue