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

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