From 05c35f2cf7ed7e6cdf0cd84a6bb1a381faa46584 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sat, 15 Oct 2011 03:03:51 -0400 Subject: [PATCH] Actually checksum xattr values, not just names We need to call lgetxattr() and not just llistxattr(). --- src/libhacktree/hacktree-core.c | 131 ++++++++++++++++++-------------- src/libhacktree/hacktree-core.h | 19 +++-- src/libhacktree/hacktree-repo.c | 17 +++-- tests/t0005-nested-tree.sh | 4 +- 4 files changed, 97 insertions(+), 74 deletions(-) diff --git a/src/libhacktree/hacktree-core.c b/src/libhacktree/hacktree-core.c index 165dfe75..9817c85c 100644 --- a/src/libhacktree/hacktree-core.c +++ b/src/libhacktree/hacktree-core.c @@ -61,16 +61,64 @@ canonicalize_xattrs (char *xattr_string, size_t len) return g_string_free (result, FALSE); } -gboolean -hacktree_get_xattrs_for_directory (const char *path, - char **out_xattrs, /* out */ - gsize *out_len, /* out */ - GError **error) +static gboolean +read_xattr_name_array (const char *path, + const char *xattrs, + size_t len, + GVariantBuilder *builder, + GError **error) { gboolean ret = FALSE; - char *xattrs = NULL; + const char *p; + + p = xattrs; + while (p < xattrs+len) + { + ssize_t bytes_read; + char *buf; + + bytes_read = lgetxattr (path, p, NULL, 0); + if (bytes_read < 0) + { + ht_util_set_error_from_errno (error, errno); + goto out; + } + if (bytes_read == 0) + continue; + + buf = g_malloc (bytes_read); + if (lgetxattr (path, p, buf, bytes_read) < 0) + { + ht_util_set_error_from_errno (error, errno); + g_free (buf); + goto out; + } + + g_variant_builder_add (builder, "(@ay@ay)", + g_variant_new_bytestring (p), + g_variant_new_fixed_array (G_VARIANT_TYPE ("y"), buf, bytes_read, 1)); + + g_free (buf); + p = p + strlen (p) + 1; + } + + ret = TRUE; + out: + return ret; +} + +GVariant * +hacktree_get_xattrs_for_path (const char *path, + GError **error) +{ + GVariant *ret = NULL; + GVariantBuilder builder; + char *xattr_names = NULL; + char *xattr_names_canonical = NULL; ssize_t bytes_read; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); + bytes_read = llistxattr (path, NULL, 0); if (bytes_read < 0) @@ -83,27 +131,25 @@ hacktree_get_xattrs_for_directory (const char *path, } else if (bytes_read > 0) { - xattrs = g_malloc (bytes_read); - if (!llistxattr (path, xattrs, bytes_read)) + const char *p; + xattr_names = g_malloc (bytes_read); + if (llistxattr (path, xattr_names, bytes_read) < 0) { ht_util_set_error_from_errno (error, errno); - g_free (xattrs); - xattrs = NULL; goto out; } - - *out_xattrs = canonicalize_xattrs (xattrs, bytes_read); - *out_len = (gsize)bytes_read; - } - else - { - *out_xattrs = NULL; - *out_len = 0; + xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read); + + if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, &builder, error)) + goto out; } - ret = TRUE; + ret = g_variant_builder_end (&builder); out: - g_free (xattrs); + if (!ret) + g_variant_builder_clear (&builder); + g_free (xattr_names); + g_free (xattr_names_canonical); return ret; } @@ -117,8 +163,7 @@ hacktree_stat_and_checksum_file (int dir_fd, const char *path, GChecksum *content_and_meta_sha256 = NULL; char *stat_string = NULL; ssize_t bytes_read; - char *xattrs = NULL; - char *xattrs_canonicalized = NULL; + GVariant *xattrs = NULL; int fd = -1; DIR *temp_dir = NULL; char *basename = NULL; @@ -159,39 +204,9 @@ hacktree_stat_and_checksum_file (int dir_fd, const char *path, } stat_string = stat_to_string (&stbuf); - - /* FIXME - Add llistxattrat */ - if (!S_ISLNK(stbuf.st_mode)) - bytes_read = flistxattr (fd, NULL, 0); - else - bytes_read = llistxattr (path, NULL, 0); - - if (bytes_read < 0) - { - if (errno != ENOTSUP) - { - ht_util_set_error_from_errno (error, errno); - goto out; - } - } - else if (bytes_read > 0) - { - gboolean tmp; - xattrs = g_malloc (bytes_read); - /* FIXME - Add llistxattrat */ - if (!S_ISLNK(stbuf.st_mode)) - tmp = flistxattr (fd, xattrs, bytes_read); - else - tmp = llistxattr (path, xattrs, bytes_read); - - if (!tmp) - { - ht_util_set_error_from_errno (error, errno); - goto out; - } - - xattrs_canonicalized = canonicalize_xattrs (xattrs, bytes_read); - } + xattrs = hacktree_get_xattrs_for_path (path, error); + if (!xattrs) + goto out; content_sha256 = g_checksum_new (G_CHECKSUM_SHA256); @@ -235,7 +250,7 @@ hacktree_stat_and_checksum_file (int dir_fd, const char *path, content_and_meta_sha256 = g_checksum_copy (content_sha256); g_checksum_update (content_and_meta_sha256, (guint8*)stat_string, strlen (stat_string)); - g_checksum_update (content_and_meta_sha256, (guint8*)xattrs_canonicalized, strlen (stat_string)); + g_checksum_update (content_and_meta_sha256, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs)); *out_stbuf = stbuf; *out_checksum = content_and_meta_sha256; @@ -248,8 +263,8 @@ hacktree_stat_and_checksum_file (int dir_fd, const char *path, g_free (symlink_target); g_free (basename); g_free (stat_string); - g_free (xattrs); - g_free (xattrs_canonicalized); + if (xattrs) + g_variant_unref (xattrs); if (content_sha256) g_checksum_free (content_sha256); diff --git a/src/libhacktree/hacktree-core.h b/src/libhacktree/hacktree-core.h index 51020397..4f06ae58 100644 --- a/src/libhacktree/hacktree-core.h +++ b/src/libhacktree/hacktree-core.h @@ -36,11 +36,18 @@ typedef enum { typedef enum { HACKTREE_SERIALIZED_TREE_VARIANT = 1, HACKTREE_SERIALIZED_COMMIT_VARIANT = 2, - HACKTREE_SERIALIZED_DIRMETA_VARIANT = 3 + HACKTREE_SERIALIZED_DIRMETA_VARIANT = 3, + HACKTREE_SERIALIZED_XATTR_VARIANT = 4 } HacktreeSerializedVariantType; #define HACKTREE_SERIALIZED_VARIANT_FORMAT "(uv)" +/* + * xattr objects: + * a(ayay) - array of (name, value) pairs, both binary data, though name is a bytestring + */ +#define HACKTREE_XATTR_GVARIANT_FORMAT "a(ayay)" + #define HACKTREE_DIR_META_VERSION 0 /* * dirmeta objects: @@ -48,9 +55,9 @@ typedef enum { * u - uid * u - gid * u - mode - * ay - xattrs + * a(ayay) - xattrs */ -#define HACKTREE_DIRMETA_GVARIANT_FORMAT "(uuuuay)" +#define HACKTREE_DIRMETA_GVARIANT_FORMAT "(uuuua(ayay))" #define HACKTREE_TREE_VERSION 0 /* @@ -75,10 +82,8 @@ typedef enum { */ #define HACKTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}sssts)" -gboolean hacktree_get_xattrs_for_directory (const char *path, - char **out_xattrs, - gsize *out_len, - GError **error); +GVariant *hacktree_get_xattrs_for_path (const char *path, + GError **error); gboolean hacktree_stat_and_checksum_file (int dirfd, const char *path, GChecksum **out_checksum, diff --git a/src/libhacktree/hacktree-repo.c b/src/libhacktree/hacktree-repo.c index 6541b74a..2469b35b 100644 --- a/src/libhacktree/hacktree-repo.c +++ b/src/libhacktree/hacktree-repo.c @@ -402,7 +402,7 @@ import_directory_meta (HacktreeRepo *self, struct stat stbuf; GChecksum *ret_checksum = NULL; GVariant *dirmeta = NULL; - char *xattrs = NULL; + GVariant *xattrs = NULL; gsize xattr_len; if (lstat (path, &stbuf) < 0) @@ -418,16 +418,17 @@ import_directory_meta (HacktreeRepo *self, goto out; } - if (!hacktree_get_xattrs_for_directory (path, &xattrs, &xattr_len, error)) + xattrs = hacktree_get_xattrs_for_path (path, error); + if (!xattrs) goto out; - dirmeta = g_variant_new ("(uuuu@ay)", + dirmeta = g_variant_new ("(uuuu@a(ayay))", HACKTREE_DIR_META_VERSION, (guint32)stbuf.st_uid, (guint32)stbuf.st_gid, (guint32)(stbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)), - g_variant_new_fixed_array (G_VARIANT_TYPE ("y"), - xattrs, xattr_len, 1)); + xattrs); + xattrs = NULL; /* was floating */ g_variant_ref_sink (dirmeta); if (!import_gvariant_object (self, HACKTREE_SERIALIZED_DIRMETA_VARIANT, @@ -448,7 +449,8 @@ import_directory_meta (HacktreeRepo *self, *out_checksum = ret_checksum; *out_variant = dirmeta; } - g_free (xattrs); + if (xattrs) + g_variant_unref (xattrs); return ret; } @@ -1473,10 +1475,9 @@ checkout_one_directory (HacktreeRepo *self, dest_path = g_build_filename (destination, dirname, NULL); - g_variant_get (dir->meta_data, "(uuuu@ay)", + g_variant_get (dir->meta_data, "(uuuu@a(ayay))", &version, &uid, &gid, &mode, &xattr_variant); - xattrs = g_variant_get_fixed_array (xattr_variant, &xattr_len, 1); if (mkdir (dest_path, (mode_t)mode) < 0) { diff --git a/tests/t0005-nested-tree.sh b/tests/t0005-nested-tree.sh index 76952bcf..f7f51827 100755 --- a/tests/t0005-nested-tree.sh +++ b/tests/t0005-nested-tree.sh @@ -22,7 +22,7 @@ set -e . libtest.sh -echo '1..3' +echo '1..5' setup_test_repository2 echo 'ok setup' @@ -30,8 +30,10 @@ hacktree checkout $ht_repo HEAD $test_tmpdir/checkout2-head echo 'ok checkout cmd' cd $test_tmpdir/checkout2-head assert_has_file firstfile +echo 'ok checkout firstfile' assert_has_file baz/cow assert_has_file baz/saucer +echo 'ok checkout baz (2)' assert_has_file baz/deeper/ohyeah assert_has_file baz/another/y echo 'ok checkout verify exists'