76f44bbfdcc42e89c7aaed3033284d30be76015e
[libguestfs.git] / daemon / xattr.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <unistd.h>
23
24 #ifdef HAVE_ATTR_XATTR_H
25 #include <attr/xattr.h>
26
27 #include "../src/guestfs_protocol.h"
28 #include "daemon.h"
29 #include "actions.h"
30
31 static guestfs_int_xattr_list *getxattrs (char *path, ssize_t (*listxattr) (const char *path, char *list, size_t size), ssize_t (*getxattr) (const char *path, const char *name, void *value, size_t size));
32 static int _setxattr (char *xattr, char *val, int vallen, char *path, int (*setxattr) (const char *path, const char *name, const void *value, size_t size, int flags));
33 static int _removexattr (char *xattr, char *path, int (*removexattr) (const char *path, const char *name));
34
35 guestfs_int_xattr_list *
36 do_getxattrs (char *path)
37 {
38 #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR)
39   return getxattrs (path, listxattr, getxattr);
40 #else
41   reply_with_error ("getxattrs: no support for listxattr and getxattr");
42   return NULL;
43 #endif
44 }
45
46 guestfs_int_xattr_list *
47 do_lgetxattrs (char *path)
48 {
49 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
50   return getxattrs (path, llistxattr, lgetxattr);
51 #else
52   reply_with_error ("lgetxattrs: no support for llistxattr and lgetxattr");
53   return NULL;
54 #endif
55 }
56
57 int
58 do_setxattr (char *xattr, char *val, int vallen, char *path)
59 {
60 #if defined(HAVE_SETXATTR)
61   return _setxattr (xattr, val, vallen, path, setxattr);
62 #else
63   reply_with_error ("setxattr: no support for setxattr");
64   return -1;
65 #endif
66 }
67
68 int
69 do_lsetxattr (char *xattr, char *val, int vallen, char *path)
70 {
71 #if defined(HAVE_LSETXATTR)
72   return _setxattr (xattr, val, vallen, path, lsetxattr);
73 #else
74   reply_with_error ("lsetxattr: no support for lsetxattr");
75   return -1;
76 #endif
77 }
78
79 int
80 do_removexattr (char *xattr, char *path)
81 {
82 #if defined(HAVE_REMOVEXATTR)
83   return _removexattr (xattr, path, removexattr);
84 #else
85   reply_with_error ("removexattr: no support for removexattr");
86   return -1;
87 #endif
88 }
89
90 int
91 do_lremovexattr (char *xattr, char *path)
92 {
93 #if defined(HAVE_LREMOVEXATTR)
94   return _removexattr (xattr, path, lremovexattr);
95 #else
96   reply_with_error ("lremovexattr: no support for lremovexattr");
97   return -1;
98 #endif
99 }
100
101 static guestfs_int_xattr_list *
102 getxattrs (char *path,
103            ssize_t (*listxattr) (const char *path, char *list, size_t size),
104            ssize_t (*getxattr) (const char *path, const char *name,
105                                 void *value, size_t size))
106 {
107   ssize_t len, vlen;
108   char *buf = NULL;
109   int i, j;
110   guestfs_int_xattr_list *r = NULL;
111
112   NEED_ROOT (NULL);
113   ABS_PATH (path, NULL);
114
115   CHROOT_IN;
116   len = listxattr (path, NULL, 0);
117   CHROOT_OUT;
118   if (len == -1) {
119     reply_with_perror ("listxattr");
120     goto error;
121   }
122
123   buf = malloc (len);
124   if (buf == NULL) {
125     reply_with_perror ("malloc");
126     goto error;
127   }
128
129   CHROOT_IN;
130   len = listxattr (path, buf, len);
131   CHROOT_OUT;
132   if (len == -1) {
133     reply_with_perror ("listxattr");
134     goto error;
135   }
136
137   r = calloc (1, sizeof (*r));
138   if (r == NULL) {
139     reply_with_perror ("malloc");
140     goto error;
141   }
142
143   /* What we get from the kernel is a string "foo\0bar\0baz" of length
144    * len.  First count the strings.
145    */
146   r->guestfs_int_xattr_list_len = 0;
147   for (i = 0; i < len; i += strlen (&buf[i]) + 1)
148     r->guestfs_int_xattr_list_len++;
149
150   r->guestfs_int_xattr_list_val =
151     calloc (r->guestfs_int_xattr_list_len, sizeof (guestfs_int_xattr));
152   if (r->guestfs_int_xattr_list_val == NULL) {
153     reply_with_perror ("calloc");
154     goto error;
155   }
156
157   for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
158     CHROOT_IN;
159     vlen = getxattr (path, &buf[i], NULL, 0);
160     CHROOT_OUT;
161     if (vlen == -1) {
162       reply_with_perror ("getxattr");
163       goto error;
164     }
165
166     r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]);
167     r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen);
168     r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen;
169
170     if (r->guestfs_int_xattr_list_val[j].attrname == NULL ||
171         r->guestfs_int_xattr_list_val[j].attrval.attrval_val == NULL) {
172       reply_with_perror ("malloc");
173       goto error;
174     }
175
176     CHROOT_IN;
177     vlen = getxattr (path, &buf[i],
178                      r->guestfs_int_xattr_list_val[j].attrval.attrval_val,
179                      vlen);
180     CHROOT_OUT;
181     if (vlen == -1) {
182       reply_with_perror ("getxattr");
183       goto error;
184     }
185   }
186
187   free (buf);
188
189   return r;
190
191  error:
192   free (buf);
193   if (r) {
194     if (r->guestfs_int_xattr_list_val)
195       for (i = 0; i < r->guestfs_int_xattr_list_len; ++i) {
196         free (r->guestfs_int_xattr_list_val[i].attrname);
197         free (r->guestfs_int_xattr_list_val[i].attrval.attrval_val);
198       }
199     free (r->guestfs_int_xattr_list_val);
200   }
201   free (r);
202   return NULL;
203 }
204
205 static int
206 _setxattr (char *xattr, char *val, int vallen, char *path,
207            int (*setxattr) (const char *path, const char *name,
208                             const void *value, size_t size, int flags))
209 {
210   int r;
211
212   CHROOT_IN;
213   r = setxattr (path, xattr, val, vallen, 0);
214   CHROOT_OUT;
215   if (r == -1) {
216     reply_with_perror ("setxattr");
217     return -1;
218   }
219
220   return 0;
221 }
222
223 static int
224 _removexattr (char *xattr, char *path,
225               int (*removexattr) (const char *path, const char *name))
226 {
227   int r;
228
229   CHROOT_IN;
230   r = removexattr (path, xattr);
231   CHROOT_OUT;
232   if (r == -1) {
233     reply_with_perror ("removexattr");
234     return -1;
235   }
236
237   return 0;
238 }
239
240 #else /* !HAVE_ATTR_XATTR_H */
241
242 guestfs_int_xattr_list *
243 do_getxattrs (char *path)
244 {
245   reply_with_error ("getxattrs: no support for xattrs");
246   return NULL;
247 }
248
249 guestfs_int_xattr_list *
250 do_lgetxattrs (char *path)
251 {
252   reply_with_error ("lgetxattrs: no support for xattrs");
253   return NULL;
254 }
255
256 int
257 do_setxattr (char *xattr, char *val, int vallen, char *path)
258 {
259   reply_with_error ("setxattr: no support for xattrs");
260   return -1;
261 }
262
263 int
264 do_lsetxattr (char *xattr, char *val, int vallen, char *path)
265 {
266   reply_with_error ("lsetxattr: no support for xattrs");
267   return -1;
268 }
269
270 int
271 do_removexattr (char *xattr, char *path)
272 {
273   reply_with_error ("removexattr: no support for xattrs");
274   return -1;
275 }
276
277 int
278 do_lremovexattr (char *xattr, char *path)
279 {
280   reply_with_error ("lremovexattr: no support for xattrs");
281   return -1;
282 }
283
284 #endif /* !HAVE_ATTR_XATTR_H */