diff options
Diffstat (limited to 'fs/posix_acl.c')
-rw-r--r-- | fs/posix_acl.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/fs/posix_acl.c b/fs/posix_acl.c index a9dafa83678c..0ef1c3722504 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c | |||
@@ -598,6 +598,37 @@ no_mem: | |||
598 | } | 598 | } |
599 | EXPORT_SYMBOL_GPL(posix_acl_create); | 599 | EXPORT_SYMBOL_GPL(posix_acl_create); |
600 | 600 | ||
601 | /** | ||
602 | * posix_acl_update_mode - update mode in set_acl | ||
603 | * | ||
604 | * Update the file mode when setting an ACL: compute the new file permission | ||
605 | * bits based on the ACL. In addition, if the ACL is equivalent to the new | ||
606 | * file mode, set *acl to NULL to indicate that no ACL should be set. | ||
607 | * | ||
608 | * As with chmod, clear the setgit bit if the caller is not in the owning group | ||
609 | * or capable of CAP_FSETID (see inode_change_ok). | ||
610 | * | ||
611 | * Called from set_acl inode operations. | ||
612 | */ | ||
613 | int posix_acl_update_mode(struct inode *inode, umode_t *mode_p, | ||
614 | struct posix_acl **acl) | ||
615 | { | ||
616 | umode_t mode = inode->i_mode; | ||
617 | int error; | ||
618 | |||
619 | error = posix_acl_equiv_mode(*acl, &mode); | ||
620 | if (error < 0) | ||
621 | return error; | ||
622 | if (error == 0) | ||
623 | *acl = NULL; | ||
624 | if (!in_group_p(inode->i_gid) && | ||
625 | !capable_wrt_inode_uidgid(inode, CAP_FSETID)) | ||
626 | mode &= ~S_ISGID; | ||
627 | *mode_p = mode; | ||
628 | return 0; | ||
629 | } | ||
630 | EXPORT_SYMBOL(posix_acl_update_mode); | ||
631 | |||
601 | /* | 632 | /* |
602 | * Fix up the uids and gids in posix acl extended attributes in place. | 633 | * Fix up the uids and gids in posix acl extended attributes in place. |
603 | */ | 634 | */ |