On 2024-11-11 02:06, Bruno Haible wrote:
The test, intest-openat.c:94, is reasonable IMO: It verifies that the
openat() replacement for native Windows behaves the same as a POSIX-compliant
openat()....
What do you think? Should some module dependency be added to the 'openat'
module? Or to the 'save-cwd' module?

It's probably simpler to have the openat replacement return the lowest available fd as per POSIX. I installed the attached untested patch to try to do that, and we can see whether CI likes it.
From 22f3766d77fef397e9b99b944afe773de413b9b3 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Mon, 11 Nov 2024 16:25:50 -0800
Subject: [PATCH] openat: port lowest-fd to native MS-Windows

Problem reported by Bruno Haible in:
https://lists.gnu.org/r/bug-gnulib/2024-11/msg00081.html
* lib/openat.c (openat_permissive): When save_cwd allocates an FD,
allocate another one DFD and then close FD so that the later
open returns FD (the lowest available fd), as POSIX requires.
---
 ChangeLog    |  9 +++++++++
 lib/openat.c | 33 ++++++++++++++++++++++-----------
 2 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 29e63351b5..348fd1d27d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2024-11-11  Paul Eggert  <egg...@cs.ucla.edu>
+
+	openat: port lowest-fd to native MS-Windows
+	Problem reported by Bruno Haible in:
+	https://lists.gnu.org/r/bug-gnulib/2024-11/msg00081.html
+	* lib/openat.c (openat_permissive): When save_cwd allocates an FD,
+	allocate another one DFD and then close FD so that the later
+	open returns FD (the lowest available fd), as POSIX requires.
+
 2024-11-11  Bruno Haible  <br...@clisp.org>
 
 	fts: Fix dependencies (regression 2024-11-06).
diff --git a/lib/openat.c b/lib/openat.c
index 65cfc5ede4..698874427b 100644
--- a/lib/openat.c
+++ b/lib/openat.c
@@ -220,7 +220,6 @@ openat_permissive (int fd, char const *file, int flags, mode_t mode,
   struct saved_cwd saved_cwd;
   int saved_errno;
   int err;
-  bool save_ok;
 
   if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
     return open (file, flags, mode);
@@ -245,23 +244,35 @@ openat_permissive (int fd, char const *file, int flags, mode_t mode,
       }
   }
 
-  save_ok = (save_cwd (&saved_cwd) == 0);
-  if (! save_ok)
+  bool save_failed = save_cwd (&saved_cwd) < 0;
+
+  /* If save_cwd allocated a descriptor DFD other than FD, do another
+     save_cwd and then close DFD, so that the later open (if successful)
+     returns DFD (the lowest-numbered descriptor) as POSIX requires.  */
+  int dfd = saved_cwd.desc;
+  if (0 <= dfd && dfd != fd)
     {
-      if (! cwd_errno)
-        openat_save_fail (errno);
-      *cwd_errno = errno;
+      save_failed = save_cwd (&saved_cwd) < 0;
+      close (dfd);
+      dfd = saved_cwd.desc;
     }
-  if (0 <= fd && fd == saved_cwd.desc)
+
+  /* If saving the working directory collides with the user's requested fd,
+     then the user's fd must have been closed to begin with.  */
+  if (0 <= dfd && dfd == fd)
     {
-      /* If saving the working directory collides with the user's
-         requested fd, then the user's fd must have been closed to
-         begin with.  */
       free_cwd (&saved_cwd);
       errno = EBADF;
       return -1;
     }
 
+  if (save_failed)
+    {
+      if (! cwd_errno)
+        openat_save_fail (errno);
+      *cwd_errno = errno;
+    }
+
   err = fchdir (fd);
   saved_errno = errno;
 
@@ -269,7 +280,7 @@ openat_permissive (int fd, char const *file, int flags, mode_t mode,
     {
       err = open (file, flags, mode);
       saved_errno = errno;
-      if (save_ok && restore_cwd (&saved_cwd) != 0)
+      if (!save_failed && restore_cwd (&saved_cwd) != 0)
         {
           if (! cwd_errno)
             {
-- 
2.43.0

Reply via email to