#include "../kernel-features.h"
+# if __ASSUME_FCNTL64 == 0
+/* This variable is shared with all files that check for fcntl64. */
+int __have_no_fcntl64;
+# endif
+#endif
+
int
__libc_fcntl (int fd, int cmd, ...)
{
va_list ap;
-#if __NR_fcntl64
- int result;
-#endif
void *arg;
va_start (ap, cmd);
arg = va_arg (ap, void *);
va_end (ap);
-#if __NR_fcntl64
- result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#if __ASSUME_FCNTL64 > 0
+ return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#else
+# ifdef __NR_fcntl64
+ if (! __have_no_fcntl64)
+ {
+ int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+ if (result >= 0 || errno != ENOSYS)
+ return result;
-# if __ASSUME_FCNTL64 == 0
- if (result != -1 || errno != ENOSYS)
+ __have_no_fcntl64 = 1;
+ }
# endif
- return result;
-#endif
-
-#if __ASSUME_FCNTL64 == 0
- if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64)
+ switch (cmd)
{
- __set_errno (EINVAL);
- return -1;
- }
+ case F_GETLK64:
+ /* Convert arg from flock64 to flock and back. */
+ {
+ struct flock fl;
+ struct flock64 *fl64 = arg;
+ int res;
- return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
-#endif
+ fl.l_start = (off_t)fl64->l_start;
+ /* Check if we can represent the values with the smaller type. */
+ if ((off64_t)fl.l_start != fl64->l_start)
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ fl.l_len = (off_t)fl64->l_len;
+ /* Check if we can represent the values with the smaller type. */
+ if ((off64_t)fl.l_len != fl64->l_len)
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ fl.l_type = fl64->l_type;
+ fl.l_whence = fl64->l_whence;
+ fl.l_pid = fl64->l_pid;
+
+ res = INLINE_SYSCALL (fcntl, 3, fd, cmd, &fl);
+ if (res != 0)
+ return res;
+ /* Everything ok, convert back. */
+ fl64->l_type = fl.l_type;
+ fl64->l_whence = fl.l_whence;
+ fl64->l_start = fl.l_start;
+ fl64->l_len = fl.l_len;
+ fl64->l_pid = fl.l_pid;
+
+ return 0;
+ }
+ case F_SETLK64:
+ case F_SETLKW64:
+ /* Try to convert arg from flock64 to flock. */
+ {
+ struct flock fl;
+ struct flock64 *fl64 = arg;
+ fl.l_start = (off_t)fl64->l_start;
+ /* Check if we can represent the values with the smaller type. */
+ if ((off64_t)fl.l_start != fl64->l_start)
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ fl.l_len = (off_t)fl64->l_len;
+ /* Check if we can represent the values with the smaller type. */
+ if ((off64_t)fl.l_len != fl64->l_len)
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ fl.l_type = fl64->l_type;
+ fl.l_whence = fl64->l_whence;
+ fl.l_pid = fl64->l_pid;
+ return INLINE_SYSCALL (fcntl, 3, fd, cmd, &fl);
+ }
+ default:
+ return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+ }
+ return -1;
+#endif /* __ASSUME_FCNTL64 */
}
weak_alias (__libc_fcntl, __fcntl)
--- /dev/null
+/* Copyright (C) 1994, 1996, 1997, 1998, 1999, 2000 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sysdep.h>
+
+#include "kernel-features.h"
+
+/* lockf is a simplified interface to fcntl's locking facilities. */
+
+#ifdef __NR_fcntl64
+extern int __syscall_fcntl64 (int __fd, int __cmd, ...);
+
+# if __ASSUME_FCNTL64 == 0
+/* This variable is shared with all files that check for fcntl64. The
+ declaration is in fcntl.c. */
+extern int __have_no_fcntl64;
+# endif
+#endif
+
+int
+lockf64 (int fd, int cmd, off64_t len64)
+{
+#if __ASSUME_FCNTL64 == 0
+ struct flock fl;
+ off_t len = (off_t) len64;
+#endif
+#ifdef __NR_fcntl64
+ struct flock64 fl64;
+ int cmd64;
+#endif
+
+#if __ASSUME_FCNTL64 == 0
+ memset ((char *) &fl, '\0', sizeof (fl));
+
+ /* lockf is always relative to the current file position. */
+ fl.l_whence = SEEK_CUR;
+ fl.l_start = 0;
+ fl.l_len = len;
+#endif
+#ifdef __NR_fcntl64
+# if __ASSUME_FCNTL64 == 0
+ if (!__have_no_fcntl64)
+ {
+# endif
+ memset ((char *) &fl64, '\0', sizeof (fl64));
+ fl64.l_whence = SEEK_CUR;
+ fl64.l_start = 0;
+ fl64.l_len = len64;
+# if __ASSUME_FCNTL64 == 0
+ }
+# endif
+#endif
+
+#if __ASSUME_FCNTL64 == 0 && !defined __NR_fcntl64
+ if (len64 != (off64_t) len)
+ {
+ /* We can't represent the length. */
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+#endif
+ switch (cmd)
+ {
+ case F_TEST:
+ /* Test the lock: return 0 if FD is unlocked or locked by this process;
+ return -1, set errno to EACCES, if another process holds the lock. */
+#if __ASSUME_FCNTL64 > 0
+ if (INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64) < 0)
+ return -1;
+ if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ())
+ return 0;
+ __set_errno (EACCES);
+ return -1;
+#else
+# ifdef __NR_fcntl64
+ if (!__have_no_fcntl64)
+ {
+ int res = INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64);
+
+ /* If errno == ENOSYS try the 32bit interface if len64 can
+ be represented with 32 bits. */
+
+ if (res == 0)
+ {
+ if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ())
+ return 0;
+ __set_errno (EACCES);
+ return -1;
+ }
+ else if (errno == ENOSYS)
+ __have_no_fcntl64 = 1;
+ else
+ /* res < 0 && errno != ENOSYS. */
+ return -1;
+ if (len64 != (off64_t) len)
+ {
+ /* We can't represent the length. */
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ }
+# endif
+ if (__fcntl (fd, F_GETLK, &fl) < 0)
+ return -1;
+ if (fl.l_type == F_UNLCK || fl.l_pid == __getpid ())
+ return 0;
+ __set_errno (EACCES);
+ return -1;
+#endif
+ case F_ULOCK:
+#if __ASSUME_FCNTL64 == 0
+ fl.l_type = F_UNLCK;
+ cmd = F_SETLK;
+#endif
+#ifdef __NR_fcntl64
+ fl64.l_type = F_UNLCK;
+ cmd64 = F_SETLK64;
+#endif
+ break;
+ case F_LOCK:
+#if __ASSUME_FCNTL64 == 0
+ fl.l_type = F_WRLCK;
+ cmd = F_SETLKW;
+#endif
+#ifdef __NR_fcntl64
+ fl64.l_type = F_WRLCK;
+ cmd64 = F_SETLKW64;
+#endif
+ break;
+ case F_TLOCK:
+#if __ASSUME_FCNTL64 == 0
+ fl.l_type = F_WRLCK;
+ cmd = F_SETLK;
+#endif
+#ifdef __NR_fcntl64
+ fl64.l_type = F_WRLCK;
+ cmd64 = F_SETLK64;
+#endif
+ break;
+
+ default:
+ __set_errno (EINVAL);
+ return -1;
+ }
+#if __ASSUME_FCNTL64 > 0
+ return INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64);
+#else
+# ifdef __NR_fcntl64
+
+ if (!__have_no_fcntl64)
+ {
+ int res = INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64);
+
+ /* If errno == ENOSYS try the 32bit interface if len64 can
+ be represented with 32 bits. */
+ if (res == 0 || errno != ENOSYS)
+ return res;
+
+ __have_no_fcntl64 = 1;
+
+ if (len64 != (off64_t) len)
+ {
+ /* We can't represent the length. */
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ }
+# endif
+ return __fcntl (fd, cmd, &fl);
+#endif
+}