Updated to fedora-glibc-20051116T0829
[glibc.git] / sysdeps / unix / sysv / linux / i386 / fchownat.c
blobeb74fad8e01cbd395b273eff9f4794b09f45b8ad
1 /* Copyright (C) 2005 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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. */
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include <sysdep.h>
26 #include <sys/syscall.h>
27 #include <shlib-compat.h>
28 #include <bp-checks.h>
30 #include <linux/posix_types.h>
31 #include "kernel-features.h"
34 In Linux 2.1.x the chown functions have been changed. A new function lchown
35 was introduced. The new chown now follows symlinks - the old chown and the
36 new lchown do not follow symlinks.
37 The new lchown function has the same number as the old chown had and the
38 new chown has a new number. When compiling with headers from Linux > 2.1.8x
39 it's impossible to run this libc with older kernels. In these cases libc
40 has therefore to route calls to chown to the old chown function.
43 extern int __chown_is_lchown (const char *__file, uid_t __owner,
44 gid_t __group);
45 extern int __real_chown (const char *__file, uid_t __owner, gid_t __group);
48 #if defined __NR_lchown || __ASSUME_LCHOWN_SYSCALL > 0
49 /* Running under Linux > 2.1.80. */
51 # ifdef __NR_chown32
52 # if __ASSUME_32BITUIDS == 0
53 /* This variable is shared with all files that need to check for 32bit
54 uids. */
55 extern int __libc_missing_32bit_uids;
56 # endif
57 # endif /* __NR_chown32 */
58 #endif
61 int
62 fchownat (int fd, const char *file, uid_t owner, gid_t group, int flag)
64 if (flag & ~AT_SYMLINK_NOFOLLOW)
66 __set_errno (EINVAL);
67 return -1;
70 char *buf = NULL;
72 if (fd != AT_FDCWD && file[0] != '/')
74 size_t filelen = strlen (file);
75 static const char procfd[] = "/proc/self/fd/%d/%s";
76 /* Buffer for the path name we are going to use. It consists of
77 - the string /proc/self/fd/
78 - the file descriptor number
79 - the file name provided.
80 The final NUL is included in the sizeof. A bit of overhead
81 due to the format elements compensates for possible negative
82 numbers. */
83 size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
84 buf = alloca (buflen);
86 __snprintf (buf, buflen, procfd, fd, file);
87 file = buf;
90 int result;
91 INTERNAL_SYSCALL_DECL (err);
93 #if defined __NR_lchown || __ASSUME_LCHOWN_SYSCALL > 0
94 # if __ASSUME_LCHOWN_SYSCALL == 0
95 static int __libc_old_chown;
97 # ifdef __NR_chown32
98 if (__libc_missing_32bit_uids <= 0)
100 if (flag & AT_SYMLINK_NOFOLLOW)
101 result = INTERNAL_SYSCALL (lchown32, err, 3, CHECK_STRING (file),
102 owner, group);
103 else
104 result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file),
105 owner, group);
107 if (!INTERNAL_SYSCALL_ERROR_P (result, err))
108 return result;
109 if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
110 goto fail;
112 __libc_missing_32bit_uids = 1;
114 # endif /* __NR_chown32 */
116 if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
117 || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
119 __set_errno (EINVAL);
120 return -1;
123 if (!__libc_old_chown && (flag & AT_SYMLINK_NOFOLLOW) == 0)
125 result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner,
126 group);
128 if (!INTERNAL_SYSCALL_ERROR_P (result, err))
129 return result;
130 if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
131 goto fail;
133 __libc_old_chown = 1;
136 result = INTERNAL_SYSCALL (lchown, err, 3, CHECK_STRING (file), owner,
137 group);
138 # elif __ASSUME_32BITUIDS
139 /* This implies __ASSUME_LCHOWN_SYSCALL. */
140 result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
141 group);
142 # else
143 /* !__ASSUME_32BITUIDS && ASSUME_LCHOWN_SYSCALL */
144 # ifdef __NR_chown32
145 if (__libc_missing_32bit_uids <= 0)
147 result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
148 group);
149 if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
150 return result;
151 if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
152 goto fail;
154 __libc_missing_32bit_uids = 1;
156 # endif /* __NR_chown32 */
157 if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
158 || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
160 __set_errno (EINVAL);
161 return -1;
164 result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner, group);
165 # endif
166 #else
167 result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner, group);
168 #endif
170 if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
172 fail:
173 __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
174 result = -1;
177 return result;