1 /* libguestfs - the guestfsd daemon
2 * Copyright (C) 2009 Red Hat Inc.
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.
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.
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.
24 #include "../src/guestfs_protocol.h"
28 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
30 #ifdef HAVE_ATTR_XATTR_H
31 #include <attr/xattr.h>
33 #ifdef HAVE_SYS_XATTR_H
34 #include <sys/xattr.h>
38 static guestfs_int_xattr_list *getxattrs (const 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));
39 static int _setxattr (const char *xattr, const char *val, int vallen, const char *path, int (*setxattr) (const char *path, const char *name, const void *value, size_t size, int flags));
40 static int _removexattr (const char *xattr, const char *path, int (*removexattr) (const char *path, const char *name));
42 guestfs_int_xattr_list *
43 do_getxattrs (const char *path)
45 #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR)
46 return getxattrs (path, listxattr, getxattr);
48 reply_with_error ("getxattrs: no support for listxattr and getxattr");
53 guestfs_int_xattr_list *
54 do_lgetxattrs (const char *path)
56 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
57 return getxattrs (path, llistxattr, lgetxattr);
59 reply_with_error ("lgetxattrs: no support for llistxattr and lgetxattr");
65 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
67 #if defined(HAVE_SETXATTR)
68 return _setxattr (xattr, val, vallen, path, setxattr);
70 reply_with_error ("setxattr: no support for setxattr");
76 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
78 #if defined(HAVE_LSETXATTR)
79 return _setxattr (xattr, val, vallen, path, lsetxattr);
81 reply_with_error ("lsetxattr: no support for lsetxattr");
87 do_removexattr (const char *xattr, const char *path)
89 #if defined(HAVE_REMOVEXATTR)
90 return _removexattr (xattr, path, removexattr);
92 reply_with_error ("removexattr: no support for removexattr");
98 do_lremovexattr (const char *xattr, const char *path)
100 #if defined(HAVE_LREMOVEXATTR)
101 return _removexattr (xattr, path, lremovexattr);
103 reply_with_error ("lremovexattr: no support for lremovexattr");
108 static guestfs_int_xattr_list *
109 getxattrs (const char *path,
110 ssize_t (*listxattr) (const char *path, char *list, size_t size),
111 ssize_t (*getxattr) (const char *path, const char *name,
112 void *value, size_t size))
117 guestfs_int_xattr_list *r = NULL;
120 len = listxattr (path, NULL, 0);
123 reply_with_perror ("listxattr");
129 reply_with_perror ("malloc");
134 len = listxattr (path, buf, len);
137 reply_with_perror ("listxattr");
141 r = calloc (1, sizeof (*r));
143 reply_with_perror ("malloc");
147 /* What we get from the kernel is a string "foo\0bar\0baz" of length
148 * len. First count the strings.
150 r->guestfs_int_xattr_list_len = 0;
151 for (i = 0; i < len; i += strlen (&buf[i]) + 1)
152 r->guestfs_int_xattr_list_len++;
154 r->guestfs_int_xattr_list_val =
155 calloc (r->guestfs_int_xattr_list_len, sizeof (guestfs_int_xattr));
156 if (r->guestfs_int_xattr_list_val == NULL) {
157 reply_with_perror ("calloc");
161 for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
163 vlen = getxattr (path, &buf[i], NULL, 0);
166 reply_with_perror ("getxattr");
170 r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]);
171 r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen);
172 r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen;
174 if (r->guestfs_int_xattr_list_val[j].attrname == NULL ||
175 r->guestfs_int_xattr_list_val[j].attrval.attrval_val == NULL) {
176 reply_with_perror ("malloc");
181 vlen = getxattr (path, &buf[i],
182 r->guestfs_int_xattr_list_val[j].attrval.attrval_val,
186 reply_with_perror ("getxattr");
198 if (r->guestfs_int_xattr_list_val) {
200 for (k = 0; k < r->guestfs_int_xattr_list_len; ++k) {
201 free (r->guestfs_int_xattr_list_val[k].attrname);
202 free (r->guestfs_int_xattr_list_val[k].attrval.attrval_val);
205 free (r->guestfs_int_xattr_list_val);
212 _setxattr (const char *xattr, const char *val, int vallen, const char *path,
213 int (*setxattr) (const char *path, const char *name,
214 const void *value, size_t size, int flags))
219 r = setxattr (path, xattr, val, vallen, 0);
222 reply_with_perror ("setxattr");
230 _removexattr (const char *xattr, const char *path,
231 int (*removexattr) (const char *path, const char *name))
236 r = removexattr (path, xattr);
239 reply_with_perror ("removexattr");
246 guestfs_int_xattr_list *
247 do_lxattrlist (const char *path, char *const *names)
249 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
250 /* XXX This would be easier if the kernel had lgetxattrat. In the
251 * meantime we use this buffer to store the whole path name.
253 char pathname[PATH_MAX];
254 size_t path_len = strlen (path);
255 guestfs_int_xattr_list *ret = NULL;
257 size_t k, m, nr_attrs;
261 if (path_len >= PATH_MAX) {
262 reply_with_perror ("lxattrlist: path longer than PATH_MAX");
266 strcpy (pathname, path);
268 ret = malloc (sizeof (*ret));
270 reply_with_perror ("malloc");
274 ret->guestfs_int_xattr_list_len = 0;
275 ret->guestfs_int_xattr_list_val = NULL;
277 for (k = 0; names[k] != NULL; ++k) {
278 /* Be careful in here about which errors cause the whole call
279 * to abort, and which errors allow us to continue processing
280 * the call, recording a special "error attribute" in the
281 * outgoing struct list.
283 if (path_len + strlen (names[k]) + 2 > PATH_MAX) {
284 reply_with_perror ("lxattrlist: path and name longer than PATH_MAX");
287 pathname[path_len] = '/';
288 strcpy (&pathname[path_len+1], names[k]);
290 /* Reserve space for the special attribute. */
292 realloc (ret->guestfs_int_xattr_list_val,
293 (ret->guestfs_int_xattr_list_len+1)*sizeof (guestfs_int_xattr));
294 if (newptr == NULL) {
295 reply_with_perror ("realloc");
298 ret->guestfs_int_xattr_list_val = newptr;
299 ret->guestfs_int_xattr_list_len++;
301 guestfs_int_xattr *entry =
302 &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-1];
303 entry->attrname = NULL;
304 entry->attrval.attrval_len = 0;
305 entry->attrval.attrval_val = NULL;
307 entry->attrname = strdup ("");
308 if (entry->attrname == NULL) {
309 reply_with_perror ("strdup");
314 len = llistxattr (pathname, NULL, 0);
317 continue; /* not fatal */
321 reply_with_perror ("malloc");
326 len = llistxattr (pathname, buf, len);
329 continue; /* not fatal */
331 /* What we get from the kernel is a string "foo\0bar\0baz" of length
332 * len. First count the strings.
335 for (i = 0; i < len; i += strlen (&buf[i]) + 1)
339 realloc (ret->guestfs_int_xattr_list_val,
340 (ret->guestfs_int_xattr_list_len+nr_attrs) *
341 sizeof (guestfs_int_xattr));
342 if (newptr == NULL) {
343 reply_with_perror ("realloc");
346 ret->guestfs_int_xattr_list_val = newptr;
347 ret->guestfs_int_xattr_list_len += nr_attrs;
349 /* entry[0] is the special attribute,
350 * entry[1..nr_attrs] are the attributes.
352 entry = &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-nr_attrs-1];
353 for (m = 1; m <= nr_attrs; ++m) {
354 entry[m].attrname = NULL;
355 entry[m].attrval.attrval_len = 0;
356 entry[m].attrval.attrval_val = NULL;
359 for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
361 vlen = lgetxattr (pathname, &buf[i], NULL, 0);
364 reply_with_perror ("getxattr");
368 entry[j+1].attrname = strdup (&buf[i]);
369 entry[j+1].attrval.attrval_val = malloc (vlen);
370 entry[j+1].attrval.attrval_len = vlen;
372 if (entry[j+1].attrname == NULL ||
373 entry[j+1].attrval.attrval_val == NULL) {
374 reply_with_perror ("malloc");
379 vlen = lgetxattr (pathname, &buf[i],
380 entry[j+1].attrval.attrval_val, vlen);
383 reply_with_perror ("getxattr");
388 free (buf); buf = NULL;
391 snprintf (num, sizeof num, "%zu", nr_attrs);
392 entry[0].attrval.attrval_len = strlen (num) + 1;
393 entry[0].attrval.attrval_val = strdup (num);
395 if (entry[0].attrval.attrval_val == NULL) {
396 reply_with_perror ("strdup");
401 /* If verbose, debug what we're about to send back. */
403 fprintf (stderr, "lxattrlist: returning: [\n");
404 for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
405 const guestfs_int_xattr *entry = &ret->guestfs_int_xattr_list_val[k];
406 if (strcmp (entry[0].attrname, "") != 0) {
407 fprintf (stderr, "ERROR: expecting empty attrname at k = %zu\n", k);
410 fprintf (stderr, " %zu: special attrval = %s\n",
411 k, entry[0].attrval.attrval_val);
412 for (i = 1; k+i < ret->guestfs_int_xattr_list_len; ++i) {
413 if (strcmp (entry[i].attrname, "") == 0)
415 fprintf (stderr, " name %s, value length %d\n",
416 entry[i].attrname, entry[i].attrval.attrval_len);
420 fprintf (stderr, "]\n");
428 if (ret->guestfs_int_xattr_list_val) {
429 for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
430 free (ret->guestfs_int_xattr_list_val[k].attrname);
431 free (ret->guestfs_int_xattr_list_val[k].attrval.attrval_val);
433 free (ret->guestfs_int_xattr_list_val);
439 reply_with_error ("lxattrlist: no support for llistxattr and lgetxattr");
444 #else /* no xattr.h */
446 guestfs_int_xattr_list *
447 do_getxattrs (const char *path)
449 reply_with_error ("getxattrs: no support for xattrs");
453 guestfs_int_xattr_list *
454 do_lgetxattrs (const char *path)
456 reply_with_error ("lgetxattrs: no support for xattrs");
461 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
463 reply_with_error ("setxattr: no support for xattrs");
468 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
470 reply_with_error ("lsetxattr: no support for xattrs");
475 do_removexattr (const char *xattr, const char *path)
477 reply_with_error ("removexattr: no support for xattrs");
482 do_lremovexattr (const char *xattr, const char *path)
484 reply_with_error ("lremovexattr: no support for xattrs");
488 guestfs_int_xattr_list *
489 do_lxattrlist (const char *path, char *const *names)
491 reply_with_error ("lxattrlist: no support for xattrs");
495 #endif /* no xattr.h */