]> git.cworth.org Git - tar/blob - gnu/lchown.c
0753010b9b994220fb9d895b6306d04e800164ae
[tar] / gnu / lchown.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* Provide a stub lchown function for systems that lack it.
4
5    Copyright (C) 1998-1999, 2002, 2004, 2006-2007, 2009-2010 Free Software
6    Foundation, Inc.
7
8    This program is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21 /* written by Jim Meyering */
22
23 #include <config.h>
24
25 #include <unistd.h>
26
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <string.h>
30 #include <sys/stat.h>
31
32 #if !HAVE_LCHOWN
33
34 /* If the system chown does not follow symlinks, we don't want it
35    replaced by gnulib's chown, which does follow symlinks.  */
36 # if CHOWN_MODIFIES_SYMLINK
37 #  undef chown
38 # endif
39
40 /* Work just like chown, except when FILE is a symbolic link.
41    In that case, set errno to EOPNOTSUPP and return -1.
42    But if autoconf tests determined that chown modifies
43    symlinks, then just call chown.  */
44
45 int
46 lchown (const char *file, uid_t uid, gid_t gid)
47 {
48 # if HAVE_CHOWN
49 #  if ! CHOWN_MODIFIES_SYMLINK
50   struct stat stats;
51
52   if (lstat (file, &stats) == 0 && S_ISLNK (stats.st_mode))
53     {
54       errno = EOPNOTSUPP;
55       return -1;
56     }
57 #  endif
58
59   return chown (file, uid, gid);
60
61 # else /* !HAVE_CHOWN */
62   errno = ENOSYS;
63   return -1;
64 # endif
65 }
66
67 #else /* HAVE_LCHOWN */
68
69 # undef lchown
70
71 /* Work around trailing slash bugs in lchown.  */
72 int
73 rpl_lchown (const char *file, uid_t uid, gid_t gid)
74 {
75   struct stat st;
76   bool stat_valid = false;
77   int result;
78
79 # if CHOWN_CHANGE_TIME_BUG
80   if (gid != (gid_t) -1 || uid != (uid_t) -1)
81     {
82       if (lstat (file, &st))
83         return -1;
84       stat_valid = true;
85       if (!S_ISLNK (st.st_mode))
86         return chown (file, uid, gid);
87     }
88 # endif
89
90 # if CHOWN_TRAILING_SLASH_BUG
91   if (!stat_valid)
92     {
93       size_t len = strlen (file);
94       if (len && file[len - 1] == '/')
95         return chown (file, uid, gid);
96     }
97 # endif
98
99   result = lchown (file, uid, gid);
100
101 # if CHOWN_CHANGE_TIME_BUG && HAVE_LCHMOD
102   if (result == 0 && stat_valid
103       && (uid == st.st_uid || uid == (uid_t) -1)
104       && (gid == st.st_gid || gid == (gid_t) -1))
105     {
106       /* No change in ownership, but at least one argument was not -1,
107          so we are required to update ctime.  Since lchown succeeded,
108          we assume that lchmod will do likewise.  But if the system
109          lacks lchmod and lutimes, we are out of luck.  Oh well.  */
110       result = lchmod (file, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO
111                                            | S_ISUID | S_ISGID | S_ISVTX));
112     }
113 # endif
114
115   return result;
116 }
117
118 #endif /* HAVE_LCHOWN */