• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 #include "hfsplus_fs.h"
10 #include "xattr.h"
11 #include "acl.h"
12 
hfsplus_get_posix_acl(struct inode * inode,int type)13 struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
14 {
15 	struct posix_acl *acl;
16 	char *xattr_name;
17 	char *value = NULL;
18 	ssize_t size;
19 
20 	hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
21 
22 	switch (type) {
23 	case ACL_TYPE_ACCESS:
24 		xattr_name = POSIX_ACL_XATTR_ACCESS;
25 		break;
26 	case ACL_TYPE_DEFAULT:
27 		xattr_name = POSIX_ACL_XATTR_DEFAULT;
28 		break;
29 	default:
30 		return ERR_PTR(-EINVAL);
31 	}
32 
33 	size = __hfsplus_getxattr(inode, xattr_name, NULL, 0);
34 
35 	if (size > 0) {
36 		value = (char *)hfsplus_alloc_attr_entry();
37 		if (unlikely(!value))
38 			return ERR_PTR(-ENOMEM);
39 		size = __hfsplus_getxattr(inode, xattr_name, value, size);
40 	}
41 
42 	if (size > 0)
43 		acl = posix_acl_from_xattr(&init_user_ns, value, size);
44 	else if (size == -ENODATA)
45 		acl = NULL;
46 	else
47 		acl = ERR_PTR(size);
48 
49 	hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
50 
51 	if (!IS_ERR(acl))
52 		set_cached_acl(inode, type, acl);
53 
54 	return acl;
55 }
56 
hfsplus_set_posix_acl(struct inode * inode,struct posix_acl * acl,int type)57 int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
58 		int type)
59 {
60 	int err;
61 	char *xattr_name;
62 	size_t size = 0;
63 	char *value = NULL;
64 
65 	hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
66 
67 	switch (type) {
68 	case ACL_TYPE_ACCESS:
69 		xattr_name = POSIX_ACL_XATTR_ACCESS;
70 		if (acl) {
71 			err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
72 			if (err)
73 				return err;
74 		}
75 		err = 0;
76 		break;
77 
78 	case ACL_TYPE_DEFAULT:
79 		xattr_name = POSIX_ACL_XATTR_DEFAULT;
80 		if (!S_ISDIR(inode->i_mode))
81 			return acl ? -EACCES : 0;
82 		break;
83 
84 	default:
85 		return -EINVAL;
86 	}
87 
88 	if (acl) {
89 		size = posix_acl_xattr_size(acl->a_count);
90 		if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE))
91 			return -ENOMEM;
92 		value = (char *)hfsplus_alloc_attr_entry();
93 		if (unlikely(!value))
94 			return -ENOMEM;
95 		err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
96 		if (unlikely(err < 0))
97 			goto end_set_acl;
98 	}
99 
100 	err = __hfsplus_setxattr(inode, xattr_name, value, size, 0);
101 
102 end_set_acl:
103 	hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
104 
105 	if (!err)
106 		set_cached_acl(inode, type, acl);
107 
108 	return err;
109 }
110 
hfsplus_init_posix_acl(struct inode * inode,struct inode * dir)111 int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
112 {
113 	int err = 0;
114 	struct posix_acl *default_acl, *acl;
115 
116 	hfs_dbg(ACL_MOD,
117 		"[%s]: ino %lu, dir->ino %lu\n",
118 		__func__, inode->i_ino, dir->i_ino);
119 
120 	if (S_ISLNK(inode->i_mode))
121 		return 0;
122 
123 	err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
124 	if (err)
125 		return err;
126 
127 	if (default_acl) {
128 		err = hfsplus_set_posix_acl(inode, default_acl,
129 					    ACL_TYPE_DEFAULT);
130 		posix_acl_release(default_acl);
131 	}
132 
133 	if (acl) {
134 		if (!err)
135 			err = hfsplus_set_posix_acl(inode, acl,
136 						    ACL_TYPE_ACCESS);
137 		posix_acl_release(acl);
138 	}
139 	return err;
140 }
141