4 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
7 #include <linux/init.h>
8 #include <linux/sched.h>
9 #include <linux/slab.h>
16 * Convert from filesystem to in-memory representation.
18 static struct posix_acl
*
19 ext2_acl_from_disk(const void *value
, size_t size
)
21 const char *end
= (char *)value
+ size
;
23 struct posix_acl
*acl
;
27 if (size
< sizeof(ext2_acl_header
))
28 return ERR_PTR(-EINVAL
);
29 if (((ext2_acl_header
*)value
)->a_version
!=
30 cpu_to_le32(EXT2_ACL_VERSION
))
31 return ERR_PTR(-EINVAL
);
32 value
= (char *)value
+ sizeof(ext2_acl_header
);
33 count
= ext2_acl_count(size
);
35 return ERR_PTR(-EINVAL
);
38 acl
= posix_acl_alloc(count
, GFP_KERNEL
);
40 return ERR_PTR(-ENOMEM
);
41 for (n
=0; n
< count
; n
++) {
42 ext2_acl_entry
*entry
=
43 (ext2_acl_entry
*)value
;
44 if ((char *)value
+ sizeof(ext2_acl_entry_short
) > end
)
46 acl
->a_entries
[n
].e_tag
= le16_to_cpu(entry
->e_tag
);
47 acl
->a_entries
[n
].e_perm
= le16_to_cpu(entry
->e_perm
);
48 switch(acl
->a_entries
[n
].e_tag
) {
53 value
= (char *)value
+
54 sizeof(ext2_acl_entry_short
);
58 value
= (char *)value
+ sizeof(ext2_acl_entry
);
59 if ((char *)value
> end
)
61 acl
->a_entries
[n
].e_uid
=
62 make_kuid(&init_user_ns
,
63 le32_to_cpu(entry
->e_id
));
66 value
= (char *)value
+ sizeof(ext2_acl_entry
);
67 if ((char *)value
> end
)
69 acl
->a_entries
[n
].e_gid
=
70 make_kgid(&init_user_ns
,
71 le32_to_cpu(entry
->e_id
));
83 posix_acl_release(acl
);
84 return ERR_PTR(-EINVAL
);
88 * Convert from in-memory to filesystem representation.
91 ext2_acl_to_disk(const struct posix_acl
*acl
, size_t *size
)
93 ext2_acl_header
*ext_acl
;
97 *size
= ext2_acl_size(acl
->a_count
);
98 ext_acl
= kmalloc(sizeof(ext2_acl_header
) + acl
->a_count
*
99 sizeof(ext2_acl_entry
), GFP_KERNEL
);
101 return ERR_PTR(-ENOMEM
);
102 ext_acl
->a_version
= cpu_to_le32(EXT2_ACL_VERSION
);
103 e
= (char *)ext_acl
+ sizeof(ext2_acl_header
);
104 for (n
=0; n
< acl
->a_count
; n
++) {
105 const struct posix_acl_entry
*acl_e
= &acl
->a_entries
[n
];
106 ext2_acl_entry
*entry
= (ext2_acl_entry
*)e
;
107 entry
->e_tag
= cpu_to_le16(acl_e
->e_tag
);
108 entry
->e_perm
= cpu_to_le16(acl_e
->e_perm
);
109 switch(acl_e
->e_tag
) {
111 entry
->e_id
= cpu_to_le32(
112 from_kuid(&init_user_ns
, acl_e
->e_uid
));
113 e
+= sizeof(ext2_acl_entry
);
116 entry
->e_id
= cpu_to_le32(
117 from_kgid(&init_user_ns
, acl_e
->e_gid
));
118 e
+= sizeof(ext2_acl_entry
);
125 e
+= sizeof(ext2_acl_entry_short
);
132 return (char *)ext_acl
;
136 return ERR_PTR(-EINVAL
);
140 * inode->i_mutex: don't care
143 ext2_get_acl(struct inode
*inode
, int type
)
147 struct posix_acl
*acl
;
151 case ACL_TYPE_ACCESS
:
152 name_index
= EXT2_XATTR_INDEX_POSIX_ACL_ACCESS
;
154 case ACL_TYPE_DEFAULT
:
155 name_index
= EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT
;
160 retval
= ext2_xattr_get(inode
, name_index
, "", NULL
, 0);
162 value
= kmalloc(retval
, GFP_KERNEL
);
164 return ERR_PTR(-ENOMEM
);
165 retval
= ext2_xattr_get(inode
, name_index
, "", value
, retval
);
168 acl
= ext2_acl_from_disk(value
, retval
);
169 else if (retval
== -ENODATA
|| retval
== -ENOSYS
)
172 acl
= ERR_PTR(retval
);
176 set_cached_acl(inode
, type
, acl
);
182 * inode->i_mutex: down
185 ext2_set_acl(struct inode
*inode
, struct posix_acl
*acl
, int type
)
193 case ACL_TYPE_ACCESS
:
194 name_index
= EXT2_XATTR_INDEX_POSIX_ACL_ACCESS
;
196 error
= posix_acl_equiv_mode(acl
, &inode
->i_mode
);
200 inode
->i_ctime
= CURRENT_TIME_SEC
;
201 mark_inode_dirty(inode
);
208 case ACL_TYPE_DEFAULT
:
209 name_index
= EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT
;
210 if (!S_ISDIR(inode
->i_mode
))
211 return acl
? -EACCES
: 0;
218 value
= ext2_acl_to_disk(acl
, &size
);
220 return (int)PTR_ERR(value
);
223 error
= ext2_xattr_set(inode
, name_index
, "", value
, size
, 0);
227 set_cached_acl(inode
, type
, acl
);
232 * Initialize the ACLs of a new inode. Called from ext2_new_inode.
235 * inode->i_mutex: up (access to inode is still exclusive)
238 ext2_init_acl(struct inode
*inode
, struct inode
*dir
)
240 struct posix_acl
*default_acl
, *acl
;
243 error
= posix_acl_create(dir
, &inode
->i_mode
, &default_acl
, &acl
);
248 error
= ext2_set_acl(inode
, default_acl
, ACL_TYPE_DEFAULT
);
249 posix_acl_release(default_acl
);
253 error
= ext2_set_acl(inode
, acl
, ACL_TYPE_ACCESS
);
254 posix_acl_release(acl
);