[Resending, I had dropped perl5-porters by mistake, sorry.] On 2025-06-02 20:06:40 +0200, Florian Weimer wrote: > * Leon Timmermans: > > > On Mon, Jun 2, 2025 at 10:22 AM Florian Weimer via perl5-porters > > <perl5-port...@perl.org> wrote: > >> > >> * Stig Palmquist: > >> > >> > References > >> > ---------- > >> > https://github.com/Perl/perl5/commit/918bfff86ca8d6d4e4ec5b30994451e0bd74aba9.patch > >> > >> Is this fix really correct? > >> > >> + ret = fdopendir(dup(my_dirfd(dp))); > >> > >> This does not create a separate open file description, only a second > >> descriptor that shares the read position of the directory stream with > >> the original directory stream. I think you have to use something like > >> this: > >> > >> ret = fdopendir(openat(my_dirfd(dp), ".", O_DIRECTORY | O_CLOEXEC)); > > > > Our thread cloning in general is a terribly awkward business, where > > "what is the correct behavior" isn't always well defined or possible; > > I can see the arguments for both to be honest. > > > > For file descriptors we don't create new file descriptions either (we > > don't even create new file descriptors, we refcount them), so why > > should we do so for directory handles? I'm not sure that expectation > > makes sense in that context. > > That's a fair point. It's more like fork in this regard, which has > similar failure cases for DIR * objects (shared file description, but > unshared buffers and a separate descriptor). > > > And if we did go the openat way, I don't think that seekdir on the new > > handle with the telldir of the old one is necessarily valid if the > > directory has been changed (I mean even a rewinddir can invalidate > > telldir's return value). I don't think we can do a fully correct copy > > here. > > Ugh, I had not considered that. Yes, glibc will have to switch to an > implementation where telldir offsets are specific to a DIR * for certain > file systems on 32-bit architectures (because telldir returns long, not > off_t).
Another issue with ret = fdopendir(openat(my_dirfd(dp), ".", O_DIRECTORY | O_CLOEXEC)); is that this can fail if the directory permissions have changed: ------------------------------------------------------------------ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> int main (void) { const char *dirname = "tstdir-dir"; DIR *dir; int fd; errno = 0; if (mkdir (dirname, 0700) && errno != EEXIST) return 1; if (chmod (dirname, 0700)) return 2; fd = open (dirname, O_DIRECTORY | O_CLOEXEC); if (fd == -1) return 3; dir = fdopendir (fd); if (!dir) return 4; if (chmod (dirname, 0)) return 5; dir = fdopendir (openat (fd, ".", O_DIRECTORY | O_CLOEXEC)); printf ("dir = %p\n", (void *) dir); dir = fdopendir (dup (fd)); printf ("dir = %p\n", (void *) dir); return 0; } ------------------------------------------------------------------ outputs something like dir = (nil) dir = 0x56269b6316f0 -- Vincent Lefèvre <vinc...@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / Pascaline project (LIP, ENS-Lyon)