mirror of
https://github.com/flatpak/flatpak.git
synced 2026-03-29 04:14:23 -04:00
Import xattr reading code from libgsystem
This commit is contained in:
@@ -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
|
||||
|
||||
283
glnx-xattrs.c
Normal file
283
glnx-xattrs.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
45
glnx-xattrs.h
Normal file
45
glnx-xattrs.h
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user