xattr.c 19 KB

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