Skip to content
Snippets Groups Projects
Commit f5399c83 authored by Colin Walters's avatar Colin Walters
Browse files

Import xattr reading code from libgsystem

parent ba67dd39
No related branches found
No related tags found
No related merge requests found
......@@ -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
/* -*- 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);
}
}
/* -*- 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
......@@ -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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment