diff options
Diffstat (limited to 'fs/hfsplus/xattr.c')
-rw-r--r-- | fs/hfsplus/xattr.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index bd8471fb9a6a..31f70f55a0f2 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -127,6 +127,69 @@ static int can_set_xattr(struct inode *inode, const char *name, return 0; } +#define SETOFFSET(buf, ndsiz, offset, rec) \ + (*(u16 *)((u8 *)(buf) + (ndsiz) + (-2 * (rec))) = (cpu_to_be16(offset))) + +static void hfsplus_init_header_node(struct inode *attr_file, + u32 clump_size, + char *buf, size_t node_size) +{ + struct hfs_bnode_desc *desc; + struct hfs_btree_header_rec *head; + u16 offset; + u32 hdr_node_map_rec_bits; + char *bmp; + u32 temp; + + hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %zu\n", + clump_size, node_size); + + desc = (struct hfs_bnode_desc *)buf; + desc->type = HFS_NODE_HEADER; + desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT); + offset = sizeof(struct hfs_bnode_desc); + SETOFFSET(buf, node_size, offset, 1); + + head = (struct hfs_btree_header_rec *)(buf + offset); + head->node_size = cpu_to_be16(node_size); + head->node_count = cpu_to_be32(i_size_read(attr_file) / node_size); + head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1); + head->clump_size = cpu_to_be32(clump_size); + head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS); + head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16)); + offset += sizeof(struct hfs_btree_header_rec); + SETOFFSET(buf, node_size, offset, 2); + + offset += HFSPLUS_BTREE_HDR_USER_BYTES; + SETOFFSET(buf, node_size, offset, 3); + + hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16))); + if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) { + u32 map_node_bits; + u32 map_nodes; + + desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1); + map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) - + (2 * sizeof(u16)) - 2); + map_nodes = (be32_to_cpu(head->node_count) - + hdr_node_map_rec_bits + + (map_node_bits - 1)) / map_node_bits; + be32_add_cpu(&head->free_nodes, 0 - map_nodes); + } + + bmp = buf + offset; + temp = be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes); + + /* Working a byte at a time is endian safe */ + while (temp >= 8) { + *bmp = 0xFF; temp -= 8; bmp++; + } + *bmp = ~(0xFF >> temp); + offset += hdr_node_map_rec_bits / 8; + + SETOFFSET(buf, node_size, offset, 4); +} + int __hfsplus_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags) { |