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