1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* 3 * linux/fs/hfsplus/xattr.c 3 * linux/fs/hfsplus/xattr.c 4 * 4 * 5 * Vyacheslav Dubeyko <slava@dubeyko.com> 5 * Vyacheslav Dubeyko <slava@dubeyko.com> 6 * 6 * 7 * Logic of processing extended attributes 7 * Logic of processing extended attributes 8 */ 8 */ 9 9 10 #include "hfsplus_fs.h" 10 #include "hfsplus_fs.h" >> 11 #include <linux/posix_acl_xattr.h> 11 #include <linux/nls.h> 12 #include <linux/nls.h> 12 #include "xattr.h" 13 #include "xattr.h" >> 14 #include "acl.h" 13 15 14 static int hfsplus_removexattr(struct inode *i 16 static int hfsplus_removexattr(struct inode *inode, const char *name); 15 17 16 const struct xattr_handler * const hfsplus_xat !! 18 const struct xattr_handler *hfsplus_xattr_handlers[] = { 17 &hfsplus_xattr_osx_handler, 19 &hfsplus_xattr_osx_handler, 18 &hfsplus_xattr_user_handler, 20 &hfsplus_xattr_user_handler, 19 &hfsplus_xattr_trusted_handler, 21 &hfsplus_xattr_trusted_handler, >> 22 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL >> 23 &posix_acl_access_xattr_handler, >> 24 &posix_acl_default_xattr_handler, >> 25 #endif 20 &hfsplus_xattr_security_handler, 26 &hfsplus_xattr_security_handler, 21 NULL 27 NULL 22 }; 28 }; 23 29 24 static int strcmp_xattr_finder_info(const char 30 static int strcmp_xattr_finder_info(const char *name) 25 { 31 { 26 if (name) { 32 if (name) { 27 return strncmp(name, HFSPLUS_X 33 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME, 28 sizeof(HFSPLUS 34 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME)); 29 } 35 } 30 return -1; 36 return -1; 31 } 37 } 32 38 33 static int strcmp_xattr_acl(const char *name) 39 static int strcmp_xattr_acl(const char *name) 34 { 40 { 35 if (name) { 41 if (name) { 36 return strncmp(name, HFSPLUS_X 42 return strncmp(name, HFSPLUS_XATTR_ACL_NAME, 37 sizeof(HFSPLUS 43 sizeof(HFSPLUS_XATTR_ACL_NAME)); 38 } 44 } 39 return -1; 45 return -1; 40 } 46 } 41 47 42 static bool is_known_namespace(const char *nam 48 static bool is_known_namespace(const char *name) 43 { 49 { 44 if (strncmp(name, XATTR_SYSTEM_PREFIX, 50 if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && 45 strncmp(name, XATTR_USER_PREFIX, X 51 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && 46 strncmp(name, XATTR_SECURITY_PREFI 52 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && 47 strncmp(name, XATTR_TRUSTED_PREFIX 53 strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) 48 return false; 54 return false; 49 55 50 return true; 56 return true; 51 } 57 } 52 58 53 static void hfsplus_init_header_node(struct in 59 static void hfsplus_init_header_node(struct inode *attr_file, 54 u32 cl 60 u32 clump_size, 55 char * 61 char *buf, u16 node_size) 56 { 62 { 57 struct hfs_bnode_desc *desc; 63 struct hfs_bnode_desc *desc; 58 struct hfs_btree_header_rec *head; 64 struct hfs_btree_header_rec *head; 59 u16 offset; 65 u16 offset; 60 __be16 *rec_offsets; 66 __be16 *rec_offsets; 61 u32 hdr_node_map_rec_bits; 67 u32 hdr_node_map_rec_bits; 62 char *bmp; 68 char *bmp; 63 u32 used_nodes; 69 u32 used_nodes; 64 u32 used_bmp_bytes; 70 u32 used_bmp_bytes; 65 u64 tmp; 71 u64 tmp; 66 72 67 hfs_dbg(ATTR_MOD, "init_hdr_attr_file: 73 hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n", 68 clump_size, node_size); 74 clump_size, node_size); 69 75 70 /* The end of the node contains list o 76 /* The end of the node contains list of record offsets */ 71 rec_offsets = (__be16 *)(buf + node_si 77 rec_offsets = (__be16 *)(buf + node_size); 72 78 73 desc = (struct hfs_bnode_desc *)buf; 79 desc = (struct hfs_bnode_desc *)buf; 74 desc->type = HFS_NODE_HEADER; 80 desc->type = HFS_NODE_HEADER; 75 desc->num_recs = cpu_to_be16(HFSPLUS_B 81 desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT); 76 offset = sizeof(struct hfs_bnode_desc) 82 offset = sizeof(struct hfs_bnode_desc); 77 *--rec_offsets = cpu_to_be16(offset); 83 *--rec_offsets = cpu_to_be16(offset); 78 84 79 head = (struct hfs_btree_header_rec *) 85 head = (struct hfs_btree_header_rec *)(buf + offset); 80 head->node_size = cpu_to_be16(node_siz 86 head->node_size = cpu_to_be16(node_size); 81 tmp = i_size_read(attr_file); 87 tmp = i_size_read(attr_file); 82 do_div(tmp, node_size); 88 do_div(tmp, node_size); 83 head->node_count = cpu_to_be32(tmp); 89 head->node_count = cpu_to_be32(tmp); 84 head->free_nodes = cpu_to_be32(be32_to 90 head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1); 85 head->clump_size = cpu_to_be32(clump_s 91 head->clump_size = cpu_to_be32(clump_size); 86 head->attributes |= cpu_to_be32(HFS_TR 92 head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS); 87 head->max_key_len = cpu_to_be16(HFSPLU 93 head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16)); 88 offset += sizeof(struct hfs_btree_head 94 offset += sizeof(struct hfs_btree_header_rec); 89 *--rec_offsets = cpu_to_be16(offset); 95 *--rec_offsets = cpu_to_be16(offset); 90 offset += HFSPLUS_BTREE_HDR_USER_BYTES 96 offset += HFSPLUS_BTREE_HDR_USER_BYTES; 91 *--rec_offsets = cpu_to_be16(offset); 97 *--rec_offsets = cpu_to_be16(offset); 92 98 93 hdr_node_map_rec_bits = 8 * (node_size 99 hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16))); 94 if (be32_to_cpu(head->node_count) > hd 100 if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) { 95 u32 map_node_bits; 101 u32 map_node_bits; 96 u32 map_nodes; 102 u32 map_nodes; 97 103 98 desc->next = cpu_to_be32(be32_ 104 desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1); 99 map_node_bits = 8 * (node_size 105 map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) - 100 (2 * s 106 (2 * sizeof(u16)) - 2); 101 map_nodes = (be32_to_cpu(head- 107 map_nodes = (be32_to_cpu(head->node_count) - 102 hdr_node_map_r 108 hdr_node_map_rec_bits + 103 (map_node_bits 109 (map_node_bits - 1)) / map_node_bits; 104 be32_add_cpu(&head->free_nodes 110 be32_add_cpu(&head->free_nodes, 0 - map_nodes); 105 } 111 } 106 112 107 bmp = buf + offset; 113 bmp = buf + offset; 108 used_nodes = 114 used_nodes = 109 be32_to_cpu(head->node_count) 115 be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes); 110 used_bmp_bytes = used_nodes / 8; 116 used_bmp_bytes = used_nodes / 8; 111 if (used_bmp_bytes) { 117 if (used_bmp_bytes) { 112 memset(bmp, 0xFF, used_bmp_byt 118 memset(bmp, 0xFF, used_bmp_bytes); 113 bmp += used_bmp_bytes; 119 bmp += used_bmp_bytes; 114 used_nodes %= 8; 120 used_nodes %= 8; 115 } 121 } 116 *bmp = ~(0xFF >> used_nodes); 122 *bmp = ~(0xFF >> used_nodes); 117 offset += hdr_node_map_rec_bits / 8; 123 offset += hdr_node_map_rec_bits / 8; 118 *--rec_offsets = cpu_to_be16(offset); 124 *--rec_offsets = cpu_to_be16(offset); 119 } 125 } 120 126 121 static int hfsplus_create_attributes_file(stru 127 static int hfsplus_create_attributes_file(struct super_block *sb) 122 { 128 { 123 int err = 0; 129 int err = 0; 124 struct hfsplus_sb_info *sbi = HFSPLUS_ 130 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 125 struct inode *attr_file; 131 struct inode *attr_file; 126 struct hfsplus_inode_info *hip; 132 struct hfsplus_inode_info *hip; 127 u32 clump_size; 133 u32 clump_size; 128 u16 node_size = HFSPLUS_ATTR_TREE_NODE 134 u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE; 129 char *buf; 135 char *buf; 130 int index, written; 136 int index, written; 131 struct address_space *mapping; 137 struct address_space *mapping; 132 struct page *page; 138 struct page *page; 133 int old_state = HFSPLUS_EMPTY_ATTR_TRE 139 int old_state = HFSPLUS_EMPTY_ATTR_TREE; 134 140 135 hfs_dbg(ATTR_MOD, "create_attr_file: i 141 hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID); 136 142 137 check_attr_tree_state_again: 143 check_attr_tree_state_again: 138 switch (atomic_read(&sbi->attr_tree_st 144 switch (atomic_read(&sbi->attr_tree_state)) { 139 case HFSPLUS_EMPTY_ATTR_TREE: 145 case HFSPLUS_EMPTY_ATTR_TREE: 140 if (old_state != atomic_cmpxch 146 if (old_state != atomic_cmpxchg(&sbi->attr_tree_state, 141 147 old_state, 142 148 HFSPLUS_CREATING_ATTR_TREE)) 143 goto check_attr_tree_s 149 goto check_attr_tree_state_again; 144 break; 150 break; 145 case HFSPLUS_CREATING_ATTR_TREE: 151 case HFSPLUS_CREATING_ATTR_TREE: 146 /* 152 /* 147 * This state means that anoth 153 * This state means that another thread is in process 148 * of AttributesFile creation. 154 * of AttributesFile creation. Theoretically, it is 149 * possible to be here. But re 155 * possible to be here. But really __setxattr() method 150 * first of all calls hfs_find 156 * first of all calls hfs_find_init() for lookup in 151 * B-tree of CatalogFile. This 157 * B-tree of CatalogFile. This method locks mutex of 152 * CatalogFile's B-tree. As a 158 * CatalogFile's B-tree. As a result, if some thread 153 * is inside AttributedFile cr 159 * is inside AttributedFile creation operation then 154 * another threads will be wai 160 * another threads will be waiting unlocking of 155 * CatalogFile's B-tree's mute 161 * CatalogFile's B-tree's mutex. However, if code will 156 * change then we will return 162 * change then we will return error code (-EAGAIN) from 157 * here. Really, it means that 163 * here. Really, it means that first try to set of xattr 158 * fails with error but second 164 * fails with error but second attempt will have success. 159 */ 165 */ 160 return -EAGAIN; 166 return -EAGAIN; 161 case HFSPLUS_VALID_ATTR_TREE: 167 case HFSPLUS_VALID_ATTR_TREE: 162 return 0; 168 return 0; 163 case HFSPLUS_FAILED_ATTR_TREE: 169 case HFSPLUS_FAILED_ATTR_TREE: 164 return -EOPNOTSUPP; 170 return -EOPNOTSUPP; 165 default: 171 default: 166 BUG(); 172 BUG(); 167 } 173 } 168 174 169 attr_file = hfsplus_iget(sb, HFSPLUS_A 175 attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID); 170 if (IS_ERR(attr_file)) { 176 if (IS_ERR(attr_file)) { 171 pr_err("failed to load attribu 177 pr_err("failed to load attributes file\n"); 172 return PTR_ERR(attr_file); 178 return PTR_ERR(attr_file); 173 } 179 } 174 180 175 BUG_ON(i_size_read(attr_file) != 0); 181 BUG_ON(i_size_read(attr_file) != 0); 176 182 177 hip = HFSPLUS_I(attr_file); 183 hip = HFSPLUS_I(attr_file); 178 184 179 clump_size = hfsplus_calc_btree_clump_ 185 clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize, 180 186 node_size, 181 187 sbi->sect_count, 182 188 HFSPLUS_ATTR_CNID); 183 189 184 mutex_lock(&hip->extents_lock); 190 mutex_lock(&hip->extents_lock); 185 hip->clump_blocks = clump_size >> sbi- 191 hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift; 186 mutex_unlock(&hip->extents_lock); 192 mutex_unlock(&hip->extents_lock); 187 193 188 if (sbi->free_blocks <= (hip->clump_bl 194 if (sbi->free_blocks <= (hip->clump_blocks << 1)) { 189 err = -ENOSPC; 195 err = -ENOSPC; 190 goto end_attr_file_creation; 196 goto end_attr_file_creation; 191 } 197 } 192 198 193 while (hip->alloc_blocks < hip->clump_ 199 while (hip->alloc_blocks < hip->clump_blocks) { 194 err = hfsplus_file_extend(attr 200 err = hfsplus_file_extend(attr_file, false); 195 if (unlikely(err)) { 201 if (unlikely(err)) { 196 pr_err("failed to exte 202 pr_err("failed to extend attributes file\n"); 197 goto end_attr_file_cre 203 goto end_attr_file_creation; 198 } 204 } 199 hip->phys_size = attr_file->i_ 205 hip->phys_size = attr_file->i_size = 200 (loff_t)hip->alloc_blo 206 (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift; 201 hip->fs_blocks = hip->alloc_bl 207 hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift; 202 inode_set_bytes(attr_file, att 208 inode_set_bytes(attr_file, attr_file->i_size); 203 } 209 } 204 210 205 buf = kzalloc(node_size, GFP_NOFS); 211 buf = kzalloc(node_size, GFP_NOFS); 206 if (!buf) { 212 if (!buf) { >> 213 pr_err("failed to allocate memory for header node\n"); 207 err = -ENOMEM; 214 err = -ENOMEM; 208 goto end_attr_file_creation; 215 goto end_attr_file_creation; 209 } 216 } 210 217 211 hfsplus_init_header_node(attr_file, cl 218 hfsplus_init_header_node(attr_file, clump_size, buf, node_size); 212 219 213 mapping = attr_file->i_mapping; 220 mapping = attr_file->i_mapping; 214 221 215 index = 0; 222 index = 0; 216 written = 0; 223 written = 0; 217 for (; written < node_size; index++, w 224 for (; written < node_size; index++, written += PAGE_SIZE) { 218 void *kaddr; 225 void *kaddr; 219 226 220 page = read_mapping_page(mappi 227 page = read_mapping_page(mapping, index, NULL); 221 if (IS_ERR(page)) { 228 if (IS_ERR(page)) { 222 err = PTR_ERR(page); 229 err = PTR_ERR(page); 223 goto failed_header_nod 230 goto failed_header_node_init; 224 } 231 } 225 232 226 kaddr = kmap_atomic(page); 233 kaddr = kmap_atomic(page); 227 memcpy(kaddr, buf + written, 234 memcpy(kaddr, buf + written, 228 min_t(size_t, PAGE_SIZ 235 min_t(size_t, PAGE_SIZE, node_size - written)); 229 kunmap_atomic(kaddr); 236 kunmap_atomic(kaddr); 230 237 231 set_page_dirty(page); 238 set_page_dirty(page); 232 put_page(page); 239 put_page(page); 233 } 240 } 234 241 235 hfsplus_mark_inode_dirty(attr_file, HF 242 hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY); 236 243 237 sbi->attr_tree = hfs_btree_open(sb, HF 244 sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); 238 if (!sbi->attr_tree) 245 if (!sbi->attr_tree) 239 pr_err("failed to load attribu 246 pr_err("failed to load attributes file\n"); 240 247 241 failed_header_node_init: 248 failed_header_node_init: 242 kfree(buf); 249 kfree(buf); 243 250 244 end_attr_file_creation: 251 end_attr_file_creation: 245 iput(attr_file); 252 iput(attr_file); 246 253 247 if (!err) 254 if (!err) 248 atomic_set(&sbi->attr_tree_sta 255 atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE); 249 else if (err == -ENOSPC) 256 else if (err == -ENOSPC) 250 atomic_set(&sbi->attr_tree_sta 257 atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE); 251 else 258 else 252 atomic_set(&sbi->attr_tree_sta 259 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE); 253 260 254 return err; 261 return err; 255 } 262 } 256 263 257 int __hfsplus_setxattr(struct inode *inode, co 264 int __hfsplus_setxattr(struct inode *inode, const char *name, 258 const void *value, siz 265 const void *value, size_t size, int flags) 259 { 266 { 260 int err; !! 267 int err = 0; 261 struct hfs_find_data cat_fd; 268 struct hfs_find_data cat_fd; 262 hfsplus_cat_entry entry; 269 hfsplus_cat_entry entry; 263 u16 cat_entry_flags, cat_entry_type; 270 u16 cat_entry_flags, cat_entry_type; 264 u16 folder_finderinfo_len = sizeof(str 271 u16 folder_finderinfo_len = sizeof(struct DInfo) + 265 sizeof 272 sizeof(struct DXInfo); 266 u16 file_finderinfo_len = sizeof(struc 273 u16 file_finderinfo_len = sizeof(struct FInfo) + 267 sizeof 274 sizeof(struct FXInfo); 268 275 269 if ((!S_ISREG(inode->i_mode) && 276 if ((!S_ISREG(inode->i_mode) && 270 !S_ISDIR(inode->i_mode 277 !S_ISDIR(inode->i_mode)) || 271 HFSPLUS_IS_RSR 278 HFSPLUS_IS_RSRC(inode)) 272 return -EOPNOTSUPP; 279 return -EOPNOTSUPP; 273 280 274 if (value == NULL) 281 if (value == NULL) 275 return hfsplus_removexattr(ino 282 return hfsplus_removexattr(inode, name); 276 283 277 err = hfs_find_init(HFSPLUS_SB(inode-> 284 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 278 if (err) { 285 if (err) { 279 pr_err("can't init xattr find 286 pr_err("can't init xattr find struct\n"); 280 return err; 287 return err; 281 } 288 } 282 289 283 err = hfsplus_find_cat(inode->i_sb, in 290 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 284 if (err) { 291 if (err) { 285 pr_err("catalog searching fail 292 pr_err("catalog searching failed\n"); 286 goto end_setxattr; 293 goto end_setxattr; 287 } 294 } 288 295 289 if (!strcmp_xattr_finder_info(name)) { 296 if (!strcmp_xattr_finder_info(name)) { 290 if (flags & XATTR_CREATE) { 297 if (flags & XATTR_CREATE) { 291 pr_err("xattr exists y 298 pr_err("xattr exists yet\n"); 292 err = -EOPNOTSUPP; 299 err = -EOPNOTSUPP; 293 goto end_setxattr; 300 goto end_setxattr; 294 } 301 } 295 hfs_bnode_read(cat_fd.bnode, & 302 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, 296 sizeof 303 sizeof(hfsplus_cat_entry)); 297 if (be16_to_cpu(entry.type) == 304 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { 298 if (size == folder_fin 305 if (size == folder_finderinfo_len) { 299 memcpy(&entry. !! 306 memcpy(&entry.folder.user_info, value, 300 307 folder_finderinfo_len); 301 hfs_bnode_writ 308 hfs_bnode_write(cat_fd.bnode, &entry, 302 cat_fd 309 cat_fd.entryoffset, 303 sizeof 310 sizeof(struct hfsplus_cat_folder)); 304 hfsplus_mark_i 311 hfsplus_mark_inode_dirty(inode, 305 312 HFSPLUS_I_CAT_DIRTY); 306 } else { 313 } else { 307 err = -ERANGE; 314 err = -ERANGE; 308 goto end_setxa 315 goto end_setxattr; 309 } 316 } 310 } else if (be16_to_cpu(entry.t 317 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { 311 if (size == file_finde 318 if (size == file_finderinfo_len) { 312 memcpy(&entry. !! 319 memcpy(&entry.file.user_info, value, 313 320 file_finderinfo_len); 314 hfs_bnode_writ 321 hfs_bnode_write(cat_fd.bnode, &entry, 315 cat_fd 322 cat_fd.entryoffset, 316 sizeof 323 sizeof(struct hfsplus_cat_file)); 317 hfsplus_mark_i 324 hfsplus_mark_inode_dirty(inode, 318 325 HFSPLUS_I_CAT_DIRTY); 319 } else { 326 } else { 320 err = -ERANGE; 327 err = -ERANGE; 321 goto end_setxa 328 goto end_setxattr; 322 } 329 } 323 } else { 330 } else { 324 err = -EOPNOTSUPP; 331 err = -EOPNOTSUPP; 325 goto end_setxattr; 332 goto end_setxattr; 326 } 333 } 327 goto end_setxattr; 334 goto end_setxattr; 328 } 335 } 329 336 330 if (!HFSPLUS_SB(inode->i_sb)->attr_tre 337 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { 331 err = hfsplus_create_attribute 338 err = hfsplus_create_attributes_file(inode->i_sb); 332 if (unlikely(err)) 339 if (unlikely(err)) 333 goto end_setxattr; 340 goto end_setxattr; 334 } 341 } 335 342 336 if (hfsplus_attr_exists(inode, name)) 343 if (hfsplus_attr_exists(inode, name)) { 337 if (flags & XATTR_CREATE) { 344 if (flags & XATTR_CREATE) { 338 pr_err("xattr exists y 345 pr_err("xattr exists yet\n"); 339 err = -EOPNOTSUPP; 346 err = -EOPNOTSUPP; 340 goto end_setxattr; 347 goto end_setxattr; 341 } 348 } 342 err = hfsplus_delete_attr(inod 349 err = hfsplus_delete_attr(inode, name); 343 if (err) 350 if (err) 344 goto end_setxattr; 351 goto end_setxattr; 345 err = hfsplus_create_attr(inod 352 err = hfsplus_create_attr(inode, name, value, size); 346 if (err) 353 if (err) 347 goto end_setxattr; 354 goto end_setxattr; 348 } else { 355 } else { 349 if (flags & XATTR_REPLACE) { 356 if (flags & XATTR_REPLACE) { 350 pr_err("cannot replace 357 pr_err("cannot replace xattr\n"); 351 err = -EOPNOTSUPP; 358 err = -EOPNOTSUPP; 352 goto end_setxattr; 359 goto end_setxattr; 353 } 360 } 354 err = hfsplus_create_attr(inod 361 err = hfsplus_create_attr(inode, name, value, size); 355 if (err) 362 if (err) 356 goto end_setxattr; 363 goto end_setxattr; 357 } 364 } 358 365 359 cat_entry_type = hfs_bnode_read_u16(ca 366 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 360 if (cat_entry_type == HFSPLUS_FOLDER) 367 if (cat_entry_type == HFSPLUS_FOLDER) { 361 cat_entry_flags = hfs_bnode_re 368 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 362 cat_fd.ent 369 cat_fd.entryoffset + 363 offsetof(s 370 offsetof(struct hfsplus_cat_folder, flags)); 364 cat_entry_flags |= HFSPLUS_XAT 371 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 365 if (!strcmp_xattr_acl(name)) 372 if (!strcmp_xattr_acl(name)) 366 cat_entry_flags |= HFS 373 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 367 hfs_bnode_write_u16(cat_fd.bno 374 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 368 offsetof(struc 375 offsetof(struct hfsplus_cat_folder, flags), 369 cat_entry_flag 376 cat_entry_flags); 370 hfsplus_mark_inode_dirty(inode 377 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 371 } else if (cat_entry_type == HFSPLUS_F 378 } else if (cat_entry_type == HFSPLUS_FILE) { 372 cat_entry_flags = hfs_bnode_re 379 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 373 cat_fd.ent 380 cat_fd.entryoffset + 374 offsetof(s 381 offsetof(struct hfsplus_cat_file, flags)); 375 cat_entry_flags |= HFSPLUS_XAT 382 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 376 if (!strcmp_xattr_acl(name)) 383 if (!strcmp_xattr_acl(name)) 377 cat_entry_flags |= HFS 384 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 378 hfs_bnode_write_u16(cat_fd.bno 385 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 379 offsetof(s 386 offsetof(struct hfsplus_cat_file, flags), 380 cat_entry_ 387 cat_entry_flags); 381 hfsplus_mark_inode_dirty(inode 388 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 382 } else { 389 } else { 383 pr_err("invalid catalog entry 390 pr_err("invalid catalog entry type\n"); 384 err = -EIO; 391 err = -EIO; 385 goto end_setxattr; 392 goto end_setxattr; 386 } 393 } 387 394 388 end_setxattr: 395 end_setxattr: 389 hfs_find_exit(&cat_fd); 396 hfs_find_exit(&cat_fd); 390 return err; 397 return err; 391 } 398 } 392 399 393 static int name_len(const char *xattr_name, in 400 static int name_len(const char *xattr_name, int xattr_name_len) 394 { 401 { 395 int len = xattr_name_len + 1; 402 int len = xattr_name_len + 1; 396 403 397 if (!is_known_namespace(xattr_name)) 404 if (!is_known_namespace(xattr_name)) 398 len += XATTR_MAC_OSX_PREFIX_LE 405 len += XATTR_MAC_OSX_PREFIX_LEN; 399 406 400 return len; 407 return len; 401 } 408 } 402 409 403 static ssize_t copy_name(char *buffer, const c !! 410 static int copy_name(char *buffer, const char *xattr_name, int name_len) 404 { 411 { 405 ssize_t len; !! 412 int len = name_len; >> 413 int offset = 0; 406 414 407 if (!is_known_namespace(xattr_name)) !! 415 if (!is_known_namespace(xattr_name)) { 408 len = scnprintf(buffer, name_l !! 416 strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN); 409 "%s%s", XATTR !! 417 offset += XATTR_MAC_OSX_PREFIX_LEN; 410 else !! 418 len += XATTR_MAC_OSX_PREFIX_LEN; 411 len = strscpy(buffer, xattr_na !! 419 } >> 420 >> 421 strncpy(buffer + offset, xattr_name, name_len); >> 422 memset(buffer + offset + name_len, 0, 1); >> 423 len += 1; 412 424 413 /* include NUL-byte in length for non- << 414 if (len >= 0) << 415 len++; << 416 return len; 425 return len; 417 } 426 } 418 427 419 int hfsplus_setxattr(struct inode *inode, cons 428 int hfsplus_setxattr(struct inode *inode, const char *name, 420 const void *value, size_t 429 const void *value, size_t size, int flags, 421 const char *prefix, size_ 430 const char *prefix, size_t prefixlen) 422 { 431 { 423 char *xattr_name; 432 char *xattr_name; 424 int res; 433 int res; 425 434 426 xattr_name = kmalloc(NLS_MAX_CHARSET_S 435 xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, 427 GFP_KERNEL); 436 GFP_KERNEL); 428 if (!xattr_name) 437 if (!xattr_name) 429 return -ENOMEM; 438 return -ENOMEM; 430 strcpy(xattr_name, prefix); 439 strcpy(xattr_name, prefix); 431 strcpy(xattr_name + prefixlen, name); 440 strcpy(xattr_name + prefixlen, name); 432 res = __hfsplus_setxattr(inode, xattr_ 441 res = __hfsplus_setxattr(inode, xattr_name, value, size, flags); 433 kfree(xattr_name); 442 kfree(xattr_name); 434 return res; 443 return res; 435 } 444 } 436 445 437 static ssize_t hfsplus_getxattr_finder_info(st 446 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode, 438 447 void *value, size_t size) 439 { 448 { 440 ssize_t res = 0; 449 ssize_t res = 0; 441 struct hfs_find_data fd; 450 struct hfs_find_data fd; 442 u16 entry_type; 451 u16 entry_type; 443 u16 folder_rec_len = sizeof(struct DIn 452 u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo); 444 u16 file_rec_len = sizeof(struct FInfo 453 u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo); 445 u16 record_len = max(folder_rec_len, f 454 u16 record_len = max(folder_rec_len, file_rec_len); 446 u8 folder_finder_info[sizeof(struct DI 455 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 447 u8 file_finder_info[sizeof(struct FInf 456 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 448 457 449 if (size >= record_len) { 458 if (size >= record_len) { 450 res = hfs_find_init(HFSPLUS_SB 459 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 451 if (res) { 460 if (res) { 452 pr_err("can't init xat 461 pr_err("can't init xattr find struct\n"); 453 return res; 462 return res; 454 } 463 } 455 res = hfsplus_find_cat(inode-> 464 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 456 if (res) 465 if (res) 457 goto end_getxattr_find 466 goto end_getxattr_finder_info; 458 entry_type = hfs_bnode_read_u1 467 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 459 468 460 if (entry_type == HFSPLUS_FOLD 469 if (entry_type == HFSPLUS_FOLDER) { 461 hfs_bnode_read(fd.bnod 470 hfs_bnode_read(fd.bnode, folder_finder_info, 462 fd.entryoffset 471 fd.entryoffset + 463 offsetof(struc 472 offsetof(struct hfsplus_cat_folder, user_info), 464 folder_rec_len 473 folder_rec_len); 465 memcpy(value, folder_f 474 memcpy(value, folder_finder_info, folder_rec_len); 466 res = folder_rec_len; 475 res = folder_rec_len; 467 } else if (entry_type == HFSPL 476 } else if (entry_type == HFSPLUS_FILE) { 468 hfs_bnode_read(fd.bnod 477 hfs_bnode_read(fd.bnode, file_finder_info, 469 fd.entryoffset 478 fd.entryoffset + 470 offsetof(struc 479 offsetof(struct hfsplus_cat_file, user_info), 471 file_rec_len); 480 file_rec_len); 472 memcpy(value, file_fin 481 memcpy(value, file_finder_info, file_rec_len); 473 res = file_rec_len; 482 res = file_rec_len; 474 } else { 483 } else { 475 res = -EOPNOTSUPP; 484 res = -EOPNOTSUPP; 476 goto end_getxattr_find 485 goto end_getxattr_finder_info; 477 } 486 } 478 } else 487 } else 479 res = size ? -ERANGE : record_ 488 res = size ? -ERANGE : record_len; 480 489 481 end_getxattr_finder_info: 490 end_getxattr_finder_info: 482 if (size >= record_len) 491 if (size >= record_len) 483 hfs_find_exit(&fd); 492 hfs_find_exit(&fd); 484 return res; 493 return res; 485 } 494 } 486 495 487 ssize_t __hfsplus_getxattr(struct inode *inode 496 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, 488 void *value, size_t s 497 void *value, size_t size) 489 { 498 { 490 struct hfs_find_data fd; 499 struct hfs_find_data fd; 491 hfsplus_attr_entry *entry; 500 hfsplus_attr_entry *entry; 492 __be32 xattr_record_type; 501 __be32 xattr_record_type; 493 u32 record_type; 502 u32 record_type; 494 u16 record_length = 0; 503 u16 record_length = 0; 495 ssize_t res; !! 504 ssize_t res = 0; 496 505 497 if ((!S_ISREG(inode->i_mode) && 506 if ((!S_ISREG(inode->i_mode) && 498 !S_ISDIR(inode->i_mode 507 !S_ISDIR(inode->i_mode)) || 499 HFSPLUS_IS_RSR 508 HFSPLUS_IS_RSRC(inode)) 500 return -EOPNOTSUPP; 509 return -EOPNOTSUPP; 501 510 502 if (!strcmp_xattr_finder_info(name)) 511 if (!strcmp_xattr_finder_info(name)) 503 return hfsplus_getxattr_finder 512 return hfsplus_getxattr_finder_info(inode, value, size); 504 513 505 if (!HFSPLUS_SB(inode->i_sb)->attr_tre 514 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 506 return -EOPNOTSUPP; 515 return -EOPNOTSUPP; 507 516 508 entry = hfsplus_alloc_attr_entry(); 517 entry = hfsplus_alloc_attr_entry(); 509 if (!entry) { 518 if (!entry) { 510 pr_err("can't allocate xattr e 519 pr_err("can't allocate xattr entry\n"); 511 return -ENOMEM; 520 return -ENOMEM; 512 } 521 } 513 522 514 res = hfs_find_init(HFSPLUS_SB(inode-> 523 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 515 if (res) { 524 if (res) { 516 pr_err("can't init xattr find 525 pr_err("can't init xattr find struct\n"); 517 goto failed_getxattr_init; 526 goto failed_getxattr_init; 518 } 527 } 519 528 520 res = hfsplus_find_attr(inode->i_sb, i 529 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); 521 if (res) { 530 if (res) { 522 if (res == -ENOENT) 531 if (res == -ENOENT) 523 res = -ENODATA; 532 res = -ENODATA; 524 else 533 else 525 pr_err("xattr searchin 534 pr_err("xattr searching failed\n"); 526 goto out; 535 goto out; 527 } 536 } 528 537 529 hfs_bnode_read(fd.bnode, &xattr_record 538 hfs_bnode_read(fd.bnode, &xattr_record_type, 530 fd.entryoffset, sizeof 539 fd.entryoffset, sizeof(xattr_record_type)); 531 record_type = be32_to_cpu(xattr_record 540 record_type = be32_to_cpu(xattr_record_type); 532 if (record_type == HFSPLUS_ATTR_INLINE 541 if (record_type == HFSPLUS_ATTR_INLINE_DATA) { 533 record_length = hfs_bnode_read 542 record_length = hfs_bnode_read_u16(fd.bnode, 534 fd.entryoffset 543 fd.entryoffset + 535 offsetof(struc 544 offsetof(struct hfsplus_attr_inline_data, 536 length)); 545 length)); 537 if (record_length > HFSPLUS_MA 546 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) { 538 pr_err("invalid xattr 547 pr_err("invalid xattr record size\n"); 539 res = -EIO; 548 res = -EIO; 540 goto out; 549 goto out; 541 } 550 } 542 } else if (record_type == HFSPLUS_ATTR 551 } else if (record_type == HFSPLUS_ATTR_FORK_DATA || 543 record_type == HFSPLUS 552 record_type == HFSPLUS_ATTR_EXTENTS) { 544 pr_err("only inline data xattr 553 pr_err("only inline data xattr are supported\n"); 545 res = -EOPNOTSUPP; 554 res = -EOPNOTSUPP; 546 goto out; 555 goto out; 547 } else { 556 } else { 548 pr_err("invalid xattr record\n 557 pr_err("invalid xattr record\n"); 549 res = -EIO; 558 res = -EIO; 550 goto out; 559 goto out; 551 } 560 } 552 561 553 if (size) { 562 if (size) { 554 hfs_bnode_read(fd.bnode, entry 563 hfs_bnode_read(fd.bnode, entry, fd.entryoffset, 555 offsetof(struc 564 offsetof(struct hfsplus_attr_inline_data, 556 raw_by 565 raw_bytes) + record_length); 557 } 566 } 558 567 559 if (size >= record_length) { 568 if (size >= record_length) { 560 memcpy(value, entry->inline_da 569 memcpy(value, entry->inline_data.raw_bytes, record_length); 561 res = record_length; 570 res = record_length; 562 } else 571 } else 563 res = size ? -ERANGE : record_ 572 res = size ? -ERANGE : record_length; 564 573 565 out: 574 out: 566 hfs_find_exit(&fd); 575 hfs_find_exit(&fd); 567 576 568 failed_getxattr_init: 577 failed_getxattr_init: 569 hfsplus_destroy_attr_entry(entry); 578 hfsplus_destroy_attr_entry(entry); 570 return res; 579 return res; 571 } 580 } 572 581 573 ssize_t hfsplus_getxattr(struct inode *inode, 582 ssize_t hfsplus_getxattr(struct inode *inode, const char *name, 574 void *value, size_t s 583 void *value, size_t size, 575 const char *prefix, s 584 const char *prefix, size_t prefixlen) 576 { 585 { 577 int res; 586 int res; 578 char *xattr_name; 587 char *xattr_name; 579 588 580 xattr_name = kmalloc(NLS_MAX_CHARSET_S 589 xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, 581 GFP_KERNEL); 590 GFP_KERNEL); 582 if (!xattr_name) 591 if (!xattr_name) 583 return -ENOMEM; 592 return -ENOMEM; 584 593 585 strcpy(xattr_name, prefix); 594 strcpy(xattr_name, prefix); 586 strcpy(xattr_name + prefixlen, name); 595 strcpy(xattr_name + prefixlen, name); 587 596 588 res = __hfsplus_getxattr(inode, xattr_ 597 res = __hfsplus_getxattr(inode, xattr_name, value, size); 589 kfree(xattr_name); 598 kfree(xattr_name); 590 return res; 599 return res; 591 600 592 } 601 } 593 602 594 static inline int can_list(const char *xattr_n 603 static inline int can_list(const char *xattr_name) 595 { 604 { 596 if (!xattr_name) 605 if (!xattr_name) 597 return 0; 606 return 0; 598 607 599 return strncmp(xattr_name, XATTR_TRUST 608 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX, 600 XATTR_TRUSTED_PREFIX_L 609 XATTR_TRUSTED_PREFIX_LEN) || 601 capable(CAP_SY 610 capable(CAP_SYS_ADMIN); 602 } 611 } 603 612 604 static ssize_t hfsplus_listxattr_finder_info(s 613 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, 605 614 char *buffer, size_t size) 606 { 615 { 607 ssize_t res; !! 616 ssize_t res = 0; 608 struct inode *inode = d_inode(dentry); 617 struct inode *inode = d_inode(dentry); 609 struct hfs_find_data fd; 618 struct hfs_find_data fd; 610 u16 entry_type; 619 u16 entry_type; 611 u8 folder_finder_info[sizeof(struct DI 620 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 612 u8 file_finder_info[sizeof(struct FInf 621 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 613 unsigned long len, found_bit; 622 unsigned long len, found_bit; 614 int xattr_name_len, symbols_count; 623 int xattr_name_len, symbols_count; 615 624 616 res = hfs_find_init(HFSPLUS_SB(inode-> 625 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 617 if (res) { 626 if (res) { 618 pr_err("can't init xattr find 627 pr_err("can't init xattr find struct\n"); 619 return res; 628 return res; 620 } 629 } 621 630 622 res = hfsplus_find_cat(inode->i_sb, in 631 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 623 if (res) 632 if (res) 624 goto end_listxattr_finder_info 633 goto end_listxattr_finder_info; 625 634 626 entry_type = hfs_bnode_read_u16(fd.bno 635 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 627 if (entry_type == HFSPLUS_FOLDER) { 636 if (entry_type == HFSPLUS_FOLDER) { 628 len = sizeof(struct DInfo) + s 637 len = sizeof(struct DInfo) + sizeof(struct DXInfo); 629 hfs_bnode_read(fd.bnode, folde 638 hfs_bnode_read(fd.bnode, folder_finder_info, 630 fd.entryoffset 639 fd.entryoffset + 631 offsetof(struc 640 offsetof(struct hfsplus_cat_folder, user_info), 632 len); 641 len); 633 found_bit = find_first_bit((vo 642 found_bit = find_first_bit((void *)folder_finder_info, len*8); 634 } else if (entry_type == HFSPLUS_FILE) 643 } else if (entry_type == HFSPLUS_FILE) { 635 len = sizeof(struct FInfo) + s 644 len = sizeof(struct FInfo) + sizeof(struct FXInfo); 636 hfs_bnode_read(fd.bnode, file_ 645 hfs_bnode_read(fd.bnode, file_finder_info, 637 fd.entryoffset 646 fd.entryoffset + 638 offsetof(struc 647 offsetof(struct hfsplus_cat_file, user_info), 639 len); 648 len); 640 found_bit = find_first_bit((vo 649 found_bit = find_first_bit((void *)file_finder_info, len*8); 641 } else { 650 } else { 642 res = -EOPNOTSUPP; 651 res = -EOPNOTSUPP; 643 goto end_listxattr_finder_info 652 goto end_listxattr_finder_info; 644 } 653 } 645 654 646 if (found_bit >= (len*8)) 655 if (found_bit >= (len*8)) 647 res = 0; 656 res = 0; 648 else { 657 else { 649 symbols_count = sizeof(HFSPLUS 658 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1; 650 xattr_name_len = 659 xattr_name_len = 651 name_len(HFSPLUS_XATTR 660 name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count); 652 if (!buffer || !size) { 661 if (!buffer || !size) { 653 if (can_list(HFSPLUS_X 662 if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) 654 res = xattr_na 663 res = xattr_name_len; 655 } else if (can_list(HFSPLUS_XA 664 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) { 656 if (size < xattr_name_ 665 if (size < xattr_name_len) 657 res = -ERANGE; 666 res = -ERANGE; 658 else { 667 else { 659 res = copy_nam 668 res = copy_name(buffer, 660 669 HFSPLUS_XATTR_FINDER_INFO_NAME, 661 670 symbols_count); 662 } 671 } 663 } 672 } 664 } 673 } 665 674 666 end_listxattr_finder_info: 675 end_listxattr_finder_info: 667 hfs_find_exit(&fd); 676 hfs_find_exit(&fd); 668 677 669 return res; 678 return res; 670 } 679 } 671 680 672 ssize_t hfsplus_listxattr(struct dentry *dentr 681 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 673 { 682 { 674 ssize_t err; 683 ssize_t err; 675 ssize_t res; !! 684 ssize_t res = 0; 676 struct inode *inode = d_inode(dentry); 685 struct inode *inode = d_inode(dentry); 677 struct hfs_find_data fd; 686 struct hfs_find_data fd; >> 687 u16 key_len = 0; 678 struct hfsplus_attr_key attr_key; 688 struct hfsplus_attr_key attr_key; 679 char *strbuf; 689 char *strbuf; 680 int xattr_name_len; 690 int xattr_name_len; 681 691 682 if ((!S_ISREG(inode->i_mode) && 692 if ((!S_ISREG(inode->i_mode) && 683 !S_ISDIR(inode->i_mode 693 !S_ISDIR(inode->i_mode)) || 684 HFSPLUS_IS_RSR 694 HFSPLUS_IS_RSRC(inode)) 685 return -EOPNOTSUPP; 695 return -EOPNOTSUPP; 686 696 687 res = hfsplus_listxattr_finder_info(de 697 res = hfsplus_listxattr_finder_info(dentry, buffer, size); 688 if (res < 0) 698 if (res < 0) 689 return res; 699 return res; 690 else if (!HFSPLUS_SB(inode->i_sb)->att 700 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 691 return (res == 0) ? -EOPNOTSUP 701 return (res == 0) ? -EOPNOTSUPP : res; 692 702 693 err = hfs_find_init(HFSPLUS_SB(inode-> 703 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 694 if (err) { 704 if (err) { 695 pr_err("can't init xattr find 705 pr_err("can't init xattr find struct\n"); 696 return err; 706 return err; 697 } 707 } 698 708 699 strbuf = kzalloc(NLS_MAX_CHARSET_SIZE !! 709 strbuf = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 700 XATTR_MAC_OSX_PREFIX_L 710 XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL); 701 if (!strbuf) { 711 if (!strbuf) { 702 res = -ENOMEM; 712 res = -ENOMEM; 703 goto out; 713 goto out; 704 } 714 } 705 715 706 err = hfsplus_find_attr(inode->i_sb, i 716 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); 707 if (err) { 717 if (err) { 708 if (err == -ENOENT) { 718 if (err == -ENOENT) { 709 if (res == 0) 719 if (res == 0) 710 res = -ENODATA 720 res = -ENODATA; 711 goto end_listxattr; 721 goto end_listxattr; 712 } else { 722 } else { 713 res = err; 723 res = err; 714 goto end_listxattr; 724 goto end_listxattr; 715 } 725 } 716 } 726 } 717 727 718 for (;;) { 728 for (;;) { 719 u16 key_len = hfs_bnode_read_u !! 729 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset); 720 << 721 if (key_len == 0 || key_len > 730 if (key_len == 0 || key_len > fd.tree->max_key_len) { 722 pr_err("invalid xattr 731 pr_err("invalid xattr key length: %d\n", key_len); 723 res = -EIO; 732 res = -EIO; 724 goto end_listxattr; 733 goto end_listxattr; 725 } 734 } 726 735 727 hfs_bnode_read(fd.bnode, &attr 736 hfs_bnode_read(fd.bnode, &attr_key, 728 fd.keyoffset, 737 fd.keyoffset, key_len + sizeof(key_len)); 729 738 730 if (be32_to_cpu(attr_key.cnid) 739 if (be32_to_cpu(attr_key.cnid) != inode->i_ino) 731 goto end_listxattr; 740 goto end_listxattr; 732 741 733 xattr_name_len = NLS_MAX_CHARS 742 xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN; 734 if (hfsplus_uni2asc(inode->i_s 743 if (hfsplus_uni2asc(inode->i_sb, 735 (const struct hfsplus_ 744 (const struct hfsplus_unistr *)&fd.key->attr.key_name, 736 strbuf 745 strbuf, &xattr_name_len)) { 737 pr_err("unicode conver 746 pr_err("unicode conversion failed\n"); 738 res = -EIO; 747 res = -EIO; 739 goto end_listxattr; 748 goto end_listxattr; 740 } 749 } 741 750 742 if (!buffer || !size) { 751 if (!buffer || !size) { 743 if (can_list(strbuf)) 752 if (can_list(strbuf)) 744 res += name_le 753 res += name_len(strbuf, xattr_name_len); 745 } else if (can_list(strbuf)) { 754 } else if (can_list(strbuf)) { 746 if (size < (res + name 755 if (size < (res + name_len(strbuf, xattr_name_len))) { 747 res = -ERANGE; 756 res = -ERANGE; 748 goto end_listx 757 goto end_listxattr; 749 } else 758 } else 750 res += copy_na 759 res += copy_name(buffer + res, 751 760 strbuf, xattr_name_len); 752 } 761 } 753 762 754 if (hfs_brec_goto(&fd, 1)) 763 if (hfs_brec_goto(&fd, 1)) 755 goto end_listxattr; 764 goto end_listxattr; 756 } 765 } 757 766 758 end_listxattr: 767 end_listxattr: 759 kfree(strbuf); 768 kfree(strbuf); 760 out: 769 out: 761 hfs_find_exit(&fd); 770 hfs_find_exit(&fd); 762 return res; 771 return res; 763 } 772 } 764 773 765 static int hfsplus_removexattr(struct inode *i 774 static int hfsplus_removexattr(struct inode *inode, const char *name) 766 { 775 { 767 int err; !! 776 int err = 0; 768 struct hfs_find_data cat_fd; 777 struct hfs_find_data cat_fd; 769 u16 flags; 778 u16 flags; 770 u16 cat_entry_type; 779 u16 cat_entry_type; 771 int is_xattr_acl_deleted; !! 780 int is_xattr_acl_deleted = 0; 772 int is_all_xattrs_deleted; !! 781 int is_all_xattrs_deleted = 0; 773 782 774 if (!HFSPLUS_SB(inode->i_sb)->attr_tre 783 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 775 return -EOPNOTSUPP; 784 return -EOPNOTSUPP; 776 785 777 if (!strcmp_xattr_finder_info(name)) 786 if (!strcmp_xattr_finder_info(name)) 778 return -EOPNOTSUPP; 787 return -EOPNOTSUPP; 779 788 780 err = hfs_find_init(HFSPLUS_SB(inode-> 789 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 781 if (err) { 790 if (err) { 782 pr_err("can't init xattr find 791 pr_err("can't init xattr find struct\n"); 783 return err; 792 return err; 784 } 793 } 785 794 786 err = hfsplus_find_cat(inode->i_sb, in 795 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 787 if (err) { 796 if (err) { 788 pr_err("catalog searching fail 797 pr_err("catalog searching failed\n"); 789 goto end_removexattr; 798 goto end_removexattr; 790 } 799 } 791 800 792 err = hfsplus_delete_attr(inode, name) 801 err = hfsplus_delete_attr(inode, name); 793 if (err) 802 if (err) 794 goto end_removexattr; 803 goto end_removexattr; 795 804 796 is_xattr_acl_deleted = !strcmp_xattr_a 805 is_xattr_acl_deleted = !strcmp_xattr_acl(name); 797 is_all_xattrs_deleted = !hfsplus_attr_ 806 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL); 798 807 799 if (!is_xattr_acl_deleted && !is_all_x 808 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted) 800 goto end_removexattr; 809 goto end_removexattr; 801 810 802 cat_entry_type = hfs_bnode_read_u16(ca 811 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 803 812 804 if (cat_entry_type == HFSPLUS_FOLDER) 813 if (cat_entry_type == HFSPLUS_FOLDER) { 805 flags = hfs_bnode_read_u16(cat 814 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 806 offsetof(struc 815 offsetof(struct hfsplus_cat_folder, flags)); 807 if (is_xattr_acl_deleted) 816 if (is_xattr_acl_deleted) 808 flags &= ~HFSPLUS_ACL_ 817 flags &= ~HFSPLUS_ACL_EXISTS; 809 if (is_all_xattrs_deleted) 818 if (is_all_xattrs_deleted) 810 flags &= ~HFSPLUS_XATT 819 flags &= ~HFSPLUS_XATTR_EXISTS; 811 hfs_bnode_write_u16(cat_fd.bno 820 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 812 offsetof(struc 821 offsetof(struct hfsplus_cat_folder, flags), 813 flags); 822 flags); 814 hfsplus_mark_inode_dirty(inode 823 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 815 } else if (cat_entry_type == HFSPLUS_F 824 } else if (cat_entry_type == HFSPLUS_FILE) { 816 flags = hfs_bnode_read_u16(cat 825 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 817 offsetof(struc 826 offsetof(struct hfsplus_cat_file, flags)); 818 if (is_xattr_acl_deleted) 827 if (is_xattr_acl_deleted) 819 flags &= ~HFSPLUS_ACL_ 828 flags &= ~HFSPLUS_ACL_EXISTS; 820 if (is_all_xattrs_deleted) 829 if (is_all_xattrs_deleted) 821 flags &= ~HFSPLUS_XATT 830 flags &= ~HFSPLUS_XATTR_EXISTS; 822 hfs_bnode_write_u16(cat_fd.bno 831 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 823 offsetof(struc 832 offsetof(struct hfsplus_cat_file, flags), 824 flags); 833 flags); 825 hfsplus_mark_inode_dirty(inode 834 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 826 } else { 835 } else { 827 pr_err("invalid catalog entry 836 pr_err("invalid catalog entry type\n"); 828 err = -EIO; 837 err = -EIO; 829 goto end_removexattr; 838 goto end_removexattr; 830 } 839 } 831 840 832 end_removexattr: 841 end_removexattr: 833 hfs_find_exit(&cat_fd); 842 hfs_find_exit(&cat_fd); 834 return err; 843 return err; 835 } 844 } 836 845 837 static int hfsplus_osx_getxattr(const struct x 846 static int hfsplus_osx_getxattr(const struct xattr_handler *handler, 838 struct dentry 847 struct dentry *unused, struct inode *inode, 839 const char *na 848 const char *name, void *buffer, size_t size) 840 { 849 { 841 /* 850 /* 842 * Don't allow retrieving properly pre 851 * Don't allow retrieving properly prefixed attributes 843 * by prepending them with "osx." 852 * by prepending them with "osx." 844 */ 853 */ 845 if (is_known_namespace(name)) 854 if (is_known_namespace(name)) 846 return -EOPNOTSUPP; 855 return -EOPNOTSUPP; 847 856 848 /* 857 /* 849 * osx is the namespace we use to indi 858 * osx is the namespace we use to indicate an unprefixed 850 * attribute on the filesystem (like t 859 * attribute on the filesystem (like the ones that OS X 851 * creates), so we pass the name throu 860 * creates), so we pass the name through unmodified (after 852 * ensuring it doesn't conflict with a 861 * ensuring it doesn't conflict with another namespace). 853 */ 862 */ 854 return __hfsplus_getxattr(inode, name, 863 return __hfsplus_getxattr(inode, name, buffer, size); 855 } 864 } 856 865 857 static int hfsplus_osx_setxattr(const struct x 866 static int hfsplus_osx_setxattr(const struct xattr_handler *handler, 858 struct mnt_idm << 859 struct dentry 867 struct dentry *unused, struct inode *inode, 860 const char *na 868 const char *name, const void *buffer, 861 size_t size, i 869 size_t size, int flags) 862 { 870 { 863 /* 871 /* 864 * Don't allow setting properly prefix 872 * Don't allow setting properly prefixed attributes 865 * by prepending them with "osx." 873 * by prepending them with "osx." 866 */ 874 */ 867 if (is_known_namespace(name)) 875 if (is_known_namespace(name)) 868 return -EOPNOTSUPP; 876 return -EOPNOTSUPP; 869 877 870 /* 878 /* 871 * osx is the namespace we use to indi 879 * osx is the namespace we use to indicate an unprefixed 872 * attribute on the filesystem (like t 880 * attribute on the filesystem (like the ones that OS X 873 * creates), so we pass the name throu 881 * creates), so we pass the name through unmodified (after 874 * ensuring it doesn't conflict with a 882 * ensuring it doesn't conflict with another namespace). 875 */ 883 */ 876 return __hfsplus_setxattr(inode, name, 884 return __hfsplus_setxattr(inode, name, buffer, size, flags); 877 } 885 } 878 886 879 const struct xattr_handler hfsplus_xattr_osx_h 887 const struct xattr_handler hfsplus_xattr_osx_handler = { 880 .prefix = XATTR_MAC_OSX_PREFIX, 888 .prefix = XATTR_MAC_OSX_PREFIX, 881 .get = hfsplus_osx_getxattr, 889 .get = hfsplus_osx_getxattr, 882 .set = hfsplus_osx_setxattr, 890 .set = hfsplus_osx_setxattr, 883 }; 891 }; 884 892
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.