xref: /netbsd-src/external/gpl3/gdb/dist/gnulib/import/at-func.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
18dffb485Schristos /* Define at-style functions like fstatat, unlinkat, fchownat, etc.
2*4b169a6bSchristos    Copyright (C) 2006, 2009-2022 Free Software Foundation, Inc.
38dffb485Schristos 
48dffb485Schristos    This program is free software: you can redistribute it and/or modify
58dffb485Schristos    it under the terms of the GNU General Public License as published by
6*4b169a6bSchristos    the Free Software Foundation, either version 3 of the License, or
78dffb485Schristos    (at your option) any later version.
88dffb485Schristos 
98dffb485Schristos    This program is distributed in the hope that it will be useful,
108dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
118dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
128dffb485Schristos    GNU General Public License for more details.
138dffb485Schristos 
148dffb485Schristos    You should have received a copy of the GNU General Public License
158dffb485Schristos    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
168dffb485Schristos 
178dffb485Schristos /* written by Jim Meyering */
188dffb485Schristos 
198dffb485Schristos #include "filename.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
208dffb485Schristos 
218dffb485Schristos #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
228dffb485Schristos # include <errno.h>
238dffb485Schristos # ifndef ENOTSUP
248dffb485Schristos #  define ENOTSUP EINVAL
258dffb485Schristos # endif
268dffb485Schristos #else
278dffb485Schristos # include "openat.h"
288dffb485Schristos # include "openat-priv.h"
298dffb485Schristos # include "save-cwd.h"
308dffb485Schristos #endif
318dffb485Schristos 
328dffb485Schristos #ifdef AT_FUNC_USE_F1_COND
338dffb485Schristos # define CALL_FUNC(F)                           \
348dffb485Schristos   (flag == AT_FUNC_USE_F1_COND                  \
358dffb485Schristos     ? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS)     \
368dffb485Schristos     : AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
378dffb485Schristos # define VALIDATE_FLAG(F)                       \
388dffb485Schristos   if (flag & ~AT_FUNC_USE_F1_COND)              \
398dffb485Schristos     {                                           \
408dffb485Schristos       errno = EINVAL;                           \
418dffb485Schristos       return FUNC_FAIL;                         \
428dffb485Schristos     }
438dffb485Schristos #else
448dffb485Schristos # define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS))
458dffb485Schristos # define VALIDATE_FLAG(F) /* empty */
468dffb485Schristos #endif
478dffb485Schristos 
488dffb485Schristos #ifdef AT_FUNC_RESULT
498dffb485Schristos # define FUNC_RESULT AT_FUNC_RESULT
508dffb485Schristos #else
518dffb485Schristos # define FUNC_RESULT int
528dffb485Schristos #endif
538dffb485Schristos 
548dffb485Schristos #ifdef AT_FUNC_FAIL
558dffb485Schristos # define FUNC_FAIL AT_FUNC_FAIL
568dffb485Schristos #else
578dffb485Schristos # define FUNC_FAIL -1
588dffb485Schristos #endif
598dffb485Schristos 
608dffb485Schristos /* Call AT_FUNC_F1 to operate on FILE, which is in the directory
618dffb485Schristos    open on descriptor FD.  If AT_FUNC_USE_F1_COND is defined to a value,
628dffb485Schristos    AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag;
638dffb485Schristos    call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than
648dffb485Schristos    AT_FUNC_USE_F1_COND.  Return int and fail with -1 unless AT_FUNC_RESULT
658dffb485Schristos    or AT_FUNC_FAIL are defined.  If possible, do it without changing the
668dffb485Schristos    working directory.  Otherwise, resort to using save_cwd/fchdir,
678dffb485Schristos    then AT_FUNC_F?/restore_cwd.  If either the save_cwd or the restore_cwd
688dffb485Schristos    fails, then give a diagnostic and exit nonzero.  */
698dffb485Schristos FUNC_RESULT
AT_FUNC_NAME(int fd,char const * file AT_FUNC_POST_FILE_PARAM_DECLS)708dffb485Schristos AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
718dffb485Schristos {
728dffb485Schristos   VALIDATE_FLAG (flag);
738dffb485Schristos 
748dffb485Schristos   if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
758dffb485Schristos     return CALL_FUNC (file);
768dffb485Schristos 
778dffb485Schristos #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
788dffb485Schristos   errno = ENOTSUP;
798dffb485Schristos   return FUNC_FAIL;
808dffb485Schristos #else
818dffb485Schristos   {
828dffb485Schristos   /* Be careful to choose names unlikely to conflict with
838dffb485Schristos      AT_FUNC_POST_FILE_PARAM_DECLS.  */
848dffb485Schristos   struct saved_cwd saved_cwd;
858dffb485Schristos   int saved_errno;
868dffb485Schristos   FUNC_RESULT err;
878dffb485Schristos 
888dffb485Schristos   {
898dffb485Schristos     char proc_buf[OPENAT_BUFFER_SIZE];
908dffb485Schristos     char *proc_file = openat_proc_name (proc_buf, fd, file);
918dffb485Schristos     if (proc_file)
928dffb485Schristos       {
938dffb485Schristos         FUNC_RESULT proc_result = CALL_FUNC (proc_file);
948dffb485Schristos         int proc_errno = errno;
958dffb485Schristos         if (proc_file != proc_buf)
968dffb485Schristos           free (proc_file);
978dffb485Schristos         /* If the syscall succeeds, or if it fails with an unexpected
988dffb485Schristos            errno value, then return right away.  Otherwise, fall through
998dffb485Schristos            and resort to using save_cwd/restore_cwd.  */
1008dffb485Schristos         if (FUNC_FAIL != proc_result)
1018dffb485Schristos           return proc_result;
1028dffb485Schristos         if (! EXPECTED_ERRNO (proc_errno))
1038dffb485Schristos           {
1048dffb485Schristos             errno = proc_errno;
1058dffb485Schristos             return proc_result;
1068dffb485Schristos           }
1078dffb485Schristos       }
1088dffb485Schristos   }
1098dffb485Schristos 
1108dffb485Schristos   if (save_cwd (&saved_cwd) != 0)
1118dffb485Schristos     openat_save_fail (errno);
1128dffb485Schristos   if (0 <= fd && fd == saved_cwd.desc)
1138dffb485Schristos     {
1148dffb485Schristos       /* If saving the working directory collides with the user's
1158dffb485Schristos          requested fd, then the user's fd must have been closed to
1168dffb485Schristos          begin with.  */
1178dffb485Schristos       free_cwd (&saved_cwd);
1188dffb485Schristos       errno = EBADF;
1198dffb485Schristos       return FUNC_FAIL;
1208dffb485Schristos     }
1218dffb485Schristos 
1228dffb485Schristos   if (fchdir (fd) != 0)
1238dffb485Schristos     {
1248dffb485Schristos       saved_errno = errno;
1258dffb485Schristos       free_cwd (&saved_cwd);
1268dffb485Schristos       errno = saved_errno;
1278dffb485Schristos       return FUNC_FAIL;
1288dffb485Schristos     }
1298dffb485Schristos 
1308dffb485Schristos   err = CALL_FUNC (file);
1318dffb485Schristos   saved_errno = (err == FUNC_FAIL ? errno : 0);
1328dffb485Schristos 
1338dffb485Schristos   if (restore_cwd (&saved_cwd) != 0)
1348dffb485Schristos     openat_restore_fail (errno);
1358dffb485Schristos 
1368dffb485Schristos   free_cwd (&saved_cwd);
1378dffb485Schristos 
1388dffb485Schristos   if (saved_errno)
1398dffb485Schristos     errno = saved_errno;
1408dffb485Schristos   return err;
1418dffb485Schristos   }
1428dffb485Schristos #endif
1438dffb485Schristos }
1448dffb485Schristos #undef CALL_FUNC
1458dffb485Schristos #undef FUNC_RESULT
1468dffb485Schristos #undef FUNC_FAIL
147