1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* provide a replacement fdopendir function
4 Copyright (C) 2004-2011 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 # ifndef REPLACE_FCHDIR
39 # define REPLACE_FCHDIR 0
42 static DIR *fdopendir_with_dup (int, int, struct saved_cwd const *);
43 static DIR *fd_clone_opendir (int, struct saved_cwd const *);
45 /* Replacement for POSIX fdopendir.
47 First, try to simulate it via opendir ("/proc/self/fd/..."). Failing
48 that, simulate it by using fchdir metadata, or by doing
49 save_cwd/fchdir/opendir(".")/restore_cwd.
50 If either the save_cwd or the restore_cwd fails (relatively unlikely),
51 then give a diagnostic and exit nonzero.
53 If successful, the resulting stream is based on FD in
54 implementations where streams are based on file descriptors and in
55 applications where no other thread or signal handler allocates or
56 frees file descriptors. In other cases, consult dirfd on the result
57 to find out whether FD is still being used.
59 Otherwise, this function works just like POSIX fdopendir.
63 Unlike other fd-related functions, this one places constraints on FD.
64 If this function returns successfully, FD is under control of the
65 dirent.h system, and the caller should not close or modify the state of
66 FD other than by the dirent.h functions. */
70 DIR *dir = fdopendir_with_dup (fd, -1, NULL);
72 if (! REPLACE_FCHDIR && ! dir)
74 int saved_errno = errno;
75 if (EXPECTED_ERRNO (saved_errno))
78 if (save_cwd (&cwd) != 0)
79 openat_save_fail (errno);
80 dir = fdopendir_with_dup (fd, -1, &cwd);
90 /* Like fdopendir, except that if OLDER_DUPFD is not -1, it is known
91 to be a dup of FD which is less than FD - 1 and which will be
92 closed by the caller and not otherwise used by the caller. This
93 function makes sure that FD is closed and all file descriptors less
94 than FD are open, and then calls fd_clone_opendir on a dup of FD.
95 That way, barring race conditions, fd_clone_opendir returns a
96 stream whose file descriptor is FD.
98 If REPLACE_CHDIR or CWD is null, use opendir ("/proc/self/fd/...",
99 falling back on fchdir metadata. Otherwise, CWD is a saved version
100 of the working directory; use fchdir/opendir(".")/restore_cwd(CWD). */
102 fdopendir_with_dup (int fd, int older_dupfd, struct saved_cwd const *cwd)
104 int dupfd = dup (fd);
105 if (dupfd < 0 && errno == EMFILE)
113 if (dupfd < fd - 1 && dupfd != older_dupfd)
115 dir = fdopendir_with_dup (fd, dupfd, cwd);
121 dir = fd_clone_opendir (dupfd, cwd);
125 int fd1 = dup (dupfd);
127 openat_save_fail (fd1 < 0 ? errno : EBADF);
131 if (dupfd != older_dupfd)
138 /* Like fdopendir, except the result controls a clone of FD. It is
139 the caller's responsibility both to close FD and (if the result is
140 not null) to closedir the result. */
142 fd_clone_opendir (int fd, struct saved_cwd const *cwd)
144 if (REPLACE_FCHDIR || ! cwd)
147 int saved_errno = EOPNOTSUPP;
148 char buf[OPENAT_BUFFER_SIZE];
149 char *proc_file = openat_proc_name (buf, fd, ".");
152 dir = opendir (proc_file);
154 if (proc_file != buf)
158 if (! dir && EXPECTED_ERRNO (saved_errno))
160 char const *name = _gl_directory_name (fd);
161 return (name ? opendir (name) : NULL);
169 if (fchdir (fd) != 0)
173 DIR *dir = opendir (".");
174 int saved_errno = errno;
175 if (restore_cwd (cwd) != 0)
176 openat_restore_fail (errno);
183 #else /* HAVE_FDOPENDIR */
186 # include <sys/stat.h>
190 /* Like fdopendir, but work around GNU/Hurd bug by validating FD. */
193 rpl_fdopendir (int fd)
198 if (!S_ISDIR (st.st_mode))
203 return fdopendir (fd);
206 #endif /* HAVE_FDOPENDIR */