1 /* provide a replacement openat function
2 Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* written by Jim Meyering */
27 #include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
31 #include "openat-priv.h"
34 /* Replacement for Solaris' openat function.
35 <http://www.google.com/search?q=openat+site:docs.sun.com>
36 First, try to simulate it via open ("/proc/self/fd/FD/FILE").
37 Failing that, simulate it by doing save_cwd/fchdir/open/restore_cwd.
38 If either the save_cwd or the restore_cwd fails (relatively unlikely),
39 then give a diagnostic and exit nonzero.
40 Otherwise, upon failure, set errno and return -1, as openat does.
41 Upon successful completion, return a file descriptor. */
43 openat (int fd, char const *file, int flags, ...)
50 va_start (arg, flags);
52 /* If mode_t is narrower than int, use the promoted type (int),
53 not mode_t. Use sizeof to guess whether mode_t is narrower;
54 we don't know of any practical counterexamples. */
55 mode = (sizeof (mode_t) < sizeof (int)
57 : va_arg (arg, mode_t));
62 return openat_permissive (fd, file, flags, mode, NULL);
65 /* Like openat (FD, FILE, FLAGS, MODE), but if CWD_ERRNO is
66 nonnull, set *CWD_ERRNO to an errno value if unable to save
67 or restore the initial working directory. This is needed only
68 the first time remove.c's remove_dir opens a command-line
71 If a previous attempt to restore the current working directory
72 failed, then we must not even try to access a `.'-relative name.
73 It is the caller's responsibility not to call this function
77 openat_permissive (int fd, char const *file, int flags, mode_t mode,
80 struct saved_cwd saved_cwd;
85 if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
86 return open (file, flags, mode);
89 char buf[OPENAT_BUFFER_SIZE];
90 char *proc_file = openat_proc_name (buf, fd, file);
93 int open_result = open (proc_file, flags, mode);
94 int open_errno = errno;
97 /* If the syscall succeeds, or if it fails with an unexpected
98 errno value, then return right away. Otherwise, fall through
99 and resort to using save_cwd/restore_cwd. */
100 if (0 <= open_result || ! EXPECTED_ERRNO (open_errno))
108 save_ok = (save_cwd (&saved_cwd) == 0);
112 openat_save_fail (errno);
121 err = open (file, flags, mode);
123 if (save_ok && restore_cwd (&saved_cwd) != 0)
126 openat_restore_fail (errno);
131 free_cwd (&saved_cwd);
136 /* Return true if our openat implementation must resort to
137 using save_cwd and restore_cwd. */
139 openat_needs_fchdir (void)
141 bool needs_fchdir = true;
142 int fd = open ("/", O_RDONLY);
146 char buf[OPENAT_BUFFER_SIZE];
147 char *proc_file = openat_proc_name (buf, fd, ".");
150 needs_fchdir = false;
151 if (proc_file != buf)
162 /* Replacement for Solaris' function by the same name.
163 <http://www.google.com/search?q=fdopendir+site:docs.sun.com>
164 First, try to simulate it via opendir ("/proc/self/fd/FD"). Failing
165 that, simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd.
166 If either the save_cwd or the restore_cwd fails (relatively unlikely),
167 then give a diagnostic and exit nonzero.
168 Otherwise, this function works just like Solaris' fdopendir.
171 Unlike the other fd-related functions here, this one
172 effectively consumes its FD parameter. The caller should not
173 close or otherwise manipulate FD if this function returns successfully. */
177 struct saved_cwd saved_cwd;
181 char buf[OPENAT_BUFFER_SIZE];
182 char *proc_file = openat_proc_name (buf, fd, ".");
185 dir = opendir (proc_file);
191 saved_errno = EOPNOTSUPP;
194 /* If the syscall fails with an expected errno value, resort to
195 save_cwd/restore_cwd. */
196 if (! dir && EXPECTED_ERRNO (saved_errno))
198 if (save_cwd (&saved_cwd) != 0)
199 openat_save_fail (errno);
201 if (fchdir (fd) != 0)
211 if (restore_cwd (&saved_cwd) != 0)
212 openat_restore_fail (errno);
215 free_cwd (&saved_cwd);
220 if (proc_file != buf)
228 /* Replacement for Solaris' function by the same name.
229 <http://www.google.com/search?q=fstatat+site:docs.sun.com>
230 First, try to simulate it via l?stat ("/proc/self/fd/FD/FILE").
231 Failing that, simulate it via save_cwd/fchdir/(stat|lstat)/restore_cwd.
232 If either the save_cwd or the restore_cwd fails (relatively unlikely),
233 then give a diagnostic and exit nonzero.
234 Otherwise, this function works just like Solaris' fstatat. */
236 #define AT_FUNC_NAME fstatat
237 #define AT_FUNC_F1 lstat
238 #define AT_FUNC_F2 stat
239 #define AT_FUNC_USE_F1_COND flag == AT_SYMLINK_NOFOLLOW
240 #define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat *st, int flag
241 #define AT_FUNC_POST_FILE_ARGS , st
246 #undef AT_FUNC_USE_F1_COND
247 #undef AT_FUNC_POST_FILE_PARAM_DECLS
248 #undef AT_FUNC_POST_FILE_ARGS
250 /* Replacement for Solaris' function by the same name.
251 <http://www.google.com/search?q=unlinkat+site:docs.sun.com>
252 First, try to simulate it via (unlink|rmdir) ("/proc/self/fd/FD/FILE").
253 Failing that, simulate it via save_cwd/fchdir/(unlink|rmdir)/restore_cwd.
254 If either the save_cwd or the restore_cwd fails (relatively unlikely),
255 then give a diagnostic and exit nonzero.
256 Otherwise, this function works just like Solaris' unlinkat. */
258 #define AT_FUNC_NAME unlinkat
259 #define AT_FUNC_F1 rmdir
260 #define AT_FUNC_F2 unlink
261 #define AT_FUNC_USE_F1_COND flag == AT_REMOVEDIR
262 #define AT_FUNC_POST_FILE_PARAM_DECLS , int flag
263 #define AT_FUNC_POST_FILE_ARGS /* empty */
268 #undef AT_FUNC_USE_F1_COND
269 #undef AT_FUNC_POST_FILE_PARAM_DECLS
270 #undef AT_FUNC_POST_FILE_ARGS