Merge branch 'kbuild' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[deliverable/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 <linux/posix_acl_xattr.h>
11 #include "xattr.h"
12 #include "acl.h"
13
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,
21 #endif
22 &hfsplus_xattr_security_handler,
23 NULL
24 };
25
26 static int strcmp_xattr_finder_info(const char *name)
27 {
28 if (name) {
29 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME,
30 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME));
31 }
32 return -1;
33 }
34
35 static int strcmp_xattr_acl(const char *name)
36 {
37 if (name) {
38 return strncmp(name, HFSPLUS_XATTR_ACL_NAME,
39 sizeof(HFSPLUS_XATTR_ACL_NAME));
40 }
41 return -1;
42 }
43
44 static inline int is_known_namespace(const char *name)
45 {
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))
50 return false;
51
52 return true;
53 }
54
55 static void hfsplus_init_header_node(struct inode *attr_file,
56 u32 clump_size,
57 char *buf, u16 node_size)
58 {
59 struct hfs_bnode_desc *desc;
60 struct hfs_btree_header_rec *head;
61 u16 offset;
62 __be16 *rec_offsets;
63 u32 hdr_node_map_rec_bits;
64 char *bmp;
65 u32 used_nodes;
66 u32 used_bmp_bytes;
67 loff_t tmp;
68
69 hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n",
70 clump_size, node_size);
71
72 /* The end of the node contains list of record offsets */
73 rec_offsets = (__be16 *)(buf + node_size);
74
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);
80
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);
94
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) {
97 u32 map_node_bits;
98 u32 map_nodes;
99
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);
107 }
108
109 bmp = buf + offset;
110 used_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;
116 used_nodes %= 8;
117 }
118 *bmp = ~(0xFF >> used_nodes);
119 offset += hdr_node_map_rec_bits / 8;
120 *--rec_offsets = cpu_to_be16(offset);
121 }
122
123 static int hfsplus_create_attributes_file(struct super_block *sb)
124 {
125 int err = 0;
126 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
127 struct inode *attr_file;
128 struct hfsplus_inode_info *hip;
129 u32 clump_size;
130 u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE;
131 char *buf;
132 int index, written;
133 struct address_space *mapping;
134 struct page *page;
135 int old_state = HFSPLUS_EMPTY_ATTR_TREE;
136
137 hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
138
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,
143 old_state,
144 HFSPLUS_CREATING_ATTR_TREE))
145 goto check_attr_tree_state_again;
146 break;
147 case HFSPLUS_CREATING_ATTR_TREE:
148 /*
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.
161 */
162 return -EAGAIN;
163 case HFSPLUS_VALID_ATTR_TREE:
164 return 0;
165 case HFSPLUS_FAILED_ATTR_TREE:
166 return -EOPNOTSUPP;
167 default:
168 BUG();
169 }
170
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);
175 }
176
177 BUG_ON(i_size_read(attr_file) != 0);
178
179 hip = HFSPLUS_I(attr_file);
180
181 clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize,
182 node_size,
183 sbi->sect_count,
184 HFSPLUS_ATTR_CNID);
185
186 mutex_lock(&hip->extents_lock);
187 hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift;
188 mutex_unlock(&hip->extents_lock);
189
190 if (sbi->free_blocks <= (hip->clump_blocks << 1)) {
191 err = -ENOSPC;
192 goto end_attr_file_creation;
193 }
194
195 while (hip->alloc_blocks < hip->clump_blocks) {
196 err = hfsplus_file_extend(attr_file);
197 if (unlikely(err)) {
198 pr_err("failed to extend attributes file\n");
199 goto end_attr_file_creation;
200 }
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);
205 }
206
207 buf = kzalloc(node_size, GFP_NOFS);
208 if (!buf) {
209 pr_err("failed to allocate memory for header node\n");
210 err = -ENOMEM;
211 goto end_attr_file_creation;
212 }
213
214 hfsplus_init_header_node(attr_file, clump_size, buf, node_size);
215
216 mapping = attr_file->i_mapping;
217
218 index = 0;
219 written = 0;
220 for (; written < node_size; index++, written += PAGE_CACHE_SIZE) {
221 void *kaddr;
222
223 page = read_mapping_page(mapping, index, NULL);
224 if (IS_ERR(page)) {
225 err = PTR_ERR(page);
226 goto failed_header_node_init;
227 }
228
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);
233
234 set_page_dirty(page);
235 page_cache_release(page);
236 }
237
238 hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY);
239
240 sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
241 if (!sbi->attr_tree)
242 pr_err("failed to load attributes file\n");
243
244 failed_header_node_init:
245 kfree(buf);
246
247 end_attr_file_creation:
248 iput(attr_file);
249
250 if (!err)
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);
254 else
255 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE);
256
257 return err;
258 }
259
260 int __hfsplus_setxattr(struct inode *inode, const char *name,
261 const void *value, size_t size, int flags)
262 {
263 int err = 0;
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);
271
272 if ((!S_ISREG(inode->i_mode) &&
273 !S_ISDIR(inode->i_mode)) ||
274 HFSPLUS_IS_RSRC(inode))
275 return -EOPNOTSUPP;
276
277 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
278 XATTR_MAC_OSX_PREFIX_LEN) == 0)
279 name += XATTR_MAC_OSX_PREFIX_LEN;
280
281 if (value == NULL) {
282 value = "";
283 size = 0;
284 }
285
286 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
287 if (err) {
288 pr_err("can't init xattr find struct\n");
289 return err;
290 }
291
292 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
293 if (err) {
294 pr_err("catalog searching failed\n");
295 goto end_setxattr;
296 }
297
298 if (!strcmp_xattr_finder_info(name)) {
299 if (flags & XATTR_CREATE) {
300 pr_err("xattr exists yet\n");
301 err = -EOPNOTSUPP;
302 goto end_setxattr;
303 }
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,
311 cat_fd.entryoffset,
312 sizeof(struct hfsplus_cat_folder));
313 hfsplus_mark_inode_dirty(inode,
314 HFSPLUS_I_CAT_DIRTY);
315 } else {
316 err = -ERANGE;
317 goto end_setxattr;
318 }
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,
324 cat_fd.entryoffset,
325 sizeof(struct hfsplus_cat_file));
326 hfsplus_mark_inode_dirty(inode,
327 HFSPLUS_I_CAT_DIRTY);
328 } else {
329 err = -ERANGE;
330 goto end_setxattr;
331 }
332 } else {
333 err = -EOPNOTSUPP;
334 goto end_setxattr;
335 }
336 goto end_setxattr;
337 }
338
339 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
340 err = hfsplus_create_attributes_file(inode->i_sb);
341 if (unlikely(err))
342 goto end_setxattr;
343 }
344
345 if (hfsplus_attr_exists(inode, name)) {
346 if (flags & XATTR_CREATE) {
347 pr_err("xattr exists yet\n");
348 err = -EOPNOTSUPP;
349 goto end_setxattr;
350 }
351 err = hfsplus_delete_attr(inode, name);
352 if (err)
353 goto end_setxattr;
354 err = hfsplus_create_attr(inode, name, value, size);
355 if (err)
356 goto end_setxattr;
357 } else {
358 if (flags & XATTR_REPLACE) {
359 pr_err("cannot replace xattr\n");
360 err = -EOPNOTSUPP;
361 goto end_setxattr;
362 }
363 err = hfsplus_create_attr(inode, name, value, size);
364 if (err)
365 goto end_setxattr;
366 }
367
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,
371 cat_fd.entryoffset +
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),
378 cat_entry_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,
382 cat_fd.entryoffset +
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),
389 cat_entry_flags);
390 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
391 } else {
392 pr_err("invalid catalog entry type\n");
393 err = -EIO;
394 goto end_setxattr;
395 }
396
397 end_setxattr:
398 hfs_find_exit(&cat_fd);
399 return err;
400 }
401
402 static inline int is_osx_xattr(const char *xattr_name)
403 {
404 return !is_known_namespace(xattr_name);
405 }
406
407 static int name_len(const char *xattr_name, int xattr_name_len)
408 {
409 int len = xattr_name_len + 1;
410
411 if (is_osx_xattr(xattr_name))
412 len += XATTR_MAC_OSX_PREFIX_LEN;
413
414 return len;
415 }
416
417 static int copy_name(char *buffer, const char *xattr_name, int name_len)
418 {
419 int len = name_len;
420 int offset = 0;
421
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;
426 }
427
428 strncpy(buffer + offset, xattr_name, name_len);
429 memset(buffer + offset + name_len, 0, 1);
430 len += 1;
431
432 return len;
433 }
434
435 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode,
436 void *value, size_t size)
437 {
438 ssize_t res = 0;
439 struct hfs_find_data fd;
440 u16 entry_type;
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)];
446
447 if (size >= record_len) {
448 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
449 if (res) {
450 pr_err("can't init xattr find struct\n");
451 return res;
452 }
453 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
454 if (res)
455 goto end_getxattr_finder_info;
456 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
457
458 if (entry_type == HFSPLUS_FOLDER) {
459 hfs_bnode_read(fd.bnode, folder_finder_info,
460 fd.entryoffset +
461 offsetof(struct hfsplus_cat_folder, user_info),
462 folder_rec_len);
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,
467 fd.entryoffset +
468 offsetof(struct hfsplus_cat_file, user_info),
469 file_rec_len);
470 memcpy(value, file_finder_info, file_rec_len);
471 res = file_rec_len;
472 } else {
473 res = -EOPNOTSUPP;
474 goto end_getxattr_finder_info;
475 }
476 } else
477 res = size ? -ERANGE : record_len;
478
479 end_getxattr_finder_info:
480 if (size >= record_len)
481 hfs_find_exit(&fd);
482 return res;
483 }
484
485 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
486 void *value, size_t size)
487 {
488 struct hfs_find_data fd;
489 hfsplus_attr_entry *entry;
490 __be32 xattr_record_type;
491 u32 record_type;
492 u16 record_length = 0;
493 ssize_t res = 0;
494
495 if ((!S_ISREG(inode->i_mode) &&
496 !S_ISDIR(inode->i_mode)) ||
497 HFSPLUS_IS_RSRC(inode))
498 return -EOPNOTSUPP;
499
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;
504 /*
505 * Don't allow retrieving properly prefixed attributes
506 * by prepending them with "osx."
507 */
508 if (is_known_namespace(name))
509 return -EOPNOTSUPP;
510 }
511
512 if (!strcmp_xattr_finder_info(name))
513 return hfsplus_getxattr_finder_info(inode, value, size);
514
515 if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
516 return -EOPNOTSUPP;
517
518 entry = hfsplus_alloc_attr_entry();
519 if (!entry) {
520 pr_err("can't allocate xattr entry\n");
521 return -ENOMEM;
522 }
523
524 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
525 if (res) {
526 pr_err("can't init xattr find struct\n");
527 goto failed_getxattr_init;
528 }
529
530 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
531 if (res) {
532 if (res == -ENOENT)
533 res = -ENODATA;
534 else
535 pr_err("xattr searching failed\n");
536 goto out;
537 }
538
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,
544 fd.entryoffset +
545 offsetof(struct hfsplus_attr_inline_data,
546 length));
547 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
548 pr_err("invalid xattr record size\n");
549 res = -EIO;
550 goto out;
551 }
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");
555 res = -EOPNOTSUPP;
556 goto out;
557 } else {
558 pr_err("invalid xattr record\n");
559 res = -EIO;
560 goto out;
561 }
562
563 if (size) {
564 hfs_bnode_read(fd.bnode, entry, fd.entryoffset,
565 offsetof(struct hfsplus_attr_inline_data,
566 raw_bytes) + record_length);
567 }
568
569 if (size >= record_length) {
570 memcpy(value, entry->inline_data.raw_bytes, record_length);
571 res = record_length;
572 } else
573 res = size ? -ERANGE : record_length;
574
575 out:
576 hfs_find_exit(&fd);
577
578 failed_getxattr_init:
579 hfsplus_destroy_attr_entry(entry);
580 return res;
581 }
582
583 static inline int can_list(const char *xattr_name)
584 {
585 if (!xattr_name)
586 return 0;
587
588 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
589 XATTR_TRUSTED_PREFIX_LEN) ||
590 capable(CAP_SYS_ADMIN);
591 }
592
593 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
594 char *buffer, size_t size)
595 {
596 ssize_t res = 0;
597 struct inode *inode = dentry->d_inode;
598 struct hfs_find_data fd;
599 u16 entry_type;
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;
604
605 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
606 if (res) {
607 pr_err("can't init xattr find struct\n");
608 return res;
609 }
610
611 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
612 if (res)
613 goto end_listxattr_finder_info;
614
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,
619 fd.entryoffset +
620 offsetof(struct hfsplus_cat_folder, user_info),
621 len);
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,
626 fd.entryoffset +
627 offsetof(struct hfsplus_cat_file, user_info),
628 len);
629 found_bit = find_first_bit((void *)file_finder_info, len*8);
630 } else {
631 res = -EOPNOTSUPP;
632 goto end_listxattr_finder_info;
633 }
634
635 if (found_bit >= (len*8))
636 res = 0;
637 else {
638 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1;
639 xattr_name_len =
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)
646 res = -ERANGE;
647 else {
648 res = copy_name(buffer,
649 HFSPLUS_XATTR_FINDER_INFO_NAME,
650 symbols_count);
651 }
652 }
653 }
654
655 end_listxattr_finder_info:
656 hfs_find_exit(&fd);
657
658 return res;
659 }
660
661 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
662 {
663 ssize_t err;
664 ssize_t res = 0;
665 struct inode *inode = dentry->d_inode;
666 struct hfs_find_data fd;
667 u16 key_len = 0;
668 struct hfsplus_attr_key attr_key;
669 char strbuf[HFSPLUS_ATTR_MAX_STRLEN +
670 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
671 int xattr_name_len;
672
673 if ((!S_ISREG(inode->i_mode) &&
674 !S_ISDIR(inode->i_mode)) ||
675 HFSPLUS_IS_RSRC(inode))
676 return -EOPNOTSUPP;
677
678 res = hfsplus_listxattr_finder_info(dentry, buffer, size);
679 if (res < 0)
680 return res;
681 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
682 return (res == 0) ? -EOPNOTSUPP : res;
683
684 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
685 if (err) {
686 pr_err("can't init xattr find struct\n");
687 return err;
688 }
689
690 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
691 if (err) {
692 if (err == -ENOENT) {
693 if (res == 0)
694 res = -ENODATA;
695 goto end_listxattr;
696 } else {
697 res = err;
698 goto end_listxattr;
699 }
700 }
701
702 for (;;) {
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);
706 res = -EIO;
707 goto end_listxattr;
708 }
709
710 hfs_bnode_read(fd.bnode, &attr_key,
711 fd.keyoffset, key_len + sizeof(key_len));
712
713 if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
714 goto end_listxattr;
715
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");
721 res = -EIO;
722 goto end_listxattr;
723 }
724
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))) {
730 res = -ERANGE;
731 goto end_listxattr;
732 } else
733 res += copy_name(buffer + res,
734 strbuf, xattr_name_len);
735 }
736
737 if (hfs_brec_goto(&fd, 1))
738 goto end_listxattr;
739 }
740
741 end_listxattr:
742 hfs_find_exit(&fd);
743 return res;
744 }
745
746 int hfsplus_removexattr(struct dentry *dentry, const char *name)
747 {
748 int err = 0;
749 struct inode *inode = dentry->d_inode;
750 struct hfs_find_data cat_fd;
751 u16 flags;
752 u16 cat_entry_type;
753 int is_xattr_acl_deleted = 0;
754 int is_all_xattrs_deleted = 0;
755
756 if ((!S_ISREG(inode->i_mode) &&
757 !S_ISDIR(inode->i_mode)) ||
758 HFSPLUS_IS_RSRC(inode))
759 return -EOPNOTSUPP;
760
761 if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
762 return -EOPNOTSUPP;
763
764 if (strncmp(name, XATTR_MAC_OSX_PREFIX,
765 XATTR_MAC_OSX_PREFIX_LEN) == 0)
766 name += XATTR_MAC_OSX_PREFIX_LEN;
767
768 if (!strcmp_xattr_finder_info(name))
769 return -EOPNOTSUPP;
770
771 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
772 if (err) {
773 pr_err("can't init xattr find struct\n");
774 return err;
775 }
776
777 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
778 if (err) {
779 pr_err("catalog searching failed\n");
780 goto end_removexattr;
781 }
782
783 err = hfsplus_delete_attr(inode, name);
784 if (err)
785 goto end_removexattr;
786
787 is_xattr_acl_deleted = !strcmp_xattr_acl(name);
788 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
789
790 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
791 goto end_removexattr;
792
793 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
794
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),
804 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),
815 flags);
816 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
817 } else {
818 pr_err("invalid catalog entry type\n");
819 err = -EIO;
820 goto end_removexattr;
821 }
822
823 end_removexattr:
824 hfs_find_exit(&cat_fd);
825 return err;
826 }
827
828 static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
829 void *buffer, size_t size, int type)
830 {
831 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
832 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
833 size_t len = strlen(name);
834
835 if (!strcmp(name, ""))
836 return -EINVAL;
837
838 if (len > HFSPLUS_ATTR_MAX_STRLEN)
839 return -EOPNOTSUPP;
840
841 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
842 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
843
844 return hfsplus_getxattr(dentry, xattr_name, buffer, size);
845 }
846
847 static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
848 const void *buffer, size_t size, int flags, int type)
849 {
850 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
851 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
852 size_t len = strlen(name);
853
854 if (!strcmp(name, ""))
855 return -EINVAL;
856
857 if (len > HFSPLUS_ATTR_MAX_STRLEN)
858 return -EOPNOTSUPP;
859
860 if (is_known_namespace(name))
861 return -EOPNOTSUPP;
862
863 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
864 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
865
866 return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags);
867 }
868
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)
871 {
872 /*
873 * This method is not used.
874 * It is used hfsplus_listxattr() instead of generic_listxattr().
875 */
876 return -EOPNOTSUPP;
877 }
878
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,
884 };
This page took 0.046859 seconds and 6 git commands to generate.