xattr.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * FUSE: Filesystem in Userspace
  3. * Copyright (C) 2001-2016 Miklos Szeredi <miklos@szeredi.hu>
  4. *
  5. * This program can be distributed under the terms of the GNU GPL.
  6. * See the file COPYING.
  7. */
  8. #include "fuse_i.h"
  9. #include <linux/xattr.h>
  10. #include <linux/posix_acl_xattr.h>
  11. int fuse_setxattr(struct inode *inode, const char *name, const void *value,
  12. size_t size, int flags)
  13. {
  14. struct fuse_mount *fm = get_fuse_mount(inode);
  15. FUSE_ARGS(args);
  16. struct fuse_setxattr_in inarg;
  17. int err;
  18. if (fm->fc->no_setxattr)
  19. return -EOPNOTSUPP;
  20. memset(&inarg, 0, sizeof(inarg));
  21. inarg.size = size;
  22. inarg.flags = flags;
  23. args.opcode = FUSE_SETXATTR;
  24. args.nodeid = get_node_id(inode);
  25. args.in_numargs = 3;
  26. args.in_args[0].size = sizeof(inarg);
  27. args.in_args[0].value = &inarg;
  28. args.in_args[1].size = strlen(name) + 1;
  29. args.in_args[1].value = name;
  30. args.in_args[2].size = size;
  31. args.in_args[2].value = value;
  32. err = fuse_simple_request(fm, &args);
  33. if (err == -ENOSYS) {
  34. fm->fc->no_setxattr = 1;
  35. err = -EOPNOTSUPP;
  36. }
  37. if (!err) {
  38. fuse_invalidate_attr(inode);
  39. fuse_update_ctime(inode);
  40. }
  41. return err;
  42. }
  43. ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
  44. size_t size)
  45. {
  46. struct fuse_mount *fm = get_fuse_mount(inode);
  47. FUSE_ARGS(args);
  48. struct fuse_getxattr_in inarg;
  49. struct fuse_getxattr_out outarg;
  50. ssize_t ret;
  51. if (fm->fc->no_getxattr)
  52. return -EOPNOTSUPP;
  53. memset(&inarg, 0, sizeof(inarg));
  54. inarg.size = size;
  55. args.opcode = FUSE_GETXATTR;
  56. args.nodeid = get_node_id(inode);
  57. args.in_numargs = 2;
  58. args.in_args[0].size = sizeof(inarg);
  59. args.in_args[0].value = &inarg;
  60. args.in_args[1].size = strlen(name) + 1;
  61. args.in_args[1].value = name;
  62. /* This is really two different operations rolled into one */
  63. args.out_numargs = 1;
  64. if (size) {
  65. args.out_argvar = true;
  66. args.out_args[0].size = size;
  67. args.out_args[0].value = value;
  68. } else {
  69. args.out_args[0].size = sizeof(outarg);
  70. args.out_args[0].value = &outarg;
  71. }
  72. ret = fuse_simple_request(fm, &args);
  73. if (!ret && !size)
  74. ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
  75. if (ret == -ENOSYS) {
  76. fm->fc->no_getxattr = 1;
  77. ret = -EOPNOTSUPP;
  78. }
  79. return ret;
  80. }
  81. static int fuse_verify_xattr_list(char *list, size_t size)
  82. {
  83. size_t origsize = size;
  84. while (size) {
  85. size_t thislen = strnlen(list, size);
  86. if (!thislen || thislen == size)
  87. return -EIO;
  88. size -= thislen + 1;
  89. list += thislen + 1;
  90. }
  91. return origsize;
  92. }
  93. ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
  94. {
  95. struct inode *inode = d_inode(entry);
  96. struct fuse_mount *fm = get_fuse_mount(inode);
  97. FUSE_ARGS(args);
  98. struct fuse_getxattr_in inarg;
  99. struct fuse_getxattr_out outarg;
  100. ssize_t ret;
  101. if (fuse_is_bad(inode))
  102. return -EIO;
  103. if (!fuse_allow_current_process(fm->fc))
  104. return -EACCES;
  105. if (fm->fc->no_listxattr)
  106. return -EOPNOTSUPP;
  107. memset(&inarg, 0, sizeof(inarg));
  108. inarg.size = size;
  109. args.opcode = FUSE_LISTXATTR;
  110. args.nodeid = get_node_id(inode);
  111. args.in_numargs = 1;
  112. args.in_args[0].size = sizeof(inarg);
  113. args.in_args[0].value = &inarg;
  114. /* This is really two different operations rolled into one */
  115. args.out_numargs = 1;
  116. if (size) {
  117. args.out_argvar = true;
  118. args.out_args[0].size = size;
  119. args.out_args[0].value = list;
  120. } else {
  121. args.out_args[0].size = sizeof(outarg);
  122. args.out_args[0].value = &outarg;
  123. }
  124. ret = fuse_simple_request(fm, &args);
  125. if (!ret && !size)
  126. ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
  127. if (ret > 0 && size)
  128. ret = fuse_verify_xattr_list(list, ret);
  129. if (ret == -ENOSYS) {
  130. fm->fc->no_listxattr = 1;
  131. ret = -EOPNOTSUPP;
  132. }
  133. return ret;
  134. }
  135. int fuse_removexattr(struct inode *inode, const char *name)
  136. {
  137. struct fuse_mount *fm = get_fuse_mount(inode);
  138. FUSE_ARGS(args);
  139. int err;
  140. if (fm->fc->no_removexattr)
  141. return -EOPNOTSUPP;
  142. args.opcode = FUSE_REMOVEXATTR;
  143. args.nodeid = get_node_id(inode);
  144. args.in_numargs = 1;
  145. args.in_args[0].size = strlen(name) + 1;
  146. args.in_args[0].value = name;
  147. err = fuse_simple_request(fm, &args);
  148. if (err == -ENOSYS) {
  149. fm->fc->no_removexattr = 1;
  150. err = -EOPNOTSUPP;
  151. }
  152. if (!err) {
  153. fuse_invalidate_attr(inode);
  154. fuse_update_ctime(inode);
  155. }
  156. return err;
  157. }
  158. static int fuse_xattr_get(const struct xattr_handler *handler,
  159. struct dentry *dentry, struct inode *inode,
  160. const char *name, void *value, size_t size, int flags)
  161. {
  162. if (fuse_is_bad(inode))
  163. return -EIO;
  164. return fuse_getxattr(inode, name, value, size);
  165. }
  166. static int fuse_xattr_set(const struct xattr_handler *handler,
  167. struct dentry *dentry, struct inode *inode,
  168. const char *name, const void *value, size_t size,
  169. int flags)
  170. {
  171. if (fuse_is_bad(inode))
  172. return -EIO;
  173. if (!value)
  174. return fuse_removexattr(inode, name);
  175. return fuse_setxattr(inode, name, value, size, flags);
  176. }
  177. static bool no_xattr_list(struct dentry *dentry)
  178. {
  179. return false;
  180. }
  181. static int no_xattr_get(const struct xattr_handler *handler,
  182. struct dentry *dentry, struct inode *inode,
  183. const char *name, void *value, size_t size, int flags)
  184. {
  185. return -EOPNOTSUPP;
  186. }
  187. static int no_xattr_set(const struct xattr_handler *handler,
  188. struct dentry *dentry, struct inode *nodee,
  189. const char *name, const void *value,
  190. size_t size, int flags)
  191. {
  192. return -EOPNOTSUPP;
  193. }
  194. static const struct xattr_handler fuse_xattr_handler = {
  195. .prefix = "",
  196. .get = fuse_xattr_get,
  197. .set = fuse_xattr_set,
  198. };
  199. const struct xattr_handler *fuse_xattr_handlers[] = {
  200. &fuse_xattr_handler,
  201. NULL
  202. };
  203. const struct xattr_handler *fuse_acl_xattr_handlers[] = {
  204. &posix_acl_access_xattr_handler,
  205. &posix_acl_default_xattr_handler,
  206. &fuse_xattr_handler,
  207. NULL
  208. };
  209. static const struct xattr_handler fuse_no_acl_access_xattr_handler = {
  210. .name = XATTR_NAME_POSIX_ACL_ACCESS,
  211. .flags = ACL_TYPE_ACCESS,
  212. .list = no_xattr_list,
  213. .get = no_xattr_get,
  214. .set = no_xattr_set,
  215. };
  216. static const struct xattr_handler fuse_no_acl_default_xattr_handler = {
  217. .name = XATTR_NAME_POSIX_ACL_DEFAULT,
  218. .flags = ACL_TYPE_ACCESS,
  219. .list = no_xattr_list,
  220. .get = no_xattr_get,
  221. .set = no_xattr_set,
  222. };
  223. const struct xattr_handler *fuse_no_acl_xattr_handlers[] = {
  224. &fuse_no_acl_access_xattr_handler,
  225. &fuse_no_acl_default_xattr_handler,
  226. &fuse_xattr_handler,
  227. NULL
  228. };