2.9
[glibc/nacl-glibc.git] / sysdeps / unix / sysv / linux / powerpc / chown.c
blobfdcbd3683a8c97c8b61c0f8af77b8123511b285b
1 /* chown() compatibility.
2 Copyright (C) 1998, 2000, 2002, 2003, 2005 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 <string.h>
22 #include <unistd.h>
23 #include <limits.h>
24 #include <sysdep.h>
25 #include <stdlib.h>
27 #include <kernel-features.h>
30 In Linux 2.1.x the chown functions have been changed. A new function lchown
31 was introduced. The new chown now follows symlinks - the old chown and the
32 new lchown do not follow symlinks.
33 This file emulates chown() under the old kernels.
36 int
37 __chown (const char *file, uid_t owner, gid_t group)
39 #if __ASSUME_LCHOWN_SYSCALL
40 return INLINE_SYSCALL (chown, 3, file, owner, group);
41 #else
42 int err;
43 int old_errno;
44 char link[PATH_MAX + 2];
45 char path[2 * PATH_MAX + 4];
46 int loopct;
47 size_t filelen;
48 static int libc_old_chown = 0 /* -1=old linux, 1=new linux, 0=unknown */;
50 if (libc_old_chown == 1)
51 return INLINE_SYSCALL (chown, 3, __ptrvalue (file), owner, group);
53 old_errno = errno;
55 # ifdef __NR_lchown
56 if (libc_old_chown == 0)
58 err = INLINE_SYSCALL (chown, 3, __ptrvalue (file), owner, group);
59 if (err != -1 || errno != ENOSYS)
61 libc_old_chown = 1;
62 return err;
64 libc_old_chown = -1;
66 # endif
68 err = __readlink (file, link, PATH_MAX + 1);
69 if (err == -1)
71 __set_errno (old_errno);
72 return __lchown (file, owner, group);
75 filelen = strlen (file) + 1;
76 if (filelen > sizeof (path))
78 __set_errno (ENAMETOOLONG);
79 return -1;
81 memcpy (path, file, filelen);
83 /* 'The system has an arbitrary limit...' In practise, we'll hit
84 ENAMETOOLONG before this, usually. */
85 for (loopct = 0; loopct < 128; ++loopct)
87 size_t linklen;
89 if (err >= PATH_MAX + 1)
91 __set_errno (ENAMETOOLONG);
92 return -1;
95 link[err] = 0; /* Null-terminate string, just-in-case. */
97 linklen = strlen (link) + 1;
99 if (link[0] == '/')
100 memcpy (path, link, linklen);
101 else
103 filelen = strlen (path);
105 while (filelen > 1 && path[filelen - 1] == '/')
106 --filelen;
107 while (filelen > 0 && path[filelen - 1] != '/')
108 --filelen;
109 if (filelen + linklen > sizeof (path))
111 errno = ENAMETOOLONG;
112 return -1;
114 memcpy (path + filelen, link, linklen);
117 err = __readlink (path, link, PATH_MAX + 1);
119 if (err == -1)
121 __set_errno (old_errno);
122 return __lchown (path, owner, group);
125 __set_errno (ELOOP);
126 return -1;
127 #endif
129 libc_hidden_def (__chown)
131 #include <shlib-compat.h>
132 versioned_symbol (libc, __chown, chown, GLIBC_2_1);