/* written by Jim Meyering */
+#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
+#include "openat.h"
+#include "openat-priv.h"
+#include "save-cwd.h"
+
#ifdef AT_FUNC_USE_F1_COND
# define CALL_FUNC(F) \
(flag == AT_FUNC_USE_F1_COND \
if (flag & ~AT_FUNC_USE_F1_COND) \
{ \
errno = EINVAL; \
- return -1; \
+ 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 inlude 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. If possible, do it without changing the
+ 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. */
-int
+FUNC_RESULT
AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
{
+ /* Be careful to choose names unlikely to conflict with
+ AT_FUNC_POST_FILE_PARAM_DECLS. */
struct saved_cwd saved_cwd;
int saved_errno;
- int err;
+ FUNC_RESULT err;
VALIDATE_FLAG (flag);
return CALL_FUNC (file);
{
- char buf[OPENAT_BUFFER_SIZE];
- char *proc_file = openat_proc_name (buf, fd, file);
+ char proc_buf[OPENAT_BUFFER_SIZE];
+ char *proc_file = openat_proc_name (proc_buf, fd, file);
if (proc_file)
{
- int proc_result = CALL_FUNC (proc_file);
- int proc_errno = errno;
- if (proc_file != 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 (0 <= proc_result)
- return proc_result;
- if (! EXPECTED_ERRNO (proc_errno))
- {
- errno = proc_errno;
- return proc_result;
- }
+ 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 -1;
+ return FUNC_FAIL;
}
err = CALL_FUNC (file);
- saved_errno = (err < 0 ? errno : 0);
+ saved_errno = (err == FUNC_FAIL ? errno : 0);
if (restore_cwd (&saved_cwd) != 0)
openat_restore_fail (errno);
return err;
}
#undef CALL_FUNC
+#undef FUNC_RESULT
+#undef FUNC_FAIL