123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- /* Define at-style functions like fstatat, unlinkat, fchownat, etc.
- Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
- /* written by Jim Meyering */
- #include "filename.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
- #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
- # include <errno.h>
- # ifndef ENOTSUP
- # define ENOTSUP EINVAL
- # endif
- #else
- # include "openat.h"
- # include "openat-priv.h"
- # include "save-cwd.h"
- #endif
- #ifdef AT_FUNC_USE_F1_COND
- # define CALL_FUNC(F) \
- (flag == AT_FUNC_USE_F1_COND \
- ? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS) \
- : AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
- # define VALIDATE_FLAG(F) \
- if (flag & ~AT_FUNC_USE_F1_COND) \
- { \
- errno = EINVAL; \
- return FUNC_FAIL; \
- }
- #else
- # define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS))
- # define VALIDATE_FLAG(F) /* empty */
- #endif
- #ifdef AT_FUNC_RESULT
- # define FUNC_RESULT AT_FUNC_RESULT
- #else
- # define FUNC_RESULT int
- #endif
- #ifdef AT_FUNC_FAIL
- # define FUNC_FAIL AT_FUNC_FAIL
- #else
- # define FUNC_FAIL -1
- #endif
- /* Call AT_FUNC_F1 to operate on FILE, which is in the directory
- open on descriptor FD. If AT_FUNC_USE_F1_COND is defined to a value,
- AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag;
- call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than
- AT_FUNC_USE_F1_COND. Return int and fail with -1 unless AT_FUNC_RESULT
- or AT_FUNC_FAIL are defined. If possible, do it without changing the
- working directory. Otherwise, resort to using save_cwd/fchdir,
- then AT_FUNC_F?/restore_cwd. If either the save_cwd or the restore_cwd
- fails, then give a diagnostic and exit nonzero. */
- FUNC_RESULT
- AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
- {
- VALIDATE_FLAG (flag);
- if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
- return CALL_FUNC (file);
- #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
- errno = ENOTSUP;
- return FUNC_FAIL;
- #else
- {
- /* Be careful to choose names unlikely to conflict with
- AT_FUNC_POST_FILE_PARAM_DECLS. */
- struct saved_cwd saved_cwd;
- int saved_errno;
- FUNC_RESULT err;
- {
- char proc_buf[OPENAT_BUFFER_SIZE];
- char *proc_file = openat_proc_name (proc_buf, fd, file);
- if (proc_file)
- {
- FUNC_RESULT proc_result = CALL_FUNC (proc_file);
- int proc_errno = errno;
- if (proc_file != proc_buf)
- free (proc_file);
- /* If the syscall succeeds, or if it fails with an unexpected
- errno value, then return right away. Otherwise, fall through
- and resort to using save_cwd/restore_cwd. */
- if (FUNC_FAIL != proc_result)
- return proc_result;
- if (! EXPECTED_ERRNO (proc_errno))
- {
- errno = proc_errno;
- return proc_result;
- }
- }
- }
- if (save_cwd (&saved_cwd) != 0)
- openat_save_fail (errno);
- if (0 <= fd && fd == saved_cwd.desc)
- {
- /* If saving the working directory collides with the user's
- requested fd, then the user's fd must have been closed to
- begin with. */
- free_cwd (&saved_cwd);
- errno = EBADF;
- return FUNC_FAIL;
- }
- if (fchdir (fd) != 0)
- {
- saved_errno = errno;
- free_cwd (&saved_cwd);
- errno = saved_errno;
- return FUNC_FAIL;
- }
- err = CALL_FUNC (file);
- saved_errno = (err == FUNC_FAIL ? errno : 0);
- if (restore_cwd (&saved_cwd) != 0)
- openat_restore_fail (errno);
- free_cwd (&saved_cwd);
- if (saved_errno)
- errno = saved_errno;
- return err;
- }
- #endif
- }
- #undef CALL_FUNC
- #undef FUNC_RESULT
- #undef FUNC_FAIL
|