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 */
26 #include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
28 #include "openat-priv.h"
36 /* Replacement for Solaris' openat function.
37 <http://www.google.com/search?q=openat+site:docs.sun.com>
38 Simulate it by doing save_cwd/fchdir/open/restore_cwd.
39 If either the save_cwd or the restore_cwd fails (relatively unlikely,
40 and usually indicative of a problem that deserves close attention),
41 then give a diagnostic and exit nonzero.
42 Otherwise, upon failure, set errno and return -1, as openat does.
43 Upon successful completion, return a file descriptor. */
45 openat (int fd, char const *file, int flags, ...)
52 va_start (arg, flags);
54 /* If mode_t is narrower than int, use the promoted type (int),
55 not mode_t. Use sizeof to guess whether mode_t is narrower;
56 we don't know of any practical counterexamples. */
57 mode = (sizeof (mode_t) < sizeof (int)
59 : va_arg (arg, mode_t));
64 return openat_permissive (fd, file, flags, mode, NULL);
67 /* Like openat (FD, FILE, FLAGS, MODE), but if CWD_ERRNO is
68 nonnull, set *CWD_ERRNO to an errno value if unable to save
69 or restore the initial working directory. This is needed only
70 the first time remove.c's remove_dir opens a command-line
73 If a previous attempt to restore the current working directory
74 failed, then we must not even try to access a `.'-relative name.
75 It is the caller's responsibility not to call this function
79 openat_permissive (int fd, char const *file, int flags, mode_t mode,
82 struct saved_cwd saved_cwd;
87 if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
88 return open (file, flags, mode);
92 BUILD_PROC_NAME (proc_file, fd, file);
93 err = open (proc_file, flags, mode);
94 /* If the syscall succeeds, or if it fails with an unexpected
95 errno value, then return right away. Otherwise, fall through
96 and resort to using save_cwd/restore_cwd. */
97 if (0 <= err || ! EXPECTED_ERRNO (errno))
101 save_ok = (save_cwd (&saved_cwd) == 0);
105 openat_save_fail (errno);
114 err = open (file, flags, mode);
116 if (save_ok && restore_cwd (&saved_cwd) != 0)
119 openat_restore_fail (errno);
124 free_cwd (&saved_cwd);
131 /* Replacement for Solaris' function by the same name.
132 <http://www.google.com/search?q=fdopendir+site:docs.sun.com>
133 Simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd.
134 If either the save_cwd or the restore_cwd fails (relatively unlikely,
135 and usually indicative of a problem that deserves close attention),
136 then give a diagnostic and exit nonzero.
137 Otherwise, this function works just like Solaris' fdopendir.
140 Unlike the other fd-related functions here, this one
141 effectively consumes its FD parameter. The caller should not
142 close or otherwise manipulate FD if this function returns successfully. */
146 struct saved_cwd saved_cwd;
151 BUILD_PROC_NAME (proc_file, fd, ".");
152 dir = opendir (proc_file);
155 /* If the syscall fails with an expected errno value, resort to
156 save_cwd/restore_cwd. */
157 if (! dir && EXPECTED_ERRNO (saved_errno))
159 if (save_cwd (&saved_cwd) != 0)
160 openat_save_fail (errno);
162 if (fchdir (fd) != 0)
172 if (restore_cwd (&saved_cwd) != 0)
173 openat_restore_fail (errno);
176 free_cwd (&saved_cwd);
187 /* Replacement for Solaris' function by the same name.
188 <http://www.google.com/search?q=fstatat+site:docs.sun.com>
189 Simulate it by doing save_cwd/fchdir/(stat|lstat)/restore_cwd.
190 If either the save_cwd or the restore_cwd fails (relatively unlikely,
191 and usually indicative of a problem that deserves close attention),
192 then give a diagnostic and exit nonzero.
193 Otherwise, this function works just like Solaris' fstatat. */
195 fstatat (int fd, char const *file, struct stat *st, int flag)
197 struct saved_cwd saved_cwd;
201 if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
202 return (flag == AT_SYMLINK_NOFOLLOW
208 BUILD_PROC_NAME (proc_file, fd, file);
209 err = (flag == AT_SYMLINK_NOFOLLOW
210 ? lstat (proc_file, st)
211 : stat (proc_file, st));
212 /* If the syscall succeeds, or if it fails with an unexpected
213 errno value, then return right away. Otherwise, fall through
214 and resort to using save_cwd/restore_cwd. */
215 if (0 <= err || ! EXPECTED_ERRNO (errno))
219 if (save_cwd (&saved_cwd) != 0)
220 openat_save_fail (errno);
227 err = (flag == AT_SYMLINK_NOFOLLOW
232 if (restore_cwd (&saved_cwd) != 0)
233 openat_restore_fail (errno);
236 free_cwd (&saved_cwd);
241 /* Replacement for Solaris' function by the same name.
242 <http://www.google.com/search?q=unlinkat+site:docs.sun.com>
243 Simulate it by doing save_cwd/fchdir/(unlink|rmdir)/restore_cwd.
244 If either the save_cwd or the restore_cwd fails (relatively unlikely,
245 and usually indicative of a problem that deserves close attention),
246 then give a diagnostic and exit nonzero.
247 Otherwise, this function works just like Solaris' unlinkat. */
249 unlinkat (int fd, char const *file, int flag)
251 struct saved_cwd saved_cwd;
255 if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
256 return (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file));
260 BUILD_PROC_NAME (proc_file, fd, file);
261 err = (flag == AT_REMOVEDIR ? rmdir (proc_file) : unlink (proc_file));
262 /* If the syscall succeeds, or if it fails with an unexpected
263 errno value, then return right away. Otherwise, fall through
264 and resort to using save_cwd/restore_cwd. */
265 if (0 <= err || ! EXPECTED_ERRNO (errno))
269 if (save_cwd (&saved_cwd) != 0)
270 openat_save_fail (errno);
277 err = (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file));
280 if (restore_cwd (&saved_cwd) != 0)
281 openat_restore_fail (errno);
284 free_cwd (&saved_cwd);