[tz] [PROPOSED PATCH 4/5] Keep localtime, posixrules symlinks if already
Paul Eggert
eggert at cs.ucla.edu
Tue Sep 6 04:40:36 UTC 2016
* NEWS: Document this.
* zic.c (dolink): New arg STAYSYMLINK. All callers changed.
If true, use symlink rather than link if the destination is
already a symlink.
(itsdir): Return 2 if a symlink, for the benefit of dolink.
---
NEWS | 5 +++
zic.c | 139 +++++++++++++++++++++++++++++++++---------------------------------
2 files changed, 75 insertions(+), 69 deletions(-)
diff --git a/NEWS b/NEWS
index a2a57fc..7f92e17 100644
--- a/NEWS
+++ b/NEWS
@@ -55,6 +55,11 @@ Unreleased, experimental changes
stamps on the reference platform. (Thanks to Alexander Belopolsky
for reporting the bug and suggesting a way forward.)
+ If the installed localtime and/or posixrules files are symbolic
+ links, zic now keeps them symbolic links when updating them, for
+ compatibility with platforms like OpenSUSE where other programs
+ configure these files as symlinks.
+
zic now avoids hard linking to symbolic links, and avoids some
unnecessary mkdir and stat system calls.
diff --git a/zic.c b/zic.c
index 1c8a193..011b3cc 100644
--- a/zic.c
+++ b/zic.c
@@ -116,7 +116,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);
@@ -653,7 +653,7 @@ _("%s: More than one -L option specified\n"),
*/
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,
@@ -662,11 +662,11 @@ _("%s: More than one -L option specified\n"),
}
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;
@@ -759,12 +759,13 @@ relname(char const *dir, char const *base)
}
static void
-dolink(char const *fromfield, char const *tofield)
+dolink(char const *fromfield, char const *tofield, bool staysymlink)
{
register char * fromname;
register char * toname;
register int fromisdir;
int todirs_made = -1;
+ int link_errno;
fromname = relname(directory, fromfield);
toname = relname(directory, tofield);
@@ -779,6 +780,8 @@ dolink(char const *fromfield, char const *tofield)
progname, fromname, e);
exit(EXIT_FAILURE);
}
+ if (staysymlink)
+ staysymlink = itsdir(toname) == 2;
if (remove(toname) == 0)
todirs_made = 0;
else if (errno != ENOENT) {
@@ -786,69 +789,67 @@ dolink(char const *fromfield, char const *tofield)
fprintf(stderr, _("%s: Can't remove %s: %s\n"), progname, toname, e);
exit(EXIT_FAILURE);
}
- if (link(fromname, toname) != 0) {
- int link_errno = errno;
-
- if (link_errno == ENOENT && todirs_made < 0) {
- todirs_made = mkdirs(toname);
- if (todirs_made)
- 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);
- if (symlink_result != 0 && errno == ENOENT
- && todirs_made < 0 && mkdirs(toname))
- 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");
- if (!fp) {
- const char *e = strerror(errno);
- fprintf(stderr,
- _("%s: Can't read %s: %s\n"),
- progname, fromname, e);
- exit(EXIT_FAILURE);
- }
- tp = fopen(toname, "wb");
- if (!tp) {
- const char *e = strerror(errno);
- fprintf(stderr,
- _("%s: Can't create %s: %s\n"),
- progname, toname, e);
- exit(EXIT_FAILURE);
- }
- while ((c = getc(fp)) != EOF)
- putc(c, tp);
- close_file(fp, fromname);
- close_file(tp, toname);
- if (link_errno != ENOTSUP)
- warning(_("copy used because hard link failed: %s"),
- strerror (link_errno));
+ link_errno = (staysymlink ? ENOTSUP
+ : link(fromname, toname) == 0 ? 0 : errno);
+ if (link_errno == ENOENT && todirs_made < 0) {
+ todirs_made = mkdirs(toname);
+ if (todirs_made)
+ 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_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, toname) == 0 ? 0 : errno;
+ if (symlink_errno == ENOENT && todirs_made < 0 && mkdirs(toname))
+ symlink_errno = symlink(symlinkcontents, toname) == 0 ? 0 : errno;
+ free(symlinkcontents);
+ if (symlink_errno == 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");
+ if (!fp) {
+ char const *e = strerror(errno);
+ fprintf(stderr, _("%s: Can't read %s: %s\n"),
+ progname, fromname, e);
+ exit(EXIT_FAILURE);
+ }
+ tp = fopen(toname, "wb");
+ if (!tp) {
+ char const *e = strerror(errno);
+ fprintf(stderr, _("%s: Can't create %s: %s\n"),
+ progname, toname, e);
+ exit(EXIT_FAILURE);
}
+ while ((c = getc(fp)) != EOF)
+ putc(c, tp);
+ close_file(fp, fromname);
+ close_file(tp, toname);
+ 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);
@@ -898,7 +899,7 @@ 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 or a symbolic link, 0 if it's
+/* 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)
@@ -907,7 +908,7 @@ itsdir(char const *name)
int res = lstat(name, &st);
if (res == 0) {
#ifdef S_ISDIR
- return S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode);
+ return S_ISDIR(st.st_mode) ? 1 : S_ISLNK(st.st_mode) ? 2 : 0;
#else
char *nameslashdot = relname(name, ".");
bool dir = lstat(nameslashdot, &st) == 0;
--
2.7.4
More information about the tz
mailing list