Merge branch 'master'
[pandora-kernel.git] / fs / gfs2 / eaops.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
4  *
5  * This copyrighted material is made available to anyone wishing to use,
6  * modify, copy, or redistribute it subject to the terms and conditions
7  * of the GNU General Public License v.2.
8  */
9
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12 #include <linux/spinlock.h>
13 #include <linux/completion.h>
14 #include <linux/buffer_head.h>
15 #include <linux/xattr.h>
16 #include <asm/semaphore.h>
17 #include <asm/uaccess.h>
18
19 #include "gfs2.h"
20 #include "acl.h"
21 #include "eaops.h"
22 #include "eattr.h"
23
24 /**
25  * gfs2_ea_name2type - get the type of the ea, and truncate type from the name
26  * @namep: ea name, possibly with type appended
27  *
28  * Returns: GFS2_EATYPE_XXX
29  */
30
31 unsigned int gfs2_ea_name2type(const char *name, char **truncated_name)
32 {
33         unsigned int type;
34
35         if (strncmp(name, "system.", 7) == 0) {
36                 type = GFS2_EATYPE_SYS;
37                 if (truncated_name)
38                         *truncated_name = strchr(name, '.') + 1;
39         } else if (strncmp(name, "user.", 5) == 0) {
40                 type = GFS2_EATYPE_USR;
41                 if (truncated_name)
42                         *truncated_name = strchr(name, '.') + 1;
43         } else {
44                 type = GFS2_EATYPE_UNUSED;
45                 if (truncated_name)
46                         *truncated_name = NULL;
47         }
48
49         return type;
50 }
51
52 static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
53 {
54         struct inode *inode = ip->i_vnode;
55         int error = permission(inode, MAY_READ, NULL);
56         if (error)
57                 return error;
58
59         return gfs2_ea_get_i(ip, er);
60 }
61
62 static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
63 {
64         struct inode *inode = ip->i_vnode;
65
66         if (S_ISREG(inode->i_mode) ||
67             (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
68                 int error = permission(inode, MAY_WRITE, NULL);
69                 if (error)
70                         return error;
71         } else
72                 return -EPERM;
73
74         return gfs2_ea_set_i(ip, er);
75 }
76
77 static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
78 {
79         struct inode *inode = ip->i_vnode;
80
81         if (S_ISREG(inode->i_mode) ||
82             (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
83                 int error = permission(inode, MAY_WRITE, NULL);
84                 if (error)
85                         return error;
86         } else
87                 return -EPERM;
88
89         return gfs2_ea_remove_i(ip, er);
90 }
91
92 static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
93 {
94         if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
95             !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
96             !capable(CAP_SYS_ADMIN))
97                 return -EPERM;
98
99         if (ip->i_sbd->sd_args.ar_posix_acl == 0 &&
100             (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
101              GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
102                 return -EOPNOTSUPP;
103
104
105
106         return gfs2_ea_get_i(ip, er);
107 }
108
109 static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
110 {
111         int remove = 0;
112         int error;
113
114         if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
115                 if (!(er->er_flags & GFS2_ERF_MODE)) {
116                         er->er_mode = ip->i_di.di_mode;
117                         er->er_flags |= GFS2_ERF_MODE;
118                 }
119                 error = gfs2_acl_validate_set(ip, 1, er,
120                                               &remove, &er->er_mode);
121                 if (error)
122                         return error;
123                 error = gfs2_ea_set_i(ip, er);
124                 if (error)
125                         return error;
126                 if (remove)
127                         gfs2_ea_remove_i(ip, er);
128                 return 0;
129
130         } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
131                 error = gfs2_acl_validate_set(ip, 0, er,
132                                               &remove, NULL);
133                 if (error)
134                         return error;
135                 if (!remove)
136                         error = gfs2_ea_set_i(ip, er);
137                 else {
138                         error = gfs2_ea_remove_i(ip, er);
139                         if (error == -ENODATA)
140                                 error = 0;
141                 }
142                 return error;   
143         }
144
145         return -EPERM;
146 }
147
148 static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
149 {
150         if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
151                 int error = gfs2_acl_validate_remove(ip, 1);
152                 if (error)
153                         return error;
154
155         } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
156                 int error = gfs2_acl_validate_remove(ip, 0);
157                 if (error)
158                         return error;
159
160         } else
161                 return -EPERM;
162
163         return gfs2_ea_remove_i(ip, er);
164 }
165
166 struct gfs2_eattr_operations gfs2_user_eaops = {
167         .eo_get = user_eo_get,
168         .eo_set = user_eo_set,
169         .eo_remove = user_eo_remove,
170         .eo_name = "user",
171 };
172
173 struct gfs2_eattr_operations gfs2_system_eaops = {
174         .eo_get = system_eo_get,
175         .eo_set = system_eo_set,
176         .eo_remove = system_eo_remove,
177         .eo_name = "system",
178 };
179
180 struct gfs2_eattr_operations *gfs2_ea_ops[] = {
181         NULL,
182         &gfs2_user_eaops,
183         &gfs2_system_eaops,
184 };
185