root/maint/gnulib/lib/at-func.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AT_FUNC_NAME

   1 /* Define at-style functions like fstatat, unlinkat, fchownat, etc.
   2    Copyright (C) 2006, 2009-2021 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 <https://www.gnu.org/licenses/>.  */
  16 
  17 /* written by Jim Meyering */
  18 
  19 #include "filename.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
  20 
  21 #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
  22 # include <errno.h>
  23 # ifndef ENOTSUP
  24 #  define ENOTSUP EINVAL
  25 # endif
  26 #else
  27 # include "openat.h"
  28 # include "openat-priv.h"
  29 # include "save-cwd.h"
  30 #endif
  31 
  32 #ifdef AT_FUNC_USE_F1_COND
  33 # define CALL_FUNC(F)                           \
  34   (flag == AT_FUNC_USE_F1_COND                  \
  35     ? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS)     \
  36     : AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
  37 # define VALIDATE_FLAG(F)                       \
  38   if (flag & ~AT_FUNC_USE_F1_COND)              \
  39     {                                           \
  40       errno = EINVAL;                           \
  41       return FUNC_FAIL;                         \
  42     }
  43 #else
  44 # define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS))
  45 # define VALIDATE_FLAG(F) /* empty */
  46 #endif
  47 
  48 #ifdef AT_FUNC_RESULT
  49 # define FUNC_RESULT AT_FUNC_RESULT
  50 #else
  51 # define FUNC_RESULT int
  52 #endif
  53 
  54 #ifdef AT_FUNC_FAIL
  55 # define FUNC_FAIL AT_FUNC_FAIL
  56 #else
  57 # define FUNC_FAIL -1
  58 #endif
  59 
  60 /* Call AT_FUNC_F1 to operate on FILE, which is in the directory
  61    open on descriptor FD.  If AT_FUNC_USE_F1_COND is defined to a value,
  62    AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag;
  63    call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than
  64    AT_FUNC_USE_F1_COND.  Return int and fail with -1 unless AT_FUNC_RESULT
  65    or AT_FUNC_FAIL are defined.  If possible, do it without changing the
  66    working directory.  Otherwise, resort to using save_cwd/fchdir,
  67    then AT_FUNC_F?/restore_cwd.  If either the save_cwd or the restore_cwd
  68    fails, then give a diagnostic and exit nonzero.  */
  69 FUNC_RESULT
  70 AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72   VALIDATE_FLAG (flag);
  73 
  74   if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
  75     return CALL_FUNC (file);
  76 
  77 #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
  78   errno = ENOTSUP;
  79   return FUNC_FAIL;
  80 #else
  81   {
  82   /* Be careful to choose names unlikely to conflict with
  83      AT_FUNC_POST_FILE_PARAM_DECLS.  */
  84   struct saved_cwd saved_cwd;
  85   int saved_errno;
  86   FUNC_RESULT err;
  87 
  88   {
  89     char proc_buf[OPENAT_BUFFER_SIZE];
  90     char *proc_file = openat_proc_name (proc_buf, fd, file);
  91     if (proc_file)
  92       {
  93         FUNC_RESULT proc_result = CALL_FUNC (proc_file);
  94         int proc_errno = errno;
  95         if (proc_file != proc_buf)
  96           free (proc_file);
  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 (FUNC_FAIL != proc_result)
 101           return proc_result;
 102         if (! EXPECTED_ERRNO (proc_errno))
 103           {
 104             errno = proc_errno;
 105             return proc_result;
 106           }
 107       }
 108   }
 109 
 110   if (save_cwd (&saved_cwd) != 0)
 111     openat_save_fail (errno);
 112   if (0 <= fd && fd == saved_cwd.desc)
 113     {
 114       /* If saving the working directory collides with the user's
 115          requested fd, then the user's fd must have been closed to
 116          begin with.  */
 117       free_cwd (&saved_cwd);
 118       errno = EBADF;
 119       return FUNC_FAIL;
 120     }
 121 
 122   if (fchdir (fd) != 0)
 123     {
 124       saved_errno = errno;
 125       free_cwd (&saved_cwd);
 126       errno = saved_errno;
 127       return FUNC_FAIL;
 128     }
 129 
 130   err = CALL_FUNC (file);
 131   saved_errno = (err == FUNC_FAIL ? errno : 0);
 132 
 133   if (restore_cwd (&saved_cwd) != 0)
 134     openat_restore_fail (errno);
 135 
 136   free_cwd (&saved_cwd);
 137 
 138   if (saved_errno)
 139     errno = saved_errno;
 140   return err;
 141   }
 142 #endif
 143 }
 144 #undef CALL_FUNC
 145 #undef FUNC_RESULT
 146 #undef FUNC_FAIL

/* [previous][next][first][last][top][bottom][index][help] */