265c2f72ec1d442fabf862840b8daf4fa421e926
[gnulib.git] / lib / lchown.c
1 /* Provide a stub lchown function for systems that lack it.
2
3    Copyright (C) 1998, 1999, 2002, 2004, 2006, 2007, 2009 Free
4    Software Foundation, Inc.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 /* written by Jim Meyering */
20
21 #include <config.h>
22
23 #include <unistd.h>
24
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/stat.h>
28
29 #if !HAVE_LCHOWN
30
31 /* If the system chown does not follow symlinks, we don't want it
32    replaced by gnulib's chown, which does follow symlinks.  */
33 # if CHOWN_MODIFIES_SYMLINK
34 #  undef chown
35 # endif
36
37 /* Work just like chown, except when FILE is a symbolic link.
38    In that case, set errno to EOPNOTSUPP and return -1.
39    But if autoconf tests determined that chown modifies
40    symlinks, then just call chown.  */
41
42 int
43 lchown (const char *file, uid_t uid, gid_t gid)
44 {
45 # if HAVE_CHOWN
46 #  if ! CHOWN_MODIFIES_SYMLINK
47   struct stat stats;
48
49   if (lstat (file, &stats) == 0 && S_ISLNK (stats.st_mode))
50     {
51       errno = EOPNOTSUPP;
52       return -1;
53     }
54 #  endif
55
56   return chown (file, uid, gid);
57
58 # else /* !HAVE_CHOWN */
59   errno = ENOSYS;
60   return -1;
61 # endif
62 }
63
64 #else /* HAVE_LCHOWN */
65
66 # undef lchown
67
68 /* Work around trailing slash bugs in lchown.  */
69 int
70 rpl_lchown (const char *file, uid_t uid, gid_t gid)
71 {
72   size_t len = strlen (file);
73   if (len && file[len - 1] == '/')
74     return chown (file, uid, gid);
75   return lchown (file, uid, gid);
76 }
77
78 #endif /* HAVE_LCHOWN */