* io/fcntl.h [__USE_ATFILE] (AT_EACCESS): New macro.

* posix/unistd.h [__USE_ATFILE]: Declare faccessat.
	* io/faccessat.c: New file.
	* sysdeps/unix/sysv/linux/faccessat.c: New file.
	* io/Makefile (routines): Add faccessat.
	* io/Versions (libc: GLIBC_2.4): Likewise.
	* io/tst-faccessat.c: New file.
	* io/Makefile (tests): Add it.

	* io/sys/stat.h: Likewise.
This commit is contained in:
Roland McGrath 2006-01-06 12:14:26 +00:00
parent 030219826e
commit d15b99ac5a
9 changed files with 359 additions and 11 deletions

View File

@ -1,5 +1,14 @@
2006-01-06 Roland McGrath <roland@redhat.com> 2006-01-06 Roland McGrath <roland@redhat.com>
* io/fcntl.h [__USE_ATFILE] (AT_EACCESS): New macro.
* posix/unistd.h [__USE_ATFILE]: Declare faccessat.
* io/faccessat.c: New file.
* sysdeps/unix/sysv/linux/faccessat.c: New file.
* io/Makefile (routines): Add faccessat.
* io/Versions (libc: GLIBC_2.4): Likewise.
* io/tst-faccessat.c: New file.
* io/Makefile (tests): Add it.
* scripts/check-local-headers.sh: Revert last change. * scripts/check-local-headers.sh: Revert last change.
* io/euidaccess.c: Add eaccess as an alias. * io/euidaccess.c: Add eaccess as an alias.
@ -67,6 +76,7 @@
* libio/stdio.h: Likewise. * libio/stdio.h: Likewise.
* posix/unistd.h: Likewise. * posix/unistd.h: Likewise.
* time/sys/time.h: Likewise. * time/sys/time.h: Likewise.
* io/sys/stat.h: Likewise.
* io/sys/stat.h [__USE_GNU]: Declare fchmodat. * io/sys/stat.h [__USE_GNU]: Declare fchmodat.
* io/fchmodat.c: New file. * io/fchmodat.c: New file.

View File

@ -35,10 +35,10 @@ routines := \
fxstatat fxstatat64 \ fxstatat fxstatat64 \
statfs fstatfs statfs64 fstatfs64 \ statfs fstatfs statfs64 fstatfs64 \
statvfs fstatvfs statvfs64 fstatvfs64 \ statvfs fstatvfs statvfs64 fstatvfs64 \
umask chmod fchmod lchmod fchmodat \ umask chmod fchmod lchmod fchmodat \
mkdir mkdirat \ mkdir mkdirat \
open open64 openat openat64 close \ open open64 openat openat64 close \
read write lseek lseek64 access euidaccess \ read write lseek lseek64 access euidaccess faccessat \
fcntl flock lockf lockf64 \ fcntl flock lockf lockf64 \
dup dup2 pipe \ dup dup2 pipe \
creat creat64 \ creat creat64 \
@ -64,7 +64,7 @@ test-srcs := ftwtest
tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
tst-fcntl bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 tst-statvfs \ tst-fcntl bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 tst-statvfs \
tst-openat tst-unlinkat tst-fstatat tst-futimesat \ tst-openat tst-unlinkat tst-fstatat tst-futimesat \
tst-renameat tst-fchownat tst-fchmodat tst-renameat tst-fchownat tst-fchmodat tst-faccessat
distribute := ftwtest-sh distribute := ftwtest-sh

View File

@ -100,6 +100,7 @@ libc {
GLIBC_2.4 { GLIBC_2.4 {
eaccess; eaccess;
faccessat;
fchmodat; fchmodat;
fchownat; fchownat;
__fxstatat; __fxstatat64; __fxstatat; __fxstatat64;

51
io/faccessat.c Normal file
View File

@ -0,0 +1,51 @@
/* Test for access to file, relative to open directory. Stub version.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
int
faccessat (fd, file, type, flag)
int fd;
const char *file;
int type;
int flag;
{
if (file == NULL || (flag & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS)) != 0
|| (type & ~(R_OK|W_OK|X_OK|F_OK)) != 0)
{
__set_errno (EINVAL);
return -1;
}
if (fd < 0 && fd != AT_FDCWD)
{
__set_errno (EBADF);
return -1;
}
__set_errno (ENOSYS);
return -1;
}
stub_warning (faccessat)
#include <stub-tag.h>

View File

@ -63,6 +63,8 @@ __BEGIN_DECLS
# define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ # define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
# define AT_REMOVEDIR 0x200 /* Remove directory instead of # define AT_REMOVEDIR 0x200 /* Remove directory instead of
unlinking file. */ unlinking file. */
# define AT_EACCESS 0x200 /* Test access permitted for
effective IDs, not real IDs. */
#endif #endif
/* Do the file control operation described by CMD on FD. /* Do the file control operation described by CMD on FD.

View File

@ -228,7 +228,7 @@ extern int stat64 (__const char *__restrict __file,
extern int fstat64 (int __fd, struct stat64 *__buf) __THROW __nonnull ((2)); extern int fstat64 (int __fd, struct stat64 *__buf) __THROW __nonnull ((2));
#endif #endif
#ifdef __USE_GNU #ifdef __USE_ATFILE
/* Similar to stat, get the attributes for FILE and put them in BUF. /* Similar to stat, get the attributes for FILE and put them in BUF.
Relative path names are interpreted relative to FD unless FD is Relative path names are interpreted relative to FD unless FD is
AT_FDCWD. */ AT_FDCWD. */
@ -293,12 +293,12 @@ extern int lchmod (__const char *__file, __mode_t __mode)
extern int fchmod (int __fd, __mode_t __mode) __THROW; extern int fchmod (int __fd, __mode_t __mode) __THROW;
#endif #endif
#ifdef __USE_GNU #ifdef __USE_ATFILE
/* Set file access permissions of FILE relative to /* Set file access permissions of FILE relative to
the directory FD is open on. */ the directory FD is open on. */
extern int fchmodat (int __fd, __const char *__file, __mode_t mode, int __flag) extern int fchmodat (int __fd, __const char *__file, __mode_t mode, int __flag)
__THROW __nonnull ((2)) __wur; __THROW __nonnull ((2)) __wur;
#endif /* Use GNU. */ #endif /* Use ATFILE. */
@ -316,7 +316,7 @@ extern __mode_t getumask (void) __THROW;
extern int mkdir (__const char *__path, __mode_t __mode) extern int mkdir (__const char *__path, __mode_t __mode)
__THROW __nonnull ((1)); __THROW __nonnull ((1));
#ifdef __USE_GNU #ifdef __USE_ATFILE
/* Like mkdir, create a new directory with permission bits MODE. But /* Like mkdir, create a new directory with permission bits MODE. But
interpret relative PATH names relative to the directory associated interpret relative PATH names relative to the directory associated
with FD. */ with FD. */
@ -332,7 +332,7 @@ extern int mknod (__const char *__path, __mode_t __mode, __dev_t __dev)
__THROW __nonnull ((1)); __THROW __nonnull ((1));
#endif #endif
#ifdef __USE_GNU #ifdef __USE_ATFILE
/* Like mknod, create a new device file with permission bits MODE and /* Like mknod, create a new device file with permission bits MODE and
device number DEV. But interpret relative PATH names relative to device number DEV. But interpret relative PATH names relative to
the directory associated with FD. */ the directory associated with FD. */
@ -345,7 +345,7 @@ extern int mknodat (int __fd, __const char *__path, __mode_t __mode,
extern int mkfifo (__const char *__path, __mode_t __mode) extern int mkfifo (__const char *__path, __mode_t __mode)
__THROW __nonnull ((1)); __THROW __nonnull ((1));
#ifdef __USE_GNU #ifdef __USE_ATFILE
/* Like mkfifo, create a new FIFO with permission bits MODE. But /* Like mkfifo, create a new FIFO with permission bits MODE. But
interpret relative PATH names relative to the directory associated interpret relative PATH names relative to the directory associated
with FD. */ with FD. */
@ -450,7 +450,7 @@ __NTH (fstat (int __fd, struct stat *__statbuf))
return __fxstat (_STAT_VER, __fd, __statbuf); return __fxstat (_STAT_VER, __fd, __statbuf);
} }
# ifdef __USE_GNU # ifdef __USE_ATFILE
extern __inline__ int extern __inline__ int
__NTH (fstatat (int __fd, __const char *__filename, struct stat *__statbuf, __NTH (fstatat (int __fd, __const char *__filename, struct stat *__statbuf,
int __flag)) int __flag))
@ -467,7 +467,7 @@ __NTH (mknod (__const char *__path, __mode_t __mode, __dev_t __dev))
} }
# endif # endif
# ifdef __USE_GNU # ifdef __USE_ATFILE
extern __inline__ int extern __inline__ int
__NTH (mknodat (int __fd, __const char *__path, __mode_t __mode, __NTH (mknodat (int __fd, __const char *__path, __mode_t __mode,
__dev_t __dev)) __dev_t __dev))

153
io/tst-faccessat.c Normal file
View File

@ -0,0 +1,153 @@
/* Test for faccessat function. */
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static int dir_fd;
static void
prepare (void)
{
size_t test_dir_len = strlen (test_dir);
static const char dir_name[] = "/tst-faccessat.XXXXXX";
size_t dirbuflen = test_dir_len + sizeof (dir_name);
char *dirbuf = malloc (dirbuflen);
if (dirbuf == NULL)
{
puts ("out of memory");
exit (1);
}
snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
if (mkdtemp (dirbuf) == NULL)
{
puts ("cannot create temporary directory");
exit (1);
}
add_temp_file (dirbuf);
dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY);
if (dir_fd == -1)
{
puts ("cannot open directory");
exit (1);
}
}
static int
do_test (void)
{
/* fdopendir takes over the descriptor, make a copy. */
int dupfd = dup (dir_fd);
if (dupfd == -1)
{
puts ("dup failed");
return 1;
}
if (lseek (dupfd, 0, SEEK_SET) != 0)
{
puts ("1st lseek failed");
return 1;
}
/* The directory should be empty save the . and .. files. */
DIR *dir = fdopendir (dupfd);
if (dir == NULL)
{
puts ("fdopendir failed");
return 1;
}
struct dirent64 *d;
while ((d = readdir64 (dir)) != NULL)
if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
{
printf ("temp directory contains file \"%s\"\n", d->d_name);
return 1;
}
closedir (dir);
/* Try to create a file. */
int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
if (fd == -1)
{
if (errno == ENOSYS)
{
puts ("*at functions not supported");
return 0;
}
puts ("file creation failed");
return 1;
}
write (fd, "hello", 5);
puts ("file created");
close (fd);
int result = 0;
if (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS))
{
printf ("faccessat F_OK: %m\n");
result = 1;
}
if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS))
{
printf ("faccessat W_OK: %m\n");
result = 1;
}
errno = 0;
if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) == 0
|| errno != EACCES)
{
printf ("faccessat X_OK on nonexecutable: %m\n");
result = 1;
}
if (fchmodat (dir_fd, "some-file", 0400, 0) != 0)
{
printf ("fchownat failed: %m\n");
return 1;
}
if (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS))
{
printf ("faccessat R_OK: %m\n");
result = 1;
}
errno = 0;
if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
|| errno != EACCES)
{
printf ("faccessat W_OK on unwritable file: %m\n");
result = 1;
}
if (unlinkat (dir_fd, "some-file", 0) != 0)
{
puts ("unlinkat failed");
result = 1;
}
close (dir_fd);
return result;
}

View File

@ -266,6 +266,14 @@ extern int eaccess (__const char *__name, int __type)
__THROW __nonnull ((1)); __THROW __nonnull ((1));
#endif #endif
#ifdef __USE_ATFILE
/* Test for access to FILE relative to the directory FD is open on.
If AT_EACCESS is set in FLAG, then use effective IDs like `eaccess',
otherwise use real IDs like `access'. */
extern int faccessat (int __fd, __const char *__file, int __type, int __flag)
__THROW __nonnull ((2)) __wur;
#endif /* Use GNU. */
/* Values for the WHENCE argument to lseek. */ /* Values for the WHENCE argument to lseek. */
#ifndef _STDIO_H /* <stdio.h> has the same definitions. */ #ifndef _STDIO_H /* <stdio.h> has the same definitions. */

View File

@ -0,0 +1,123 @@
/* Test for access to file, relative to open directory. Linux version.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#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 <sysdep.h>
int
faccessat (fd, file, mode, flag)
int fd;
const char *file;
int mode;
int flag;
{
if (flag & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS))
{
__set_errno (EINVAL);
return -1;
}
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;
}
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. */
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;
}
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;
}