2010-05-17 06:17:04 +04:00
/*
* Squashfs - a compressed read only filesystem for Linux
*
* Copyright ( c ) 2010
2011-05-26 13:39:56 +04:00
* Phillip Lougher < phillip @ squashfs . org . uk >
2010-05-17 06:17:04 +04:00
*
* 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 ; either version 2 ,
* or ( at your option ) any later version .
*
* This program is distributed in the hope that it will 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 to the Free Software
* Foundation , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
2010-05-31 21:50:22 +04:00
* xattr . c
2010-05-17 06:17:04 +04:00
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/string.h>
# include <linux/fs.h>
# include <linux/vfs.h>
# include <linux/xattr.h>
# include <linux/slab.h>
# include "squashfs_fs.h"
# include "squashfs_fs_sb.h"
# include "squashfs_fs_i.h"
# include "squashfs.h"
2010-05-23 06:29:26 +04:00
static const struct xattr_handler * squashfs_xattr_handler ( int ) ;
2010-05-17 06:17:04 +04:00
ssize_t squashfs_listxattr ( struct dentry * d , char * buffer ,
size_t buffer_size )
{
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( d ) ;
2010-05-17 06:17:04 +04:00
struct super_block * sb = inode - > i_sb ;
struct squashfs_sb_info * msblk = sb - > s_fs_info ;
u64 start = SQUASHFS_XATTR_BLK ( squashfs_i ( inode ) - > xattr )
+ msblk - > xattr_table ;
int offset = SQUASHFS_XATTR_OFFSET ( squashfs_i ( inode ) - > xattr ) ;
int count = squashfs_i ( inode ) - > xattr_count ;
size_t rest = buffer_size ;
int err ;
/* check that the file system has xattrs */
if ( msblk - > xattr_id_table = = NULL )
return - EOPNOTSUPP ;
/* loop reading each xattr name */
while ( count - - ) {
struct squashfs_xattr_entry entry ;
struct squashfs_xattr_val val ;
2010-05-23 06:29:26 +04:00
const struct xattr_handler * handler ;
2015-12-02 16:44:43 +03:00
int name_size ;
2010-05-17 06:17:04 +04:00
err = squashfs_read_metadata ( sb , & entry , & start , & offset ,
sizeof ( entry ) ) ;
if ( err < 0 )
goto failed ;
name_size = le16_to_cpu ( entry . size ) ;
handler = squashfs_xattr_handler ( le16_to_cpu ( entry . type ) ) ;
2015-12-02 16:44:43 +03:00
if ( handler & & ( ! handler - > list | | handler - > list ( d ) ) ) {
const char * prefix = handler - > prefix ? : handler - > name ;
size_t prefix_size = strlen ( prefix ) ;
2010-05-17 06:17:04 +04:00
if ( buffer ) {
if ( prefix_size + name_size + 1 > rest ) {
err = - ERANGE ;
goto failed ;
}
2015-12-02 16:44:43 +03:00
memcpy ( buffer , prefix , prefix_size ) ;
2010-05-17 06:17:04 +04:00
buffer + = prefix_size ;
}
err = squashfs_read_metadata ( sb , buffer , & start ,
& offset , name_size ) ;
if ( err < 0 )
goto failed ;
if ( buffer ) {
buffer [ name_size ] = ' \0 ' ;
buffer + = name_size + 1 ;
}
rest - = prefix_size + name_size + 1 ;
} else {
/* no handler or insuffficient privileges, so skip */
err = squashfs_read_metadata ( sb , NULL , & start ,
& offset , name_size ) ;
if ( err < 0 )
goto failed ;
}
/* skip remaining xattr entry */
err = squashfs_read_metadata ( sb , & val , & start , & offset ,
sizeof ( val ) ) ;
if ( err < 0 )
goto failed ;
err = squashfs_read_metadata ( sb , NULL , & start , & offset ,
le32_to_cpu ( val . vsize ) ) ;
if ( err < 0 )
goto failed ;
}
err = buffer_size - rest ;
failed :
return err ;
}
static int squashfs_xattr_get ( struct inode * inode , int name_index ,
const char * name , void * buffer , size_t buffer_size )
{
struct super_block * sb = inode - > i_sb ;
struct squashfs_sb_info * msblk = sb - > s_fs_info ;
u64 start = SQUASHFS_XATTR_BLK ( squashfs_i ( inode ) - > xattr )
+ msblk - > xattr_table ;
int offset = SQUASHFS_XATTR_OFFSET ( squashfs_i ( inode ) - > xattr ) ;
int count = squashfs_i ( inode ) - > xattr_count ;
int name_len = strlen ( name ) ;
int err , vsize ;
char * target = kmalloc ( name_len , GFP_KERNEL ) ;
if ( target = = NULL )
return - ENOMEM ;
/* loop reading each xattr name */
for ( ; count ; count - - ) {
struct squashfs_xattr_entry entry ;
struct squashfs_xattr_val val ;
int type , prefix , name_size ;
err = squashfs_read_metadata ( sb , & entry , & start , & offset ,
sizeof ( entry ) ) ;
if ( err < 0 )
goto failed ;
name_size = le16_to_cpu ( entry . size ) ;
type = le16_to_cpu ( entry . type ) ;
prefix = type & SQUASHFS_XATTR_PREFIX_MASK ;
2010-05-23 11:27:42 +04:00
if ( prefix = = name_index & & name_size = = name_len )
err = squashfs_read_metadata ( sb , target , & start ,
& offset , name_size ) ;
else
err = squashfs_read_metadata ( sb , NULL , & start ,
& offset , name_size ) ;
2010-05-17 06:17:04 +04:00
if ( err < 0 )
goto failed ;
if ( prefix = = name_index & & name_size = = name_len & &
strncmp ( target , name , name_size ) = = 0 ) {
/* found xattr */
if ( type & SQUASHFS_XATTR_VALUE_OOL ) {
2010-10-25 02:13:57 +04:00
__le64 xattr_val ;
u64 xattr ;
2010-05-17 06:17:04 +04:00
/* val is a reference to the real location */
err = squashfs_read_metadata ( sb , & val , & start ,
& offset , sizeof ( val ) ) ;
if ( err < 0 )
goto failed ;
2010-10-25 02:13:57 +04:00
err = squashfs_read_metadata ( sb , & xattr_val ,
& start , & offset , sizeof ( xattr_val ) ) ;
2010-05-17 06:17:04 +04:00
if ( err < 0 )
goto failed ;
2010-10-25 02:13:57 +04:00
xattr = le64_to_cpu ( xattr_val ) ;
2010-05-17 06:17:04 +04:00
start = SQUASHFS_XATTR_BLK ( xattr ) +
msblk - > xattr_table ;
offset = SQUASHFS_XATTR_OFFSET ( xattr ) ;
}
/* read xattr value */
err = squashfs_read_metadata ( sb , & val , & start , & offset ,
sizeof ( val ) ) ;
if ( err < 0 )
goto failed ;
vsize = le32_to_cpu ( val . vsize ) ;
if ( buffer ) {
if ( vsize > buffer_size ) {
err = - ERANGE ;
goto failed ;
}
err = squashfs_read_metadata ( sb , buffer , & start ,
& offset , vsize ) ;
if ( err < 0 )
goto failed ;
}
break ;
}
/* no match, skip remaining xattr entry */
err = squashfs_read_metadata ( sb , & val , & start , & offset ,
sizeof ( val ) ) ;
if ( err < 0 )
goto failed ;
err = squashfs_read_metadata ( sb , NULL , & start , & offset ,
le32_to_cpu ( val . vsize ) ) ;
if ( err < 0 )
goto failed ;
}
err = count ? vsize : - ENODATA ;
failed :
kfree ( target ) ;
return err ;
}
2015-10-04 20:18:53 +03:00
static int squashfs_xattr_handler_get ( const struct xattr_handler * handler ,
2016-04-11 03:48:24 +03:00
struct dentry * unused ,
struct inode * inode ,
const char * name ,
2015-10-04 20:18:53 +03:00
void * buffer , size_t size )
2010-05-17 06:17:04 +04:00
{
2016-04-11 03:48:24 +03:00
return squashfs_xattr_get ( inode , handler - > flags , name ,
2010-05-17 06:17:04 +04:00
buffer , size ) ;
}
2015-10-04 20:18:53 +03:00
/*
* User namespace support
*/
2010-05-23 06:29:26 +04:00
static const struct xattr_handler squashfs_xattr_user_handler = {
2010-05-17 06:17:04 +04:00
. prefix = XATTR_USER_PREFIX ,
2015-10-04 20:18:53 +03:00
. flags = SQUASHFS_XATTR_USER ,
. get = squashfs_xattr_handler_get
2010-05-17 06:17:04 +04:00
} ;
/*
* Trusted namespace support
*/
2015-12-02 16:44:43 +03:00
static bool squashfs_trusted_xattr_handler_list ( struct dentry * d )
2010-05-17 06:17:04 +04:00
{
2015-12-02 16:44:43 +03:00
return capable ( CAP_SYS_ADMIN ) ;
2010-05-17 06:17:04 +04:00
}
2010-05-23 06:29:26 +04:00
static const struct xattr_handler squashfs_xattr_trusted_handler = {
2010-05-17 06:17:04 +04:00
. prefix = XATTR_TRUSTED_PREFIX ,
2015-10-04 20:18:53 +03:00
. flags = SQUASHFS_XATTR_TRUSTED ,
. list = squashfs_trusted_xattr_handler_list ,
. get = squashfs_xattr_handler_get
2010-05-17 06:17:04 +04:00
} ;
/*
* Security namespace support
*/
2010-05-23 06:29:26 +04:00
static const struct xattr_handler squashfs_xattr_security_handler = {
2010-05-17 06:17:04 +04:00
. prefix = XATTR_SECURITY_PREFIX ,
2015-10-04 20:18:53 +03:00
. flags = SQUASHFS_XATTR_SECURITY ,
. get = squashfs_xattr_handler_get
2010-05-17 06:17:04 +04:00
} ;
2010-05-31 21:32:17 +04:00
static const struct xattr_handler * squashfs_xattr_handler ( int type )
2010-05-17 06:17:04 +04:00
{
if ( type & ~ ( SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL ) )
/* ignore unrecognised type */
return NULL ;
switch ( type & SQUASHFS_XATTR_PREFIX_MASK ) {
case SQUASHFS_XATTR_USER :
return & squashfs_xattr_user_handler ;
case SQUASHFS_XATTR_TRUSTED :
return & squashfs_xattr_trusted_handler ;
case SQUASHFS_XATTR_SECURITY :
return & squashfs_xattr_security_handler ;
default :
/* ignore unrecognised type */
return NULL ;
}
}
2010-05-23 06:29:26 +04:00
const struct xattr_handler * squashfs_xattr_handlers [ ] = {
2010-05-17 06:17:04 +04:00
& squashfs_xattr_user_handler ,
& squashfs_xattr_trusted_handler ,
& squashfs_xattr_security_handler ,
NULL
} ;