Mark compat code with attribute_compat_text_section.
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / i386 / chown.c
1 /* Copyright (C) 1998,1999,2000,2002,2003,2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <errno.h>
20 #include <unistd.h>
21
22 #include <sysdep.h>
23 #include <sys/syscall.h>
24 #include <shlib-compat.h>
25 #include <bp-checks.h>
26
27 #include <linux/posix_types.h>
28 #include "kernel-features.h"
29
30 /*
31   In Linux 2.1.x the chown functions have been changed.  A new function lchown
32   was introduced.  The new chown now follows symlinks - the old chown and the
33   new lchown do not follow symlinks.
34   The new lchown function has the same number as the old chown had and the
35   new chown has a new number.  When compiling with headers from Linux > 2.1.8x
36   it's impossible to run this libc with older kernels.  In these cases libc
37   has therefore to route calls to chown to the old chown function.
38 */
39
40 extern int __chown_is_lchown (const char *__file, uid_t __owner,
41                               gid_t __group);
42 extern int __real_chown (const char *__file, uid_t __owner, gid_t __group);
43
44
45 #if defined __NR_lchown || __ASSUME_LCHOWN_SYSCALL > 0
46 /* Running under Linux > 2.1.80.  */
47
48 # ifdef __NR_chown32
49 #  if __ASSUME_32BITUIDS == 0
50 /* This variable is shared with all files that need to check for 32bit
51    uids.  */
52 extern int __libc_missing_32bit_uids;
53 #  endif
54 # endif /* __NR_chown32 */
55
56 int
57 __real_chown (const char *file, uid_t owner, gid_t group)
58 {
59 # if __ASSUME_LCHOWN_SYSCALL == 0
60   static int __libc_old_chown;
61   int result;
62
63   if (!__libc_old_chown)
64     {
65       int saved_errno = errno;
66 #  ifdef __NR_chown32
67       if (__libc_missing_32bit_uids <= 0)
68         {
69           int result;
70           int saved_errno = errno;
71
72           result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
73           if (result == 0 || errno != ENOSYS)
74             return result;
75
76           __set_errno (saved_errno);
77           __libc_missing_32bit_uids = 1;
78         }
79 #  endif /* __NR_chown32 */
80       if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
81           || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
82         {
83           __set_errno (EINVAL);
84           return -1;
85         }
86
87       result = INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
88
89       if (result >= 0 || errno != ENOSYS)
90         return result;
91
92       __set_errno (saved_errno);
93       __libc_old_chown = 1;
94     }
95
96   return __lchown (file, owner, group);
97 # elif __ASSUME_32BITUIDS
98   /* This implies __ASSUME_LCHOWN_SYSCALL.  */
99   return INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
100 # else
101   /* !__ASSUME_32BITUIDS && ASSUME_LCHOWN_SYSCALL  */
102 #  ifdef __NR_chown32
103   if (__libc_missing_32bit_uids <= 0)
104     {
105       int result;
106       int saved_errno = errno;
107
108       result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
109       if (result == 0 || errno != ENOSYS)
110         return result;
111
112       __set_errno (saved_errno);
113       __libc_missing_32bit_uids = 1;
114     }
115 #  endif /* __NR_chown32 */
116   if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
117       || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
118     {
119       __set_errno (EINVAL);
120       return -1;
121     }
122
123   return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
124 # endif
125 }
126 #endif
127
128
129 #if !defined __NR_lchown && __ASSUME_LCHOWN_SYSCALL == 0
130 /* Compiling under older kernels.  */
131 int
132 __chown_is_lchown (const char *file, uid_t owner, gid_t group)
133 {
134   return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
135 }
136 #elif SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
137 /* Compiling for compatibiity.  */
138 int
139 attribute_compat_text_section
140 __chown_is_lchown (const char *file, uid_t owner, gid_t group)
141 {
142   return __lchown (file, owner, group);
143 }
144 #endif
145
146 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
147 compat_symbol (libc, __chown_is_lchown, chown, GLIBC_2_0);
148 #endif
149
150 #ifdef __NR_lchown
151 versioned_symbol (libc, __real_chown, chown, GLIBC_2_1);
152 strong_alias (__real_chown, __chown)
153 #else
154 strong_alias (__chown_is_lchown, __chown_is_lchown21)
155 versioned_symbol (libc, __chown_is_lchown21, chown, GLIBC_2_1);
156 strong_alias (__chown_is_lchown, __chown)
157 #endif
158 libc_hidden_def (__chown)