1 /*
2 Copyright (C) 2002 Andreas Gruenbacher <agruen@suse.de>, SuSE Linux AG.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this manual. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /* Copy extended attributes between files. */
19
20 #if defined (HAVE_CONFIG_H)
21 #include "config.h"
22 #endif
23
24 #include <sys/types.h>
25 # include <sys/xattr.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #if defined(HAVE_ALLOCA_H)
31 # include <alloca.h>
32 #endif
33
34 #if defined(HAVE_ATTR_LIBATTR_H)
35 # include "attr/libattr.h"
36 #endif
37
38 #define ERROR_CONTEXT_MACROS
39 #include "error_context.h"
40 #include "nls.h"
41
42 #if !defined(ENOTSUP)
43 # define ENOTSUP (-1)
44 #endif
45
46 #if defined(HAVE_ALLOCA)
47 # define my_alloc(size) alloca (size)
48 # define my_free(ptr) do { } while(0)
49 #else
50 # define my_alloc(size) malloc (size)
51 # define my_free(ptr) free (ptr)
52 #endif
53
54 /* Copy extended attributes from src_path to dst_path. If the file
55 has an extended Access ACL (system.posix_acl_access) and that is
56 copied successfully, the file mode permission bits are copied as
57 a side effect. This may not always the case, so the file mode
58 and/or ownership must be copied separately. */
59 int
60 attr_copy_fd(const char *src_path, int src_fd,
61 const char *dst_path, int dst_fd,
62 int (*check) (const char *, struct error_context *),
63 struct error_context *ctx)
64 {
65 #if defined(HAVE_FLISTXATTR) && defined(HAVE_FGETXATTR) && \
66 defined(HAVE_FSETXATTR)
67 int ret = 0;
68 ssize_t size;
69 char *names = NULL, *end_names, *name, *value = NULL;
70 unsigned int setxattr_ENOTSUP = 0;
71
72 /* ignore acls by default */
73 if (check == NULL)
74 check = attr_copy_check_permissions;
75
76 size = flistxattr (src_fd, NULL, 0);
77 if (size < 0) {
78 if (errno != ENOSYS && errno != ENOTSUP) {
79 const char *qpath = quote (ctx, src_path);
80 error (ctx, _("listing attributes of %s"), qpath);
81 quote_free (ctx, qpath);
82 ret = -1;
83 }
84 goto getout;
85 }
86 names = (char *) my_alloc (size+1);
87 if (names == NULL) {
88 error (ctx, "");
89 ret = -1;
90 goto getout;
91 }
92 size = flistxattr (src_fd, names, size);
93 if (size < 0) {
94 const char *qpath = quote (ctx, src_path);
95 error (ctx, _("listing attributes of %s"), qpath);
96 quote_free (ctx, qpath);
97 ret = -1;
98 goto getout;
99 } else {
100 names[size] = '\0';
101 end_names = names + size;
102 }
103
104 for (name = names; name != end_names; name = strchr(name, '\0') + 1) {
105 void *old_value;
106
107 /* check if this attribute shall be preserved */
108 if (!*name || !check(name, ctx))
109 continue;
110
111 size = fgetxattr (src_fd, name, NULL, 0);
112 if (size < 0) {
113 const char *qpath = quote (ctx, src_path);
114 const char *qname = quote (ctx, name);
115 error (ctx, _("getting attribute %s of %s"),
116 qname, qpath);
117 quote_free (ctx, qname);
118 quote_free (ctx, qpath);
119 ret = -1;
120 continue;
121 }
122 value = (char *) realloc (old_value = value, size);
123 if (size != 0 && value == NULL) {
124 free(old_value);
125 error (ctx, "");
126 ret = -1;
127 }
128 size = fgetxattr (src_fd, name, value, size);
129 if (size < 0) {
130 const char *qpath = quote (ctx, src_path);
131 const char *qname = quote (ctx, name);
132 error (ctx, _("getting attribute %s of %s"),
133 qname, qpath);
134 quote_free (ctx, qname);
135 quote_free (ctx, qpath);
136 ret = -1;
137 continue;
138 }
139 if (fsetxattr (dst_fd, name, value, size, 0) != 0) {
140 if (errno == ENOTSUP)
141 setxattr_ENOTSUP++;
142 else {
143 const char *qpath = quote (ctx, dst_path);
144 if (errno == ENOSYS) {
145 error (ctx, _("setting attributes for "
146 "%s"), qpath);
147 ret = -1;
148 /* no hope of getting any further */
149 break;
150 } else {
151 const char *qname = quote (ctx, name);
152 error (ctx, _("setting attribute %s for "
153 "%s"), qname, qpath);
154 quote_free (ctx, qname);
155 ret = -1;
156 }
157 quote_free (ctx, qpath);
158 }
159 }
160 }
161 if (setxattr_ENOTSUP) {
162 const char *qpath = quote (ctx, dst_path);
163 errno = ENOTSUP;
164 error (ctx, _("setting attributes for %s"), qpath);
165 ret = -1;
166 quote_free (ctx, qpath);
167 }
168 getout:
169 free (value);
170 my_free (names);
171 return ret;
172 #else
173 return 0;
174 #endif
175 }
176