Blame SOURCES/0065-daemon-xattr-Refactor-code-which-splits-attr-names-f.patch

5ce0c7
From a13f9b06370a6fef6f671f5aa7c23df0f0fd542e Mon Sep 17 00:00:00 2001
d60042
From: "Richard W.M. Jones" <rjones@redhat.com>
d60042
Date: Thu, 12 Mar 2020 13:57:06 +0000
d60042
Subject: [PATCH] daemon: xattr: Refactor code which splits attr names from the
d60042
 kernel.
d60042
d60042
The kernel returns xattr names in a slightly peculiar format.  We
d60042
parsed this format several times in the code.  Refactor this parsing
d60042
so we only do it in one place.
d60042
d60042
(cherry picked from commit 5c175fe73264bbf1d3ef79bb066dfb6aff902ad1)
d60042
---
d60042
 daemon/xattr.c | 127 ++++++++++++++++++++++++++++++-------------------
d60042
 1 file changed, 79 insertions(+), 48 deletions(-)
d60042
d60042
diff --git a/daemon/xattr.c b/daemon/xattr.c
d60042
index bc5c2df97..3e1144963 100644
d60042
--- a/daemon/xattr.c
d60042
+++ b/daemon/xattr.c
d60042
@@ -89,6 +89,36 @@ do_lremovexattr (const char *xattr, const char *path)
d60042
   return _removexattr (xattr, path, lremovexattr);
d60042
 }
d60042
 
d60042
+/**
d60042
+ * L<listxattr(2)> returns the string C<"foo\0bar\0baz"> of length
d60042
+ * C<len>.  (The last string in the list is \0-terminated but the \0
d60042
+ * is not included in C<len>).
d60042
+ *
d60042
+ * This function splits it into a regular list of strings.
d60042
+ *
d60042
+ * B<Note> that the returned list contains pointers to the original
d60042
+ * strings in C<buf> so be careful that you do not double-free them.
d60042
+ */
d60042
+static char **
d60042
+split_attr_names (char *buf, size_t len)
d60042
+{
d60042
+  size_t i;
d60042
+  DECLARE_STRINGSBUF (ret);
d60042
+
d60042
+  for (i = 0; i < len; i += strlen (&buf[i]) + 1) {
d60042
+    if (add_string_nodup (&ret, &buf[i]) == -1) {
d60042
+      free (ret.argv);
d60042
+      return NULL;
d60042
+    }
d60042
+  }
d60042
+  if (end_stringsbuf (&ret) == -1) {
d60042
+    free (ret.argv);
d60042
+    return NULL;
d60042
+  }
d60042
+
d60042
+  return take_stringsbuf (&ret;;
d60042
+}
d60042
+
d60042
 static int
d60042
 compare_xattrs (const void *vxa1, const void *vxa2)
d60042
 {
d60042
@@ -106,7 +136,8 @@ getxattrs (const char *path,
d60042
 {
d60042
   ssize_t len, vlen;
d60042
   CLEANUP_FREE char *buf = NULL;
d60042
-  size_t i, j;
d60042
+  CLEANUP_FREE /* not string list */ char **names = NULL;
d60042
+  size_t i;
d60042
   guestfs_int_xattr_list *r = NULL;
d60042
 
d60042
   buf = _listxattrs (path, listxattr, &len;;
d60042
@@ -114,18 +145,17 @@ getxattrs (const char *path,
d60042
     /* _listxattrs issues reply_with_perror already. */
d60042
     goto error;
d60042
 
d60042
+  names = split_attr_names (buf, len);
d60042
+  if (names == NULL)
d60042
+    goto error;
d60042
+
d60042
   r = calloc (1, sizeof (*r));
d60042
   if (r == NULL) {
d60042
     reply_with_perror ("calloc");
d60042
     goto error;
d60042
   }
d60042
 
d60042
-  /* What we get from the kernel is a string "foo\0bar\0baz" of length
d60042
-   * len.  First count the strings.
d60042
-   */
d60042
-  r->guestfs_int_xattr_list_len = 0;
d60042
-  for (i = 0; i < (size_t) len; i += strlen (&buf[i]) + 1)
d60042
-    r->guestfs_int_xattr_list_len++;
d60042
+  r->guestfs_int_xattr_list_len = guestfs_int_count_strings (names);
d60042
 
d60042
   r->guestfs_int_xattr_list_val =
d60042
     calloc (r->guestfs_int_xattr_list_len, sizeof (guestfs_int_xattr));
d60042
@@ -134,34 +164,34 @@ getxattrs (const char *path,
d60042
     goto error;
d60042
   }
d60042
 
d60042
-  for (i = 0, j = 0; i < (size_t) len; i += strlen (&buf[i]) + 1, ++j) {
d60042
+  for (i = 0; names[i] != NULL; ++i) {
d60042
     CHROOT_IN;
d60042
-    vlen = getxattr (path, &buf[i], NULL, 0);
d60042
+    vlen = getxattr (path, names[i], NULL, 0);
d60042
     CHROOT_OUT;
d60042
     if (vlen == -1) {
d60042
-      reply_with_perror ("getxattr");
d60042
+      reply_with_perror ("getxattr: %s", names[i]);
d60042
       goto error;
d60042
     }
d60042
 
d60042
     if (vlen > XATTR_SIZE_MAX) {
d60042
       /* The next call to getxattr will fail anyway, so ... */
d60042
-      reply_with_error ("extended attribute is too large");
d60042
+      reply_with_error ("%s: extended attribute is too large", names[i]);
d60042
       goto error;
d60042
     }
d60042
 
d60042
-    r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]);
d60042
-    r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen);
d60042
-    r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen;
d60042
+    r->guestfs_int_xattr_list_val[i].attrname = strdup (names[i]);
d60042
+    r->guestfs_int_xattr_list_val[i].attrval.attrval_val = malloc (vlen);
d60042
+    r->guestfs_int_xattr_list_val[i].attrval.attrval_len = vlen;
d60042
 
d60042
-    if (r->guestfs_int_xattr_list_val[j].attrname == NULL ||
d60042
-        r->guestfs_int_xattr_list_val[j].attrval.attrval_val == NULL) {
d60042
+    if (r->guestfs_int_xattr_list_val[i].attrname == NULL ||
d60042
+        r->guestfs_int_xattr_list_val[i].attrval.attrval_val == NULL) {
d60042
       reply_with_perror ("malloc");
d60042
       goto error;
d60042
     }
d60042
 
d60042
     CHROOT_IN;
d60042
-    vlen = getxattr (path, &buf[i],
d60042
-                     r->guestfs_int_xattr_list_val[j].attrval.attrval_val,
d60042
+    vlen = getxattr (path, names[i],
d60042
+                     r->guestfs_int_xattr_list_val[i].attrval.attrval_val,
d60042
                      vlen);
d60042
     CHROOT_OUT;
d60042
     if (vlen == -1) {
d60042
@@ -276,7 +306,7 @@ guestfs_int_xattr_list *
d60042
 do_internal_lxattrlist (const char *path, char *const *names)
d60042
 {
d60042
   guestfs_int_xattr_list *ret = NULL;
d60042
-  size_t i, j;
d60042
+  size_t i;
d60042
   size_t k, m, nr_attrs;
d60042
   ssize_t len, vlen;
d60042
 
d60042
@@ -293,6 +323,7 @@ do_internal_lxattrlist (const char *path, char *const *names)
d60042
     void *newptr;
d60042
     CLEANUP_FREE char *pathname = NULL;
d60042
     CLEANUP_FREE char *buf = NULL;
d60042
+    CLEANUP_FREE /* not string list */ char **attrnames = NULL;
d60042
 
d60042
     /* Be careful in this loop about which errors cause the whole call
d60042
      * to abort, and which errors allow us to continue processing
d60042
@@ -350,12 +381,10 @@ do_internal_lxattrlist (const char *path, char *const *names)
d60042
     if (len == -1)
d60042
       continue; /* not fatal */
d60042
 
d60042
-    /* What we get from the kernel is a string "foo\0bar\0baz" of length
d60042
-     * len.  First count the strings.
d60042
-     */
d60042
-    nr_attrs = 0;
d60042
-    for (i = 0; i < (size_t) len; i += strlen (&buf[i]) + 1)
d60042
-      nr_attrs++;
d60042
+    attrnames = split_attr_names (buf, len);
d60042
+    if (attrnames == NULL)
d60042
+      goto error;
d60042
+    nr_attrs = guestfs_int_count_strings (attrnames);
d60042
 
d60042
     newptr =
d60042
       realloc (ret->guestfs_int_xattr_list_val,
d60042
@@ -378,36 +407,36 @@ do_internal_lxattrlist (const char *path, char *const *names)
d60042
       entry[m].attrval.attrval_val = NULL;
d60042
     }
d60042
 
d60042
-    for (i = 0, j = 0; i < (size_t) len; i += strlen (&buf[i]) + 1, ++j) {
d60042
+    for (i = 0; attrnames[i] != NULL; ++i) {
d60042
       CHROOT_IN;
d60042
-      vlen = lgetxattr (pathname, &buf[i], NULL, 0);
d60042
+      vlen = lgetxattr (pathname, attrnames[i], NULL, 0);
d60042
       CHROOT_OUT;
d60042
       if (vlen == -1) {
d60042
-        reply_with_perror ("getxattr");
d60042
+        reply_with_perror ("getxattr: %s", attrnames[i]);
d60042
         goto error;
d60042
       }
d60042
 
d60042
       if (vlen > XATTR_SIZE_MAX) {
d60042
-        reply_with_error ("extended attribute is too large");
d60042
+        reply_with_error ("%s: extended attribute is too large", attrnames[i]);
d60042
         goto error;
d60042
       }
d60042
 
d60042
-      entry[j+1].attrname = strdup (&buf[i]);
d60042
-      entry[j+1].attrval.attrval_val = malloc (vlen);
d60042
-      entry[j+1].attrval.attrval_len = vlen;
d60042
+      entry[i+1].attrname = strdup (attrnames[i]);
d60042
+      entry[i+1].attrval.attrval_val = malloc (vlen);
d60042
+      entry[i+1].attrval.attrval_len = vlen;
d60042
 
d60042
-      if (entry[j+1].attrname == NULL ||
d60042
-          entry[j+1].attrval.attrval_val == NULL) {
d60042
+      if (entry[i+1].attrname == NULL ||
d60042
+          entry[i+1].attrval.attrval_val == NULL) {
d60042
         reply_with_perror ("malloc");
d60042
         goto error;
d60042
       }
d60042
 
d60042
       CHROOT_IN;
d60042
-      vlen = lgetxattr (pathname, &buf[i],
d60042
-                        entry[j+1].attrval.attrval_val, vlen);
d60042
+      vlen = lgetxattr (pathname, attrnames[i],
d60042
+                        entry[i+1].attrval.attrval_val, vlen);
d60042
       CHROOT_OUT;
d60042
       if (vlen == -1) {
d60042
-        reply_with_perror ("getxattr");
d60042
+        reply_with_perror ("getxattr: %s", attrnames[i]);
d60042
         goto error;
d60042
       }
d60042
     }
d60042
@@ -510,6 +539,7 @@ copy_xattrs (const char *src, const char *dest)
d60042
 {
d60042
   ssize_t len, vlen, ret, attrval_len = 0;
d60042
   CLEANUP_FREE char *buf = NULL, *attrval = NULL;
d60042
+  CLEANUP_FREE /* not string list */ char **names = NULL;
d60042
   size_t i;
d60042
 
d60042
   buf = _listxattrs (src, listxattr, &len;;
d60042
@@ -517,21 +547,22 @@ copy_xattrs (const char *src, const char *dest)
d60042
     /* _listxattrs issues reply_with_perror already. */
d60042
     goto error;
d60042
 
d60042
-  /* What we get from the kernel is a string "foo\0bar\0baz" of length
d60042
-   * len.
d60042
-   */
d60042
-  for (i = 0; i < (size_t) len; i += strlen (&buf[i]) + 1) {
d60042
+  names = split_attr_names (buf, len);
d60042
+  if (names == NULL)
d60042
+    goto error;
d60042
+
d60042
+  for (i = 0; names[i] != NULL; ++i) {
d60042
     CHROOT_IN;
d60042
-    vlen = getxattr (src, &buf[i], NULL, 0);
d60042
+    vlen = getxattr (src, names[i], NULL, 0);
d60042
     CHROOT_OUT;
d60042
     if (vlen == -1) {
d60042
-      reply_with_perror ("getxattr: %s, %s", src, &buf[i]);
d60042
+      reply_with_perror ("getxattr: %s, %s", src, names[i]);
d60042
       goto error;
d60042
     }
d60042
 
d60042
     if (vlen > XATTR_SIZE_MAX) {
d60042
       /* The next call to getxattr will fail anyway, so ... */
d60042
-      reply_with_error ("extended attribute is too large");
d60042
+      reply_with_error ("%s: extended attribute is too large", names[i]);
d60042
       goto error;
d60042
     }
d60042
 
d60042
@@ -546,18 +577,18 @@ copy_xattrs (const char *src, const char *dest)
d60042
     }
d60042
 
d60042
     CHROOT_IN;
d60042
-    vlen = getxattr (src, &buf[i], attrval, vlen);
d60042
+    vlen = getxattr (src, names[i], attrval, vlen);
d60042
     CHROOT_OUT;
d60042
     if (vlen == -1) {
d60042
-      reply_with_perror ("getxattr: %s, %s", src, &buf[i]);
d60042
+      reply_with_perror ("getxattr: %s, %s", src, names[i]);
d60042
       goto error;
d60042
     }
d60042
 
d60042
     CHROOT_IN;
d60042
-    ret = setxattr (dest, &buf[i], attrval, vlen, 0);
d60042
+    ret = setxattr (dest, names[i], attrval, vlen, 0);
d60042
     CHROOT_OUT;
d60042
     if (ret == -1) {
d60042
-      reply_with_perror ("setxattr: %s, %s", dest, &buf[i]);
d60042
+      reply_with_perror ("setxattr: %s, %s", dest, names[i]);
d60042
       goto error;
d60042
     }
d60042
   }
d60042
-- 
5ce0c7
2.18.4
d60042