Back to index

glibc  2.9
chown.c
Go to the documentation of this file.
00001 /* Copyright (C) 1998,1999,2000,2002,2003,2004,2006
00002        Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <unistd.h>
00022 
00023 #include <sysdep.h>
00024 #include <sys/syscall.h>
00025 #include <shlib-compat.h>
00026 #include <bp-checks.h>
00027 
00028 #include <linux/posix_types.h>
00029 #include <kernel-features.h>
00030 
00031 /*
00032   In Linux 2.1.x the chown functions have been changed.  A new function lchown
00033   was introduced.  The new chown now follows symlinks - the old chown and the
00034   new lchown do not follow symlinks.
00035   The new lchown function has the same number as the old chown had and the
00036   new chown has a new number.  When compiling with headers from Linux > 2.1.8x
00037   it's impossible to run this libc with older kernels.  In these cases libc
00038   has therefore to route calls to chown to the old chown function.
00039 */
00040 
00041 extern int __chown_is_lchown (const char *__file, uid_t __owner,
00042                            gid_t __group);
00043 extern int __real_chown (const char *__file, uid_t __owner, gid_t __group);
00044 
00045 
00046 #if defined __NR_lchown || __ASSUME_LCHOWN_SYSCALL > 0
00047 /* Running under Linux > 2.1.80.  */
00048 
00049 # ifdef __NR_chown32
00050 #  if __ASSUME_32BITUIDS == 0
00051 /* This variable is shared with all files that need to check for 32bit
00052    uids.  */
00053 extern int __libc_missing_32bit_uids;
00054 #  endif
00055 # endif /* __NR_chown32 */
00056 
00057 int
00058 __real_chown (const char *file, uid_t owner, gid_t group)
00059 {
00060 # if __ASSUME_LCHOWN_SYSCALL == 0
00061   static int __libc_old_chown;
00062   int result;
00063 
00064   if (!__libc_old_chown)
00065     {
00066       int saved_errno = errno;
00067 #  ifdef __NR_chown32
00068       if (__libc_missing_32bit_uids <= 0)
00069        {
00070          int result;
00071          int saved_errno = errno;
00072 
00073          result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
00074          if (result == 0 || errno != ENOSYS)
00075            return result;
00076 
00077          __set_errno (saved_errno);
00078          __libc_missing_32bit_uids = 1;
00079        }
00080 #  endif /* __NR_chown32 */
00081       if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
00082          || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
00083        {
00084          __set_errno (EINVAL);
00085          return -1;
00086        }
00087 
00088       result = INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
00089 
00090       if (result >= 0 || errno != ENOSYS)
00091        return result;
00092 
00093       __set_errno (saved_errno);
00094       __libc_old_chown = 1;
00095     }
00096 
00097   return __lchown (file, owner, group);
00098 # elif __ASSUME_32BITUIDS
00099   /* This implies __ASSUME_LCHOWN_SYSCALL.  */
00100   return INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
00101 # else
00102   /* !__ASSUME_32BITUIDS && ASSUME_LCHOWN_SYSCALL  */
00103 #  ifdef __NR_chown32
00104   if (__libc_missing_32bit_uids <= 0)
00105     {
00106       int result;
00107       int saved_errno = errno;
00108 
00109       result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
00110       if (result == 0 || errno != ENOSYS)
00111        return result;
00112 
00113       __set_errno (saved_errno);
00114       __libc_missing_32bit_uids = 1;
00115     }
00116 #  endif /* __NR_chown32 */
00117   if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
00118       || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
00119     {
00120       __set_errno (EINVAL);
00121       return -1;
00122     }
00123 
00124   return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
00125 # endif
00126 }
00127 #endif
00128 
00129 
00130 #if !defined __NR_lchown && __ASSUME_LCHOWN_SYSCALL == 0
00131 /* Compiling under older kernels.  */
00132 int
00133 __chown_is_lchown (const char *file, uid_t owner, gid_t group)
00134 {
00135   return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
00136 }
00137 #elif SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
00138 /* Compiling for compatibiity.  */
00139 int
00140 attribute_compat_text_section
00141 __chown_is_lchown (const char *file, uid_t owner, gid_t group)
00142 {
00143   return __lchown (file, owner, group);
00144 }
00145 #endif
00146 
00147 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
00148 compat_symbol (libc, __chown_is_lchown, chown, GLIBC_2_0);
00149 #endif
00150 
00151 #ifdef __NR_lchown
00152 versioned_symbol (libc, __real_chown, chown, GLIBC_2_1);
00153 strong_alias (__real_chown, __chown)
00154 #else
00155 strong_alias (__chown_is_lchown, __chown_is_lchown21)
00156 versioned_symbol (libc, __chown_is_lchown21, chown, GLIBC_2_1);
00157 strong_alias (__chown_is_lchown, __chown)
00158 #endif
00159 libc_hidden_def (__chown)