2 * linux/fs/hfsplus/xattr.c
4 * Vyacheslav Dubeyko <slava@dubeyko.com>
6 * Logic of processing extended attributes
9 #include "hfsplus_fs.h"
10 #include <linux/posix_acl_xattr.h>
14 const struct xattr_handler *hfsplus_xattr_handlers[] = {
15 &hfsplus_xattr_osx_handler,
16 &hfsplus_xattr_user_handler,
17 &hfsplus_xattr_trusted_handler,
18 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
19 &posix_acl_access_xattr_handler,
20 &posix_acl_default_xattr_handler,
22 &hfsplus_xattr_security_handler,
26 static int strcmp_xattr_finder_info(const char *name)
29 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME,
30 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME));
35 static int strcmp_xattr_acl(const char *name)
38 return strncmp(name, HFSPLUS_XATTR_ACL_NAME,
39 sizeof(HFSPLUS_XATTR_ACL_NAME));
44 static inline int is_known_namespace(const char *name)
46 if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) &&
47 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
48 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
49 strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
55 static void hfsplus_init_header_node(struct inode *attr_file,
57 char *buf, u16 node_size)
59 struct hfs_bnode_desc *desc;
60 struct hfs_btree_header_rec *head;
63 u32 hdr_node_map_rec_bits;
69 hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n",
70 clump_size, node_size);
72 /* The end of the node contains list of record offsets */
73 rec_offsets = (__be16 *)(buf + node_size);
75 desc = (struct hfs_bnode_desc *)buf;
76 desc->type = HFS_NODE_HEADER;
77 desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT);
78 offset = sizeof(struct hfs_bnode_desc);
79 *--rec_offsets = cpu_to_be16(offset);
81 head = (struct hfs_btree_header_rec *)(buf + offset);
82 head->node_size = cpu_to_be16(node_size);
83 tmp = i_size_read(attr_file);
84 do_div(tmp, node_size);
85 head->node_count = cpu_to_be32(tmp);
86 head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1);
87 head->clump_size = cpu_to_be32(clump_size);
88 head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS);
89 head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16));
90 offset += sizeof(struct hfs_btree_header_rec);
91 *--rec_offsets = cpu_to_be16(offset);
92 offset += HFSPLUS_BTREE_HDR_USER_BYTES;
93 *--rec_offsets = cpu_to_be16(offset);
95 hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16)));
96 if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) {
100 desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1);
101 map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) -
102 (2 * sizeof(u16)) - 2);
103 map_nodes = (be32_to_cpu(head->node_count) -
104 hdr_node_map_rec_bits +
105 (map_node_bits - 1)) / map_node_bits;
106 be32_add_cpu(&head->free_nodes, 0 - map_nodes);
111 be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes);
112 used_bmp_bytes = used_nodes / 8;
113 if (used_bmp_bytes) {
114 memset(bmp, 0xFF, used_bmp_bytes);
115 bmp += used_bmp_bytes;
118 *bmp = ~(0xFF >> used_nodes);
119 offset += hdr_node_map_rec_bits / 8;
120 *--rec_offsets = cpu_to_be16(offset);
123 static int hfsplus_create_attributes_file(struct super_block *sb)
126 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
127 struct inode *attr_file;
128 struct hfsplus_inode_info *hip;
130 u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE;
133 struct address_space *mapping;
135 int old_state = HFSPLUS_EMPTY_ATTR_TREE;
137 hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
139 check_attr_tree_state_again:
140 switch (atomic_read(&sbi->attr_tree_state)) {
141 case HFSPLUS_EMPTY_ATTR_TREE:
142 if (old_state != atomic_cmpxchg(&sbi->attr_tree_state,
144 HFSPLUS_CREATING_ATTR_TREE))
145 goto check_attr_tree_state_again;
147 case HFSPLUS_CREATING_ATTR_TREE:
149 * This state means that another thread is in process
150 * of AttributesFile creation. Theoretically, it is
151 * possible to be here. But really __setxattr() method
152 * first of all calls hfs_find_init() for lookup in
153 * B-tree of CatalogFile. This method locks mutex of
154 * CatalogFile's B-tree. As a result, if some thread
155 * is inside AttributedFile creation operation then
156 * another threads will be waiting unlocking of
157 * CatalogFile's B-tree's mutex. However, if code will
158 * change then we will return error code (-EAGAIN) from
159 * here. Really, it means that first try to set of xattr
160 * fails with error but second attempt will have success.
163 case HFSPLUS_VALID_ATTR_TREE:
165 case HFSPLUS_FAILED_ATTR_TREE:
171 attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID);
172 if (IS_ERR(attr_file)) {
173 pr_err("failed to load attributes file\n");
174 return PTR_ERR(attr_file);
177 BUG_ON(i_size_read(attr_file) != 0);
179 hip = HFSPLUS_I(attr_file);
181 clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize,
186 mutex_lock(&hip->extents_lock);
187 hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift;
188 mutex_unlock(&hip->extents_lock);
190 if (sbi->free_blocks <= (hip->clump_blocks << 1)) {
192 goto end_attr_file_creation;
195 while (hip->alloc_blocks < hip->clump_blocks) {
196 err = hfsplus_file_extend(attr_file);
198 pr_err("failed to extend attributes file\n");
199 goto end_attr_file_creation;
201 hip->phys_size = attr_file->i_size =
202 (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift;
203 hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift;
204 inode_set_bytes(attr_file, attr_file->i_size);
207 buf = kzalloc(node_size, GFP_NOFS);
209 pr_err("failed to allocate memory for header node\n");
211 goto end_attr_file_creation;
214 hfsplus_init_header_node(attr_file, clump_size, buf, node_size);
216 mapping = attr_file->i_mapping;
220 for (; written < node_size; index++, written += PAGE_CACHE_SIZE) {
223 page = read_mapping_page(mapping, index, NULL);
226 goto failed_header_node_init;
229 kaddr = kmap_atomic(page);
230 memcpy(kaddr, buf + written,
231 min_t(size_t, PAGE_CACHE_SIZE, node_size - written));
232 kunmap_atomic(kaddr);
234 set_page_dirty(page);
235 page_cache_release(page);
238 hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY);
240 sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
242 pr_err("failed to load attributes file\n");
244 failed_header_node_init:
247 end_attr_file_creation:
251 atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
252 else if (err == -ENOSPC)
253 atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
255 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE);
260 int __hfsplus_setxattr(struct inode *inode, const char *name,
261 const void *value, size_t size, int flags)
264 struct hfs_find_data cat_fd;
265 hfsplus_cat_entry entry;
266 u16 cat_entry_flags, cat_entry_type;
267 u16 folder_finderinfo_len = sizeof(struct DInfo) +
268 sizeof(struct DXInfo);
269 u16 file_finderinfo_len = sizeof(struct FInfo) +
270 sizeof(struct FXInfo);
272 if ((!S_ISREG(inode->i_mode) &&
273 !S_ISDIR(inode->i_mode)) ||
274 HFSPLUS_IS_RSRC(inode))
277 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
278 XATTR_MAC_OSX_PREFIX_LEN) == 0)
279 name += XATTR_MAC_OSX_PREFIX_LEN;
286 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
288 pr_err("can't init xattr find struct\n");
292 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
294 pr_err("catalog searching failed\n");
298 if (!strcmp_xattr_finder_info(name)) {
299 if (flags & XATTR_CREATE) {
300 pr_err("xattr exists yet\n");
304 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset,
305 sizeof(hfsplus_cat_entry));
306 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) {
307 if (size == folder_finderinfo_len) {
308 memcpy(&entry.folder.user_info, value,
309 folder_finderinfo_len);
310 hfs_bnode_write(cat_fd.bnode, &entry,
312 sizeof(struct hfsplus_cat_folder));
313 hfsplus_mark_inode_dirty(inode,
314 HFSPLUS_I_CAT_DIRTY);
319 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) {
320 if (size == file_finderinfo_len) {
321 memcpy(&entry.file.user_info, value,
322 file_finderinfo_len);
323 hfs_bnode_write(cat_fd.bnode, &entry,
325 sizeof(struct hfsplus_cat_file));
326 hfsplus_mark_inode_dirty(inode,
327 HFSPLUS_I_CAT_DIRTY);
339 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
340 err = hfsplus_create_attributes_file(inode->i_sb);
345 if (hfsplus_attr_exists(inode, name)) {
346 if (flags & XATTR_CREATE) {
347 pr_err("xattr exists yet\n");
351 err = hfsplus_delete_attr(inode, name);
354 err = hfsplus_create_attr(inode, name, value, size);
358 if (flags & XATTR_REPLACE) {
359 pr_err("cannot replace xattr\n");
363 err = hfsplus_create_attr(inode, name, value, size);
368 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
369 if (cat_entry_type == HFSPLUS_FOLDER) {
370 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
372 offsetof(struct hfsplus_cat_folder, flags));
373 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
374 if (!strcmp_xattr_acl(name))
375 cat_entry_flags |= HFSPLUS_ACL_EXISTS;
376 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
377 offsetof(struct hfsplus_cat_folder, flags),
379 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
380 } else if (cat_entry_type == HFSPLUS_FILE) {
381 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
383 offsetof(struct hfsplus_cat_file, flags));
384 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
385 if (!strcmp_xattr_acl(name))
386 cat_entry_flags |= HFSPLUS_ACL_EXISTS;
387 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
388 offsetof(struct hfsplus_cat_file, flags),
390 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
392 pr_err("invalid catalog entry type\n");
398 hfs_find_exit(&cat_fd);
402 static inline int is_osx_xattr(const char *xattr_name)
404 return !is_known_namespace(xattr_name);
407 static int name_len(const char *xattr_name, int xattr_name_len)
409 int len = xattr_name_len + 1;
411 if (is_osx_xattr(xattr_name))
412 len += XATTR_MAC_OSX_PREFIX_LEN;
417 static int copy_name(char *buffer, const char *xattr_name, int name_len)
422 if (is_osx_xattr(xattr_name)) {
423 strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
424 offset += XATTR_MAC_OSX_PREFIX_LEN;
425 len += XATTR_MAC_OSX_PREFIX_LEN;
428 strncpy(buffer + offset, xattr_name, name_len);
429 memset(buffer + offset + name_len, 0, 1);
435 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode,
436 void *value, size_t size)
439 struct hfs_find_data fd;
441 u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo);
442 u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo);
443 u16 record_len = max(folder_rec_len, file_rec_len);
444 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
445 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
447 if (size >= record_len) {
448 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
450 pr_err("can't init xattr find struct\n");
453 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
455 goto end_getxattr_finder_info;
456 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
458 if (entry_type == HFSPLUS_FOLDER) {
459 hfs_bnode_read(fd.bnode, folder_finder_info,
461 offsetof(struct hfsplus_cat_folder, user_info),
463 memcpy(value, folder_finder_info, folder_rec_len);
464 res = folder_rec_len;
465 } else if (entry_type == HFSPLUS_FILE) {
466 hfs_bnode_read(fd.bnode, file_finder_info,
468 offsetof(struct hfsplus_cat_file, user_info),
470 memcpy(value, file_finder_info, file_rec_len);
474 goto end_getxattr_finder_info;
477 res = size ? -ERANGE : record_len;
479 end_getxattr_finder_info:
480 if (size >= record_len)
485 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
486 void *value, size_t size)
488 struct hfs_find_data fd;
489 hfsplus_attr_entry *entry;
490 __be32 xattr_record_type;
492 u16 record_length = 0;
495 if ((!S_ISREG(inode->i_mode) &&
496 !S_ISDIR(inode->i_mode)) ||
497 HFSPLUS_IS_RSRC(inode))
500 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
501 XATTR_MAC_OSX_PREFIX_LEN) == 0) {
502 /* skip "osx." prefix */
503 name += XATTR_MAC_OSX_PREFIX_LEN;
505 * Don't allow retrieving properly prefixed attributes
506 * by prepending them with "osx."
508 if (is_known_namespace(name))
512 if (!strcmp_xattr_finder_info(name))
513 return hfsplus_getxattr_finder_info(inode, value, size);
515 if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
518 entry = hfsplus_alloc_attr_entry();
520 pr_err("can't allocate xattr entry\n");
524 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
526 pr_err("can't init xattr find struct\n");
527 goto failed_getxattr_init;
530 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
535 pr_err("xattr searching failed\n");
539 hfs_bnode_read(fd.bnode, &xattr_record_type,
540 fd.entryoffset, sizeof(xattr_record_type));
541 record_type = be32_to_cpu(xattr_record_type);
542 if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
543 record_length = hfs_bnode_read_u16(fd.bnode,
545 offsetof(struct hfsplus_attr_inline_data,
547 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
548 pr_err("invalid xattr record size\n");
552 } else if (record_type == HFSPLUS_ATTR_FORK_DATA ||
553 record_type == HFSPLUS_ATTR_EXTENTS) {
554 pr_err("only inline data xattr are supported\n");
558 pr_err("invalid xattr record\n");
564 hfs_bnode_read(fd.bnode, entry, fd.entryoffset,
565 offsetof(struct hfsplus_attr_inline_data,
566 raw_bytes) + record_length);
569 if (size >= record_length) {
570 memcpy(value, entry->inline_data.raw_bytes, record_length);
573 res = size ? -ERANGE : record_length;
578 failed_getxattr_init:
579 hfsplus_destroy_attr_entry(entry);
583 static inline int can_list(const char *xattr_name)
588 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
589 XATTR_TRUSTED_PREFIX_LEN) ||
590 capable(CAP_SYS_ADMIN);
593 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
594 char *buffer, size_t size)
597 struct inode *inode = dentry->d_inode;
598 struct hfs_find_data fd;
600 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
601 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
602 unsigned long len, found_bit;
603 int xattr_name_len, symbols_count;
605 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
607 pr_err("can't init xattr find struct\n");
611 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
613 goto end_listxattr_finder_info;
615 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
616 if (entry_type == HFSPLUS_FOLDER) {
617 len = sizeof(struct DInfo) + sizeof(struct DXInfo);
618 hfs_bnode_read(fd.bnode, folder_finder_info,
620 offsetof(struct hfsplus_cat_folder, user_info),
622 found_bit = find_first_bit((void *)folder_finder_info, len*8);
623 } else if (entry_type == HFSPLUS_FILE) {
624 len = sizeof(struct FInfo) + sizeof(struct FXInfo);
625 hfs_bnode_read(fd.bnode, file_finder_info,
627 offsetof(struct hfsplus_cat_file, user_info),
629 found_bit = find_first_bit((void *)file_finder_info, len*8);
632 goto end_listxattr_finder_info;
635 if (found_bit >= (len*8))
638 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1;
640 name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count);
641 if (!buffer || !size) {
642 if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME))
643 res = xattr_name_len;
644 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) {
645 if (size < xattr_name_len)
648 res = copy_name(buffer,
649 HFSPLUS_XATTR_FINDER_INFO_NAME,
655 end_listxattr_finder_info:
661 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
665 struct inode *inode = dentry->d_inode;
666 struct hfs_find_data fd;
668 struct hfsplus_attr_key attr_key;
669 char strbuf[HFSPLUS_ATTR_MAX_STRLEN +
670 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
673 if ((!S_ISREG(inode->i_mode) &&
674 !S_ISDIR(inode->i_mode)) ||
675 HFSPLUS_IS_RSRC(inode))
678 res = hfsplus_listxattr_finder_info(dentry, buffer, size);
681 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
682 return (res == 0) ? -EOPNOTSUPP : res;
684 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
686 pr_err("can't init xattr find struct\n");
690 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
692 if (err == -ENOENT) {
703 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
704 if (key_len == 0 || key_len > fd.tree->max_key_len) {
705 pr_err("invalid xattr key length: %d\n", key_len);
710 hfs_bnode_read(fd.bnode, &attr_key,
711 fd.keyoffset, key_len + sizeof(key_len));
713 if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
716 xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN;
717 if (hfsplus_uni2asc(inode->i_sb,
718 (const struct hfsplus_unistr *)&fd.key->attr.key_name,
719 strbuf, &xattr_name_len)) {
720 pr_err("unicode conversion failed\n");
725 if (!buffer || !size) {
726 if (can_list(strbuf))
727 res += name_len(strbuf, xattr_name_len);
728 } else if (can_list(strbuf)) {
729 if (size < (res + name_len(strbuf, xattr_name_len))) {
733 res += copy_name(buffer + res,
734 strbuf, xattr_name_len);
737 if (hfs_brec_goto(&fd, 1))
746 int hfsplus_removexattr(struct dentry *dentry, const char *name)
749 struct inode *inode = dentry->d_inode;
750 struct hfs_find_data cat_fd;
753 int is_xattr_acl_deleted = 0;
754 int is_all_xattrs_deleted = 0;
756 if ((!S_ISREG(inode->i_mode) &&
757 !S_ISDIR(inode->i_mode)) ||
758 HFSPLUS_IS_RSRC(inode))
761 if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
764 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
765 XATTR_MAC_OSX_PREFIX_LEN) == 0)
766 name += XATTR_MAC_OSX_PREFIX_LEN;
768 if (!strcmp_xattr_finder_info(name))
771 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
773 pr_err("can't init xattr find struct\n");
777 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
779 pr_err("catalog searching failed\n");
780 goto end_removexattr;
783 err = hfsplus_delete_attr(inode, name);
785 goto end_removexattr;
787 is_xattr_acl_deleted = !strcmp_xattr_acl(name);
788 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
790 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
791 goto end_removexattr;
793 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
795 if (cat_entry_type == HFSPLUS_FOLDER) {
796 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
797 offsetof(struct hfsplus_cat_folder, flags));
798 if (is_xattr_acl_deleted)
799 flags &= ~HFSPLUS_ACL_EXISTS;
800 if (is_all_xattrs_deleted)
801 flags &= ~HFSPLUS_XATTR_EXISTS;
802 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
803 offsetof(struct hfsplus_cat_folder, flags),
805 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
806 } else if (cat_entry_type == HFSPLUS_FILE) {
807 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
808 offsetof(struct hfsplus_cat_file, flags));
809 if (is_xattr_acl_deleted)
810 flags &= ~HFSPLUS_ACL_EXISTS;
811 if (is_all_xattrs_deleted)
812 flags &= ~HFSPLUS_XATTR_EXISTS;
813 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
814 offsetof(struct hfsplus_cat_file, flags),
816 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
818 pr_err("invalid catalog entry type\n");
820 goto end_removexattr;
824 hfs_find_exit(&cat_fd);
828 static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
829 void *buffer, size_t size, int type)
831 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
832 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
833 size_t len = strlen(name);
835 if (!strcmp(name, ""))
838 if (len > HFSPLUS_ATTR_MAX_STRLEN)
841 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
842 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
844 return hfsplus_getxattr(dentry, xattr_name, buffer, size);
847 static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
848 const void *buffer, size_t size, int flags, int type)
850 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
851 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
852 size_t len = strlen(name);
854 if (!strcmp(name, ""))
857 if (len > HFSPLUS_ATTR_MAX_STRLEN)
860 if (is_known_namespace(name))
863 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
864 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
866 return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags);
869 static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list,
870 size_t list_size, const char *name, size_t name_len, int type)
873 * This method is not used.
874 * It is used hfsplus_listxattr() instead of generic_listxattr().
879 const struct xattr_handler hfsplus_xattr_osx_handler = {
880 .prefix = XATTR_MAC_OSX_PREFIX,
881 .list = hfsplus_osx_listxattr,
882 .get = hfsplus_osx_getxattr,
883 .set = hfsplus_osx_setxattr,