2008-06-23 07:34:09 +04:00
/*
* Copyright ( C ) 2008 Christoph Hellwig .
* Portions Copyright ( C ) 2000 - 2008 Silicon Graphics , Inc .
*
* 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 the Free Software Foundation .
*
* This program is distributed in the hope that it would 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
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include "xfs.h"
2013-08-12 14:49:23 +04:00
# include "xfs_log_format.h"
2008-06-23 07:34:09 +04:00
# include "xfs_da_btree.h"
# include "xfs_bmap_btree.h"
# include "xfs_inode.h"
# include "xfs_attr.h"
# include "xfs_attr_leaf.h"
# include "xfs_acl.h"
# include <linux/posix_acl_xattr.h>
# include <linux/xattr.h>
static int
2009-11-13 12:52:56 +03:00
xfs_xattr_get ( struct dentry * dentry , const char * name ,
2008-06-23 07:34:09 +04:00
void * value , size_t size , int xflags )
{
2009-11-13 12:52:56 +03:00
struct xfs_inode * ip = XFS_I ( dentry - > d_inode ) ;
2008-06-23 07:34:09 +04:00
int error , asize = size ;
if ( strcmp ( name , " " ) = = 0 )
return - EINVAL ;
/* Convert Linux syscall to XFS internal ATTR flags */
if ( ! size ) {
xflags | = ATTR_KERNOVAL ;
value = NULL ;
}
2010-01-20 02:47:48 +03:00
error = - xfs_attr_get ( ip , ( unsigned char * ) name , value , & asize , xflags ) ;
2008-06-23 07:34:09 +04:00
if ( error )
return error ;
return asize ;
}
static int
2009-11-13 12:52:56 +03:00
xfs_xattr_set ( struct dentry * dentry , const char * name , const void * value ,
2008-06-23 07:34:09 +04:00
size_t size , int flags , int xflags )
{
2009-11-13 12:52:56 +03:00
struct xfs_inode * ip = XFS_I ( dentry - > d_inode ) ;
2008-06-23 07:34:09 +04:00
if ( strcmp ( name , " " ) = = 0 )
return - EINVAL ;
/* Convert Linux syscall to XFS internal ATTR flags */
if ( flags & XATTR_CREATE )
xflags | = ATTR_CREATE ;
if ( flags & XATTR_REPLACE )
xflags | = ATTR_REPLACE ;
if ( ! value )
2010-01-20 02:47:48 +03:00
return - xfs_attr_remove ( ip , ( unsigned char * ) name , xflags ) ;
return - xfs_attr_set ( ip , ( unsigned char * ) name ,
( void * ) value , size , xflags ) ;
2008-06-23 07:34:09 +04:00
}
2010-05-14 04:53:20 +04:00
static const struct xattr_handler xfs_xattr_user_handler = {
2008-06-23 07:34:09 +04:00
. prefix = XATTR_USER_PREFIX ,
2009-11-13 12:52:56 +03:00
. flags = 0 , /* no flags implies user namespace */
. get = xfs_xattr_get ,
. set = xfs_xattr_set ,
2008-06-23 07:34:09 +04:00
} ;
2010-05-14 04:53:20 +04:00
static const struct xattr_handler xfs_xattr_trusted_handler = {
2008-06-23 07:34:09 +04:00
. prefix = XATTR_TRUSTED_PREFIX ,
2009-11-13 12:52:56 +03:00
. flags = ATTR_ROOT ,
. get = xfs_xattr_get ,
. set = xfs_xattr_set ,
2008-06-23 07:34:09 +04:00
} ;
2010-05-14 04:53:20 +04:00
static const struct xattr_handler xfs_xattr_security_handler = {
2008-06-23 07:34:09 +04:00
. prefix = XATTR_SECURITY_PREFIX ,
2009-11-13 12:52:56 +03:00
. flags = ATTR_SECURE ,
. get = xfs_xattr_get ,
. set = xfs_xattr_set ,
2008-06-23 07:34:09 +04:00
} ;
2010-05-14 04:53:20 +04:00
const struct xattr_handler * xfs_xattr_handlers [ ] = {
2008-06-23 07:34:09 +04:00
& xfs_xattr_user_handler ,
& xfs_xattr_trusted_handler ,
& xfs_xattr_security_handler ,
2009-06-10 19:07:47 +04:00
# ifdef CONFIG_XFS_POSIX_ACL
2009-11-13 12:52:56 +03:00
& xfs_xattr_acl_access_handler ,
& xfs_xattr_acl_default_handler ,
2009-06-10 19:07:47 +04:00
# endif
2008-06-23 07:34:09 +04:00
NULL
} ;
static unsigned int xfs_xattr_prefix_len ( int flags )
{
if ( flags & XFS_ATTR_SECURE )
return sizeof ( " security " ) ;
else if ( flags & XFS_ATTR_ROOT )
return sizeof ( " trusted " ) ;
else
return sizeof ( " user " ) ;
}
static const char * xfs_xattr_prefix ( int flags )
{
if ( flags & XFS_ATTR_SECURE )
return xfs_xattr_security_handler . prefix ;
else if ( flags & XFS_ATTR_ROOT )
return xfs_xattr_trusted_handler . prefix ;
else
return xfs_xattr_user_handler . prefix ;
}
static int
2010-01-20 02:47:48 +03:00
xfs_xattr_put_listent (
struct xfs_attr_list_context * context ,
int flags ,
unsigned char * name ,
int namelen ,
int valuelen ,
unsigned char * value )
2008-06-23 07:34:09 +04:00
{
unsigned int prefix_len = xfs_xattr_prefix_len ( flags ) ;
char * offset ;
int arraytop ;
ASSERT ( context - > count > = 0 ) ;
/*
* Only show root namespace entries if we are actually allowed to
* see them .
*/
if ( ( flags & XFS_ATTR_ROOT ) & & ! capable ( CAP_SYS_ADMIN ) )
return 0 ;
arraytop = context - > count + prefix_len + namelen + 1 ;
if ( arraytop > context - > firstu ) {
context - > count = - 1 ; /* insufficient space */
return 1 ;
}
offset = ( char * ) context - > alist + context - > count ;
strncpy ( offset , xfs_xattr_prefix ( flags ) , prefix_len ) ;
offset + = prefix_len ;
2010-01-20 02:47:48 +03:00
strncpy ( offset , ( char * ) name , namelen ) ; /* real name */
2008-06-23 07:34:09 +04:00
offset + = namelen ;
* offset = ' \0 ' ;
context - > count + = prefix_len + namelen + 1 ;
return 0 ;
}
static int
2010-01-20 02:47:48 +03:00
xfs_xattr_put_listent_sizes (
struct xfs_attr_list_context * context ,
int flags ,
unsigned char * name ,
int namelen ,
int valuelen ,
unsigned char * value )
2008-06-23 07:34:09 +04:00
{
context - > count + = xfs_xattr_prefix_len ( flags ) + namelen + 1 ;
return 0 ;
}
static int
list_one_attr ( const char * name , const size_t len , void * data ,
size_t size , ssize_t * result )
{
char * p = data + * result ;
* result + = len ;
if ( ! size )
return 0 ;
if ( * result > size )
return - ERANGE ;
strcpy ( p , name ) ;
return 0 ;
}
ssize_t
xfs_vn_listxattr ( struct dentry * dentry , char * data , size_t size )
{
struct xfs_attr_list_context context ;
struct attrlist_cursor_kern cursor = { 0 } ;
struct inode * inode = dentry - > d_inode ;
int error ;
/*
* First read the regular on - disk attributes .
*/
memset ( & context , 0 , sizeof ( context ) ) ;
context . dp = XFS_I ( inode ) ;
context . cursor = & cursor ;
context . resynch = 1 ;
context . alist = data ;
context . bufsize = size ;
context . firstu = context . bufsize ;
if ( size )
context . put_listent = xfs_xattr_put_listent ;
else
context . put_listent = xfs_xattr_put_listent_sizes ;
xfs_attr_list_int ( & context ) ;
if ( context . count < 0 )
return - ERANGE ;
/*
* Then add the two synthetic ACL attributes .
*/
2009-06-10 19:07:47 +04:00
if ( posix_acl_access_exists ( inode ) ) {
2008-06-23 07:34:09 +04:00
error = list_one_attr ( POSIX_ACL_XATTR_ACCESS ,
strlen ( POSIX_ACL_XATTR_ACCESS ) + 1 ,
data , size , & context . count ) ;
if ( error )
return error ;
}
2009-06-10 19:07:47 +04:00
if ( posix_acl_default_exists ( inode ) ) {
2008-06-23 07:34:09 +04:00
error = list_one_attr ( POSIX_ACL_XATTR_DEFAULT ,
strlen ( POSIX_ACL_XATTR_DEFAULT ) + 1 ,
data , size , & context . count ) ;
if ( error )
return error ;
}
return context . count ;
}