at-func.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* Define at-style functions like fstatat, unlinkat, fchownat, etc.
  2. Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. /* written by Jim Meyering */
  14. #include "filename.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
  15. #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
  16. # include <errno.h>
  17. # ifndef ENOTSUP
  18. # define ENOTSUP EINVAL
  19. # endif
  20. #else
  21. # include "openat.h"
  22. # include "openat-priv.h"
  23. # include "save-cwd.h"
  24. #endif
  25. #ifdef AT_FUNC_USE_F1_COND
  26. # define CALL_FUNC(F) \
  27. (flag == AT_FUNC_USE_F1_COND \
  28. ? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS) \
  29. : AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
  30. # define VALIDATE_FLAG(F) \
  31. if (flag & ~AT_FUNC_USE_F1_COND) \
  32. { \
  33. errno = EINVAL; \
  34. return FUNC_FAIL; \
  35. }
  36. #else
  37. # define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS))
  38. # define VALIDATE_FLAG(F) /* empty */
  39. #endif
  40. #ifdef AT_FUNC_RESULT
  41. # define FUNC_RESULT AT_FUNC_RESULT
  42. #else
  43. # define FUNC_RESULT int
  44. #endif
  45. #ifdef AT_FUNC_FAIL
  46. # define FUNC_FAIL AT_FUNC_FAIL
  47. #else
  48. # define FUNC_FAIL -1
  49. #endif
  50. /* Call AT_FUNC_F1 to operate on FILE, which is in the directory
  51. open on descriptor FD. If AT_FUNC_USE_F1_COND is defined to a value,
  52. AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag;
  53. call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than
  54. AT_FUNC_USE_F1_COND. Return int and fail with -1 unless AT_FUNC_RESULT
  55. or AT_FUNC_FAIL are defined. If possible, do it without changing the
  56. working directory. Otherwise, resort to using save_cwd/fchdir,
  57. then AT_FUNC_F?/restore_cwd. If either the save_cwd or the restore_cwd
  58. fails, then give a diagnostic and exit nonzero. */
  59. FUNC_RESULT
  60. AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
  61. {
  62. VALIDATE_FLAG (flag);
  63. if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
  64. return CALL_FUNC (file);
  65. #ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
  66. errno = ENOTSUP;
  67. return FUNC_FAIL;
  68. #else
  69. {
  70. /* Be careful to choose names unlikely to conflict with
  71. AT_FUNC_POST_FILE_PARAM_DECLS. */
  72. struct saved_cwd saved_cwd;
  73. int saved_errno;
  74. FUNC_RESULT err;
  75. {
  76. char proc_buf[OPENAT_BUFFER_SIZE];
  77. char *proc_file = openat_proc_name (proc_buf, fd, file);
  78. if (proc_file)
  79. {
  80. FUNC_RESULT proc_result = CALL_FUNC (proc_file);
  81. int proc_errno = errno;
  82. if (proc_file != proc_buf)
  83. free (proc_file);
  84. /* If the syscall succeeds, or if it fails with an unexpected
  85. errno value, then return right away. Otherwise, fall through
  86. and resort to using save_cwd/restore_cwd. */
  87. if (FUNC_FAIL != proc_result)
  88. return proc_result;
  89. if (! EXPECTED_ERRNO (proc_errno))
  90. {
  91. errno = proc_errno;
  92. return proc_result;
  93. }
  94. }
  95. }
  96. if (save_cwd (&saved_cwd) != 0)
  97. openat_save_fail (errno);
  98. if (0 <= fd && fd == saved_cwd.desc)
  99. {
  100. /* If saving the working directory collides with the user's
  101. requested fd, then the user's fd must have been closed to
  102. begin with. */
  103. free_cwd (&saved_cwd);
  104. errno = EBADF;
  105. return FUNC_FAIL;
  106. }
  107. if (fchdir (fd) != 0)
  108. {
  109. saved_errno = errno;
  110. free_cwd (&saved_cwd);
  111. errno = saved_errno;
  112. return FUNC_FAIL;
  113. }
  114. err = CALL_FUNC (file);
  115. saved_errno = (err == FUNC_FAIL ? errno : 0);
  116. if (restore_cwd (&saved_cwd) != 0)
  117. openat_restore_fail (errno);
  118. free_cwd (&saved_cwd);
  119. if (saved_errno)
  120. errno = saved_errno;
  121. return err;
  122. }
  123. #endif
  124. }
  125. #undef CALL_FUNC
  126. #undef FUNC_RESULT
  127. #undef FUNC_FAIL