diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/fcntl.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/fcntl.c | 119 |
1 files changed, 78 insertions, 41 deletions
diff --git a/sysdeps/unix/sysv/linux/fcntl.c b/sysdeps/unix/sysv/linux/fcntl.c index fbac93930b..cbab7b401a 100644 --- a/sysdeps/unix/sysv/linux/fcntl.c +++ b/sysdeps/unix/sysv/linux/fcntl.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2000-2016 Free Software Foundation, Inc. +/* Linux fcntl syscall implementation. + Copyright (C) 2000-2018 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 @@ -15,35 +16,19 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <assert.h> -#include <errno.h> -#include <sysdep-cancel.h> /* Must come before <fcntl.h>. */ #include <fcntl.h> #include <stdarg.h> +#include <errno.h> +#include <sysdep-cancel.h> -#include <sys/syscall.h> - - -static int -do_fcntl (int fd, int cmd, void *arg) -{ - if (cmd != F_GETOWN) - return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); - - INTERNAL_SYSCALL_DECL (err); - struct f_owner_ex fex; - int res = INTERNAL_SYSCALL (fcntl, err, 3, fd, F_GETOWN_EX, &fex); - if (!INTERNAL_SYSCALL_ERROR_P (res, err)) - return fex.type == F_OWNER_GID ? -fex.pid : fex.pid; - - return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (res, - err)); -} +#ifndef __OFF_T_MATCHES_OFF64_T +# ifndef FCNTL_ADJUST_CMD +# define FCNTL_ADJUST_CMD(__cmd) __cmd +# endif -#ifndef NO_CANCELLATION int -__fcntl_nocancel (int fd, int cmd, ...) +__libc_fcntl (int fd, int cmd, ...) { va_list ap; void *arg; @@ -52,13 +37,70 @@ __fcntl_nocancel (int fd, int cmd, ...) arg = va_arg (ap, void *); va_end (ap); - return do_fcntl (fd, cmd, arg); + cmd = FCNTL_ADJUST_CMD (cmd); + + switch (cmd) + { + case F_SETLKW: + case F_SETLKW64: + return SYSCALL_CANCEL (fcntl64, fd, cmd, arg); + case F_OFD_SETLKW: + { + struct flock *flk = (struct flock *) arg; + struct flock64 flk64 = + { + .l_type = flk->l_type, + .l_whence = flk->l_whence, + .l_start = flk->l_start, + .l_len = flk->l_len, + .l_pid = flk->l_pid + }; + return SYSCALL_CANCEL (fcntl64, fd, cmd, &flk64); + } + case F_OFD_GETLK: + case F_OFD_SETLK: + { + struct flock *flk = (struct flock *) arg; + struct flock64 flk64 = + { + .l_type = flk->l_type, + .l_whence = flk->l_whence, + .l_start = flk->l_start, + .l_len = flk->l_len, + .l_pid = flk->l_pid + }; + int ret = INLINE_SYSCALL_CALL (fcntl64, fd, cmd, &flk64); + if (ret == -1) + return -1; + if ((off_t) flk64.l_start != flk64.l_start + || (off_t) flk64.l_len != flk64.l_len) + { + __set_errno (EOVERFLOW); + return -1; + } + flk->l_type = flk64.l_type; + flk->l_whence = flk64.l_whence; + flk->l_start = flk64.l_start; + flk->l_len = flk64.l_len; + flk->l_pid = flk64.l_pid; + return ret; + } + /* Since only F_SETLKW{64}/F_OLD_SETLK are cancellation entrypoints and + only OFD locks require LFS handling, all others flags are handled + unmodified by calling __NR_fcntl64. */ + default: + return __fcntl64_nocancel_adjusted (fd, cmd, arg); + } } -#endif +libc_hidden_def (__libc_fcntl) +weak_alias (__libc_fcntl, __fcntl) +libc_hidden_weak (__fcntl) +# include <shlib-compat.h> +# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_28) int -__libc_fcntl (int fd, int cmd, ...) +__old_libc_fcntl64 (int fd, int cmd, ...) { va_list ap; void *arg; @@ -67,19 +109,14 @@ __libc_fcntl (int fd, int cmd, ...) arg = va_arg (ap, void *); va_end (ap); - if (SINGLE_THREAD_P || cmd != F_SETLKW) - return do_fcntl (fd, cmd, arg); - - int oldtype = LIBC_CANCEL_ASYNC (); - - int result = do_fcntl (fd, cmd, arg); - - LIBC_CANCEL_RESET (oldtype); - - return result; + /* Previous versions called __NR_fcntl64 for fcntl (which did not handle + OFD locks in LFS mode). */ + return __libc_fcntl64 (fd, cmd, arg); } -libc_hidden_def (__libc_fcntl) - -weak_alias (__libc_fcntl, __fcntl) -libc_hidden_weak (__fcntl) +compat_symbol (libc, __old_libc_fcntl64, fcntl, GLIBC_2_0); +versioned_symbol (libc, __libc_fcntl, fcntl, GLIBC_2_28); +# else weak_alias (__libc_fcntl, fcntl) +# endif + +#endif /* __OFF_T_MATCHES_OFF64_T */ |