ocfs2-devel: remove redundant OCFS2_MOUNT_POSIX_ACL check in ocfs2_get_acl_nolock()
[safe/jmp/linux-2.6] / fs / ocfs2 / acl.c
1 /* -*- mode: c; c-basic-offset: 8; -*-
2  * vim: noexpandtab sw=8 ts=8 sts=0:
3  *
4  * acl.c
5  *
6  * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
7  *
8  * CREDITS:
9  * Lots of code in this file is copy from linux/fs/ext3/acl.c.
10  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public
14  * License version 2 as published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  */
21
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/string.h>
25
26 #define MLOG_MASK_PREFIX ML_INODE
27 #include <cluster/masklog.h>
28
29 #include "ocfs2.h"
30 #include "alloc.h"
31 #include "dlmglue.h"
32 #include "file.h"
33 #include "ocfs2_fs.h"
34
35 #include "xattr.h"
36 #include "acl.h"
37
38 /*
39  * Convert from xattr value to acl struct.
40  */
41 static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
42 {
43         int n, count;
44         struct posix_acl *acl;
45
46         if (!value)
47                 return NULL;
48         if (size < sizeof(struct posix_acl_entry))
49                 return ERR_PTR(-EINVAL);
50
51         count = size / sizeof(struct posix_acl_entry);
52         if (count < 0)
53                 return ERR_PTR(-EINVAL);
54         if (count == 0)
55                 return NULL;
56
57         acl = posix_acl_alloc(count, GFP_NOFS);
58         if (!acl)
59                 return ERR_PTR(-ENOMEM);
60         for (n = 0; n < count; n++) {
61                 struct ocfs2_acl_entry *entry =
62                         (struct ocfs2_acl_entry *)value;
63
64                 acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
65                 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
66                 acl->a_entries[n].e_id   = le32_to_cpu(entry->e_id);
67                 value += sizeof(struct posix_acl_entry);
68
69         }
70         return acl;
71 }
72
73 /*
74  * Convert acl struct to xattr value.
75  */
76 static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
77 {
78         struct ocfs2_acl_entry *entry = NULL;
79         char *ocfs2_acl;
80         size_t n;
81
82         *size = acl->a_count * sizeof(struct posix_acl_entry);
83
84         ocfs2_acl = kmalloc(*size, GFP_NOFS);
85         if (!ocfs2_acl)
86                 return ERR_PTR(-ENOMEM);
87
88         entry = (struct ocfs2_acl_entry *)ocfs2_acl;
89         for (n = 0; n < acl->a_count; n++, entry++) {
90                 entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
91                 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
92                 entry->e_id   = cpu_to_le32(acl->a_entries[n].e_id);
93         }
94         return ocfs2_acl;
95 }
96
97 static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
98                                               int type,
99                                               struct buffer_head *di_bh)
100 {
101         int name_index;
102         char *value = NULL;
103         struct posix_acl *acl;
104         int retval;
105
106         switch (type) {
107         case ACL_TYPE_ACCESS:
108                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
109                 break;
110         case ACL_TYPE_DEFAULT:
111                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
112                 break;
113         default:
114                 return ERR_PTR(-EINVAL);
115         }
116
117         retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0);
118         if (retval > 0) {
119                 value = kmalloc(retval, GFP_NOFS);
120                 if (!value)
121                         return ERR_PTR(-ENOMEM);
122                 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
123                                                 "", value, retval);
124         }
125
126         if (retval > 0)
127                 acl = ocfs2_acl_from_xattr(value, retval);
128         else if (retval == -ENODATA || retval == 0)
129                 acl = NULL;
130         else
131                 acl = ERR_PTR(retval);
132
133         kfree(value);
134
135         return acl;
136 }
137
138
139 /*
140  * Get posix acl.
141  */
142 static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type)
143 {
144         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
145         struct buffer_head *di_bh = NULL;
146         struct posix_acl *acl;
147         int ret;
148
149         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
150                 return NULL;
151
152         ret = ocfs2_inode_lock(inode, &di_bh, 0);
153         if (ret < 0) {
154                 mlog_errno(ret);
155                 acl = ERR_PTR(ret);
156                 return acl;
157         }
158
159         acl = ocfs2_get_acl_nolock(inode, type, di_bh);
160
161         ocfs2_inode_unlock(inode, 0);
162
163         brelse(di_bh);
164
165         return acl;
166 }
167
168 /*
169  * Set the access or default ACL of an inode.
170  */
171 static int ocfs2_set_acl(handle_t *handle,
172                          struct inode *inode,
173                          struct buffer_head *di_bh,
174                          int type,
175                          struct posix_acl *acl,
176                          struct ocfs2_alloc_context *meta_ac,
177                          struct ocfs2_alloc_context *data_ac)
178 {
179         int name_index;
180         void *value = NULL;
181         size_t size = 0;
182         int ret;
183
184         if (S_ISLNK(inode->i_mode))
185                 return -EOPNOTSUPP;
186
187         switch (type) {
188         case ACL_TYPE_ACCESS:
189                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
190                 if (acl) {
191                         mode_t mode = inode->i_mode;
192                         ret = posix_acl_equiv_mode(acl, &mode);
193                         if (ret < 0)
194                                 return ret;
195                         else {
196                                 inode->i_mode = mode;
197                                 if (ret == 0)
198                                         acl = NULL;
199                         }
200                 }
201                 break;
202         case ACL_TYPE_DEFAULT:
203                 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
204                 if (!S_ISDIR(inode->i_mode))
205                         return acl ? -EACCES : 0;
206                 break;
207         default:
208                 return -EINVAL;
209         }
210
211         if (acl) {
212                 value = ocfs2_acl_to_xattr(acl, &size);
213                 if (IS_ERR(value))
214                         return (int)PTR_ERR(value);
215         }
216
217         if (handle)
218                 ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index,
219                                              "", value, size, 0,
220                                              meta_ac, data_ac);
221         else
222                 ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0);
223
224         kfree(value);
225
226         return ret;
227 }
228
229 int ocfs2_check_acl(struct inode *inode, int mask)
230 {
231         struct posix_acl *acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS);
232
233         if (IS_ERR(acl))
234                 return PTR_ERR(acl);
235         if (acl) {
236                 int ret = posix_acl_permission(inode, acl, mask);
237                 posix_acl_release(acl);
238                 return ret;
239         }
240
241         return -EAGAIN;
242 }
243
244 int ocfs2_acl_chmod(struct inode *inode)
245 {
246         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
247         struct posix_acl *acl, *clone;
248         int ret;
249
250         if (S_ISLNK(inode->i_mode))
251                 return -EOPNOTSUPP;
252
253         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
254                 return 0;
255
256         acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS);
257         if (IS_ERR(acl) || !acl)
258                 return PTR_ERR(acl);
259         clone = posix_acl_clone(acl, GFP_KERNEL);
260         posix_acl_release(acl);
261         if (!clone)
262                 return -ENOMEM;
263         ret = posix_acl_chmod_masq(clone, inode->i_mode);
264         if (!ret)
265                 ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
266                                     clone, NULL, NULL);
267         posix_acl_release(clone);
268         return ret;
269 }
270
271 /*
272  * Initialize the ACLs of a new inode. If parent directory has default ACL,
273  * then clone to new inode. Called from ocfs2_mknod.
274  */
275 int ocfs2_init_acl(handle_t *handle,
276                    struct inode *inode,
277                    struct inode *dir,
278                    struct buffer_head *di_bh,
279                    struct buffer_head *dir_bh,
280                    struct ocfs2_alloc_context *meta_ac,
281                    struct ocfs2_alloc_context *data_ac)
282 {
283         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
284         struct posix_acl *acl = NULL;
285         int ret = 0;
286
287         if (!S_ISLNK(inode->i_mode)) {
288                 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
289                         acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
290                                                    dir_bh);
291                         if (IS_ERR(acl))
292                                 return PTR_ERR(acl);
293                 }
294                 if (!acl)
295                         inode->i_mode &= ~current_umask();
296         }
297         if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
298                 struct posix_acl *clone;
299                 mode_t mode;
300
301                 if (S_ISDIR(inode->i_mode)) {
302                         ret = ocfs2_set_acl(handle, inode, di_bh,
303                                             ACL_TYPE_DEFAULT, acl,
304                                             meta_ac, data_ac);
305                         if (ret)
306                                 goto cleanup;
307                 }
308                 clone = posix_acl_clone(acl, GFP_NOFS);
309                 ret = -ENOMEM;
310                 if (!clone)
311                         goto cleanup;
312
313                 mode = inode->i_mode;
314                 ret = posix_acl_create_masq(clone, &mode);
315                 if (ret >= 0) {
316                         inode->i_mode = mode;
317                         if (ret > 0) {
318                                 ret = ocfs2_set_acl(handle, inode,
319                                                     di_bh, ACL_TYPE_ACCESS,
320                                                     clone, meta_ac, data_ac);
321                         }
322                 }
323                 posix_acl_release(clone);
324         }
325 cleanup:
326         posix_acl_release(acl);
327         return ret;
328 }
329
330 static size_t ocfs2_xattr_list_acl_access(struct inode *inode,
331                                           char *list,
332                                           size_t list_len,
333                                           const char *name,
334                                           size_t name_len)
335 {
336         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
337         const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
338
339         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
340                 return 0;
341
342         if (list && size <= list_len)
343                 memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
344         return size;
345 }
346
347 static size_t ocfs2_xattr_list_acl_default(struct inode *inode,
348                                            char *list,
349                                            size_t list_len,
350                                            const char *name,
351                                            size_t name_len)
352 {
353         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
354         const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
355
356         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
357                 return 0;
358
359         if (list && size <= list_len)
360                 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
361         return size;
362 }
363
364 static int ocfs2_xattr_get_acl(struct inode *inode,
365                                int type,
366                                void *buffer,
367                                size_t size)
368 {
369         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
370         struct posix_acl *acl;
371         int ret;
372
373         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
374                 return -EOPNOTSUPP;
375
376         acl = ocfs2_get_acl(inode, type);
377         if (IS_ERR(acl))
378                 return PTR_ERR(acl);
379         if (acl == NULL)
380                 return -ENODATA;
381         ret = posix_acl_to_xattr(acl, buffer, size);
382         posix_acl_release(acl);
383
384         return ret;
385 }
386
387 static int ocfs2_xattr_get_acl_access(struct inode *inode,
388                                       const char *name,
389                                       void *buffer,
390                                       size_t size)
391 {
392         if (strcmp(name, "") != 0)
393                 return -EINVAL;
394         return ocfs2_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
395 }
396
397 static int ocfs2_xattr_get_acl_default(struct inode *inode,
398                                        const char *name,
399                                        void *buffer,
400                                        size_t size)
401 {
402         if (strcmp(name, "") != 0)
403                 return -EINVAL;
404         return ocfs2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
405 }
406
407 static int ocfs2_xattr_set_acl(struct inode *inode,
408                                int type,
409                                const void *value,
410                                size_t size)
411 {
412         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
413         struct posix_acl *acl;
414         int ret = 0;
415
416         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
417                 return -EOPNOTSUPP;
418
419         if (!is_owner_or_cap(inode))
420                 return -EPERM;
421
422         if (value) {
423                 acl = posix_acl_from_xattr(value, size);
424                 if (IS_ERR(acl))
425                         return PTR_ERR(acl);
426                 else if (acl) {
427                         ret = posix_acl_valid(acl);
428                         if (ret)
429                                 goto cleanup;
430                 }
431         } else
432                 acl = NULL;
433
434         ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL);
435
436 cleanup:
437         posix_acl_release(acl);
438         return ret;
439 }
440
441 static int ocfs2_xattr_set_acl_access(struct inode *inode,
442                                       const char *name,
443                                       const void *value,
444                                       size_t size,
445                                       int flags)
446 {
447         if (strcmp(name, "") != 0)
448                 return -EINVAL;
449         return ocfs2_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
450 }
451
452 static int ocfs2_xattr_set_acl_default(struct inode *inode,
453                                        const char *name,
454                                        const void *value,
455                                        size_t size,
456                                        int flags)
457 {
458         if (strcmp(name, "") != 0)
459                 return -EINVAL;
460         return ocfs2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
461 }
462
463 struct xattr_handler ocfs2_xattr_acl_access_handler = {
464         .prefix = POSIX_ACL_XATTR_ACCESS,
465         .list   = ocfs2_xattr_list_acl_access,
466         .get    = ocfs2_xattr_get_acl_access,
467         .set    = ocfs2_xattr_set_acl_access,
468 };
469
470 struct xattr_handler ocfs2_xattr_acl_default_handler = {
471         .prefix = POSIX_ACL_XATTR_DEFAULT,
472         .list   = ocfs2_xattr_list_acl_default,
473         .get    = ocfs2_xattr_get_acl_default,
474         .set    = ocfs2_xattr_set_acl_default,
475 };