1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* provide a replacement fdopendir function
4 Copyright (C) 2004-2010 Free Software Foundation, Inc.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* written by Jim Meyering */
31 # include "openat-priv.h"
32 # include "save-cwd.h"
34 # if GNULIB_DIRENT_SAFER
35 # include "dirent--.h"
38 static DIR *fdopendir_with_dup (int, int);
39 static DIR *fd_clone_opendir (int);
41 /* Replacement for POSIX fdopendir.
43 First, try to simulate it via opendir ("/proc/self/fd/FD"). Failing
44 that, simulate it by using fchdir metadata, or by doing
45 save_cwd/fchdir/opendir(".")/restore_cwd.
46 If either the save_cwd or the restore_cwd fails (relatively unlikely),
47 then give a diagnostic and exit nonzero.
49 If successful, the resulting stream is based on FD in
50 implementations where streams are based on file descriptors and in
51 applications where no other thread or signal handler allocates or
52 frees file descriptors. In other cases, consult dirfd on the result
53 to find out whether FD is still being used.
55 Otherwise, this function works just like POSIX fdopendir.
59 Unlike other fd-related functions, this one places constraints on FD.
60 If this function returns successfully, FD is under control of the
61 dirent.h system, and the caller should not close or modify the state of
62 FD other than by the dirent.h functions. */
66 return fdopendir_with_dup (fd, -1);
69 /* Like fdopendir, except that if OLDER_DUPFD is not -1, it is known
70 to be a dup of FD which is less than FD - 1 and which will be
71 closed by the caller and not otherwise used by the caller. This
72 function makes sure that FD is closed and all file descriptors less
73 than FD are open, and then calls fd_clone_opendir on a dup of FD.
74 That way, barring race conditions, fd_clone_opendir returns a
75 stream whose file descriptor is FD. */
77 fdopendir_with_dup (int fd, int older_dupfd)
80 if (dupfd < 0 && errno == EMFILE)
88 if (dupfd < fd - 1 && dupfd != older_dupfd)
90 dir = fdopendir_with_dup (fd, dupfd);
96 dir = fd_clone_opendir (dupfd);
100 int fd1 = dup (dupfd);
102 openat_save_fail (fd1 < 0 ? errno : EBADF);
106 if (dupfd != older_dupfd)
113 /* Like fdopendir, except the result controls a clone of FD. It is
114 the caller's responsibility both to close FD and (if the result is
115 not null) to closedir the result. */
117 fd_clone_opendir (int fd)
122 char buf[OPENAT_BUFFER_SIZE];
123 char *proc_file = openat_proc_name (buf, fd, ".");
126 dir = opendir (proc_file);
132 saved_errno = EOPNOTSUPP;
135 /* If the syscall fails with an expected errno value, resort to
136 save_cwd/restore_cwd. */
137 if (! dir && EXPECTED_ERRNO (saved_errno))
140 const char *name = _gl_directory_name (fd);
142 dir = opendir (name);
144 # else /* !REPLACE_FCHDIR */
146 /* Occupy the destination FD slot, so that save_cwd cannot hijack it. */
147 int fd_reserve = dup (fd);
155 struct saved_cwd saved_cwd;
156 if (save_cwd (&saved_cwd) != 0)
157 openat_save_fail (errno);
159 /* Liberate the target file descriptor, so that opendir uses it. */
162 if (fchdir (fd) != 0)
172 if (restore_cwd (&saved_cwd) != 0)
173 openat_restore_fail (errno);
176 free_cwd (&saved_cwd);
177 # endif /* !REPLACE_FCHDIR */
181 if (proc_file != buf)
187 #else /* HAVE_FDOPENDIR */
190 # include <sys/stat.h>
194 /* Like fdopendir, but work around GNU/Hurd bug by validating FD. */
197 rpl_fdopendir (int fd)
202 if (!S_ISDIR (st.st_mode))
207 return fdopendir (fd);
210 #endif /* HAVE_FDOPENDIR */