Tizen 2.0 Release
[external/tizen-coreutils.git] / lib / acl.c
1 /* acl.c - access control lists
2
3    Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program 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
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19    Written by Paul Eggert and Andreas Gruenbacher.  */
20
21 #include <config.h>
22
23 #include "acl.h"
24
25 #include "acl-internal.h"
26
27 /* If DESC is a valid file descriptor use fchmod to change the
28    file's mode to MODE on systems that have fchown. On systems
29    that don't have fchown and if DESC is invalid, use chown on
30    NAME instead.  */
31
32 int
33 chmod_or_fchmod (const char *name, int desc, mode_t mode)
34 {
35   if (HAVE_FCHMOD && desc != -1)
36     return fchmod (desc, mode);
37   else
38     return chmod (name, mode);
39 }
40
41 /* Copy access control lists from one file to another. If SOURCE_DESC is
42    a valid file descriptor, use file descriptor operations, else use
43    filename based operations on SRC_NAME. Likewise for DEST_DESC and
44    DEST_NAME.
45    If access control lists are not available, fchmod the target file to
46    MODE.  Also sets the non-permission bits of the destination file
47    (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
48    System call return value semantics.  */
49
50 int
51 copy_acl (const char *src_name, int source_desc, const char *dst_name,
52           int dest_desc, mode_t mode)
53 {
54   int ret;
55
56 #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
57   /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
58
59   acl_t acl;
60   if (HAVE_ACL_GET_FD && source_desc != -1)
61     acl = acl_get_fd (source_desc);
62   else
63     acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
64   if (acl == NULL)
65     {
66       if (ACL_NOT_WELL_SUPPORTED (errno))
67         return set_acl (dst_name, dest_desc, mode);
68       else
69         {
70           error (0, errno, "%s", quote (src_name));
71           return -1;
72         }
73     }
74
75   if (HAVE_ACL_SET_FD && dest_desc != -1)
76     ret = acl_set_fd (dest_desc, acl);
77   else
78     ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
79   if (ret != 0)
80     {
81       int saved_errno = errno;
82
83       if (ACL_NOT_WELL_SUPPORTED (errno))
84         {
85           int n = acl_entries (acl);
86
87           acl_free (acl);
88           if (n == 3)
89             {
90               if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
91                 saved_errno = errno;
92               else
93                 return 0;
94             }
95           else
96             chmod_or_fchmod (dst_name, dest_desc, mode);
97         }
98       else
99         {
100           acl_free (acl);
101           chmod_or_fchmod (dst_name, dest_desc, mode);
102         }
103       error (0, saved_errno, _("preserving permissions for %s"),
104              quote (dst_name));
105       return -1;
106     }
107   else
108     acl_free (acl);
109
110   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
111     {
112       /* We did not call chmod so far, so the special bits have not yet
113          been set.  */
114
115       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
116         {
117           error (0, errno, _("preserving permissions for %s"),
118                  quote (dst_name));
119           return -1;
120         }
121     }
122
123   if (S_ISDIR (mode))
124     {
125       acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
126       if (acl == NULL)
127         {
128           error (0, errno, "%s", quote (src_name));
129           return -1;
130         }
131
132       if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
133         {
134           error (0, errno, _("preserving permissions for %s"),
135                  quote (dst_name));
136           acl_free (acl);
137           return -1;
138         }
139       else
140         acl_free (acl);
141     }
142   return 0;
143 #else
144   ret = chmod_or_fchmod (dst_name, dest_desc, mode);
145   if (ret != 0)
146     error (0, errno, _("preserving permissions for %s"), quote (dst_name));
147   return ret;
148 #endif
149 }
150
151 /* Set the access control lists of a file. If DESC is a valid file
152    descriptor, use file descriptor operations where available, else use
153    filename based operations on NAME.  If access control lists are not
154    available, fchmod the target file to MODE.  Also sets the
155    non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
156    to those from MODE if any are set.  System call return value
157    semantics.  */
158
159 int
160 set_acl (char const *name, int desc, mode_t mode)
161 {
162 #if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
163   /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
164
165   /* We must also have have_acl_from_text and acl_delete_def_file.
166      (acl_delete_def_file could be emulated with acl_init followed
167       by acl_set_file, but acl_set_file with an empty acl is
168       unspecified.)  */
169
170 # ifndef HAVE_ACL_FROM_TEXT
171 #  error Must have acl_from_text (see POSIX 1003.1e draft 17).
172 # endif
173 # ifndef HAVE_ACL_DELETE_DEF_FILE
174 #  error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
175 # endif
176
177   acl_t acl;
178   int ret;
179
180   if (HAVE_ACL_FROM_MODE)
181     {
182       acl = acl_from_mode (mode);
183       if (!acl)
184         {
185           error (0, errno, "%s", quote (name));
186           return -1;
187         }
188     }
189   else
190     {
191       char acl_text[] = "u::---,g::---,o::---";
192
193       if (mode & S_IRUSR) acl_text[ 3] = 'r';
194       if (mode & S_IWUSR) acl_text[ 4] = 'w';
195       if (mode & S_IXUSR) acl_text[ 5] = 'x';
196       if (mode & S_IRGRP) acl_text[10] = 'r';
197       if (mode & S_IWGRP) acl_text[11] = 'w';
198       if (mode & S_IXGRP) acl_text[12] = 'x';
199       if (mode & S_IROTH) acl_text[17] = 'r';
200       if (mode & S_IWOTH) acl_text[18] = 'w';
201       if (mode & S_IXOTH) acl_text[19] = 'x';
202
203       acl = acl_from_text (acl_text);
204       if (!acl)
205         {
206           error (0, errno, "%s", quote (name));
207           return -1;
208         }
209     }
210   if (HAVE_ACL_SET_FD && desc != -1)
211     ret = acl_set_fd (desc, acl);
212   else
213     ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
214   if (ret != 0)
215     {
216       int saved_errno = errno;
217       acl_free (acl);
218
219       if (ACL_NOT_WELL_SUPPORTED (errno))
220         {
221           if (chmod_or_fchmod (name, desc, mode) != 0)
222             saved_errno = errno;
223           else
224             return 0;
225         }
226       error (0, saved_errno, _("setting permissions for %s"), quote (name));
227       return -1;
228     }
229   else
230     acl_free (acl);
231
232   if (S_ISDIR (mode) && acl_delete_def_file (name))
233     {
234       error (0, errno, _("setting permissions for %s"), quote (name));
235       return -1;
236     }
237
238   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
239     {
240       /* We did not call chmod so far, so the special bits have not yet
241          been set.  */
242
243       if (chmod_or_fchmod (name, desc, mode))
244         {
245           error (0, errno, _("preserving permissions for %s"), quote (name));
246           return -1;
247         }
248     }
249   return 0;
250 #else
251    int ret = chmod_or_fchmod (name, desc, mode);
252    if (ret)
253      error (0, errno, _("setting permissions for %s"), quote (name));
254    return ret;
255 #endif
256 }