Imported Upstream version 2.4.46
[platform/upstream/attr.git] / libattr / attr_copy_file.c
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 <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #if defined(HAVE_ALLOCA_H)
30 # include <alloca.h>
31 #endif
32
33 #if defined(HAVE_ATTR_XATTR_H)
34 # include <attr/xattr.h>
35 #endif
36
37 #if defined(HAVE_ATTR_LIBATTR_H)
38 # include "attr/libattr.h"
39 #endif
40
41 #define ERROR_CONTEXT_MACROS
42 #include "error_context.h"
43
44 #if !defined(ENOTSUP)
45 # define ENOTSUP (-1)
46 #endif
47
48 #if defined(HAVE_ALLOCA)
49 # define my_alloc(size) alloca (size)
50 # define my_free(ptr) do { } while(0)
51 #else
52 # define my_alloc(size) malloc (size)
53 # define my_free(ptr) free (ptr)
54 #endif
55
56 /* Copy extended attributes from src_path to dst_path. If the file
57    has an extended Access ACL (system.posix_acl_access) and that is
58    copied successfully, the file mode permission bits are copied as
59    a side effect. This may not always the case, so the file mode
60    and/or ownership must be copied separately. */
61 int
62 attr_copy_file(const char *src_path, const char *dst_path,
63                int (*check) (const char *, struct error_context *),
64                struct error_context *ctx)
65 {
66 #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR) && defined(HAVE_SETXATTR)
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 = llistxattr (src_path, 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 = llistxattr (src_path, 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 = lgetxattr (src_path, 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 = lgetxattr (src_path, 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 (lsetxattr (dst_path, 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