blob: 1b376eceb6af5273a7f963dd19ef96571f7b5035 [file] [log] [blame]
David Teiglandb3b94fa2006-01-16 16:50:04 +00001/*
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>
Steven Whitehouse5c676f62006-02-27 17:23:27 -050016#include <linux/gfs2_ondisk.h>
David Teiglandb3b94fa2006-01-16 16:50:04 +000017#include <asm/semaphore.h>
18#include <asm/uaccess.h>
19
20#include "gfs2.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050021#include "lm_interface.h"
22#include "incore.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000023#include "acl.h"
24#include "eaops.h"
25#include "eattr.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050026#include "util.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000027
28/**
29 * gfs2_ea_name2type - get the type of the ea, and truncate type from the name
30 * @namep: ea name, possibly with type appended
31 *
32 * Returns: GFS2_EATYPE_XXX
33 */
34
35unsigned int gfs2_ea_name2type(const char *name, char **truncated_name)
36{
37 unsigned int type;
38
39 if (strncmp(name, "system.", 7) == 0) {
40 type = GFS2_EATYPE_SYS;
41 if (truncated_name)
42 *truncated_name = strchr(name, '.') + 1;
43 } else if (strncmp(name, "user.", 5) == 0) {
44 type = GFS2_EATYPE_USR;
45 if (truncated_name)
46 *truncated_name = strchr(name, '.') + 1;
47 } else {
48 type = GFS2_EATYPE_UNUSED;
49 if (truncated_name)
50 *truncated_name = NULL;
51 }
52
53 return type;
54}
55
56static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
57{
58 struct inode *inode = ip->i_vnode;
59 int error = permission(inode, MAY_READ, NULL);
60 if (error)
61 return error;
62
63 return gfs2_ea_get_i(ip, er);
64}
65
66static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
67{
68 struct inode *inode = ip->i_vnode;
69
70 if (S_ISREG(inode->i_mode) ||
71 (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
72 int error = permission(inode, MAY_WRITE, NULL);
73 if (error)
74 return error;
75 } else
76 return -EPERM;
77
78 return gfs2_ea_set_i(ip, er);
79}
80
81static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
82{
83 struct inode *inode = ip->i_vnode;
84
85 if (S_ISREG(inode->i_mode) ||
86 (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
87 int error = permission(inode, MAY_WRITE, NULL);
88 if (error)
89 return error;
90 } else
91 return -EPERM;
92
93 return gfs2_ea_remove_i(ip, er);
94}
95
96static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
97{
98 if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
99 !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
100 !capable(CAP_SYS_ADMIN))
101 return -EPERM;
102
103 if (ip->i_sbd->sd_args.ar_posix_acl == 0 &&
104 (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
105 GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
106 return -EOPNOTSUPP;
107
108
109
110 return gfs2_ea_get_i(ip, er);
111}
112
113static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
114{
115 int remove = 0;
116 int error;
117
118 if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
119 if (!(er->er_flags & GFS2_ERF_MODE)) {
120 er->er_mode = ip->i_di.di_mode;
121 er->er_flags |= GFS2_ERF_MODE;
122 }
123 error = gfs2_acl_validate_set(ip, 1, er,
124 &remove, &er->er_mode);
125 if (error)
126 return error;
127 error = gfs2_ea_set_i(ip, er);
128 if (error)
129 return error;
130 if (remove)
131 gfs2_ea_remove_i(ip, er);
132 return 0;
133
134 } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
135 error = gfs2_acl_validate_set(ip, 0, er,
136 &remove, NULL);
137 if (error)
138 return error;
139 if (!remove)
140 error = gfs2_ea_set_i(ip, er);
141 else {
142 error = gfs2_ea_remove_i(ip, er);
143 if (error == -ENODATA)
144 error = 0;
145 }
146 return error;
147 }
148
149 return -EPERM;
150}
151
152static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
153{
154 if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
155 int error = gfs2_acl_validate_remove(ip, 1);
156 if (error)
157 return error;
158
159 } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
160 int error = gfs2_acl_validate_remove(ip, 0);
161 if (error)
162 return error;
163
164 } else
165 return -EPERM;
166
167 return gfs2_ea_remove_i(ip, er);
168}
169
Adrian Bunk08bc2db2006-04-28 10:59:12 -0400170static struct gfs2_eattr_operations gfs2_user_eaops = {
David Teiglandb3b94fa2006-01-16 16:50:04 +0000171 .eo_get = user_eo_get,
172 .eo_set = user_eo_set,
173 .eo_remove = user_eo_remove,
174 .eo_name = "user",
175};
176
177struct gfs2_eattr_operations gfs2_system_eaops = {
178 .eo_get = system_eo_get,
179 .eo_set = system_eo_set,
180 .eo_remove = system_eo_remove,
181 .eo_name = "system",
182};
183
184struct gfs2_eattr_operations *gfs2_ea_ops[] = {
185 NULL,
186 &gfs2_user_eaops,
187 &gfs2_system_eaops,
188};
189