On 2025-10-20 05:00, Manuela Friedrich wrote:
After removing   -DHAVE_POSIX_DECLS=0  we got these failures

Instead of removing -DHAVE_POSIX_DECLS=0, please add -DHAVE_DIRECT_H; this should fix the mkdir part of the problem.

Also, I just now installed the attached patch to address the umask part of the problem; please give it a try.

Thanks for following up on this.
From 8d65db9786753f3b263087e31c59d191561d63e3 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Mon, 20 Oct 2025 09:11:01 -0700
Subject: [PROPOSED] Prefer fdopen to umask in zic

Improve zic by using fdopen instead of umask to create TZif files
with permissions other than the default 0666-modified-by-umask.
Because tzcode predates POSIX.1-1988 (which standardized fdopen)
it used the umask trick instead of fdopen.
However, as demonstrated by Manuela Friedrich in:
https://lists.iana.org/hyperkitty/list/[email protected]/thread/2ASUTQ6MXJJFXDYQPWHWA2SN2E2HOWZX/
and followups, the umask trick is a hassle to port to MS-Windows.
The umask trick also makes it harder to add a reliable -m option
in the style of FreeBSD, whose zic -m has subtle bugs
due to its use of umask.
* NEWS: Mention this.
* zic.c (O_BINARY): Default to 0, as in localtime.c.
(umask): Remove macro and/or decl; no longer used.
(S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH)
(S_IWOTH, S_IXOTH, S_IRWXU, S_IRWXG, S_IRWXO):
Default to POSIX.1-2008+ values; this is cleaner than
using octal numbers everywhere else.
All uses of octal numbers changed.
(CREAT_PERMS): New macro.
(main): Do not call umask.
(open_outfile): Use fdopen with CREAT_MASK rather than relying
on umask.  This avoids problems with umask on MS-Windows,
and likely simplifies future improvements.
---
 NEWS  |  5 ++++
 zic.c | 76 +++++++++++++++++++++++++++++++++--------------------------
 2 files changed, 47 insertions(+), 34 deletions(-)

diff --git a/NEWS b/NEWS
index 46bf48ed..8253cfb6 100644
--- a/NEWS
+++ b/NEWS
@@ -102,6 +102,11 @@ Unreleased, experimental changes
     exceedingly long TZ strings no longer fail merely because they
     exceed an arbitrary file name length limit imposed by tzcode.
 
+    zic now uses the fdopen function, which was standardized by
+    POSIX.1-1988 and is now safe to use in portable code.
+    This replaces its use of the older umask function, which
+    complicated maintenance.
+
   Changes to commentary
 
     The leapseconds file contains commentary about the IERS and NIST
diff --git a/zic.c b/zic.c
index b1923438..67bcaa43 100644
--- a/zic.c
+++ b/zic.c
@@ -18,6 +18,10 @@
 #include "tzfile.h"
 
 #include <fcntl.h>
+#ifndef O_BINARY
+# define O_BINARY 0 /* MS-Windows */
+#endif
+
 #include <locale.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -50,9 +54,6 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 };
 # ifndef mkdir
 #  define mkdir(name, mode) _mkdir(name)
 # endif
-# ifndef umask
-#  define umask(mode) _umask(mode)
-# endif
 #endif
 
 #ifndef HAVE_GETRANDOM
@@ -73,23 +74,35 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 };
 # include <sys/stat.h>
 #endif
 
-#ifdef S_IRWXU
+#ifndef S_IRWXU
+# define S_IRUSR 0400
+# define S_IWUSR 0200
+# define S_IXUSR 0100
+# define S_IRGRP 0040
+# define S_IWGRP 0020
+# define S_IXGRP 0010
+# define S_IROTH 0004
+# define S_IWOTH 0002
+# define S_IXOTH 0001
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#endif
+
 /* All file permission bits.  */
-# define ALL_PERMS (S_IRWXU | S_IRWXG | S_IRWXO)
+#define ALL_PERMS (S_IRWXU | S_IRWXG | S_IRWXO)
 
 /* Troublesome file permission bits.  */
-# define TROUBLE_PERMS (S_IWGRP | S_IWOTH)
-#else
-# define ALL_PERMS	0777
-# define TROUBLE_PERMS	0022
-#endif
+#define TROUBLE_PERMS (S_IWGRP | S_IWOTH)
 
 /* File permission bits for making directories.
-   The initial umask modifies these bits.
-   Although the "& ~TROUBLE_PERMS" is redundant because we remove
-   TROUBLE_PERMS from the umask early on, the redundancy does not hurt.  */
+   The umask modifies these bits.  */
 #define MKDIR_PERMS (ALL_PERMS & ~TROUBLE_PERMS)
 
+/* File permission bits for making regular files.
+   The umask modifies these bits.  */
+#define CREAT_PERMS (MKDIR_PERMS & ~(S_IXUSR | S_IXGRP | S_IXOTH))
+
 
 /* The minimum alignment of a type, for pre-C23 platforms.
    The __SUNPRO_C test is because Oracle Developer Studio 12.6 lacks
@@ -172,9 +185,6 @@ extern int	link(const char * target, const char * linkname);
 # ifndef mkdir
 extern int	mkdir(char const *, mode_t);
 # endif
-# ifndef umask
-extern mode_t	umask(mode_t);
-# endif
 extern char *	optarg;
 extern int	optind;
 #endif
@@ -1014,10 +1024,6 @@ main(int argc, char **argv)
 	register ptrdiff_t i, j;
 	bool timerange_given = false;
 
-	/* Adjust umask so that created files lack troublesome permission bits.
-	   Needed because regular files are created via fopen not openat.  */
-	umask(umask(TROUBLE_PERMS) | TROUBLE_PERMS);
-
 #if HAVE_GETTEXT
 	setlocale(LC_ALL, "");
 # ifdef TZ_DOMAINDIR
@@ -1401,33 +1407,35 @@ diagslash(char const *filename)
 static FILE *
 open_outfile(char const **outname, char **tempname)
 {
-#if __STDC_VERSION__ < 201112
-  static char const fopen_mode[] = "wb";
-#else
-  static char const fopen_mode[] = "wbx";
-#endif
-
-  FILE *fp;
   bool dirs_made = false;
   if (!*tempname)
     random_dirent(outname, tempname);
 
-  while (! (fp = fopen(*outname, fopen_mode))) {
-    int fopen_errno = errno;
-    if (fopen_errno == ENOENT && !dirs_made) {
+  while (true) {
+    int oflags = O_WRONLY | O_BINARY | O_CREAT | O_EXCL;
+    int fd = open(*outname, oflags, CREAT_PERMS);
+    int err;
+    if (fd < 0)
+      err = errno;
+    else {
+      FILE *fp = fdopen(fd, "wb");
+      if (fp)
+	return fp;
+      err = errno;
+      close(fd);
+    }
+    if (err == ENOENT && !dirs_made) {
       mkdirs(*outname, true);
       dirs_made = true;
-    } else if (fopen_errno == EEXIST)
+    } else if (err == EEXIST)
       random_dirent(outname, tempname);
     else {
       fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"),
 	      progname, diagdir(*outname), diagslash(*outname), *outname,
-	      strerror(fopen_errno));
+	      strerror(err));
       exit(EXIT_FAILURE);
     }
   }
-
-  return fp;
 }
 
 /* If TEMPNAME, the result is in the temporary file TEMPNAME even
-- 
2.51.0

Reply via email to