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