Merge tag 'v3.13' into stable-3.14
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / hfsplus / xattr.c
1 /*
2  * linux/fs/hfsplus/xattr.c
3  *
4  * Vyacheslav Dubeyko <slava@dubeyko.com>
5  *
6  * Logic of processing extended attributes
7  */
8
9 #include "hfsplus_fs.h"
10 #include "xattr.h"
11 #include "acl.h"
12
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
23 };
24
25 static int strcmp_xattr_finder_info(const char *name)
26 {
27         if (name) {
28                 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME,
29                                 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME));
30         }
31         return -1;
32 }
33
34 static int strcmp_xattr_acl(const char *name)
35 {
36         if (name) {
37                 return strncmp(name, HFSPLUS_XATTR_ACL_NAME,
38                                 sizeof(HFSPLUS_XATTR_ACL_NAME));
39         }
40         return -1;
41 }
42
43 static inline int is_known_namespace(const char *name)
44 {
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;
50
51         return true;
52 }
53
54 static int can_set_system_xattr(struct inode *inode, const char *name,
55                                 const void *value, size_t size)
56 {
57 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
58         struct posix_acl *acl;
59         int err;
60
61         if (!inode_owner_or_capable(inode))
62                 return -EPERM;
63
64         /*
65          * POSIX_ACL_XATTR_ACCESS is tied to i_mode
66          */
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);
77                 }
78                 /*
79                  * We're changing the ACL.  Get rid of the cached one
80                  */
81                 forget_cached_acl(inode, ACL_TYPE_ACCESS);
82
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);
89
90                 /*
91                  * We're changing the default ACL.  Get rid of the cached one
92                  */
93                 forget_cached_acl(inode, ACL_TYPE_DEFAULT);
94
95                 return 0;
96         }
97 #endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */
98         return -EOPNOTSUPP;
99 }
100
101 static int can_set_xattr(struct inode *inode, const char *name,
102                                 const void *value, size_t value_len)
103 {
104         if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
105                 return can_set_system_xattr(inode, name, value, value_len);
106
107         if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
108                 /*
109                  * This makes sure that we aren't trying to set an
110                  * attribute in a different namespace by prefixing it
111                  * with "osx."
112                  */
113                 if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
114                         return -EOPNOTSUPP;
115
116                 return 0;
117         }
118
119         /*
120          * Don't allow setting an attribute in an unknown namespace.
121          */
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;
126
127         return 0;
128 }
129
130 static void hfsplus_init_header_node(struct inode *attr_file,
131                                         u32 clump_size,
132                                         char *buf, u16 node_size)
133 {
134         struct hfs_bnode_desc *desc;
135         struct hfs_btree_header_rec *head;
136         u16 offset;
137         __be16 *rec_offsets;
138         u32 hdr_node_map_rec_bits;
139         char *bmp;
140         u32 used_nodes;
141         u32 used_bmp_bytes;
142         loff_t tmp;
143
144         hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n",
145                                 clump_size, node_size);
146
147         /* The end of the node contains list of record offsets */
148         rec_offsets = (__be16 *)(buf + node_size);
149
150         desc = (struct hfs_bnode_desc *)buf;
151         desc->type = HFS_NODE_HEADER;
152         desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT);
153         offset = sizeof(struct hfs_bnode_desc);
154         *--rec_offsets = cpu_to_be16(offset);
155
156         head = (struct hfs_btree_header_rec *)(buf + offset);
157         head->node_size = cpu_to_be16(node_size);
158         tmp = i_size_read(attr_file);
159         do_div(tmp, node_size);
160         head->node_count = cpu_to_be32(tmp);
161         head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1);
162         head->clump_size = cpu_to_be32(clump_size);
163         head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS);
164         head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16));
165         offset += sizeof(struct hfs_btree_header_rec);
166         *--rec_offsets = cpu_to_be16(offset);
167         offset += HFSPLUS_BTREE_HDR_USER_BYTES;
168         *--rec_offsets = cpu_to_be16(offset);
169
170         hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16)));
171         if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) {
172                 u32 map_node_bits;
173                 u32 map_nodes;
174
175                 desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1);
176                 map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) -
177                                         (2 * sizeof(u16)) - 2);
178                 map_nodes = (be32_to_cpu(head->node_count) -
179                                 hdr_node_map_rec_bits +
180                                 (map_node_bits - 1)) / map_node_bits;
181                 be32_add_cpu(&head->free_nodes, 0 - map_nodes);
182         }
183
184         bmp = buf + offset;
185         used_nodes =
186                 be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes);
187         used_bmp_bytes = used_nodes / 8;
188         if (used_bmp_bytes) {
189                 memset(bmp, 0xFF, used_bmp_bytes);
190                 bmp += used_bmp_bytes;
191                 used_nodes %= 8;
192         }
193         *bmp = ~(0xFF >> used_nodes);
194         offset += hdr_node_map_rec_bits / 8;
195         *--rec_offsets = cpu_to_be16(offset);
196 }
197
198 static int hfsplus_create_attributes_file(struct super_block *sb)
199 {
200         int err = 0;
201         struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
202         struct inode *attr_file;
203         struct hfsplus_inode_info *hip;
204         u32 clump_size;
205         u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE;
206         char *buf;
207         int index, written;
208         struct address_space *mapping;
209         struct page *page;
210         int old_state = HFSPLUS_EMPTY_ATTR_TREE;
211
212         hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
213
214 check_attr_tree_state_again:
215         switch (atomic_read(&sbi->attr_tree_state)) {
216         case HFSPLUS_EMPTY_ATTR_TREE:
217                 if (old_state != atomic_cmpxchg(&sbi->attr_tree_state,
218                                                 old_state,
219                                                 HFSPLUS_CREATING_ATTR_TREE))
220                         goto check_attr_tree_state_again;
221                 break;
222         case HFSPLUS_CREATING_ATTR_TREE:
223                 /*
224                  * This state means that another thread is in process
225                  * of AttributesFile creation. Theoretically, it is
226                  * possible to be here. But really __setxattr() method
227                  * first of all calls hfs_find_init() for lookup in
228                  * B-tree of CatalogFile. This method locks mutex of
229                  * CatalogFile's B-tree. As a result, if some thread
230                  * is inside AttributedFile creation operation then
231                  * another threads will be waiting unlocking of
232                  * CatalogFile's B-tree's mutex. However, if code will
233                  * change then we will return error code (-EAGAIN) from
234                  * here. Really, it means that first try to set of xattr
235                  * fails with error but second attempt will have success.
236                  */
237                 return -EAGAIN;
238         case HFSPLUS_VALID_ATTR_TREE:
239                 return 0;
240         case HFSPLUS_FAILED_ATTR_TREE:
241                 return -EOPNOTSUPP;
242         default:
243                 BUG();
244         }
245
246         attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID);
247         if (IS_ERR(attr_file)) {
248                 pr_err("failed to load attributes file\n");
249                 return PTR_ERR(attr_file);
250         }
251
252         BUG_ON(i_size_read(attr_file) != 0);
253
254         hip = HFSPLUS_I(attr_file);
255
256         clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize,
257                                                     node_size,
258                                                     sbi->sect_count,
259                                                     HFSPLUS_ATTR_CNID);
260
261         mutex_lock(&hip->extents_lock);
262         hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift;
263         mutex_unlock(&hip->extents_lock);
264
265         if (sbi->free_blocks <= (hip->clump_blocks << 1)) {
266                 err = -ENOSPC;
267                 goto end_attr_file_creation;
268         }
269
270         while (hip->alloc_blocks < hip->clump_blocks) {
271                 err = hfsplus_file_extend(attr_file);
272                 if (unlikely(err)) {
273                         pr_err("failed to extend attributes file\n");
274                         goto end_attr_file_creation;
275                 }
276                 hip->phys_size = attr_file->i_size =
277                         (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift;
278                 hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift;
279                 inode_set_bytes(attr_file, attr_file->i_size);
280         }
281
282         buf = kzalloc(node_size, GFP_NOFS);
283         if (!buf) {
284                 pr_err("failed to allocate memory for header node\n");
285                 err = -ENOMEM;
286                 goto end_attr_file_creation;
287         }
288
289         hfsplus_init_header_node(attr_file, clump_size, buf, node_size);
290
291         mapping = attr_file->i_mapping;
292
293         index = 0;
294         written = 0;
295         for (; written < node_size; index++, written += PAGE_CACHE_SIZE) {
296                 void *kaddr;
297
298                 page = read_mapping_page(mapping, index, NULL);
299                 if (IS_ERR(page)) {
300                         err = PTR_ERR(page);
301                         goto failed_header_node_init;
302                 }
303
304                 kaddr = kmap_atomic(page);
305                 memcpy(kaddr, buf + written,
306                         min_t(size_t, PAGE_CACHE_SIZE, node_size - written));
307                 kunmap_atomic(kaddr);
308
309                 set_page_dirty(page);
310                 page_cache_release(page);
311         }
312
313         hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY);
314
315         sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
316         if (!sbi->attr_tree)
317                 pr_err("failed to load attributes file\n");
318
319 failed_header_node_init:
320         kfree(buf);
321
322 end_attr_file_creation:
323         iput(attr_file);
324
325         if (!err)
326                 atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
327         else if (err == -ENOSPC)
328                 atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
329         else
330                 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE);
331
332         return err;
333 }
334
335 int __hfsplus_setxattr(struct inode *inode, const char *name,
336                         const void *value, size_t size, int flags)
337 {
338         int err = 0;
339         struct hfs_find_data cat_fd;
340         hfsplus_cat_entry entry;
341         u16 cat_entry_flags, cat_entry_type;
342         u16 folder_finderinfo_len = sizeof(struct DInfo) +
343                                         sizeof(struct DXInfo);
344         u16 file_finderinfo_len = sizeof(struct FInfo) +
345                                         sizeof(struct FXInfo);
346
347         if ((!S_ISREG(inode->i_mode) &&
348                         !S_ISDIR(inode->i_mode)) ||
349                                 HFSPLUS_IS_RSRC(inode))
350                 return -EOPNOTSUPP;
351
352         err = can_set_xattr(inode, name, value, size);
353         if (err)
354                 return err;
355
356         if (strncmp(name, XATTR_MAC_OSX_PREFIX,
357                                 XATTR_MAC_OSX_PREFIX_LEN) == 0)
358                 name += XATTR_MAC_OSX_PREFIX_LEN;
359
360         if (value == NULL) {
361                 value = "";
362                 size = 0;
363         }
364
365         err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
366         if (err) {
367                 pr_err("can't init xattr find struct\n");
368                 return err;
369         }
370
371         err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
372         if (err) {
373                 pr_err("catalog searching failed\n");
374                 goto end_setxattr;
375         }
376
377         if (!strcmp_xattr_finder_info(name)) {
378                 if (flags & XATTR_CREATE) {
379                         pr_err("xattr exists yet\n");
380                         err = -EOPNOTSUPP;
381                         goto end_setxattr;
382                 }
383                 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset,
384                                         sizeof(hfsplus_cat_entry));
385                 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) {
386                         if (size == folder_finderinfo_len) {
387                                 memcpy(&entry.folder.user_info, value,
388                                                 folder_finderinfo_len);
389                                 hfs_bnode_write(cat_fd.bnode, &entry,
390                                         cat_fd.entryoffset,
391                                         sizeof(struct hfsplus_cat_folder));
392                                 hfsplus_mark_inode_dirty(inode,
393                                                 HFSPLUS_I_CAT_DIRTY);
394                         } else {
395                                 err = -ERANGE;
396                                 goto end_setxattr;
397                         }
398                 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) {
399                         if (size == file_finderinfo_len) {
400                                 memcpy(&entry.file.user_info, value,
401                                                 file_finderinfo_len);
402                                 hfs_bnode_write(cat_fd.bnode, &entry,
403                                         cat_fd.entryoffset,
404                                         sizeof(struct hfsplus_cat_file));
405                                 hfsplus_mark_inode_dirty(inode,
406                                                 HFSPLUS_I_CAT_DIRTY);
407                         } else {
408                                 err = -ERANGE;
409                                 goto end_setxattr;
410                         }
411                 } else {
412                         err = -EOPNOTSUPP;
413                         goto end_setxattr;
414                 }
415                 goto end_setxattr;
416         }
417
418         if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
419                 err = hfsplus_create_attributes_file(inode->i_sb);
420                 if (unlikely(err))
421                         goto end_setxattr;
422         }
423
424         if (hfsplus_attr_exists(inode, name)) {
425                 if (flags & XATTR_CREATE) {
426                         pr_err("xattr exists yet\n");
427                         err = -EOPNOTSUPP;
428                         goto end_setxattr;
429                 }
430                 err = hfsplus_delete_attr(inode, name);
431                 if (err)
432                         goto end_setxattr;
433                 err = hfsplus_create_attr(inode, name, value, size);
434                 if (err)
435                         goto end_setxattr;
436         } else {
437                 if (flags & XATTR_REPLACE) {
438                         pr_err("cannot replace xattr\n");
439                         err = -EOPNOTSUPP;
440                         goto end_setxattr;
441                 }
442                 err = hfsplus_create_attr(inode, name, value, size);
443                 if (err)
444                         goto end_setxattr;
445         }
446
447         cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
448         if (cat_entry_type == HFSPLUS_FOLDER) {
449                 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
450                                     cat_fd.entryoffset +
451                                     offsetof(struct hfsplus_cat_folder, flags));
452                 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
453                 if (!strcmp_xattr_acl(name))
454                         cat_entry_flags |= HFSPLUS_ACL_EXISTS;
455                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
456                                 offsetof(struct hfsplus_cat_folder, flags),
457                                 cat_entry_flags);
458                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
459         } else if (cat_entry_type == HFSPLUS_FILE) {
460                 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
461                                     cat_fd.entryoffset +
462                                     offsetof(struct hfsplus_cat_file, flags));
463                 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
464                 if (!strcmp_xattr_acl(name))
465                         cat_entry_flags |= HFSPLUS_ACL_EXISTS;
466                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
467                                     offsetof(struct hfsplus_cat_file, flags),
468                                     cat_entry_flags);
469                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
470         } else {
471                 pr_err("invalid catalog entry type\n");
472                 err = -EIO;
473                 goto end_setxattr;
474         }
475
476 end_setxattr:
477         hfs_find_exit(&cat_fd);
478         return err;
479 }
480
481 static inline int is_osx_xattr(const char *xattr_name)
482 {
483         return !is_known_namespace(xattr_name);
484 }
485
486 static int name_len(const char *xattr_name, int xattr_name_len)
487 {
488         int len = xattr_name_len + 1;
489
490         if (is_osx_xattr(xattr_name))
491                 len += XATTR_MAC_OSX_PREFIX_LEN;
492
493         return len;
494 }
495
496 static int copy_name(char *buffer, const char *xattr_name, int name_len)
497 {
498         int len = name_len;
499         int offset = 0;
500
501         if (is_osx_xattr(xattr_name)) {
502                 strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
503                 offset += XATTR_MAC_OSX_PREFIX_LEN;
504                 len += XATTR_MAC_OSX_PREFIX_LEN;
505         }
506
507         strncpy(buffer + offset, xattr_name, name_len);
508         memset(buffer + offset + name_len, 0, 1);
509         len += 1;
510
511         return len;
512 }
513
514 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode,
515                                                 void *value, size_t size)
516 {
517         ssize_t res = 0;
518         struct hfs_find_data fd;
519         u16 entry_type;
520         u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo);
521         u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo);
522         u16 record_len = max(folder_rec_len, file_rec_len);
523         u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
524         u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
525
526         if (size >= record_len) {
527                 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
528                 if (res) {
529                         pr_err("can't init xattr find struct\n");
530                         return res;
531                 }
532                 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
533                 if (res)
534                         goto end_getxattr_finder_info;
535                 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
536
537                 if (entry_type == HFSPLUS_FOLDER) {
538                         hfs_bnode_read(fd.bnode, folder_finder_info,
539                                 fd.entryoffset +
540                                 offsetof(struct hfsplus_cat_folder, user_info),
541                                 folder_rec_len);
542                         memcpy(value, folder_finder_info, folder_rec_len);
543                         res = folder_rec_len;
544                 } else if (entry_type == HFSPLUS_FILE) {
545                         hfs_bnode_read(fd.bnode, file_finder_info,
546                                 fd.entryoffset +
547                                 offsetof(struct hfsplus_cat_file, user_info),
548                                 file_rec_len);
549                         memcpy(value, file_finder_info, file_rec_len);
550                         res = file_rec_len;
551                 } else {
552                         res = -EOPNOTSUPP;
553                         goto end_getxattr_finder_info;
554                 }
555         } else
556                 res = size ? -ERANGE : record_len;
557
558 end_getxattr_finder_info:
559         if (size >= record_len)
560                 hfs_find_exit(&fd);
561         return res;
562 }
563
564 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
565                          void *value, size_t size)
566 {
567         struct hfs_find_data fd;
568         hfsplus_attr_entry *entry;
569         __be32 xattr_record_type;
570         u32 record_type;
571         u16 record_length = 0;
572         ssize_t res = 0;
573
574         if ((!S_ISREG(inode->i_mode) &&
575                         !S_ISDIR(inode->i_mode)) ||
576                                 HFSPLUS_IS_RSRC(inode))
577                 return -EOPNOTSUPP;
578
579         if (strncmp(name, XATTR_MAC_OSX_PREFIX,
580                                 XATTR_MAC_OSX_PREFIX_LEN) == 0) {
581                 /* skip "osx." prefix */
582                 name += XATTR_MAC_OSX_PREFIX_LEN;
583                 /*
584                  * Don't allow retrieving properly prefixed attributes
585                  * by prepending them with "osx."
586                  */
587                 if (is_known_namespace(name))
588                         return -EOPNOTSUPP;
589         }
590
591         if (!strcmp_xattr_finder_info(name))
592                 return hfsplus_getxattr_finder_info(inode, value, size);
593
594         if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
595                 return -EOPNOTSUPP;
596
597         entry = hfsplus_alloc_attr_entry();
598         if (!entry) {
599                 pr_err("can't allocate xattr entry\n");
600                 return -ENOMEM;
601         }
602
603         res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
604         if (res) {
605                 pr_err("can't init xattr find struct\n");
606                 goto failed_getxattr_init;
607         }
608
609         res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
610         if (res) {
611                 if (res == -ENOENT)
612                         res = -ENODATA;
613                 else
614                         pr_err("xattr searching failed\n");
615                 goto out;
616         }
617
618         hfs_bnode_read(fd.bnode, &xattr_record_type,
619                         fd.entryoffset, sizeof(xattr_record_type));
620         record_type = be32_to_cpu(xattr_record_type);
621         if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
622                 record_length = hfs_bnode_read_u16(fd.bnode,
623                                 fd.entryoffset +
624                                 offsetof(struct hfsplus_attr_inline_data,
625                                 length));
626                 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
627                         pr_err("invalid xattr record size\n");
628                         res = -EIO;
629                         goto out;
630                 }
631         } else if (record_type == HFSPLUS_ATTR_FORK_DATA ||
632                         record_type == HFSPLUS_ATTR_EXTENTS) {
633                 pr_err("only inline data xattr are supported\n");
634                 res = -EOPNOTSUPP;
635                 goto out;
636         } else {
637                 pr_err("invalid xattr record\n");
638                 res = -EIO;
639                 goto out;
640         }
641
642         if (size) {
643                 hfs_bnode_read(fd.bnode, entry, fd.entryoffset,
644                                 offsetof(struct hfsplus_attr_inline_data,
645                                         raw_bytes) + record_length);
646         }
647
648         if (size >= record_length) {
649                 memcpy(value, entry->inline_data.raw_bytes, record_length);
650                 res = record_length;
651         } else
652                 res = size ? -ERANGE : record_length;
653
654 out:
655         hfs_find_exit(&fd);
656
657 failed_getxattr_init:
658         hfsplus_destroy_attr_entry(entry);
659         return res;
660 }
661
662 static inline int can_list(const char *xattr_name)
663 {
664         if (!xattr_name)
665                 return 0;
666
667         return strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
668                         XATTR_TRUSTED_PREFIX_LEN) ||
669                                 capable(CAP_SYS_ADMIN);
670 }
671
672 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
673                                                 char *buffer, size_t size)
674 {
675         ssize_t res = 0;
676         struct inode *inode = dentry->d_inode;
677         struct hfs_find_data fd;
678         u16 entry_type;
679         u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
680         u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
681         unsigned long len, found_bit;
682         int xattr_name_len, symbols_count;
683
684         res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
685         if (res) {
686                 pr_err("can't init xattr find struct\n");
687                 return res;
688         }
689
690         res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
691         if (res)
692                 goto end_listxattr_finder_info;
693
694         entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
695         if (entry_type == HFSPLUS_FOLDER) {
696                 len = sizeof(struct DInfo) + sizeof(struct DXInfo);
697                 hfs_bnode_read(fd.bnode, folder_finder_info,
698                                 fd.entryoffset +
699                                 offsetof(struct hfsplus_cat_folder, user_info),
700                                 len);
701                 found_bit = find_first_bit((void *)folder_finder_info, len*8);
702         } else if (entry_type == HFSPLUS_FILE) {
703                 len = sizeof(struct FInfo) + sizeof(struct FXInfo);
704                 hfs_bnode_read(fd.bnode, file_finder_info,
705                                 fd.entryoffset +
706                                 offsetof(struct hfsplus_cat_file, user_info),
707                                 len);
708                 found_bit = find_first_bit((void *)file_finder_info, len*8);
709         } else {
710                 res = -EOPNOTSUPP;
711                 goto end_listxattr_finder_info;
712         }
713
714         if (found_bit >= (len*8))
715                 res = 0;
716         else {
717                 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1;
718                 xattr_name_len =
719                         name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count);
720                 if (!buffer || !size) {
721                         if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME))
722                                 res = xattr_name_len;
723                 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) {
724                         if (size < xattr_name_len)
725                                 res = -ERANGE;
726                         else {
727                                 res = copy_name(buffer,
728                                                 HFSPLUS_XATTR_FINDER_INFO_NAME,
729                                                 symbols_count);
730                         }
731                 }
732         }
733
734 end_listxattr_finder_info:
735         hfs_find_exit(&fd);
736
737         return res;
738 }
739
740 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
741 {
742         ssize_t err;
743         ssize_t res = 0;
744         struct inode *inode = dentry->d_inode;
745         struct hfs_find_data fd;
746         u16 key_len = 0;
747         struct hfsplus_attr_key attr_key;
748         char strbuf[HFSPLUS_ATTR_MAX_STRLEN +
749                         XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
750         int xattr_name_len;
751
752         if ((!S_ISREG(inode->i_mode) &&
753                         !S_ISDIR(inode->i_mode)) ||
754                                 HFSPLUS_IS_RSRC(inode))
755                 return -EOPNOTSUPP;
756
757         res = hfsplus_listxattr_finder_info(dentry, buffer, size);
758         if (res < 0)
759                 return res;
760         else if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
761                 return (res == 0) ? -EOPNOTSUPP : res;
762
763         err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
764         if (err) {
765                 pr_err("can't init xattr find struct\n");
766                 return err;
767         }
768
769         err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
770         if (err) {
771                 if (err == -ENOENT) {
772                         if (res == 0)
773                                 res = -ENODATA;
774                         goto end_listxattr;
775                 } else {
776                         res = err;
777                         goto end_listxattr;
778                 }
779         }
780
781         for (;;) {
782                 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
783                 if (key_len == 0 || key_len > fd.tree->max_key_len) {
784                         pr_err("invalid xattr key length: %d\n", key_len);
785                         res = -EIO;
786                         goto end_listxattr;
787                 }
788
789                 hfs_bnode_read(fd.bnode, &attr_key,
790                                 fd.keyoffset, key_len + sizeof(key_len));
791
792                 if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
793                         goto end_listxattr;
794
795                 xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN;
796                 if (hfsplus_uni2asc(inode->i_sb,
797                         (const struct hfsplus_unistr *)&fd.key->attr.key_name,
798                                         strbuf, &xattr_name_len)) {
799                         pr_err("unicode conversion failed\n");
800                         res = -EIO;
801                         goto end_listxattr;
802                 }
803
804                 if (!buffer || !size) {
805                         if (can_list(strbuf))
806                                 res += name_len(strbuf, xattr_name_len);
807                 } else if (can_list(strbuf)) {
808                         if (size < (res + name_len(strbuf, xattr_name_len))) {
809                                 res = -ERANGE;
810                                 goto end_listxattr;
811                         } else
812                                 res += copy_name(buffer + res,
813                                                 strbuf, xattr_name_len);
814                 }
815
816                 if (hfs_brec_goto(&fd, 1))
817                         goto end_listxattr;
818         }
819
820 end_listxattr:
821         hfs_find_exit(&fd);
822         return res;
823 }
824
825 int hfsplus_removexattr(struct dentry *dentry, const char *name)
826 {
827         int err = 0;
828         struct inode *inode = dentry->d_inode;
829         struct hfs_find_data cat_fd;
830         u16 flags;
831         u16 cat_entry_type;
832         int is_xattr_acl_deleted = 0;
833         int is_all_xattrs_deleted = 0;
834
835         if ((!S_ISREG(inode->i_mode) &&
836                         !S_ISDIR(inode->i_mode)) ||
837                                 HFSPLUS_IS_RSRC(inode))
838                 return -EOPNOTSUPP;
839
840         if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
841                 return -EOPNOTSUPP;
842
843         err = can_set_xattr(inode, name, NULL, 0);
844         if (err)
845                 return err;
846
847         if (strncmp(name, XATTR_MAC_OSX_PREFIX,
848                                 XATTR_MAC_OSX_PREFIX_LEN) == 0)
849                 name += XATTR_MAC_OSX_PREFIX_LEN;
850
851         if (!strcmp_xattr_finder_info(name))
852                 return -EOPNOTSUPP;
853
854         err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
855         if (err) {
856                 pr_err("can't init xattr find struct\n");
857                 return err;
858         }
859
860         err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
861         if (err) {
862                 pr_err("catalog searching failed\n");
863                 goto end_removexattr;
864         }
865
866         err = hfsplus_delete_attr(inode, name);
867         if (err)
868                 goto end_removexattr;
869
870         is_xattr_acl_deleted = !strcmp_xattr_acl(name);
871         is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
872
873         if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
874                 goto end_removexattr;
875
876         cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
877
878         if (cat_entry_type == HFSPLUS_FOLDER) {
879                 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
880                                 offsetof(struct hfsplus_cat_folder, flags));
881                 if (is_xattr_acl_deleted)
882                         flags &= ~HFSPLUS_ACL_EXISTS;
883                 if (is_all_xattrs_deleted)
884                         flags &= ~HFSPLUS_XATTR_EXISTS;
885                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
886                                 offsetof(struct hfsplus_cat_folder, flags),
887                                 flags);
888                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
889         } else if (cat_entry_type == HFSPLUS_FILE) {
890                 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
891                                 offsetof(struct hfsplus_cat_file, flags));
892                 if (is_xattr_acl_deleted)
893                         flags &= ~HFSPLUS_ACL_EXISTS;
894                 if (is_all_xattrs_deleted)
895                         flags &= ~HFSPLUS_XATTR_EXISTS;
896                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
897                                 offsetof(struct hfsplus_cat_file, flags),
898                                 flags);
899                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
900         } else {
901                 pr_err("invalid catalog entry type\n");
902                 err = -EIO;
903                 goto end_removexattr;
904         }
905
906 end_removexattr:
907         hfs_find_exit(&cat_fd);
908         return err;
909 }
910
911 static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
912                                         void *buffer, size_t size, int type)
913 {
914         char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
915                                 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
916         size_t len = strlen(name);
917
918         if (!strcmp(name, ""))
919                 return -EINVAL;
920
921         if (len > HFSPLUS_ATTR_MAX_STRLEN)
922                 return -EOPNOTSUPP;
923
924         strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
925         strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
926
927         return hfsplus_getxattr(dentry, xattr_name, buffer, size);
928 }
929
930 static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
931                 const void *buffer, size_t size, int flags, int type)
932 {
933         char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
934                                 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
935         size_t len = strlen(name);
936
937         if (!strcmp(name, ""))
938                 return -EINVAL;
939
940         if (len > HFSPLUS_ATTR_MAX_STRLEN)
941                 return -EOPNOTSUPP;
942
943         strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
944         strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
945
946         return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags);
947 }
948
949 static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list,
950                 size_t list_size, const char *name, size_t name_len, int type)
951 {
952         /*
953          * This method is not used.
954          * It is used hfsplus_listxattr() instead of generic_listxattr().
955          */
956         return -EOPNOTSUPP;
957 }
958
959 const struct xattr_handler hfsplus_xattr_osx_handler = {
960         .prefix = XATTR_MAC_OSX_PREFIX,
961         .list   = hfsplus_osx_listxattr,
962         .get    = hfsplus_osx_getxattr,
963         .set    = hfsplus_osx_setxattr,
964 };