[libglnx] Import xattr reading code from libgsystem



commit f5399c8348b04f9cf5bd4d9d3903e5843c1feeb5
Author: Colin Walters <walters verbum org>
Date:   Sun Feb 15 16:09:58 2015 -0500

    Import xattr reading code from libgsystem

 Makefile-libglnx.am |    6 +-
 glnx-xattrs.c       |  283 +++++++++++++++++++++++++++++++++++++++++++++++++++
 glnx-xattrs.h       |   45 ++++++++
 libglnx.h           |    1 +
 4 files changed, 333 insertions(+), 2 deletions(-)
---
diff --git a/Makefile-libglnx.am b/Makefile-libglnx.am
index 4620001..a04f19e 100644
--- a/Makefile-libglnx.am
+++ b/Makefile-libglnx.am
@@ -26,11 +26,13 @@ libglnx_la_SOURCES = \
        $(libglnx_srcpath)/glnx-errors.c \
        $(libglnx_srcpath)/glnx-dirfd.h \
        $(libglnx_srcpath)/glnx-dirfd.c \
+       $(libglnx_srcpath)/glnx-xattrs.h \
+       $(libglnx_srcpath)/glnx-xattrs.c \
        $(libglnx_srcpath)/glnx-shutil.h \
        $(libglnx_srcpath)/glnx-shutil.c \
        $(libglnx_srcpath)/libglnx.h \
        $(NULL)
 
 libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
-libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined 
-export-dynamic
-libglnx_la_LIBADD = $(libglnx_libs)
+libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined 
-export-dynamic 
+libglnx_la_LIBADD = $(libglnx_libs) -lattr
diff --git a/glnx-xattrs.c b/glnx-xattrs.c
new file mode 100644
index 0000000..249b211
--- /dev/null
+++ b/glnx-xattrs.c
@@ -0,0 +1,283 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2014,2015 Colin Walters <walters verbum org>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include <glnx-xattrs.h>
+#include <glnx-errors.h>
+#include <glnx-local-alloc.h>
+
+static GVariant *
+variant_new_ay_bytes (GBytes *bytes)
+{
+  gsize size;
+  gconstpointer data;
+  data = g_bytes_get_data (bytes, &size);
+  g_bytes_ref (bytes);
+  return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size,
+                                  TRUE, (GDestroyNotify)g_bytes_unref, bytes);
+}
+
+static char *
+canonicalize_xattrs (char    *xattr_string,
+                     size_t   len)
+{
+  char *p;
+  GSList *xattrs = NULL;
+  GSList *iter;
+  GString *result;
+
+  result = g_string_new (0);
+
+  p = xattr_string;
+  while (p < xattr_string+len)
+    {
+      xattrs = g_slist_prepend (xattrs, p);
+      p += strlen (p) + 1;
+    }
+
+  xattrs = g_slist_sort (xattrs, (GCompareFunc) strcmp);
+  for (iter = xattrs; iter; iter = iter->next) {
+    g_string_append (result, iter->data);
+    g_string_append_c (result, '\0');
+  }
+
+  g_slist_free (xattrs);
+  return g_string_free (result, FALSE);
+}
+
+static gboolean
+read_xattr_name_array (const char *path,
+                       int         fd,
+                       const char *xattrs,
+                       size_t      len,
+                       GVariantBuilder *builder,
+                       GError  **error)
+{
+  gboolean ret = FALSE;
+  const char *p;
+  int r;
+  const char *funcstr;
+
+  g_assert (path != NULL || fd != -1);
+
+  funcstr = fd != -1 ? "fgetxattr" : "lgetxattr";
+
+  p = xattrs;
+  while (p < xattrs+len)
+    {
+      ssize_t bytes_read;
+      char *buf;
+      GBytes *bytes = NULL;
+
+      if (fd != -1)
+        bytes_read = fgetxattr (fd, p, NULL, 0);
+      else
+        bytes_read = lgetxattr (path, p, NULL, 0);
+      if (bytes_read < 0)
+        {
+          glnx_set_prefix_error_from_errno (error, "%s", funcstr);
+          goto out;
+        }
+      if (bytes_read == 0)
+        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);
+          glnx_set_prefix_error_from_errno (error, "%s", funcstr);
+          goto out;
+        }
+      
+      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;
+}
+
+static gboolean
+get_xattrs_impl (const char      *path,
+                 GVariant       **out_xattrs,
+                 GCancellable   *cancellable,
+                 GError        **error)
+{
+  gboolean ret = FALSE;
+  ssize_t bytes_read;
+  glnx_free char *xattr_names = NULL;
+  glnx_free char *xattr_names_canonical = NULL;
+  GVariantBuilder builder;
+  gboolean builder_initialized = FALSE;
+  g_autoptr(GVariant) ret_xattrs = NULL;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
+  builder_initialized = TRUE;
+
+  bytes_read = llistxattr (path, NULL, 0);
+
+  if (bytes_read < 0)
+    {
+      if (errno != ENOTSUP)
+        {
+          glnx_set_prefix_error_from_errno (error, "%s", "llistxattr");
+          goto out;
+        }
+    }
+  else if (bytes_read > 0)
+    {
+      xattr_names = g_malloc (bytes_read);
+      if (llistxattr (path, xattr_names, bytes_read) < 0)
+        {
+          glnx_set_prefix_error_from_errno (error, "%s", "llistxattr");
+          goto out;
+        }
+      xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
+      
+      if (!read_xattr_name_array (path, -1, xattr_names_canonical, bytes_read, &builder, error))
+        goto out;
+    }
+
+  ret_xattrs = g_variant_builder_end (&builder);
+  builder_initialized = FALSE;
+  g_variant_ref_sink (ret_xattrs);
+  
+  ret = TRUE;
+  if (out_xattrs)
+    *out_xattrs = g_steal_pointer (&ret_xattrs);
+ out:
+  if (!builder_initialized)
+    g_variant_builder_clear (&builder);
+  return ret;
+}
+
+/**
+ * glnx_fd_get_all_xattrs:
+ * @fd: a file descriptor
+ * @out_xattrs: (out): A new #GVariant containing the extended attributes
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Read all extended attributes from @fd in a canonical sorted order, and
+ * set @out_xattrs with the result.
+ *
+ * If the filesystem does not support extended attributes, @out_xattrs
+ * will have 0 elements, and this function will return successfully.
+ */
+gboolean
+glnx_fd_get_all_xattrs (int            fd,
+                        GVariant     **out_xattrs,
+                        GCancellable  *cancellable,
+                        GError       **error)
+{
+  gboolean ret = FALSE;
+  ssize_t bytes_read;
+  glnx_free char *xattr_names = NULL;
+  glnx_free char *xattr_names_canonical = NULL;
+  GVariantBuilder builder;
+  gboolean builder_initialized = FALSE;
+  g_autoptr(GVariant) ret_xattrs = NULL;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
+  builder_initialized = TRUE;
+
+  bytes_read = flistxattr (fd, NULL, 0);
+
+  if (bytes_read < 0)
+    {
+      if (errno != ENOTSUP)
+        {
+          glnx_set_prefix_error_from_errno (error, "%s", "flistxattr");
+          goto out;
+        }
+    }
+  else if (bytes_read > 0)
+    {
+      xattr_names = g_malloc (bytes_read);
+      if (flistxattr (fd, xattr_names, bytes_read) < 0)
+        {
+          glnx_set_prefix_error_from_errno (error, "%s", "flistxattr");
+          goto out;
+        }
+      xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
+      
+      if (!read_xattr_name_array (NULL, fd, xattr_names_canonical, bytes_read, &builder, error))
+        goto out;
+    }
+
+  ret_xattrs = g_variant_builder_end (&builder);
+  builder_initialized = FALSE;
+  g_variant_ref_sink (ret_xattrs);
+  
+  ret = TRUE;
+  if (out_xattrs)
+    *out_xattrs = g_steal_pointer (&ret_xattrs);
+ out:
+  if (!builder_initialized)
+    g_variant_builder_clear (&builder);
+  return ret;
+}
+
+/**
+ * glnx_dfd_name_get_all_xattrs:
+ * @dfd: Parent directory file descriptor
+ * @name: File name
+ * @out_xattrs: (out): Extended attribute set
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Load all extended attributes for the file named @name residing in
+ * directory @dfd.
+ */
+gboolean
+glnx_dfd_name_get_all_xattrs (int            dfd,
+                              const char    *name,
+                              GVariant     **out_xattrs,
+                              GCancellable  *cancellable,
+                              GError       **error)
+{
+  if (dfd == AT_FDCWD || dfd == -1)
+    {
+      return get_xattrs_impl (name, out_xattrs, cancellable, error);
+    }
+  else
+    {
+      char buf[PATH_MAX];
+      /* A workaround for the lack of lgetxattrat(), thanks to Florian Weimer:
+       * https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html
+       */
+      snprintf (buf, sizeof (buf), "/proc/self/fd/%d/%s", dfd, name);
+      return get_xattrs_impl (buf, out_xattrs, cancellable, error);
+    }
+}
diff --git a/glnx-xattrs.h b/glnx-xattrs.h
new file mode 100644
index 0000000..360092d
--- /dev/null
+++ b/glnx-xattrs.h
@@ -0,0 +1,45 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2014,2015 Colin Walters <walters verbum org>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#pragma once
+
+#include <glnx-backport-autoptr.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <attr/xattr.h>
+
+G_BEGIN_DECLS
+
+gboolean
+glnx_dfd_name_get_all_xattrs (int                    dfd,
+                              const char            *name,
+                              GVariant             **out_xattrs,
+                              GCancellable          *cancellable,
+                              GError               **error);
+
+gboolean
+glnx_fd_get_all_xattrs (int                    fd,
+                        GVariant             **out_xattrs,
+                        GCancellable          *cancellable,
+                        GError               **error);
+
+G_END_DECLS
diff --git a/libglnx.h b/libglnx.h
index 294b904..e74eeda 100644
--- a/libglnx.h
+++ b/libglnx.h
@@ -30,5 +30,6 @@ G_BEGIN_DECLS
 #include <glnx-errors.h>
 #include <glnx-dirfd.h>
 #include <glnx-shutil.h>
+#include <glnx-xattrs.h>
 
 G_END_DECLS


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