2005-04-17 02:20:36 +04:00
/*
* dir . c
*
* PURPOSE
* Directory handling routines for the OSTA - UDF ( tm ) filesystem .
*
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License ( GPL ) . Copies of the GPL can be obtained from :
* ftp : //prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work .
*
* ( C ) 1998 - 2004 Ben Fennema
*
* HISTORY
*
* 10 / 05 / 98 dgb Split directory operations into its own file
* Implemented directory reads via do_udf_readdir
* 10 / 06 / 98 Made directory operations work !
* 11 / 17 / 98 Rewrote directory to support ICBTAG_FLAG_AD_LONG
* 11 / 25 / 98 blf Rewrote directory handling ( readdir + lookup ) to support reading
* across blocks .
* 12 / 12 / 98 Split out the lookup code to namei . c . bulk of directory
* code now in directory . c : udf_fileident_read .
*/
# include "udfdecl.h"
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/mm.h>
# include <linux/slab.h>
2016-11-01 16:40:13 +03:00
# include <linux/bio.h>
2021-11-04 17:22:35 +03:00
# include <linux/iversion.h>
2005-04-17 02:20:36 +04:00
# include "udf_i.h"
# include "udf_sb.h"
2013-05-16 09:09:37 +04:00
static int udf_readdir ( struct file * file , struct dir_context * ctx )
2005-04-17 02:20:36 +04:00
{
2013-05-16 09:09:37 +04:00
struct inode * dir = file_inode ( file ) ;
2021-11-04 17:22:35 +03:00
loff_t nf_pos , emit_pos = 0 ;
2005-04-17 02:20:36 +04:00
int flen ;
2022-10-04 16:00:15 +03:00
unsigned char * fname = NULL ;
int ret = 0 ;
2014-12-19 00:49:12 +03:00
struct super_block * sb = dir - > i_sb ;
2021-11-04 17:22:35 +03:00
bool pos_valid = false ;
2022-10-04 16:00:15 +03:00
struct udf_fileident_iter iter ;
2005-04-17 02:20:36 +04:00
2013-05-16 09:09:37 +04:00
if ( ctx - > pos = = 0 ) {
if ( ! dir_emit_dot ( file , ctx ) )
return 0 ;
ctx - > pos = 1 ;
}
nf_pos = ( ctx - > pos - 1 ) < < 2 ;
2022-10-04 16:00:15 +03:00
if ( nf_pos > = dir - > i_size )
2008-03-04 16:14:05 +03:00
goto out ;
2021-11-04 17:22:35 +03:00
/*
* Something changed since last readdir ( either lseek was called or dir
* changed ) ? We need to verify the position correctly points at the
* beginning of some dir entry so that the directory parsing code does
* not get confused . Since UDF does not have any reliable way of
* identifying beginning of dir entry ( names are under user control ) ,
* we need to scan the directory from the beginning .
*/
if ( ! inode_eq_iversion ( dir , file - > f_version ) ) {
emit_pos = nf_pos ;
nf_pos = 0 ;
} else {
pos_valid = true ;
}
2008-03-04 16:14:05 +03:00
fname = kmalloc ( UDF_NAME_LEN , GFP_NOFS ) ;
if ( ! fname ) {
ret = - ENOMEM ;
goto out ;
}
2005-04-17 02:20:36 +04:00
2022-10-04 16:00:15 +03:00
for ( ret = udf_fiiter_init ( & iter , dir , nf_pos ) ;
! ret & & iter . pos < dir - > i_size ;
ret = udf_fiiter_advance ( & iter ) ) {
2013-05-16 09:09:37 +04:00
struct kernel_lb_addr tloc ;
2022-10-04 16:00:15 +03:00
udf_pblk_t iblock ;
2013-05-16 09:09:37 +04:00
2021-11-04 17:22:35 +03:00
/* Still not at offset where user asked us to read from? */
2022-10-04 16:00:15 +03:00
if ( iter . pos < emit_pos )
2021-11-04 17:22:35 +03:00
continue ;
2005-04-17 02:20:36 +04:00
2022-10-04 16:00:15 +03:00
/* Update file position only if we got past the current one */
pos_valid = true ;
ctx - > pos = ( iter . pos > > 2 ) + 1 ;
2005-04-17 02:20:36 +04:00
2022-10-04 16:00:15 +03:00
if ( iter . fi . fileCharacteristics & FID_FILE_CHAR_DELETED ) {
2014-12-19 00:49:12 +03:00
if ( ! UDF_QUERY_FLAG ( sb , UDF_FLAG_UNDELETE ) )
2005-04-17 02:20:36 +04:00
continue ;
}
2007-07-19 12:47:43 +04:00
2022-10-04 16:00:15 +03:00
if ( iter . fi . fileCharacteristics & FID_FILE_CHAR_HIDDEN ) {
2014-12-19 00:49:12 +03:00
if ( ! UDF_QUERY_FLAG ( sb , UDF_FLAG_UNHIDE ) )
2005-04-17 02:20:36 +04:00
continue ;
}
2022-10-04 16:00:15 +03:00
if ( iter . fi . fileCharacteristics & FID_FILE_CHAR_PARENT ) {
2013-05-16 09:09:37 +04:00
if ( ! dir_emit_dotdot ( file , ctx ) )
2022-10-04 16:00:15 +03:00
goto out_iter ;
2013-05-16 09:09:37 +04:00
continue ;
2005-04-17 02:20:36 +04:00
}
2022-10-04 16:00:15 +03:00
flen = udf_get_filename ( sb , iter . name ,
iter . fi . lengthFileIdent , fname , UDF_NAME_LEN ) ;
2015-04-08 22:23:57 +03:00
if ( flen < 0 )
2013-05-16 09:09:37 +04:00
continue ;
2022-10-04 16:00:15 +03:00
tloc = lelb_to_cpu ( iter . fi . icb . extLocation ) ;
2014-12-19 00:49:12 +03:00
iblock = udf_get_lb_pblock ( sb , & tloc , 0 ) ;
2013-05-16 09:09:37 +04:00
if ( ! dir_emit ( ctx , fname , flen , iblock , DT_UNKNOWN ) )
2022-10-04 16:00:15 +03:00
goto out_iter ;
}
2005-04-17 02:20:36 +04:00
2022-10-04 16:00:15 +03:00
if ( ! ret ) {
ctx - > pos = ( iter . pos > > 2 ) + 1 ;
pos_valid = true ;
}
out_iter :
udf_fiiter_release ( & iter ) ;
2008-03-04 16:14:05 +03:00
out :
2021-11-04 17:22:35 +03:00
if ( pos_valid )
file - > f_version = inode_query_iversion ( dir ) ;
2008-03-04 16:14:05 +03:00
kfree ( fname ) ;
2005-04-17 02:20:36 +04:00
2008-03-04 16:14:05 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:47 +03:00
/* readdir and lookup functions */
const struct file_operations udf_dir_operations = {
2010-05-27 01:44:53 +04:00
. llseek = generic_file_llseek ,
2008-02-08 15:20:47 +03:00
. read = generic_read_dir ,
2016-05-01 05:37:34 +03:00
. iterate_shared = udf_readdir ,
2010-05-05 17:15:39 +04:00
. unlocked_ioctl = udf_ioctl ,
2010-05-26 19:53:41 +04:00
. fsync = generic_file_fsync ,
2008-02-08 15:20:47 +03:00
} ;