4 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
7 * Portions of this code from linux/fs/ext2/acl.c
9 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 #include <linux/f2fs_fs.h>
20 #define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
21 (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
23 static inline size_t f2fs_acl_size(int count
)
26 return sizeof(struct f2fs_acl_header
) +
27 count
* sizeof(struct f2fs_acl_entry_short
);
29 return sizeof(struct f2fs_acl_header
) +
30 4 * sizeof(struct f2fs_acl_entry_short
) +
31 (count
- 4) * sizeof(struct f2fs_acl_entry
);
35 static inline int f2fs_acl_count(size_t size
)
38 size
-= sizeof(struct f2fs_acl_header
);
39 s
= size
- 4 * sizeof(struct f2fs_acl_entry_short
);
41 if (size
% sizeof(struct f2fs_acl_entry_short
))
43 return size
/ sizeof(struct f2fs_acl_entry_short
);
45 if (s
% sizeof(struct f2fs_acl_entry
))
47 return s
/ sizeof(struct f2fs_acl_entry
) + 4;
51 static struct posix_acl
*f2fs_acl_from_disk(const char *value
, size_t size
)
54 struct posix_acl
*acl
;
55 struct f2fs_acl_header
*hdr
= (struct f2fs_acl_header
*)value
;
56 struct f2fs_acl_entry
*entry
= (struct f2fs_acl_entry
*)(hdr
+ 1);
57 const char *end
= value
+ size
;
59 if (hdr
->a_version
!= cpu_to_le32(F2FS_ACL_VERSION
))
60 return ERR_PTR(-EINVAL
);
62 count
= f2fs_acl_count(size
);
64 return ERR_PTR(-EINVAL
);
68 acl
= posix_acl_alloc(count
, GFP_KERNEL
);
70 return ERR_PTR(-ENOMEM
);
72 for (i
= 0; i
< count
; i
++) {
74 if ((char *)entry
> end
)
77 acl
->a_entries
[i
].e_tag
= le16_to_cpu(entry
->e_tag
);
78 acl
->a_entries
[i
].e_perm
= le16_to_cpu(entry
->e_perm
);
80 switch (acl
->a_entries
[i
].e_tag
) {
85 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
86 sizeof(struct f2fs_acl_entry_short
));
90 acl
->a_entries
[i
].e_uid
=
91 make_kuid(&init_user_ns
,
92 le32_to_cpu(entry
->e_id
));
93 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
94 sizeof(struct f2fs_acl_entry
));
97 acl
->a_entries
[i
].e_gid
=
98 make_kgid(&init_user_ns
,
99 le32_to_cpu(entry
->e_id
));
100 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
101 sizeof(struct f2fs_acl_entry
));
107 if ((char *)entry
!= end
)
111 posix_acl_release(acl
);
112 return ERR_PTR(-EINVAL
);
115 static void *f2fs_acl_to_disk(const struct posix_acl
*acl
, size_t *size
)
117 struct f2fs_acl_header
*f2fs_acl
;
118 struct f2fs_acl_entry
*entry
;
121 f2fs_acl
= kmalloc(sizeof(struct f2fs_acl_header
) + acl
->a_count
*
122 sizeof(struct f2fs_acl_entry
), GFP_KERNEL
);
124 return ERR_PTR(-ENOMEM
);
126 f2fs_acl
->a_version
= cpu_to_le32(F2FS_ACL_VERSION
);
127 entry
= (struct f2fs_acl_entry
*)(f2fs_acl
+ 1);
129 for (i
= 0; i
< acl
->a_count
; i
++) {
131 entry
->e_tag
= cpu_to_le16(acl
->a_entries
[i
].e_tag
);
132 entry
->e_perm
= cpu_to_le16(acl
->a_entries
[i
].e_perm
);
134 switch (acl
->a_entries
[i
].e_tag
) {
136 entry
->e_id
= cpu_to_le32(
137 from_kuid(&init_user_ns
,
138 acl
->a_entries
[i
].e_uid
));
139 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
140 sizeof(struct f2fs_acl_entry
));
143 entry
->e_id
= cpu_to_le32(
144 from_kgid(&init_user_ns
,
145 acl
->a_entries
[i
].e_gid
));
146 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
147 sizeof(struct f2fs_acl_entry
));
153 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
154 sizeof(struct f2fs_acl_entry_short
));
160 *size
= f2fs_acl_size(acl
->a_count
);
161 return (void *)f2fs_acl
;
165 return ERR_PTR(-EINVAL
);
168 struct posix_acl
*f2fs_get_acl(struct inode
*inode
, int type
)
170 struct f2fs_sb_info
*sbi
= F2FS_SB(inode
->i_sb
);
171 int name_index
= F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT
;
173 struct posix_acl
*acl
;
176 if (!test_opt(sbi
, POSIX_ACL
))
179 acl
= get_cached_acl(inode
, type
);
180 if (acl
!= ACL_NOT_CACHED
)
183 if (type
== ACL_TYPE_ACCESS
)
184 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_ACCESS
;
186 retval
= f2fs_getxattr(inode
, name_index
, "", NULL
, 0);
188 value
= kmalloc(retval
, GFP_KERNEL
);
190 return ERR_PTR(-ENOMEM
);
191 retval
= f2fs_getxattr(inode
, name_index
, "", value
, retval
);
195 acl
= f2fs_acl_from_disk(value
, retval
);
196 else if (retval
== -ENODATA
)
199 acl
= ERR_PTR(retval
);
203 set_cached_acl(inode
, type
, acl
);
208 static int f2fs_set_acl(struct inode
*inode
, int type
, struct posix_acl
*acl
)
210 struct f2fs_sb_info
*sbi
= F2FS_SB(inode
->i_sb
);
211 struct f2fs_inode_info
*fi
= F2FS_I(inode
);
217 if (!test_opt(sbi
, POSIX_ACL
))
219 if (S_ISLNK(inode
->i_mode
))
223 case ACL_TYPE_ACCESS
:
224 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_ACCESS
;
226 error
= posix_acl_equiv_mode(acl
, &inode
->i_mode
);
229 set_acl_inode(fi
, inode
->i_mode
);
235 case ACL_TYPE_DEFAULT
:
236 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT
;
237 if (!S_ISDIR(inode
->i_mode
))
238 return acl
? -EACCES
: 0;
246 value
= f2fs_acl_to_disk(acl
, &size
);
248 cond_clear_inode_flag(fi
, FI_ACL_MODE
);
249 return (int)PTR_ERR(value
);
253 error
= f2fs_setxattr(inode
, name_index
, "", value
, size
, NULL
);
257 set_cached_acl(inode
, type
, acl
);
259 cond_clear_inode_flag(fi
, FI_ACL_MODE
);
263 int f2fs_init_acl(struct inode
*inode
, struct inode
*dir
)
265 struct posix_acl
*acl
= NULL
;
266 struct f2fs_sb_info
*sbi
= F2FS_SB(dir
->i_sb
);
269 if (!S_ISLNK(inode
->i_mode
)) {
270 if (test_opt(sbi
, POSIX_ACL
)) {
271 acl
= f2fs_get_acl(dir
, ACL_TYPE_DEFAULT
);
276 inode
->i_mode
&= ~current_umask();
279 if (test_opt(sbi
, POSIX_ACL
) && acl
) {
281 if (S_ISDIR(inode
->i_mode
)) {
282 error
= f2fs_set_acl(inode
, ACL_TYPE_DEFAULT
, acl
);
286 error
= posix_acl_create(&acl
, GFP_KERNEL
, &inode
->i_mode
);
290 error
= f2fs_set_acl(inode
, ACL_TYPE_ACCESS
, acl
);
293 posix_acl_release(acl
);
297 int f2fs_acl_chmod(struct inode
*inode
)
299 struct f2fs_sb_info
*sbi
= F2FS_SB(inode
->i_sb
);
300 struct posix_acl
*acl
;
302 umode_t mode
= get_inode_mode(inode
);
304 if (!test_opt(sbi
, POSIX_ACL
))
309 acl
= f2fs_get_acl(inode
, ACL_TYPE_ACCESS
);
310 if (IS_ERR(acl
) || !acl
)
313 error
= posix_acl_chmod(&acl
, GFP_KERNEL
, mode
);
316 error
= f2fs_set_acl(inode
, ACL_TYPE_ACCESS
, acl
);
317 posix_acl_release(acl
);
321 static size_t f2fs_xattr_list_acl(struct dentry
*dentry
, char *list
,
322 size_t list_size
, const char *name
, size_t name_len
, int type
)
324 struct f2fs_sb_info
*sbi
= F2FS_SB(dentry
->d_sb
);
325 const char *xname
= POSIX_ACL_XATTR_DEFAULT
;
328 if (!test_opt(sbi
, POSIX_ACL
))
331 if (type
== ACL_TYPE_ACCESS
)
332 xname
= POSIX_ACL_XATTR_ACCESS
;
334 size
= strlen(xname
) + 1;
335 if (list
&& size
<= list_size
)
336 memcpy(list
, xname
, size
);
340 static int f2fs_xattr_get_acl(struct dentry
*dentry
, const char *name
,
341 void *buffer
, size_t size
, int type
)
343 struct f2fs_sb_info
*sbi
= F2FS_SB(dentry
->d_sb
);
344 struct posix_acl
*acl
;
347 if (strcmp(name
, "") != 0)
349 if (!test_opt(sbi
, POSIX_ACL
))
352 acl
= f2fs_get_acl(dentry
->d_inode
, type
);
357 error
= posix_acl_to_xattr(&init_user_ns
, acl
, buffer
, size
);
358 posix_acl_release(acl
);
363 static int f2fs_xattr_set_acl(struct dentry
*dentry
, const char *name
,
364 const void *value
, size_t size
, int flags
, int type
)
366 struct f2fs_sb_info
*sbi
= F2FS_SB(dentry
->d_sb
);
367 struct inode
*inode
= dentry
->d_inode
;
368 struct posix_acl
*acl
= NULL
;
371 if (strcmp(name
, "") != 0)
373 if (!test_opt(sbi
, POSIX_ACL
))
375 if (!inode_owner_or_capable(inode
))
379 acl
= posix_acl_from_xattr(&init_user_ns
, value
, size
);
383 error
= posix_acl_valid(acl
);
385 goto release_and_out
;
391 error
= f2fs_set_acl(inode
, type
, acl
);
394 posix_acl_release(acl
);
398 const struct xattr_handler f2fs_xattr_acl_default_handler
= {
399 .prefix
= POSIX_ACL_XATTR_DEFAULT
,
400 .flags
= ACL_TYPE_DEFAULT
,
401 .list
= f2fs_xattr_list_acl
,
402 .get
= f2fs_xattr_get_acl
,
403 .set
= f2fs_xattr_set_acl
,
406 const struct xattr_handler f2fs_xattr_acl_access_handler
= {
407 .prefix
= POSIX_ACL_XATTR_ACCESS
,
408 .flags
= ACL_TYPE_ACCESS
,
409 .list
= f2fs_xattr_list_acl
,
410 .get
= f2fs_xattr_get_acl
,
411 .set
= f2fs_xattr_set_acl
,