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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
17 #include <linux/sched.h>
18 #include <linux/time.h>
19 #include <linux/crc32.h>
20 #include <linux/jffs2.h>
21 #include <linux/xattr.h>
22 #include <linux/posix_acl_xattr.h>
23 #include <linux/mtd/mtd.h>
26 static size_t jffs2_acl_size(int count
)
29 return sizeof(struct jffs2_acl_header
)
30 + count
* sizeof(struct jffs2_acl_entry_short
);
32 return sizeof(struct jffs2_acl_header
)
33 + 4 * sizeof(struct jffs2_acl_entry_short
)
34 + (count
- 4) * sizeof(struct jffs2_acl_entry
);
38 static int jffs2_acl_count(size_t size
)
42 size
-= sizeof(struct jffs2_acl_header
);
43 if (size
< 4 * sizeof(struct jffs2_acl_entry_short
)) {
44 if (size
% sizeof(struct jffs2_acl_entry_short
))
46 return size
/ sizeof(struct jffs2_acl_entry_short
);
48 s
= size
- 4 * sizeof(struct jffs2_acl_entry_short
);
49 if (s
% sizeof(struct jffs2_acl_entry
))
51 return s
/ sizeof(struct jffs2_acl_entry
) + 4;
55 static struct posix_acl
*jffs2_acl_from_medium(void *value
, size_t size
)
57 void *end
= value
+ size
;
58 struct jffs2_acl_header
*header
= value
;
59 struct jffs2_acl_entry
*entry
;
60 struct posix_acl
*acl
;
66 if (size
< sizeof(struct jffs2_acl_header
))
67 return ERR_PTR(-EINVAL
);
68 ver
= je32_to_cpu(header
->a_version
);
69 if (ver
!= JFFS2_ACL_VERSION
) {
70 JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver
);
71 return ERR_PTR(-EINVAL
);
74 value
+= sizeof(struct jffs2_acl_header
);
75 count
= jffs2_acl_count(size
);
77 return ERR_PTR(-EINVAL
);
81 acl
= posix_acl_alloc(count
, GFP_KERNEL
);
83 return ERR_PTR(-ENOMEM
);
85 for (i
=0; i
< count
; i
++) {
87 if (value
+ sizeof(struct jffs2_acl_entry_short
) > end
)
89 acl
->a_entries
[i
].e_tag
= je16_to_cpu(entry
->e_tag
);
90 acl
->a_entries
[i
].e_perm
= je16_to_cpu(entry
->e_perm
);
91 switch (acl
->a_entries
[i
].e_tag
) {
96 value
+= sizeof(struct jffs2_acl_entry_short
);
100 value
+= sizeof(struct jffs2_acl_entry
);
103 acl
->a_entries
[i
].e_uid
=
104 make_kuid(&init_user_ns
,
105 je32_to_cpu(entry
->e_id
));
108 value
+= sizeof(struct jffs2_acl_entry
);
111 acl
->a_entries
[i
].e_gid
=
112 make_kgid(&init_user_ns
,
113 je32_to_cpu(entry
->e_id
));
124 posix_acl_release(acl
);
125 return ERR_PTR(-EINVAL
);
128 static void *jffs2_acl_to_medium(const struct posix_acl
*acl
, size_t *size
)
130 struct jffs2_acl_header
*header
;
131 struct jffs2_acl_entry
*entry
;
135 *size
= jffs2_acl_size(acl
->a_count
);
136 header
= kmalloc(sizeof(*header
) + acl
->a_count
* sizeof(*entry
), GFP_KERNEL
);
138 return ERR_PTR(-ENOMEM
);
139 header
->a_version
= cpu_to_je32(JFFS2_ACL_VERSION
);
141 for (i
=0; i
< acl
->a_count
; i
++) {
142 const struct posix_acl_entry
*acl_e
= &acl
->a_entries
[i
];
144 entry
->e_tag
= cpu_to_je16(acl_e
->e_tag
);
145 entry
->e_perm
= cpu_to_je16(acl_e
->e_perm
);
146 switch(acl_e
->e_tag
) {
148 entry
->e_id
= cpu_to_je32(
149 from_kuid(&init_user_ns
, acl_e
->e_uid
));
150 e
+= sizeof(struct jffs2_acl_entry
);
153 entry
->e_id
= cpu_to_je32(
154 from_kgid(&init_user_ns
, acl_e
->e_gid
));
155 e
+= sizeof(struct jffs2_acl_entry
);
162 e
+= sizeof(struct jffs2_acl_entry_short
);
172 return ERR_PTR(-EINVAL
);
175 struct posix_acl
*jffs2_get_acl(struct inode
*inode
, int type
)
177 struct posix_acl
*acl
;
181 acl
= get_cached_acl(inode
, type
);
182 if (acl
!= ACL_NOT_CACHED
)
186 case ACL_TYPE_ACCESS
:
187 xprefix
= JFFS2_XPREFIX_ACL_ACCESS
;
189 case ACL_TYPE_DEFAULT
:
190 xprefix
= JFFS2_XPREFIX_ACL_DEFAULT
;
195 rc
= do_jffs2_getxattr(inode
, xprefix
, "", NULL
, 0);
197 value
= kmalloc(rc
, GFP_KERNEL
);
199 return ERR_PTR(-ENOMEM
);
200 rc
= do_jffs2_getxattr(inode
, xprefix
, "", value
, rc
);
203 acl
= jffs2_acl_from_medium(value
, rc
);
204 } else if (rc
== -ENODATA
|| rc
== -ENOSYS
) {
212 set_cached_acl(inode
, type
, acl
);
216 static int __jffs2_set_acl(struct inode
*inode
, int xprefix
, struct posix_acl
*acl
)
223 value
= jffs2_acl_to_medium(acl
, &size
);
225 return PTR_ERR(value
);
227 rc
= do_jffs2_setxattr(inode
, xprefix
, "", value
, size
, 0);
228 if (!value
&& rc
== -ENODATA
)
235 static int jffs2_set_acl(struct inode
*inode
, int type
, struct posix_acl
*acl
)
239 if (S_ISLNK(inode
->i_mode
))
243 case ACL_TYPE_ACCESS
:
244 xprefix
= JFFS2_XPREFIX_ACL_ACCESS
;
246 umode_t mode
= inode
->i_mode
;
247 rc
= posix_acl_equiv_mode(acl
, &mode
);
250 if (inode
->i_mode
!= mode
) {
253 attr
.ia_valid
= ATTR_MODE
| ATTR_CTIME
;
255 attr
.ia_ctime
= CURRENT_TIME_SEC
;
256 rc
= jffs2_do_setattr(inode
, &attr
);
264 case ACL_TYPE_DEFAULT
:
265 xprefix
= JFFS2_XPREFIX_ACL_DEFAULT
;
266 if (!S_ISDIR(inode
->i_mode
))
267 return acl
? -EACCES
: 0;
272 rc
= __jffs2_set_acl(inode
, xprefix
, acl
);
274 set_cached_acl(inode
, type
, acl
);
278 int jffs2_init_acl_pre(struct inode
*dir_i
, struct inode
*inode
, umode_t
*i_mode
)
280 struct posix_acl
*acl
;
285 if (S_ISLNK(*i_mode
))
286 return 0; /* Symlink always has no-ACL */
288 acl
= jffs2_get_acl(dir_i
, ACL_TYPE_DEFAULT
);
293 *i_mode
&= ~current_umask();
295 if (S_ISDIR(*i_mode
))
296 set_cached_acl(inode
, ACL_TYPE_DEFAULT
, acl
);
298 rc
= posix_acl_create(&acl
, GFP_KERNEL
, i_mode
);
302 set_cached_acl(inode
, ACL_TYPE_ACCESS
, acl
);
304 posix_acl_release(acl
);
309 int jffs2_init_acl_post(struct inode
*inode
)
313 if (inode
->i_default_acl
) {
314 rc
= __jffs2_set_acl(inode
, JFFS2_XPREFIX_ACL_DEFAULT
, inode
->i_default_acl
);
320 rc
= __jffs2_set_acl(inode
, JFFS2_XPREFIX_ACL_ACCESS
, inode
->i_acl
);
328 int jffs2_acl_chmod(struct inode
*inode
)
330 struct posix_acl
*acl
;
333 if (S_ISLNK(inode
->i_mode
))
335 acl
= jffs2_get_acl(inode
, ACL_TYPE_ACCESS
);
336 if (IS_ERR(acl
) || !acl
)
338 rc
= posix_acl_chmod(&acl
, GFP_KERNEL
, inode
->i_mode
);
341 rc
= jffs2_set_acl(inode
, ACL_TYPE_ACCESS
, acl
);
342 posix_acl_release(acl
);
346 static size_t jffs2_acl_access_listxattr(struct dentry
*dentry
, char *list
,
347 size_t list_size
, const char *name
, size_t name_len
, int type
)
349 const int retlen
= sizeof(POSIX_ACL_XATTR_ACCESS
);
351 if (list
&& retlen
<= list_size
)
352 strcpy(list
, POSIX_ACL_XATTR_ACCESS
);
356 static size_t jffs2_acl_default_listxattr(struct dentry
*dentry
, char *list
,
357 size_t list_size
, const char *name
, size_t name_len
, int type
)
359 const int retlen
= sizeof(POSIX_ACL_XATTR_DEFAULT
);
361 if (list
&& retlen
<= list_size
)
362 strcpy(list
, POSIX_ACL_XATTR_DEFAULT
);
366 static int jffs2_acl_getxattr(struct dentry
*dentry
, const char *name
,
367 void *buffer
, size_t size
, int type
)
369 struct posix_acl
*acl
;
375 acl
= jffs2_get_acl(dentry
->d_inode
, type
);
380 rc
= posix_acl_to_xattr(&init_user_ns
, acl
, buffer
, size
);
381 posix_acl_release(acl
);
386 static int jffs2_acl_setxattr(struct dentry
*dentry
, const char *name
,
387 const void *value
, size_t size
, int flags
, int type
)
389 struct posix_acl
*acl
;
394 if (!inode_owner_or_capable(dentry
->d_inode
))
398 acl
= posix_acl_from_xattr(&init_user_ns
, value
, size
);
402 rc
= posix_acl_valid(acl
);
409 rc
= jffs2_set_acl(dentry
->d_inode
, type
, acl
);
411 posix_acl_release(acl
);
415 const struct xattr_handler jffs2_acl_access_xattr_handler
= {
416 .prefix
= POSIX_ACL_XATTR_ACCESS
,
417 .flags
= ACL_TYPE_DEFAULT
,
418 .list
= jffs2_acl_access_listxattr
,
419 .get
= jffs2_acl_getxattr
,
420 .set
= jffs2_acl_setxattr
,
423 const struct xattr_handler jffs2_acl_default_xattr_handler
= {
424 .prefix
= POSIX_ACL_XATTR_DEFAULT
,
425 .flags
= ACL_TYPE_DEFAULT
,
426 .list
= jffs2_acl_default_listxattr
,
427 .get
= jffs2_acl_getxattr
,
428 .set
= jffs2_acl_setxattr
,