forked from pool/timezone
6b60f7e04a
1 OBS-URL: https://build.opensuse.org/request/show/379068 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/timezone?expand=0&rev=102
320 lines
9.3 KiB
Diff
320 lines
9.3 KiB
Diff
commit 39fd078a694fa762de5ae7efceca1dbfb7be94b3
|
||
Author: Paul Eggert <eggert@cs.ucla.edu>
|
||
Date: Fri Feb 26 03:33:54 2016 -0800
|
||
|
||
Port better to MS-Windows
|
||
|
||
Problems reported by Ian Abbott in:
|
||
http://mm.icann.org/pipermail/tz/2016-February/023286.html
|
||
http://mm.icann.org/pipermail/tz/2016-February/023287.html
|
||
* Makefile (CFLAGS): Add comment about new -D options.
|
||
* date.c (environ, optarg, optind, tzname):
|
||
* private.h (asctime_r, timezone, daylight, altzone):
|
||
* strftime.c (tzname):
|
||
* zdump.c (environ, getopt, optarg, optind, tzname):
|
||
* zic.c (getopt, link, optarg, optind):
|
||
Do not declare if HAVE_POSIX_DECLS, to avoid collisions with
|
||
system declarations, which is a problem with MS-Windows
|
||
and tzname and the dllimport attribute.
|
||
* date.c, zdump.c (tzname): Do not specify size, as POSIX doesn’t.
|
||
* private.h (HAVE_POSIX_DECLS): Default to 1.
|
||
(ENOTSUP): Default to EINVAL.
|
||
* zic.c: If HAVE_DIRECT_H, include direct.h and io.h and
|
||
define a mkdir macro, for MS-Windows.
|
||
(link, symlink): Set errno to ENOTSUP in the substitutes.
|
||
(dolink): Don’t complain merely because link and/or
|
||
symlink is not supported. Be a bit more economical and robust
|
||
about checking for directories and existing destinations.
|
||
Report errno-related string on link failures.
|
||
(itsdir): Work correctly even if a directory has a timestamp that
|
||
is out of time_t range, so that stat fails with errno ==
|
||
EOVERFLOW.
|
||
(writezone): Don’t remove files we can’t stat.
|
||
|
||
diff --git a/Makefile b/Makefile
|
||
index 568f7f6..20c2c98 100644
|
||
--- a/Makefile
|
||
+++ b/Makefile
|
||
@@ -106,6 +106,7 @@ LDLIBS=
|
||
|
||
# Add the following to the end of the "CFLAGS=" line as needed.
|
||
# -DBIG_BANG=-9999999LL if the Big Bang occurred at time -9999999 (see zic.c)
|
||
+# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
|
||
# -DHAVE_DOS_FILE_NAMES if file names have drive specifiers etc. (MS-DOS)
|
||
# -DHAVE_GETTEXT=1 if 'gettext' works (GNU, Linux, Solaris); also see LDLIBS
|
||
# -DHAVE_INCOMPATIBLE_CTIME_R=1 if your system's time.h declares
|
||
@@ -116,6 +117,8 @@ LDLIBS=
|
||
# -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
|
||
# This defaults to 1 if a working localtime_rz seems to be available.
|
||
# localtime_rz can make zdump significantly faster, but is nonstandard.
|
||
+# -DHAVE_POSIX_DECLS=0 if your system's include files do not declare
|
||
+# functions like 'link' or variables like 'tzname' required by POSIX
|
||
# -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h"
|
||
# -DHAVE_STRFTIME_L=1 if <time.h> declares locale_t and strftime_l
|
||
# This defaults to 0 if _POSIX_VERSION < 200809, 1 otherwise.
|
||
diff --git a/date.c b/date.c
|
||
index 824e57d..4c11f61 100644
|
||
--- a/date.c
|
||
+++ b/date.c
|
||
@@ -42,10 +42,12 @@
|
||
#define SECSPERMIN 60
|
||
#endif /* !defined SECSPERMIN */
|
||
|
||
+#if !HAVE_POSIX_DECLS
|
||
extern char ** environ;
|
||
extern char * optarg;
|
||
extern int optind;
|
||
-extern char * tzname[2];
|
||
+extern char * tzname[];
|
||
+#endif
|
||
|
||
static int retval = EXIT_SUCCESS;
|
||
|
||
diff --git a/private.h b/private.h
|
||
index 1c176e6..6080e71 100644
|
||
--- a/private.h
|
||
+++ b/private.h
|
||
@@ -34,6 +34,10 @@
|
||
#define HAVE_LINK 1
|
||
#endif /* !defined HAVE_LINK */
|
||
|
||
+#ifndef HAVE_POSIX_DECLS
|
||
+#define HAVE_POSIX_DECLS 1
|
||
+#endif
|
||
+
|
||
#ifndef HAVE_STRDUP
|
||
#define HAVE_STRDUP 1
|
||
#endif
|
||
@@ -106,6 +110,9 @@
|
||
#ifndef ENAMETOOLONG
|
||
# define ENAMETOOLONG EINVAL
|
||
#endif
|
||
+#ifndef ENOTSUP
|
||
+# define ENOTSUP EINVAL
|
||
+#endif
|
||
#ifndef EOVERFLOW
|
||
# define EOVERFLOW EINVAL
|
||
#endif
|
||
@@ -379,6 +386,8 @@ time_t time(time_t *);
|
||
void tzset(void);
|
||
#endif
|
||
|
||
+#if !HAVE_POSIX_DECLS
|
||
+
|
||
/*
|
||
** Some time.h implementations don't declare asctime_r.
|
||
** Others might define it as a macro.
|
||
@@ -402,6 +411,8 @@ extern int daylight;
|
||
extern long altzone;
|
||
#endif
|
||
|
||
+#endif
|
||
+
|
||
/*
|
||
** The STD_INSPIRED functions are similar, but most also need
|
||
** declarations if time_tz is defined.
|
||
diff --git a/strftime.c b/strftime.c
|
||
index 7a139bd..f75f9fd 100644
|
||
--- a/strftime.c
|
||
+++ b/strftime.c
|
||
@@ -106,7 +106,9 @@ static char * _fmt(const char *, const struct tm *, char *, const char *,
|
||
int *);
|
||
static char * _yconv(int, int, bool, bool, char *, char const *);
|
||
|
||
+#if !HAVE_POSIX_DECLS
|
||
extern char * tzname[];
|
||
+#endif
|
||
|
||
#ifndef YEAR_2000_NAME
|
||
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
|
||
diff --git a/zdump.c b/zdump.c
|
||
index 063a263..64d90f6 100644
|
||
--- a/zdump.c
|
||
+++ b/zdump.c
|
||
@@ -238,12 +238,14 @@ enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
|
||
# define timezone_t char **
|
||
#endif
|
||
|
||
+#if !HAVE_POSIX_DECLS
|
||
extern char ** environ;
|
||
extern int getopt(int argc, char * const argv[],
|
||
const char * options);
|
||
extern char * optarg;
|
||
extern int optind;
|
||
-extern char * tzname[2];
|
||
+extern char * tzname[];
|
||
+#endif
|
||
|
||
/* The minimum and maximum finite time values. */
|
||
enum { atime_shift = CHAR_BIT * sizeof (time_t) - 2 };
|
||
diff --git a/zic.c b/zic.c
|
||
index 78ab870..0ec3359 100644
|
||
--- a/zic.c
|
||
+++ b/zic.c
|
||
@@ -22,6 +22,13 @@ typedef int_fast64_t zic_t;
|
||
#define ZIC_MAX_ABBR_LEN_WO_WARN 6
|
||
#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
|
||
|
||
+#ifdef HAVE_DIRECT_H
|
||
+# include <direct.h>
|
||
+# include <io.h>
|
||
+# undef mkdir
|
||
+# define mkdir(name, mode) _mkdir(name)
|
||
+#endif
|
||
+
|
||
#if HAVE_SYS_STAT_H
|
||
#include <sys/stat.h>
|
||
#endif
|
||
@@ -87,17 +94,19 @@ struct zone {
|
||
zic_t z_untiltime;
|
||
};
|
||
|
||
+#if !HAVE_POSIX_DECLS
|
||
extern int getopt(int argc, char * const argv[],
|
||
const char * options);
|
||
extern int link(const char * fromname, const char * toname);
|
||
extern char * optarg;
|
||
extern int optind;
|
||
+#endif
|
||
|
||
#if ! HAVE_LINK
|
||
-# define link(from, to) (-1)
|
||
+# define link(from, to) (errno = ENOTSUP, -1)
|
||
#endif
|
||
#if ! HAVE_SYMLINK
|
||
-# define symlink(from, to) (-1)
|
||
+# define symlink(from, to) (errno = ENOTSUP, -1)
|
||
#endif
|
||
|
||
static void addtt(zic_t starttime, int type);
|
||
@@ -758,41 +767,47 @@ dolink(char const *fromfield, char const *tofield)
|
||
progname, fromname, e);
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
- if (itsdir(toname) <= 0)
|
||
- remove(toname);
|
||
if (link(fromname, toname) != 0) {
|
||
- int result;
|
||
+ int link_errno = errno;
|
||
+ bool retry_if_link_supported = false;
|
||
|
||
- if (! mkdirs(toname))
|
||
- exit(EXIT_FAILURE);
|
||
-
|
||
- result = link(fromname, toname);
|
||
- if (result != 0) {
|
||
- const char *s = fromfield;
|
||
- const char *t;
|
||
- char *p;
|
||
- size_t dotdots = 0;
|
||
- register char * symlinkcontents = NULL;
|
||
-
|
||
- do
|
||
- t = s;
|
||
- while ((s = strchr(s, '/'))
|
||
- && ! strncmp (fromfield, tofield,
|
||
- ++s - fromfield));
|
||
-
|
||
- 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);
|
||
- result = symlink(symlinkcontents, toname);
|
||
- if (result == 0)
|
||
-warning(_("hard link failed, symbolic link used"));
|
||
- free(symlinkcontents);
|
||
- }
|
||
- if (result != 0) {
|
||
+ if (link_errno == ENOENT || link_errno == ENOTSUP) {
|
||
+ if (! mkdirs(toname))
|
||
+ 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;
|
||
+ if (link_errno != 0) {
|
||
+ const char *s = fromfield;
|
||
+ const char *t;
|
||
+ char *p;
|
||
+ size_t dotdots = 0;
|
||
+ char *symlinkcontents;
|
||
+ int symlink_result;
|
||
+
|
||
+ 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_result = symlink(symlinkcontents, toname);
|
||
+ free(symlinkcontents);
|
||
+ if (symlink_result == 0) {
|
||
+ if (link_errno != ENOTSUP)
|
||
+ warning(_("symbolic link used because hard link failed: %s"),
|
||
+ strerror (link_errno));
|
||
+ } else {
|
||
FILE *fp, *tp;
|
||
int c;
|
||
fp = fopen(fromname, "rb");
|
||
@@ -815,8 +830,11 @@ warning(_("hard link failed, symbolic link used"));
|
||
putc(c, tp);
|
||
close_file(fp, fromname);
|
||
close_file(tp, toname);
|
||
- warning(_("link failed, copy used"));
|
||
- }
|
||
+ if (link_errno != ENOTSUP)
|
||
+ warning(_("copy used because hard link failed: %s"),
|
||
+ strerror (link_errno));
|
||
+ }
|
||
+ }
|
||
}
|
||
free(fromname);
|
||
free(toname);
|
||
@@ -863,18 +881,17 @@ itsdir(char const *name)
|
||
{
|
||
struct stat st;
|
||
int res = stat(name, &st);
|
||
- if (res != 0)
|
||
- return res;
|
||
#ifdef S_ISDIR
|
||
- return S_ISDIR(st.st_mode) != 0;
|
||
-#else
|
||
- {
|
||
+ if (res == 0)
|
||
+ return S_ISDIR(st.st_mode) != 0;
|
||
+#endif
|
||
+ if (res == 0 || errno == EOVERFLOW) {
|
||
char *nameslashdot = relname(name, ".");
|
||
- res = stat(nameslashdot, &st);
|
||
+ bool dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
|
||
free(nameslashdot);
|
||
- return res == 0;
|
||
+ return dir;
|
||
}
|
||
-#endif
|
||
+ return -1;
|
||
}
|
||
|
||
/*
|
||
@@ -1685,7 +1702,7 @@ writezone(const char *const name, const char *const string, char version)
|
||
/*
|
||
** Remove old file, if any, to snap links.
|
||
*/
|
||
- if (itsdir(fullname) <= 0 && remove(fullname) != 0 && errno != ENOENT) {
|
||
+ if (itsdir(fullname) == 0 && remove(fullname) != 0 && errno != ENOENT) {
|
||
const char *e = strerror(errno);
|
||
|
||
fprintf(stderr, _("%s: Can't remove %s: %s\n"),
|