Line data Source code
1 : /* Define an at-style functions like fstatat, unlinkat, fchownat, etc.
2 : Copyright (C) 2006 Free Software Foundation, Inc.
3 :
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 3 of the License, or
7 : (at your option) any later version.
8 :
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.
13 :
14 : You should have received a copy of the GNU General Public License
15 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
16 :
17 : /* written by Jim Meyering */
18 :
19 : #define CALL_FUNC(F) \
20 : (AT_FUNC_USE_F1_COND \
21 : ? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS) \
22 : : AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
23 :
24 : /* Call AT_FUNC_F1 or AT_FUNC_F2 (testing AT_FUNC_USE_F1_COND to
25 : determine which) to operate on FILE, which is in the directory
26 : open on descriptor FD. If possible, do it without changing the
27 : working directory. Otherwise, resort to using save_cwd/fchdir,
28 : then AT_FUNC_F?/restore_cwd. If either the save_cwd or the restore_cwd
29 : fails, then give a diagnostic and exit nonzero. */
30 : int
31 133394 : AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
32 : {
33 : struct saved_cwd saved_cwd;
34 : int saved_errno;
35 : int err;
36 :
37 133394 : if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
38 16 : return CALL_FUNC (file);
39 :
40 : {
41 : char buf[OPENAT_BUFFER_SIZE];
42 133378 : char *proc_file = openat_proc_name (buf, fd, file);
43 133378 : if (proc_file)
44 : {
45 133378 : int proc_result = CALL_FUNC (proc_file);
46 133378 : int proc_errno = errno;
47 133378 : if (proc_file != buf)
48 0 : free (proc_file);
49 : /* If the syscall succeeds, or if it fails with an unexpected
50 : errno value, then return right away. Otherwise, fall through
51 : and resort to using save_cwd/restore_cwd. */
52 133378 : if (0 <= proc_result)
53 0 : return proc_result;
54 133378 : if (! EXPECTED_ERRNO (proc_errno))
55 : {
56 0 : errno = proc_errno;
57 0 : return proc_result;
58 : }
59 : }
60 : }
61 :
62 133378 : if (save_cwd (&saved_cwd) != 0)
63 0 : openat_save_fail (errno);
64 :
65 133378 : if (fchdir (fd) != 0)
66 : {
67 0 : saved_errno = errno;
68 0 : free_cwd (&saved_cwd);
69 0 : errno = saved_errno;
70 0 : return -1;
71 : }
72 :
73 133378 : err = CALL_FUNC (file);
74 133378 : saved_errno = (err < 0 ? errno : 0);
75 :
76 133378 : if (restore_cwd (&saved_cwd) != 0)
77 0 : openat_restore_fail (errno);
78 :
79 133378 : free_cwd (&saved_cwd);
80 :
81 133378 : if (saved_errno)
82 133378 : errno = saved_errno;
83 133378 : return err;
84 : }
85 : #undef CALL_FUNC
|