xattr.c 25 KB

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