2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-17 02:20:36 +04:00
/*
* linux / fs / adfs / dir_fplus . c
*
* Copyright ( C ) 1997 - 1999 Russell King
*/
# include "adfs.h"
# include "dir_fplus.h"
2019-12-09 14:09:35 +03:00
static int adfs_fplus_read ( struct super_block * sb , u32 indaddr ,
unsigned int size , struct adfs_dir * dir )
2005-04-17 02:20:36 +04:00
{
struct adfs_bigdirheader * h ;
struct adfs_bigdirtail * t ;
2019-12-09 14:09:35 +03:00
unsigned int dirsize ;
int ret ;
2005-04-17 02:20:36 +04:00
2019-12-09 14:09:35 +03:00
/* Read first buffer */
ret = adfs_dir_read_buffers ( sb , indaddr , sb - > s_blocksize , dir ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2019-12-09 14:09:10 +03:00
h = ( struct adfs_bigdirheader * ) dir - > bhs [ 0 ] - > b_data ;
2019-12-09 14:09:35 +03:00
dirsize = le32_to_cpu ( h - > bigdirsize ) ;
if ( dirsize ! = size ) {
2019-06-04 16:49:52 +03:00
adfs_msg ( sb , KERN_WARNING ,
2019-12-09 14:09:35 +03:00
" dir %06x header size %X does not match directory size %X " ,
indaddr , dirsize , size ) ;
2005-04-17 02:20:36 +04:00
}
if ( h - > bigdirversion [ 0 ] ! = 0 | | h - > bigdirversion [ 1 ] ! = 0 | |
h - > bigdirversion [ 2 ] ! = 0 | | size & 2047 | |
2011-03-23 02:35:04 +03:00
h - > bigdirstartname ! = cpu_to_le32 ( BIGDIRSTARTNAME ) ) {
2019-12-09 14:09:35 +03:00
adfs_error ( sb , " dir %06x has malformed header " , indaddr ) ;
2005-04-17 02:20:36 +04:00
goto out ;
2011-03-23 02:35:04 +03:00
}
2005-04-17 02:20:36 +04:00
2019-12-09 14:09:35 +03:00
/* Read remaining buffers */
ret = adfs_dir_read_buffers ( sb , indaddr , dirsize , dir ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2011-03-23 02:35:04 +03:00
t = ( struct adfs_bigdirtail * )
2019-12-09 14:09:35 +03:00
( dir - > bhs [ dir - > nr_buffers - 1 ] - > b_data + ( sb - > s_blocksize - 8 ) ) ;
2005-04-17 02:20:36 +04:00
if ( t - > bigdirendname ! = cpu_to_le32 ( BIGDIRENDNAME ) | |
t - > bigdirendmasseq ! = h - > startmasseq | |
2011-03-23 02:35:04 +03:00
t - > reserved [ 0 ] ! = 0 | | t - > reserved [ 1 ] ! = 0 ) {
2019-12-09 14:09:35 +03:00
adfs_error ( sb , " dir %06x has malformed tail " , indaddr ) ;
2005-04-17 02:20:36 +04:00
goto out ;
2011-03-23 02:35:04 +03:00
}
2005-04-17 02:20:36 +04:00
dir - > parent_id = le32_to_cpu ( h - > bigdirparent ) ;
return 0 ;
2011-03-23 02:35:04 +03:00
2005-04-17 02:20:36 +04:00
out :
2019-12-09 14:09:20 +03:00
adfs_dir_relse ( dir ) ;
2011-03-23 02:35:04 +03:00
2005-04-17 02:20:36 +04:00
return ret ;
}
static int
adfs_fplus_setpos ( struct adfs_dir * dir , unsigned int fpos )
{
2011-03-23 02:35:04 +03:00
struct adfs_bigdirheader * h =
2019-12-09 14:09:10 +03:00
( struct adfs_bigdirheader * ) dir - > bhs [ 0 ] - > b_data ;
2005-04-17 02:20:36 +04:00
int ret = - ENOENT ;
if ( fpos < = le32_to_cpu ( h - > bigdirentries ) ) {
dir - > pos = fpos ;
ret = 0 ;
}
return ret ;
}
static int
adfs_fplus_getnext ( struct adfs_dir * dir , struct object_info * obj )
{
2011-03-23 02:35:04 +03:00
struct adfs_bigdirheader * h =
2019-12-09 14:09:10 +03:00
( struct adfs_bigdirheader * ) dir - > bhs [ 0 ] - > b_data ;
2005-04-17 02:20:36 +04:00
struct adfs_bigdirentry bde ;
unsigned int offset ;
2019-12-09 14:09:30 +03:00
int ret ;
2005-04-17 02:20:36 +04:00
if ( dir - > pos > = le32_to_cpu ( h - > bigdirentries ) )
2019-12-09 14:09:30 +03:00
return - ENOENT ;
2005-04-17 02:20:36 +04:00
offset = offsetof ( struct adfs_bigdirheader , bigdirname ) ;
offset + = ( ( le32_to_cpu ( h - > bigdirnamelen ) + 4 ) & ~ 3 ) ;
offset + = dir - > pos * sizeof ( struct adfs_bigdirentry ) ;
2019-12-09 14:09:30 +03:00
ret = adfs_dir_copyfrom ( & bde , dir , offset ,
sizeof ( struct adfs_bigdirentry ) ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
obj - > loadaddr = le32_to_cpu ( bde . bigdirload ) ;
obj - > execaddr = le32_to_cpu ( bde . bigdirexec ) ;
obj - > size = le32_to_cpu ( bde . bigdirlen ) ;
2019-06-04 16:49:57 +03:00
obj - > indaddr = le32_to_cpu ( bde . bigdirindaddr ) ;
2005-04-17 02:20:36 +04:00
obj - > attr = le32_to_cpu ( bde . bigdirattr ) ;
obj - > name_len = le32_to_cpu ( bde . bigdirobnamelen ) ;
offset = offsetof ( struct adfs_bigdirheader , bigdirname ) ;
offset + = ( ( le32_to_cpu ( h - > bigdirnamelen ) + 4 ) & ~ 3 ) ;
offset + = le32_to_cpu ( h - > bigdirentries ) * sizeof ( struct adfs_bigdirentry ) ;
offset + = le32_to_cpu ( bde . bigdirobnameptr ) ;
2019-12-09 14:09:30 +03:00
ret = adfs_dir_copyfrom ( obj - > name , dir , offset , obj - > name_len ) ;
if ( ret )
return ret ;
2019-03-24 15:57:32 +03:00
adfs_object_fixup ( dir , obj ) ;
2011-03-23 02:35:06 +03:00
2005-04-17 02:20:36 +04:00
dir - > pos + = 1 ;
2019-12-09 14:09:30 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2019-12-09 14:10:16 +03:00
static int adfs_fplus_iterate ( struct adfs_dir * dir , struct dir_context * ctx )
{
struct object_info obj ;
if ( ( ctx - > pos - 2 ) > > 32 )
return 0 ;
if ( adfs_fplus_setpos ( dir , ctx - > pos - 2 ) )
return 0 ;
while ( ! adfs_fplus_getnext ( dir , & obj ) ) {
if ( ! dir_emit ( ctx , obj . name , obj . name_len ,
obj . indaddr , DT_UNKNOWN ) )
break ;
ctx - > pos + + ;
}
return 0 ;
}
2015-11-21 18:15:37 +03:00
const struct adfs_dir_ops adfs_fplus_dir_ops = {
2005-04-17 02:20:36 +04:00
. read = adfs_fplus_read ,
2019-12-09 14:10:16 +03:00
. iterate = adfs_fplus_iterate ,
2005-04-17 02:20:36 +04:00
. setpos = adfs_fplus_setpos ,
. getnext = adfs_fplus_getnext ,
} ;