2 * JFFS2 -- Journalling Flash File System, Version 2.
4 * Copyright © 2006 NEC Corporation
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
8 * For licensing information, see the file 'LICENCE' in this directory.
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
15 #include <linux/sched.h>
16 #include <linux/time.h>
17 #include <linux/crc32.h>
18 #include <linux/jffs2.h>
19 #include <linux/xattr.h>
20 #include <linux/posix_acl_xattr.h>
21 #include <linux/mtd/mtd.h>
24 static size_t jffs2_acl_size(int count
)
27 return sizeof(struct jffs2_acl_header
)
28 + count
* sizeof(struct jffs2_acl_entry_short
);
30 return sizeof(struct jffs2_acl_header
)
31 + 4 * sizeof(struct jffs2_acl_entry_short
)
32 + (count
- 4) * sizeof(struct jffs2_acl_entry
);
36 static int jffs2_acl_count(size_t size
)
40 size
-= sizeof(struct jffs2_acl_header
);
41 s
= size
- 4 * sizeof(struct jffs2_acl_entry_short
);
43 if (size
% sizeof(struct jffs2_acl_entry_short
))
45 return size
/ sizeof(struct jffs2_acl_entry_short
);
47 if (s
% sizeof(struct jffs2_acl_entry
))
49 return s
/ sizeof(struct jffs2_acl_entry
) + 4;
53 static struct posix_acl
*jffs2_acl_from_medium(void *value
, size_t size
)
55 void *end
= value
+ size
;
56 struct jffs2_acl_header
*header
= value
;
57 struct jffs2_acl_entry
*entry
;
58 struct posix_acl
*acl
;
64 if (size
< sizeof(struct jffs2_acl_header
))
65 return ERR_PTR(-EINVAL
);
66 ver
= je32_to_cpu(header
->a_version
);
67 if (ver
!= JFFS2_ACL_VERSION
) {
68 JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver
);
69 return ERR_PTR(-EINVAL
);
72 value
+= sizeof(struct jffs2_acl_header
);
73 count
= jffs2_acl_count(size
);
75 return ERR_PTR(-EINVAL
);
79 acl
= posix_acl_alloc(count
, GFP_KERNEL
);
81 return ERR_PTR(-ENOMEM
);
83 for (i
=0; i
< count
; i
++) {
85 if (value
+ sizeof(struct jffs2_acl_entry_short
) > end
)
87 acl
->a_entries
[i
].e_tag
= je16_to_cpu(entry
->e_tag
);
88 acl
->a_entries
[i
].e_perm
= je16_to_cpu(entry
->e_perm
);
89 switch (acl
->a_entries
[i
].e_tag
) {
94 value
+= sizeof(struct jffs2_acl_entry_short
);
95 acl
->a_entries
[i
].e_id
= ACL_UNDEFINED_ID
;
100 value
+= sizeof(struct jffs2_acl_entry
);
103 acl
->a_entries
[i
].e_id
= je32_to_cpu(entry
->e_id
);
114 posix_acl_release(acl
);
115 return ERR_PTR(-EINVAL
);
118 static void *jffs2_acl_to_medium(const struct posix_acl
*acl
, size_t *size
)
120 struct jffs2_acl_header
*header
;
121 struct jffs2_acl_entry
*entry
;
125 *size
= jffs2_acl_size(acl
->a_count
);
126 header
= kmalloc(sizeof(*header
) + acl
->a_count
* sizeof(*entry
), GFP_KERNEL
);
128 return ERR_PTR(-ENOMEM
);
129 header
->a_version
= cpu_to_je32(JFFS2_ACL_VERSION
);
131 for (i
=0; i
< acl
->a_count
; i
++) {
133 entry
->e_tag
= cpu_to_je16(acl
->a_entries
[i
].e_tag
);
134 entry
->e_perm
= cpu_to_je16(acl
->a_entries
[i
].e_perm
);
135 switch(acl
->a_entries
[i
].e_tag
) {
138 entry
->e_id
= cpu_to_je32(acl
->a_entries
[i
].e_id
);
139 e
+= sizeof(struct jffs2_acl_entry
);
146 e
+= sizeof(struct jffs2_acl_entry_short
);
156 return ERR_PTR(-EINVAL
);
159 static struct posix_acl
*jffs2_iget_acl(struct inode
*inode
, struct posix_acl
**i_acl
)
161 struct posix_acl
*acl
= JFFS2_ACL_NOT_CACHED
;
163 spin_lock(&inode
->i_lock
);
164 if (*i_acl
!= JFFS2_ACL_NOT_CACHED
)
165 acl
= posix_acl_dup(*i_acl
);
166 spin_unlock(&inode
->i_lock
);
170 static void jffs2_iset_acl(struct inode
*inode
, struct posix_acl
**i_acl
, struct posix_acl
*acl
)
172 spin_lock(&inode
->i_lock
);
173 if (*i_acl
!= JFFS2_ACL_NOT_CACHED
)
174 posix_acl_release(*i_acl
);
175 *i_acl
= posix_acl_dup(acl
);
176 spin_unlock(&inode
->i_lock
);
179 static struct posix_acl
*jffs2_get_acl(struct inode
*inode
, int type
)
181 struct jffs2_inode_info
*f
= JFFS2_INODE_INFO(inode
);
182 struct posix_acl
*acl
;
187 case ACL_TYPE_ACCESS
:
188 acl
= jffs2_iget_acl(inode
, &f
->i_acl_access
);
189 if (acl
!= JFFS2_ACL_NOT_CACHED
)
191 xprefix
= JFFS2_XPREFIX_ACL_ACCESS
;
193 case ACL_TYPE_DEFAULT
:
194 acl
= jffs2_iget_acl(inode
, &f
->i_acl_default
);
195 if (acl
!= JFFS2_ACL_NOT_CACHED
)
197 xprefix
= JFFS2_XPREFIX_ACL_DEFAULT
;
200 return ERR_PTR(-EINVAL
);
202 rc
= do_jffs2_getxattr(inode
, xprefix
, "", NULL
, 0);
204 value
= kmalloc(rc
, GFP_KERNEL
);
206 return ERR_PTR(-ENOMEM
);
207 rc
= do_jffs2_getxattr(inode
, xprefix
, "", value
, rc
);
210 acl
= jffs2_acl_from_medium(value
, rc
);
211 } else if (rc
== -ENODATA
|| rc
== -ENOSYS
) {
220 case ACL_TYPE_ACCESS
:
221 jffs2_iset_acl(inode
, &f
->i_acl_access
, acl
);
223 case ACL_TYPE_DEFAULT
:
224 jffs2_iset_acl(inode
, &f
->i_acl_default
, acl
);
231 static int __jffs2_set_acl(struct inode
*inode
, int xprefix
, struct posix_acl
*acl
)
238 value
= jffs2_acl_to_medium(acl
, &size
);
240 return PTR_ERR(value
);
242 rc
= do_jffs2_setxattr(inode
, xprefix
, "", value
, size
, 0);
243 if (!value
&& rc
== -ENODATA
)
250 static int jffs2_set_acl(struct inode
*inode
, int type
, struct posix_acl
*acl
)
252 struct jffs2_inode_info
*f
= JFFS2_INODE_INFO(inode
);
255 if (S_ISLNK(inode
->i_mode
))
259 case ACL_TYPE_ACCESS
:
260 xprefix
= JFFS2_XPREFIX_ACL_ACCESS
;
262 mode_t mode
= inode
->i_mode
;
263 rc
= posix_acl_equiv_mode(acl
, &mode
);
266 if (inode
->i_mode
!= mode
) {
269 attr
.ia_valid
= ATTR_MODE
;
271 rc
= jffs2_do_setattr(inode
, &attr
);
279 case ACL_TYPE_DEFAULT
:
280 xprefix
= JFFS2_XPREFIX_ACL_DEFAULT
;
281 if (!S_ISDIR(inode
->i_mode
))
282 return acl
? -EACCES
: 0;
287 rc
= __jffs2_set_acl(inode
, xprefix
, acl
);
290 case ACL_TYPE_ACCESS
:
291 jffs2_iset_acl(inode
, &f
->i_acl_access
, acl
);
293 case ACL_TYPE_DEFAULT
:
294 jffs2_iset_acl(inode
, &f
->i_acl_default
, acl
);
301 static int jffs2_check_acl(struct inode
*inode
, int mask
)
303 struct posix_acl
*acl
;
306 acl
= jffs2_get_acl(inode
, ACL_TYPE_ACCESS
);
310 rc
= posix_acl_permission(inode
, acl
, mask
);
311 posix_acl_release(acl
);
317 int jffs2_permission(struct inode
*inode
, int mask
, struct nameidata
*nd
)
319 return generic_permission(inode
, mask
, jffs2_check_acl
);
322 int jffs2_init_acl_pre(struct inode
*dir_i
, struct inode
*inode
, int *i_mode
)
324 struct jffs2_inode_info
*f
= JFFS2_INODE_INFO(inode
);
325 struct posix_acl
*acl
, *clone
;
328 f
->i_acl_default
= NULL
;
329 f
->i_acl_access
= NULL
;
331 if (S_ISLNK(*i_mode
))
332 return 0; /* Symlink always has no-ACL */
334 acl
= jffs2_get_acl(dir_i
, ACL_TYPE_DEFAULT
);
339 *i_mode
&= ~current
->fs
->umask
;
341 if (S_ISDIR(*i_mode
))
342 jffs2_iset_acl(inode
, &f
->i_acl_default
, acl
);
344 clone
= posix_acl_clone(acl
, GFP_KERNEL
);
347 rc
= posix_acl_create_masq(clone
, (mode_t
*)i_mode
);
349 posix_acl_release(clone
);
353 jffs2_iset_acl(inode
, &f
->i_acl_access
, clone
);
355 posix_acl_release(clone
);
360 int jffs2_init_acl_post(struct inode
*inode
)
362 struct jffs2_inode_info
*f
= JFFS2_INODE_INFO(inode
);
365 if (f
->i_acl_default
) {
366 rc
= __jffs2_set_acl(inode
, JFFS2_XPREFIX_ACL_DEFAULT
, f
->i_acl_default
);
371 if (f
->i_acl_access
) {
372 rc
= __jffs2_set_acl(inode
, JFFS2_XPREFIX_ACL_ACCESS
, f
->i_acl_access
);
380 void jffs2_clear_acl(struct jffs2_inode_info
*f
)
382 if (f
->i_acl_access
&& f
->i_acl_access
!= JFFS2_ACL_NOT_CACHED
) {
383 posix_acl_release(f
->i_acl_access
);
384 f
->i_acl_access
= JFFS2_ACL_NOT_CACHED
;
386 if (f
->i_acl_default
&& f
->i_acl_default
!= JFFS2_ACL_NOT_CACHED
) {
387 posix_acl_release(f
->i_acl_default
);
388 f
->i_acl_default
= JFFS2_ACL_NOT_CACHED
;
392 int jffs2_acl_chmod(struct inode
*inode
)
394 struct posix_acl
*acl
, *clone
;
397 if (S_ISLNK(inode
->i_mode
))
399 acl
= jffs2_get_acl(inode
, ACL_TYPE_ACCESS
);
400 if (IS_ERR(acl
) || !acl
)
402 clone
= posix_acl_clone(acl
, GFP_KERNEL
);
403 posix_acl_release(acl
);
406 rc
= posix_acl_chmod_masq(clone
, inode
->i_mode
);
408 rc
= jffs2_set_acl(inode
, ACL_TYPE_ACCESS
, clone
);
409 posix_acl_release(clone
);
413 static size_t jffs2_acl_access_listxattr(struct inode
*inode
, char *list
, size_t list_size
,
414 const char *name
, size_t name_len
)
416 const int retlen
= sizeof(POSIX_ACL_XATTR_ACCESS
);
418 if (list
&& retlen
<= list_size
)
419 strcpy(list
, POSIX_ACL_XATTR_ACCESS
);
423 static size_t jffs2_acl_default_listxattr(struct inode
*inode
, char *list
, size_t list_size
,
424 const char *name
, size_t name_len
)
426 const int retlen
= sizeof(POSIX_ACL_XATTR_DEFAULT
);
428 if (list
&& retlen
<= list_size
)
429 strcpy(list
, POSIX_ACL_XATTR_DEFAULT
);
433 static int jffs2_acl_getxattr(struct inode
*inode
, int type
, void *buffer
, size_t size
)
435 struct posix_acl
*acl
;
438 acl
= jffs2_get_acl(inode
, type
);
443 rc
= posix_acl_to_xattr(acl
, buffer
, size
);
444 posix_acl_release(acl
);
449 static int jffs2_acl_access_getxattr(struct inode
*inode
, const char *name
, void *buffer
, size_t size
)
453 return jffs2_acl_getxattr(inode
, ACL_TYPE_ACCESS
, buffer
, size
);
456 static int jffs2_acl_default_getxattr(struct inode
*inode
, const char *name
, void *buffer
, size_t size
)
460 return jffs2_acl_getxattr(inode
, ACL_TYPE_DEFAULT
, buffer
, size
);
463 static int jffs2_acl_setxattr(struct inode
*inode
, int type
, const void *value
, size_t size
)
465 struct posix_acl
*acl
;
468 if (!is_owner_or_cap(inode
))
472 acl
= posix_acl_from_xattr(value
, size
);
476 rc
= posix_acl_valid(acl
);
483 rc
= jffs2_set_acl(inode
, type
, acl
);
485 posix_acl_release(acl
);
489 static int jffs2_acl_access_setxattr(struct inode
*inode
, const char *name
,
490 const void *buffer
, size_t size
, int flags
)
494 return jffs2_acl_setxattr(inode
, ACL_TYPE_ACCESS
, buffer
, size
);
497 static int jffs2_acl_default_setxattr(struct inode
*inode
, const char *name
,
498 const void *buffer
, size_t size
, int flags
)
502 return jffs2_acl_setxattr(inode
, ACL_TYPE_DEFAULT
, buffer
, size
);
505 struct xattr_handler jffs2_acl_access_xattr_handler
= {
506 .prefix
= POSIX_ACL_XATTR_ACCESS
,
507 .list
= jffs2_acl_access_listxattr
,
508 .get
= jffs2_acl_access_getxattr
,
509 .set
= jffs2_acl_access_setxattr
,
512 struct xattr_handler jffs2_acl_default_xattr_handler
= {
513 .prefix
= POSIX_ACL_XATTR_DEFAULT
,
514 .list
= jffs2_acl_default_listxattr
,
515 .get
= jffs2_acl_default_getxattr
,
516 .set
= jffs2_acl_default_setxattr
,