2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-08-12 14:49:38 +04:00
/*
* Copyright ( c ) 2000 - 2005 Silicon Graphics , Inc .
* Copyright ( c ) 2013 Red Hat , Inc .
* All Rights Reserved .
*/
# include "xfs.h"
# include "xfs_fs.h"
2019-06-29 05:25:35 +03:00
# include "xfs_shared.h"
2013-10-23 03:51:50 +04:00
# include "xfs_format.h"
2013-10-23 03:50:10 +04:00
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2013-08-12 14:49:38 +04:00
# include "xfs_mount.h"
2013-10-15 02:17:51 +04:00
# include "xfs_da_format.h"
2013-08-12 14:49:38 +04:00
# include "xfs_inode.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2013-08-12 14:49:38 +04:00
# include "xfs_bmap.h"
# include "xfs_attr.h"
2013-10-23 03:51:50 +04:00
# include "xfs_attr_sf.h"
2013-08-12 14:49:38 +04:00
# include "xfs_attr_leaf.h"
# include "xfs_error.h"
# include "xfs_trace.h"
2013-10-29 15:11:51 +04:00
# include "xfs_dir2.h"
2013-08-12 14:49:38 +04:00
STATIC int
xfs_attr_shortform_compare ( const void * a , const void * b )
{
xfs_attr_sf_sort_t * sa , * sb ;
sa = ( xfs_attr_sf_sort_t * ) a ;
sb = ( xfs_attr_sf_sort_t * ) b ;
if ( sa - > hash < sb - > hash ) {
2014-06-22 09:03:54 +04:00
return - 1 ;
2013-08-12 14:49:38 +04:00
} else if ( sa - > hash > sb - > hash ) {
2014-06-22 09:03:54 +04:00
return 1 ;
2013-08-12 14:49:38 +04:00
} else {
2014-06-22 09:03:54 +04:00
return sa - > entno - sb - > entno ;
2013-08-12 14:49:38 +04:00
}
}
# define XFS_ISRESET_CURSOR(cursor) \
( ! ( ( cursor ) - > initted ) & & ! ( ( cursor ) - > hashval ) & & \
! ( ( cursor ) - > blkno ) & & ! ( ( cursor ) - > offset ) )
/*
* Copy out entries of shortform attribute lists for attr_list ( ) .
* Shortform attribute lists are not stored in hashval sorted order .
* If the output buffer is not large enough to hold them all , then we
* we have to calculate each entries ' hashvalue and sort them before
* we can begin returning them to the user .
*/
2016-06-01 10:38:15 +03:00
static int
2019-10-29 02:12:33 +03:00
xfs_attr_shortform_list (
struct xfs_attr_list_context * context )
2013-08-12 14:49:38 +04:00
{
2019-10-29 02:12:33 +03:00
struct attrlist_cursor_kern * cursor ;
struct xfs_attr_sf_sort * sbuf , * sbp ;
struct xfs_attr_shortform * sf ;
struct xfs_attr_sf_entry * sfe ;
struct xfs_inode * dp ;
int sbsize , nsbuf , count , i ;
int error = 0 ;
2013-08-12 14:49:38 +04:00
ASSERT ( context ! = NULL ) ;
dp = context - > dp ;
ASSERT ( dp ! = NULL ) ;
ASSERT ( dp - > i_afp ! = NULL ) ;
sf = ( xfs_attr_shortform_t * ) dp - > i_afp - > if_u1 . if_data ;
ASSERT ( sf ! = NULL ) ;
if ( ! sf - > hdr . count )
2014-06-22 09:03:54 +04:00
return 0 ;
2013-08-12 14:49:38 +04:00
cursor = context - > cursor ;
ASSERT ( cursor ! = NULL ) ;
trace_xfs_attr_list_sf ( context ) ;
/*
* If the buffer is large enough and the cursor is at the start ,
* do not bother with sorting since we will return everything in
* one buffer and another call using the cursor won ' t need to be
* made .
* Note the generous fudge factor of 16 overhead bytes per entry .
* If bufsize is zero then put_listent must be a search function
* and can just scan through what we have .
*/
if ( context - > bufsize = = 0 | |
( XFS_ISRESET_CURSOR ( cursor ) & &
2018-08-01 22:58:34 +03:00
( dp - > i_afp - > if_bytes + sf - > hdr . count * 16 ) < context - > bufsize ) ) {
2013-08-12 14:49:38 +04:00
for ( i = 0 , sfe = & sf - > list [ 0 ] ; i < sf - > hdr . count ; i + + ) {
2019-11-11 23:53:22 +03:00
if ( XFS_IS_CORRUPT ( context - > dp - > i_mount ,
! xfs_attr_namecheck ( sfe - > nameval ,
sfe - > namelen ) ) )
2019-10-29 02:12:33 +03:00
return - EFSCORRUPTED ;
2016-12-05 04:32:14 +03:00
context - > put_listent ( context ,
sfe - > flags ,
sfe - > nameval ,
( int ) sfe - > namelen ,
( int ) sfe - > valuelen ) ;
2013-08-12 14:49:38 +04:00
/*
* Either search callback finished early or
* didn ' t fit it all in the buffer after all .
*/
if ( context - > seen_enough )
break ;
sfe = XFS_ATTR_SF_NEXTENTRY ( sfe ) ;
}
trace_xfs_attr_list_sf_all ( context ) ;
2014-06-22 09:03:54 +04:00
return 0 ;
2013-08-12 14:49:38 +04:00
}
/* do no more for a search callback */
if ( context - > bufsize = = 0 )
return 0 ;
/*
* It didn ' t all fit , so we have to sort everything on hashval .
*/
sbsize = sf - > hdr . count * sizeof ( * sbuf ) ;
2019-08-26 22:06:22 +03:00
sbp = sbuf = kmem_alloc ( sbsize , KM_NOFS ) ;
2013-08-12 14:49:38 +04:00
/*
* Scan the attribute list for the rest of the entries , storing
* the relevant info from only those that match into a buffer .
*/
nsbuf = 0 ;
for ( i = 0 , sfe = & sf - > list [ 0 ] ; i < sf - > hdr . count ; i + + ) {
if ( unlikely (
( ( char * ) sfe < ( char * ) sf ) | |
( ( char * ) sfe > = ( ( char * ) sf + dp - > i_afp - > if_bytes ) ) ) ) {
XFS_CORRUPTION_ERROR ( " xfs_attr_shortform_list " ,
XFS_ERRLEVEL_LOW ,
2018-06-04 20:23:54 +03:00
context - > dp - > i_mount , sfe ,
sizeof ( * sfe ) ) ;
2013-08-12 14:49:38 +04:00
kmem_free ( sbuf ) ;
2014-06-25 08:58:08 +04:00
return - EFSCORRUPTED ;
2013-08-12 14:49:38 +04:00
}
sbp - > entno = i ;
sbp - > hash = xfs_da_hashname ( sfe - > nameval , sfe - > namelen ) ;
sbp - > name = sfe - > nameval ;
sbp - > namelen = sfe - > namelen ;
/* These are bytes, and both on-disk, don't endian-flip */
sbp - > valuelen = sfe - > valuelen ;
sbp - > flags = sfe - > flags ;
sfe = XFS_ATTR_SF_NEXTENTRY ( sfe ) ;
sbp + + ;
nsbuf + + ;
}
/*
* Sort the entries on hash then entno .
*/
xfs_sort ( sbuf , nsbuf , sizeof ( * sbuf ) , xfs_attr_shortform_compare ) ;
/*
* Re - find our place IN THE SORTED LIST .
*/
count = 0 ;
cursor - > initted = 1 ;
cursor - > blkno = 0 ;
for ( sbp = sbuf , i = 0 ; i < nsbuf ; i + + , sbp + + ) {
if ( sbp - > hash = = cursor - > hashval ) {
if ( cursor - > offset = = count ) {
break ;
}
count + + ;
} else if ( sbp - > hash > cursor - > hashval ) {
break ;
}
}
2019-10-29 02:12:33 +03:00
if ( i = = nsbuf )
goto out ;
2013-08-12 14:49:38 +04:00
/*
* Loop putting entries into the user buffer .
*/
for ( ; i < nsbuf ; i + + , sbp + + ) {
if ( cursor - > hashval ! = sbp - > hash ) {
cursor - > hashval = sbp - > hash ;
cursor - > offset = 0 ;
}
2019-11-11 23:53:22 +03:00
if ( XFS_IS_CORRUPT ( context - > dp - > i_mount ,
! xfs_attr_namecheck ( sbp - > name ,
sbp - > namelen ) ) ) {
2019-10-29 02:12:33 +03:00
error = - EFSCORRUPTED ;
goto out ;
}
2016-12-05 04:32:14 +03:00
context - > put_listent ( context ,
sbp - > flags ,
sbp - > name ,
sbp - > namelen ,
sbp - > valuelen ) ;
2013-08-12 14:49:38 +04:00
if ( context - > seen_enough )
break ;
cursor - > offset + + ;
}
2019-10-29 02:12:33 +03:00
out :
2013-08-12 14:49:38 +04:00
kmem_free ( sbuf ) ;
2019-10-29 02:12:33 +03:00
return error ;
2013-08-12 14:49:38 +04:00
}
2017-10-26 02:59:42 +03:00
/*
* We didn ' t find the block & hash mentioned in the cursor state , so
* walk down the attr btree looking for the hash .
*/
2013-08-12 14:49:38 +04:00
STATIC int
2017-10-26 02:59:42 +03:00
xfs_attr_node_list_lookup (
struct xfs_attr_list_context * context ,
struct attrlist_cursor_kern * cursor ,
struct xfs_buf * * pbp )
2013-08-12 14:49:38 +04:00
{
2017-10-26 02:59:42 +03:00
struct xfs_da3_icnode_hdr nodehdr ;
struct xfs_da_intnode * node ;
struct xfs_da_node_entry * btree ;
struct xfs_inode * dp = context - > dp ;
struct xfs_mount * mp = dp - > i_mount ;
struct xfs_trans * tp = context - > tp ;
struct xfs_buf * bp ;
int i ;
int error = 0 ;
2017-10-26 02:59:43 +03:00
unsigned int expected_level = 0 ;
2017-10-26 02:59:42 +03:00
uint16_t magic ;
ASSERT ( * pbp = = NULL ) ;
cursor - > blkno = 0 ;
for ( ; ; ) {
2019-11-20 20:46:04 +03:00
error = xfs_da3_node_read ( tp , dp , cursor - > blkno , & bp ,
2017-10-26 02:59:42 +03:00
XFS_ATTR_FORK ) ;
if ( error )
return error ;
node = bp - > b_addr ;
magic = be16_to_cpu ( node - > hdr . info . magic ) ;
if ( magic = = XFS_ATTR_LEAF_MAGIC | |
magic = = XFS_ATTR3_LEAF_MAGIC )
break ;
if ( magic ! = XFS_DA_NODE_MAGIC & &
magic ! = XFS_DA3_NODE_MAGIC ) {
XFS_CORRUPTION_ERROR ( __func__ , XFS_ERRLEVEL_LOW , mp ,
2018-06-04 20:23:54 +03:00
node , sizeof ( * node ) ) ;
2017-10-26 02:59:42 +03:00
goto out_corruptbuf ;
}
2019-11-09 01:53:00 +03:00
xfs_da3_node_hdr_from_disk ( mp , & nodehdr , node ) ;
2017-10-26 02:59:42 +03:00
2017-10-26 02:59:43 +03:00
/* Tree taller than we can handle; bail out! */
if ( nodehdr . level > = XFS_DA_NODE_MAXDEPTH )
goto out_corruptbuf ;
/* Check the level from the root node. */
if ( cursor - > blkno = = 0 )
expected_level = nodehdr . level - 1 ;
else if ( expected_level ! = nodehdr . level )
goto out_corruptbuf ;
else
expected_level - - ;
2019-11-09 01:57:48 +03:00
btree = nodehdr . btree ;
2017-10-26 02:59:42 +03:00
for ( i = 0 ; i < nodehdr . count ; btree + + , i + + ) {
if ( cursor - > hashval < = be32_to_cpu ( btree - > hashval ) ) {
cursor - > blkno = be32_to_cpu ( btree - > before ) ;
trace_xfs_attr_list_node_descend ( context ,
btree ) ;
break ;
}
}
xfs_trans_brelse ( tp , bp ) ;
if ( i = = nodehdr . count )
return 0 ;
2017-10-26 02:59:43 +03:00
/* We can't point back to the root. */
2019-11-11 23:53:22 +03:00
if ( XFS_IS_CORRUPT ( mp , cursor - > blkno = = 0 ) )
2017-10-26 02:59:43 +03:00
return - EFSCORRUPTED ;
2017-10-26 02:59:42 +03:00
}
2017-10-26 02:59:43 +03:00
if ( expected_level ! = 0 )
goto out_corruptbuf ;
2017-10-26 02:59:42 +03:00
* pbp = bp ;
return 0 ;
out_corruptbuf :
2019-11-02 19:40:53 +03:00
xfs_buf_corruption_error ( bp ) ;
2017-10-26 02:59:42 +03:00
xfs_trans_brelse ( tp , bp ) ;
return - EFSCORRUPTED ;
}
STATIC int
xfs_attr_node_list (
struct xfs_attr_list_context * context )
{
struct xfs_attr3_icleaf_hdr leafhdr ;
struct attrlist_cursor_kern * cursor ;
struct xfs_attr_leafblock * leaf ;
struct xfs_da_intnode * node ;
struct xfs_buf * bp ;
struct xfs_inode * dp = context - > dp ;
struct xfs_mount * mp = dp - > i_mount ;
2019-10-29 02:12:33 +03:00
int error = 0 ;
2013-08-12 14:49:38 +04:00
trace_xfs_attr_node_list ( context ) ;
cursor = context - > cursor ;
cursor - > initted = 1 ;
/*
* Do all sorts of validation on the passed - in cursor structure .
* If anything is amiss , ignore the cursor and look up the hashval
* starting from the btree root .
*/
bp = NULL ;
if ( cursor - > blkno > 0 ) {
2019-11-20 20:46:04 +03:00
error = xfs_da3_node_read ( context - > tp , dp , cursor - > blkno , & bp ,
XFS_ATTR_FORK ) ;
2014-06-25 08:58:08 +04:00
if ( ( error ! = 0 ) & & ( error ! = - EFSCORRUPTED ) )
2014-06-22 09:03:54 +04:00
return error ;
2013-08-12 14:49:38 +04:00
if ( bp ) {
struct xfs_attr_leaf_entry * entries ;
node = bp - > b_addr ;
switch ( be16_to_cpu ( node - > hdr . info . magic ) ) {
case XFS_DA_NODE_MAGIC :
case XFS_DA3_NODE_MAGIC :
trace_xfs_attr_list_wrong_blk ( context ) ;
2017-06-16 21:00:14 +03:00
xfs_trans_brelse ( context - > tp , bp ) ;
2013-08-12 14:49:38 +04:00
bp = NULL ;
break ;
case XFS_ATTR_LEAF_MAGIC :
case XFS_ATTR3_LEAF_MAGIC :
leaf = bp - > b_addr ;
2015-04-13 04:26:02 +03:00
xfs_attr3_leaf_hdr_from_disk ( mp - > m_attr_geo ,
& leafhdr , leaf ) ;
2013-08-12 14:49:38 +04:00
entries = xfs_attr3_leaf_entryp ( leaf ) ;
if ( cursor - > hashval > be32_to_cpu (
entries [ leafhdr . count - 1 ] . hashval ) ) {
trace_xfs_attr_list_wrong_blk ( context ) ;
2017-06-16 21:00:14 +03:00
xfs_trans_brelse ( context - > tp , bp ) ;
2013-08-12 14:49:38 +04:00
bp = NULL ;
} else if ( cursor - > hashval < = be32_to_cpu (
entries [ 0 ] . hashval ) ) {
trace_xfs_attr_list_wrong_blk ( context ) ;
2017-06-16 21:00:14 +03:00
xfs_trans_brelse ( context - > tp , bp ) ;
2013-08-12 14:49:38 +04:00
bp = NULL ;
}
break ;
default :
trace_xfs_attr_list_wrong_blk ( context ) ;
2017-06-16 21:00:14 +03:00
xfs_trans_brelse ( context - > tp , bp ) ;
2013-08-12 14:49:38 +04:00
bp = NULL ;
}
}
}
/*
* We did not find what we expected given the cursor ' s contents ,
* so we start from the top and work down based on the hash value .
* Note that start of node block is same as start of leaf block .
*/
if ( bp = = NULL ) {
2017-10-26 02:59:42 +03:00
error = xfs_attr_node_list_lookup ( context , cursor , & bp ) ;
if ( error | | ! bp )
return error ;
2013-08-12 14:49:38 +04:00
}
ASSERT ( bp ! = NULL ) ;
/*
* Roll upward through the blocks , processing each leaf block in
* order . As long as there is space in the result buffer , keep
* adding the information .
*/
for ( ; ; ) {
leaf = bp - > b_addr ;
2019-10-29 02:12:33 +03:00
error = xfs_attr3_leaf_list_int ( bp , context ) ;
if ( error )
break ;
2015-04-13 04:26:02 +03:00
xfs_attr3_leaf_hdr_from_disk ( mp - > m_attr_geo , & leafhdr , leaf ) ;
2013-08-12 14:49:38 +04:00
if ( context - > seen_enough | | leafhdr . forw = = 0 )
break ;
cursor - > blkno = leafhdr . forw ;
2017-06-16 21:00:14 +03:00
xfs_trans_brelse ( context - > tp , bp ) ;
2019-11-20 20:46:02 +03:00
error = xfs_attr3_leaf_read ( context - > tp , dp , cursor - > blkno ,
& bp ) ;
2013-08-12 14:49:38 +04:00
if ( error )
return error ;
}
2017-06-16 21:00:14 +03:00
xfs_trans_brelse ( context - > tp , bp ) ;
2019-10-29 02:12:33 +03:00
return error ;
2013-08-12 14:49:38 +04:00
}
/*
* Copy out attribute list entries for attr_list ( ) , for leaf attribute lists .
*/
2019-10-29 02:12:33 +03:00
int
2013-08-12 14:49:38 +04:00
xfs_attr3_leaf_list_int (
struct xfs_buf * bp ,
struct xfs_attr_list_context * context )
{
struct attrlist_cursor_kern * cursor ;
struct xfs_attr_leafblock * leaf ;
struct xfs_attr3_icleaf_hdr ichdr ;
struct xfs_attr_leaf_entry * entries ;
struct xfs_attr_leaf_entry * entry ;
int i ;
2015-04-13 04:26:02 +03:00
struct xfs_mount * mp = context - > dp - > i_mount ;
2013-08-12 14:49:38 +04:00
trace_xfs_attr_list_leaf ( context ) ;
leaf = bp - > b_addr ;
2015-04-13 04:26:02 +03:00
xfs_attr3_leaf_hdr_from_disk ( mp - > m_attr_geo , & ichdr , leaf ) ;
2013-08-12 14:49:38 +04:00
entries = xfs_attr3_leaf_entryp ( leaf ) ;
cursor = context - > cursor ;
cursor - > initted = 1 ;
/*
* Re - find our place in the leaf block if this is a new syscall .
*/
if ( context - > resynch ) {
entry = & entries [ 0 ] ;
for ( i = 0 ; i < ichdr . count ; entry + + , i + + ) {
if ( be32_to_cpu ( entry - > hashval ) = = cursor - > hashval ) {
if ( cursor - > offset = = context - > dupcnt ) {
context - > dupcnt = 0 ;
break ;
}
context - > dupcnt + + ;
} else if ( be32_to_cpu ( entry - > hashval ) >
cursor - > hashval ) {
context - > dupcnt = 0 ;
break ;
}
}
if ( i = = ichdr . count ) {
trace_xfs_attr_list_notfound ( context ) ;
2019-10-29 02:12:33 +03:00
return 0 ;
2013-08-12 14:49:38 +04:00
}
} else {
entry = & entries [ 0 ] ;
i = 0 ;
}
context - > resynch = 0 ;
/*
* We have found our place , start copying out the new attributes .
*/
for ( ; i < ichdr . count ; entry + + , i + + ) {
2016-04-06 00:57:47 +03:00
char * name ;
int namelen , valuelen ;
2013-08-12 14:49:38 +04:00
if ( be32_to_cpu ( entry - > hashval ) ! = cursor - > hashval ) {
cursor - > hashval = be32_to_cpu ( entry - > hashval ) ;
cursor - > offset = 0 ;
}
2017-10-18 07:37:45 +03:00
if ( ( entry - > flags & XFS_ATTR_INCOMPLETE ) & &
! ( context - > flags & ATTR_INCOMPLETE ) )
2013-08-12 14:49:38 +04:00
continue ; /* skip incomplete entries */
if ( entry - > flags & XFS_ATTR_LOCAL ) {
2016-04-06 00:57:47 +03:00
xfs_attr_leaf_name_local_t * name_loc ;
2013-08-12 14:49:38 +04:00
2016-04-06 00:57:47 +03:00
name_loc = xfs_attr3_leaf_name_local ( leaf , i ) ;
name = name_loc - > nameval ;
namelen = name_loc - > namelen ;
valuelen = be16_to_cpu ( name_loc - > valuelen ) ;
} else {
xfs_attr_leaf_name_remote_t * name_rmt ;
2013-08-12 14:49:38 +04:00
2016-04-06 00:57:47 +03:00
name_rmt = xfs_attr3_leaf_name_remote ( leaf , i ) ;
name = name_rmt - > name ;
namelen = name_rmt - > namelen ;
valuelen = be32_to_cpu ( name_rmt - > valuelen ) ;
2013-08-12 14:49:38 +04:00
}
2016-04-06 00:57:47 +03:00
2019-11-11 23:53:22 +03:00
if ( XFS_IS_CORRUPT ( context - > dp - > i_mount ,
! xfs_attr_namecheck ( name , namelen ) ) )
2019-10-29 02:12:33 +03:00
return - EFSCORRUPTED ;
2016-12-05 04:32:14 +03:00
context - > put_listent ( context , entry - > flags ,
2016-04-06 00:57:47 +03:00
name , namelen , valuelen ) ;
2013-08-12 14:49:38 +04:00
if ( context - > seen_enough )
break ;
cursor - > offset + + ;
}
trace_xfs_attr_list_leaf_end ( context ) ;
2019-10-29 02:12:33 +03:00
return 0 ;
2013-08-12 14:49:38 +04:00
}
/*
* Copy out attribute entries for attr_list ( ) , for leaf attribute lists .
*/
STATIC int
xfs_attr_leaf_list ( xfs_attr_list_context_t * context )
{
int error ;
struct xfs_buf * bp ;
trace_xfs_attr_leaf_list ( context ) ;
context - > cursor - > blkno = 0 ;
2019-11-20 20:46:02 +03:00
error = xfs_attr3_leaf_read ( context - > tp , context - > dp , 0 , & bp ) ;
2013-08-12 14:49:38 +04:00
if ( error )
2014-06-22 09:04:54 +04:00
return error ;
2013-08-12 14:49:38 +04:00
2019-10-29 02:12:33 +03:00
error = xfs_attr3_leaf_list_int ( bp , context ) ;
2017-06-16 21:00:14 +03:00
xfs_trans_brelse ( context - > tp , bp ) ;
2019-10-29 02:12:33 +03:00
return error ;
2013-08-12 14:49:38 +04:00
}
2017-06-16 21:00:14 +03:00
int
xfs_attr_list_int_ilocked (
struct xfs_attr_list_context * context )
{
struct xfs_inode * dp = context - > dp ;
2017-07-13 22:14:33 +03:00
ASSERT ( xfs_isilocked ( dp , XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ;
2017-06-16 21:00:14 +03:00
/*
* Decide on what work routines to call based on the inode size .
*/
if ( ! xfs_inode_hasattr ( dp ) )
return 0 ;
else if ( dp - > i_d . di_aformat = = XFS_DINODE_FMT_LOCAL )
return xfs_attr_shortform_list ( context ) ;
else if ( xfs_bmap_one_block ( dp , XFS_ATTR_FORK ) )
return xfs_attr_leaf_list ( context ) ;
return xfs_attr_node_list ( context ) ;
}
2013-08-12 14:49:38 +04:00
int
xfs_attr_list_int (
xfs_attr_list_context_t * context )
{
int error ;
xfs_inode_t * dp = context - > dp ;
2013-12-07 00:30:16 +04:00
uint lock_mode ;
2013-08-12 14:49:38 +04:00
2015-10-12 10:21:22 +03:00
XFS_STATS_INC ( dp - > i_mount , xs_attr_list ) ;
2013-08-12 14:49:38 +04:00
if ( XFS_FORCED_SHUTDOWN ( dp - > i_mount ) )
2014-06-25 08:58:08 +04:00
return - EIO ;
2013-08-12 14:49:38 +04:00
2013-12-07 00:30:16 +04:00
lock_mode = xfs_ilock_attr_map_shared ( dp ) ;
2017-06-16 21:00:14 +03:00
error = xfs_attr_list_int_ilocked ( context ) ;
2013-12-07 00:30:16 +04:00
xfs_iunlock ( dp , lock_mode ) ;
2013-08-12 14:49:38 +04:00
return error ;
}
# define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \
( ( ( struct attrlist_ent * ) 0 ) - > a_name - ( char * ) 0 )
# define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \
2017-11-09 20:34:28 +03:00
( ( ATTR_ENTBASESIZE + ( namelen ) + 1 + sizeof ( uint32_t ) - 1 ) \
& ~ ( sizeof ( uint32_t ) - 1 ) )
2013-08-12 14:49:38 +04:00
/*
* Format an attribute and copy it out to the user ' s buffer .
* Take care to check values and protect against them changing later ,
* we may be reading them directly out of a user buffer .
*/
2016-12-05 04:32:14 +03:00
STATIC void
2013-08-12 14:49:38 +04:00
xfs_attr_put_listent (
xfs_attr_list_context_t * context ,
int flags ,
unsigned char * name ,
int namelen ,
2016-04-06 00:57:32 +03:00
int valuelen )
2013-08-12 14:49:38 +04:00
{
struct attrlist * alist = ( struct attrlist * ) context - > alist ;
attrlist_ent_t * aep ;
int arraytop ;
2019-02-13 22:15:17 +03:00
ASSERT ( ! context - > seen_enough ) ;
2013-08-12 14:49:38 +04:00
ASSERT ( ! ( context - > flags & ATTR_KERNOVAL ) ) ;
ASSERT ( context - > count > = 0 ) ;
ASSERT ( context - > count < ( ATTR_MAX_VALUELEN / 8 ) ) ;
ASSERT ( context - > firstu > = sizeof ( * alist ) ) ;
ASSERT ( context - > firstu < = context - > bufsize ) ;
/*
* Only list entries in the right namespace .
*/
if ( ( ( context - > flags & ATTR_SECURE ) = = 0 ) ! =
( ( flags & XFS_ATTR_SECURE ) = = 0 ) )
2016-12-05 04:32:14 +03:00
return ;
2013-08-12 14:49:38 +04:00
if ( ( ( context - > flags & ATTR_ROOT ) = = 0 ) ! =
( ( flags & XFS_ATTR_ROOT ) = = 0 ) )
2016-12-05 04:32:14 +03:00
return ;
2013-08-12 14:49:38 +04:00
arraytop = sizeof ( * alist ) +
context - > count * sizeof ( alist - > al_offset [ 0 ] ) ;
context - > firstu - = ATTR_ENTSIZE ( namelen ) ;
if ( context - > firstu < arraytop ) {
trace_xfs_attr_list_full ( context ) ;
alist - > al_more = 1 ;
context - > seen_enough = 1 ;
2016-12-05 04:32:14 +03:00
return ;
2013-08-12 14:49:38 +04:00
}
aep = ( attrlist_ent_t * ) & context - > alist [ context - > firstu ] ;
aep - > a_valuelen = valuelen ;
memcpy ( aep - > a_name , name , namelen ) ;
aep - > a_name [ namelen ] = 0 ;
alist - > al_offset [ context - > count + + ] = context - > firstu ;
alist - > al_count = context - > count ;
trace_xfs_attr_list_add ( context ) ;
2016-12-05 04:32:14 +03:00
return ;
2013-08-12 14:49:38 +04:00
}
/*
* Generate a list of extended attribute names and optionally
* also value lengths . Positive return value follows the XFS
* convention of being an error , zero or negative return code
* is the length of the buffer returned ( negated ) , indicating
* success .
*/
int
xfs_attr_list (
xfs_inode_t * dp ,
char * buffer ,
int bufsize ,
int flags ,
attrlist_cursor_kern_t * cursor )
{
xfs_attr_list_context_t context ;
struct attrlist * alist ;
int error ;
/*
* Validate the cursor .
*/
if ( cursor - > pad1 | | cursor - > pad2 )
2014-06-25 08:58:08 +04:00
return - EINVAL ;
2013-08-12 14:49:38 +04:00
if ( ( cursor - > initted = = 0 ) & &
( cursor - > hashval | | cursor - > blkno | | cursor - > offset ) )
2014-06-25 08:58:08 +04:00
return - EINVAL ;
2013-08-12 14:49:38 +04:00
2017-10-18 07:37:45 +03:00
/* Only internal consumers can retrieve incomplete attrs. */
if ( flags & ATTR_INCOMPLETE )
return - EINVAL ;
2013-08-12 14:49:38 +04:00
/*
* Check for a properly aligned buffer .
*/
if ( ( ( long ) buffer ) & ( sizeof ( int ) - 1 ) )
2014-06-25 08:58:08 +04:00
return - EFAULT ;
2013-08-12 14:49:38 +04:00
if ( flags & ATTR_KERNOVAL )
bufsize = 0 ;
/*
* Initialize the output buffer .
*/
memset ( & context , 0 , sizeof ( context ) ) ;
context . dp = dp ;
context . cursor = cursor ;
context . resynch = 1 ;
context . flags = flags ;
context . alist = buffer ;
context . bufsize = ( bufsize & ~ ( sizeof ( int ) - 1 ) ) ; /* align */
context . firstu = context . bufsize ;
context . put_listent = xfs_attr_put_listent ;
alist = ( struct attrlist * ) context . alist ;
alist - > al_count = 0 ;
alist - > al_more = 0 ;
alist - > al_offset [ 0 ] = context . bufsize ;
error = xfs_attr_list_int ( & context ) ;
2014-06-25 08:58:08 +04:00
ASSERT ( error < = 0 ) ;
2013-08-12 14:49:38 +04:00
return error ;
}