X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=daemon%2Fxattr.c;h=a5169cfbafbf659896e5600150ea1e8ccd22bdbb;hp=17d9382cf2d30257d005bb46eb1ab483d6a7c1af;hb=428a45c3e15f03e9861e1b551e1ae8da821dba5f;hpb=84fc760439e82e6b3616abd0d1f9bd7d7eb01ec0 diff --git a/daemon/xattr.c b/daemon/xattr.c index 17d9382..a5169cf 100644 --- a/daemon/xattr.c +++ b/daemon/xattr.c @@ -21,19 +21,26 @@ #include #include -#include "../src/guestfs_protocol.h" +#include "guestfs_protocol.h" #include "daemon.h" #include "actions.h" +#include "optgroups.h" #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H) -#ifdef HAVE_ATTR_XATTR_H -#include -#else -#ifdef HAVE_SYS_XATTR_H -#include -#endif -#endif +# ifdef HAVE_ATTR_XATTR_H +# include +# else +# ifdef HAVE_SYS_XATTR_H +# include +# endif +# endif + +int +optgroup_linuxxattrs_available (void) +{ + return 1; +} 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)); 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)); @@ -45,7 +52,7 @@ do_getxattrs (const char *path) #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR) return getxattrs (path, listxattr, getxattr); #else - reply_with_error ("getxattrs: no support for listxattr and getxattr"); + reply_with_error ("no support for listxattr and getxattr"); return NULL; #endif } @@ -56,7 +63,7 @@ do_lgetxattrs (const char *path) #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR) return getxattrs (path, llistxattr, lgetxattr); #else - reply_with_error ("lgetxattrs: no support for llistxattr and lgetxattr"); + reply_with_error ("no support for llistxattr and lgetxattr"); return NULL; #endif } @@ -67,7 +74,7 @@ do_setxattr (const char *xattr, const char *val, int vallen, const char *path) #if defined(HAVE_SETXATTR) return _setxattr (xattr, val, vallen, path, setxattr); #else - reply_with_error ("setxattr: no support for setxattr"); + reply_with_error ("no support for setxattr"); return -1; #endif } @@ -78,7 +85,7 @@ do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path) #if defined(HAVE_LSETXATTR) return _setxattr (xattr, val, vallen, path, lsetxattr); #else - reply_with_error ("lsetxattr: no support for lsetxattr"); + reply_with_error ("no support for lsetxattr"); return -1; #endif } @@ -89,7 +96,7 @@ do_removexattr (const char *xattr, const char *path) #if defined(HAVE_REMOVEXATTR) return _removexattr (xattr, path, removexattr); #else - reply_with_error ("removexattr: no support for removexattr"); + reply_with_error ("no support for removexattr"); return -1; #endif } @@ -100,7 +107,7 @@ do_lremovexattr (const char *xattr, const char *path) #if defined(HAVE_LREMOVEXATTR) return _removexattr (xattr, path, lremovexattr); #else - reply_with_error ("lremovexattr: no support for lremovexattr"); + reply_with_error ("no support for lremovexattr"); return -1; #endif } @@ -120,7 +127,7 @@ getxattrs (const char *path, len = listxattr (path, NULL, 0); CHROOT_OUT; if (len == -1) { - reply_with_perror ("listxattr"); + reply_with_perror ("listxattr: %s", path); goto error; } @@ -134,7 +141,7 @@ getxattrs (const char *path, len = listxattr (path, buf, len); CHROOT_OUT; if (len == -1) { - reply_with_perror ("listxattr"); + reply_with_perror ("listxattr: %s", path); goto error; } @@ -195,11 +202,13 @@ getxattrs (const char *path, error: free (buf); if (r) { - if (r->guestfs_int_xattr_list_val) - for (i = 0; i < r->guestfs_int_xattr_list_len; ++i) { - free (r->guestfs_int_xattr_list_val[i].attrname); - free (r->guestfs_int_xattr_list_val[i].attrval.attrval_val); + if (r->guestfs_int_xattr_list_val) { + unsigned int k; + for (k = 0; k < r->guestfs_int_xattr_list_len; ++k) { + free (r->guestfs_int_xattr_list_val[k].attrname); + free (r->guestfs_int_xattr_list_val[k].attrval.attrval_val); } + } free (r->guestfs_int_xattr_list_val); } free (r); @@ -241,48 +250,251 @@ _removexattr (const char *xattr, const char *path, return 0; } +guestfs_int_xattr_list * +do_lxattrlist (const char *path, char *const *names) +{ +#if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR) + /* XXX This would be easier if the kernel had lgetxattrat. In the + * meantime we use this buffer to store the whole path name. + */ + char pathname[PATH_MAX]; + size_t path_len = strlen (path); + guestfs_int_xattr_list *ret = NULL; + int i, j; + size_t k, m, nr_attrs; + ssize_t len, vlen; + char *buf = NULL; + + if (path_len >= PATH_MAX) { + reply_with_perror ("path longer than PATH_MAX"); + goto error; + } + + strcpy (pathname, path); + + ret = malloc (sizeof (*ret)); + if (ret == NULL) { + reply_with_perror ("malloc"); + goto error; + } + + ret->guestfs_int_xattr_list_len = 0; + ret->guestfs_int_xattr_list_val = NULL; + + for (k = 0; names[k] != NULL; ++k) { + /* Be careful in here about which errors cause the whole call + * to abort, and which errors allow us to continue processing + * the call, recording a special "error attribute" in the + * outgoing struct list. + */ + if (path_len + strlen (names[k]) + 2 > PATH_MAX) { + reply_with_perror ("path and name longer than PATH_MAX"); + goto error; + } + pathname[path_len] = '/'; + strcpy (&pathname[path_len+1], names[k]); + + /* Reserve space for the special attribute. */ + void *newptr = + realloc (ret->guestfs_int_xattr_list_val, + (ret->guestfs_int_xattr_list_len+1)*sizeof (guestfs_int_xattr)); + if (newptr == NULL) { + reply_with_perror ("realloc"); + goto error; + } + ret->guestfs_int_xattr_list_val = newptr; + ret->guestfs_int_xattr_list_len++; + + guestfs_int_xattr *entry = + &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-1]; + entry->attrname = NULL; + entry->attrval.attrval_len = 0; + entry->attrval.attrval_val = NULL; + + entry->attrname = strdup (""); + if (entry->attrname == NULL) { + reply_with_perror ("strdup"); + goto error; + } + + CHROOT_IN; + len = llistxattr (pathname, NULL, 0); + CHROOT_OUT; + if (len == -1) + continue; /* not fatal */ + + buf = malloc (len); + if (buf == NULL) { + reply_with_perror ("malloc"); + goto error; + } + + CHROOT_IN; + len = llistxattr (pathname, buf, len); + CHROOT_OUT; + if (len == -1) + continue; /* not fatal */ + + /* What we get from the kernel is a string "foo\0bar\0baz" of length + * len. First count the strings. + */ + nr_attrs = 0; + for (i = 0; i < len; i += strlen (&buf[i]) + 1) + nr_attrs++; + + newptr = + realloc (ret->guestfs_int_xattr_list_val, + (ret->guestfs_int_xattr_list_len+nr_attrs) * + sizeof (guestfs_int_xattr)); + if (newptr == NULL) { + reply_with_perror ("realloc"); + goto error; + } + ret->guestfs_int_xattr_list_val = newptr; + ret->guestfs_int_xattr_list_len += nr_attrs; + + /* entry[0] is the special attribute, + * entry[1..nr_attrs] are the attributes. + */ + entry = &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-nr_attrs-1]; + for (m = 1; m <= nr_attrs; ++m) { + entry[m].attrname = NULL; + entry[m].attrval.attrval_len = 0; + entry[m].attrval.attrval_val = NULL; + } + + for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) { + CHROOT_IN; + vlen = lgetxattr (pathname, &buf[i], NULL, 0); + CHROOT_OUT; + if (vlen == -1) { + reply_with_perror ("getxattr"); + goto error; + } + + entry[j+1].attrname = strdup (&buf[i]); + entry[j+1].attrval.attrval_val = malloc (vlen); + entry[j+1].attrval.attrval_len = vlen; + + if (entry[j+1].attrname == NULL || + entry[j+1].attrval.attrval_val == NULL) { + reply_with_perror ("malloc"); + goto error; + } + + CHROOT_IN; + vlen = lgetxattr (pathname, &buf[i], + entry[j+1].attrval.attrval_val, vlen); + CHROOT_OUT; + if (vlen == -1) { + reply_with_perror ("getxattr"); + goto error; + } + } + + free (buf); buf = NULL; + + char num[16]; + snprintf (num, sizeof num, "%zu", nr_attrs); + entry[0].attrval.attrval_len = strlen (num) + 1; + entry[0].attrval.attrval_val = strdup (num); + + if (entry[0].attrval.attrval_val == NULL) { + reply_with_perror ("strdup"); + goto error; + } + } + + /* If verbose, debug what we're about to send back. */ + if (verbose) { + fprintf (stderr, "lxattrlist: returning: [\n"); + for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) { + const guestfs_int_xattr *entry = &ret->guestfs_int_xattr_list_val[k]; + if (STRNEQ (entry[0].attrname, "")) { + fprintf (stderr, "ERROR: expecting empty attrname at k = %zu\n", k); + break; + } + fprintf (stderr, " %zu: special attrval = %s\n", + k, entry[0].attrval.attrval_val); + for (i = 1; k+i < ret->guestfs_int_xattr_list_len; ++i) { + if (STREQ (entry[i].attrname, "")) + break; + fprintf (stderr, " name %s, value length %d\n", + entry[i].attrname, entry[i].attrval.attrval_len); + } + k += i-1; + } + fprintf (stderr, "]\n"); + } + + return ret; + + error: + free (buf); + if (ret) { + if (ret->guestfs_int_xattr_list_val) { + for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) { + free (ret->guestfs_int_xattr_list_val[k].attrname); + free (ret->guestfs_int_xattr_list_val[k].attrval.attrval_val); + } + free (ret->guestfs_int_xattr_list_val); + } + free (ret); + } + return NULL; +#else + reply_with_error ("no support for llistxattr and lgetxattr"); + return NULL; +#endif +} + #else /* no xattr.h */ +int +optgroup_linuxxattrs_available (void) +{ + return 0; +} guestfs_int_xattr_list * do_getxattrs (const char *path) { - reply_with_error ("getxattrs: no support for xattrs"); - return NULL; + NOT_AVAILABLE (NULL); } guestfs_int_xattr_list * do_lgetxattrs (const char *path) { - reply_with_error ("lgetxattrs: no support for xattrs"); - return NULL; + NOT_AVAILABLE (NULL); } int do_setxattr (const char *xattr, const char *val, int vallen, const char *path) { - reply_with_error ("setxattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); } int do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path) { - reply_with_error ("lsetxattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); } int do_removexattr (const char *xattr, const char *path) { - reply_with_error ("removexattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); } int do_lremovexattr (const char *xattr, const char *path) { - reply_with_error ("lremovexattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); +} + +guestfs_int_xattr_list * +do_lxattrlist (const char *path, char *const *names) +{ + NOT_AVAILABLE (NULL); } #endif /* no xattr.h */