xattr.c 18 KB

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