Git init
[framework/base/acl.git] / libacl / perm_copy_fd.c
1 /* Copy POSIX 1003.1e draft 17 (abandoned) ACLs between files. */
2  
3 /* Copyright (C) 2002 Andreas Gruenbacher <agruen@suse.de>, SuSE Linux AG.
4
5   This program 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.
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 GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #if defined (HAVE_CONFIG_H)
21 #include "config.h"
22 #endif
23 #if defined(HAVE_LIBACL_LIBACL_H)
24 # include "libacl.h"
25 #endif
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #if defined(HAVE_SYS_ACL_H)
34 #include <sys/acl.h>
35 #endif
36
37 #if defined(HAVE_ACL_LIBACL_H)
38 #include <acl/libacl.h>
39 #endif
40
41 #define ERROR_CONTEXT_MACROS
42 #ifdef HAVE_ATTR_ERROR_CONTEXT_H
43 #include <attr/error_context.h>
44 #else
45 #include "error_context.h"
46 #endif
47
48 #if !defined(ENOTSUP)
49 # define ENOTSUP (-1)
50 #endif
51
52 #if !defined(HAVE_ACL_FREE)
53 static int
54 acl_free(void *obj_p)
55 {
56         free (obj_p);
57         return 0;
58 }
59 #endif
60
61 #if !defined(HAVE_ACL_ENTRIES)
62 static int
63 acl_entries(acl_t acl)
64 {
65 # if defined(HAVE_ACL_GET_ENTRY)
66         /* POSIX 1003.1e draft 17 (abandoned) compatible version.  */
67         acl_entry_t entry;
68         int entries = 0;
69
70         int entries = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
71         if (entries > 0) {
72                 while (acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) > 0)
73                         entries++;
74         }
75         return entries;
76 # else
77         return -1;
78 # endif
79 }
80 #endif
81
82 #if !defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_FROM_TEXT)
83 # define HAVE_ACL_FROM_MODE
84 static acl_t
85 acl_from_mode(mode_t mode)
86 {
87         char acl_text[] = "u::---,g::---,o::---";
88         acl_t acl;
89
90         if (mode & S_IRUSR) acl_text[ 3] = 'r';
91         if (mode & S_IWUSR) acl_text[ 4] = 'w';
92         if (mode & S_IXUSR) acl_text[ 5] = 'x';
93         if (mode & S_IRGRP) acl_text[10] = 'r';
94         if (mode & S_IWGRP) acl_text[11] = 'w';
95         if (mode & S_IXGRP) acl_text[12] = 'x';
96         if (mode & S_IROTH) acl_text[17] = 'r';
97         if (mode & S_IWOTH) acl_text[18] = 'w';
98         if (mode & S_IXOTH) acl_text[19] = 'x';
99
100         return acl_from_text (acl_text);
101 }
102 #endif
103
104 /* Set the access control list of path to the permissions defined by mode.  */
105 static int
106 set_acl_fd (char const *path, int fd, mode_t mode, struct error_context *ctx)
107 {
108         int ret = 0;
109 #if defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_SET_FD)
110         /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
111         acl_t acl = acl_from_mode (mode);
112         if (!acl) {
113                 error (ctx, "");
114                 return -1;
115         }
116
117         if (acl_set_fd (fd, acl) != 0) {
118                 ret = -1;
119                 if (errno == ENOTSUP || errno == ENOSYS) {
120                         (void) acl_free (acl);
121                         goto chmod_only;
122                 } else {
123                         const char *qpath = quote (ctx, path);
124                         error (ctx, _("setting permissions for %s"), qpath);
125                         quote_free (ctx, qpath);
126                 }
127         }
128         (void) acl_free (acl);
129         return ret;
130 #endif
131
132 chmod_only:
133         ret = fchmod (fd, mode);
134         if (ret != 0) {
135                 const char *qpath = quote (ctx, path);
136                 error (ctx, _("setting permissions for %s"), qpath);
137                 quote_free (ctx, qpath);
138         }
139         return ret;
140 }
141
142 /* Copy the permissions of src_path to dst_path. This includes the
143    file mode permission bits and ACLs. File ownership is not copied.
144  */
145 int
146 perm_copy_fd (const char *src_path, int src_fd,
147                const char *dst_path, int dst_fd,
148                struct error_context *ctx)
149 {
150 #if defined(HAVE_ACL_GET_FD) && defined(HAVE_ACL_SET_FD)
151         acl_t acl;
152 #endif
153         struct stat st;
154         int ret = 0;
155
156         ret = fstat(src_fd, &st);
157         if (ret != 0) {
158                 const char *qpath = quote (ctx, src_path);
159                 error (ctx, "%s", qpath);
160                 quote_free (ctx, qpath);
161                 return -1;
162         }
163 #if defined(HAVE_ACL_GET_FD) && defined(HAVE_ACL_SET_FD)
164         /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
165         acl = acl_get_fd (src_fd);
166         if (acl == NULL) {
167                 ret = -1;
168                 if (errno == ENOSYS || errno == ENOTSUP)
169                         ret = set_acl_fd (dst_path, dst_fd, st.st_mode, ctx);
170                 else {
171                         const char *qpath = quote (ctx, src_path);
172                         error (ctx, "%s", qpath);
173                         quote_free (ctx, qpath);
174                 }
175                 return ret;
176         }
177
178         if (acl_set_fd (dst_fd, acl) != 0) {
179                 int saved_errno = errno;
180                 __apply_mask_to_mode(&st.st_mode, acl);
181                 ret = fchmod (dst_fd, st.st_mode);
182                 if ((errno != ENOSYS && errno != ENOTSUP) ||
183                     acl_entries (acl) != 3) {
184                         const char *qpath = quote (ctx, dst_path);
185                         errno = saved_errno;
186                         error (ctx, _("preserving permissions for %s"), qpath);
187                         quote_free (ctx, qpath);
188                         ret = -1;
189                 }
190         }
191         (void) acl_free (acl);
192         return ret;
193 #else
194         /* POSIX.1 version. */
195         ret = fchmod (dst_fd, st.st_mode);
196         if (ret != 0) {
197                 const char *qpath = quote (ctx, dst_path);
198                 error (ctx, _("setting permissions for %s"), qpath);
199                 quote_free (ctx, qpath);
200         }
201         return ret;
202 #endif
203 }
204