Back to index

glibc  2.9
fcntl.c
Go to the documentation of this file.
00001 /* Copyright (C) 2000,2002,2003,2004,2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <assert.h>
00020 #include <errno.h>
00021 #include <sysdep-cancel.h>  /* Must come before <fcntl.h>.  */
00022 #include <fcntl.h>
00023 #include <stdarg.h>
00024 
00025 #include <sys/syscall.h>
00026 #include <kernel-features.h>
00027 
00028 #if __ASSUME_FCNTL64 == 0
00029 /* This variable is shared with all files that check for fcntl64.  */
00030 int __have_no_fcntl64;
00031 #endif
00032 
00033 #if defined NO_CANCELLATION && __ASSUME_FCNTL64 == 0
00034 # define __fcntl_nocancel  __libc_fcntl
00035 #endif
00036 
00037 #if !defined NO_CANCELLATION || __ASSUME_FCNTL64 == 0
00038 int
00039 __fcntl_nocancel (int fd, int cmd, ...)
00040 {
00041   va_list ap;
00042   void *arg;
00043 
00044   va_start (ap, cmd);
00045   arg = va_arg (ap, void *);
00046   va_end (ap);
00047 
00048 #if __ASSUME_FCNTL64 == 0
00049 # ifdef __NR_fcntl64
00050   if (! __have_no_fcntl64)
00051     {
00052       int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
00053       if (result >= 0 || errno != ENOSYS)
00054        return result;
00055 
00056       __have_no_fcntl64 = 1;
00057     }
00058 # endif
00059   switch (cmd)
00060     {
00061     case F_GETLK64:
00062       /* Convert arg from flock64 to flock and back.  */
00063       {
00064        struct flock fl;
00065        struct flock64 *fl64 = arg;
00066        int res;
00067 
00068        fl.l_start = (off_t)fl64->l_start;
00069        /* Check if we can represent the values with the smaller type.  */
00070        if ((off64_t) fl.l_start != fl64->l_start)
00071          {
00072          eoverflow:
00073            __set_errno (EOVERFLOW);
00074            return -1;
00075          }
00076        fl.l_len = (off_t) fl64->l_len;
00077        /* Check if we can represent the values with the smaller type.  */
00078        if ((off64_t) fl.l_len != fl64->l_len)
00079          goto eoverflow;
00080 
00081        fl.l_type = fl64->l_type;
00082        fl.l_whence = fl64->l_whence;
00083        fl.l_pid = fl64->l_pid;
00084 
00085        res = INLINE_SYSCALL (fcntl, 3, fd, F_GETLK, &fl);
00086        if (res  != 0)
00087          return res;
00088        /* Everything ok, convert back.  */
00089        fl64->l_type = fl.l_type;
00090        fl64->l_whence = fl.l_whence;
00091        fl64->l_start = fl.l_start;
00092        fl64->l_len = fl.l_len;
00093        fl64->l_pid = fl.l_pid;
00094 
00095        return 0;
00096       }
00097     case F_SETLK64:
00098     case F_SETLKW64:
00099       /* Try to convert arg from flock64 to flock.  */
00100       {
00101        struct flock fl;
00102        struct flock64 *fl64 = arg;
00103 
00104        fl.l_start = (off_t) fl64->l_start;
00105        /* Check if we can represent the values with the smaller type.  */
00106        if ((off64_t) fl.l_start != fl64->l_start)
00107          goto eoverflow;
00108 
00109        fl.l_len = (off_t)fl64->l_len;
00110        /* Check if we can represent the values with the smaller type.  */
00111        if ((off64_t) fl.l_len != fl64->l_len)
00112          {
00113            __set_errno (EOVERFLOW);
00114            return -1;
00115          }
00116        fl.l_type = fl64->l_type;
00117        fl.l_whence = fl64->l_whence;
00118        fl.l_pid = fl64->l_pid;
00119        assert (F_SETLK - F_SETLKW == F_SETLK64 - F_SETLKW64);
00120        return INLINE_SYSCALL (fcntl, 3, fd, cmd + F_SETLK - F_SETLK64, &fl);
00121       }
00122     default:
00123       return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
00124     }
00125   return -1;
00126 #else
00127   return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
00128 #endif  /* !__ASSUME_FCNTL64  */
00129 }
00130 #endif /* NO_CANCELLATION || !__ASSUME_FCNTL64 */
00131 
00132 
00133 #ifndef __fcntl_nocancel
00134 int
00135 __libc_fcntl (int fd, int cmd, ...)
00136 {
00137   va_list ap;
00138   void *arg;
00139 
00140   va_start (ap, cmd);
00141   arg = va_arg (ap, void *);
00142   va_end (ap);
00143 
00144 #if __ASSUME_FCNTL64 > 0
00145   if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64))
00146     return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
00147 
00148   int oldtype = LIBC_CANCEL_ASYNC ();
00149 
00150   int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
00151 #else
00152   if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64))
00153     return __fcntl_nocancel (fd, cmd, arg);
00154 
00155   int oldtype = LIBC_CANCEL_ASYNC ();
00156 
00157   int result = __fcntl_nocancel (fd, cmd, arg);
00158 #endif
00159 
00160   LIBC_CANCEL_RESET (oldtype);
00161 
00162   return result;
00163 }
00164 #endif
00165 libc_hidden_def (__libc_fcntl)
00166 
00167 weak_alias (__libc_fcntl, __fcntl)
00168 libc_hidden_weak (__fcntl)
00169 weak_alias (__libc_fcntl, fcntl)