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,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);

View File

@ -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,

View File

@ -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)
{

View File

@ -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'