2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
* Copyright ( C ) 2004 - 2005 Red Hat , Inc . All rights reserved .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*/
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
# include <linux/xattr.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-01-16 19:50:04 +03:00
# include <asm/semaphore.h>
# include <asm/uaccess.h>
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "lm_interface.h"
# include "incore.h"
2006-01-16 19:50:04 +03:00
# include "acl.h"
# include "eaops.h"
# include "eattr.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-01-16 19:50:04 +03:00
/**
* gfs2_ea_name2type - get the type of the ea , and truncate type from the name
* @ namep : ea name , possibly with type appended
*
* Returns : GFS2_EATYPE_XXX
*/
unsigned int gfs2_ea_name2type ( const char * name , char * * truncated_name )
{
unsigned int type ;
if ( strncmp ( name , " system. " , 7 ) = = 0 ) {
type = GFS2_EATYPE_SYS ;
if ( truncated_name )
* truncated_name = strchr ( name , ' . ' ) + 1 ;
} else if ( strncmp ( name , " user. " , 5 ) = = 0 ) {
type = GFS2_EATYPE_USR ;
if ( truncated_name )
* truncated_name = strchr ( name , ' . ' ) + 1 ;
} else {
type = GFS2_EATYPE_UNUSED ;
if ( truncated_name )
* truncated_name = NULL ;
}
return type ;
}
static int user_eo_get ( struct gfs2_inode * ip , struct gfs2_ea_request * er )
{
struct inode * inode = ip - > i_vnode ;
int error = permission ( inode , MAY_READ , NULL ) ;
if ( error )
return error ;
return gfs2_ea_get_i ( ip , er ) ;
}
static int user_eo_set ( struct gfs2_inode * ip , struct gfs2_ea_request * er )
{
struct inode * inode = ip - > i_vnode ;
if ( S_ISREG ( inode - > i_mode ) | |
( S_ISDIR ( inode - > i_mode ) & & ! ( inode - > i_mode & S_ISVTX ) ) ) {
int error = permission ( inode , MAY_WRITE , NULL ) ;
if ( error )
return error ;
} else
return - EPERM ;
return gfs2_ea_set_i ( ip , er ) ;
}
static int user_eo_remove ( struct gfs2_inode * ip , struct gfs2_ea_request * er )
{
struct inode * inode = ip - > i_vnode ;
if ( S_ISREG ( inode - > i_mode ) | |
( S_ISDIR ( inode - > i_mode ) & & ! ( inode - > i_mode & S_ISVTX ) ) ) {
int error = permission ( inode , MAY_WRITE , NULL ) ;
if ( error )
return error ;
} else
return - EPERM ;
return gfs2_ea_remove_i ( ip , er ) ;
}
static int system_eo_get ( struct gfs2_inode * ip , struct gfs2_ea_request * er )
{
if ( ! GFS2_ACL_IS_ACCESS ( er - > er_name , er - > er_name_len ) & &
! GFS2_ACL_IS_DEFAULT ( er - > er_name , er - > er_name_len ) & &
! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( ip - > i_sbd - > sd_args . ar_posix_acl = = 0 & &
( GFS2_ACL_IS_ACCESS ( er - > er_name , er - > er_name_len ) | |
GFS2_ACL_IS_DEFAULT ( er - > er_name , er - > er_name_len ) ) )
return - EOPNOTSUPP ;
return gfs2_ea_get_i ( ip , er ) ;
}
static int system_eo_set ( struct gfs2_inode * ip , struct gfs2_ea_request * er )
{
int remove = 0 ;
int error ;
if ( GFS2_ACL_IS_ACCESS ( er - > er_name , er - > er_name_len ) ) {
if ( ! ( er - > er_flags & GFS2_ERF_MODE ) ) {
er - > er_mode = ip - > i_di . di_mode ;
er - > er_flags | = GFS2_ERF_MODE ;
}
error = gfs2_acl_validate_set ( ip , 1 , er ,
& remove , & er - > er_mode ) ;
if ( error )
return error ;
error = gfs2_ea_set_i ( ip , er ) ;
if ( error )
return error ;
if ( remove )
gfs2_ea_remove_i ( ip , er ) ;
return 0 ;
} else if ( GFS2_ACL_IS_DEFAULT ( er - > er_name , er - > er_name_len ) ) {
error = gfs2_acl_validate_set ( ip , 0 , er ,
& remove , NULL ) ;
if ( error )
return error ;
if ( ! remove )
error = gfs2_ea_set_i ( ip , er ) ;
else {
error = gfs2_ea_remove_i ( ip , er ) ;
if ( error = = - ENODATA )
error = 0 ;
}
return error ;
}
return - EPERM ;
}
static int system_eo_remove ( struct gfs2_inode * ip , struct gfs2_ea_request * er )
{
if ( GFS2_ACL_IS_ACCESS ( er - > er_name , er - > er_name_len ) ) {
int error = gfs2_acl_validate_remove ( ip , 1 ) ;
if ( error )
return error ;
} else if ( GFS2_ACL_IS_DEFAULT ( er - > er_name , er - > er_name_len ) ) {
int error = gfs2_acl_validate_remove ( ip , 0 ) ;
if ( error )
return error ;
} else
return - EPERM ;
return gfs2_ea_remove_i ( ip , er ) ;
}
struct gfs2_eattr_operations gfs2_user_eaops = {
. eo_get = user_eo_get ,
. eo_set = user_eo_set ,
. eo_remove = user_eo_remove ,
. eo_name = " user " ,
} ;
struct gfs2_eattr_operations gfs2_system_eaops = {
. eo_get = system_eo_get ,
. eo_set = system_eo_set ,
. eo_remove = system_eo_remove ,
. eo_name = " system " ,
} ;
struct gfs2_eattr_operations * gfs2_ea_ops [ ] = {
NULL ,
& gfs2_user_eaops ,
& gfs2_system_eaops ,
} ;