xattr.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: catalog searching failed\n");
  99. goto end_setxattr;
  100. }
  101. if (!strcmp_xattr_finder_info(name)) {
  102. if (flags & XATTR_CREATE) {
  103. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: only inline data xattr are supported\n");
  334. res = -EOPNOTSUPP;
  335. goto out;
  336. } else {
  337. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: 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. printk(KERN_ERR "hfs: invalid xattr key length: %d\n",
  466. key_len);
  467. res = -EIO;
  468. goto end_listxattr;
  469. }
  470. hfs_bnode_read(fd.bnode, &attr_key,
  471. fd.keyoffset, key_len + sizeof(key_len));
  472. if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
  473. goto end_listxattr;
  474. xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN;
  475. if (hfsplus_uni2asc(inode->i_sb,
  476. (const struct hfsplus_unistr *)&fd.key->attr.key_name,
  477. strbuf, &xattr_name_len)) {
  478. printk(KERN_ERR "hfs: unicode conversion failed\n");
  479. res = -EIO;
  480. goto end_listxattr;
  481. }
  482. if (!buffer || !size) {
  483. if (can_list(strbuf))
  484. res += name_len(strbuf, xattr_name_len);
  485. } else if (can_list(strbuf)) {
  486. if (size < (res + name_len(strbuf, xattr_name_len))) {
  487. res = -ERANGE;
  488. goto end_listxattr;
  489. } else
  490. res += copy_name(buffer + res,
  491. strbuf, xattr_name_len);
  492. }
  493. if (hfs_brec_goto(&fd, 1))
  494. goto end_listxattr;
  495. }
  496. end_listxattr:
  497. hfs_find_exit(&fd);
  498. return res;
  499. }
  500. int hfsplus_removexattr(struct dentry *dentry, const char *name)
  501. {
  502. int err = 0;
  503. struct inode *inode = dentry->d_inode;
  504. struct hfs_find_data cat_fd;
  505. u16 flags;
  506. u16 cat_entry_type;
  507. int is_xattr_acl_deleted = 0;
  508. int is_all_xattrs_deleted = 0;
  509. if ((!S_ISREG(inode->i_mode) &&
  510. !S_ISDIR(inode->i_mode)) ||
  511. HFSPLUS_IS_RSRC(inode))
  512. return -EOPNOTSUPP;
  513. if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
  514. return -EOPNOTSUPP;
  515. err = can_set_xattr(inode, name, NULL, 0);
  516. if (err)
  517. return err;
  518. if (strncmp(name, XATTR_MAC_OSX_PREFIX,
  519. XATTR_MAC_OSX_PREFIX_LEN) == 0)
  520. name += XATTR_MAC_OSX_PREFIX_LEN;
  521. if (!strcmp_xattr_finder_info(name))
  522. return -EOPNOTSUPP;
  523. err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
  524. if (err) {
  525. printk(KERN_ERR "hfs: can't init xattr find struct\n");
  526. return err;
  527. }
  528. err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
  529. if (err) {
  530. printk(KERN_ERR "hfs: catalog searching failed\n");
  531. goto end_removexattr;
  532. }
  533. err = hfsplus_delete_attr(inode, name);
  534. if (err)
  535. goto end_removexattr;
  536. is_xattr_acl_deleted = !strcmp_xattr_acl(name);
  537. is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
  538. if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
  539. goto end_removexattr;
  540. cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
  541. if (cat_entry_type == HFSPLUS_FOLDER) {
  542. flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
  543. offsetof(struct hfsplus_cat_folder, flags));
  544. if (is_xattr_acl_deleted)
  545. flags &= ~HFSPLUS_ACL_EXISTS;
  546. if (is_all_xattrs_deleted)
  547. flags &= ~HFSPLUS_XATTR_EXISTS;
  548. hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
  549. offsetof(struct hfsplus_cat_folder, flags),
  550. flags);
  551. hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
  552. } else if (cat_entry_type == HFSPLUS_FILE) {
  553. flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
  554. offsetof(struct hfsplus_cat_file, flags));
  555. if (is_xattr_acl_deleted)
  556. flags &= ~HFSPLUS_ACL_EXISTS;
  557. if (is_all_xattrs_deleted)
  558. flags &= ~HFSPLUS_XATTR_EXISTS;
  559. hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
  560. offsetof(struct hfsplus_cat_file, flags),
  561. flags);
  562. hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
  563. } else {
  564. printk(KERN_ERR "hfs: invalid catalog entry type\n");
  565. err = -EIO;
  566. goto end_removexattr;
  567. }
  568. end_removexattr:
  569. hfs_find_exit(&cat_fd);
  570. return err;
  571. }
  572. static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
  573. void *buffer, size_t size, int type)
  574. {
  575. char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
  576. XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
  577. size_t len = strlen(name);
  578. if (!strcmp(name, ""))
  579. return -EINVAL;
  580. if (len > HFSPLUS_ATTR_MAX_STRLEN)
  581. return -EOPNOTSUPP;
  582. strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
  583. strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
  584. return hfsplus_getxattr(dentry, xattr_name, buffer, size);
  585. }
  586. static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
  587. const void *buffer, size_t size, int flags, int type)
  588. {
  589. char xattr_name[HFSPLUS_ATTR_MAX_STRLEN +
  590. XATTR_MAC_OSX_PREFIX_LEN + 1] = {0};
  591. size_t len = strlen(name);
  592. if (!strcmp(name, ""))
  593. return -EINVAL;
  594. if (len > HFSPLUS_ATTR_MAX_STRLEN)
  595. return -EOPNOTSUPP;
  596. strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
  597. strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
  598. return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags);
  599. }
  600. static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list,
  601. size_t list_size, const char *name, size_t name_len, int type)
  602. {
  603. /*
  604. * This method is not used.
  605. * It is used hfsplus_listxattr() instead of generic_listxattr().
  606. */
  607. return -EOPNOTSUPP;
  608. }
  609. const struct xattr_handler hfsplus_xattr_osx_handler = {
  610. .prefix = XATTR_MAC_OSX_PREFIX,
  611. .list = hfsplus_osx_listxattr,
  612. .get = hfsplus_osx_getxattr,
  613. .set = hfsplus_osx_setxattr,
  614. };