xattr.c 25 KB

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