Merge branch 'for-3.9-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[linux.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
12 const struct xattr_handler *hfsplus_xattr_handlers[] = {
13         &hfsplus_xattr_osx_handler,
14         &hfsplus_xattr_user_handler,
15         &hfsplus_xattr_trusted_handler,
16         &hfsplus_xattr_security_handler,
17         NULL
18 };
19
20 static int strcmp_xattr_finder_info(const char *name)
21 {
22         if (name) {
23                 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME,
24                                 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME));
25         }
26         return -1;
27 }
28
29 static int strcmp_xattr_acl(const char *name)
30 {
31         if (name) {
32                 return strncmp(name, HFSPLUS_XATTR_ACL_NAME,
33                                 sizeof(HFSPLUS_XATTR_ACL_NAME));
34         }
35         return -1;
36 }
37
38 static inline int is_known_namespace(const char *name)
39 {
40         if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) &&
41             strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
42             strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
43             strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
44                 return false;
45
46         return true;
47 }
48
49 static int can_set_xattr(struct inode *inode, const char *name,
50                                 const void *value, size_t value_len)
51 {
52         if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
53                 return -EOPNOTSUPP; /* TODO: implement ACL support */
54
55         if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
56                 /*
57                  * This makes sure that we aren't trying to set an
58                  * attribute in a different namespace by prefixing it
59                  * with "osx."
60                  */
61                 if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
62                         return -EOPNOTSUPP;
63
64                 return 0;
65         }
66
67         /*
68          * Don't allow setting an attribute in an unknown namespace.
69          */
70         if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&
71             strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
72             strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
73                 return -EOPNOTSUPP;
74
75         return 0;
76 }
77
78 int __hfsplus_setxattr(struct inode *inode, const char *name,
79                         const void *value, size_t size, int flags)
80 {
81         int err = 0;
82         struct hfs_find_data cat_fd;
83         hfsplus_cat_entry entry;
84         u16 cat_entry_flags, cat_entry_type;
85         u16 folder_finderinfo_len = sizeof(struct DInfo) +
86                                         sizeof(struct DXInfo);
87         u16 file_finderinfo_len = sizeof(struct FInfo) +
88                                         sizeof(struct FXInfo);
89
90         if ((!S_ISREG(inode->i_mode) &&
91                         !S_ISDIR(inode->i_mode)) ||
92                                 HFSPLUS_IS_RSRC(inode))
93                 return -EOPNOTSUPP;
94
95         err = can_set_xattr(inode, name, value, size);
96         if (err)
97                 return err;
98
99         if (strncmp(name, XATTR_MAC_OSX_PREFIX,
100                                 XATTR_MAC_OSX_PREFIX_LEN) == 0)
101                 name += XATTR_MAC_OSX_PREFIX_LEN;
102
103         if (value == NULL) {
104                 value = "";
105                 size = 0;
106         }
107
108         err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
109         if (err) {
110                 printk(KERN_ERR "hfs: can't init xattr find struct\n");
111                 return err;
112         }
113
114         err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
115         if (err) {
116                 printk(KERN_ERR "hfs: catalog searching failed\n");
117                 goto end_setxattr;
118         }
119
120         if (!strcmp_xattr_finder_info(name)) {
121                 if (flags & XATTR_CREATE) {
122                         printk(KERN_ERR "hfs: xattr exists yet\n");
123                         err = -EOPNOTSUPP;
124                         goto end_setxattr;
125                 }
126                 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset,
127                                         sizeof(hfsplus_cat_entry));
128                 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) {
129                         if (size == folder_finderinfo_len) {
130                                 memcpy(&entry.folder.user_info, value,
131                                                 folder_finderinfo_len);
132                                 hfs_bnode_write(cat_fd.bnode, &entry,
133                                         cat_fd.entryoffset,
134                                         sizeof(struct hfsplus_cat_folder));
135                                 hfsplus_mark_inode_dirty(inode,
136                                                 HFSPLUS_I_CAT_DIRTY);
137                         } else {
138                                 err = -ERANGE;
139                                 goto end_setxattr;
140                         }
141                 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) {
142                         if (size == file_finderinfo_len) {
143                                 memcpy(&entry.file.user_info, value,
144                                                 file_finderinfo_len);
145                                 hfs_bnode_write(cat_fd.bnode, &entry,
146                                         cat_fd.entryoffset,
147                                         sizeof(struct hfsplus_cat_file));
148                                 hfsplus_mark_inode_dirty(inode,
149                                                 HFSPLUS_I_CAT_DIRTY);
150                         } else {
151                                 err = -ERANGE;
152                                 goto end_setxattr;
153                         }
154                 } else {
155                         err = -EOPNOTSUPP;
156                         goto end_setxattr;
157                 }
158                 goto end_setxattr;
159         }
160
161         if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
162                 err = -EOPNOTSUPP;
163                 goto end_setxattr;
164         }
165
166         if (hfsplus_attr_exists(inode, name)) {
167                 if (flags & XATTR_CREATE) {
168                         printk(KERN_ERR "hfs: xattr exists yet\n");
169                         err = -EOPNOTSUPP;
170                         goto end_setxattr;
171                 }
172                 err = hfsplus_delete_attr(inode, name);
173                 if (err)
174                         goto end_setxattr;
175                 err = hfsplus_create_attr(inode, name, value, size);
176                 if (err)
177                         goto end_setxattr;
178         } else {
179                 if (flags & XATTR_REPLACE) {
180                         printk(KERN_ERR "hfs: cannot replace xattr\n");
181                         err = -EOPNOTSUPP;
182                         goto end_setxattr;
183                 }
184                 err = hfsplus_create_attr(inode, name, value, size);
185                 if (err)
186                         goto end_setxattr;
187         }
188
189         cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
190         if (cat_entry_type == HFSPLUS_FOLDER) {
191                 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
192                                     cat_fd.entryoffset +
193                                     offsetof(struct hfsplus_cat_folder, flags));
194                 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
195                 if (!strcmp_xattr_acl(name))
196                         cat_entry_flags |= HFSPLUS_ACL_EXISTS;
197                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
198                                 offsetof(struct hfsplus_cat_folder, flags),
199                                 cat_entry_flags);
200                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
201         } else if (cat_entry_type == HFSPLUS_FILE) {
202                 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
203                                     cat_fd.entryoffset +
204                                     offsetof(struct hfsplus_cat_file, flags));
205                 cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
206                 if (!strcmp_xattr_acl(name))
207                         cat_entry_flags |= HFSPLUS_ACL_EXISTS;
208                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
209                                     offsetof(struct hfsplus_cat_file, flags),
210                                     cat_entry_flags);
211                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
212         } else {
213                 printk(KERN_ERR "hfs: invalid catalog entry type\n");
214                 err = -EIO;
215                 goto end_setxattr;
216         }
217
218 end_setxattr:
219         hfs_find_exit(&cat_fd);
220         return err;
221 }
222
223 static inline int is_osx_xattr(const char *xattr_name)
224 {
225         return !is_known_namespace(xattr_name);
226 }
227
228 static int name_len(const char *xattr_name, int xattr_name_len)
229 {
230         int len = xattr_name_len + 1;
231
232         if (is_osx_xattr(xattr_name))
233                 len += XATTR_MAC_OSX_PREFIX_LEN;
234
235         return len;
236 }
237
238 static int copy_name(char *buffer, const char *xattr_name, int name_len)
239 {
240         int len = name_len;
241         int offset = 0;
242
243         if (is_osx_xattr(xattr_name)) {
244                 strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
245                 offset += XATTR_MAC_OSX_PREFIX_LEN;
246                 len += XATTR_MAC_OSX_PREFIX_LEN;
247         }
248
249         strncpy(buffer + offset, xattr_name, name_len);
250         memset(buffer + offset + name_len, 0, 1);
251         len += 1;
252
253         return len;
254 }
255
256 static ssize_t hfsplus_getxattr_finder_info(struct dentry *dentry,
257                                                 void *value, size_t size)
258 {
259         ssize_t res = 0;
260         struct inode *inode = dentry->d_inode;
261         struct hfs_find_data fd;
262         u16 entry_type;
263         u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo);
264         u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo);
265         u16 record_len = max(folder_rec_len, file_rec_len);
266         u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
267         u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
268
269         if (size >= record_len) {
270                 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
271                 if (res) {
272                         printk(KERN_ERR "hfs: can't init xattr find struct\n");
273                         return res;
274                 }
275                 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
276                 if (res)
277                         goto end_getxattr_finder_info;
278                 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
279
280                 if (entry_type == HFSPLUS_FOLDER) {
281                         hfs_bnode_read(fd.bnode, folder_finder_info,
282                                 fd.entryoffset +
283                                 offsetof(struct hfsplus_cat_folder, user_info),
284                                 folder_rec_len);
285                         memcpy(value, folder_finder_info, folder_rec_len);
286                         res = folder_rec_len;
287                 } else if (entry_type == HFSPLUS_FILE) {
288                         hfs_bnode_read(fd.bnode, file_finder_info,
289                                 fd.entryoffset +
290                                 offsetof(struct hfsplus_cat_file, user_info),
291                                 file_rec_len);
292                         memcpy(value, file_finder_info, file_rec_len);
293                         res = file_rec_len;
294                 } else {
295                         res = -EOPNOTSUPP;
296                         goto end_getxattr_finder_info;
297                 }
298         } else
299                 res = size ? -ERANGE : record_len;
300
301 end_getxattr_finder_info:
302         if (size >= record_len)
303                 hfs_find_exit(&fd);
304         return res;
305 }
306
307 ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
308                          void *value, size_t size)
309 {
310         struct inode *inode = dentry->d_inode;
311         struct hfs_find_data fd;
312         hfsplus_attr_entry *entry;
313         __be32 xattr_record_type;
314         u32 record_type;
315         u16 record_length = 0;
316         ssize_t res = 0;
317
318         if ((!S_ISREG(inode->i_mode) &&
319                         !S_ISDIR(inode->i_mode)) ||
320                                 HFSPLUS_IS_RSRC(inode))
321                 return -EOPNOTSUPP;
322
323         if (strncmp(name, XATTR_MAC_OSX_PREFIX,
324                                 XATTR_MAC_OSX_PREFIX_LEN) == 0) {
325                 /* skip "osx." prefix */
326                 name += XATTR_MAC_OSX_PREFIX_LEN;
327                 /*
328                  * Don't allow retrieving properly prefixed attributes
329                  * by prepending them with "osx."
330                  */
331                 if (is_known_namespace(name))
332                         return -EOPNOTSUPP;
333         }
334
335         if (!strcmp_xattr_finder_info(name))
336                 return hfsplus_getxattr_finder_info(dentry, value, size);
337
338         if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
339                 return -EOPNOTSUPP;
340
341         entry = hfsplus_alloc_attr_entry();
342         if (!entry) {
343                 printk(KERN_ERR "hfs: can't allocate xattr entry\n");
344                 return -ENOMEM;
345         }
346
347         res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
348         if (res) {
349                 printk(KERN_ERR "hfs: can't init xattr find struct\n");
350                 goto failed_getxattr_init;
351         }
352
353         res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
354         if (res) {
355                 if (res == -ENOENT)
356                         res = -ENODATA;
357                 else
358                         printk(KERN_ERR "hfs: xattr searching failed\n");
359                 goto out;
360         }
361
362         hfs_bnode_read(fd.bnode, &xattr_record_type,
363                         fd.entryoffset, sizeof(xattr_record_type));
364         record_type = be32_to_cpu(xattr_record_type);
365         if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
366                 record_length = hfs_bnode_read_u16(fd.bnode,
367                                 fd.entryoffset +
368                                 offsetof(struct hfsplus_attr_inline_data,
369                                 length));
370                 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
371                         printk(KERN_ERR "hfs: invalid xattr record size\n");
372                         res = -EIO;
373                         goto out;
374                 }
375         } else if (record_type == HFSPLUS_ATTR_FORK_DATA ||
376                         record_type == HFSPLUS_ATTR_EXTENTS) {
377                 printk(KERN_ERR "hfs: only inline data xattr are supported\n");
378                 res = -EOPNOTSUPP;
379                 goto out;
380         } else {
381                 printk(KERN_ERR "hfs: invalid xattr record\n");
382                 res = -EIO;
383                 goto out;
384         }
385
386         if (size) {
387                 hfs_bnode_read(fd.bnode, entry, fd.entryoffset,
388                                 offsetof(struct hfsplus_attr_inline_data,
389                                         raw_bytes) + record_length);
390         }
391
392         if (size >= record_length) {
393                 memcpy(value, entry->inline_data.raw_bytes, record_length);
394                 res = record_length;
395         } else
396                 res = size ? -ERANGE : record_length;
397
398 out:
399         hfs_find_exit(&fd);
400
401 failed_getxattr_init:
402         hfsplus_destroy_attr_entry(entry);
403         return res;
404 }
405
406 static inline int can_list(const char *xattr_name)
407 {
408         if (!xattr_name)
409                 return 0;
410
411         return strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
412                         XATTR_TRUSTED_PREFIX_LEN) ||
413                                 capable(CAP_SYS_ADMIN);
414 }
415
416 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
417                                                 char *buffer, size_t size)
418 {
419         ssize_t res = 0;
420         struct inode *inode = dentry->d_inode;
421         struct hfs_find_data fd;
422         u16 entry_type;
423         u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
424         u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
425         unsigned long len, found_bit;
426         int xattr_name_len, symbols_count;
427
428         res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
429         if (res) {
430                 printk(KERN_ERR "hfs: can't init xattr find struct\n");
431                 return res;
432         }
433
434         res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
435         if (res)
436                 goto end_listxattr_finder_info;
437
438         entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
439         if (entry_type == HFSPLUS_FOLDER) {
440                 len = sizeof(struct DInfo) + sizeof(struct DXInfo);
441                 hfs_bnode_read(fd.bnode, folder_finder_info,
442                                 fd.entryoffset +
443                                 offsetof(struct hfsplus_cat_folder, user_info),
444                                 len);
445                 found_bit = find_first_bit((void *)folder_finder_info, len*8);
446         } else if (entry_type == HFSPLUS_FILE) {
447                 len = sizeof(struct FInfo) + sizeof(struct FXInfo);
448                 hfs_bnode_read(fd.bnode, file_finder_info,
449                                 fd.entryoffset +
450                                 offsetof(struct hfsplus_cat_file, user_info),
451                                 len);
452                 found_bit = find_first_bit((void *)file_finder_info, len*8);
453         } else {
454                 res = -EOPNOTSUPP;
455                 goto end_listxattr_finder_info;
456         }
457
458         if (found_bit >= (len*8))
459                 res = 0;
460         else {
461                 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1;
462                 xattr_name_len =
463                         name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count);
464                 if (!buffer || !size) {
465                         if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME))
466                                 res = xattr_name_len;
467                 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) {
468                         if (size < xattr_name_len)
469                                 res = -ERANGE;
470                         else {
471                                 res = copy_name(buffer,
472                                                 HFSPLUS_XATTR_FINDER_INFO_NAME,
473                                                 symbols_count);
474                         }
475                 }
476         }
477
478 end_listxattr_finder_info:
479         hfs_find_exit(&fd);
480
481         return res;
482 }
483
484 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
485 {
486         ssize_t err;
487         ssize_t res = 0;
488         struct inode *inode = dentry->d_inode;
489         struct hfs_find_data fd;
490         u16 key_len = 0;
491         struct hfsplus_attr_key attr_key;
492         char strbuf[HFSPLUS_ATTR_MAX_STRLEN +
493                         XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
494         int xattr_name_len;
495
496         if ((!S_ISREG(inode->i_mode) &&
497                         !S_ISDIR(inode->i_mode)) ||
498                                 HFSPLUS_IS_RSRC(inode))
499                 return -EOPNOTSUPP;
500
501         res = hfsplus_listxattr_finder_info(dentry, buffer, size);
502         if (res < 0)
503                 return res;
504         else if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
505                 return (res == 0) ? -EOPNOTSUPP : res;
506
507         err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
508         if (err) {
509                 printk(KERN_ERR "hfs: can't init xattr find struct\n");
510                 return err;
511         }
512
513         err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
514         if (err) {
515                 if (err == -ENOENT) {
516                         if (res == 0)
517                                 res = -ENODATA;
518                         goto end_listxattr;
519                 } else {
520                         res = err;
521                         goto end_listxattr;
522                 }
523         }
524
525         for (;;) {
526                 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
527                 if (key_len == 0 || key_len > fd.tree->max_key_len) {
528                         printk(KERN_ERR "hfs: invalid xattr key length: %d\n",
529                                                         key_len);
530                         res = -EIO;
531                         goto end_listxattr;
532                 }
533
534                 hfs_bnode_read(fd.bnode, &attr_key,
535                                 fd.keyoffset, key_len + sizeof(key_len));
536
537                 if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
538                         goto end_listxattr;
539
540                 xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN;
541                 if (hfsplus_uni2asc(inode->i_sb,
542                         (const struct hfsplus_unistr *)&fd.key->attr.key_name,
543                                         strbuf, &xattr_name_len)) {
544                         printk(KERN_ERR "hfs: unicode conversion failed\n");
545                         res = -EIO;
546                         goto end_listxattr;
547                 }
548
549                 if (!buffer || !size) {
550                         if (can_list(strbuf))
551                                 res += name_len(strbuf, xattr_name_len);
552                 } else if (can_list(strbuf)) {
553                         if (size < (res + name_len(strbuf, xattr_name_len))) {
554                                 res = -ERANGE;
555                                 goto end_listxattr;
556                         } else
557                                 res += copy_name(buffer + res,
558                                                 strbuf, xattr_name_len);
559                 }
560
561                 if (hfs_brec_goto(&fd, 1))
562                         goto end_listxattr;
563         }
564
565 end_listxattr:
566         hfs_find_exit(&fd);
567         return res;
568 }
569
570 int hfsplus_removexattr(struct dentry *dentry, const char *name)
571 {
572         int err = 0;
573         struct inode *inode = dentry->d_inode;
574         struct hfs_find_data cat_fd;
575         u16 flags;
576         u16 cat_entry_type;
577         int is_xattr_acl_deleted = 0;
578         int is_all_xattrs_deleted = 0;
579
580         if ((!S_ISREG(inode->i_mode) &&
581                         !S_ISDIR(inode->i_mode)) ||
582                                 HFSPLUS_IS_RSRC(inode))
583                 return -EOPNOTSUPP;
584
585         if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
586                 return -EOPNOTSUPP;
587
588         err = can_set_xattr(inode, name, NULL, 0);
589         if (err)
590                 return err;
591
592         if (strncmp(name, XATTR_MAC_OSX_PREFIX,
593                                 XATTR_MAC_OSX_PREFIX_LEN) == 0)
594                 name += XATTR_MAC_OSX_PREFIX_LEN;
595
596         if (!strcmp_xattr_finder_info(name))
597                 return -EOPNOTSUPP;
598
599         err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
600         if (err) {
601                 printk(KERN_ERR "hfs: can't init xattr find struct\n");
602                 return err;
603         }
604
605         err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
606         if (err) {
607                 printk(KERN_ERR "hfs: catalog searching failed\n");
608                 goto end_removexattr;
609         }
610
611         err = hfsplus_delete_attr(inode, name);
612         if (err)
613                 goto end_removexattr;
614
615         is_xattr_acl_deleted = !strcmp_xattr_acl(name);
616         is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
617
618         if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
619                 goto end_removexattr;
620
621         cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
622
623         if (cat_entry_type == HFSPLUS_FOLDER) {
624                 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
625                                 offsetof(struct hfsplus_cat_folder, flags));
626                 if (is_xattr_acl_deleted)
627                         flags &= ~HFSPLUS_ACL_EXISTS;
628                 if (is_all_xattrs_deleted)
629                         flags &= ~HFSPLUS_XATTR_EXISTS;
630                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
631                                 offsetof(struct hfsplus_cat_folder, flags),
632                                 flags);
633                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
634         } else if (cat_entry_type == HFSPLUS_FILE) {
635                 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
636                                 offsetof(struct hfsplus_cat_file, flags));
637                 if (is_xattr_acl_deleted)
638                         flags &= ~HFSPLUS_ACL_EXISTS;
639                 if (is_all_xattrs_deleted)
640                         flags &= ~HFSPLUS_XATTR_EXISTS;
641                 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
642                                 offsetof(struct hfsplus_cat_file, flags),
643                                 flags);
644                 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
645         } else {
646                 printk(KERN_ERR "hfs: invalid catalog entry type\n");
647                 err = -EIO;
648                 goto end_removexattr;
649         }
650
651 end_removexattr:
652         hfs_find_exit(&cat_fd);
653         return err;
654 }
655
656 static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
657                                         void *buffer, size_t size, int type)
658 {
659         char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
660                                 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
661         size_t len = strlen(name);
662
663         if (!strcmp(name, ""))
664                 return -EINVAL;
665
666         if (len > HFSPLUS_ATTR_MAX_STRLEN)
667                 return -EOPNOTSUPP;
668
669         strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
670         strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
671
672         return hfsplus_getxattr(dentry, xattr_name, buffer, size);
673 }
674
675 static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
676                 const void *buffer, size_t size, int flags, int type)
677 {
678         char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
679                                 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
680         size_t len = strlen(name);
681
682         if (!strcmp(name, ""))
683                 return -EINVAL;
684
685         if (len > HFSPLUS_ATTR_MAX_STRLEN)
686                 return -EOPNOTSUPP;
687
688         strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
689         strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
690
691         return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags);
692 }
693
694 static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list,
695                 size_t list_size, const char *name, size_t name_len, int type)
696 {
697         /*
698          * This method is not used.
699          * It is used hfsplus_listxattr() instead of generic_listxattr().
700          */
701         return -EOPNOTSUPP;
702 }
703
704 const struct xattr_handler hfsplus_xattr_osx_handler = {
705         .prefix = XATTR_MAC_OSX_PREFIX,
706         .list   = hfsplus_osx_listxattr,
707         .get    = hfsplus_osx_getxattr,
708         .set    = hfsplus_osx_setxattr,
709 };