xattr.c 21 KB

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