|
@@ -260,16 +260,12 @@ out:
|
|
|
|
|
|
ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|
|
{
|
|
|
- struct btrfs_key key, found_key;
|
|
|
+ struct btrfs_key key;
|
|
|
struct inode *inode = d_inode(dentry);
|
|
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
|
|
struct btrfs_path *path;
|
|
|
- struct extent_buffer *leaf;
|
|
|
- struct btrfs_dir_item *di;
|
|
|
- int ret = 0, slot;
|
|
|
+ int ret = 0;
|
|
|
size_t total_size = 0, size_left = size;
|
|
|
- unsigned long name_ptr;
|
|
|
- size_t name_len;
|
|
|
|
|
|
/*
|
|
|
* ok we want all objects associated with this id.
|
|
@@ -291,6 +287,13 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|
|
goto err;
|
|
|
|
|
|
while (1) {
|
|
|
+ struct extent_buffer *leaf;
|
|
|
+ int slot;
|
|
|
+ struct btrfs_dir_item *di;
|
|
|
+ struct btrfs_key found_key;
|
|
|
+ u32 item_size;
|
|
|
+ u32 cur;
|
|
|
+
|
|
|
leaf = path->nodes[0];
|
|
|
slot = path->slots[0];
|
|
|
|
|
@@ -316,31 +319,45 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|
|
if (found_key.type > BTRFS_XATTR_ITEM_KEY)
|
|
|
break;
|
|
|
if (found_key.type < BTRFS_XATTR_ITEM_KEY)
|
|
|
- goto next;
|
|
|
+ goto next_item;
|
|
|
|
|
|
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
|
|
|
- if (verify_dir_item(root, leaf, di))
|
|
|
- goto next;
|
|
|
-
|
|
|
- name_len = btrfs_dir_name_len(leaf, di);
|
|
|
- total_size += name_len + 1;
|
|
|
+ item_size = btrfs_item_size_nr(leaf, slot);
|
|
|
+ cur = 0;
|
|
|
+ while (cur < item_size) {
|
|
|
+ u16 name_len = btrfs_dir_name_len(leaf, di);
|
|
|
+ u16 data_len = btrfs_dir_data_len(leaf, di);
|
|
|
+ u32 this_len = sizeof(*di) + name_len + data_len;
|
|
|
+ unsigned long name_ptr = (unsigned long)(di + 1);
|
|
|
+
|
|
|
+ if (verify_dir_item(root, leaf, di)) {
|
|
|
+ ret = -EIO;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
|
|
|
- /* we are just looking for how big our buffer needs to be */
|
|
|
- if (!size)
|
|
|
- goto next;
|
|
|
+ total_size += name_len + 1;
|
|
|
+ /*
|
|
|
+ * We are just looking for how big our buffer needs to
|
|
|
+ * be.
|
|
|
+ */
|
|
|
+ if (!size)
|
|
|
+ goto next;
|
|
|
|
|
|
- if (!buffer || (name_len + 1) > size_left) {
|
|
|
- ret = -ERANGE;
|
|
|
- goto err;
|
|
|
- }
|
|
|
+ if (!buffer || (name_len + 1) > size_left) {
|
|
|
+ ret = -ERANGE;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
|
|
|
- name_ptr = (unsigned long)(di + 1);
|
|
|
- read_extent_buffer(leaf, buffer, name_ptr, name_len);
|
|
|
- buffer[name_len] = '\0';
|
|
|
+ read_extent_buffer(leaf, buffer, name_ptr, name_len);
|
|
|
+ buffer[name_len] = '\0';
|
|
|
|
|
|
- size_left -= name_len + 1;
|
|
|
- buffer += name_len + 1;
|
|
|
+ size_left -= name_len + 1;
|
|
|
+ buffer += name_len + 1;
|
|
|
next:
|
|
|
+ cur += this_len;
|
|
|
+ di = (struct btrfs_dir_item *)((char *)di + this_len);
|
|
|
+ }
|
|
|
+next_item:
|
|
|
path->slots[0]++;
|
|
|
}
|
|
|
ret = total_size;
|