Blame view

fs/jfs/acl.c 5.59 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   *   Copyright (C) International Business Machines  Corp., 2002-2004
   *   Copyright (C) Andreas Gruenbacher, 2001
   *   Copyright (C) Linus Torvalds, 1991, 1992
   *
   *   This program is free software;  you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
63f83c9fc   Dave Kleikamp   JFS: White space ...
8
   *   the Free Software Foundation; either version 2 of the License, or
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   *   (at your option) any later version.
63f83c9fc   Dave Kleikamp   JFS: White space ...
10
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
   *   the GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
63f83c9fc   Dave Kleikamp   JFS: White space ...
17
   *   along with this program;  if not, write to the Free Software
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  #include <linux/sched.h>
  #include <linux/fs.h>
  #include <linux/quotaops.h>
9a59f452a   Christoph Hellwig   [PATCH] remove <l...
24
  #include <linux/posix_acl_xattr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include "jfs_incore.h"
4f4b401bf   Dave Kleikamp   JFS: allow extend...
26
  #include "jfs_txnmgr.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  #include "jfs_xattr.h"
  #include "jfs_acl.h"
  
  static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
  {
  	struct posix_acl *acl;
  	char *ea_name;
  	struct jfs_inode_info *ji = JFS_IP(inode);
  	struct posix_acl **p_acl;
  	int size;
  	char *value = NULL;
  
  	switch(type) {
  		case ACL_TYPE_ACCESS:
9a59f452a   Christoph Hellwig   [PATCH] remove <l...
41
  			ea_name = POSIX_ACL_XATTR_ACCESS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  			p_acl = &ji->i_acl;
  			break;
  		case ACL_TYPE_DEFAULT:
9a59f452a   Christoph Hellwig   [PATCH] remove <l...
45
  			ea_name = POSIX_ACL_XATTR_DEFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  			p_acl = &ji->i_default_acl;
  			break;
  		default:
  			return ERR_PTR(-EINVAL);
  	}
  
  	if (*p_acl != JFS_ACL_NOT_CACHED)
  		return posix_acl_dup(*p_acl);
  
  	size = __jfs_getxattr(inode, ea_name, NULL, 0);
  
  	if (size > 0) {
  		value = kmalloc(size, GFP_KERNEL);
  		if (!value)
  			return ERR_PTR(-ENOMEM);
  		size = __jfs_getxattr(inode, ea_name, value, size);
  	}
  
  	if (size < 0) {
  		if (size == -ENODATA) {
  			*p_acl = NULL;
  			acl = NULL;
  		} else
  			acl = ERR_PTR(size);
  	} else {
  		acl = posix_acl_from_xattr(value, size);
  		if (!IS_ERR(acl))
  			*p_acl = posix_acl_dup(acl);
  	}
259692bd5   Jesper Juhl   JFS: Remove redun...
75
  	kfree(value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
  	return acl;
  }
4f4b401bf   Dave Kleikamp   JFS: allow extend...
78
79
  static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
  		       struct posix_acl *acl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
85
86
87
88
89
90
91
92
  {
  	char *ea_name;
  	struct jfs_inode_info *ji = JFS_IP(inode);
  	struct posix_acl **p_acl;
  	int rc;
  	int size = 0;
  	char *value = NULL;
  
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
  
  	switch(type) {
  		case ACL_TYPE_ACCESS:
9a59f452a   Christoph Hellwig   [PATCH] remove <l...
93
  			ea_name = POSIX_ACL_XATTR_ACCESS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
  			p_acl = &ji->i_acl;
  			break;
  		case ACL_TYPE_DEFAULT:
9a59f452a   Christoph Hellwig   [PATCH] remove <l...
97
  			ea_name = POSIX_ACL_XATTR_DEFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
  			p_acl = &ji->i_default_acl;
  			if (!S_ISDIR(inode->i_mode))
  				return acl ? -EACCES : 0;
  			break;
  		default:
  			return -EINVAL;
  	}
  	if (acl) {
9a59f452a   Christoph Hellwig   [PATCH] remove <l...
106
  		size = posix_acl_xattr_size(acl->a_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
113
  		value = kmalloc(size, GFP_KERNEL);
  		if (!value)
  			return -ENOMEM;
  		rc = posix_acl_to_xattr(acl, value, size);
  		if (rc < 0)
  			goto out;
  	}
4f4b401bf   Dave Kleikamp   JFS: allow extend...
114
  	rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  out:
259692bd5   Jesper Juhl   JFS: Remove redun...
116
  	kfree(value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  
  	if (!rc) {
  		if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED))
  			posix_acl_release(*p_acl);
  		*p_acl = posix_acl_dup(acl);
  	}
  	return rc;
  }
  
  static int jfs_check_acl(struct inode *inode, int mask)
  {
  	struct jfs_inode_info *ji = JFS_IP(inode);
  
  	if (ji->i_acl == JFS_ACL_NOT_CACHED) {
  		struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
  		if (IS_ERR(acl))
  			return PTR_ERR(acl);
  		posix_acl_release(acl);
  	}
  
  	if (ji->i_acl)
  		return posix_acl_permission(inode, ji->i_acl, mask);
  	return -EAGAIN;
  }
  
  int jfs_permission(struct inode *inode, int mask, struct nameidata *nd)
  {
  	return generic_permission(inode, mask, jfs_check_acl);
  }
4f4b401bf   Dave Kleikamp   JFS: allow extend...
146
  int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  {
  	struct posix_acl *acl = NULL;
  	struct posix_acl *clone;
  	mode_t mode;
  	int rc = 0;
  
  	if (S_ISLNK(inode->i_mode))
  		return 0;
  
  	acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT);
  	if (IS_ERR(acl))
  		return PTR_ERR(acl);
  
  	if (acl) {
  		if (S_ISDIR(inode->i_mode)) {
4f4b401bf   Dave Kleikamp   JFS: allow extend...
162
  			rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
171
172
173
174
175
  			if (rc)
  				goto cleanup;
  		}
  		clone = posix_acl_clone(acl, GFP_KERNEL);
  		if (!clone) {
  			rc = -ENOMEM;
  			goto cleanup;
  		}
  		mode = inode->i_mode;
  		rc = posix_acl_create_masq(clone, &mode);
  		if (rc >= 0) {
  			inode->i_mode = mode;
  			if (rc > 0)
4f4b401bf   Dave Kleikamp   JFS: allow extend...
176
177
  				rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS,
  						 clone);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
182
183
  		}
  		posix_acl_release(clone);
  cleanup:
  		posix_acl_release(acl);
  	} else
  		inode->i_mode &= ~current->fs->umask;
63f83c9fc   Dave Kleikamp   JFS: White space ...
184

69eb66d7d   Dave Kleikamp   JFS: add uid, gid...
185
186
  	JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
  			       inode->i_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  
  	return rc;
  }
  
  static int jfs_acl_chmod(struct inode *inode)
  {
  	struct posix_acl *acl, *clone;
  	int rc;
  
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
  
  	acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
  	if (IS_ERR(acl) || !acl)
  		return PTR_ERR(acl);
  
  	clone = posix_acl_clone(acl, GFP_KERNEL);
  	posix_acl_release(acl);
  	if (!clone)
  		return -ENOMEM;
  
  	rc = posix_acl_chmod_masq(clone, inode->i_mode);
4f4b401bf   Dave Kleikamp   JFS: allow extend...
209
210
  	if (!rc) {
  		tid_t tid = txBegin(inode->i_sb, 0);
1de87444f   Ingo Molnar   JFS: semaphore to...
211
  		mutex_lock(&JFS_IP(inode)->commit_mutex);
4f4b401bf   Dave Kleikamp   JFS: allow extend...
212
213
214
215
  		rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone);
  		if (!rc)
  			rc = txCommit(tid, 1, &inode, 0);
  		txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
216
  		mutex_unlock(&JFS_IP(inode)->commit_mutex);
4f4b401bf   Dave Kleikamp   JFS: allow extend...
217
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  
  	posix_acl_release(clone);
  	return rc;
  }
  
  int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
  {
  	struct inode *inode = dentry->d_inode;
  	int rc;
  
  	rc = inode_change_ok(inode, iattr);
  	if (rc)
  		return rc;
  
  	if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
  	    (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
  		if (DQUOT_TRANSFER(inode, iattr))
  			return -EDQUOT;
  	}
  
  	rc = inode_setattr(inode, iattr);
  
  	if (!rc && (iattr->ia_valid & ATTR_MODE))
  		rc = jfs_acl_chmod(inode);
  
  	return rc;
  }