From: Paul Eggert Date: Tue, 12 Nov 2024 00:25:50 +0000 (-0800) Subject: openat: port lowest-fd to native MS-Windows X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=22f3766d77fef397e9b99b944afe773de413b9b3;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index 29e63351b5..348fd1d27d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2024-11-11 Paul Eggert + + 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 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) {