diff options
Diffstat (limited to 'fs/ocfs2/acl.c')
-rw-r--r-- | fs/ocfs2/acl.c | 234 |
1 files changed, 6 insertions, 228 deletions
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index b4f788e0ca31..555f4cddefe3 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c | |||
@@ -160,36 +160,6 @@ static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode, | |||
160 | return acl; | 160 | return acl; |
161 | } | 161 | } |
162 | 162 | ||
163 | |||
164 | /* | ||
165 | * Get posix acl. | ||
166 | */ | ||
167 | static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) | ||
168 | { | ||
169 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
170 | struct buffer_head *di_bh = NULL; | ||
171 | struct posix_acl *acl; | ||
172 | int ret; | ||
173 | |||
174 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
175 | return NULL; | ||
176 | |||
177 | ret = ocfs2_inode_lock(inode, &di_bh, 0); | ||
178 | if (ret < 0) { | ||
179 | mlog_errno(ret); | ||
180 | acl = ERR_PTR(ret); | ||
181 | return acl; | ||
182 | } | ||
183 | |||
184 | acl = ocfs2_get_acl_nolock(inode, type, di_bh); | ||
185 | |||
186 | ocfs2_inode_unlock(inode, 0); | ||
187 | |||
188 | brelse(di_bh); | ||
189 | |||
190 | return acl; | ||
191 | } | ||
192 | |||
193 | /* | 163 | /* |
194 | * Helper function to set i_mode in memory and disk. Some call paths | 164 | * Helper function to set i_mode in memory and disk. Some call paths |
195 | * will not have di_bh or a journal handle to pass, in which case it | 165 | * will not have di_bh or a journal handle to pass, in which case it |
@@ -250,7 +220,7 @@ out: | |||
250 | /* | 220 | /* |
251 | * Set the access or default ACL of an inode. | 221 | * Set the access or default ACL of an inode. |
252 | */ | 222 | */ |
253 | static int ocfs2_set_acl(handle_t *handle, | 223 | int ocfs2_set_acl(handle_t *handle, |
254 | struct inode *inode, | 224 | struct inode *inode, |
255 | struct buffer_head *di_bh, | 225 | struct buffer_head *di_bh, |
256 | int type, | 226 | int type, |
@@ -313,6 +283,11 @@ static int ocfs2_set_acl(handle_t *handle, | |||
313 | return ret; | 283 | return ret; |
314 | } | 284 | } |
315 | 285 | ||
286 | int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type) | ||
287 | { | ||
288 | return ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); | ||
289 | } | ||
290 | |||
316 | struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) | 291 | struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) |
317 | { | 292 | { |
318 | struct ocfs2_super *osb; | 293 | struct ocfs2_super *osb; |
@@ -334,200 +309,3 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) | |||
334 | 309 | ||
335 | return acl; | 310 | return acl; |
336 | } | 311 | } |
337 | |||
338 | int ocfs2_acl_chmod(struct inode *inode) | ||
339 | { | ||
340 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
341 | struct posix_acl *acl; | ||
342 | int ret; | ||
343 | |||
344 | if (S_ISLNK(inode->i_mode)) | ||
345 | return -EOPNOTSUPP; | ||
346 | |||
347 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
348 | return 0; | ||
349 | |||
350 | acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); | ||
351 | if (IS_ERR(acl) || !acl) | ||
352 | return PTR_ERR(acl); | ||
353 | ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); | ||
354 | if (ret) | ||
355 | return ret; | ||
356 | ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, | ||
357 | acl, NULL, NULL); | ||
358 | posix_acl_release(acl); | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * Initialize the ACLs of a new inode. If parent directory has default ACL, | ||
364 | * then clone to new inode. Called from ocfs2_mknod. | ||
365 | */ | ||
366 | int ocfs2_init_acl(handle_t *handle, | ||
367 | struct inode *inode, | ||
368 | struct inode *dir, | ||
369 | struct buffer_head *di_bh, | ||
370 | struct buffer_head *dir_bh, | ||
371 | struct ocfs2_alloc_context *meta_ac, | ||
372 | struct ocfs2_alloc_context *data_ac) | ||
373 | { | ||
374 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
375 | struct posix_acl *acl = NULL; | ||
376 | int ret = 0, ret2; | ||
377 | umode_t mode; | ||
378 | |||
379 | if (!S_ISLNK(inode->i_mode)) { | ||
380 | if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { | ||
381 | acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, | ||
382 | dir_bh); | ||
383 | if (IS_ERR(acl)) | ||
384 | return PTR_ERR(acl); | ||
385 | } | ||
386 | if (!acl) { | ||
387 | mode = inode->i_mode & ~current_umask(); | ||
388 | ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); | ||
389 | if (ret) { | ||
390 | mlog_errno(ret); | ||
391 | goto cleanup; | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { | ||
396 | if (S_ISDIR(inode->i_mode)) { | ||
397 | ret = ocfs2_set_acl(handle, inode, di_bh, | ||
398 | ACL_TYPE_DEFAULT, acl, | ||
399 | meta_ac, data_ac); | ||
400 | if (ret) | ||
401 | goto cleanup; | ||
402 | } | ||
403 | mode = inode->i_mode; | ||
404 | ret = posix_acl_create(&acl, GFP_NOFS, &mode); | ||
405 | if (ret < 0) | ||
406 | return ret; | ||
407 | |||
408 | ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); | ||
409 | if (ret2) { | ||
410 | mlog_errno(ret2); | ||
411 | ret = ret2; | ||
412 | goto cleanup; | ||
413 | } | ||
414 | if (ret > 0) { | ||
415 | ret = ocfs2_set_acl(handle, inode, | ||
416 | di_bh, ACL_TYPE_ACCESS, | ||
417 | acl, meta_ac, data_ac); | ||
418 | } | ||
419 | } | ||
420 | cleanup: | ||
421 | posix_acl_release(acl); | ||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry, | ||
426 | char *list, | ||
427 | size_t list_len, | ||
428 | const char *name, | ||
429 | size_t name_len, | ||
430 | int type) | ||
431 | { | ||
432 | struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); | ||
433 | const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); | ||
434 | |||
435 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
436 | return 0; | ||
437 | |||
438 | if (list && size <= list_len) | ||
439 | memcpy(list, POSIX_ACL_XATTR_ACCESS, size); | ||
440 | return size; | ||
441 | } | ||
442 | |||
443 | static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry, | ||
444 | char *list, | ||
445 | size_t list_len, | ||
446 | const char *name, | ||
447 | size_t name_len, | ||
448 | int type) | ||
449 | { | ||
450 | struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); | ||
451 | const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); | ||
452 | |||
453 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
454 | return 0; | ||
455 | |||
456 | if (list && size <= list_len) | ||
457 | memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); | ||
458 | return size; | ||
459 | } | ||
460 | |||
461 | static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name, | ||
462 | void *buffer, size_t size, int type) | ||
463 | { | ||
464 | struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); | ||
465 | struct posix_acl *acl; | ||
466 | int ret; | ||
467 | |||
468 | if (strcmp(name, "") != 0) | ||
469 | return -EINVAL; | ||
470 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
471 | return -EOPNOTSUPP; | ||
472 | |||
473 | acl = ocfs2_get_acl(dentry->d_inode, type); | ||
474 | if (IS_ERR(acl)) | ||
475 | return PTR_ERR(acl); | ||
476 | if (acl == NULL) | ||
477 | return -ENODATA; | ||
478 | ret = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); | ||
479 | posix_acl_release(acl); | ||
480 | |||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name, | ||
485 | const void *value, size_t size, int flags, int type) | ||
486 | { | ||
487 | struct inode *inode = dentry->d_inode; | ||
488 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
489 | struct posix_acl *acl; | ||
490 | int ret = 0; | ||
491 | |||
492 | if (strcmp(name, "") != 0) | ||
493 | return -EINVAL; | ||
494 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
495 | return -EOPNOTSUPP; | ||
496 | |||
497 | if (!inode_owner_or_capable(inode)) | ||
498 | return -EPERM; | ||
499 | |||
500 | if (value) { | ||
501 | acl = posix_acl_from_xattr(&init_user_ns, value, size); | ||
502 | if (IS_ERR(acl)) | ||
503 | return PTR_ERR(acl); | ||
504 | else if (acl) { | ||
505 | ret = posix_acl_valid(acl); | ||
506 | if (ret) | ||
507 | goto cleanup; | ||
508 | } | ||
509 | } else | ||
510 | acl = NULL; | ||
511 | |||
512 | ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); | ||
513 | |||
514 | cleanup: | ||
515 | posix_acl_release(acl); | ||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | const struct xattr_handler ocfs2_xattr_acl_access_handler = { | ||
520 | .prefix = POSIX_ACL_XATTR_ACCESS, | ||
521 | .flags = ACL_TYPE_ACCESS, | ||
522 | .list = ocfs2_xattr_list_acl_access, | ||
523 | .get = ocfs2_xattr_get_acl, | ||
524 | .set = ocfs2_xattr_set_acl, | ||
525 | }; | ||
526 | |||
527 | const struct xattr_handler ocfs2_xattr_acl_default_handler = { | ||
528 | .prefix = POSIX_ACL_XATTR_DEFAULT, | ||
529 | .flags = ACL_TYPE_DEFAULT, | ||
530 | .list = ocfs2_xattr_list_acl_default, | ||
531 | .get = ocfs2_xattr_get_acl, | ||
532 | .set = ocfs2_xattr_set_acl, | ||
533 | }; | ||