Back to index

glibc  2.9
Functions
faccessat.c File Reference
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <alloca.h>
#include <kernel-features.h>
#include <sysdep.h>

Go to the source code of this file.

Functions

int faccessat (int fd, const char *file, int mode, int flag)

Function Documentation

int faccessat ( int  fd,
const char *  file,
int  mode,
int  flag 
)

Definition at line 33 of file faccessat.c.

{
  if (flag & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS))
    {
      __set_errno (EINVAL);
      return -1;
    }

#ifdef __NR_faccessat
  if ((flag == 0 || ((flag & ~AT_EACCESS) == 0 && ! __libc_enable_secure))
# ifndef __ASSUME_ATFCTS
      && __have_atfcts >= 0
# endif
      )
    {
      int result = INLINE_SYSCALL (faccessat, 3, fd, file, mode);
# ifndef __ASSUME_ATFCTS
      if (result == -1 && errno == ENOSYS)
       __have_atfcts = -1;
      else
# endif
       return result;
    }
#endif

#ifndef __ASSUME_ATFCTS
  if ((!(flag & AT_EACCESS) || ! __libc_enable_secure)
# ifndef __NR_laccess              /* Linux so far has no laccess syscall.  */
      && !(flag & AT_SYMLINK_NOFOLLOW)
# endif
      )
    {
      /* If we are not set-uid or set-gid, access does the same.  */
      char *buf = NULL;

      if (fd != AT_FDCWD && file[0] != '/')
       {
         size_t filelen = strlen (file);
         static const char procfd[] = "/proc/self/fd/%d/%s";
         /* Buffer for the path name we are going to use.  It consists of
            - the string /proc/self/fd/
            - the file descriptor number
            - the file name provided.
            The final NUL is included in the sizeof.   A bit of overhead
            due to the format elements compensates for possible negative
            numbers.  */
         size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
         buf = alloca (buflen);

         __snprintf (buf, buflen, procfd, fd, file);
         file = buf;
       }

      int result;
      INTERNAL_SYSCALL_DECL (err);

# ifdef __NR_laccess
      if (flag & AT_SYMLINK_NOFOLLOW)
       result = INTERNAL_SYSCALL (laccess, err, 2, file, mode);
      else
# endif
       result = INTERNAL_SYSCALL (access, err, 2, file, mode);

      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
       {
         __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
         result = -1;
       }

      return result;
    }
#endif

  struct stat64 stats;
  if (fstatat64 (fd, file, &stats, flag & AT_SYMLINK_NOFOLLOW))
    return -1;

  mode &= (X_OK | W_OK | R_OK);    /* Clear any bogus bits. */
#if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH
# error Oops, portability assumptions incorrect.
#endif

  if (mode == F_OK)
    return 0;               /* The file exists. */

  uid_t uid = (flag & AT_EACCESS) ? __geteuid () : __getuid ();

  /* The super-user can read and write any file, and execute any file
     that anyone can execute. */
  if (uid == 0 && ((mode & X_OK) == 0
                 || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
    return 0;

  int granted = (uid == stats.st_uid
               ? (unsigned int) (stats.st_mode & (mode << 6)) >> 6
               : (stats.st_gid == ((flag & AT_EACCESS)
                                 ? __getegid () : __getgid ())
                  || __group_member (stats.st_gid))
               ? (unsigned int) (stats.st_mode & (mode << 3)) >> 3
               : (stats.st_mode & mode));

  if (granted == mode)
    return 0;

  __set_errno (EACCES);
  return -1;
}

Here is the call graph for this function: