Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

writer: Fix return value of lcfs_node_unset_xattr #401

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions libcomposefs/lcfs-writer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1660,24 +1660,26 @@ int lcfs_node_unset_xattr(struct lcfs_node_s *node, const char *name)
{
ssize_t index = find_xattr(node, name);

if (index >= 0) {
struct lcfs_xattr_s *xattr = &node->xattrs[index];
size_t value_len = xattr->value_len;
free(xattr->key);
free(xattr->value);
if (index != (ssize_t)node->n_xattrs - 1)
node->xattrs[index] = node->xattrs[node->n_xattrs - 1];
node->n_xattrs--;
// Note 2*size - to account for worst case alignment
if (node->n_xattrs > 0)
node->xattr_size -= (2 * LCFS_INODE_XATTRMETA_SIZE - 1) +
strlen(name) + value_len;
else
node->xattr_size = 0; // If last xattr, remove the overhead too
assert(node->xattr_size >= 0);
if (index < 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way around reads a lot nicer now. Thanks for the change.

errno = ENODATA;
return -1;
}

return -1;
struct lcfs_xattr_s *xattr = &node->xattrs[index];
size_t value_len = xattr->value_len;
free(xattr->key);
free(xattr->value);
if (index != (ssize_t)node->n_xattrs - 1)
node->xattrs[index] = node->xattrs[node->n_xattrs - 1];
node->n_xattrs--;
// Note 2*size - to account for worst case alignment
if (node->n_xattrs > 0)
node->xattr_size -= (2 * LCFS_INODE_XATTRMETA_SIZE - 1) +
strlen(name) + value_len;
else
node->xattr_size = 0; // If last xattr, remove the overhead too
assert(node->xattr_size >= 0);
return 0;
cgwalters marked this conversation as resolved.
Show resolved Hide resolved
}

/* Set an extended attribute; If from_external_input is true then we
Expand All @@ -1702,7 +1704,8 @@ int lcfs_node_set_xattr_internal(struct lcfs_node_s *node, const char *name,
}

// Remove any existing value
(void)lcfs_node_unset_xattr(node, name);
if (lcfs_node_unset_xattr(node, name) < 0 && errno != ENODATA)
return -1;

// Double the xattr metadata size, subtracting 1 to account for worst case alignment.
size_t entry_size = (2 * LCFS_INODE_XATTRMETA_SIZE) - 1 + namelen + value_len;
Expand Down
46 changes: 46 additions & 0 deletions tests/test-lcfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "lcfs-writer.h"
#include "lcfs-mount.h"
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
Expand Down Expand Up @@ -58,6 +59,49 @@ static void test_basic(void)
assert(r == 0);
}

static void test_xattr_addremove(void)
{
cleanup_node struct lcfs_node_s *node = lcfs_node_new();
lcfs_node_set_mode(node, S_IFDIR | 0755);
cleanup_node struct lcfs_node_s *child = lcfs_node_new();
lcfs_node_set_mode(child, S_IFDIR | 0700);
int r = lcfs_node_unset_xattr(child, "user.foo");
int errsv = errno;
assert(r == -1);
assert(errsv == ENODATA);
r = lcfs_node_set_xattr(child, "user.foo", "bar", 3);
assert(r == 0);
r = lcfs_node_unset_xattr(child, "user.foo");
assert(r == 0);
r = lcfs_node_add_child(node, child, "somechild");
assert(r == 0);
child = NULL;
}

// Test that calling lcfs_node_set_xattr multiple times
// with the same key has last-one-wins semantics.
static void test_xattr_doubleadd(void)
{
cleanup_node struct lcfs_node_s *node = lcfs_node_new();
lcfs_node_set_mode(node, S_IFDIR | 0755);
cleanup_node struct lcfs_node_s *child = lcfs_node_new();
lcfs_node_set_mode(child, S_IFDIR | 0700);
int r = lcfs_node_set_xattr(child, "user.foo", "bar", 3);
assert(r == 0);
// Should successfully silently overwrite.
r = lcfs_node_set_xattr(child, "user.foo", "baz", 3);
assert(r == 0);

size_t found_len;
const char *found_value = lcfs_node_get_xattr(child, "user.foo", &found_len);
assert(found_value);
assert(found_len == 3);
assert(memcmp(found_value, "baz", found_len) == 0);
r = lcfs_node_add_child(node, child, "somechild");
assert(r == 0);
child = NULL;
}

static void test_add_uninitialized_child(void)
{
cleanup_node struct lcfs_node_s *node = lcfs_node_new();
Expand Down Expand Up @@ -99,4 +143,6 @@ int main(int argc, char **argv)
test_basic();
test_no_verity();
test_add_uninitialized_child();
test_xattr_addremove();
test_xattr_doubleadd();
}
Loading