[libglnx] xattrs: Handle xattrs changing size concurrently



commit afd178fb521a7373930dc8973b115c7ff62f6ee0
Author: Colin Walters <walters verbum org>
Date:   Tue Jan 10 22:04:51 2017 -0500

    xattrs: Handle xattrs changing size concurrently
    
    We should be robust in the face of this and return a snapshot of the current
    value we saw, not transiently fail. This is the semantics we expect with ostree
    upgrades for `/etc` for example.

 glnx-xattrs.c |   29 ++++++++++++++++++-----------
 1 files changed, 18 insertions(+), 11 deletions(-)
---
diff --git a/glnx-xattrs.c b/glnx-xattrs.c
index d50b3c2..e535b18 100644
--- a/glnx-xattrs.c
+++ b/glnx-xattrs.c
@@ -83,19 +83,22 @@ read_xattr_name_array (const char *path,
 
   funcstr = fd != -1 ? "fgetxattr" : "lgetxattr";
 
-  p = xattrs;
-  while (p < xattrs+len)
+  for (p = xattrs; p < xattrs+len; p = p + strlen (p) + 1)
     {
       ssize_t bytes_read;
-      char *buf;
-      GBytes *bytes = NULL;
+      g_autofree char *buf = NULL;
+      g_autoptr(GBytes) bytes = NULL;
 
+    again:
       if (fd != -1)
         bytes_read = fgetxattr (fd, p, NULL, 0);
       else
         bytes_read = lgetxattr (path, p, NULL, 0);
       if (bytes_read < 0)
         {
+          if (errno == ENODATA)
+            continue;
+
           glnx_set_prefix_error_from_errno (error, "%s", funcstr);
           goto out;
         }
@@ -103,26 +106,30 @@ read_xattr_name_array (const char *path,
         continue;
 
       buf = g_malloc (bytes_read);
-      bytes = g_bytes_new_take (buf, bytes_read);
       if (fd != -1)
         r = fgetxattr (fd, p, buf, bytes_read);
       else
         r = lgetxattr (path, p, buf, bytes_read);
       if (r < 0)
         {
-          g_bytes_unref (bytes);
+          if (errno == ERANGE)
+            {
+              g_free (g_steal_pointer (&buf));
+              goto again;
+            }
+          else if (errno == ENODATA)
+            continue;
+
           glnx_set_prefix_error_from_errno (error, "%s", funcstr);
           goto out;
         }
-      
+
+      bytes = g_bytes_new_take (g_steal_pointer (&buf), bytes_read);
       g_variant_builder_add (builder, "(@ay@ay)",
                              g_variant_new_bytestring (p),
                              variant_new_ay_bytes (bytes));
-
-      p = p + strlen (p) + 1;
-      g_bytes_unref (bytes);
     }
-  
+
   ret = TRUE;
  out:
   return ret;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]