xattr.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  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. #include "hfsplus_fs.h"
  10. #include <linux/nls.h>
  11. #include "xattr.h"
  12. static int hfsplus_removexattr(struct inode *inode, const char *name);
  13. const struct xattr_handler *hfsplus_xattr_handlers[] = {
  14. &hfsplus_xattr_osx_handler,
  15. &hfsplus_xattr_user_handler,
  16. &hfsplus_xattr_trusted_handler,
  17. &hfsplus_xattr_security_handler,
  18. NULL
  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. static int strcmp_xattr_acl(const char *name)
  29. {
  30. if (name) {
  31. return strncmp(name, HFSPLUS_XATTR_ACL_NAME,
  32. sizeof(HFSPLUS_XATTR_ACL_NAME));
  33. }
  34. return -1;
  35. }
  36. static bool is_known_namespace(const char *name)
  37. {
  38. if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) &&
  39. strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
  40. strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
  41. strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
  42. return false;
  43. return true;
  44. }
  45. static void hfsplus_init_header_node(struct inode *attr_file,
  46. u32 clump_size,
  47. char *buf, u16 node_size)
  48. {
  49. struct hfs_bnode_desc *desc;
  50. struct hfs_btree_header_rec *head;
  51. u16 offset;
  52. __be16 *rec_offsets;
  53. u32 hdr_node_map_rec_bits;
  54. char *bmp;
  55. u32 used_nodes;
  56. u32 used_bmp_bytes;
  57. u64 tmp;
  58. hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n",
  59. clump_size, node_size);
  60. /* The end of the node contains list of record offsets */
  61. rec_offsets = (__be16 *)(buf + node_size);
  62. desc = (struct hfs_bnode_desc *)buf;
  63. desc->type = HFS_NODE_HEADER;
  64. desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT);
  65. offset = sizeof(struct hfs_bnode_desc);
  66. *--rec_offsets = cpu_to_be16(offset);
  67. head = (struct hfs_btree_header_rec *)(buf + offset);
  68. head->node_size = cpu_to_be16(node_size);
  69. tmp = i_size_read(attr_file);
  70. do_div(tmp, node_size);
  71. head->node_count = cpu_to_be32(tmp);
  72. head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1);
  73. head->clump_size = cpu_to_be32(clump_size);
  74. head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS);
  75. head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16));
  76. offset += sizeof(struct hfs_btree_header_rec);
  77. *--rec_offsets = cpu_to_be16(offset);
  78. offset += HFSPLUS_BTREE_HDR_USER_BYTES;
  79. *--rec_offsets = cpu_to_be16(offset);
  80. hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16)));
  81. if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) {
  82. u32 map_node_bits;
  83. u32 map_nodes;
  84. desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1);
  85. map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) -
  86. (2 * sizeof(u16)) - 2);
  87. map_nodes = (be32_to_cpu(head->node_count) -
  88. hdr_node_map_rec_bits +
  89. (map_node_bits - 1)) / map_node_bits;
  90. be32_add_cpu(&head->free_nodes, 0 - map_nodes);
  91. }
  92. bmp = buf + offset;
  93. used_nodes =
  94. be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes);
  95. used_bmp_bytes = used_nodes / 8;
  96. if (used_bmp_bytes) {
  97. memset(bmp, 0xFF, used_bmp_bytes);
  98. bmp += used_bmp_bytes;
  99. used_nodes %= 8;
  100. }
  101. *bmp = ~(0xFF >> used_nodes);
  102. offset += hdr_node_map_rec_bits / 8;
  103. *--rec_offsets = cpu_to_be16(offset);
  104. }
  105. static int hfsplus_create_attributes_file(struct super_block *sb)
  106. {
  107. int err = 0;
  108. struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
  109. struct inode *attr_file;
  110. struct hfsplus_inode_info *hip;
  111. u32 clump_size;
  112. u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE;
  113. char *buf;
  114. int index, written;
  115. struct address_space *mapping;
  116. struct page *page;
  117. int old_state = HFSPLUS_EMPTY_ATTR_TREE;
  118. hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
  119. check_attr_tree_state_again:
  120. switch (atomic_read(&sbi->attr_tree_state)) {
  121. case HFSPLUS_EMPTY_ATTR_TREE:
  122. if (old_state != atomic_cmpxchg(&sbi->attr_tree_state,
  123. old_state,
  124. HFSPLUS_CREATING_ATTR_TREE))
  125. goto check_attr_tree_state_again;
  126. break;
  127. case HFSPLUS_CREATING_ATTR_TREE:
  128. /*
  129. * This state means that another thread is in process
  130. * of AttributesFile creation. Theoretically, it is
  131. * possible to be here. But really __setxattr() method
  132. * first of all calls hfs_find_init() for lookup in
  133. * B-tree of CatalogFile. This method locks mutex of
  134. * CatalogFile's B-tree. As a result, if some thread
  135. * is inside AttributedFile creation operation then
  136. * another threads will be waiting unlocking of
  137. * CatalogFile's B-tree's mutex. However, if code will
  138. * change then we will return error code (-EAGAIN) from
  139. * here. Really, it means that first try to set of xattr
  140. * fails with error but second attempt will have success.
  141. */
  142. return -EAGAIN;
  143. case HFSPLUS_VALID_ATTR_TREE:
  144. return 0;
  145. case HFSPLUS_FAILED_ATTR_TREE:
  146. return -EOPNOTSUPP;
  147. default:
  148. BUG();
  149. }
  150. attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID);
  151. if (IS_ERR(attr_file)) {
  152. pr_err("failed to load attributes file\n");
  153. return PTR_ERR(attr_file);
  154. }
  155. BUG_ON(i_size_read(attr_file) != 0);
  156. hip = HFSPLUS_I(attr_file);
  157. clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize,
  158. node_size,
  159. sbi->sect_count,
  160. HFSPLUS_ATTR_CNID);
  161. mutex_lock(&hip->extents_lock);
  162. hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift;
  163. mutex_unlock(&hip->extents_lock);
  164. if (sbi->free_blocks <= (hip->clump_blocks << 1)) {
  165. err = -ENOSPC;
  166. goto end_attr_file_creation;
  167. }
  168. while (hip->alloc_blocks < hip->clump_blocks) {
  169. err = hfsplus_file_extend(attr_file, false);
  170. if (unlikely(err)) {
  171. pr_err("failed to extend attributes file\n");
  172. goto end_attr_file_creation;
  173. }
  174. hip->phys_size = attr_file->i_size =
  175. (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift;
  176. hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift;
  177. inode_set_bytes(attr_file, attr_file->i_size);
  178. }
  179. buf = kzalloc(node_size, GFP_NOFS);
  180. if (!buf) {
  181. pr_err("failed to allocate memory for header node\n");
  182. err = -ENOMEM;
  183. goto end_attr_file_creation;
  184. }
  185. hfsplus_init_header_node(attr_file, clump_size, buf, node_size);
  186. mapping = attr_file->i_mapping;
  187. index = 0;
  188. written = 0;
  189. for (; written < node_size; index++, written += PAGE_SIZE) {
  190. void *kaddr;
  191. page = read_mapping_page(mapping, index, NULL);
  192. if (IS_ERR(page)) {
  193. err = PTR_ERR(page);
  194. goto failed_header_node_init;
  195. }
  196. kaddr = kmap_atomic(page);
  197. memcpy(kaddr, buf + written,
  198. min_t(size_t, PAGE_SIZE, node_size - written));
  199. kunmap_atomic(kaddr);
  200. set_page_dirty(page);
  201. put_page(page);
  202. }
  203. hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY);
  204. sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
  205. if (!sbi->attr_tree)
  206. pr_err("failed to load attributes file\n");
  207. failed_header_node_init:
  208. kfree(buf);
  209. end_attr_file_creation:
  210. iput(attr_file);
  211. if (!err)
  212. atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
  213. else if (err == -ENOSPC)
  214. atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
  215. else
  216. atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE);
  217. return err;
  218. }
  219. int __hfsplus_setxattr(struct inode *inode, const char *name,
  220. const void *value, size_t size, int flags)
  221. {
  222. int err = 0;
  223. struct hfs_find_data cat_fd;
  224. hfsplus_cat_entry entry;
  225. u16 cat_entry_flags, cat_entry_type;
  226. u16 folder_finderinfo_len = sizeof(struct DInfo) +
  227. sizeof(struct DXInfo);
  228. u16 file_finderinfo_len = sizeof(struct FInfo) +
  229. sizeof(struct FXInfo);
  230. if ((!S_ISREG(inode->i_mode) &&
  231. !S_ISDIR(inode->i_mode)) ||
  232. HFSPLUS_IS_RSRC(inode))
  233. return -EOPNOTSUPP;
  234. if (value == NULL)
  235. return hfsplus_removexattr(inode, name);
  236. err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
  237. if (err) {
  238. pr_err("can't init xattr find struct\n");
  239. return err;
  240. }
  241. err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
  242. if (err) {
  243. pr_err("catalog searching failed\n");
  244. goto end_setxattr;
  245. }
  246. if (!strcmp_xattr_finder_info(name)) {
  247. if (flags & XATTR_CREATE) {
  248. pr_err("xattr exists yet\n");
  249. err = -EOPNOTSUPP;
  250. goto end_setxattr;
  251. }
  252. hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset,
  253. sizeof(hfsplus_cat_entry));
  254. if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) {
  255. if (size == folder_finderinfo_len) {
  256. memcpy(&entry.folder.user_info, value,
  257. folder_finderinfo_len);
  258. hfs_bnode_write(cat_fd.bnode, &entry,
  259. cat_fd.entryoffset,
  260. sizeof(struct hfsplus_cat_folder));
  261. hfsplus_mark_inode_dirty(inode,
  262. HFSPLUS_I_CAT_DIRTY);
  263. } else {
  264. err = -ERANGE;
  265. goto end_setxattr;
  266. }
  267. } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) {
  268. if (size == file_finderinfo_len) {
  269. memcpy(&entry.file.user_info, value,
  270. file_finderinfo_len);
  271. hfs_bnode_write(cat_fd.bnode, &entry,
  272. cat_fd.entryoffset,
  273. sizeof(struct hfsplus_cat_file));
  274. hfsplus_mark_inode_dirty(inode,
  275. HFSPLUS_I_CAT_DIRTY);
  276. } else {
  277. err = -ERANGE;
  278. goto end_setxattr;
  279. }
  280. } else {
  281. err = -EOPNOTSUPP;
  282. goto end_setxattr;
  283. }
  284. goto end_setxattr;
  285. }
  286. if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
  287. err = hfsplus_create_attributes_file(inode->i_sb);
  288. if (unlikely(err))
  289. goto end_setxattr;
  290. }
  291. if (hfsplus_attr_exists(inode, name)) {
  292. if (flags & XATTR_CREATE) {
  293. pr_err("xattr exists yet\n");
  294. err = -EOPNOTSUPP;
  295. goto end_setxattr;
  296. }
  297. err = hfsplus_delete_attr(inode, name);
  298. if (err)
  299. goto end_setxattr;
  300. err = hfsplus_create_attr(inode, name, value, size);
  301. if (err)
  302. goto end_setxattr;
  303. } else {
  304. if (flags & XATTR_REPLACE) {
  305. pr_err("cannot replace xattr\n");
  306. err = -EOPNOTSUPP;
  307. goto end_setxattr;
  308. }
  309. err = hfsplus_create_attr(inode, name, value, size);
  310. if (err)
  311. goto end_setxattr;
  312. }
  313. cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
  314. if (cat_entry_type == HFSPLUS_FOLDER) {
  315. cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
  316. cat_fd.entryoffset +
  317. offsetof(struct hfsplus_cat_folder, flags));
  318. cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
  319. if (!strcmp_xattr_acl(name))
  320. cat_entry_flags |= HFSPLUS_ACL_EXISTS;
  321. hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
  322. offsetof(struct hfsplus_cat_folder, flags),
  323. cat_entry_flags);
  324. hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
  325. } else if (cat_entry_type == HFSPLUS_FILE) {
  326. cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
  327. cat_fd.entryoffset +
  328. offsetof(struct hfsplus_cat_file, flags));
  329. cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
  330. if (!strcmp_xattr_acl(name))
  331. cat_entry_flags |= HFSPLUS_ACL_EXISTS;
  332. hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
  333. offsetof(struct hfsplus_cat_file, flags),
  334. cat_entry_flags);
  335. hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
  336. } else {
  337. pr_err("invalid catalog entry type\n");
  338. err = -EIO;
  339. goto end_setxattr;
  340. }
  341. end_setxattr:
  342. hfs_find_exit(&cat_fd);
  343. return err;
  344. }
  345. static int name_len(const char *xattr_name, int xattr_name_len)
  346. {
  347. int len = xattr_name_len + 1;
  348. if (!is_known_namespace(xattr_name))
  349. len += XATTR_MAC_OSX_PREFIX_LEN;
  350. return len;
  351. }
  352. static int copy_name(char *buffer, const char *xattr_name, int name_len)
  353. {
  354. int len = name_len;
  355. int offset = 0;
  356. if (!is_known_namespace(xattr_name)) {
  357. memcpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
  358. offset += XATTR_MAC_OSX_PREFIX_LEN;
  359. len += XATTR_MAC_OSX_PREFIX_LEN;
  360. }
  361. strncpy(buffer + offset, xattr_name, name_len);
  362. memset(buffer + offset + name_len, 0, 1);
  363. len += 1;
  364. return len;
  365. }
  366. int hfsplus_setxattr(struct inode *inode, const char *name,
  367. const void *value, size_t size, int flags,
  368. const char *prefix, size_t prefixlen)
  369. {
  370. char *xattr_name;
  371. int res;
  372. xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
  373. GFP_KERNEL);
  374. if (!xattr_name)
  375. return -ENOMEM;
  376. strcpy(xattr_name, prefix);
  377. strcpy(xattr_name + prefixlen, name);
  378. res = __hfsplus_setxattr(inode, xattr_name, value, size, flags);
  379. kfree(xattr_name);
  380. return res;
  381. }
  382. static ssize_t hfsplus_getxattr_finder_info(struct inode *inode,
  383. void *value, size_t size)
  384. {
  385. ssize_t res = 0;
  386. struct hfs_find_data fd;
  387. u16 entry_type;
  388. u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo);
  389. u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo);
  390. u16 record_len = max(folder_rec_len, file_rec_len);
  391. u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
  392. u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
  393. if (size >= record_len) {
  394. res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
  395. if (res) {
  396. pr_err("can't init xattr find struct\n");
  397. return res;
  398. }
  399. res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
  400. if (res)
  401. goto end_getxattr_finder_info;
  402. entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
  403. if (entry_type == HFSPLUS_FOLDER) {
  404. hfs_bnode_read(fd.bnode, folder_finder_info,
  405. fd.entryoffset +
  406. offsetof(struct hfsplus_cat_folder, user_info),
  407. folder_rec_len);
  408. memcpy(value, folder_finder_info, folder_rec_len);
  409. res = folder_rec_len;
  410. } else if (entry_type == HFSPLUS_FILE) {
  411. hfs_bnode_read(fd.bnode, file_finder_info,
  412. fd.entryoffset +
  413. offsetof(struct hfsplus_cat_file, user_info),
  414. file_rec_len);
  415. memcpy(value, file_finder_info, file_rec_len);
  416. res = file_rec_len;
  417. } else {
  418. res = -EOPNOTSUPP;
  419. goto end_getxattr_finder_info;
  420. }
  421. } else
  422. res = size ? -ERANGE : record_len;
  423. end_getxattr_finder_info:
  424. if (size >= record_len)
  425. hfs_find_exit(&fd);
  426. return res;
  427. }
  428. ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
  429. void *value, size_t size)
  430. {
  431. struct hfs_find_data fd;
  432. hfsplus_attr_entry *entry;
  433. __be32 xattr_record_type;
  434. u32 record_type;
  435. u16 record_length = 0;
  436. ssize_t res = 0;
  437. if ((!S_ISREG(inode->i_mode) &&
  438. !S_ISDIR(inode->i_mode)) ||
  439. HFSPLUS_IS_RSRC(inode))
  440. return -EOPNOTSUPP;
  441. if (!strcmp_xattr_finder_info(name))
  442. return hfsplus_getxattr_finder_info(inode, value, size);
  443. if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
  444. return -EOPNOTSUPP;
  445. entry = hfsplus_alloc_attr_entry();
  446. if (!entry) {
  447. pr_err("can't allocate xattr entry\n");
  448. return -ENOMEM;
  449. }
  450. res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
  451. if (res) {
  452. pr_err("can't init xattr find struct\n");
  453. goto failed_getxattr_init;
  454. }
  455. res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
  456. if (res) {
  457. if (res == -ENOENT)
  458. res = -ENODATA;
  459. else
  460. pr_err("xattr searching failed\n");
  461. goto out;
  462. }
  463. hfs_bnode_read(fd.bnode, &xattr_record_type,
  464. fd.entryoffset, sizeof(xattr_record_type));
  465. record_type = be32_to_cpu(xattr_record_type);
  466. if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
  467. record_length = hfs_bnode_read_u16(fd.bnode,
  468. fd.entryoffset +
  469. offsetof(struct hfsplus_attr_inline_data,
  470. length));
  471. if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
  472. pr_err("invalid xattr record size\n");
  473. res = -EIO;
  474. goto out;
  475. }
  476. } else if (record_type == HFSPLUS_ATTR_FORK_DATA ||
  477. record_type == HFSPLUS_ATTR_EXTENTS) {
  478. pr_err("only inline data xattr are supported\n");
  479. res = -EOPNOTSUPP;
  480. goto out;
  481. } else {
  482. pr_err("invalid xattr record\n");
  483. res = -EIO;
  484. goto out;
  485. }
  486. if (size) {
  487. hfs_bnode_read(fd.bnode, entry, fd.entryoffset,
  488. offsetof(struct hfsplus_attr_inline_data,
  489. raw_bytes) + record_length);
  490. }
  491. if (size >= record_length) {
  492. memcpy(value, entry->inline_data.raw_bytes, record_length);
  493. res = record_length;
  494. } else
  495. res = size ? -ERANGE : record_length;
  496. out:
  497. hfs_find_exit(&fd);
  498. failed_getxattr_init:
  499. hfsplus_destroy_attr_entry(entry);
  500. return res;
  501. }
  502. ssize_t hfsplus_getxattr(struct inode *inode, const char *name,
  503. void *value, size_t size,
  504. const char *prefix, size_t prefixlen)
  505. {
  506. int res;
  507. char *xattr_name;
  508. xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
  509. GFP_KERNEL);
  510. if (!xattr_name)
  511. return -ENOMEM;
  512. strcpy(xattr_name, prefix);
  513. strcpy(xattr_name + prefixlen, name);
  514. res = __hfsplus_getxattr(inode, xattr_name, value, size);
  515. kfree(xattr_name);
  516. return res;
  517. }
  518. static inline int can_list(const char *xattr_name)
  519. {
  520. if (!xattr_name)
  521. return 0;
  522. return strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
  523. XATTR_TRUSTED_PREFIX_LEN) ||
  524. capable(CAP_SYS_ADMIN);
  525. }
  526. static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
  527. char *buffer, size_t size)
  528. {
  529. ssize_t res = 0;
  530. struct inode *inode = d_inode(dentry);
  531. struct hfs_find_data fd;
  532. u16 entry_type;
  533. u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
  534. u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
  535. unsigned long len, found_bit;
  536. int xattr_name_len, symbols_count;
  537. res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
  538. if (res) {
  539. pr_err("can't init xattr find struct\n");
  540. return res;
  541. }
  542. res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
  543. if (res)
  544. goto end_listxattr_finder_info;
  545. entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
  546. if (entry_type == HFSPLUS_FOLDER) {
  547. len = sizeof(struct DInfo) + sizeof(struct DXInfo);
  548. hfs_bnode_read(fd.bnode, folder_finder_info,
  549. fd.entryoffset +
  550. offsetof(struct hfsplus_cat_folder, user_info),
  551. len);
  552. found_bit = find_first_bit((void *)folder_finder_info, len*8);
  553. } else if (entry_type == HFSPLUS_FILE) {
  554. len = sizeof(struct FInfo) + sizeof(struct FXInfo);
  555. hfs_bnode_read(fd.bnode, file_finder_info,
  556. fd.entryoffset +
  557. offsetof(struct hfsplus_cat_file, user_info),
  558. len);
  559. found_bit = find_first_bit((void *)file_finder_info, len*8);
  560. } else {
  561. res = -EOPNOTSUPP;
  562. goto end_listxattr_finder_info;
  563. }
  564. if (found_bit >= (len*8))
  565. res = 0;
  566. else {
  567. symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1;
  568. xattr_name_len =
  569. name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count);
  570. if (!buffer || !size) {
  571. if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME))
  572. res = xattr_name_len;
  573. } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) {
  574. if (size < xattr_name_len)
  575. res = -ERANGE;
  576. else {
  577. res = copy_name(buffer,
  578. HFSPLUS_XATTR_FINDER_INFO_NAME,
  579. symbols_count);
  580. }
  581. }
  582. }
  583. end_listxattr_finder_info:
  584. hfs_find_exit(&fd);
  585. return res;
  586. }
  587. ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
  588. {
  589. ssize_t err;
  590. ssize_t res = 0;
  591. struct inode *inode = d_inode(dentry);
  592. struct hfs_find_data fd;
  593. u16 key_len = 0;
  594. struct hfsplus_attr_key attr_key;
  595. char *strbuf;
  596. int xattr_name_len;
  597. if ((!S_ISREG(inode->i_mode) &&
  598. !S_ISDIR(inode->i_mode)) ||
  599. HFSPLUS_IS_RSRC(inode))
  600. return -EOPNOTSUPP;
  601. res = hfsplus_listxattr_finder_info(dentry, buffer, size);
  602. if (res < 0)
  603. return res;
  604. else if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
  605. return (res == 0) ? -EOPNOTSUPP : res;
  606. err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
  607. if (err) {
  608. pr_err("can't init xattr find struct\n");
  609. return err;
  610. }
  611. strbuf = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
  612. XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL);
  613. if (!strbuf) {
  614. res = -ENOMEM;
  615. goto out;
  616. }
  617. err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
  618. if (err) {
  619. if (err == -ENOENT) {
  620. if (res == 0)
  621. res = -ENODATA;
  622. goto end_listxattr;
  623. } else {
  624. res = err;
  625. goto end_listxattr;
  626. }
  627. }
  628. for (;;) {
  629. key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
  630. if (key_len == 0 || key_len > fd.tree->max_key_len) {
  631. pr_err("invalid xattr key length: %d\n", key_len);
  632. res = -EIO;
  633. goto end_listxattr;
  634. }
  635. hfs_bnode_read(fd.bnode, &attr_key,
  636. fd.keyoffset, key_len + sizeof(key_len));
  637. if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
  638. goto end_listxattr;
  639. xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN;
  640. if (hfsplus_uni2asc(inode->i_sb,
  641. (const struct hfsplus_unistr *)&fd.key->attr.key_name,
  642. strbuf, &xattr_name_len)) {
  643. pr_err("unicode conversion failed\n");
  644. res = -EIO;
  645. goto end_listxattr;
  646. }
  647. if (!buffer || !size) {
  648. if (can_list(strbuf))
  649. res += name_len(strbuf, xattr_name_len);
  650. } else if (can_list(strbuf)) {
  651. if (size < (res + name_len(strbuf, xattr_name_len))) {
  652. res = -ERANGE;
  653. goto end_listxattr;
  654. } else
  655. res += copy_name(buffer + res,
  656. strbuf, xattr_name_len);
  657. }
  658. if (hfs_brec_goto(&fd, 1))
  659. goto end_listxattr;
  660. }
  661. end_listxattr:
  662. kfree(strbuf);
  663. out:
  664. hfs_find_exit(&fd);
  665. return res;
  666. }
  667. static int hfsplus_removexattr(struct inode *inode, const char *name)
  668. {
  669. int err = 0;
  670. struct hfs_find_data cat_fd;
  671. u16 flags;
  672. u16 cat_entry_type;
  673. int is_xattr_acl_deleted = 0;
  674. int is_all_xattrs_deleted = 0;
  675. if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
  676. return -EOPNOTSUPP;
  677. if (!strcmp_xattr_finder_info(name))
  678. return -EOPNOTSUPP;
  679. err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
  680. if (err) {
  681. pr_err("can't init xattr find struct\n");
  682. return err;
  683. }
  684. err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
  685. if (err) {
  686. pr_err("catalog searching failed\n");
  687. goto end_removexattr;
  688. }
  689. err = hfsplus_delete_attr(inode, name);
  690. if (err)
  691. goto end_removexattr;
  692. is_xattr_acl_deleted = !strcmp_xattr_acl(name);
  693. is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
  694. if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
  695. goto end_removexattr;
  696. cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
  697. if (cat_entry_type == HFSPLUS_FOLDER) {
  698. flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
  699. offsetof(struct hfsplus_cat_folder, flags));
  700. if (is_xattr_acl_deleted)
  701. flags &= ~HFSPLUS_ACL_EXISTS;
  702. if (is_all_xattrs_deleted)
  703. flags &= ~HFSPLUS_XATTR_EXISTS;
  704. hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
  705. offsetof(struct hfsplus_cat_folder, flags),
  706. flags);
  707. hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
  708. } else if (cat_entry_type == HFSPLUS_FILE) {
  709. flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
  710. offsetof(struct hfsplus_cat_file, flags));
  711. if (is_xattr_acl_deleted)
  712. flags &= ~HFSPLUS_ACL_EXISTS;
  713. if (is_all_xattrs_deleted)
  714. flags &= ~HFSPLUS_XATTR_EXISTS;
  715. hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
  716. offsetof(struct hfsplus_cat_file, flags),
  717. flags);
  718. hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
  719. } else {
  720. pr_err("invalid catalog entry type\n");
  721. err = -EIO;
  722. goto end_removexattr;
  723. }
  724. end_removexattr:
  725. hfs_find_exit(&cat_fd);
  726. return err;
  727. }
  728. static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
  729. struct dentry *unused, struct inode *inode,
  730. const char *name, void *buffer, size_t size,
  731. int flags)
  732. {
  733. /*
  734. * Don't allow retrieving properly prefixed attributes
  735. * by prepending them with "osx."
  736. */
  737. if (is_known_namespace(name))
  738. return -EOPNOTSUPP;
  739. /*
  740. * osx is the namespace we use to indicate an unprefixed
  741. * attribute on the filesystem (like the ones that OS X
  742. * creates), so we pass the name through unmodified (after
  743. * ensuring it doesn't conflict with another namespace).
  744. */
  745. return __hfsplus_getxattr(inode, name, buffer, size);
  746. }
  747. static int hfsplus_osx_setxattr(const struct xattr_handler *handler,
  748. struct dentry *unused, struct inode *inode,
  749. const char *name, const void *buffer,
  750. size_t size, int flags)
  751. {
  752. /*
  753. * Don't allow setting properly prefixed attributes
  754. * by prepending them with "osx."
  755. */
  756. if (is_known_namespace(name))
  757. return -EOPNOTSUPP;
  758. /*
  759. * osx is the namespace we use to indicate an unprefixed
  760. * attribute on the filesystem (like the ones that OS X
  761. * creates), so we pass the name through unmodified (after
  762. * ensuring it doesn't conflict with another namespace).
  763. */
  764. return __hfsplus_setxattr(inode, name, buffer, size, flags);
  765. }
  766. const struct xattr_handler hfsplus_xattr_osx_handler = {
  767. .prefix = XATTR_MAC_OSX_PREFIX,
  768. .get = hfsplus_osx_getxattr,
  769. .set = hfsplus_osx_setxattr,
  770. };