Blame lib/at-func.c

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