diff options
author | Colin Walters <walters@verbum.org> | 2022-05-07 13:51:31 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2022-05-09 12:33:38 -0400 |
commit | f79b2cea91fc54a84e1f7c3f370dbad6e82f1954 (patch) | |
tree | 9f10fe73cc0d75494fbbe6d7a34124c31a557457 | |
parent | 22b8324019da3cff9effc7b8c1131ba2f0828877 (diff) | |
download | ostree-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.am | 6 | ||||
-rw-r--r-- | apidoc/ostree-sections.txt | 2 | ||||
-rw-r--r-- | src/libostree/libostree-devel.sym | 6 | ||||
-rw-r--r-- | src/libostree/ostree-core.c | 49 | ||||
-rw-r--r-- | src/libostree/ostree-core.h | 6 | ||||
-rw-r--r-- | src/libostree/ostree-repo-commit.c | 11 | ||||
-rw-r--r-- | src/libostree/ostree-repo.c | 10 | ||||
-rw-r--r-- | tests/test-basic-c.c | 72 |
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: |