2005-04-16 15:20:36 -07:00
/*
* fs / cifs / readdir . c
*
* Directory search handling
2007-07-06 23:13:06 +00:00
*
2008-02-07 23:25:02 +00:00
* Copyright ( C ) International Business Machines Corp . , 2004 , 2008
2005-04-16 15:20:36 -07:00
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
*
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation ; either version 2.1 of the License , or
* ( at your option ) any later version .
*
* This library 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 Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/fs.h>
2006-06-01 19:41:23 +00:00
# include <linux/pagemap.h>
2005-04-16 15:20:36 -07:00
# include <linux/stat.h>
# include "cifspdu.h"
# include "cifsglob.h"
# include "cifsproto.h"
# include "cifs_unicode.h"
# include "cifs_debug.h"
# include "cifs_fs_sb.h"
# include "cifsfs.h"
2009-04-30 07:18:00 -04:00
/*
* To be safe - for UCS to UTF - 8 with strings loaded with the rare long
* characters alloc more to account for such multibyte target UTF - 8
* characters .
*/
# define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2)
2006-05-31 22:40:51 +00:00
# ifdef CONFIG_CIFS_DEBUG2
static void dump_cifs_file_struct ( struct file * file , char * label )
2005-04-16 15:20:36 -07:00
{
2007-07-06 23:13:06 +00:00
struct cifsFileInfo * cf ;
2005-04-16 15:20:36 -07:00
2007-04-30 20:13:06 +00:00
if ( file ) {
2005-04-16 15:20:36 -07:00
cf = file - > private_data ;
2007-04-30 20:13:06 +00:00
if ( cf = = NULL ) {
2007-07-06 23:13:06 +00:00
cFYI ( 1 , ( " empty cifs private file data " ) ) ;
2005-04-16 15:20:36 -07:00
return ;
}
2008-02-07 23:25:02 +00:00
if ( cf - > invalidHandle )
2007-07-06 23:13:06 +00:00
cFYI ( 1 , ( " invalid handle " ) ) ;
2008-02-07 23:25:02 +00:00
if ( cf - > srch_inf . endOfSearch )
2007-07-06 23:13:06 +00:00
cFYI ( 1 , ( " end of search " ) ) ;
2008-02-07 23:25:02 +00:00
if ( cf - > srch_inf . emptyDir )
2007-07-06 23:13:06 +00:00
cFYI ( 1 , ( " empty dir " ) ) ;
2005-04-16 15:20:36 -07:00
}
2006-05-31 22:40:51 +00:00
}
2008-02-12 20:32:36 +00:00
# else
static inline void dump_cifs_file_struct ( struct file * file , char * label )
{
}
2006-05-31 22:40:51 +00:00
# endif /* DEBUG2 */
2005-04-16 15:20:36 -07:00
2009-06-25 00:56:52 -04:00
/*
* Find the dentry that matches " name " . If there isn ' t one , create one . If it ' s
* a negative dentry or the uniqueid changed , then drop it and recreate it .
*/
static struct dentry *
cifs_readdir_lookup ( struct dentry * parent , struct qstr * name ,
struct cifs_fattr * fattr )
{
struct dentry * dentry , * alias ;
struct inode * inode ;
struct super_block * sb = parent - > d_inode - > i_sb ;
cFYI ( 1 , ( " For %s " , name - > name ) ) ;
dentry = d_lookup ( parent , name ) ;
if ( dentry ) {
/* FIXME: check for inode number changes? */
if ( dentry - > d_inode ! = NULL )
return dentry ;
d_drop ( dentry ) ;
dput ( dentry ) ;
}
dentry = d_alloc ( parent , name ) ;
if ( dentry = = NULL )
return NULL ;
inode = cifs_iget ( sb , fattr ) ;
if ( ! inode ) {
dput ( dentry ) ;
return NULL ;
}
if ( CIFS_SB ( sb ) - > tcon - > nocase )
dentry - > d_op = & cifs_ci_dentry_ops ;
else
dentry - > d_op = & cifs_dentry_ops ;
alias = d_materialise_unique ( dentry , inode ) ;
if ( alias ! = NULL ) {
dput ( dentry ) ;
if ( IS_ERR ( alias ) )
return NULL ;
dentry = alias ;
}
return dentry ;
}
2009-07-09 01:46:37 -04:00
static void
cifs_fill_common_info ( struct cifs_fattr * fattr , struct cifs_sb_info * cifs_sb )
2005-04-16 15:20:36 -07:00
{
2009-07-09 01:46:37 -04:00
fattr - > cf_uid = cifs_sb - > mnt_uid ;
fattr - > cf_gid = cifs_sb - > mnt_gid ;
2005-04-16 15:20:36 -07:00
2009-07-09 01:46:37 -04:00
if ( fattr - > cf_cifsattrs & ATTR_DIRECTORY ) {
fattr - > cf_mode = S_IFDIR | cifs_sb - > mnt_dir_mode ;
fattr - > cf_dtype = DT_DIR ;
2005-04-16 15:20:36 -07:00
} else {
2009-07-09 01:46:37 -04:00
fattr - > cf_mode = S_IFREG | cifs_sb - > mnt_file_mode ;
fattr - > cf_dtype = DT_REG ;
2005-04-16 15:20:36 -07:00
}
2009-07-09 01:46:37 -04:00
if ( fattr - > cf_cifsattrs & ATTR_READONLY )
fattr - > cf_mode & = ~ S_IWUGO ;
2006-06-07 00:18:43 +00:00
2009-07-09 01:46:37 -04:00
if ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL & &
fattr - > cf_cifsattrs & ATTR_SYSTEM ) {
if ( fattr - > cf_eof = = 0 ) {
fattr - > cf_mode & = ~ S_IFMT ;
fattr - > cf_mode | = S_IFIFO ;
fattr - > cf_dtype = DT_FIFO ;
2005-11-18 11:31:10 -08:00
} else {
2008-05-22 09:31:40 -04:00
/*
2009-07-09 01:46:37 -04:00
* trying to get the type and mode via SFU can be slow ,
* so just call those regular files for now , and mark
* for reval
2008-05-22 09:31:40 -04:00
*/
2009-07-09 01:46:37 -04:00
fattr - > cf_flags | = CIFS_FATTR_NEED_REVAL ;
2008-05-22 09:31:40 -04:00
}
}
2009-07-09 01:46:37 -04:00
}
2005-04-16 15:20:36 -07:00
2009-09-25 02:24:45 +00:00
static void
2009-07-09 01:46:37 -04:00
cifs_dir_info_to_fattr ( struct cifs_fattr * fattr , FILE_DIRECTORY_INFO * info ,
struct cifs_sb_info * cifs_sb )
{
memset ( fattr , 0 , sizeof ( * fattr ) ) ;
fattr - > cf_cifsattrs = le32_to_cpu ( info - > ExtFileAttributes ) ;
fattr - > cf_eof = le64_to_cpu ( info - > EndOfFile ) ;
fattr - > cf_bytes = le64_to_cpu ( info - > AllocationSize ) ;
fattr - > cf_atime = cifs_NTtimeToUnix ( info - > LastAccessTime ) ;
fattr - > cf_ctime = cifs_NTtimeToUnix ( info - > ChangeTime ) ;
fattr - > cf_mtime = cifs_NTtimeToUnix ( info - > LastWriteTime ) ;
cifs_fill_common_info ( fattr , cifs_sb ) ;
}
2005-04-16 15:20:36 -07:00
2009-09-25 02:24:45 +00:00
static void
2009-07-09 01:46:37 -04:00
cifs_std_info_to_fattr ( struct cifs_fattr * fattr , FIND_FILE_STANDARD_INFO * info ,
struct cifs_sb_info * cifs_sb )
{
int offset = cifs_sb - > tcon - > ses - > server - > timeAdj ;
2005-04-16 15:20:36 -07:00
2009-07-09 01:46:37 -04:00
memset ( fattr , 0 , sizeof ( * fattr ) ) ;
fattr - > cf_atime = cnvrtDosUnixTm ( info - > LastAccessDate ,
info - > LastAccessTime , offset ) ;
fattr - > cf_ctime = cnvrtDosUnixTm ( info - > LastWriteDate ,
info - > LastWriteTime , offset ) ;
fattr - > cf_mtime = cnvrtDosUnixTm ( info - > LastWriteDate ,
info - > LastWriteTime , offset ) ;
fattr - > cf_cifsattrs = le16_to_cpu ( info - > Attributes ) ;
fattr - > cf_bytes = le32_to_cpu ( info - > AllocationSize ) ;
fattr - > cf_eof = le32_to_cpu ( info - > DataSize ) ;
cifs_fill_common_info ( fattr , cifs_sb ) ;
2005-04-16 15:20:36 -07:00
}
2009-05-01 05:27:32 +00:00
/* BB eventually need to add the following helper function to
resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
we try to do FindFirst on ( NTFS ) directory symlinks */
/*
int get_symlink_reparse_path ( char * full_path , struct cifs_sb_info * cifs_sb ,
int xid )
{
__u16 fid ;
int len ;
int oplock = 0 ;
int rc ;
struct cifsTconInfo * ptcon = cifs_sb - > tcon ;
char * tmpbuffer ;
rc = CIFSSMBOpen ( xid , ptcon , full_path , FILE_OPEN , GENERIC_READ ,
OPEN_REPARSE_POINT , & fid , & oplock , NULL ,
cifs_sb - > local_nls ,
cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR ) ;
if ( ! rc ) {
tmpbuffer = kmalloc ( maxpath ) ;
rc = CIFSSMBQueryReparseLinkInfo ( xid , ptcon , full_path ,
tmpbuffer ,
maxpath - 1 ,
fid ,
cifs_sb - > local_nls ) ;
if ( CIFSSMBClose ( xid , ptcon , fid ) ) {
cFYI ( 1 , ( " Error closing temporary reparsepoint open) " ) ) ;
}
}
}
*/
2005-04-16 15:20:36 -07:00
static int initiate_cifs_search ( const int xid , struct file * file )
{
int rc = 0 ;
2007-07-08 15:40:40 +00:00
char * full_path ;
struct cifsFileInfo * cifsFile ;
2005-04-16 15:20:36 -07:00
struct cifs_sb_info * cifs_sb ;
struct cifsTconInfo * pTcon ;
2007-04-30 20:13:06 +00:00
if ( file - > private_data = = NULL ) {
2007-07-08 15:40:40 +00:00
file - > private_data =
kzalloc ( sizeof ( struct cifsFileInfo ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
}
2007-04-30 20:13:06 +00:00
if ( file - > private_data = = NULL )
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
cifsFile = file - > private_data ;
2008-04-29 00:06:05 +00:00
cifsFile - > invalidHandle = true ;
cifsFile - > srch_inf . endOfSearch = false ;
2005-04-16 15:20:36 -07:00
2006-12-08 02:36:48 -08:00
cifs_sb = CIFS_SB ( file - > f_path . dentry - > d_sb ) ;
2007-04-30 20:13:06 +00:00
if ( cifs_sb = = NULL )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
pTcon = cifs_sb - > tcon ;
2007-04-30 20:13:06 +00:00
if ( pTcon = = NULL )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2006-12-08 02:36:48 -08:00
full_path = build_path_from_dentry ( file - > f_path . dentry ) ;
2005-04-16 15:20:36 -07:00
2008-02-07 23:25:02 +00:00
if ( full_path = = NULL )
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
2005-04-28 22:41:08 -07:00
cFYI ( 1 , ( " Full path: %s start at: %lld " , full_path , file - > f_pos ) ) ;
2005-04-16 15:20:36 -07:00
2005-04-28 22:41:04 -07:00
ffirst_retry :
2005-04-16 15:20:36 -07:00
/* test for Unix extensions */
2007-07-18 23:21:09 +00:00
/* but now check for them on the share/mount not on the SMB session */
/* if (pTcon->ses->capabilities & CAP_UNIX) { */
2008-02-07 23:25:02 +00:00
if ( pTcon - > unix_ext )
2006-06-07 00:18:43 +00:00
cifsFile - > srch_inf . info_level = SMB_FIND_FILE_UNIX ;
2008-02-07 23:25:02 +00:00
else if ( ( pTcon - > ses - > capabilities &
2006-06-07 00:18:43 +00:00
( CAP_NT_SMBS | CAP_NT_FIND ) ) = = 0 ) {
cifsFile - > srch_inf . info_level = SMB_FIND_FILE_INFO_STANDARD ;
2005-04-16 15:20:36 -07:00
} else if ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM ) {
cifsFile - > srch_inf . info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO ;
} else /* not srvinos - BB fixme add check for backlevel? */ {
cifsFile - > srch_inf . info_level = SMB_FIND_FILE_DIRECTORY_INFO ;
}
2007-07-08 15:40:40 +00:00
rc = CIFSFindFirst ( xid , pTcon , full_path , cifs_sb - > local_nls ,
2005-04-28 22:41:06 -07:00
& cifsFile - > netfid , & cifsFile - > srch_inf ,
2007-07-08 15:40:40 +00:00
cifs_sb - > mnt_cifs_flags &
2005-09-15 21:47:30 -07:00
CIFS_MOUNT_MAP_SPECIAL_CHR , CIFS_DIR_SEP ( cifs_sb ) ) ;
2007-04-30 20:13:06 +00:00
if ( rc = = 0 )
2008-04-29 00:06:05 +00:00
cifsFile - > invalidHandle = false ;
2009-05-01 16:20:35 +00:00
/* BB add following call to handle readdir on new NTFS symlink errors
2009-05-01 05:27:32 +00:00
else if STATUS_STOPPED_ON_SYMLINK
call get_symlink_reparse_path and retry with new path */
else if ( ( rc = = - EOPNOTSUPP ) & &
2005-04-28 22:41:04 -07:00
( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM ) ) {
cifs_sb - > mnt_cifs_flags & = ~ CIFS_MOUNT_SERVER_INUM ;
goto ffirst_retry ;
}
2005-04-16 15:20:36 -07:00
kfree ( full_path ) ;
return rc ;
}
/* return length of unicode string in bytes */
static int cifs_unicode_bytelen ( char * str )
{
int len ;
2007-11-05 21:46:10 +00:00
__le16 * ustr = ( __le16 * ) str ;
2005-04-16 15:20:36 -07:00
2007-07-08 15:40:40 +00:00
for ( len = 0 ; len < = PATH_MAX ; len + + ) {
2007-04-30 20:13:06 +00:00
if ( ustr [ len ] = = 0 )
2005-04-16 15:20:36 -07:00
return len < < 1 ;
}
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " Unicode string longer than PATH_MAX found " ) ) ;
2005-04-16 15:20:36 -07:00
return len < < 1 ;
}
2006-06-07 00:18:43 +00:00
static char * nxt_dir_entry ( char * old_entry , char * end_of_smb , int level )
2005-04-16 15:20:36 -07:00
{
2007-07-08 15:40:40 +00:00
char * new_entry ;
2008-02-07 23:25:02 +00:00
FILE_DIRECTORY_INFO * pDirInfo = ( FILE_DIRECTORY_INFO * ) old_entry ;
2005-04-16 15:20:36 -07:00
2007-04-30 20:13:06 +00:00
if ( level = = SMB_FIND_FILE_INFO_STANDARD ) {
2008-02-07 23:25:02 +00:00
FIND_FILE_STANDARD_INFO * pfData ;
2006-06-07 00:18:43 +00:00
pfData = ( FIND_FILE_STANDARD_INFO * ) pDirInfo ;
new_entry = old_entry + sizeof ( FIND_FILE_STANDARD_INFO ) +
pfData - > FileNameLength ;
} else
new_entry = old_entry + le32_to_cpu ( pDirInfo - > NextEntryOffset ) ;
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " new entry %p old entry %p " , new_entry , old_entry ) ) ;
2005-04-16 15:20:36 -07:00
/* validate that new_entry is not past end of SMB */
2007-04-30 20:13:06 +00:00
if ( new_entry > = end_of_smb ) {
2005-04-28 22:41:08 -07:00
cERROR ( 1 ,
( " search entry %p began after end of SMB %p old entry %p " ,
2007-07-08 15:40:40 +00:00
new_entry , end_of_smb , old_entry ) ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
2007-04-30 20:13:06 +00:00
} else if ( ( ( level = = SMB_FIND_FILE_INFO_STANDARD ) & &
2007-07-08 15:40:40 +00:00
( new_entry + sizeof ( FIND_FILE_STANDARD_INFO ) > end_of_smb ) )
| | ( ( level ! = SMB_FIND_FILE_INFO_STANDARD ) & &
2006-06-07 00:18:43 +00:00
( new_entry + sizeof ( FILE_DIRECTORY_INFO ) > end_of_smb ) ) ) {
2007-07-08 15:40:40 +00:00
cERROR ( 1 , ( " search entry %p extends after end of SMB %p " ,
2005-04-28 22:41:08 -07:00
new_entry , end_of_smb ) ) ;
return NULL ;
2007-07-08 15:40:40 +00:00
} else
2005-04-16 15:20:36 -07:00
return new_entry ;
}
# define UNICODE_DOT cpu_to_le16(0x2e)
/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
static int cifs_entry_is_dot ( char * current_entry , struct cifsFileInfo * cfile )
{
int rc = 0 ;
2007-07-08 15:40:40 +00:00
char * filename = NULL ;
int len = 0 ;
2005-04-16 15:20:36 -07:00
2007-04-30 20:13:06 +00:00
if ( cfile - > srch_inf . info_level = = SMB_FIND_FILE_UNIX ) {
2008-02-07 23:25:02 +00:00
FILE_UNIX_INFO * pFindData = ( FILE_UNIX_INFO * ) current_entry ;
2005-04-16 15:20:36 -07:00
filename = & pFindData - > FileName [ 0 ] ;
2007-04-30 20:13:06 +00:00
if ( cfile - > srch_inf . unicode ) {
2005-04-16 15:20:36 -07:00
len = cifs_unicode_bytelen ( filename ) ;
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen ( filename , 5 ) ;
}
2007-04-30 20:13:06 +00:00
} else if ( cfile - > srch_inf . info_level = = SMB_FIND_FILE_DIRECTORY_INFO ) {
2008-02-07 23:25:02 +00:00
FILE_DIRECTORY_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( FILE_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2007-07-08 15:40:40 +00:00
} else if ( cfile - > srch_inf . info_level = =
2006-06-07 00:18:43 +00:00
SMB_FIND_FILE_FULL_DIRECTORY_INFO ) {
2008-02-07 23:25:02 +00:00
FILE_FULL_DIRECTORY_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( FILE_FULL_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2007-04-30 20:13:06 +00:00
} else if ( cfile - > srch_inf . info_level = =
2006-06-07 00:18:43 +00:00
SMB_FIND_FILE_ID_FULL_DIR_INFO ) {
2008-02-07 23:25:02 +00:00
SEARCH_ID_FULL_DIR_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( SEARCH_ID_FULL_DIR_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2007-07-08 15:40:40 +00:00
} else if ( cfile - > srch_inf . info_level = =
2006-06-07 00:18:43 +00:00
SMB_FIND_FILE_BOTH_DIRECTORY_INFO ) {
2008-02-07 23:25:02 +00:00
FILE_BOTH_DIRECTORY_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( FILE_BOTH_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2007-04-30 20:13:06 +00:00
} else if ( cfile - > srch_inf . info_level = = SMB_FIND_FILE_INFO_STANDARD ) {
2008-02-07 23:25:02 +00:00
FIND_FILE_STANDARD_INFO * pFindData =
2006-06-07 00:18:43 +00:00
( FIND_FILE_STANDARD_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
2006-08-15 13:35:48 +00:00
len = pFindData - > FileNameLength ;
2005-04-16 15:20:36 -07:00
} else {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " Unknown findfirst level %d " ,
cfile - > srch_inf . info_level ) ) ;
2005-04-16 15:20:36 -07:00
}
2007-04-30 20:13:06 +00:00
if ( filename ) {
if ( cfile - > srch_inf . unicode ) {
2005-04-16 15:20:36 -07:00
__le16 * ufilename = ( __le16 * ) filename ;
2007-04-30 20:13:06 +00:00
if ( len = = 2 ) {
2005-04-16 15:20:36 -07:00
/* check for . */
2007-04-30 20:13:06 +00:00
if ( ufilename [ 0 ] = = UNICODE_DOT )
2005-04-16 15:20:36 -07:00
rc = 1 ;
2007-04-30 20:13:06 +00:00
} else if ( len = = 4 ) {
2005-04-16 15:20:36 -07:00
/* check for .. */
2007-04-30 20:13:06 +00:00
if ( ( ufilename [ 0 ] = = UNICODE_DOT )
2007-07-08 15:40:40 +00:00
& & ( ufilename [ 1 ] = = UNICODE_DOT ) )
2005-04-16 15:20:36 -07:00
rc = 2 ;
}
} else /* ASCII */ {
2007-04-30 20:13:06 +00:00
if ( len = = 1 ) {
2007-07-08 15:40:40 +00:00
if ( filename [ 0 ] = = ' . ' )
2005-04-16 15:20:36 -07:00
rc = 1 ;
2007-04-30 20:13:06 +00:00
} else if ( len = = 2 ) {
2007-07-07 19:25:05 +00:00
if ( ( filename [ 0 ] = = ' . ' ) & & ( filename [ 1 ] = = ' . ' ) )
2005-04-16 15:20:36 -07:00
rc = 2 ;
}
}
}
return rc ;
}
2005-09-15 21:47:30 -07:00
/* Check if directory that we are searching has changed so we can decide
whether we can use the cached search results from the previous search */
2007-07-08 15:40:40 +00:00
static int is_dir_changed ( struct file * file )
2005-09-15 21:47:30 -07:00
{
2007-04-02 18:47:20 +00:00
struct inode * inode = file - > f_path . dentry - > d_inode ;
struct cifsInodeInfo * cifsInfo = CIFS_I ( inode ) ;
2005-09-15 21:47:30 -07:00
2007-04-02 18:47:20 +00:00
if ( cifsInfo - > time = = 0 )
2005-09-15 21:47:30 -07:00
return 1 ; /* directory was changed, perhaps due to unlink */
else
return 0 ;
}
2008-10-07 20:03:33 +00:00
static int cifs_save_resume_key ( const char * current_entry ,
struct cifsFileInfo * cifsFile )
{
int rc = 0 ;
unsigned int len = 0 ;
__u16 level ;
char * filename ;
if ( ( cifsFile = = NULL ) | | ( current_entry = = NULL ) )
return - EINVAL ;
level = cifsFile - > srch_inf . info_level ;
if ( level = = SMB_FIND_FILE_UNIX ) {
FILE_UNIX_INFO * pFindData = ( FILE_UNIX_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
if ( cifsFile - > srch_inf . unicode ) {
len = cifs_unicode_bytelen ( filename ) ;
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen ( filename , PATH_MAX ) ;
}
cifsFile - > srch_inf . resume_key = pFindData - > ResumeKey ;
} else if ( level = = SMB_FIND_FILE_DIRECTORY_INFO ) {
FILE_DIRECTORY_INFO * pFindData =
( FILE_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
cifsFile - > srch_inf . resume_key = pFindData - > FileIndex ;
} else if ( level = = SMB_FIND_FILE_FULL_DIRECTORY_INFO ) {
FILE_FULL_DIRECTORY_INFO * pFindData =
( FILE_FULL_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
cifsFile - > srch_inf . resume_key = pFindData - > FileIndex ;
} else if ( level = = SMB_FIND_FILE_ID_FULL_DIR_INFO ) {
SEARCH_ID_FULL_DIR_INFO * pFindData =
( SEARCH_ID_FULL_DIR_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
cifsFile - > srch_inf . resume_key = pFindData - > FileIndex ;
} else if ( level = = SMB_FIND_FILE_BOTH_DIRECTORY_INFO ) {
FILE_BOTH_DIRECTORY_INFO * pFindData =
( FILE_BOTH_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
cifsFile - > srch_inf . resume_key = pFindData - > FileIndex ;
} else if ( level = = SMB_FIND_FILE_INFO_STANDARD ) {
FIND_FILE_STANDARD_INFO * pFindData =
( FIND_FILE_STANDARD_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
/* one byte length, no name conversion */
len = ( unsigned int ) pFindData - > FileNameLength ;
cifsFile - > srch_inf . resume_key = pFindData - > ResumeKey ;
} else {
cFYI ( 1 , ( " Unknown findfirst level %d " , level ) ) ;
return - EINVAL ;
}
cifsFile - > srch_inf . resume_name_len = len ;
cifsFile - > srch_inf . presume_name = filename ;
return rc ;
}
2005-04-16 15:20:36 -07:00
/* find the corresponding entry in the search */
/* Note that the SMB server returns search entries for . and .. which
complicates logic here if we choose to parse for them and we do not
assume that they are located in the findfirst return buffer . */
/* We start counting in the buffer with entry 2 and increment for every
entry ( do not increment for . or . . entry ) */
static int find_cifs_entry ( const int xid , struct cifsTconInfo * pTcon ,
2007-07-08 15:40:40 +00:00
struct file * file , char * * ppCurrentEntry , int * num_to_ret )
2005-04-16 15:20:36 -07:00
{
int rc = 0 ;
int pos_in_buf = 0 ;
loff_t first_entry_in_buffer ;
loff_t index_to_find = file - > f_pos ;
2007-07-08 15:40:40 +00:00
struct cifsFileInfo * cifsFile = file - > private_data ;
2005-04-16 15:20:36 -07:00
/* check if index in the buffer */
2007-07-13 00:33:32 +00:00
2007-07-08 15:40:40 +00:00
if ( ( cifsFile = = NULL ) | | ( ppCurrentEntry = = NULL ) | |
2005-09-15 21:47:30 -07:00
( num_to_ret = = NULL ) )
2005-04-16 15:20:36 -07:00
return - ENOENT ;
2007-07-13 00:33:32 +00:00
2005-04-16 15:20:36 -07:00
* ppCurrentEntry = NULL ;
2007-07-08 15:40:40 +00:00
first_entry_in_buffer =
cifsFile - > srch_inf . index_of_last_entry -
2005-04-16 15:20:36 -07:00
cifsFile - > srch_inf . entries_in_buffer ;
2006-04-22 15:53:05 +00:00
/* if first entry in buf is zero then is first buffer
in search response data which means it is likely . and . .
will be in this buffer , although some servers do not return
. and . . for the root of a drive and for those we need
to start two entries earlier */
2006-05-31 22:40:51 +00:00
dump_cifs_file_struct ( file , " In fce " ) ;
2007-07-08 15:40:40 +00:00
if ( ( ( index_to_find < cifsFile - > srch_inf . index_of_last_entry ) & &
is_dir_changed ( file ) ) | |
2005-09-15 21:47:30 -07:00
( index_to_find < first_entry_in_buffer ) ) {
2005-04-16 15:20:36 -07:00
/* close and restart search */
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " search backing up - close and restart search " ) ) ;
2008-11-20 20:00:44 +00:00
write_lock ( & GlobalSMBSeslock ) ;
2008-05-13 21:39:32 +00:00
if ( ! cifsFile - > srch_inf . endOfSearch & &
! cifsFile - > invalidHandle ) {
cifsFile - > invalidHandle = true ;
2008-11-20 20:00:44 +00:00
write_unlock ( & GlobalSMBSeslock ) ;
2008-05-13 21:39:32 +00:00
CIFSFindClose ( xid , pTcon , cifsFile - > netfid ) ;
2008-11-20 20:00:44 +00:00
} else
write_unlock ( & GlobalSMBSeslock ) ;
2007-04-30 20:13:06 +00:00
if ( cifsFile - > srch_inf . ntwrk_buf_start ) {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " freeing SMB ff cache buf on search rewind " ) ) ;
2007-04-30 20:13:06 +00:00
if ( cifsFile - > srch_inf . smallBuf )
2006-02-28 03:45:48 +00:00
cifs_small_buf_release ( cifsFile - > srch_inf .
ntwrk_buf_start ) ;
else
cifs_buf_release ( cifsFile - > srch_inf .
ntwrk_buf_start ) ;
2008-07-24 14:48:33 +00:00
cifsFile - > srch_inf . ntwrk_buf_start = NULL ;
2005-04-16 15:20:36 -07:00
}
2007-07-08 15:40:40 +00:00
rc = initiate_cifs_search ( xid , file ) ;
2007-04-30 20:13:06 +00:00
if ( rc ) {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " error %d reinitiating a search on rewind " ,
rc ) ) ;
2005-04-16 15:20:36 -07:00
return rc ;
}
2008-10-21 14:42:13 +00:00
cifs_save_resume_key ( cifsFile - > srch_inf . last_entry , cifsFile ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-08 15:40:40 +00:00
while ( ( index_to_find > = cifsFile - > srch_inf . index_of_last_entry ) & &
2008-04-29 00:06:05 +00:00
( rc = = 0 ) & & ! cifsFile - > srch_inf . endOfSearch ) {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " calling findnext2 " ) ) ;
2007-07-08 15:40:40 +00:00
rc = CIFSFindNext ( xid , pTcon , cifsFile - > netfid ,
2005-06-22 17:13:47 -07:00
& cifsFile - > srch_inf ) ;
2008-10-21 14:42:13 +00:00
cifs_save_resume_key ( cifsFile - > srch_inf . last_entry , cifsFile ) ;
2007-04-30 20:13:06 +00:00
if ( rc )
2005-04-16 15:20:36 -07:00
return - ENOENT ;
}
2007-04-30 20:13:06 +00:00
if ( index_to_find < cifsFile - > srch_inf . index_of_last_entry ) {
2005-04-16 15:20:36 -07:00
/* we found the buffer that contains the entry */
/* scan and find it */
int i ;
2007-07-08 15:40:40 +00:00
char * current_entry ;
char * end_of_smb = cifsFile - > srch_inf . ntwrk_buf_start +
2005-04-16 15:20:36 -07:00
smbCalcSize ( ( struct smb_hdr * )
cifsFile - > srch_inf . ntwrk_buf_start ) ;
2006-04-22 15:53:05 +00:00
current_entry = cifsFile - > srch_inf . srch_entries_start ;
2005-04-16 15:20:36 -07:00
first_entry_in_buffer = cifsFile - > srch_inf . index_of_last_entry
- cifsFile - > srch_inf . entries_in_buffer ;
pos_in_buf = index_to_find - first_entry_in_buffer ;
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " found entry - pos_in_buf %d " , pos_in_buf ) ) ;
2006-06-07 00:18:43 +00:00
2008-02-07 23:25:02 +00:00
for ( i = 0 ; ( i < ( pos_in_buf ) ) & & ( current_entry ! = NULL ) ; i + + ) {
2005-06-22 17:13:47 -07:00
/* go entry by entry figuring out which is first */
2007-07-08 15:40:40 +00:00
current_entry = nxt_dir_entry ( current_entry , end_of_smb ,
2006-06-07 00:18:43 +00:00
cifsFile - > srch_inf . info_level ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-07 19:25:05 +00:00
if ( ( current_entry = = NULL ) & & ( i < pos_in_buf ) ) {
2005-04-16 15:20:36 -07:00
/* BB fixme - check if we should flag this error */
2007-07-08 15:40:40 +00:00
cERROR ( 1 , ( " reached end of buf searching for pos in buf "
2005-04-16 15:20:36 -07:00
" %d index to find %lld rc %d " ,
2007-07-08 15:40:40 +00:00
pos_in_buf , index_to_find , rc ) ) ;
2005-04-16 15:20:36 -07:00
}
rc = 0 ;
* ppCurrentEntry = current_entry ;
} else {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " index not in buffer - could not findnext into it " ) ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-07 19:25:05 +00:00
if ( pos_in_buf > = cifsFile - > srch_inf . entries_in_buffer ) {
cFYI ( 1 , ( " can not return entries pos_in_buf beyond last " ) ) ;
2005-04-16 15:20:36 -07:00
* num_to_ret = 0 ;
} else
* num_to_ret = cifsFile - > srch_inf . entries_in_buffer - pos_in_buf ;
return rc ;
}
/* inode num, inode type and filename returned */
static int cifs_get_name_from_search_buf ( struct qstr * pqst ,
char * current_entry , __u16 level , unsigned int unicode ,
2009-04-30 20:45:45 -04:00
struct cifs_sb_info * cifs_sb , unsigned int max_len , __u64 * pinum )
2005-04-16 15:20:36 -07:00
{
int rc = 0 ;
unsigned int len = 0 ;
2007-07-08 15:40:40 +00:00
char * filename ;
struct nls_table * nlt = cifs_sb - > local_nls ;
2005-04-16 15:20:36 -07:00
* pinum = 0 ;
2007-07-07 19:25:05 +00:00
if ( level = = SMB_FIND_FILE_UNIX ) {
2007-07-08 15:40:40 +00:00
FILE_UNIX_INFO * pFindData = ( FILE_UNIX_INFO * ) current_entry ;
2005-04-16 15:20:36 -07:00
filename = & pFindData - > FileName [ 0 ] ;
2007-07-07 19:25:05 +00:00
if ( unicode ) {
2005-04-16 15:20:36 -07:00
len = cifs_unicode_bytelen ( filename ) ;
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen ( filename , PATH_MAX ) ;
}
2009-06-25 00:56:52 -04:00
* pinum = le64_to_cpu ( pFindData - > basic . UniqueId ) ;
2007-07-07 19:25:05 +00:00
} else if ( level = = SMB_FIND_FILE_DIRECTORY_INFO ) {
2007-07-08 15:40:40 +00:00
FILE_DIRECTORY_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( FILE_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2007-07-07 19:25:05 +00:00
} else if ( level = = SMB_FIND_FILE_FULL_DIRECTORY_INFO ) {
2007-07-08 15:40:40 +00:00
FILE_FULL_DIRECTORY_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( FILE_FULL_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2007-07-07 19:25:05 +00:00
} else if ( level = = SMB_FIND_FILE_ID_FULL_DIR_INFO ) {
2007-07-08 15:40:40 +00:00
SEARCH_ID_FULL_DIR_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( SEARCH_ID_FULL_DIR_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2009-04-01 05:22:00 +00:00
* pinum = le64_to_cpu ( pFindData - > UniqueId ) ;
2007-07-07 19:25:05 +00:00
} else if ( level = = SMB_FIND_FILE_BOTH_DIRECTORY_INFO ) {
2007-07-08 15:40:40 +00:00
FILE_BOTH_DIRECTORY_INFO * pFindData =
2005-04-16 15:20:36 -07:00
( FILE_BOTH_DIRECTORY_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
len = le32_to_cpu ( pFindData - > FileNameLength ) ;
2007-07-07 19:25:05 +00:00
} else if ( level = = SMB_FIND_FILE_INFO_STANDARD ) {
2008-02-07 23:25:02 +00:00
FIND_FILE_STANDARD_INFO * pFindData =
2006-06-07 00:18:43 +00:00
( FIND_FILE_STANDARD_INFO * ) current_entry ;
filename = & pFindData - > FileName [ 0 ] ;
/* one byte length, no name conversion */
len = ( unsigned int ) pFindData - > FileNameLength ;
2005-04-16 15:20:36 -07:00
} else {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " Unknown findfirst level %d " , level ) ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
2006-06-07 00:18:43 +00:00
2007-07-07 19:25:05 +00:00
if ( len > max_len ) {
2007-07-08 15:40:40 +00:00
cERROR ( 1 , ( " bad search response length %d past smb end " , len ) ) ;
2006-06-07 00:18:43 +00:00
return - EINVAL ;
}
2007-07-07 19:25:05 +00:00
if ( unicode ) {
2009-04-30 07:18:00 -04:00
pqst - > len = cifs_from_ucs2 ( ( char * ) pqst - > name ,
( __le16 * ) filename ,
2009-04-30 20:45:45 -04:00
UNICODE_NAME_MAX ,
min ( len , max_len ) , nlt ,
2009-04-30 07:18:00 -04:00
cifs_sb - > mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR ) ;
2005-04-16 15:20:36 -07:00
} else {
pqst - > name = filename ;
pqst - > len = len ;
}
2007-07-08 15:40:40 +00:00
pqst - > hash = full_name_hash ( pqst - > name , pqst - > len ) ;
2007-07-07 19:25:05 +00:00
/* cFYI(1, ("filldir on %s",pqst->name)); */
2005-04-16 15:20:36 -07:00
return rc ;
}
2009-04-30 20:45:45 -04:00
static int cifs_filldir ( char * pfindEntry , struct file * file , filldir_t filldir ,
void * direntry , char * scratch_buf , unsigned int max_len )
2005-04-16 15:20:36 -07:00
{
int rc = 0 ;
struct qstr qstring ;
2007-07-08 15:40:40 +00:00
struct cifsFileInfo * pCifsF ;
2009-07-09 01:46:37 -04:00
u64 inum ;
2009-06-25 00:56:52 -04:00
ino_t ino ;
2009-07-09 01:46:37 -04:00
struct super_block * sb ;
2007-07-08 15:40:40 +00:00
struct cifs_sb_info * cifs_sb ;
2005-04-16 15:20:36 -07:00
struct dentry * tmp_dentry ;
2009-06-25 00:56:52 -04:00
struct cifs_fattr fattr ;
2005-04-16 15:20:36 -07:00
/* get filename and len into qstring */
/* get dentry */
/* decide whether to create and populate ionde */
2007-07-07 19:25:05 +00:00
if ( ( direntry = = NULL ) | | ( file = = NULL ) )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
pCifsF = file - > private_data ;
2007-07-13 00:33:32 +00:00
2007-07-07 19:25:05 +00:00
if ( ( scratch_buf = = NULL ) | | ( pfindEntry = = NULL ) | | ( pCifsF = = NULL ) )
2005-04-16 15:20:36 -07:00
return - ENOENT ;
2007-07-08 15:40:40 +00:00
rc = cifs_entry_is_dot ( pfindEntry , pCifsF ) ;
2006-04-22 15:53:05 +00:00
/* skip . and .. since we added them first */
2007-07-07 19:25:05 +00:00
if ( rc ! = 0 )
2006-04-22 15:53:05 +00:00
return 0 ;
2009-07-09 01:46:37 -04:00
sb = file - > f_path . dentry - > d_sb ;
cifs_sb = CIFS_SB ( sb ) ;
2005-04-16 15:20:36 -07:00
qstring . name = scratch_buf ;
2007-07-08 15:40:40 +00:00
rc = cifs_get_name_from_search_buf ( & qstring , pfindEntry ,
2005-04-16 15:20:36 -07:00
pCifsF - > srch_inf . info_level ,
2007-07-08 15:40:40 +00:00
pCifsF - > srch_inf . unicode , cifs_sb ,
2009-07-09 01:46:37 -04:00
max_len , & inum /* returned */ ) ;
2005-04-16 15:20:36 -07:00
2007-07-07 19:25:05 +00:00
if ( rc )
2005-04-16 15:20:36 -07:00
return rc ;
2009-07-09 01:46:37 -04:00
if ( pCifsF - > srch_inf . info_level = = SMB_FIND_FILE_UNIX )
2009-06-25 00:56:52 -04:00
cifs_unix_basic_to_fattr ( & fattr ,
& ( ( FILE_UNIX_INFO * ) pfindEntry ) - > basic ,
cifs_sb ) ;
2009-07-09 01:46:37 -04:00
else if ( pCifsF - > srch_inf . info_level = = SMB_FIND_FILE_INFO_STANDARD )
cifs_std_info_to_fattr ( & fattr , ( FIND_FILE_STANDARD_INFO * )
pfindEntry , cifs_sb ) ;
else
cifs_dir_info_to_fattr ( & fattr , ( FILE_DIRECTORY_INFO * )
pfindEntry , cifs_sb ) ;
2006-09-06 22:02:22 +00:00
2009-11-06 14:18:29 -05:00
if ( inum & & ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM ) ) {
2009-07-09 01:46:37 -04:00
fattr . cf_uniqueid = inum ;
2009-11-06 14:18:29 -05:00
} else {
2009-07-09 01:46:37 -04:00
fattr . cf_uniqueid = iunique ( sb , ROOT_I ) ;
2009-11-06 14:18:29 -05:00
cifs_autodisable_serverino ( cifs_sb ) ;
}
2007-07-13 00:33:32 +00:00
2009-07-09 01:46:37 -04:00
ino = cifs_uniqueid_to_ino_t ( fattr . cf_uniqueid ) ;
tmp_dentry = cifs_readdir_lookup ( file - > f_dentry , & qstring , & fattr ) ;
2007-07-08 15:40:40 +00:00
rc = filldir ( direntry , qstring . name , qstring . len , file - > f_pos ,
2009-07-09 01:46:37 -04:00
ino , fattr . cf_dtype ) ;
/*
* we can not return filldir errors to the caller since they are
* " normal " when the stat blocksize is too small - we return remapped
* error instead
*
* FIXME : This looks bogus . filldir returns - EOVERFLOW in the above
* case already . Why should we be clobbering other errors from it ?
*/
2007-07-07 19:25:05 +00:00
if ( rc ) {
cFYI ( 1 , ( " filldir rc = %d " , rc ) ) ;
2006-10-30 21:42:57 +00:00
rc = - EOVERFLOW ;
2005-04-16 15:20:36 -07:00
}
dput ( tmp_dentry ) ;
return rc ;
}
int cifs_readdir ( struct file * file , void * direntry , filldir_t filldir )
{
int rc = 0 ;
2007-07-08 15:40:40 +00:00
int xid , i ;
2005-04-16 15:20:36 -07:00
struct cifs_sb_info * cifs_sb ;
struct cifsTconInfo * pTcon ;
struct cifsFileInfo * cifsFile = NULL ;
2007-07-08 15:40:40 +00:00
char * current_entry ;
2005-04-16 15:20:36 -07:00
int num_to_fill = 0 ;
2007-07-08 15:40:40 +00:00
char * tmp_buf = NULL ;
2007-07-13 00:33:32 +00:00
char * end_of_smb ;
2009-04-30 20:45:45 -04:00
unsigned int max_len ;
2005-04-16 15:20:36 -07:00
xid = GetXid ( ) ;
2006-12-08 02:36:48 -08:00
cifs_sb = CIFS_SB ( file - > f_path . dentry - > d_sb ) ;
2005-04-16 15:20:36 -07:00
pTcon = cifs_sb - > tcon ;
2007-07-07 19:25:05 +00:00
if ( pTcon = = NULL )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
switch ( ( int ) file - > f_pos ) {
case 0 :
2006-04-22 15:53:05 +00:00
if ( filldir ( direntry , " . " , 1 , file - > f_pos ,
2006-12-08 02:36:48 -08:00
file - > f_path . dentry - > d_inode - > i_ino , DT_DIR ) < 0 ) {
2006-04-22 15:53:05 +00:00
cERROR ( 1 , ( " Filldir for current dir failed " ) ) ;
2005-04-16 15:20:36 -07:00
rc = - ENOMEM ;
break ;
}
2006-04-22 15:53:05 +00:00
file - > f_pos + + ;
2005-04-16 15:20:36 -07:00
case 1 :
2006-04-22 15:53:05 +00:00
if ( filldir ( direntry , " .. " , 2 , file - > f_pos ,
2006-12-08 02:36:48 -08:00
file - > f_path . dentry - > d_parent - > d_inode - > i_ino , DT_DIR ) < 0 ) {
2006-05-31 18:05:34 +00:00
cERROR ( 1 , ( " Filldir for parent dir failed " ) ) ;
2005-04-16 15:20:36 -07:00
rc = - ENOMEM ;
break ;
}
2006-04-22 15:53:05 +00:00
file - > f_pos + + ;
default :
2007-07-08 15:40:40 +00:00
/* 1) If search is active,
is in current search buffer ?
2005-04-16 15:20:36 -07:00
if it before then restart search
if after then keep searching till find it */
2007-07-07 19:25:05 +00:00
if ( file - > private_data = = NULL ) {
2007-07-08 15:40:40 +00:00
rc = initiate_cifs_search ( xid , file ) ;
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " initiate cifs search rc %d " , rc ) ) ;
if ( rc ) {
2005-04-16 15:20:36 -07:00
FreeXid ( xid ) ;
return rc ;
}
}
2007-07-07 19:25:05 +00:00
if ( file - > private_data = = NULL ) {
2005-04-16 15:20:36 -07:00
rc = - EINVAL ;
FreeXid ( xid ) ;
return rc ;
}
cifsFile = file - > private_data ;
if ( cifsFile - > srch_inf . endOfSearch ) {
2007-07-07 19:25:05 +00:00
if ( cifsFile - > srch_inf . emptyDir ) {
2005-04-16 15:20:36 -07:00
cFYI ( 1 , ( " End of search, empty dir " ) ) ;
rc = 0 ;
break ;
}
} /* else {
2008-04-29 00:06:05 +00:00
cifsFile - > invalidHandle = true ;
2005-04-16 15:20:36 -07:00
CIFSFindClose ( xid , pTcon , cifsFile - > netfid ) ;
2008-05-23 17:38:32 +00:00
} */
2005-04-16 15:20:36 -07:00
2007-07-08 15:40:40 +00:00
rc = find_cifs_entry ( xid , pTcon , file ,
& current_entry , & num_to_fill ) ;
2007-07-07 19:25:05 +00:00
if ( rc ) {
cFYI ( 1 , ( " fce error %d " , rc ) ) ;
2005-04-16 15:20:36 -07:00
goto rddir2_exit ;
} else if ( current_entry ! = NULL ) {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " entry %lld found " , file - > f_pos ) ) ;
2005-04-16 15:20:36 -07:00
} else {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " could not find entry " ) ) ;
2005-04-16 15:20:36 -07:00
goto rddir2_exit ;
}
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " loop through %d times filling dir for net buf %p " ,
num_to_fill , cifsFile - > srch_inf . ntwrk_buf_start ) ) ;
2006-06-07 00:18:43 +00:00
max_len = smbCalcSize ( ( struct smb_hdr * )
cifsFile - > srch_inf . ntwrk_buf_start ) ;
end_of_smb = cifsFile - > srch_inf . ntwrk_buf_start + max_len ;
2009-04-30 07:18:00 -04:00
tmp_buf = kmalloc ( UNICODE_NAME_MAX , GFP_KERNEL ) ;
2007-07-07 19:25:05 +00:00
for ( i = 0 ; ( i < num_to_fill ) & & ( rc = = 0 ) ; i + + ) {
if ( current_entry = = NULL ) {
2005-04-16 15:20:36 -07:00
/* evaluate whether this case is an error */
2007-08-30 22:09:15 +00:00
cERROR ( 1 , ( " past SMB end, num to fill %d i %d " ,
2005-04-16 15:20:36 -07:00
num_to_fill , i ) ) ;
break ;
}
2006-04-22 15:53:05 +00:00
/* if buggy server returns . and .. late do
we want to check for that here ? */
2006-06-07 00:18:43 +00:00
rc = cifs_filldir ( current_entry , file ,
filldir , direntry , tmp_buf , max_len ) ;
2007-07-07 19:25:05 +00:00
if ( rc = = - EOVERFLOW ) {
2006-10-30 21:42:57 +00:00
rc = 0 ;
break ;
}
2005-04-16 15:20:36 -07:00
file - > f_pos + + ;
2007-07-07 19:25:05 +00:00
if ( file - > f_pos = =
2006-05-31 22:40:51 +00:00
cifsFile - > srch_inf . index_of_last_entry ) {
2007-07-07 19:25:05 +00:00
cFYI ( 1 , ( " last entry in buf at pos %lld %s " ,
file - > f_pos , tmp_buf ) ) ;
cifs_save_resume_key ( current_entry , cifsFile ) ;
2005-04-16 15:20:36 -07:00
break ;
2007-07-07 19:25:05 +00:00
} else
current_entry =
2006-06-07 00:18:43 +00:00
nxt_dir_entry ( current_entry , end_of_smb ,
cifsFile - > srch_inf . info_level ) ;
2005-04-16 15:20:36 -07:00
}
kfree ( tmp_buf ) ;
break ;
} /* end switch */
rddir2_exit :
FreeXid ( xid ) ;
return rc ;
}