Linux 3.12.5
[linux/fpc-iii.git] / fs / hfsplus / xattr.c
blobbd8471fb9a6a80fdf74abdbd673714931c0b7867
1 /*
2 * linux/fs/hfsplus/xattr.c
4 * Vyacheslav Dubeyko <slava@dubeyko.com>
6 * Logic of processing extended attributes
7 */
9 #include "hfsplus_fs.h"
10 #include "xattr.h"
11 #include "acl.h"
13 const struct xattr_handler *hfsplus_xattr_handlers[] = {
14 &hfsplus_xattr_osx_handler,
15 &hfsplus_xattr_user_handler,
16 &hfsplus_xattr_trusted_handler,
17 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
18 &hfsplus_xattr_acl_access_handler,
19 &hfsplus_xattr_acl_default_handler,
20 #endif
21 &hfsplus_xattr_security_handler,
22 NULL
25 static int strcmp_xattr_finder_info(const char *name)
27 if (name) {
28 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME,
29 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME));
31 return -1;
34 static int strcmp_xattr_acl(const char *name)
36 if (name) {
37 return strncmp(name, HFSPLUS_XATTR_ACL_NAME,
38 sizeof(HFSPLUS_XATTR_ACL_NAME));
40 return -1;
43 static inline int is_known_namespace(const char *name)
45 if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) &&
46 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
47 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
48 strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
49 return false;
51 return true;
54 static int can_set_system_xattr(struct inode *inode, const char *name,
55 const void *value, size_t size)
57 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
58 struct posix_acl *acl;
59 int err;
61 if (!inode_owner_or_capable(inode))
62 return -EPERM;
65 * POSIX_ACL_XATTR_ACCESS is tied to i_mode
67 if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
68 acl = posix_acl_from_xattr(&init_user_ns, value, size);
69 if (IS_ERR(acl))
70 return PTR_ERR(acl);
71 if (acl) {
72 err = posix_acl_equiv_mode(acl, &inode->i_mode);
73 posix_acl_release(acl);
74 if (err < 0)
75 return err;
76 mark_inode_dirty(inode);
79 * We're changing the ACL. Get rid of the cached one
81 forget_cached_acl(inode, ACL_TYPE_ACCESS);
83 return 0;
84 } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
85 acl = posix_acl_from_xattr(&init_user_ns, value, size);
86 if (IS_ERR(acl))
87 return PTR_ERR(acl);
88 posix_acl_release(acl);
91 * We're changing the default ACL. Get rid of the cached one
93 forget_cached_acl(inode, ACL_TYPE_DEFAULT);
95 return 0;
97 #endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */
98 return -EOPNOTSUPP;
101 static int can_set_xattr(struct inode *inode, const char *name,
102 const void *value, size_t value_len)
104 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
105 return can_set_system_xattr(inode, name, value, value_len);
107 if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
109 * This makes sure that we aren't trying to set an
110 * attribute in a different namespace by prefixing it
111 * with "osx."
113 if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
114 return -EOPNOTSUPP;
116 return 0;
120 * Don't allow setting an attribute in an unknown namespace.
122 if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&
123 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
124 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
125 return -EOPNOTSUPP;
127 return 0;
130 int __hfsplus_setxattr(struct inode *inode, const char *name,
131 const void *value, size_t size, int flags)
133 int err = 0;
134 struct hfs_find_data cat_fd;
135 hfsplus_cat_entry entry;
136 u16 cat_entry_flags, cat_entry_type;
137 u16 folder_finderinfo_len = sizeof(struct DInfo) +
138 sizeof(struct DXInfo);
139 u16 file_finderinfo_len = sizeof(struct FInfo) +
140 sizeof(struct FXInfo);
142 if ((!S_ISREG(inode->i_mode) &&
143 !S_ISDIR(inode->i_mode)) ||
144 HFSPLUS_IS_RSRC(inode))
145 return -EOPNOTSUPP;
147 err = can_set_xattr(inode, name, value, size);
148 if (err)
149 return err;
151 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
152 XATTR_MAC_OSX_PREFIX_LEN) == 0)
153 name += XATTR_MAC_OSX_PREFIX_LEN;
155 if (value == NULL) {
156 value = "";
157 size = 0;
160 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
161 if (err) {
162 pr_err("can't init xattr find struct\n");
163 return err;
166 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
167 if (err) {
168 pr_err("catalog searching failed\n");
169 goto end_setxattr;
172 if (!strcmp_xattr_finder_info(name)) {
173 if (flags & XATTR_CREATE) {
174 pr_err("xattr exists yet\n");
175 err = -EOPNOTSUPP;
176 goto end_setxattr;
178 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset,
179 sizeof(hfsplus_cat_entry));
180 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) {
181 if (size == folder_finderinfo_len) {
182 memcpy(&entry.folder.user_info, value,
183 folder_finderinfo_len);
184 hfs_bnode_write(cat_fd.bnode, &entry,
185 cat_fd.entryoffset,
186 sizeof(struct hfsplus_cat_folder));
187 hfsplus_mark_inode_dirty(inode,
188 HFSPLUS_I_CAT_DIRTY);
189 } else {
190 err = -ERANGE;
191 goto end_setxattr;
193 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) {
194 if (size == file_finderinfo_len) {
195 memcpy(&entry.file.user_info, value,
196 file_finderinfo_len);
197 hfs_bnode_write(cat_fd.bnode, &entry,
198 cat_fd.entryoffset,
199 sizeof(struct hfsplus_cat_file));
200 hfsplus_mark_inode_dirty(inode,
201 HFSPLUS_I_CAT_DIRTY);
202 } else {
203 err = -ERANGE;
204 goto end_setxattr;
206 } else {
207 err = -EOPNOTSUPP;
208 goto end_setxattr;
210 goto end_setxattr;
213 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
214 err = -EOPNOTSUPP;
215 goto end_setxattr;
218 if (hfsplus_attr_exists(inode, name)) {
219 if (flags & XATTR_CREATE) {
220 pr_err("xattr exists yet\n");
221 err = -EOPNOTSUPP;
222 goto end_setxattr;
224 err = hfsplus_delete_attr(inode, name);
225 if (err)
226 goto end_setxattr;
227 err = hfsplus_create_attr(inode, name, value, size);
228 if (err)
229 goto end_setxattr;
230 } else {
231 if (flags & XATTR_REPLACE) {
232 pr_err("cannot replace xattr\n");
233 err = -EOPNOTSUPP;
234 goto end_setxattr;
236 err = hfsplus_create_attr(inode, name, value, size);
237 if (err)
238 goto end_setxattr;
241 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
242 if (cat_entry_type == HFSPLUS_FOLDER) {
243 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
244 cat_fd.entryoffset +
245 offsetof(struct hfsplus_cat_folder, flags));
246 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
247 if (!strcmp_xattr_acl(name))
248 cat_entry_flags |= HFSPLUS_ACL_EXISTS;
249 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
250 offsetof(struct hfsplus_cat_folder, flags),
251 cat_entry_flags);
252 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
253 } else if (cat_entry_type == HFSPLUS_FILE) {
254 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
255 cat_fd.entryoffset +
256 offsetof(struct hfsplus_cat_file, flags));
257 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
258 if (!strcmp_xattr_acl(name))
259 cat_entry_flags |= HFSPLUS_ACL_EXISTS;
260 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
261 offsetof(struct hfsplus_cat_file, flags),
262 cat_entry_flags);
263 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
264 } else {
265 pr_err("invalid catalog entry type\n");
266 err = -EIO;
267 goto end_setxattr;
270 end_setxattr:
271 hfs_find_exit(&cat_fd);
272 return err;
275 static inline int is_osx_xattr(const char *xattr_name)
277 return !is_known_namespace(xattr_name);
280 static int name_len(const char *xattr_name, int xattr_name_len)
282 int len = xattr_name_len + 1;
284 if (is_osx_xattr(xattr_name))
285 len += XATTR_MAC_OSX_PREFIX_LEN;
287 return len;
290 static int copy_name(char *buffer, const char *xattr_name, int name_len)
292 int len = name_len;
293 int offset = 0;
295 if (is_osx_xattr(xattr_name)) {
296 strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
297 offset += XATTR_MAC_OSX_PREFIX_LEN;
298 len += XATTR_MAC_OSX_PREFIX_LEN;
301 strncpy(buffer + offset, xattr_name, name_len);
302 memset(buffer + offset + name_len, 0, 1);
303 len += 1;
305 return len;
308 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode,
309 void *value, size_t size)
311 ssize_t res = 0;
312 struct hfs_find_data fd;
313 u16 entry_type;
314 u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo);
315 u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo);
316 u16 record_len = max(folder_rec_len, file_rec_len);
317 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
318 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
320 if (size >= record_len) {
321 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
322 if (res) {
323 pr_err("can't init xattr find struct\n");
324 return res;
326 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
327 if (res)
328 goto end_getxattr_finder_info;
329 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
331 if (entry_type == HFSPLUS_FOLDER) {
332 hfs_bnode_read(fd.bnode, folder_finder_info,
333 fd.entryoffset +
334 offsetof(struct hfsplus_cat_folder, user_info),
335 folder_rec_len);
336 memcpy(value, folder_finder_info, folder_rec_len);
337 res = folder_rec_len;
338 } else if (entry_type == HFSPLUS_FILE) {
339 hfs_bnode_read(fd.bnode, file_finder_info,
340 fd.entryoffset +
341 offsetof(struct hfsplus_cat_file, user_info),
342 file_rec_len);
343 memcpy(value, file_finder_info, file_rec_len);
344 res = file_rec_len;
345 } else {
346 res = -EOPNOTSUPP;
347 goto end_getxattr_finder_info;
349 } else
350 res = size ? -ERANGE : record_len;
352 end_getxattr_finder_info:
353 if (size >= record_len)
354 hfs_find_exit(&fd);
355 return res;
358 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
359 void *value, size_t size)
361 struct hfs_find_data fd;
362 hfsplus_attr_entry *entry;
363 __be32 xattr_record_type;
364 u32 record_type;
365 u16 record_length = 0;
366 ssize_t res = 0;
368 if ((!S_ISREG(inode->i_mode) &&
369 !S_ISDIR(inode->i_mode)) ||
370 HFSPLUS_IS_RSRC(inode))
371 return -EOPNOTSUPP;
373 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
374 XATTR_MAC_OSX_PREFIX_LEN) == 0) {
375 /* skip "osx." prefix */
376 name += XATTR_MAC_OSX_PREFIX_LEN;
378 * Don't allow retrieving properly prefixed attributes
379 * by prepending them with "osx."
381 if (is_known_namespace(name))
382 return -EOPNOTSUPP;
385 if (!strcmp_xattr_finder_info(name))
386 return hfsplus_getxattr_finder_info(inode, value, size);
388 if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
389 return -EOPNOTSUPP;
391 entry = hfsplus_alloc_attr_entry();
392 if (!entry) {
393 pr_err("can't allocate xattr entry\n");
394 return -ENOMEM;
397 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
398 if (res) {
399 pr_err("can't init xattr find struct\n");
400 goto failed_getxattr_init;
403 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
404 if (res) {
405 if (res == -ENOENT)
406 res = -ENODATA;
407 else
408 pr_err("xattr searching failed\n");
409 goto out;
412 hfs_bnode_read(fd.bnode, &xattr_record_type,
413 fd.entryoffset, sizeof(xattr_record_type));
414 record_type = be32_to_cpu(xattr_record_type);
415 if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
416 record_length = hfs_bnode_read_u16(fd.bnode,
417 fd.entryoffset +
418 offsetof(struct hfsplus_attr_inline_data,
419 length));
420 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
421 pr_err("invalid xattr record size\n");
422 res = -EIO;
423 goto out;
425 } else if (record_type == HFSPLUS_ATTR_FORK_DATA ||
426 record_type == HFSPLUS_ATTR_EXTENTS) {
427 pr_err("only inline data xattr are supported\n");
428 res = -EOPNOTSUPP;
429 goto out;
430 } else {
431 pr_err("invalid xattr record\n");
432 res = -EIO;
433 goto out;
436 if (size) {
437 hfs_bnode_read(fd.bnode, entry, fd.entryoffset,
438 offsetof(struct hfsplus_attr_inline_data,
439 raw_bytes) + record_length);
442 if (size >= record_length) {
443 memcpy(value, entry->inline_data.raw_bytes, record_length);
444 res = record_length;
445 } else
446 res = size ? -ERANGE : record_length;
448 out:
449 hfs_find_exit(&fd);
451 failed_getxattr_init:
452 hfsplus_destroy_attr_entry(entry);
453 return res;
456 static inline int can_list(const char *xattr_name)
458 if (!xattr_name)
459 return 0;
461 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
462 XATTR_TRUSTED_PREFIX_LEN) ||
463 capable(CAP_SYS_ADMIN);
466 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
467 char *buffer, size_t size)
469 ssize_t res = 0;
470 struct inode *inode = dentry->d_inode;
471 struct hfs_find_data fd;
472 u16 entry_type;
473 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
474 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
475 unsigned long len, found_bit;
476 int xattr_name_len, symbols_count;
478 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
479 if (res) {
480 pr_err("can't init xattr find struct\n");
481 return res;
484 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
485 if (res)
486 goto end_listxattr_finder_info;
488 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
489 if (entry_type == HFSPLUS_FOLDER) {
490 len = sizeof(struct DInfo) + sizeof(struct DXInfo);
491 hfs_bnode_read(fd.bnode, folder_finder_info,
492 fd.entryoffset +
493 offsetof(struct hfsplus_cat_folder, user_info),
494 len);
495 found_bit = find_first_bit((void *)folder_finder_info, len*8);
496 } else if (entry_type == HFSPLUS_FILE) {
497 len = sizeof(struct FInfo) + sizeof(struct FXInfo);
498 hfs_bnode_read(fd.bnode, file_finder_info,
499 fd.entryoffset +
500 offsetof(struct hfsplus_cat_file, user_info),
501 len);
502 found_bit = find_first_bit((void *)file_finder_info, len*8);
503 } else {
504 res = -EOPNOTSUPP;
505 goto end_listxattr_finder_info;
508 if (found_bit >= (len*8))
509 res = 0;
510 else {
511 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1;
512 xattr_name_len =
513 name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count);
514 if (!buffer || !size) {
515 if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME))
516 res = xattr_name_len;
517 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) {
518 if (size < xattr_name_len)
519 res = -ERANGE;
520 else {
521 res = copy_name(buffer,
522 HFSPLUS_XATTR_FINDER_INFO_NAME,
523 symbols_count);
528 end_listxattr_finder_info:
529 hfs_find_exit(&fd);
531 return res;
534 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
536 ssize_t err;
537 ssize_t res = 0;
538 struct inode *inode = dentry->d_inode;
539 struct hfs_find_data fd;
540 u16 key_len = 0;
541 struct hfsplus_attr_key attr_key;
542 char strbuf[HFSPLUS_ATTR_MAX_STRLEN +
543 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
544 int xattr_name_len;
546 if ((!S_ISREG(inode->i_mode) &&
547 !S_ISDIR(inode->i_mode)) ||
548 HFSPLUS_IS_RSRC(inode))
549 return -EOPNOTSUPP;
551 res = hfsplus_listxattr_finder_info(dentry, buffer, size);
552 if (res < 0)
553 return res;
554 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
555 return (res == 0) ? -EOPNOTSUPP : res;
557 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
558 if (err) {
559 pr_err("can't init xattr find struct\n");
560 return err;
563 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
564 if (err) {
565 if (err == -ENOENT) {
566 if (res == 0)
567 res = -ENODATA;
568 goto end_listxattr;
569 } else {
570 res = err;
571 goto end_listxattr;
575 for (;;) {
576 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
577 if (key_len == 0 || key_len > fd.tree->max_key_len) {
578 pr_err("invalid xattr key length: %d\n", key_len);
579 res = -EIO;
580 goto end_listxattr;
583 hfs_bnode_read(fd.bnode, &attr_key,
584 fd.keyoffset, key_len + sizeof(key_len));
586 if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
587 goto end_listxattr;
589 xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN;
590 if (hfsplus_uni2asc(inode->i_sb,
591 (const struct hfsplus_unistr *)&fd.key->attr.key_name,
592 strbuf, &xattr_name_len)) {
593 pr_err("unicode conversion failed\n");
594 res = -EIO;
595 goto end_listxattr;
598 if (!buffer || !size) {
599 if (can_list(strbuf))
600 res += name_len(strbuf, xattr_name_len);
601 } else if (can_list(strbuf)) {
602 if (size < (res + name_len(strbuf, xattr_name_len))) {
603 res = -ERANGE;
604 goto end_listxattr;
605 } else
606 res += copy_name(buffer + res,
607 strbuf, xattr_name_len);
610 if (hfs_brec_goto(&fd, 1))
611 goto end_listxattr;
614 end_listxattr:
615 hfs_find_exit(&fd);
616 return res;
619 int hfsplus_removexattr(struct dentry *dentry, const char *name)
621 int err = 0;
622 struct inode *inode = dentry->d_inode;
623 struct hfs_find_data cat_fd;
624 u16 flags;
625 u16 cat_entry_type;
626 int is_xattr_acl_deleted = 0;
627 int is_all_xattrs_deleted = 0;
629 if ((!S_ISREG(inode->i_mode) &&
630 !S_ISDIR(inode->i_mode)) ||
631 HFSPLUS_IS_RSRC(inode))
632 return -EOPNOTSUPP;
634 if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
635 return -EOPNOTSUPP;
637 err = can_set_xattr(inode, name, NULL, 0);
638 if (err)
639 return err;
641 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
642 XATTR_MAC_OSX_PREFIX_LEN) == 0)
643 name += XATTR_MAC_OSX_PREFIX_LEN;
645 if (!strcmp_xattr_finder_info(name))
646 return -EOPNOTSUPP;
648 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
649 if (err) {
650 pr_err("can't init xattr find struct\n");
651 return err;
654 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
655 if (err) {
656 pr_err("catalog searching failed\n");
657 goto end_removexattr;
660 err = hfsplus_delete_attr(inode, name);
661 if (err)
662 goto end_removexattr;
664 is_xattr_acl_deleted = !strcmp_xattr_acl(name);
665 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
667 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
668 goto end_removexattr;
670 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
672 if (cat_entry_type == HFSPLUS_FOLDER) {
673 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
674 offsetof(struct hfsplus_cat_folder, flags));
675 if (is_xattr_acl_deleted)
676 flags &= ~HFSPLUS_ACL_EXISTS;
677 if (is_all_xattrs_deleted)
678 flags &= ~HFSPLUS_XATTR_EXISTS;
679 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
680 offsetof(struct hfsplus_cat_folder, flags),
681 flags);
682 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
683 } else if (cat_entry_type == HFSPLUS_FILE) {
684 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
685 offsetof(struct hfsplus_cat_file, flags));
686 if (is_xattr_acl_deleted)
687 flags &= ~HFSPLUS_ACL_EXISTS;
688 if (is_all_xattrs_deleted)
689 flags &= ~HFSPLUS_XATTR_EXISTS;
690 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
691 offsetof(struct hfsplus_cat_file, flags),
692 flags);
693 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
694 } else {
695 pr_err("invalid catalog entry type\n");
696 err = -EIO;
697 goto end_removexattr;
700 end_removexattr:
701 hfs_find_exit(&cat_fd);
702 return err;
705 static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
706 void *buffer, size_t size, int type)
708 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
709 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
710 size_t len = strlen(name);
712 if (!strcmp(name, ""))
713 return -EINVAL;
715 if (len > HFSPLUS_ATTR_MAX_STRLEN)
716 return -EOPNOTSUPP;
718 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
719 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
721 return hfsplus_getxattr(dentry, xattr_name, buffer, size);
724 static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
725 const void *buffer, size_t size, int flags, int type)
727 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
728 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
729 size_t len = strlen(name);
731 if (!strcmp(name, ""))
732 return -EINVAL;
734 if (len > HFSPLUS_ATTR_MAX_STRLEN)
735 return -EOPNOTSUPP;
737 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
738 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
740 return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags);
743 static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list,
744 size_t list_size, const char *name, size_t name_len, int type)
747 * This method is not used.
748 * It is used hfsplus_listxattr() instead of generic_listxattr().
750 return -EOPNOTSUPP;
753 const struct xattr_handler hfsplus_xattr_osx_handler = {
754 .prefix = XATTR_MAC_OSX_PREFIX,
755 .list = hfsplus_osx_listxattr,
756 .get = hfsplus_osx_getxattr,
757 .set = hfsplus_osx_setxattr,