2004-09-18 08:16:14 +00:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - directory search functions
Copyright ( C ) Andrew Tridgell 2004
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 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2004-09-18 08:16:14 +00: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 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-09-18 08:16:14 +00:00
*/
2004-11-05 07:24:25 +00:00
# include "includes.h"
2004-09-18 08:16:14 +00:00
# include "vfs_posix.h"
2004-11-02 00:24:21 +00:00
# include "system/time.h"
2006-03-16 00:23:11 +00:00
# include "librpc/gen_ndr/security.h"
2020-11-20 15:27:17 +01:00
# include "samba/service_stream.h"
2005-07-18 03:35:52 +00:00
# include "lib/events/events.h"
2008-10-11 21:31:42 +02:00
# include "../lib/util/dlinklist.h"
2023-01-05 10:04:23 +01:00
# include "lib/util/idtree.h"
2004-10-27 01:11:44 +00:00
/* place a reasonable limit on old-style searches as clients tend to
not send search close requests */
# define MAX_OLD_SEARCHES 2000
2006-08-23 13:06:31 +00:00
# define MAX_SEARCH_HANDLES (UINT16_MAX - 1)
# define INVALID_SEARCH_HANDLE UINT16_MAX
2004-10-27 01:11:44 +00:00
2004-10-19 06:39:51 +00:00
/*
destroy an open search
*/
2006-05-24 07:35:06 +00:00
static int pvfs_search_destructor ( struct pvfs_search_state * search )
2004-10-19 06:39:51 +00:00
{
2006-03-18 10:38:38 +00:00
DLIST_REMOVE ( search - > pvfs - > search . list , search ) ;
idr_remove ( search - > pvfs - > search . idtree , search - > handle ) ;
2004-10-19 06:39:51 +00:00
return 0 ;
}
2005-07-18 03:35:52 +00:00
/*
called when a search timer goes off
*/
2008-12-29 20:24:57 +01:00
static void pvfs_search_timer ( struct tevent_context * ev , struct tevent_timer * te ,
2005-07-18 03:35:52 +00:00
struct timeval t , void * ptr )
{
struct pvfs_search_state * search = talloc_get_type ( ptr , struct pvfs_search_state ) ;
talloc_free ( search ) ;
}
/*
setup a timer to destroy a open search after a inactivity period
*/
static void pvfs_search_setup_timer ( struct pvfs_search_state * search )
{
2008-12-29 20:24:57 +01:00
struct tevent_context * ev = search - > pvfs - > ntvfs - > ctx - > event_ctx ;
2006-08-23 13:06:31 +00:00
if ( search - > handle = = INVALID_SEARCH_HANDLE ) return ;
2005-07-18 03:35:52 +00:00
talloc_free ( search - > te ) ;
2010-05-25 15:27:41 -04:00
search - > te = tevent_add_timer ( ev , search ,
2006-03-18 10:38:38 +00:00
timeval_current_ofs ( search - > pvfs - > search . inactivity_time , 0 ) ,
2005-07-18 03:35:52 +00:00
pvfs_search_timer , search ) ;
}
2004-09-18 08:16:14 +00:00
/*
fill in a single search result for a given info level
*/
static NTSTATUS fill_search_info ( struct pvfs_state * pvfs ,
2006-07-06 08:00:24 +00:00
enum smb_search_data_level level ,
2004-09-18 08:16:14 +00:00
const char * unix_path ,
2004-09-20 07:28:43 +00:00
const char * fname ,
2004-09-22 12:38:19 +00:00
struct pvfs_search_state * search ,
2006-09-10 07:24:41 +00:00
off_t dir_offset ,
2004-09-18 08:16:14 +00:00
union smb_search_data * file )
{
2004-09-20 07:28:43 +00:00
struct pvfs_filename * name ;
2004-09-18 08:16:14 +00:00
NTSTATUS status ;
2004-10-11 03:27:16 +00:00
const char * shortname ;
2006-09-10 07:24:41 +00:00
uint32_t dir_index = ( uint32_t ) dir_offset ; /* truncated - see the code
in pvfs_list_seek_ofs ( ) for
how we cope with this */
2004-09-18 08:16:14 +00:00
2008-05-05 12:18:47 +02:00
status = pvfs_resolve_partial ( pvfs , file , unix_path , fname , 0 , & name ) ;
2004-09-18 08:16:14 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-09-20 07:28:43 +00:00
2004-10-26 05:39:54 +00:00
status = pvfs_match_attrib ( pvfs , name , search - > search_attrib , search - > must_attrib ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2004-09-22 08:17:26 +00:00
}
2004-09-18 08:16:14 +00:00
switch ( level ) {
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_SEARCH :
2004-10-11 03:27:16 +00:00
shortname = pvfs_short_name ( pvfs , name , name ) ;
2004-09-22 12:38:19 +00:00
file - > search . attrib = name - > dos . attrib ;
file - > search . write_time = nt_time_to_unix ( name - > dos . write_time ) ;
file - > search . size = name - > st . st_size ;
2004-10-11 03:27:16 +00:00
file - > search . name = shortname ;
2004-10-27 01:11:44 +00:00
file - > search . id . reserved = search - > handle > > 8 ;
2004-09-22 12:38:19 +00:00
memset ( file - > search . id . name , ' ' , sizeof ( file - > search . id . name ) ) ;
2004-10-11 03:27:16 +00:00
memcpy ( file - > search . id . name , shortname ,
MIN ( strlen ( shortname ) + 1 , sizeof ( file - > search . id . name ) ) ) ;
2004-10-27 01:11:44 +00:00
file - > search . id . handle = search - > handle & 0xFF ;
2004-10-26 11:11:16 +00:00
file - > search . id . server_cookie = dir_index ;
2004-09-22 12:38:19 +00:00
file - > search . id . client_cookie = 0 ;
return NT_STATUS_OK ;
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_STANDARD :
2004-10-26 11:11:16 +00:00
file - > standard . resume_key = dir_index ;
2004-09-22 08:17:26 +00:00
file - > standard . create_time = nt_time_to_unix ( name - > dos . create_time ) ;
file - > standard . access_time = nt_time_to_unix ( name - > dos . access_time ) ;
file - > standard . write_time = nt_time_to_unix ( name - > dos . write_time ) ;
file - > standard . size = name - > st . st_size ;
file - > standard . alloc_size = name - > dos . alloc_size ;
file - > standard . attrib = name - > dos . attrib ;
file - > standard . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-22 08:17:26 +00:00
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_EA_SIZE :
2004-10-26 11:11:16 +00:00
file - > ea_size . resume_key = dir_index ;
2004-09-22 08:17:26 +00:00
file - > ea_size . create_time = nt_time_to_unix ( name - > dos . create_time ) ;
file - > ea_size . access_time = nt_time_to_unix ( name - > dos . access_time ) ;
file - > ea_size . write_time = nt_time_to_unix ( name - > dos . write_time ) ;
file - > ea_size . size = name - > st . st_size ;
file - > ea_size . alloc_size = name - > dos . alloc_size ;
file - > ea_size . attrib = name - > dos . attrib ;
file - > ea_size . ea_size = name - > dos . ea_size ;
file - > ea_size . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-22 08:17:26 +00:00
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_EA_LIST :
2004-12-18 04:38:43 +00:00
file - > ea_list . resume_key = dir_index ;
file - > ea_list . create_time = nt_time_to_unix ( name - > dos . create_time ) ;
file - > ea_list . access_time = nt_time_to_unix ( name - > dos . access_time ) ;
file - > ea_list . write_time = nt_time_to_unix ( name - > dos . write_time ) ;
file - > ea_list . size = name - > st . st_size ;
file - > ea_list . alloc_size = name - > dos . alloc_size ;
file - > ea_list . attrib = name - > dos . attrib ;
file - > ea_list . name . s = fname ;
return pvfs_query_ea_list ( pvfs , file , name , - 1 ,
search - > num_ea_names ,
search - > ea_names ,
& file - > ea_list . eas ) ;
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_DIRECTORY_INFO :
2004-10-26 11:11:16 +00:00
file - > directory_info . file_index = dir_index ;
2004-09-22 08:17:26 +00:00
file - > directory_info . create_time = name - > dos . create_time ;
file - > directory_info . access_time = name - > dos . access_time ;
file - > directory_info . write_time = name - > dos . write_time ;
file - > directory_info . change_time = name - > dos . change_time ;
file - > directory_info . size = name - > st . st_size ;
file - > directory_info . alloc_size = name - > dos . alloc_size ;
file - > directory_info . attrib = name - > dos . attrib ;
file - > directory_info . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-22 08:17:26 +00:00
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO :
2004-10-26 11:11:16 +00:00
file - > full_directory_info . file_index = dir_index ;
2004-09-22 08:17:26 +00:00
file - > full_directory_info . create_time = name - > dos . create_time ;
file - > full_directory_info . access_time = name - > dos . access_time ;
file - > full_directory_info . write_time = name - > dos . write_time ;
file - > full_directory_info . change_time = name - > dos . change_time ;
file - > full_directory_info . size = name - > st . st_size ;
file - > full_directory_info . alloc_size = name - > dos . alloc_size ;
file - > full_directory_info . attrib = name - > dos . attrib ;
file - > full_directory_info . ea_size = name - > dos . ea_size ;
file - > full_directory_info . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-22 08:17:26 +00:00
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_NAME_INFO :
2004-09-22 08:17:26 +00:00
file - > name_info . file_index = dir_index ;
file - > name_info . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-18 08:16:14 +00:00
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO :
2004-10-26 11:11:16 +00:00
file - > both_directory_info . file_index = dir_index ;
2004-09-20 07:28:43 +00:00
file - > both_directory_info . create_time = name - > dos . create_time ;
file - > both_directory_info . access_time = name - > dos . access_time ;
file - > both_directory_info . write_time = name - > dos . write_time ;
file - > both_directory_info . change_time = name - > dos . change_time ;
file - > both_directory_info . size = name - > st . st_size ;
file - > both_directory_info . alloc_size = name - > dos . alloc_size ;
file - > both_directory_info . attrib = name - > dos . attrib ;
file - > both_directory_info . ea_size = name - > dos . ea_size ;
2004-10-02 13:29:20 +00:00
file - > both_directory_info . short_name . s = pvfs_short_name ( pvfs , file , name ) ;
2004-09-20 07:28:43 +00:00
file - > both_directory_info . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-22 08:17:26 +00:00
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO :
2004-10-26 11:11:16 +00:00
file - > id_full_directory_info . file_index = dir_index ;
2004-09-22 08:17:26 +00:00
file - > id_full_directory_info . create_time = name - > dos . create_time ;
file - > id_full_directory_info . access_time = name - > dos . access_time ;
file - > id_full_directory_info . write_time = name - > dos . write_time ;
file - > id_full_directory_info . change_time = name - > dos . change_time ;
file - > id_full_directory_info . size = name - > st . st_size ;
file - > id_full_directory_info . alloc_size = name - > dos . alloc_size ;
file - > id_full_directory_info . attrib = name - > dos . attrib ;
file - > id_full_directory_info . ea_size = name - > dos . ea_size ;
file - > id_full_directory_info . file_id = name - > dos . file_id ;
file - > id_full_directory_info . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-22 08:17:26 +00:00
2006-07-06 08:00:24 +00:00
case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO :
2004-10-26 11:11:16 +00:00
file - > id_both_directory_info . file_index = dir_index ;
2004-09-22 08:17:26 +00:00
file - > id_both_directory_info . create_time = name - > dos . create_time ;
file - > id_both_directory_info . access_time = name - > dos . access_time ;
file - > id_both_directory_info . write_time = name - > dos . write_time ;
file - > id_both_directory_info . change_time = name - > dos . change_time ;
file - > id_both_directory_info . size = name - > st . st_size ;
file - > id_both_directory_info . alloc_size = name - > dos . alloc_size ;
file - > id_both_directory_info . attrib = name - > dos . attrib ;
file - > id_both_directory_info . ea_size = name - > dos . ea_size ;
file - > id_both_directory_info . file_id = name - > dos . file_id ;
2004-10-02 13:29:20 +00:00
file - > id_both_directory_info . short_name . s = pvfs_short_name ( pvfs , file , name ) ;
2004-09-22 08:17:26 +00:00
file - > id_both_directory_info . name . s = fname ;
2004-09-22 12:38:19 +00:00
return NT_STATUS_OK ;
2004-09-18 08:16:14 +00:00
2011-06-16 08:39:03 +02:00
case RAW_SEARCH_DATA_GENERIC :
case RAW_SEARCH_DATA_UNIX_INFO :
case RAW_SEARCH_DATA_UNIX_INFO2 :
2011-06-08 19:00:18 +02:00
return NT_STATUS_INVALID_LEVEL ;
2004-09-18 08:16:14 +00:00
}
2011-06-16 08:39:03 +02:00
return NT_STATUS_INVALID_LEVEL ;
2004-09-18 08:16:14 +00:00
}
2004-09-22 08:17:26 +00:00
/*
the search fill loop
*/
static NTSTATUS pvfs_search_fill ( struct pvfs_state * pvfs , TALLOC_CTX * mem_ctx ,
2010-01-05 09:42:54 -08:00
unsigned int max_count ,
2004-09-22 08:17:26 +00:00
struct pvfs_search_state * search ,
2006-07-06 08:00:24 +00:00
enum smb_search_data_level level ,
2010-01-05 09:42:54 -08:00
unsigned int * reply_count ,
2004-09-22 08:17:26 +00:00
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2004-09-22 08:17:26 +00:00
{
struct pvfs_dir * dir = search - > dir ;
NTSTATUS status ;
* reply_count = 0 ;
2004-10-26 11:11:16 +00:00
if ( max_count = = 0 ) {
max_count = 1 ;
}
while ( ( * reply_count ) < max_count ) {
2004-09-22 08:17:26 +00:00
union smb_search_data * file ;
2004-10-26 11:11:16 +00:00
const char * name ;
2006-09-10 07:24:41 +00:00
off_t ofs = search - > current_index ;
2004-10-26 11:11:16 +00:00
2004-10-26 13:18:34 +00:00
name = pvfs_list_next ( dir , & search - > current_index ) ;
2004-10-26 11:11:16 +00:00
if ( name = = NULL ) break ;
2005-01-27 07:08:20 +00:00
file = talloc ( mem_ctx , union smb_search_data ) ;
2004-09-22 08:17:26 +00:00
if ( ! file ) {
return NT_STATUS_NO_MEMORY ;
}
2004-10-26 11:11:16 +00:00
status = fill_search_info ( pvfs , level ,
pvfs_list_unix_path ( dir ) , name ,
search , search - > current_index , file ) ;
2004-09-22 08:17:26 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( file ) ;
2004-10-26 07:04:45 +00:00
continue ;
2004-09-22 08:17:26 +00:00
}
if ( ! callback ( search_private , file ) ) {
talloc_free ( file ) ;
2004-10-26 13:18:34 +00:00
search - > current_index = ofs ;
2004-09-22 08:17:26 +00:00
break ;
}
2004-10-26 11:11:16 +00:00
2004-09-22 08:17:26 +00:00
( * reply_count ) + + ;
talloc_free ( file ) ;
}
2005-07-18 03:35:52 +00:00
pvfs_search_setup_timer ( search ) ;
2004-10-26 13:18:34 +00:00
2004-09-22 08:17:26 +00:00
return NT_STATUS_OK ;
}
2004-10-27 01:11:44 +00:00
/*
we ' ve run out of search handles - cleanup those that the client forgot
to close
*/
static void pvfs_search_cleanup ( struct pvfs_state * pvfs )
{
int i ;
2010-09-10 20:46:10 +02:00
time_t t = time_mono ( NULL ) ;
2004-10-27 01:11:44 +00:00
for ( i = 0 ; i < MAX_OLD_SEARCHES ; i + + ) {
2009-02-04 08:52:41 +01:00
struct pvfs_search_state * search ;
void * p = idr_find ( pvfs - > search . idtree , i ) ;
if ( p = = NULL ) return ;
search = talloc_get_type ( p , struct pvfs_search_state ) ;
2004-10-27 01:11:44 +00:00
if ( pvfs_list_eos ( search - > dir , search - > current_index ) & &
search - > last_used ! = 0 & &
t > search - > last_used + 30 ) {
/* its almost certainly been forgotten
about */
talloc_free ( search ) ;
}
}
}
2004-09-22 12:38:19 +00:00
/*
list files in a directory matching a wildcard pattern - old SMBsearch interface
*/
2004-09-29 13:17:09 +00:00
static NTSTATUS pvfs_search_first_old ( struct ntvfs_module_context * ntvfs ,
2006-03-10 14:31:17 +00:00
struct ntvfs_request * req , union smb_search_first * io ,
2004-09-22 12:38:19 +00:00
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2004-09-22 12:38:19 +00:00
{
struct pvfs_dir * dir ;
2009-02-04 08:52:41 +01:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2004-09-22 12:38:19 +00:00
struct pvfs_search_state * search ;
2010-01-05 09:42:54 -08:00
unsigned int reply_count ;
2004-09-22 12:38:19 +00:00
uint16_t search_attrib ;
const char * pattern ;
NTSTATUS status ;
struct pvfs_filename * name ;
2004-10-19 06:39:51 +00:00
int id ;
2004-09-22 12:38:19 +00:00
search_attrib = io - > search_first . in . search_attrib ;
pattern = io - > search_first . in . pattern ;
/* resolve the cifs name to a posix name */
2004-11-15 06:57:26 +00:00
status = pvfs_resolve_name ( pvfs , req , pattern , PVFS_RESOLVE_WILDCARD , & name ) ;
2004-09-22 12:38:19 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! name - > has_wildcard & & ! name - > exists ) {
return STATUS_NO_MORE_FILES ;
}
2005-01-09 08:27:35 +00:00
status = pvfs_access_check_parent ( pvfs , req , name , SEC_DIR_TRAVERSE | SEC_DIR_LIST ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-09-22 12:38:19 +00:00
/* we initially make search a child of the request, then if we
need to keep it long term we steal it for the private
structure */
2005-01-27 07:08:20 +00:00
search = talloc ( req , struct pvfs_search_state ) ;
2004-09-22 12:38:19 +00:00
if ( ! search ) {
return NT_STATUS_NO_MEMORY ;
}
/* do the actual directory listing */
2004-10-26 13:18:34 +00:00
status = pvfs_list_start ( pvfs , name , search , & dir ) ;
2004-09-22 12:38:19 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* we need to give a handle back to the client so it
can continue a search */
2006-03-18 10:38:38 +00:00
id = idr_get_new ( pvfs - > search . idtree , search , MAX_OLD_SEARCHES ) ;
2004-10-27 01:11:44 +00:00
if ( id = = - 1 ) {
pvfs_search_cleanup ( pvfs ) ;
2006-03-18 10:38:38 +00:00
id = idr_get_new ( pvfs - > search . idtree , search , MAX_OLD_SEARCHES ) ;
2004-10-27 01:11:44 +00:00
}
2004-10-19 06:39:51 +00:00
if ( id = = - 1 ) {
return NT_STATUS_INSUFFICIENT_RESOURCES ;
2004-09-22 12:38:19 +00:00
}
2004-10-19 06:39:51 +00:00
search - > pvfs = pvfs ;
search - > handle = id ;
2004-09-22 12:38:19 +00:00
search - > dir = dir ;
search - > current_index = 0 ;
2004-10-25 07:58:47 +00:00
search - > search_attrib = search_attrib & 0xFF ;
search - > must_attrib = ( search_attrib > > 8 ) & 0xFF ;
2010-09-10 20:46:10 +02:00
search - > last_used = time_mono ( NULL ) ;
2005-07-18 03:35:52 +00:00
search - > te = NULL ;
2004-09-22 12:38:19 +00:00
2006-03-18 10:38:38 +00:00
DLIST_ADD ( pvfs - > search . list , search ) ;
2004-10-19 06:39:51 +00:00
talloc_set_destructor ( search , pvfs_search_destructor ) ;
2006-07-06 08:00:24 +00:00
status = pvfs_search_fill ( pvfs , req , io - > search_first . in . max_count , search , io - > generic . data_level ,
2004-09-22 12:38:19 +00:00
& reply_count , search_private , callback ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
io - > search_first . out . count = reply_count ;
/* not matching any entries is an error */
if ( reply_count = = 0 ) {
return STATUS_NO_MORE_FILES ;
}
talloc_steal ( pvfs , search ) ;
return NT_STATUS_OK ;
}
/* continue a old style search */
2004-09-29 13:17:09 +00:00
static NTSTATUS pvfs_search_next_old ( struct ntvfs_module_context * ntvfs ,
2006-03-10 14:31:17 +00:00
struct ntvfs_request * req , union smb_search_next * io ,
2004-09-22 12:38:19 +00:00
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2004-09-22 12:38:19 +00:00
{
2009-02-04 08:52:41 +01:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
void * p ;
2004-09-22 12:38:19 +00:00
struct pvfs_search_state * search ;
struct pvfs_dir * dir ;
2010-01-05 09:42:54 -08:00
unsigned int reply_count , max_count ;
2004-09-22 12:38:19 +00:00
uint16_t handle ;
NTSTATUS status ;
2004-10-27 01:11:44 +00:00
handle = io - > search_next . in . id . handle | ( io - > search_next . in . id . reserved < < 8 ) ;
2004-09-22 12:38:19 +00:00
max_count = io - > search_next . in . max_count ;
2009-02-04 08:52:41 +01:00
p = idr_find ( pvfs - > search . idtree , handle ) ;
if ( p = = NULL ) {
2004-09-22 12:38:19 +00:00
/* we didn't find the search handle */
return NT_STATUS_INVALID_HANDLE ;
}
2009-02-04 08:52:41 +01:00
search = talloc_get_type ( p , struct pvfs_search_state ) ;
2004-09-22 12:38:19 +00:00
dir = search - > dir ;
2006-09-10 07:24:41 +00:00
status = pvfs_list_seek_ofs ( dir , io - > search_next . in . id . server_cookie ,
& search - > current_index ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2010-09-10 20:46:10 +02:00
search - > last_used = time_mono ( NULL ) ;
2006-09-10 07:24:41 +00:00
2006-07-06 08:00:24 +00:00
status = pvfs_search_fill ( pvfs , req , max_count , search , io - > generic . data_level ,
2004-09-22 12:38:19 +00:00
& reply_count , search_private , callback ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
io - > search_next . out . count = reply_count ;
/* not matching any entries means end of search */
if ( reply_count = = 0 ) {
talloc_free ( search ) ;
}
return NT_STATUS_OK ;
}
2004-09-18 08:16:14 +00:00
/*
list files in a directory matching a wildcard pattern
*/
2006-07-06 08:00:24 +00:00
static NTSTATUS pvfs_search_first_trans2 ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req , union smb_search_first * io ,
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2004-09-18 08:16:14 +00:00
{
struct pvfs_dir * dir ;
2009-02-04 08:52:41 +01:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2004-09-18 08:16:14 +00:00
struct pvfs_search_state * search ;
2010-01-05 09:42:54 -08:00
unsigned int reply_count ;
2004-09-22 12:38:19 +00:00
uint16_t search_attrib , max_count ;
2004-09-18 08:16:14 +00:00
const char * pattern ;
NTSTATUS status ;
struct pvfs_filename * name ;
2004-10-19 06:39:51 +00:00
int id ;
2004-09-18 08:16:14 +00:00
2004-09-22 08:17:26 +00:00
search_attrib = io - > t2ffirst . in . search_attrib ;
pattern = io - > t2ffirst . in . pattern ;
2004-09-22 12:38:19 +00:00
max_count = io - > t2ffirst . in . max_count ;
2004-09-22 08:17:26 +00:00
2004-09-18 08:16:14 +00:00
/* resolve the cifs name to a posix name */
2004-11-15 06:57:26 +00:00
status = pvfs_resolve_name ( pvfs , req , pattern , PVFS_RESOLVE_WILDCARD , & name ) ;
2004-09-18 08:16:14 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! name - > has_wildcard & & ! name - > exists ) {
2004-09-22 08:17:26 +00:00
return NT_STATUS_NO_SUCH_FILE ;
2004-09-18 08:16:14 +00:00
}
2005-01-09 08:27:35 +00:00
status = pvfs_access_check_parent ( pvfs , req , name , SEC_DIR_TRAVERSE | SEC_DIR_LIST ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-09-18 08:16:14 +00:00
/* we initially make search a child of the request, then if we
need to keep it long term we steal it for the private
structure */
2005-01-27 07:08:20 +00:00
search = talloc ( req , struct pvfs_search_state ) ;
2004-09-18 08:16:14 +00:00
if ( ! search ) {
return NT_STATUS_NO_MEMORY ;
}
/* do the actual directory listing */
2004-10-26 13:18:34 +00:00
status = pvfs_list_start ( pvfs , name , search , & dir ) ;
2004-09-18 08:16:14 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2006-08-23 13:06:31 +00:00
id = idr_get_new ( pvfs - > search . idtree , search , MAX_SEARCH_HANDLES ) ;
2004-10-19 06:39:51 +00:00
if ( id = = - 1 ) {
return NT_STATUS_INSUFFICIENT_RESOURCES ;
2004-09-18 08:16:14 +00:00
}
2004-10-19 06:39:51 +00:00
search - > pvfs = pvfs ;
search - > handle = id ;
2004-09-18 08:16:14 +00:00
search - > dir = dir ;
search - > current_index = 0 ;
search - > search_attrib = search_attrib ;
2004-10-25 07:58:47 +00:00
search - > must_attrib = 0 ;
2004-10-27 01:11:44 +00:00
search - > last_used = 0 ;
2004-12-18 04:38:43 +00:00
search - > num_ea_names = io - > t2ffirst . in . num_names ;
search - > ea_names = io - > t2ffirst . in . ea_names ;
2005-07-18 03:35:52 +00:00
search - > te = NULL ;
2004-09-18 08:16:14 +00:00
2006-03-18 10:38:38 +00:00
DLIST_ADD ( pvfs - > search . list , search ) ;
2004-10-19 06:39:51 +00:00
talloc_set_destructor ( search , pvfs_search_destructor ) ;
2006-07-06 08:00:24 +00:00
status = pvfs_search_fill ( pvfs , req , max_count , search , io - > generic . data_level ,
2004-09-22 08:17:26 +00:00
& reply_count , search_private , callback ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2004-09-18 08:16:14 +00:00
}
/* not matching any entries is an error */
if ( reply_count = = 0 ) {
2004-09-22 08:17:26 +00:00
return NT_STATUS_NO_SUCH_FILE ;
2004-09-18 08:16:14 +00:00
}
2004-09-22 08:17:26 +00:00
io - > t2ffirst . out . count = reply_count ;
io - > t2ffirst . out . handle = search - > handle ;
2004-10-26 11:11:16 +00:00
io - > t2ffirst . out . end_of_search = pvfs_list_eos ( dir , search - > current_index ) ? 1 : 0 ;
2004-09-18 08:16:14 +00:00
2004-09-22 08:17:26 +00:00
/* work out if we are going to keep the search state
and allow for a search continue */
if ( ( io - > t2ffirst . in . flags & FLAG_TRANS2_FIND_CLOSE ) | |
( ( io - > t2ffirst . in . flags & FLAG_TRANS2_FIND_CLOSE_IF_END ) & &
io - > t2ffirst . out . end_of_search ) ) {
talloc_free ( search ) ;
2004-09-18 08:16:14 +00:00
} else {
2004-09-22 08:17:26 +00:00
talloc_steal ( pvfs , search ) ;
2004-09-18 08:16:14 +00:00
}
return NT_STATUS_OK ;
}
/* continue a search */
2006-07-06 08:00:24 +00:00
static NTSTATUS pvfs_search_next_trans2 ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req , union smb_search_next * io ,
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2004-09-18 08:16:14 +00:00
{
2009-02-04 08:52:41 +01:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
void * p ;
2004-09-22 08:17:26 +00:00
struct pvfs_search_state * search ;
struct pvfs_dir * dir ;
2010-01-05 09:42:54 -08:00
unsigned int reply_count ;
2004-09-21 08:46:47 +00:00
uint16_t handle ;
2004-09-22 08:17:26 +00:00
NTSTATUS status ;
2004-09-21 08:46:47 +00:00
2004-09-22 08:17:26 +00:00
handle = io - > t2fnext . in . handle ;
2004-09-21 08:46:47 +00:00
2009-02-04 08:52:41 +01:00
p = idr_find ( pvfs - > search . idtree , handle ) ;
if ( p = = NULL ) {
2004-09-21 08:46:47 +00:00
/* we didn't find the search handle */
2004-09-22 08:17:26 +00:00
return NT_STATUS_INVALID_HANDLE ;
2004-09-21 08:46:47 +00:00
}
2009-02-04 08:52:41 +01:00
search = talloc_get_type ( p , struct pvfs_search_state ) ;
2004-09-21 08:46:47 +00:00
dir = search - > dir ;
2006-09-10 07:24:41 +00:00
status = NT_STATUS_OK ;
2004-09-21 08:46:47 +00:00
2004-09-22 12:38:19 +00:00
/* work out what type of continuation is being used */
if ( io - > t2fnext . in . last_name & & * io - > t2fnext . in . last_name ) {
2004-10-26 13:18:34 +00:00
status = pvfs_list_seek ( dir , io - > t2fnext . in . last_name , & search - > current_index ) ;
2006-09-10 07:24:41 +00:00
if ( ! NT_STATUS_IS_OK ( status ) & & io - > t2fnext . in . resume_key ) {
status = pvfs_list_seek_ofs ( dir , io - > t2fnext . in . resume_key ,
& search - > current_index ) ;
2004-10-26 13:18:34 +00:00
}
2006-09-10 07:24:41 +00:00
} else if ( ! ( io - > t2fnext . in . flags & FLAG_TRANS2_FIND_CONTINUE ) ) {
status = pvfs_list_seek_ofs ( dir , io - > t2fnext . in . resume_key ,
& search - > current_index ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2004-09-21 08:46:47 +00:00
}
2004-12-18 04:38:43 +00:00
search - > num_ea_names = io - > t2fnext . in . num_names ;
search - > ea_names = io - > t2fnext . in . ea_names ;
2006-07-06 08:00:24 +00:00
status = pvfs_search_fill ( pvfs , req , io - > t2fnext . in . max_count , search , io - > generic . data_level ,
2004-09-22 08:17:26 +00:00
& reply_count , search_private , callback ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2004-09-21 08:46:47 +00:00
}
2004-09-22 08:17:26 +00:00
io - > t2fnext . out . count = reply_count ;
2004-10-26 11:11:16 +00:00
io - > t2fnext . out . end_of_search = pvfs_list_eos ( dir , search - > current_index ) ? 1 : 0 ;
2004-09-21 08:46:47 +00:00
/* work out if we are going to keep the search state */
if ( ( io - > t2fnext . in . flags & FLAG_TRANS2_FIND_CLOSE ) | |
2004-09-22 08:17:26 +00:00
( ( io - > t2fnext . in . flags & FLAG_TRANS2_FIND_CLOSE_IF_END ) & &
io - > t2fnext . out . end_of_search ) ) {
2004-09-21 08:46:47 +00:00
talloc_free ( search ) ;
}
2004-09-22 08:17:26 +00:00
2004-09-21 08:46:47 +00:00
return NT_STATUS_OK ;
2004-09-18 08:16:14 +00:00
}
2006-07-08 12:35:37 +00:00
static NTSTATUS pvfs_search_first_smb2 ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req , const struct smb2_find * io ,
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2006-07-08 12:35:37 +00:00
{
struct pvfs_dir * dir ;
2009-02-04 08:52:41 +01:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2006-07-08 12:35:37 +00:00
struct pvfs_search_state * search ;
2010-01-05 09:42:54 -08:00
unsigned int reply_count ;
2006-07-08 12:35:37 +00:00
uint16_t max_count ;
const char * pattern ;
NTSTATUS status ;
struct pvfs_filename * name ;
struct pvfs_file * f ;
f = pvfs_find_fd ( pvfs , req , io - > in . file . ntvfs ) ;
if ( ! f ) {
return NT_STATUS_FILE_CLOSED ;
}
/* its only valid for directories */
if ( f - > handle - > fd ! = - 1 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ! ( f - > access_mask & SEC_DIR_LIST ) ) {
return NT_STATUS_ACCESS_DENIED ;
}
if ( f - > search ) {
talloc_free ( f - > search ) ;
f - > search = NULL ;
}
if ( strequal ( io - > in . pattern , " " ) ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
if ( strchr_m ( io - > in . pattern , ' \\ ' ) ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
if ( strchr_m ( io - > in . pattern , ' / ' ) ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
if ( strequal ( " " , f - > handle - > name - > original_name ) ) {
2009-10-18 10:30:10 +11:00
pattern = talloc_asprintf ( req , " %s " , io - > in . pattern ) ;
2006-07-08 12:35:37 +00:00
NT_STATUS_HAVE_NO_MEMORY ( pattern ) ;
} else {
2009-10-18 10:30:10 +11:00
pattern = talloc_asprintf ( req , " %s \\ %s " ,
2006-07-08 12:35:37 +00:00
f - > handle - > name - > original_name ,
io - > in . pattern ) ;
NT_STATUS_HAVE_NO_MEMORY ( pattern ) ;
}
/* resolve the cifs name to a posix name */
status = pvfs_resolve_name ( pvfs , req , pattern , PVFS_RESOLVE_WILDCARD , & name ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
if ( ! name - > has_wildcard & & ! name - > exists ) {
return NT_STATUS_NO_SUCH_FILE ;
}
/* we initially make search a child of the request, then if we
need to keep it long term we steal it for the private
structure */
search = talloc ( req , struct pvfs_search_state ) ;
NT_STATUS_HAVE_NO_MEMORY ( search ) ;
/* do the actual directory listing */
status = pvfs_list_start ( pvfs , name , search , & dir ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
search - > pvfs = pvfs ;
2006-08-23 13:06:31 +00:00
search - > handle = INVALID_SEARCH_HANDLE ;
2006-07-08 12:35:37 +00:00
search - > dir = dir ;
search - > current_index = 0 ;
2007-05-14 11:45:39 +00:00
search - > search_attrib = 0x0000FFFF ;
2006-07-08 12:35:37 +00:00
search - > must_attrib = 0 ;
search - > last_used = 0 ;
search - > num_ea_names = 0 ;
search - > ea_names = NULL ;
search - > te = NULL ;
if ( io - > in . continue_flags & SMB2_CONTINUE_FLAG_SINGLE ) {
max_count = 1 ;
} else {
max_count = UINT16_MAX ;
}
status = pvfs_search_fill ( pvfs , req , max_count , search , io - > data_level ,
& reply_count , search_private , callback ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
/* not matching any entries is an error */
if ( reply_count = = 0 ) {
return NT_STATUS_NO_SUCH_FILE ;
}
f - > search = talloc_steal ( f , search ) ;
return NT_STATUS_OK ;
}
static NTSTATUS pvfs_search_next_smb2 ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req , const struct smb2_find * io ,
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2006-07-08 12:35:37 +00:00
{
2009-02-04 08:52:41 +01:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2006-07-08 12:35:37 +00:00
struct pvfs_search_state * search ;
2010-01-05 09:42:54 -08:00
unsigned int reply_count ;
2006-07-08 12:35:37 +00:00
uint16_t max_count ;
NTSTATUS status ;
struct pvfs_file * f ;
f = pvfs_find_fd ( pvfs , req , io - > in . file . ntvfs ) ;
if ( ! f ) {
return NT_STATUS_FILE_CLOSED ;
}
/* its only valid for directories */
if ( f - > handle - > fd ! = - 1 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* if there's no search started on the dir handle, it's like a search_first */
search = f - > search ;
if ( ! search ) {
return pvfs_search_first_smb2 ( ntvfs , req , io , search_private , callback ) ;
}
if ( io - > in . continue_flags & SMB2_CONTINUE_FLAG_RESTART ) {
search - > current_index = 0 ;
}
if ( io - > in . continue_flags & SMB2_CONTINUE_FLAG_SINGLE ) {
max_count = 1 ;
} else {
max_count = UINT16_MAX ;
}
status = pvfs_search_fill ( pvfs , req , max_count , search , io - > data_level ,
& reply_count , search_private , callback ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
/* not matching any entries is an error */
if ( reply_count = = 0 ) {
return STATUS_NO_MORE_FILES ;
}
return NT_STATUS_OK ;
}
2006-07-06 08:00:24 +00:00
/*
list files in a directory matching a wildcard pattern
*/
NTSTATUS pvfs_search_first ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req , union smb_search_first * io ,
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2006-07-06 08:00:24 +00:00
{
switch ( io - > generic . level ) {
case RAW_SEARCH_SEARCH :
case RAW_SEARCH_FFIRST :
case RAW_SEARCH_FUNIQUE :
return pvfs_search_first_old ( ntvfs , req , io , search_private , callback ) ;
case RAW_SEARCH_TRANS2 :
return pvfs_search_first_trans2 ( ntvfs , req , io , search_private , callback ) ;
2006-07-08 12:35:37 +00:00
case RAW_SEARCH_SMB2 :
return pvfs_search_first_smb2 ( ntvfs , req , & io - > smb2 , search_private , callback ) ;
2006-07-06 08:00:24 +00:00
}
return NT_STATUS_INVALID_LEVEL ;
}
/* continue a search */
NTSTATUS pvfs_search_next ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req , union smb_search_next * io ,
void * search_private ,
2007-10-06 22:28:14 +00:00
bool ( * callback ) ( void * , const union smb_search_data * ) )
2006-07-06 08:00:24 +00:00
{
switch ( io - > generic . level ) {
case RAW_SEARCH_SEARCH :
case RAW_SEARCH_FFIRST :
return pvfs_search_next_old ( ntvfs , req , io , search_private , callback ) ;
case RAW_SEARCH_FUNIQUE :
return NT_STATUS_INVALID_LEVEL ;
case RAW_SEARCH_TRANS2 :
return pvfs_search_next_trans2 ( ntvfs , req , io , search_private , callback ) ;
2006-07-08 12:35:37 +00:00
case RAW_SEARCH_SMB2 :
return pvfs_search_next_smb2 ( ntvfs , req , & io - > smb2 , search_private , callback ) ;
2006-07-06 08:00:24 +00:00
}
return NT_STATUS_INVALID_LEVEL ;
}
2004-09-18 08:16:14 +00:00
/* close a search */
2004-09-29 13:17:09 +00:00
NTSTATUS pvfs_search_close ( struct ntvfs_module_context * ntvfs ,
2006-03-10 14:31:17 +00:00
struct ntvfs_request * req , union smb_search_close * io )
2004-09-18 08:16:14 +00:00
{
2009-02-04 08:52:41 +01:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
void * p ;
2004-09-22 08:17:26 +00:00
struct pvfs_search_state * search ;
2006-08-23 13:06:31 +00:00
uint16_t handle = INVALID_SEARCH_HANDLE ;
2004-09-22 08:17:26 +00:00
2006-07-06 08:00:24 +00:00
switch ( io - > generic . level ) {
case RAW_FINDCLOSE_GENERIC :
return NT_STATUS_INVALID_LEVEL ;
case RAW_FINDCLOSE_FCLOSE :
2004-09-22 12:38:19 +00:00
handle = io - > fclose . in . id . handle ;
2006-07-06 08:00:24 +00:00
break ;
case RAW_FINDCLOSE_FINDCLOSE :
2004-09-22 12:38:19 +00:00
handle = io - > findclose . in . handle ;
2006-07-06 08:00:24 +00:00
break ;
2004-09-22 08:17:26 +00:00
}
2009-02-04 08:52:41 +01:00
p = idr_find ( pvfs - > search . idtree , handle ) ;
if ( p = = NULL ) {
2004-09-22 08:17:26 +00:00
/* we didn't find the search handle */
return NT_STATUS_INVALID_HANDLE ;
}
2009-02-04 08:52:41 +01:00
search = talloc_get_type ( p , struct pvfs_search_state ) ;
2004-09-22 08:17:26 +00:00
talloc_free ( search ) ;
return NT_STATUS_OK ;
2004-09-18 08:16:14 +00:00
}