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
,
209 struct posix_acl
*acl
, struct page
*ipage
)
211 struct f2fs_sb_info
*sbi
= F2FS_SB(inode
->i_sb
);
212 struct f2fs_inode_info
*fi
= F2FS_I(inode
);
218 if (!test_opt(sbi
, POSIX_ACL
))
220 if (S_ISLNK(inode
->i_mode
))
224 case ACL_TYPE_ACCESS
:
225 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_ACCESS
;
227 error
= posix_acl_equiv_mode(acl
, &inode
->i_mode
);
230 set_acl_inode(fi
, inode
->i_mode
);
236 case ACL_TYPE_DEFAULT
:
237 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT
;
238 if (!S_ISDIR(inode
->i_mode
))
239 return acl
? -EACCES
: 0;
247 value
= f2fs_acl_to_disk(acl
, &size
);
249 cond_clear_inode_flag(fi
, FI_ACL_MODE
);
250 return (int)PTR_ERR(value
);
254 error
= f2fs_setxattr(inode
, name_index
, "", value
, size
, ipage
);
258 set_cached_acl(inode
, type
, acl
);
260 cond_clear_inode_flag(fi
, FI_ACL_MODE
);
264 int f2fs_init_acl(struct inode
*inode
, struct inode
*dir
, struct page
*ipage
)
266 struct f2fs_sb_info
*sbi
= F2FS_SB(dir
->i_sb
);
267 struct posix_acl
*acl
= NULL
;
270 if (!S_ISLNK(inode
->i_mode
)) {
271 if (test_opt(sbi
, POSIX_ACL
)) {
272 acl
= f2fs_get_acl(dir
, ACL_TYPE_DEFAULT
);
277 inode
->i_mode
&= ~current_umask();
280 if (!test_opt(sbi
, POSIX_ACL
) || !acl
)
283 if (S_ISDIR(inode
->i_mode
)) {
284 error
= f2fs_set_acl(inode
, ACL_TYPE_DEFAULT
, acl
, ipage
);
288 error
= posix_acl_create(&acl
, GFP_KERNEL
, &inode
->i_mode
);
292 error
= f2fs_set_acl(inode
, ACL_TYPE_ACCESS
, acl
, ipage
);
294 posix_acl_release(acl
);
298 int f2fs_acl_chmod(struct inode
*inode
)
300 struct f2fs_sb_info
*sbi
= F2FS_SB(inode
->i_sb
);
301 struct posix_acl
*acl
;
303 umode_t mode
= get_inode_mode(inode
);
305 if (!test_opt(sbi
, POSIX_ACL
))
310 acl
= f2fs_get_acl(inode
, ACL_TYPE_ACCESS
);
311 if (IS_ERR(acl
) || !acl
)
314 error
= posix_acl_chmod(&acl
, GFP_KERNEL
, mode
);
318 error
= f2fs_set_acl(inode
, ACL_TYPE_ACCESS
, acl
, NULL
);
319 posix_acl_release(acl
);
323 static size_t f2fs_xattr_list_acl(struct dentry
*dentry
, char *list
,
324 size_t list_size
, const char *name
, size_t name_len
, int type
)
326 struct f2fs_sb_info
*sbi
= F2FS_SB(dentry
->d_sb
);
327 const char *xname
= POSIX_ACL_XATTR_DEFAULT
;
330 if (!test_opt(sbi
, POSIX_ACL
))
333 if (type
== ACL_TYPE_ACCESS
)
334 xname
= POSIX_ACL_XATTR_ACCESS
;
336 size
= strlen(xname
) + 1;
337 if (list
&& size
<= list_size
)
338 memcpy(list
, xname
, size
);
342 static int f2fs_xattr_get_acl(struct dentry
*dentry
, const char *name
,
343 void *buffer
, size_t size
, int type
)
345 struct f2fs_sb_info
*sbi
= F2FS_SB(dentry
->d_sb
);
346 struct posix_acl
*acl
;
349 if (strcmp(name
, "") != 0)
351 if (!test_opt(sbi
, POSIX_ACL
))
354 acl
= f2fs_get_acl(dentry
->d_inode
, type
);
359 error
= posix_acl_to_xattr(&init_user_ns
, acl
, buffer
, size
);
360 posix_acl_release(acl
);
365 static int f2fs_xattr_set_acl(struct dentry
*dentry
, const char *name
,
366 const void *value
, size_t size
, int flags
, int type
)
368 struct f2fs_sb_info
*sbi
= F2FS_SB(dentry
->d_sb
);
369 struct inode
*inode
= dentry
->d_inode
;
370 struct posix_acl
*acl
= NULL
;
373 if (strcmp(name
, "") != 0)
375 if (!test_opt(sbi
, POSIX_ACL
))
377 if (!inode_owner_or_capable(inode
))
381 acl
= posix_acl_from_xattr(&init_user_ns
, value
, size
);
385 error
= posix_acl_valid(acl
);
387 goto release_and_out
;
393 error
= f2fs_set_acl(inode
, type
, acl
, NULL
);
396 posix_acl_release(acl
);
400 const struct xattr_handler f2fs_xattr_acl_default_handler
= {
401 .prefix
= POSIX_ACL_XATTR_DEFAULT
,
402 .flags
= ACL_TYPE_DEFAULT
,
403 .list
= f2fs_xattr_list_acl
,
404 .get
= f2fs_xattr_get_acl
,
405 .set
= f2fs_xattr_set_acl
,
408 const struct xattr_handler f2fs_xattr_acl_access_handler
= {
409 .prefix
= POSIX_ACL_XATTR_ACCESS
,
410 .flags
= ACL_TYPE_ACCESS
,
411 .list
= f2fs_xattr_list_acl
,
412 .get
= f2fs_xattr_get_acl
,
413 .set
= f2fs_xattr_set_acl
,