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 static inline size_t f2fs_acl_size(int count
)
23 return sizeof(struct f2fs_acl_header
) +
24 count
* sizeof(struct f2fs_acl_entry_short
);
26 return sizeof(struct f2fs_acl_header
) +
27 4 * sizeof(struct f2fs_acl_entry_short
) +
28 (count
- 4) * sizeof(struct f2fs_acl_entry
);
32 static inline int f2fs_acl_count(size_t size
)
35 size
-= sizeof(struct f2fs_acl_header
);
36 s
= size
- 4 * sizeof(struct f2fs_acl_entry_short
);
38 if (size
% sizeof(struct f2fs_acl_entry_short
))
40 return size
/ sizeof(struct f2fs_acl_entry_short
);
42 if (s
% sizeof(struct f2fs_acl_entry
))
44 return s
/ sizeof(struct f2fs_acl_entry
) + 4;
48 static struct posix_acl
*f2fs_acl_from_disk(const char *value
, size_t size
)
51 struct posix_acl
*acl
;
52 struct f2fs_acl_header
*hdr
= (struct f2fs_acl_header
*)value
;
53 struct f2fs_acl_entry
*entry
= (struct f2fs_acl_entry
*)(hdr
+ 1);
54 const char *end
= value
+ size
;
56 if (hdr
->a_version
!= cpu_to_le32(F2FS_ACL_VERSION
))
57 return ERR_PTR(-EINVAL
);
59 count
= f2fs_acl_count(size
);
61 return ERR_PTR(-EINVAL
);
65 acl
= posix_acl_alloc(count
, GFP_KERNEL
);
67 return ERR_PTR(-ENOMEM
);
69 for (i
= 0; i
< count
; i
++) {
71 if ((char *)entry
> end
)
74 acl
->a_entries
[i
].e_tag
= le16_to_cpu(entry
->e_tag
);
75 acl
->a_entries
[i
].e_perm
= le16_to_cpu(entry
->e_perm
);
77 switch (acl
->a_entries
[i
].e_tag
) {
82 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
83 sizeof(struct f2fs_acl_entry_short
));
87 acl
->a_entries
[i
].e_uid
=
88 make_kuid(&init_user_ns
,
89 le32_to_cpu(entry
->e_id
));
90 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
91 sizeof(struct f2fs_acl_entry
));
94 acl
->a_entries
[i
].e_gid
=
95 make_kgid(&init_user_ns
,
96 le32_to_cpu(entry
->e_id
));
97 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
98 sizeof(struct f2fs_acl_entry
));
104 if ((char *)entry
!= end
)
108 posix_acl_release(acl
);
109 return ERR_PTR(-EINVAL
);
112 static void *f2fs_acl_to_disk(const struct posix_acl
*acl
, size_t *size
)
114 struct f2fs_acl_header
*f2fs_acl
;
115 struct f2fs_acl_entry
*entry
;
118 f2fs_acl
= kmalloc(sizeof(struct f2fs_acl_header
) + acl
->a_count
*
119 sizeof(struct f2fs_acl_entry
), GFP_KERNEL
);
121 return ERR_PTR(-ENOMEM
);
123 f2fs_acl
->a_version
= cpu_to_le32(F2FS_ACL_VERSION
);
124 entry
= (struct f2fs_acl_entry
*)(f2fs_acl
+ 1);
126 for (i
= 0; i
< acl
->a_count
; i
++) {
128 entry
->e_tag
= cpu_to_le16(acl
->a_entries
[i
].e_tag
);
129 entry
->e_perm
= cpu_to_le16(acl
->a_entries
[i
].e_perm
);
131 switch (acl
->a_entries
[i
].e_tag
) {
133 entry
->e_id
= cpu_to_le32(
134 from_kuid(&init_user_ns
,
135 acl
->a_entries
[i
].e_uid
));
136 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
137 sizeof(struct f2fs_acl_entry
));
140 entry
->e_id
= cpu_to_le32(
141 from_kgid(&init_user_ns
,
142 acl
->a_entries
[i
].e_gid
));
143 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
144 sizeof(struct f2fs_acl_entry
));
150 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
151 sizeof(struct f2fs_acl_entry_short
));
157 *size
= f2fs_acl_size(acl
->a_count
);
158 return (void *)f2fs_acl
;
162 return ERR_PTR(-EINVAL
);
165 struct posix_acl
*f2fs_get_acl(struct inode
*inode
, int type
)
167 int name_index
= F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT
;
169 struct posix_acl
*acl
;
172 if (type
== ACL_TYPE_ACCESS
)
173 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_ACCESS
;
175 retval
= f2fs_getxattr(inode
, name_index
, "", NULL
, 0);
177 value
= kmalloc(retval
, GFP_F2FS_ZERO
);
179 return ERR_PTR(-ENOMEM
);
180 retval
= f2fs_getxattr(inode
, name_index
, "", value
, retval
);
184 acl
= f2fs_acl_from_disk(value
, retval
);
185 else if (retval
== -ENODATA
)
188 acl
= ERR_PTR(retval
);
192 set_cached_acl(inode
, type
, acl
);
197 static int __f2fs_set_acl(struct inode
*inode
, int type
,
198 struct posix_acl
*acl
, struct page
*ipage
)
200 struct f2fs_inode_info
*fi
= F2FS_I(inode
);
207 error
= posix_acl_valid(acl
);
213 case ACL_TYPE_ACCESS
:
214 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_ACCESS
;
216 error
= posix_acl_equiv_mode(acl
, &inode
->i_mode
);
219 set_acl_inode(fi
, inode
->i_mode
);
225 case ACL_TYPE_DEFAULT
:
226 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT
;
227 if (!S_ISDIR(inode
->i_mode
))
228 return acl
? -EACCES
: 0;
236 value
= f2fs_acl_to_disk(acl
, &size
);
238 cond_clear_inode_flag(fi
, FI_ACL_MODE
);
239 return (int)PTR_ERR(value
);
243 error
= f2fs_setxattr(inode
, name_index
, "", value
, size
, ipage
, 0);
247 set_cached_acl(inode
, type
, acl
);
249 cond_clear_inode_flag(fi
, FI_ACL_MODE
);
253 int f2fs_set_acl(struct inode
*inode
, struct posix_acl
*acl
, int type
)
255 return __f2fs_set_acl(inode
, type
, acl
, NULL
);
258 int f2fs_init_acl(struct inode
*inode
, struct inode
*dir
, struct page
*ipage
)
260 struct posix_acl
*default_acl
, *acl
;
263 error
= posix_acl_create(dir
, &inode
->i_mode
, &default_acl
, &acl
);
268 error
= __f2fs_set_acl(inode
, ACL_TYPE_DEFAULT
, default_acl
,
270 posix_acl_release(default_acl
);
274 error
= __f2fs_set_acl(inode
, ACL_TYPE_ACCESS
, acl
,
276 posix_acl_release(acl
);