2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
client directory list routines
Copyright ( C ) Andrew Tridgell 1994 - 2003
Copyright ( C ) James Myers 2003 < myersjj @ samba . org >
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2006-01-03 18:40:05 +03:00
# include "libcli/libcli.h"
2004-11-01 04:03:22 +03:00
# include "libcli/raw/libcliraw.h"
2003-08-13 05:53:07 +04:00
struct search_private {
2004-11-30 08:37:57 +03:00
struct clilist_file_info * dirlist ;
2003-08-13 05:53:07 +04:00
TALLOC_CTX * mem_ctx ;
int dirlist_len ;
int ff_searchcount ; /* total received in 1 server trip */
int total_received ; /* total received all together */
2006-07-06 12:00:24 +04:00
enum smb_search_data_level data_level ;
2004-08-02 11:40:55 +04:00
const char * last_name ; /* used to continue trans2 search */
2004-09-21 12:46:47 +04:00
struct smb_search_id id ; /* used for old-style search */
2003-08-13 05:53:07 +04:00
} ;
/****************************************************************************
Interpret a long filename structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-06 12:00:24 +04:00
static BOOL interpret_long_filename ( enum smb_search_data_level level ,
2007-05-01 06:08:11 +04:00
const union smb_search_data * info ,
2004-11-30 08:37:57 +03:00
struct clilist_file_info * finfo )
2003-08-13 05:53:07 +04:00
{
2004-11-30 08:37:57 +03:00
struct clilist_file_info finfo2 ;
2003-08-13 05:53:07 +04:00
if ( ! finfo ) finfo = & finfo2 ;
ZERO_STRUCTP ( finfo ) ;
2004-08-02 11:40:55 +04:00
switch ( level ) {
2006-07-06 12:00:24 +04:00
case RAW_SEARCH_DATA_STANDARD :
2004-08-02 11:40:55 +04:00
finfo - > size = info - > standard . size ;
finfo - > mtime = info - > standard . write_time ;
2004-11-30 08:37:57 +03:00
finfo - > attrib = info - > standard . attrib ;
2004-08-02 11:40:55 +04:00
finfo - > name = info - > standard . name . s ;
2004-11-30 08:37:57 +03:00
finfo - > short_name = info - > standard . name . s ;
2004-08-02 11:40:55 +04:00
break ;
2006-07-06 12:00:24 +04:00
case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO :
2004-08-02 11:40:55 +04:00
finfo - > size = info - > both_directory_info . size ;
finfo - > mtime = nt_time_to_unix ( info - > both_directory_info . write_time ) ;
2004-11-30 08:37:57 +03:00
finfo - > attrib = info - > both_directory_info . attrib ;
finfo - > short_name = info - > both_directory_info . short_name . s ;
2004-08-02 11:40:55 +04:00
finfo - > name = info - > both_directory_info . name . s ;
break ;
default :
DEBUG ( 0 , ( " Unhandled level %d in interpret_long_filename \n " , ( int ) level ) ) ;
return False ;
2003-08-13 05:53:07 +04:00
}
2004-08-02 11:40:55 +04:00
2003-08-13 05:53:07 +04:00
return True ;
}
/* callback function used for trans2 search */
2007-05-01 06:08:11 +04:00
static BOOL smbcli_list_new_callback ( void * private , const union smb_search_data * file )
2003-08-13 05:53:07 +04:00
{
struct search_private * state = ( struct search_private * ) private ;
2004-11-30 08:37:57 +03:00
struct clilist_file_info * tdl ;
2003-08-13 05:53:07 +04:00
/* add file info to the dirlist pool */
2004-09-27 05:36:19 +04:00
tdl = talloc_realloc ( state ,
state - > dirlist ,
2005-01-07 07:39:16 +03:00
struct clilist_file_info ,
state - > dirlist_len + 1 ) ;
2003-08-13 05:53:07 +04:00
if ( ! tdl ) {
return False ;
}
state - > dirlist = tdl ;
2005-01-07 07:39:16 +03:00
state - > dirlist_len + + ;
2003-08-13 05:53:07 +04:00
2006-07-06 12:00:24 +04:00
interpret_long_filename ( state - > data_level , file , & state - > dirlist [ state - > total_received ] ) ;
2003-08-13 05:53:07 +04:00
2004-08-02 11:40:55 +04:00
state - > last_name = state - > dirlist [ state - > total_received ] . name ;
2003-08-13 05:53:07 +04:00
state - > total_received + + ;
state - > ff_searchcount + + ;
return True ;
}
2004-08-04 17:23:35 +04:00
int smbcli_list_new ( struct smbcli_tree * tree , const char * Mask , uint16_t attribute ,
2006-07-06 12:00:24 +04:00
enum smb_search_data_level level ,
2004-11-30 08:37:57 +03:00
void ( * fn ) ( struct clilist_file_info * , const char * , void * ) ,
2004-10-02 16:30:02 +04:00
void * caller_state )
2003-08-13 05:53:07 +04:00
{
union smb_search_first first_parms ;
union smb_search_next next_parms ;
struct search_private state ; /* for callbacks */
int received = 0 ;
BOOL first = True ;
int num_received = 0 ;
int max_matches = 512 ;
char * mask ;
int ff_eos = 0 , i , ff_searchcount ;
int ff_dir_handle = 0 ;
/* initialize state for search */
2004-08-04 17:23:35 +04:00
state . mem_ctx = talloc_init ( " smbcli_list_new " ) ;
2003-08-13 05:53:07 +04:00
state . dirlist_len = 0 ;
state . total_received = 0 ;
2007-09-08 17:27:14 +04:00
state . dirlist = talloc_array ( state . mem_ctx ,
struct clilist_file_info , 0 ) ;
2003-08-13 05:53:07 +04:00
mask = talloc_strdup ( state . mem_ctx , Mask ) ;
2006-07-06 12:00:24 +04:00
if ( level = = RAW_SEARCH_DATA_GENERIC ) {
2004-10-02 16:30:02 +04:00
if ( tree - > session - > transport - > negotiate . capabilities & CAP_NT_SMBS ) {
2006-07-06 12:00:24 +04:00
level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO ;
2004-10-02 16:30:02 +04:00
} else {
2006-07-06 12:00:24 +04:00
level = RAW_SEARCH_DATA_STANDARD ;
2004-10-02 16:30:02 +04:00
}
2003-08-13 05:53:07 +04:00
}
2006-07-06 12:00:24 +04:00
state . data_level = level ;
2003-08-13 05:53:07 +04:00
while ( 1 ) {
state . ff_searchcount = 0 ;
if ( first ) {
NTSTATUS status ;
2006-07-06 12:00:24 +04:00
first_parms . t2ffirst . level = RAW_SEARCH_TRANS2 ;
first_parms . t2ffirst . data_level = state . data_level ;
2003-08-13 05:53:07 +04:00
first_parms . t2ffirst . in . max_count = max_matches ;
first_parms . t2ffirst . in . search_attrib = attribute ;
first_parms . t2ffirst . in . pattern = mask ;
first_parms . t2ffirst . in . flags = FLAG_TRANS2_FIND_CLOSE_IF_END ;
first_parms . t2ffirst . in . storage_type = 0 ;
2004-02-08 03:51:07 +03:00
status = smb_raw_search_first ( tree ,
2003-08-13 05:53:07 +04:00
state . mem_ctx , & first_parms ,
2004-08-04 17:23:35 +04:00
( void * ) & state , smbcli_list_new_callback ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-01-27 10:08:20 +03:00
talloc_free ( state . mem_ctx ) ;
2003-08-13 05:53:07 +04:00
return - 1 ;
}
ff_dir_handle = first_parms . t2ffirst . out . handle ;
ff_searchcount = first_parms . t2ffirst . out . count ;
ff_eos = first_parms . t2ffirst . out . end_of_search ;
received = first_parms . t2ffirst . out . count ;
if ( received < = 0 ) break ;
if ( ff_eos ) break ;
first = False ;
} else {
NTSTATUS status ;
2006-07-06 12:00:24 +04:00
next_parms . t2fnext . level = RAW_SEARCH_TRANS2 ;
next_parms . t2fnext . data_level = state . data_level ;
2003-08-13 05:53:07 +04:00
next_parms . t2fnext . in . max_count = max_matches ;
2004-08-02 11:40:55 +04:00
next_parms . t2fnext . in . last_name = state . last_name ;
2003-08-13 05:53:07 +04:00
next_parms . t2fnext . in . handle = ff_dir_handle ;
next_parms . t2fnext . in . resume_key = 0 ;
2004-08-02 11:40:55 +04:00
next_parms . t2fnext . in . flags = FLAG_TRANS2_FIND_CLOSE_IF_END ;
2003-08-13 05:53:07 +04:00
2004-02-08 03:51:07 +03:00
status = smb_raw_search_next ( tree ,
2003-08-13 05:53:07 +04:00
state . mem_ctx ,
& next_parms ,
( void * ) & state ,
2004-08-04 17:23:35 +04:00
smbcli_list_new_callback ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return - 1 ;
}
ff_searchcount = next_parms . t2fnext . out . count ;
ff_eos = next_parms . t2fnext . out . end_of_search ;
received = next_parms . t2fnext . out . count ;
if ( received < = 0 ) break ;
if ( ff_eos ) break ;
}
num_received + = received ;
}
for ( i = 0 ; i < state . total_received ; i + + ) {
fn ( & state . dirlist [ i ] , Mask , caller_state ) ;
}
2005-01-27 10:08:20 +03:00
talloc_free ( state . mem_ctx ) ;
2003-08-13 05:53:07 +04:00
return state . total_received ;
}
/****************************************************************************
Interpret a short filename structure .
The length of the structure is returned .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-06 12:00:24 +04:00
static BOOL interpret_short_filename ( enum smb_search_data_level level ,
2007-05-01 06:08:11 +04:00
const union smb_search_data * info ,
2006-07-06 12:00:24 +04:00
struct clilist_file_info * finfo )
2003-08-13 05:53:07 +04:00
{
2004-11-30 08:37:57 +03:00
struct clilist_file_info finfo2 ;
2003-08-13 05:53:07 +04:00
if ( ! finfo ) finfo = & finfo2 ;
ZERO_STRUCTP ( finfo ) ;
2006-07-06 12:00:24 +04:00
switch ( level ) {
case RAW_SEARCH_DATA_SEARCH :
finfo - > mtime = info - > search . write_time ;
finfo - > size = info - > search . size ;
finfo - > attrib = info - > search . attrib ;
finfo - > name = info - > search . name ;
finfo - > short_name = info - > search . name ;
break ;
default :
DEBUG ( 0 , ( " Unhandled level %d in interpret_short_filename \n " , ( int ) level ) ) ;
return False ;
}
2003-08-13 05:53:07 +04:00
return True ;
}
/* callback function used for smb_search */
2007-05-01 06:08:11 +04:00
static BOOL smbcli_list_old_callback ( void * private , const union smb_search_data * file )
2003-08-13 05:53:07 +04:00
{
struct search_private * state = ( struct search_private * ) private ;
2004-11-30 08:37:57 +03:00
struct clilist_file_info * tdl ;
2003-08-13 05:53:07 +04:00
/* add file info to the dirlist pool */
2004-09-27 05:36:19 +04:00
tdl = talloc_realloc ( state ,
state - > dirlist ,
2005-01-07 07:39:16 +03:00
struct clilist_file_info ,
state - > dirlist_len + 1 ) ;
2003-08-13 05:53:07 +04:00
if ( ! tdl ) {
return False ;
}
state - > dirlist = tdl ;
2005-01-07 07:39:16 +03:00
state - > dirlist_len + + ;
2003-08-13 05:53:07 +04:00
2006-07-06 12:00:24 +04:00
interpret_short_filename ( state - > data_level , file , & state - > dirlist [ state - > total_received ] ) ;
2003-08-13 05:53:07 +04:00
state - > total_received + + ;
state - > ff_searchcount + + ;
2004-09-21 12:46:47 +04:00
state - > id = file - > search . id ; /* return resume info */
2003-08-13 05:53:07 +04:00
return True ;
}
2004-08-04 17:23:35 +04:00
int smbcli_list_old ( struct smbcli_tree * tree , const char * Mask , uint16_t attribute ,
2004-11-30 08:37:57 +03:00
void ( * fn ) ( struct clilist_file_info * , const char * , void * ) ,
2004-02-08 03:51:07 +03:00
void * caller_state )
2003-08-13 05:53:07 +04:00
{
union smb_search_first first_parms ;
union smb_search_next next_parms ;
struct search_private state ; /* for callbacks */
const int num_asked = 500 ;
int received = 0 ;
BOOL first = True ;
int num_received = 0 ;
char * mask ;
int i ;
/* initialize state for search */
2004-08-04 17:23:35 +04:00
state . mem_ctx = talloc_init ( " smbcli_list_old " ) ;
2003-08-13 05:53:07 +04:00
state . dirlist_len = 0 ;
state . total_received = 0 ;
2006-07-27 20:44:59 +04:00
state . data_level = RAW_SEARCH_DATA_SEARCH ;
2004-09-26 15:45:14 +04:00
2007-09-08 17:27:14 +04:00
state . dirlist = talloc_array ( state . mem_ctx , struct clilist_file_info ,
0 ) ;
2003-08-13 05:53:07 +04:00
mask = talloc_strdup ( state . mem_ctx , Mask ) ;
while ( 1 ) {
state . ff_searchcount = 0 ;
if ( first ) {
NTSTATUS status ;
first_parms . search_first . level = RAW_SEARCH_SEARCH ;
2006-07-06 12:00:24 +04:00
first_parms . search_first . data_level = RAW_SEARCH_DATA_SEARCH ;
2003-08-13 05:53:07 +04:00
first_parms . search_first . in . max_count = num_asked ;
first_parms . search_first . in . search_attrib = attribute ;
first_parms . search_first . in . pattern = mask ;
2004-02-08 03:51:07 +03:00
status = smb_raw_search_first ( tree , state . mem_ctx ,
& first_parms ,
( void * ) & state ,
2004-08-04 17:23:35 +04:00
smbcli_list_old_callback ) ;
2004-02-08 03:51:07 +03:00
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-01-27 10:08:20 +03:00
talloc_free ( state . mem_ctx ) ;
2003-08-13 05:53:07 +04:00
return - 1 ;
}
received = first_parms . search_first . out . count ;
if ( received < = 0 ) break ;
first = False ;
} else {
NTSTATUS status ;
next_parms . search_next . level = RAW_SEARCH_SEARCH ;
2006-07-06 12:00:24 +04:00
next_parms . search_next . data_level = RAW_SEARCH_DATA_SEARCH ;
2003-08-13 05:53:07 +04:00
next_parms . search_next . in . max_count = num_asked ;
next_parms . search_next . in . search_attrib = attribute ;
2004-09-21 12:46:47 +04:00
next_parms . search_next . in . id = state . id ;
2003-08-13 05:53:07 +04:00
2004-02-08 03:51:07 +03:00
status = smb_raw_search_next ( tree , state . mem_ctx ,
& next_parms ,
( void * ) & state ,
2004-08-04 17:23:35 +04:00
smbcli_list_old_callback ) ;
2004-09-22 09:13:32 +04:00
if ( NT_STATUS_EQUAL ( status , STATUS_NO_MORE_FILES ) ) {
break ;
}
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-01-27 10:08:20 +03:00
talloc_free ( state . mem_ctx ) ;
2003-08-13 05:53:07 +04:00
return - 1 ;
}
received = next_parms . search_next . out . count ;
if ( received < = 0 ) break ;
}
num_received + = received ;
}
for ( i = 0 ; i < state . total_received ; i + + ) {
fn ( & state . dirlist [ i ] , Mask , caller_state ) ;
}
2005-01-27 10:08:20 +03:00
talloc_free ( state . mem_ctx ) ;
2003-08-13 05:53:07 +04:00
return state . total_received ;
}
/****************************************************************************
Do a directory listing , calling fn on each file found .
This auto - switches between old and new style .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 17:23:35 +04:00
int smbcli_list ( struct smbcli_tree * tree , const char * Mask , uint16_t attribute ,
2004-11-30 08:37:57 +03:00
void ( * fn ) ( struct clilist_file_info * , const char * , void * ) , void * state )
2003-08-13 05:53:07 +04:00
{
2004-02-08 03:51:07 +03:00
if ( tree - > session - > transport - > negotiate . protocol < = PROTOCOL_LANMAN1 )
2004-08-04 17:23:35 +04:00
return smbcli_list_old ( tree , Mask , attribute , fn , state ) ;
2006-07-06 12:00:24 +04:00
return smbcli_list_new ( tree , Mask , attribute , RAW_SEARCH_DATA_GENERIC , fn , state ) ;
2003-08-13 05:53:07 +04:00
}