2 * JFFS2 -- Journalling Flash File System, Version 2.
4 * Copyright (C) 2006 NEC Corporation
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
8 * For licensing information, see the file 'LICENCE' in this directory.
11 #include <linux/kernel.h>
12 #include <linux/slab.h>
14 #include <linux/sched.h>
15 #include <linux/time.h>
16 #include <linux/crc32.h>
17 #include <linux/jffs2.h>
18 #include <linux/xattr.h>
19 #include <linux/posix_acl_xattr.h>
20 #include <linux/mtd/mtd.h>
23 static size_t jffs2_acl_size(int count
)
26 return sizeof(struct jffs2_acl_header
)
27 + count
* sizeof(struct jffs2_acl_entry_short
);
29 return sizeof(struct jffs2_acl_header
)
30 + 4 * sizeof(struct jffs2_acl_entry_short
)
31 + (count
- 4) * sizeof(struct jffs2_acl_entry
);
35 static int jffs2_acl_count(size_t size
)
39 size
-= sizeof(struct jffs2_acl_header
);
40 s
= size
- 4 * sizeof(struct jffs2_acl_entry_short
);
42 if (size
% sizeof(struct jffs2_acl_entry_short
))
44 return size
/ sizeof(struct jffs2_acl_entry_short
);
46 if (s
% sizeof(struct jffs2_acl_entry
))
48 return s
/ sizeof(struct jffs2_acl_entry
) + 4;
52 static struct posix_acl
*jffs2_acl_from_medium(void *value
, size_t size
)
54 void *end
= value
+ size
;
55 struct jffs2_acl_header
*header
= value
;
56 struct jffs2_acl_entry
*entry
;
57 struct posix_acl
*acl
;
63 if (size
< sizeof(struct jffs2_acl_header
))
64 return ERR_PTR(-EINVAL
);
65 ver
= je32_to_cpu(header
->a_version
);
66 if (ver
!= JFFS2_ACL_VERSION
) {
67 JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver
);
68 return ERR_PTR(-EINVAL
);
71 value
+= sizeof(struct jffs2_acl_header
);
72 count
= jffs2_acl_count(size
);
74 return ERR_PTR(-EINVAL
);
78 acl
= posix_acl_alloc(count
, GFP_KERNEL
);
80 return ERR_PTR(-ENOMEM
);
82 for (i
=0; i
< count
; i
++) {
84 if (value
+ sizeof(struct jffs2_acl_entry_short
) > end
)
86 acl
->a_entries
[i
].e_tag
= je16_to_cpu(entry
->e_tag
);
87 acl
->a_entries
[i
].e_perm
= je16_to_cpu(entry
->e_perm
);
88 switch (acl
->a_entries
[i
].e_tag
) {
93 value
+= sizeof(struct jffs2_acl_entry_short
);
94 acl
->a_entries
[i
].e_id
= ACL_UNDEFINED_ID
;
99 value
+= sizeof(struct jffs2_acl_entry
);
102 acl
->a_entries
[i
].e_id
= je32_to_cpu(entry
->e_id
);
113 posix_acl_release(acl
);
114 return ERR_PTR(-EINVAL
);
117 static void *jffs2_acl_to_medium(const struct posix_acl
*acl
, size_t *size
)
119 struct jffs2_acl_header
*header
;
120 struct jffs2_acl_entry
*entry
;
124 *size
= jffs2_acl_size(acl
->a_count
);
125 header
= kmalloc(sizeof(*header
) + acl
->a_count
* sizeof(*entry
), GFP_KERNEL
);
127 return ERR_PTR(-ENOMEM
);
128 header
->a_version
= cpu_to_je32(JFFS2_ACL_VERSION
);
130 for (i
=0; i
< acl
->a_count
; i
++) {
132 entry
->e_tag
= cpu_to_je16(acl
->a_entries
[i
].e_tag
);
133 entry
->e_perm
= cpu_to_je16(acl
->a_entries
[i
].e_perm
);
134 switch(acl
->a_entries
[i
].e_tag
) {
137 entry
->e_id
= cpu_to_je32(acl
->a_entries
[i
].e_id
);
138 e
+= sizeof(struct jffs2_acl_entry
);
145 e
+= sizeof(struct jffs2_acl_entry_short
);
155 return ERR_PTR(-EINVAL
);
158 static struct posix_acl
*jffs2_iget_acl(struct inode
*inode
, struct posix_acl
**i_acl
)
160 struct posix_acl
*acl
= JFFS2_ACL_NOT_CACHED
;
162 spin_lock(&inode
->i_lock
);
163 if (*i_acl
!= JFFS2_ACL_NOT_CACHED
)
164 acl
= posix_acl_dup(*i_acl
);
165 spin_unlock(&inode
->i_lock
);
169 static void jffs2_iset_acl(struct inode
*inode
, struct posix_acl
**i_acl
, struct posix_acl
*acl
)
171 spin_lock(&inode
->i_lock
);
172 if (*i_acl
!= JFFS2_ACL_NOT_CACHED
)
173 posix_acl_release(*i_acl
);
174 *i_acl
= posix_acl_dup(acl
);
175 spin_unlock(&inode
->i_lock
);
178 static struct posix_acl
*jffs2_get_acl(struct inode
*inode
, int type
)
180 struct jffs2_inode_info
*f
= JFFS2_INODE_INFO(inode
);
181 struct posix_acl
*acl
;
186 case ACL_TYPE_ACCESS
:
187 acl
= jffs2_iget_acl(inode
, &f
->i_acl_access
);
188 if (acl
!= JFFS2_ACL_NOT_CACHED
)
190 xprefix
= JFFS2_XPREFIX_ACL_ACCESS
;
192 case ACL_TYPE_DEFAULT
:
193 acl
= jffs2_iget_acl(inode
, &f
->i_acl_default
);
194 if (acl
!= JFFS2_ACL_NOT_CACHED
)
196 xprefix
= JFFS2_XPREFIX_ACL_DEFAULT
;
199 return ERR_PTR(-EINVAL
);
201 rc
= do_jffs2_getxattr(inode
, xprefix
, "", NULL
, 0);
203 value
= kmalloc(rc
, GFP_KERNEL
);
205 return ERR_PTR(-ENOMEM
);
206 rc
= do_jffs2_getxattr(inode
, xprefix
, "", value
, rc
);
209 acl
= jffs2_acl_from_medium(value
, rc
);
210 } else if (rc
== -ENODATA
|| rc
== -ENOSYS
) {
219 case ACL_TYPE_ACCESS
:
220 jffs2_iset_acl(inode
, &f
->i_acl_access
, acl
);
222 case ACL_TYPE_DEFAULT
:
223 jffs2_iset_acl(inode
, &f
->i_acl_default
, acl
);
230 static int jffs2_set_acl(struct inode
*inode
, int type
, struct posix_acl
*acl
)
232 struct jffs2_inode_info
*f
= JFFS2_INODE_INFO(inode
);
237 if (S_ISLNK(inode
->i_mode
))
241 case ACL_TYPE_ACCESS
:
242 xprefix
= JFFS2_XPREFIX_ACL_ACCESS
;
244 mode_t mode
= inode
->i_mode
;
245 rc
= posix_acl_equiv_mode(acl
, &mode
);
248 if (inode
->i_mode
!= mode
) {
249 inode
->i_mode
= mode
;
250 jffs2_dirty_inode(inode
);
256 case ACL_TYPE_DEFAULT
:
257 xprefix
= JFFS2_XPREFIX_ACL_DEFAULT
;
258 if (!S_ISDIR(inode
->i_mode
))
259 return acl
? -EACCES
: 0;
265 value
= jffs2_acl_to_medium(acl
, &size
);
267 return PTR_ERR(value
);
270 rc
= do_jffs2_setxattr(inode
, xprefix
, "", value
, size
, 0);
271 if (!value
&& rc
== -ENODATA
)
277 case ACL_TYPE_ACCESS
:
278 jffs2_iset_acl(inode
, &f
->i_acl_access
, acl
);
280 case ACL_TYPE_DEFAULT
:
281 jffs2_iset_acl(inode
, &f
->i_acl_default
, acl
);
288 static int jffs2_check_acl(struct inode
*inode
, int mask
)
290 struct posix_acl
*acl
;
293 acl
= jffs2_get_acl(inode
, ACL_TYPE_ACCESS
);
297 rc
= posix_acl_permission(inode
, acl
, mask
);
298 posix_acl_release(acl
);
304 int jffs2_permission(struct inode
*inode
, int mask
, struct nameidata
*nd
)
306 return generic_permission(inode
, mask
, jffs2_check_acl
);
309 int jffs2_init_acl(struct inode
*inode
, struct inode
*dir
)
311 struct jffs2_inode_info
*f
= JFFS2_INODE_INFO(inode
);
312 struct posix_acl
*acl
= NULL
, *clone
;
316 f
->i_acl_access
= JFFS2_ACL_NOT_CACHED
;
317 f
->i_acl_default
= JFFS2_ACL_NOT_CACHED
;
318 if (!S_ISLNK(inode
->i_mode
)) {
319 acl
= jffs2_get_acl(dir
, ACL_TYPE_DEFAULT
);
323 inode
->i_mode
&= ~current
->fs
->umask
;
326 if (S_ISDIR(inode
->i_mode
)) {
327 rc
= jffs2_set_acl(inode
, ACL_TYPE_DEFAULT
, acl
);
331 clone
= posix_acl_clone(acl
, GFP_KERNEL
);
335 mode
= inode
->i_mode
;
336 rc
= posix_acl_create_masq(clone
, &mode
);
338 inode
->i_mode
= mode
;
340 rc
= jffs2_set_acl(inode
, ACL_TYPE_ACCESS
, clone
);
342 posix_acl_release(clone
);
345 posix_acl_release(acl
);
349 void jffs2_clear_acl(struct jffs2_inode_info
*f
)
351 if (f
->i_acl_access
&& f
->i_acl_access
!= JFFS2_ACL_NOT_CACHED
) {
352 posix_acl_release(f
->i_acl_access
);
353 f
->i_acl_access
= JFFS2_ACL_NOT_CACHED
;
355 if (f
->i_acl_default
&& f
->i_acl_default
!= JFFS2_ACL_NOT_CACHED
) {
356 posix_acl_release(f
->i_acl_default
);
357 f
->i_acl_default
= JFFS2_ACL_NOT_CACHED
;
361 int jffs2_acl_chmod(struct inode
*inode
)
363 struct posix_acl
*acl
, *clone
;
366 if (S_ISLNK(inode
->i_mode
))
368 acl
= jffs2_get_acl(inode
, ACL_TYPE_ACCESS
);
369 if (IS_ERR(acl
) || !acl
)
371 clone
= posix_acl_clone(acl
, GFP_KERNEL
);
372 posix_acl_release(acl
);
375 rc
= posix_acl_chmod_masq(clone
, inode
->i_mode
);
377 rc
= jffs2_set_acl(inode
, ACL_TYPE_ACCESS
, clone
);
378 posix_acl_release(clone
);
382 static size_t jffs2_acl_access_listxattr(struct inode
*inode
, char *list
, size_t list_size
,
383 const char *name
, size_t name_len
)
385 const int retlen
= sizeof(POSIX_ACL_XATTR_ACCESS
);
387 if (list
&& retlen
<= list_size
)
388 strcpy(list
, POSIX_ACL_XATTR_ACCESS
);
392 static size_t jffs2_acl_default_listxattr(struct inode
*inode
, char *list
, size_t list_size
,
393 const char *name
, size_t name_len
)
395 const int retlen
= sizeof(POSIX_ACL_XATTR_DEFAULT
);
397 if (list
&& retlen
<= list_size
)
398 strcpy(list
, POSIX_ACL_XATTR_DEFAULT
);
402 static int jffs2_acl_getxattr(struct inode
*inode
, int type
, void *buffer
, size_t size
)
404 struct posix_acl
*acl
;
407 acl
= jffs2_get_acl(inode
, type
);
412 rc
= posix_acl_to_xattr(acl
, buffer
, size
);
413 posix_acl_release(acl
);
418 static int jffs2_acl_access_getxattr(struct inode
*inode
, const char *name
, void *buffer
, size_t size
)
422 return jffs2_acl_getxattr(inode
, ACL_TYPE_ACCESS
, buffer
, size
);
425 static int jffs2_acl_default_getxattr(struct inode
*inode
, const char *name
, void *buffer
, size_t size
)
429 return jffs2_acl_getxattr(inode
, ACL_TYPE_DEFAULT
, buffer
, size
);
432 static int jffs2_acl_setxattr(struct inode
*inode
, int type
, const void *value
, size_t size
)
434 struct posix_acl
*acl
;
437 if ((current
->fsuid
!= inode
->i_uid
) && !capable(CAP_FOWNER
))
441 acl
= posix_acl_from_xattr(value
, size
);
445 rc
= posix_acl_valid(acl
);
452 rc
= jffs2_set_acl(inode
, type
, acl
);
454 posix_acl_release(acl
);
458 static int jffs2_acl_access_setxattr(struct inode
*inode
, const char *name
,
459 const void *buffer
, size_t size
, int flags
)
463 return jffs2_acl_setxattr(inode
, ACL_TYPE_ACCESS
, buffer
, size
);
466 static int jffs2_acl_default_setxattr(struct inode
*inode
, const char *name
,
467 const void *buffer
, size_t size
, int flags
)
471 return jffs2_acl_setxattr(inode
, ACL_TYPE_DEFAULT
, buffer
, size
);
474 struct xattr_handler jffs2_acl_access_xattr_handler
= {
475 .prefix
= POSIX_ACL_XATTR_ACCESS
,
476 .list
= jffs2_acl_access_listxattr
,
477 .get
= jffs2_acl_access_getxattr
,
478 .set
= jffs2_acl_access_setxattr
,
481 struct xattr_handler jffs2_acl_default_xattr_handler
= {
482 .prefix
= POSIX_ACL_XATTR_DEFAULT
,
483 .list
= jffs2_acl_default_listxattr
,
484 .get
= jffs2_acl_default_getxattr
,
485 .set
= jffs2_acl_default_setxattr
,