xattr.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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_conn *fc = get_fuse_conn(inode);
  15. FUSE_ARGS(args);
  16. struct fuse_setxattr_in inarg;
  17. int err;
  18. if (fc->no_setxattr)
  19. return -EOPNOTSUPP;
  20. memset(&inarg, 0, sizeof(inarg));
  21. inarg.size = size;
  22. inarg.flags = flags;
  23. args.in.h.opcode = FUSE_SETXATTR;
  24. args.in.h.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(fc, &args);
  33. if (err == -ENOSYS) {
  34. 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_conn *fc = get_fuse_conn(inode);
  47. FUSE_ARGS(args);
  48. struct fuse_getxattr_in inarg;
  49. struct fuse_getxattr_out outarg;
  50. ssize_t ret;
  51. if (fc->no_getxattr)
  52. return -EOPNOTSUPP;
  53. memset(&inarg, 0, sizeof(inarg));
  54. inarg.size = size;
  55. args.in.h.opcode = FUSE_GETXATTR;
  56. args.in.h.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 = 1;
  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(fc, &args);
  73. if (!ret && !size)
  74. ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
  75. if (ret == -ENOSYS) {
  76. 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_conn *fc = get_fuse_conn(inode);
  97. FUSE_ARGS(args);
  98. struct fuse_getxattr_in inarg;
  99. struct fuse_getxattr_out outarg;
  100. ssize_t ret;
  101. if (!fuse_allow_current_process(fc))
  102. return -EACCES;
  103. if (fc->no_listxattr)
  104. return -EOPNOTSUPP;
  105. memset(&inarg, 0, sizeof(inarg));
  106. inarg.size = size;
  107. args.in.h.opcode = FUSE_LISTXATTR;
  108. args.in.h.nodeid = get_node_id(inode);
  109. args.in.numargs = 1;
  110. args.in.args[0].size = sizeof(inarg);
  111. args.in.args[0].value = &inarg;
  112. /* This is really two different operations rolled into one */
  113. args.out.numargs = 1;
  114. if (size) {
  115. args.out.argvar = 1;
  116. args.out.args[0].size = size;
  117. args.out.args[0].value = list;
  118. } else {
  119. args.out.args[0].size = sizeof(outarg);
  120. args.out.args[0].value = &outarg;
  121. }
  122. ret = fuse_simple_request(fc, &args);
  123. if (!ret && !size)
  124. ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
  125. if (ret > 0 && size)
  126. ret = fuse_verify_xattr_list(list, ret);
  127. if (ret == -ENOSYS) {
  128. fc->no_listxattr = 1;
  129. ret = -EOPNOTSUPP;
  130. }
  131. return ret;
  132. }
  133. int fuse_removexattr(struct inode *inode, const char *name)
  134. {
  135. struct fuse_conn *fc = get_fuse_conn(inode);
  136. FUSE_ARGS(args);
  137. int err;
  138. if (fc->no_removexattr)
  139. return -EOPNOTSUPP;
  140. args.in.h.opcode = FUSE_REMOVEXATTR;
  141. args.in.h.nodeid = get_node_id(inode);
  142. args.in.numargs = 1;
  143. args.in.args[0].size = strlen(name) + 1;
  144. args.in.args[0].value = name;
  145. err = fuse_simple_request(fc, &args);
  146. if (err == -ENOSYS) {
  147. fc->no_removexattr = 1;
  148. err = -EOPNOTSUPP;
  149. }
  150. if (!err) {
  151. fuse_invalidate_attr(inode);
  152. fuse_update_ctime(inode);
  153. }
  154. return err;
  155. }
  156. static int fuse_xattr_get(const struct xattr_handler *handler,
  157. struct dentry *dentry, struct inode *inode,
  158. const char *name, void *value, size_t size)
  159. {
  160. return fuse_getxattr(inode, name, value, size);
  161. }
  162. static int fuse_xattr_set(const struct xattr_handler *handler,
  163. struct dentry *dentry, struct inode *inode,
  164. const char *name, const void *value, size_t size,
  165. int flags)
  166. {
  167. if (!value)
  168. return fuse_removexattr(inode, name);
  169. return fuse_setxattr(inode, name, value, size, flags);
  170. }
  171. static bool no_xattr_list(struct dentry *dentry)
  172. {
  173. return false;
  174. }
  175. static int no_xattr_get(const struct xattr_handler *handler,
  176. struct dentry *dentry, struct inode *inode,
  177. const char *name, void *value, size_t size)
  178. {
  179. return -EOPNOTSUPP;
  180. }
  181. static int no_xattr_set(const struct xattr_handler *handler,
  182. struct dentry *dentry, struct inode *nodee,
  183. const char *name, const void *value,
  184. size_t size, int flags)
  185. {
  186. return -EOPNOTSUPP;
  187. }
  188. static const struct xattr_handler fuse_xattr_handler = {
  189. .prefix = "",
  190. .get = fuse_xattr_get,
  191. .set = fuse_xattr_set,
  192. };
  193. const struct xattr_handler *fuse_xattr_handlers[] = {
  194. &fuse_xattr_handler,
  195. NULL
  196. };
  197. const struct xattr_handler *fuse_acl_xattr_handlers[] = {
  198. &posix_acl_access_xattr_handler,
  199. &posix_acl_default_xattr_handler,
  200. &fuse_xattr_handler,
  201. NULL
  202. };
  203. static const struct xattr_handler fuse_no_acl_access_xattr_handler = {
  204. .name = XATTR_NAME_POSIX_ACL_ACCESS,
  205. .flags = ACL_TYPE_ACCESS,
  206. .list = no_xattr_list,
  207. .get = no_xattr_get,
  208. .set = no_xattr_set,
  209. };
  210. static const struct xattr_handler fuse_no_acl_default_xattr_handler = {
  211. .name = XATTR_NAME_POSIX_ACL_DEFAULT,
  212. .flags = ACL_TYPE_ACCESS,
  213. .list = no_xattr_list,
  214. .get = no_xattr_get,
  215. .set = no_xattr_set,
  216. };
  217. const struct xattr_handler *fuse_no_acl_xattr_handlers[] = {
  218. &fuse_no_acl_access_xattr_handler,
  219. &fuse_no_acl_default_xattr_handler,
  220. &fuse_xattr_handler,
  221. NULL
  222. };