#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "openat.h"
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "error.h"
#include "exitfail.h"
#include "save-cwd.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
int
rpl_openat (int fd, char const *file, int flags, ...)
{
struct saved_cwd saved_cwd;
int saved_errno;
int new_fd;
mode_t mode = 0;
if (flags & O_CREAT)
{
va_list arg;
va_start (arg, flags);
mode = va_arg (arg, mode_t);
va_end (arg);
}
if (fd == AT_FDCWD || *file == '/')
return open (file, flags, mode);
if (save_cwd (&saved_cwd) != 0)
error (exit_failure, errno,
_("openat: unable to record current working directory"));
if (fchdir (fd) != 0)
{
saved_errno = errno;
free_cwd (&saved_cwd);
errno = saved_errno;
return -1;
}
new_fd = open (file, flags, mode);
saved_errno = errno;
if (restore_cwd (&saved_cwd) != 0)
error (exit_failure, errno,
_("openat: unable to restore working directory"));
free_cwd (&saved_cwd);
errno = saved_errno;
return new_fd;
}
DIR *
fdopendir (int fd)
{
struct saved_cwd saved_cwd;
int saved_errno;
DIR *dir;
if (fd == AT_FDCWD)
return opendir (".");
if (save_cwd (&saved_cwd) != 0)
error (exit_failure, errno,
_("fdopendir: unable to record current working directory"));
if (fchdir (fd) != 0)
{
saved_errno = errno;
free_cwd (&saved_cwd);
errno = saved_errno;
return NULL;
}
dir = opendir (".");
saved_errno = errno;
if (restore_cwd (&saved_cwd) != 0)
error (exit_failure, errno,
_("fdopendir: unable to restore working directory"));
free_cwd (&saved_cwd);
errno = saved_errno;
return dir;
}
int
fstatat (int fd, char const *file, struct stat *st, int flag)
{
struct saved_cwd saved_cwd;
int saved_errno;
int err;
if (fd == AT_FDCWD)
return (flag == AT_SYMLINK_NOFOLLOW
? lstat (file, st)
: stat (file, st));
if (save_cwd (&saved_cwd) != 0)
error (exit_failure, errno,
_("fstatat: unable to record current working directory"));
if (fchdir (fd) != 0)
{
saved_errno = errno;
free_cwd (&saved_cwd);
errno = saved_errno;
return -1;
}
err = (flag == AT_SYMLINK_NOFOLLOW
? lstat (file, st)
: stat (file, st));
saved_errno = errno;
if (restore_cwd (&saved_cwd) != 0)
error (exit_failure, errno,
_("fstatat: unable to restore working directory"));
free_cwd (&saved_cwd);
errno = saved_errno;
return err;
}