ce44338d5ebbe7e6c66946a23f47cc720b28b0f1
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / i386 / chown.c
1 /* Copyright (C) 1998, 1999, 2000 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 Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    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    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 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 __syscall_chown (const char *__file,
41                             __kernel_uid_t __owner, __kernel_gid_t __group);
42 #if defined __NR_lchown || __ASSUME_LCHOWN_SYSCALL > 0
43 /* Running under Linux > 2.1.80.  */
44
45 # ifdef __NR_chown32
46 extern int __syscall_chown32 (const char *__file,
47                               __kernel_uid32_t owner, __kernel_gid32_t group);
48 #  if __ASSUME_32BITUIDS == 0
49 /* This variable is shared with all files that need to check for 32bit
50    uids.  */
51 extern int __libc_missing_32bit_uids;
52 #  endif
53 # endif /* __NR_chown32 */
54
55 int
56 __real_chown (const char *file, uid_t owner, gid_t group)
57 {
58 # if __ASSUME_LCHOWN_SYSCALL == 0
59   static int __libc_old_chown;
60   int result;
61
62   if (!__libc_old_chown)
63     {
64       int saved_errno = errno;
65 #  ifdef __NR_chown32
66       if (__libc_missing_32bit_uids <= 0)
67         {
68           int result;
69           int saved_errno = errno;
70
71           result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
72           if (result == 0 || errno != ENOSYS)
73             return result;
74
75           __set_errno (saved_errno);
76           __libc_missing_32bit_uids = 1;
77         }
78 #  endif /* __NR_chown32 */
79       if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
80           || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
81         {
82           __set_errno (EINVAL);
83           return -1;
84         }
85
86       result = INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
87
88       if (result >= 0 || errno != ENOSYS)
89         return result;
90
91       __set_errno (saved_errno);
92       __libc_old_chown = 1;
93     }
94
95   return __lchown (file, owner, group);
96 # elif __ASSUME_32BITUIDS
97   /* This implies __ASSUME_LCHOWN_SYSCALL.  */
98   return INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
99 # else
100   /* !__ASSUME_32BITUIDS && ASSUME_LCHOWN_SYSCALL  */
101 #  ifdef __NR_chown32
102   if (__libc_missing_32bit_uids <= 0)
103     {
104       int result;
105       int saved_errno = errno;
106
107       result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group);
108       if (result == 0 || errno != ENOSYS)
109         return result;
110
111       __set_errno (saved_errno);
112       __libc_missing_32bit_uids = 1;
113     }
114 #  endif /* __NR_chown32 */
115   if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
116       || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
117     {
118       __set_errno (EINVAL);
119       return -1;
120     }
121
122   return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
123 # endif
124 }
125 #endif
126
127
128 #if !defined __NR_lchown && __ASSUME_LCHOWN_SYSCALL == 0
129 /* Compiling under older kernels.  */
130 int
131 __chown_is_lchown (const char *file, uid_t owner, gid_t group)
132 {
133   return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group);
134 }
135 #elif SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
136 /* Compiling for compatibiity.  */
137 int
138 __chown_is_lchown (const char *file, uid_t owner, gid_t group)
139 {
140   return __lchown (file, owner, group);
141 }
142 #endif
143
144 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
145 strong_alias (__chown_is_lchown, _chown_is_lchown)
146 compat_symbol (libc, __chown_is_lchown, __chown, GLIBC_2_0);
147 compat_symbol (libc, _chown_is_lchown, chown, GLIBC_2_0);
148
149 # ifdef __NR_lchown
150 strong_alias (__real_chown, _real_chown)
151 versioned_symbol (libc, __real_chown, __chown, GLIBC_2_1);
152 versioned_symbol (libc, _real_chown, chown, GLIBC_2_1);
153 # else
154 strong_alias (__chown_is_lchown, __chown_is_lchown21)
155 strong_alias (__chown_is_lchown, _chown_is_lchown21)
156 versioned_symbol (libc, __chown_is_lchown21, __chown, GLIBC_2_1);
157 versioned_symbol (libc, _chown_is_lchown21, chown, GLIBC_2_1);
158 # endif
159 #else
160 # ifdef __NR_lchown
161 strong_alias (__real_chown, __chown)
162 weak_alias (__real_chown, chown)
163 # else
164 strong_alias (__chown_is_lchown, __chown)
165 weak_alias (__chown_is_lchown, chown)
166 # endif
167 #endif