posix_acl.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
  18. switch (type) {
  19. case ACL_TYPE_ACCESS:
  20. xattr_name = POSIX_ACL_XATTR_ACCESS;
  21. break;
  22. case ACL_TYPE_DEFAULT:
  23. xattr_name = POSIX_ACL_XATTR_DEFAULT;
  24. break;
  25. default:
  26. return ERR_PTR(-EINVAL);
  27. }
  28. size = __hfsplus_getxattr(inode, xattr_name, NULL, 0);
  29. if (size > 0) {
  30. value = (char *)hfsplus_alloc_attr_entry();
  31. if (unlikely(!value))
  32. return ERR_PTR(-ENOMEM);
  33. size = __hfsplus_getxattr(inode, xattr_name, value, size);
  34. }
  35. if (size > 0)
  36. acl = posix_acl_from_xattr(&init_user_ns, value, size);
  37. else if (size == -ENODATA)
  38. acl = NULL;
  39. else
  40. acl = ERR_PTR(size);
  41. hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
  42. if (!IS_ERR(acl))
  43. set_cached_acl(inode, type, acl);
  44. return acl;
  45. }
  46. int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
  47. int type)
  48. {
  49. int err;
  50. char *xattr_name;
  51. size_t size = 0;
  52. char *value = NULL;
  53. hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
  54. switch (type) {
  55. case ACL_TYPE_ACCESS:
  56. xattr_name = POSIX_ACL_XATTR_ACCESS;
  57. if (acl) {
  58. err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
  59. if (err)
  60. return err;
  61. }
  62. err = 0;
  63. break;
  64. case ACL_TYPE_DEFAULT:
  65. xattr_name = POSIX_ACL_XATTR_DEFAULT;
  66. if (!S_ISDIR(inode->i_mode))
  67. return acl ? -EACCES : 0;
  68. break;
  69. default:
  70. return -EINVAL;
  71. }
  72. if (acl) {
  73. size = posix_acl_xattr_size(acl->a_count);
  74. if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE))
  75. return -ENOMEM;
  76. value = (char *)hfsplus_alloc_attr_entry();
  77. if (unlikely(!value))
  78. return -ENOMEM;
  79. err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
  80. if (unlikely(err < 0))
  81. goto end_set_acl;
  82. }
  83. err = __hfsplus_setxattr(inode, xattr_name, value, size, 0);
  84. end_set_acl:
  85. hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
  86. if (!err)
  87. set_cached_acl(inode, type, acl);
  88. return err;
  89. }
  90. int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
  91. {
  92. int err = 0;
  93. struct posix_acl *default_acl, *acl;
  94. hfs_dbg(ACL_MOD,
  95. "[%s]: ino %lu, dir->ino %lu\n",
  96. __func__, inode->i_ino, dir->i_ino);
  97. if (S_ISLNK(inode->i_mode))
  98. return 0;
  99. err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
  100. if (err)
  101. return err;
  102. if (default_acl) {
  103. err = hfsplus_set_posix_acl(inode, default_acl,
  104. ACL_TYPE_DEFAULT);
  105. posix_acl_release(default_acl);
  106. }
  107. if (acl) {
  108. if (!err)
  109. err = hfsplus_set_posix_acl(inode, acl,
  110. ACL_TYPE_ACCESS);
  111. posix_acl_release(acl);
  112. }
  113. return err;
  114. }