xattr.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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, unsigned int extra_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. inarg.setxattr_flags = extra_flags;
  24. args.opcode = FUSE_SETXATTR;
  25. args.nodeid = get_node_id(inode);
  26. args.in_numargs = 3;
  27. args.in_args[0].size = fm->fc->setxattr_ext ?
  28. sizeof(inarg) : FUSE_COMPAT_SETXATTR_IN_SIZE;
  29. args.in_args[0].value = &inarg;
  30. args.in_args[1].size = strlen(name) + 1;
  31. args.in_args[1].value = name;
  32. args.in_args[2].size = size;
  33. args.in_args[2].value = value;
  34. err = fuse_simple_request(fm, &args);
  35. if (err == -ENOSYS) {
  36. fm->fc->no_setxattr = 1;
  37. err = -EOPNOTSUPP;
  38. }
  39. if (!err)
  40. fuse_update_ctime(inode);
  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(size_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(size_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_update_ctime(inode);
  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. if (fuse_is_bad(inode))
  161. return -EIO;
  162. return fuse_getxattr(inode, name, value, size);
  163. }
  164. static int fuse_xattr_set(const struct xattr_handler *handler,
  165. struct mnt_idmap *idmap,
  166. struct dentry *dentry, struct inode *inode,
  167. const char *name, const void *value, size_t size,
  168. int flags)
  169. {
  170. if (fuse_is_bad(inode))
  171. return -EIO;
  172. if (!value)
  173. return fuse_removexattr(inode, name);
  174. return fuse_setxattr(inode, name, value, size, flags, 0);
  175. }
  176. static const struct xattr_handler fuse_xattr_handler = {
  177. .prefix = "",
  178. .get = fuse_xattr_get,
  179. .set = fuse_xattr_set,
  180. };
  181. const struct xattr_handler * const fuse_xattr_handlers[] = {
  182. &fuse_xattr_handler,
  183. NULL
  184. };