summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2022-05-07 13:51:31 -0400
committerColin Walters <walters@verbum.org>2022-05-09 12:33:38 -0400
commitf79b2cea91fc54a84e1f7c3f370dbad6e82f1954 (patch)
tree9f10fe73cc0d75494fbbe6d7a34124c31a557457
parent22b8324019da3cff9effc7b8c1131ba2f0828877 (diff)
downloadostree-f79b2cea91fc54a84e1f7c3f370dbad6e82f1954.tar.gz
Add APIs to get xattrs from disk
I'm aiming to do some more work on the Rust side around `fsck` like functionality, and this is a useful primitive. There isn't a great Rust crate for xattrs, and I think it's better to share this code.
-rw-r--r--Makefile-libostree.am6
-rw-r--r--apidoc/ostree-sections.txt2
-rw-r--r--src/libostree/libostree-devel.sym6
-rw-r--r--src/libostree/ostree-core.c49
-rw-r--r--src/libostree/ostree-core.h6
-rw-r--r--src/libostree/ostree-repo-commit.c11
-rw-r--r--src/libostree/ostree-repo.c10
-rw-r--r--tests/test-basic-c.c72
8 files changed, 148 insertions, 14 deletions
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index b58106aa..af89ce9a 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -171,9 +171,9 @@ endif # USE_GPGME
symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym
# Uncomment this include when adding new development symbols.
-#if BUILDOPT_IS_DEVEL_BUILD
-#symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
-#endif
+if BUILDOPT_IS_DEVEL_BUILD
+symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
+endif
# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html
wl_versionscript_arg = -Wl,--version-script=
diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt
index 577ee808..adf52557 100644
--- a/apidoc/ostree-sections.txt
+++ b/apidoc/ostree-sections.txt
@@ -143,6 +143,8 @@ ostree_checksum_file
ostree_checksum_file_at
ostree_checksum_file_async
ostree_checksum_file_async_finish
+ostree_fs_get_all_xattrs
+ostree_fs_get_all_xattrs_at
ostree_create_directory_metadata
ostree_validate_structureof_objtype
ostree_validate_structureof_csum_v
diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym
index c15ae9fa..13e8041b 100644
--- a/src/libostree/libostree-devel.sym
+++ b/src/libostree/libostree-devel.sym
@@ -20,7 +20,11 @@
- uncomment the include in Makefile-libostree.am
*/
-
+LIBOSTREE_2022.4 {
+global:
+ ostree_fs_get_all_xattrs;
+ ostree_fs_get_all_xattrs_at;
+} LIBOSTREE_2021.5;
/* Stub section for the stable release *after* this development one; don't
* edit this other than to update the year. This is just a copy/paste
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index 794f0e11..56b381d9 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -837,6 +837,51 @@ gboolean ostree_break_hardlink (int dfd,
}
/**
+ * ostree_fs_get_all_xattrs:
+ * @fd: File descriptor
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Retrieve all extended attributes in a canonical (sorted) order from
+ * the given file descriptor.
+ *
+ * Returns: (transfer full): A GVariant of type `a(ayay)`
+ */
+GVariant *
+ostree_fs_get_all_xattrs (int fd, GCancellable *cancellable, GError **error)
+{
+ GVariant *ret = NULL;
+ if (!glnx_fd_get_all_xattrs (fd, &ret, cancellable, error))
+ return NULL;
+ return ret;
+}
+
+/**
+ * ostree_fs_get_all_xattrs_at:
+ * @dfd: Directory file descriptor
+ * @path: Filesystem path
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Retrieve all extended attributes in a canonical (sorted) order from
+ * the given path, relative to the provided directory file descriptor.
+ * The target path will not be dereferenced. Currently on Linux, this
+ * API must be used currently to retrieve extended attributes
+ * for symbolic links because while `O_PATH` exists, it cannot be used
+ * with `fgetxattr()`.
+ *
+ * Returns: (transfer full): A GVariant of type `a(ayay)`
+ */
+GVariant *
+ostree_fs_get_all_xattrs_at (int dfd, const char *path, GCancellable *cancellable, GError **error)
+{
+ GVariant *ret = NULL;
+ if (!glnx_dfd_name_get_all_xattrs (dfd, path, &ret, cancellable, error))
+ return NULL;
+ return ret;
+}
+
+/**
* ostree_checksum_file_from_input:
* @file_info: File information
* @xattrs: (allow-none): Optional extended attributes
@@ -928,8 +973,8 @@ ostree_checksum_file (GFile *f,
g_autoptr(GVariant) xattrs = NULL;
if (objtype == OSTREE_OBJECT_TYPE_FILE)
{
- if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f),
- &xattrs, cancellable, error))
+ xattrs = ostree_fs_get_all_xattrs_at (AT_FDCWD, gs_file_get_path_cached (f), cancellable, error);
+ if (!xattrs)
return FALSE;
}
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index 9a14192d..0d4dca8e 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -464,6 +464,12 @@ gboolean ostree_break_hardlink (int dfd,
GCancellable *cancellable,
GError **error);
+_OSTREE_PUBLIC
+GVariant *ostree_fs_get_all_xattrs (int fd, GCancellable *cancellable, GError **error);
+
+_OSTREE_PUBLIC
+GVariant *ostree_fs_get_all_xattrs_at (int dfd, const char *path, GCancellable *cancellable, GError **error);
+
/**
* OstreeChecksumFlags:
* @OSTREE_CHECKSUM_FLAGS_NONE: Default checksumming without tweaks.
diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c
index 0af8fee3..afab3fdf 100644
--- a/src/libostree/ostree-repo-commit.c
+++ b/src/libostree/ostree-repo-commit.c
@@ -3436,14 +3436,15 @@ get_final_xattrs (OstreeRepo *self,
else if (dfd_subpath == NULL)
{
g_assert (dfd != -1);
- if (!glnx_fd_get_all_xattrs (dfd, &original_xattrs, cancellable, error))
+ original_xattrs = ostree_fs_get_all_xattrs (dfd, cancellable, error);
+ if (!original_xattrs)
return FALSE;
}
else
{
g_assert (dfd != -1);
- if (!glnx_dfd_name_get_all_xattrs (dfd, dfd_subpath, &original_xattrs,
- cancellable, error))
+ original_xattrs = ostree_fs_get_all_xattrs_at (dfd, dfd_subpath, cancellable, error);
+ if (!original_xattrs)
return FALSE;
}
@@ -4641,8 +4642,8 @@ import_one_object_direct (OstreeRepo *dest_repo,
if (src_repo->mode == OSTREE_REPO_MODE_BARE)
{
g_autoptr(GVariant) xattrs = NULL;
- if (!glnx_fd_get_all_xattrs (src_fd, &xattrs,
- cancellable, error))
+ xattrs = ostree_fs_get_all_xattrs (src_fd, cancellable, error);
+ if (!xattrs)
return FALSE;
if (!glnx_fd_set_all_xattrs (tmp_dest.fd, xattrs,
cancellable, error))
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index ad071c17..994db626 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -28,6 +28,7 @@
#include <gio/gunixoutputstream.h>
#include <gio/gfiledescriptorbased.h>
#include "libglnx.h"
+#include "ostree-core.h"
#include "otutil.h"
#include <glnx-console.h>
#include <linux/magic.h>
@@ -4345,9 +4346,12 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
{
if (self->disable_xattrs)
ret_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
- else if (!glnx_fd_get_all_xattrs (fd, &ret_xattrs,
- cancellable, error))
- return FALSE;
+ else
+ {
+ ret_xattrs = ostree_fs_get_all_xattrs (fd, cancellable, error);
+ if (!ret_xattrs)
+ return FALSE;
+ }
}
else if (S_ISLNK (stbuf.st_mode) && out_xattrs)
{
diff --git a/tests/test-basic-c.c b/tests/test-basic-c.c
index bac7d56d..1886feb2 100644
--- a/tests/test-basic-c.c
+++ b/tests/test-basic-c.c
@@ -20,6 +20,7 @@
#include "config.h"
#include <stdlib.h>
+#include <stdbool.h>
#include <gio/gio.h>
#include <string.h>
#include <err.h>
@@ -476,6 +477,76 @@ test_big_metadata (void)
g_assert (ret);
}
+static void
+compare_xattrs (GVariant *orig, GVariant *new)
+{
+ g_assert_cmpint (g_variant_n_children (orig) + 1, ==, g_variant_n_children (new));
+ GVariant *kp, *vp;
+ GVariantIter iter;
+ g_variant_iter_init (&iter, new);
+ bool found = false;
+ while (g_variant_iter_loop (&iter, "(@ay@ay)", &kp, &vp))
+ {
+ const char *k = g_variant_get_bytestring (kp);
+ if (!g_str_equal (k, "user.ostreetesting"))
+ continue;
+ g_assert_cmpint (g_variant_get_size (vp), ==, 4);
+ found = true;
+ }
+ g_assert (found);
+}
+
+static void
+test_read_xattrs (void)
+{
+ g_autoptr(GError) local_error = NULL;
+ GError **error = &local_error;
+
+ g_auto(GLnxTmpDir) tmpd = { 0, };
+ // Use /var/tmp to hope we get xattr support
+ glnx_mkdtempat (AT_FDCWD, "/var/tmp/ostree-xattrs-test.XXXXXX", 0700, &tmpd, error);
+ g_assert_no_error (local_error);
+
+ const char value[] = "foo";
+
+ {
+ g_autoptr(GVariant) current_xattrs = ostree_fs_get_all_xattrs (tmpd.fd, NULL, error);
+ g_assert_no_error (local_error);
+
+ int r = fsetxattr (tmpd.fd, "user.ostreetesting", value, sizeof (value), 0);
+ g_assert_cmpint (r, ==, 0);
+
+ g_autoptr(GVariant) new_xattrs = ostree_fs_get_all_xattrs (tmpd.fd, NULL, error);
+ g_assert_no_error (local_error);
+
+ compare_xattrs (current_xattrs, new_xattrs);
+ }
+
+ {
+ if (symlinkat ("nosuchtarget", tmpd.fd, "somelink") < 0)
+ glnx_throw_errno_prefix (error, "symlinkat");
+ g_assert_no_error (local_error);
+
+ g_autoptr(GVariant) current_xattrs = ostree_fs_get_all_xattrs_at (tmpd.fd, "somelink", NULL, error);
+ g_assert_no_error (local_error);
+ (void) current_xattrs;
+
+ // OK, can't do user. xattrs on symlinks unfortunately.
+
+ // char pathbuf[PATH_MAX];
+ // snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", tmpd.fd, "somelink");
+ // int r = lsetxattr (pathbuf, "user.ostreetesting", value, sizeof (value), 0);
+ // if (r < 0)
+ // glnx_throw_errno_prefix (error, "lsetxattr");
+ // g_assert_no_error (local_error);
+
+ // g_autoptr(GVariant) new_xattrs = ostree_fs_get_all_xattrs_at (tmpd.fd, "somelink", NULL, error);
+ // g_assert_no_error (local_error);
+
+ // compare_xattrs (current_xattrs, new_xattrs);
+ }
+}
+
int main (int argc, char **argv)
{
g_autoptr(GError) error = NULL;
@@ -494,6 +565,7 @@ int main (int argc, char **argv)
g_test_add_func ("/break-hardlink", test_break_hardlink);
g_test_add_func ("/remotename", test_validate_remotename);
g_test_add_func ("/big-metadata", test_big_metadata);
+ g_test_add_func ("/read-xattrs", test_read_xattrs);
return g_test_run();
out: