Actually checksum xattr values, not just names

We need to call lgetxattr() and not just llistxattr().
This commit is contained in:
Colin Walters 2011-10-15 03:03:51 -04:00
parent 88c9851795
commit 05c35f2cf7
4 changed files with 97 additions and 74 deletions

View File

@ -61,15 +61,63 @@ canonicalize_xattrs (char *xattr_string, size_t len)
return g_string_free (result, FALSE); return g_string_free (result, FALSE);
} }
gboolean static gboolean
hacktree_get_xattrs_for_directory (const char *path, read_xattr_name_array (const char *path,
char **out_xattrs, /* out */ const char *xattrs,
gsize *out_len, /* out */ size_t len,
GVariantBuilder *builder,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
char *xattrs = NULL; const char *p;
p = xattrs;
while (p < xattrs+len)
{
ssize_t bytes_read; 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); bytes_read = llistxattr (path, NULL, 0);
@ -83,27 +131,25 @@ hacktree_get_xattrs_for_directory (const char *path,
} }
else if (bytes_read > 0) else if (bytes_read > 0)
{ {
xattrs = g_malloc (bytes_read); const char *p;
if (!llistxattr (path, xattrs, bytes_read)) xattr_names = g_malloc (bytes_read);
if (llistxattr (path, xattr_names, bytes_read) < 0)
{ {
ht_util_set_error_from_errno (error, errno); ht_util_set_error_from_errno (error, errno);
g_free (xattrs); goto out;
xattrs = NULL; }
xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, &builder, error))
goto out; goto out;
} }
*out_xattrs = canonicalize_xattrs (xattrs, bytes_read); ret = g_variant_builder_end (&builder);
*out_len = (gsize)bytes_read;
}
else
{
*out_xattrs = NULL;
*out_len = 0;
}
ret = TRUE;
out: out:
g_free (xattrs); if (!ret)
g_variant_builder_clear (&builder);
g_free (xattr_names);
g_free (xattr_names_canonical);
return ret; return ret;
} }
@ -117,8 +163,7 @@ hacktree_stat_and_checksum_file (int dir_fd, const char *path,
GChecksum *content_and_meta_sha256 = NULL; GChecksum *content_and_meta_sha256 = NULL;
char *stat_string = NULL; char *stat_string = NULL;
ssize_t bytes_read; ssize_t bytes_read;
char *xattrs = NULL; GVariant *xattrs = NULL;
char *xattrs_canonicalized = NULL;
int fd = -1; int fd = -1;
DIR *temp_dir = NULL; DIR *temp_dir = NULL;
char *basename = 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); stat_string = stat_to_string (&stbuf);
xattrs = hacktree_get_xattrs_for_path (path, error);
/* FIXME - Add llistxattrat */ if (!xattrs)
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; 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);
}
content_sha256 = g_checksum_new (G_CHECKSUM_SHA256); 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); 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*)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_stbuf = stbuf;
*out_checksum = content_and_meta_sha256; *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 (symlink_target);
g_free (basename); g_free (basename);
g_free (stat_string); g_free (stat_string);
g_free (xattrs); if (xattrs)
g_free (xattrs_canonicalized); g_variant_unref (xattrs);
if (content_sha256) if (content_sha256)
g_checksum_free (content_sha256); g_checksum_free (content_sha256);

View File

@ -36,11 +36,18 @@ typedef enum {
typedef enum { typedef enum {
HACKTREE_SERIALIZED_TREE_VARIANT = 1, HACKTREE_SERIALIZED_TREE_VARIANT = 1,
HACKTREE_SERIALIZED_COMMIT_VARIANT = 2, HACKTREE_SERIALIZED_COMMIT_VARIANT = 2,
HACKTREE_SERIALIZED_DIRMETA_VARIANT = 3 HACKTREE_SERIALIZED_DIRMETA_VARIANT = 3,
HACKTREE_SERIALIZED_XATTR_VARIANT = 4
} HacktreeSerializedVariantType; } HacktreeSerializedVariantType;
#define HACKTREE_SERIALIZED_VARIANT_FORMAT "(uv)" #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 #define HACKTREE_DIR_META_VERSION 0
/* /*
* dirmeta objects: * dirmeta objects:
@ -48,9 +55,9 @@ typedef enum {
* u - uid * u - uid
* u - gid * u - gid
* u - mode * 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 #define HACKTREE_TREE_VERSION 0
/* /*
@ -75,9 +82,7 @@ typedef enum {
*/ */
#define HACKTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}sssts)" #define HACKTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}sssts)"
gboolean hacktree_get_xattrs_for_directory (const char *path, GVariant *hacktree_get_xattrs_for_path (const char *path,
char **out_xattrs,
gsize *out_len,
GError **error); GError **error);
gboolean hacktree_stat_and_checksum_file (int dirfd, const char *path, gboolean hacktree_stat_and_checksum_file (int dirfd, const char *path,

View File

@ -402,7 +402,7 @@ import_directory_meta (HacktreeRepo *self,
struct stat stbuf; struct stat stbuf;
GChecksum *ret_checksum = NULL; GChecksum *ret_checksum = NULL;
GVariant *dirmeta = NULL; GVariant *dirmeta = NULL;
char *xattrs = NULL; GVariant *xattrs = NULL;
gsize xattr_len; gsize xattr_len;
if (lstat (path, &stbuf) < 0) if (lstat (path, &stbuf) < 0)
@ -418,16 +418,17 @@ import_directory_meta (HacktreeRepo *self,
goto out; 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; goto out;
dirmeta = g_variant_new ("(uuuu@ay)", dirmeta = g_variant_new ("(uuuu@a(ayay))",
HACKTREE_DIR_META_VERSION, HACKTREE_DIR_META_VERSION,
(guint32)stbuf.st_uid, (guint32)stbuf.st_uid,
(guint32)stbuf.st_gid, (guint32)stbuf.st_gid,
(guint32)(stbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)), (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);
xattrs, xattr_len, 1)); xattrs = NULL; /* was floating */
g_variant_ref_sink (dirmeta); g_variant_ref_sink (dirmeta);
if (!import_gvariant_object (self, HACKTREE_SERIALIZED_DIRMETA_VARIANT, if (!import_gvariant_object (self, HACKTREE_SERIALIZED_DIRMETA_VARIANT,
@ -448,7 +449,8 @@ import_directory_meta (HacktreeRepo *self,
*out_checksum = ret_checksum; *out_checksum = ret_checksum;
*out_variant = dirmeta; *out_variant = dirmeta;
} }
g_free (xattrs); if (xattrs)
g_variant_unref (xattrs);
return ret; return ret;
} }
@ -1473,10 +1475,9 @@ checkout_one_directory (HacktreeRepo *self,
dest_path = g_build_filename (destination, dirname, NULL); 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, &version, &uid, &gid, &mode,
&xattr_variant); &xattr_variant);
xattrs = g_variant_get_fixed_array (xattr_variant, &xattr_len, 1);
if (mkdir (dest_path, (mode_t)mode) < 0) if (mkdir (dest_path, (mode_t)mode) < 0)
{ {

View File

@ -22,7 +22,7 @@ set -e
. libtest.sh . libtest.sh
echo '1..3' echo '1..5'
setup_test_repository2 setup_test_repository2
echo 'ok setup' echo 'ok setup'
@ -30,8 +30,10 @@ hacktree checkout $ht_repo HEAD $test_tmpdir/checkout2-head
echo 'ok checkout cmd' echo 'ok checkout cmd'
cd $test_tmpdir/checkout2-head cd $test_tmpdir/checkout2-head
assert_has_file firstfile assert_has_file firstfile
echo 'ok checkout firstfile'
assert_has_file baz/cow assert_has_file baz/cow
assert_has_file baz/saucer assert_has_file baz/saucer
echo 'ok checkout baz (2)'
assert_has_file baz/deeper/ohyeah assert_has_file baz/deeper/ohyeah
assert_has_file baz/another/y assert_has_file baz/another/y
echo 'ok checkout verify exists' echo 'ok checkout verify exists'