1 /* Copyright (C) 2005, 2006 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
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 /* Running under Linux > 2.1.80. */
46 # if __ASSUME_32BITUIDS == 0
47 /* This variable is shared with all files that need to check for 32bit
49 extern int __libc_missing_32bit_uids
;
51 #endif /* __NR_chown32 */
54 fchownat (int fd
, const char *file
, uid_t owner
, gid_t group
, int flag
)
56 if (flag
& ~AT_SYMLINK_NOFOLLOW
)
64 if (fd
!= AT_FDCWD
&& file
[0] != '/')
66 size_t filelen
= strlen (file
);
67 static const char procfd
[] = "/proc/self/fd/%d/%s";
68 /* Buffer for the path name we are going to use. It consists of
69 - the string /proc/self/fd/
70 - the file descriptor number
71 - the file name provided.
72 The final NUL is included in the sizeof. A bit of overhead
73 due to the format elements compensates for possible negative
75 size_t buflen
= sizeof (procfd
) + sizeof (int) * 3 + filelen
;
76 buf
= alloca (buflen
);
78 __snprintf (buf
, buflen
, procfd
, fd
, file
);
83 INTERNAL_SYSCALL_DECL (err
);
85 #if __ASSUME_32BITUIDS > 0
86 result
= INTERNAL_SYSCALL (chown32
, err
, 3, CHECK_STRING (file
), owner
,
89 static int __libc_old_chown
;
92 if (__libc_missing_32bit_uids
<= 0)
94 if (flag
& AT_SYMLINK_NOFOLLOW
)
95 result
= INTERNAL_SYSCALL (lchown32
, err
, 3, CHECK_STRING (file
),
98 result
= INTERNAL_SYSCALL (chown32
, err
, 3, CHECK_STRING (file
),
101 if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result
, err
), 1))
103 if (INTERNAL_SYSCALL_ERRNO (result
, err
) != ENOSYS
)
106 __libc_missing_32bit_uids
= 1;
108 # endif /* __NR_chown32 */
109 if (((owner
+ 1) > (uid_t
) ((__kernel_uid_t
) -1U))
110 || ((group
+ 1) > (gid_t
) ((__kernel_gid_t
) -1U)))
112 __set_errno (EINVAL
);
116 if (!__libc_old_chown
&& (flag
& AT_SYMLINK_NOFOLLOW
) == 0)
118 result
= INTERNAL_SYSCALL (chown
, err
, 3, CHECK_STRING (file
), owner
,
121 if (!INTERNAL_SYSCALL_ERROR_P (result
, err
))
123 if (INTERNAL_SYSCALL_ERRNO (result
, err
) != ENOSYS
)
126 __libc_old_chown
= 1;
129 result
= INTERNAL_SYSCALL (lchown
, err
, 3, CHECK_STRING (file
), owner
,
133 if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result
, err
), 0))
136 __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result
, err
), fd
, buf
);