2006-09-29 13:01:34 +04:00
/*
* fs / generic_acl . c
*
* ( C ) 2005 Andreas Gruenbacher < agruen @ suse . de >
*
* This file is released under the GPL .
*/
# include <linux/sched.h>
# include <linux/fs.h>
# include <linux/generic_acl.h>
/**
* generic_acl_list - Generic xattr_handler - > list ( ) operation
* @ ops : Filesystem specific getacl and setacl callbacks
*/
size_t
generic_acl_list ( struct inode * inode , struct generic_acl_operations * ops ,
int type , char * list , size_t list_size )
{
struct posix_acl * acl ;
const char * name ;
size_t size ;
acl = ops - > getacl ( inode , type ) ;
if ( ! acl )
return 0 ;
posix_acl_release ( acl ) ;
switch ( type ) {
case ACL_TYPE_ACCESS :
name = POSIX_ACL_XATTR_ACCESS ;
break ;
case ACL_TYPE_DEFAULT :
name = POSIX_ACL_XATTR_DEFAULT ;
break ;
default :
return 0 ;
}
size = strlen ( name ) + 1 ;
if ( list & & size < = list_size )
memcpy ( list , name , size ) ;
return size ;
}
/**
* generic_acl_get - Generic xattr_handler - > get ( ) operation
* @ ops : Filesystem specific getacl and setacl callbacks
*/
int
generic_acl_get ( struct inode * inode , struct generic_acl_operations * ops ,
int type , void * buffer , size_t size )
{
struct posix_acl * acl ;
int error ;
acl = ops - > getacl ( inode , type ) ;
if ( ! acl )
return - ENODATA ;
error = posix_acl_to_xattr ( acl , buffer , size ) ;
posix_acl_release ( acl ) ;
return error ;
}
/**
* generic_acl_set - Generic xattr_handler - > set ( ) operation
* @ ops : Filesystem specific getacl and setacl callbacks
*/
int
generic_acl_set ( struct inode * inode , struct generic_acl_operations * ops ,
int type , const void * value , size_t size )
{
struct posix_acl * acl = NULL ;
int error ;
if ( S_ISLNK ( inode - > i_mode ) )
return - EOPNOTSUPP ;
2007-07-17 13:30:08 +04:00
if ( ! is_owner_or_cap ( inode ) )
2006-09-29 13:01:34 +04:00
return - EPERM ;
if ( value ) {
acl = posix_acl_from_xattr ( value , size ) ;
if ( IS_ERR ( acl ) )
return PTR_ERR ( acl ) ;
}
if ( acl ) {
mode_t mode ;
error = posix_acl_valid ( acl ) ;
if ( error )
goto failed ;
switch ( type ) {
case ACL_TYPE_ACCESS :
mode = inode - > i_mode ;
error = posix_acl_equiv_mode ( acl , & mode ) ;
if ( error < 0 )
goto failed ;
inode - > i_mode = mode ;
if ( error = = 0 ) {
posix_acl_release ( acl ) ;
acl = NULL ;
}
break ;
case ACL_TYPE_DEFAULT :
if ( ! S_ISDIR ( inode - > i_mode ) ) {
error = - EINVAL ;
goto failed ;
}
break ;
}
}
ops - > setacl ( inode , type , acl ) ;
error = 0 ;
failed :
posix_acl_release ( acl ) ;
return error ;
}
/**
* generic_acl_init - Take care of acl inheritance at @ inode create time
* @ ops : Filesystem specific getacl and setacl callbacks
*
* Files created inside a directory with a default ACL inherit the
* directory ' s default ACL .
*/
int
generic_acl_init ( struct inode * inode , struct inode * dir ,
struct generic_acl_operations * ops )
{
struct posix_acl * acl = NULL ;
mode_t mode = inode - > i_mode ;
int error ;
inode - > i_mode = mode & ~ current - > fs - > umask ;
if ( ! S_ISLNK ( inode - > i_mode ) )
acl = ops - > getacl ( dir , ACL_TYPE_DEFAULT ) ;
if ( acl ) {
struct posix_acl * clone ;
if ( S_ISDIR ( inode - > i_mode ) ) {
clone = posix_acl_clone ( acl , GFP_KERNEL ) ;
error = - ENOMEM ;
if ( ! clone )
goto cleanup ;
ops - > setacl ( inode , ACL_TYPE_DEFAULT , clone ) ;
posix_acl_release ( clone ) ;
}
clone = posix_acl_clone ( acl , GFP_KERNEL ) ;
error = - ENOMEM ;
if ( ! clone )
goto cleanup ;
error = posix_acl_create_masq ( clone , & mode ) ;
if ( error > = 0 ) {
inode - > i_mode = mode ;
if ( error > 0 )
ops - > setacl ( inode , ACL_TYPE_ACCESS , clone ) ;
}
posix_acl_release ( clone ) ;
}
error = 0 ;
cleanup :
posix_acl_release ( acl ) ;
return error ;
}
/**
* generic_acl_chmod - change the access acl of @ inode upon chmod ( )
* @ ops : FIlesystem specific getacl and setacl callbacks
*
* A chmod also changes the permissions of the owner , group / mask , and
* other ACL entries .
*/
int
generic_acl_chmod ( struct inode * inode , struct generic_acl_operations * ops )
{
struct posix_acl * acl , * clone ;
int error = 0 ;
if ( S_ISLNK ( inode - > i_mode ) )
return - EOPNOTSUPP ;
acl = ops - > getacl ( inode , ACL_TYPE_ACCESS ) ;
if ( acl ) {
clone = posix_acl_clone ( acl , GFP_KERNEL ) ;
posix_acl_release ( acl ) ;
if ( ! clone )
return - ENOMEM ;
error = posix_acl_chmod_masq ( clone , inode - > i_mode ) ;
if ( ! error )
ops - > setacl ( inode , ACL_TYPE_ACCESS , clone ) ;
posix_acl_release ( clone ) ;
}
return error ;
}