posix_acl.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * linux/fs/hfsplus/posix_acl.c
  3. *
  4. * Vyacheslav Dubeyko <slava@dubeyko.com>
  5. *
  6. * Handler for Posix Access Control Lists (ACLs) support.
  7. */
  8. #include "hfsplus_fs.h"
  9. #include "xattr.h"
  10. #include "acl.h"
  11. struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
  12. {
  13. struct posix_acl *acl;
  14. char *xattr_name;
  15. char *value = NULL;
  16. ssize_t size;
  17. acl = get_cached_acl(inode, type);
  18. if (acl != ACL_NOT_CACHED)
  19. return acl;
  20. switch (type) {
  21. case ACL_TYPE_ACCESS:
  22. xattr_name = POSIX_ACL_XATTR_ACCESS;
  23. break;
  24. case ACL_TYPE_DEFAULT:
  25. xattr_name = POSIX_ACL_XATTR_DEFAULT;
  26. break;
  27. default:
  28. return ERR_PTR(-EINVAL);
  29. }
  30. size = __hfsplus_getxattr(inode, xattr_name, NULL, 0);
  31. if (size > 0) {
  32. value = (char *)hfsplus_alloc_attr_entry();
  33. if (unlikely(!value))
  34. return ERR_PTR(-ENOMEM);
  35. size = __hfsplus_getxattr(inode, xattr_name, value, size);
  36. }
  37. if (size > 0)
  38. acl = posix_acl_from_xattr(&init_user_ns, value, size);
  39. else if (size == -ENODATA)
  40. acl = NULL;
  41. else
  42. acl = ERR_PTR(size);
  43. hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
  44. if (!IS_ERR(acl))
  45. set_cached_acl(inode, type, acl);
  46. return acl;
  47. }
  48. static int hfsplus_set_posix_acl(struct inode *inode,
  49. int type,
  50. struct posix_acl *acl)
  51. {
  52. int err;
  53. char *xattr_name;
  54. size_t size = 0;
  55. char *value = NULL;
  56. if (S_ISLNK(inode->i_mode))
  57. return -EOPNOTSUPP;
  58. switch (type) {
  59. case ACL_TYPE_ACCESS:
  60. xattr_name = POSIX_ACL_XATTR_ACCESS;
  61. if (acl) {
  62. err = posix_acl_equiv_mode(acl, &inode->i_mode);
  63. if (err < 0)
  64. return err;
  65. }
  66. err = 0;
  67. break;
  68. case ACL_TYPE_DEFAULT:
  69. xattr_name = POSIX_ACL_XATTR_DEFAULT;
  70. if (!S_ISDIR(inode->i_mode))
  71. return acl ? -EACCES : 0;
  72. break;
  73. default:
  74. return -EINVAL;
  75. }
  76. if (acl) {
  77. size = posix_acl_xattr_size(acl->a_count);
  78. if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE))
  79. return -ENOMEM;
  80. value = (char *)hfsplus_alloc_attr_entry();
  81. if (unlikely(!value))
  82. return -ENOMEM;
  83. err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
  84. if (unlikely(err < 0))
  85. goto end_set_acl;
  86. }
  87. err = __hfsplus_setxattr(inode, xattr_name, value, size, 0);
  88. end_set_acl:
  89. hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
  90. if (!err)
  91. set_cached_acl(inode, type, acl);
  92. return err;
  93. }
  94. int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
  95. {
  96. int err = 0;
  97. struct posix_acl *acl = NULL;
  98. hfs_dbg(ACL_MOD,
  99. "[%s]: ino %lu, dir->ino %lu\n",
  100. __func__, inode->i_ino, dir->i_ino);
  101. if (S_ISLNK(inode->i_mode))
  102. return 0;
  103. acl = hfsplus_get_posix_acl(dir, ACL_TYPE_DEFAULT);
  104. if (IS_ERR(acl))
  105. return PTR_ERR(acl);
  106. if (acl) {
  107. if (S_ISDIR(inode->i_mode)) {
  108. err = hfsplus_set_posix_acl(inode,
  109. ACL_TYPE_DEFAULT,
  110. acl);
  111. if (unlikely(err))
  112. goto init_acl_cleanup;
  113. }
  114. err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
  115. if (unlikely(err < 0))
  116. return err;
  117. if (err > 0)
  118. err = hfsplus_set_posix_acl(inode,
  119. ACL_TYPE_ACCESS,
  120. acl);
  121. } else
  122. inode->i_mode &= ~current_umask();
  123. init_acl_cleanup:
  124. posix_acl_release(acl);
  125. return err;
  126. }
  127. int hfsplus_posix_acl_chmod(struct inode *inode)
  128. {
  129. int err;
  130. struct posix_acl *acl;
  131. hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
  132. if (S_ISLNK(inode->i_mode))
  133. return -EOPNOTSUPP;
  134. acl = hfsplus_get_posix_acl(inode, ACL_TYPE_ACCESS);
  135. if (IS_ERR(acl) || !acl)
  136. return PTR_ERR(acl);
  137. err = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
  138. if (unlikely(err))
  139. return err;
  140. err = hfsplus_set_posix_acl(inode, ACL_TYPE_ACCESS, acl);
  141. posix_acl_release(acl);
  142. return err;
  143. }
  144. static int hfsplus_xattr_get_posix_acl(struct dentry *dentry,
  145. const char *name,
  146. void *buffer,
  147. size_t size,
  148. int type)
  149. {
  150. int err = 0;
  151. struct posix_acl *acl;
  152. hfs_dbg(ACL_MOD,
  153. "[%s]: ino %lu, buffer %p, size %zu, type %#x\n",
  154. __func__, dentry->d_inode->i_ino, buffer, size, type);
  155. if (strcmp(name, "") != 0)
  156. return -EINVAL;
  157. acl = hfsplus_get_posix_acl(dentry->d_inode, type);
  158. if (IS_ERR(acl))
  159. return PTR_ERR(acl);
  160. if (acl == NULL)
  161. return -ENODATA;
  162. err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
  163. posix_acl_release(acl);
  164. return err;
  165. }
  166. static int hfsplus_xattr_set_posix_acl(struct dentry *dentry,
  167. const char *name,
  168. const void *value,
  169. size_t size,
  170. int flags,
  171. int type)
  172. {
  173. int err = 0;
  174. struct inode *inode = dentry->d_inode;
  175. struct posix_acl *acl = NULL;
  176. hfs_dbg(ACL_MOD,
  177. "[%s]: ino %lu, value %p, size %zu, flags %#x, type %#x\n",
  178. __func__, inode->i_ino, value, size, flags, type);
  179. if (strcmp(name, "") != 0)
  180. return -EINVAL;
  181. if (!inode_owner_or_capable(inode))
  182. return -EPERM;
  183. if (value) {
  184. acl = posix_acl_from_xattr(&init_user_ns, value, size);
  185. if (IS_ERR(acl))
  186. return PTR_ERR(acl);
  187. else if (acl) {
  188. err = posix_acl_valid(acl);
  189. if (err)
  190. goto end_xattr_set_acl;
  191. }
  192. }
  193. err = hfsplus_set_posix_acl(inode, type, acl);
  194. end_xattr_set_acl:
  195. posix_acl_release(acl);
  196. return err;
  197. }
  198. static size_t hfsplus_xattr_list_posix_acl(struct dentry *dentry,
  199. char *list,
  200. size_t list_size,
  201. const char *name,
  202. size_t name_len,
  203. int type)
  204. {
  205. /*
  206. * This method is not used.
  207. * It is used hfsplus_listxattr() instead of generic_listxattr().
  208. */
  209. return -EOPNOTSUPP;
  210. }
  211. const struct xattr_handler hfsplus_xattr_acl_access_handler = {
  212. .prefix = POSIX_ACL_XATTR_ACCESS,
  213. .flags = ACL_TYPE_ACCESS,
  214. .list = hfsplus_xattr_list_posix_acl,
  215. .get = hfsplus_xattr_get_posix_acl,
  216. .set = hfsplus_xattr_set_posix_acl,
  217. };
  218. const struct xattr_handler hfsplus_xattr_acl_default_handler = {
  219. .prefix = POSIX_ACL_XATTR_DEFAULT,
  220. .flags = ACL_TYPE_DEFAULT,
  221. .list = hfsplus_xattr_list_posix_acl,
  222. .get = hfsplus_xattr_get_posix_acl,
  223. .set = hfsplus_xattr_set_posix_acl,
  224. };