2006-03-21 14:47:24 +03:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 2006
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
2006-03-21 14:47:24 +03: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/>.
2006-03-21 14:47:24 +03:00
*/
/*
this is the change notify database . It implements mechanisms for
storing current change notify waiters in a tdb , and checking if a
given event matches any of the stored notify waiiters .
*/
# include "includes.h"
# include "system/filesys.h"
# include "lib/tdb/include/tdb.h"
2006-10-21 03:32:23 +04:00
# include "lib/util/util_tdb.h"
2006-03-21 14:47:24 +03:00
# include "messaging/messaging.h"
2007-11-16 22:12:00 +03:00
# include "tdb_wrap.h"
2006-03-21 14:47:24 +03:00
# include "lib/messaging/irpc.h"
# include "librpc/gen_ndr/ndr_notify.h"
2006-08-30 15:29:34 +04:00
# include "lib/util/dlinklist.h"
2007-01-19 14:58:03 +03:00
# include "ntvfs/common/ntvfs_common.h"
2006-04-03 10:46:55 +04:00
# include "ntvfs/sysdep/sys_notify.h"
2007-01-10 16:25:39 +03:00
# include "cluster/cluster.h"
2007-12-14 00:46:23 +03:00
# include "param/param.h"
2006-03-21 14:47:24 +03:00
struct notify_context {
struct tdb_wrap * w ;
2007-01-10 13:52:09 +03:00
struct server_id server ;
2006-03-21 14:47:24 +03:00
struct messaging_context * messaging_ctx ;
struct notify_list * list ;
struct notify_array * array ;
2006-03-30 08:55:03 +04:00
int seqnum ;
2006-04-03 10:46:55 +04:00
struct sys_notify_context * sys_notify_ctx ;
2008-02-21 19:54:24 +03:00
struct smb_iconv_convenience * iconv_convenience ;
2006-03-21 14:47:24 +03:00
} ;
struct notify_list {
struct notify_list * next , * prev ;
2007-01-23 18:06:41 +03:00
void * private_data ;
2006-03-21 14:47:24 +03:00
void ( * callback ) ( void * , const struct notify_event * ) ;
2006-04-03 10:46:55 +04:00
void * sys_notify_handle ;
2006-04-07 14:36:54 +04:00
int depth ;
2006-03-21 14:47:24 +03:00
} ;
# define NOTIFY_KEY "notify array"
2006-07-23 22:43:07 +04:00
# define NOTIFY_ENABLE "notify:enable"
2007-10-07 02:28:14 +04:00
# define NOTIFY_ENABLE_DEFAULT true
2006-07-23 22:43:07 +04:00
2006-03-21 14:47:24 +03:00
static NTSTATUS notify_remove_all ( struct notify_context * notify ) ;
2007-01-23 18:06:41 +03:00
static void notify_handler ( struct messaging_context * msg_ctx , void * private_data ,
2007-01-10 13:52:09 +03:00
uint32_t msg_type , struct server_id server_id , DATA_BLOB * data ) ;
2006-03-21 14:47:24 +03:00
/*
destroy the notify context
*/
2006-05-24 11:34:11 +04:00
static int notify_destructor ( struct notify_context * notify )
2006-03-21 14:47:24 +03:00
{
messaging_deregister ( notify - > messaging_ctx , MSG_PVFS_NOTIFY , notify ) ;
notify_remove_all ( notify ) ;
return 0 ;
}
/*
Open up the notify . tdb database . You should close it down using
talloc_free ( ) . We need the messaging_ctx to allow for notifications
via internal messages
*/
2007-01-10 13:52:09 +03:00
struct notify_context * notify_init ( TALLOC_CTX * mem_ctx , struct server_id server ,
2006-04-03 10:46:55 +04:00
struct messaging_context * messaging_ctx ,
2007-12-14 00:46:55 +03:00
struct loadparm_context * lp_ctx ,
2006-07-23 22:43:07 +04:00
struct event_context * ev ,
struct share_config * scfg )
2006-03-21 14:47:24 +03:00
{
struct notify_context * notify ;
2007-10-07 02:28:14 +04:00
if ( share_bool_option ( scfg , NOTIFY_ENABLE , NOTIFY_ENABLE_DEFAULT ) ! = true ) {
2006-04-07 15:25:21 +04:00
return NULL ;
}
2008-04-17 03:19:53 +04:00
if ( ev = = NULL ) {
return NULL ;
}
2006-03-21 14:47:24 +03:00
notify = talloc ( mem_ctx , struct notify_context ) ;
if ( notify = = NULL ) {
return NULL ;
}
2007-12-14 00:46:55 +03:00
notify - > w = cluster_tdb_tmp_open ( notify , lp_ctx , " notify.tdb " , TDB_SEQNUM ) ;
2006-03-21 14:47:24 +03:00
if ( notify - > w = = NULL ) {
talloc_free ( notify ) ;
return NULL ;
}
notify - > server = server ;
notify - > messaging_ctx = messaging_ctx ;
notify - > list = NULL ;
notify - > array = NULL ;
2008-02-21 19:54:24 +03:00
notify - > iconv_convenience = lp_iconv_convenience ( lp_ctx ) ;
2006-03-30 08:55:03 +04:00
notify - > seqnum = tdb_get_seqnum ( notify - > w - > tdb ) ;
2006-03-21 14:47:24 +03:00
talloc_set_destructor ( notify , notify_destructor ) ;
/* register with the messaging subsystem for the notify
message type */
messaging_register ( notify - > messaging_ctx , notify ,
MSG_PVFS_NOTIFY , notify_handler ) ;
2006-07-23 22:43:07 +04:00
notify - > sys_notify_ctx = sys_notify_context_create ( scfg , notify , ev ) ;
2006-04-03 10:46:55 +04:00
2006-03-21 14:47:24 +03:00
return notify ;
}
2006-03-30 10:07:38 +04:00
/*
lock the notify db
*/
static NTSTATUS notify_lock ( struct notify_context * notify )
{
if ( tdb_lock_bystring ( notify - > w - > tdb , NOTIFY_KEY ) ! = 0 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
return NT_STATUS_OK ;
}
/*
unlock the notify db
*/
static void notify_unlock ( struct notify_context * notify )
{
tdb_unlock_bystring ( notify - > w - > tdb , NOTIFY_KEY ) ;
}
2006-03-21 14:47:24 +03:00
/*
load the notify array
*/
static NTSTATUS notify_load ( struct notify_context * notify )
{
TDB_DATA dbuf ;
DATA_BLOB blob ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2006-03-30 08:55:03 +04:00
int seqnum ;
seqnum = tdb_get_seqnum ( notify - > w - > tdb ) ;
if ( seqnum = = notify - > seqnum & & notify - > array ! = NULL ) {
return NT_STATUS_OK ;
}
notify - > seqnum = seqnum ;
2006-03-21 14:47:24 +03:00
talloc_free ( notify - > array ) ;
notify - > array = talloc_zero ( notify , struct notify_array ) ;
NT_STATUS_HAVE_NO_MEMORY ( notify - > array ) ;
dbuf = tdb_fetch_bystring ( notify - > w - > tdb , NOTIFY_KEY ) ;
if ( dbuf . dptr = = NULL ) {
return NT_STATUS_OK ;
}
blob . data = dbuf . dptr ;
blob . length = dbuf . dsize ;
2008-02-21 19:54:24 +03:00
ndr_err = ndr_pull_struct_blob ( & blob , notify - > array , notify - > iconv_convenience ,
2008-01-02 07:05:13 +03:00
notify - > array ,
2007-11-09 21:24:51 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_notify_array ) ;
2006-03-21 14:47:24 +03:00
free ( dbuf . dptr ) ;
2007-11-09 21:24:51 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2006-03-21 14:47:24 +03:00
2007-11-09 21:24:51 +03:00
return NT_STATUS_OK ;
2006-03-21 14:47:24 +03:00
}
2006-04-03 10:46:55 +04:00
/*
compare notify entries for sorting
*/
static int notify_compare ( const void * p1 , const void * p2 )
{
const struct notify_entry * e1 = p1 , * e2 = p2 ;
return strcmp ( e1 - > path , e2 - > path ) ;
}
2006-03-21 14:47:24 +03:00
/*
save the notify array
*/
static NTSTATUS notify_save ( struct notify_context * notify )
{
TDB_DATA dbuf ;
DATA_BLOB blob ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2006-03-21 14:47:24 +03:00
int ret ;
TALLOC_CTX * tmp_ctx ;
2006-04-07 14:36:54 +04:00
/* if possible, remove some depth arrays */
while ( notify - > array - > num_depths > 0 & &
notify - > array - > depth [ notify - > array - > num_depths - 1 ] . num_entries = = 0 ) {
notify - > array - > num_depths - - ;
}
/* we might just be able to delete the record */
if ( notify - > array - > num_depths = = 0 ) {
2006-03-21 14:47:24 +03:00
ret = tdb_delete_bystring ( notify - > w - > tdb , NOTIFY_KEY ) ;
if ( ret ! = 0 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
return NT_STATUS_OK ;
}
tmp_ctx = talloc_new ( notify ) ;
2007-01-23 23:57:50 +03:00
NT_STATUS_HAVE_NO_MEMORY ( tmp_ctx ) ;
2006-03-21 14:47:24 +03:00
2008-02-21 19:54:24 +03:00
ndr_err = ndr_push_struct_blob ( & blob , tmp_ctx , notify - > iconv_convenience , notify - > array ,
2007-11-09 21:24:51 +03:00
( ndr_push_flags_fn_t ) ndr_push_notify_array ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2006-03-21 14:47:24 +03:00
talloc_free ( tmp_ctx ) ;
2007-11-09 21:24:51 +03:00
return ndr_map_error2ntstatus ( ndr_err ) ;
2006-03-21 14:47:24 +03:00
}
dbuf . dptr = blob . data ;
dbuf . dsize = blob . length ;
ret = tdb_store_bystring ( notify - > w - > tdb , NOTIFY_KEY , dbuf , TDB_REPLACE ) ;
talloc_free ( tmp_ctx ) ;
if ( ret ! = 0 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
return NT_STATUS_OK ;
}
/*
handle incoming notify messages
*/
2007-01-23 18:06:41 +03:00
static void notify_handler ( struct messaging_context * msg_ctx , void * private_data ,
2007-01-10 13:52:09 +03:00
uint32_t msg_type , struct server_id server_id , DATA_BLOB * data )
2006-03-21 14:47:24 +03:00
{
2007-01-23 18:06:41 +03:00
struct notify_context * notify = talloc_get_type ( private_data , struct notify_context ) ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2006-03-21 14:47:24 +03:00
struct notify_event ev ;
TALLOC_CTX * tmp_ctx = talloc_new ( notify ) ;
struct notify_list * listel ;
2007-01-23 23:57:50 +03:00
if ( tmp_ctx = = NULL ) {
return ;
}
2008-02-21 19:54:24 +03:00
ndr_err = ndr_pull_struct_blob ( data , tmp_ctx , notify - > iconv_convenience , & ev ,
2006-03-21 14:47:24 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_notify_event ) ;
2007-11-09 21:24:51 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2006-03-21 14:47:24 +03:00
talloc_free ( tmp_ctx ) ;
return ;
}
for ( listel = notify - > list ; listel ; listel = listel - > next ) {
2007-01-23 18:06:41 +03:00
if ( listel - > private_data = = ev . private_data ) {
listel - > callback ( listel - > private_data , & ev ) ;
2006-03-21 14:47:24 +03:00
break ;
}
}
talloc_free ( tmp_ctx ) ;
}
2006-04-03 10:46:55 +04:00
/*
callback from sys_notify telling us about changes from the OS
*/
static void sys_notify_callback ( struct sys_notify_context * ctx ,
void * ptr , struct notify_event * ev )
{
struct notify_list * listel = talloc_get_type ( ptr , struct notify_list ) ;
2007-01-23 18:06:41 +03:00
ev - > private_data = listel ;
listel - > callback ( listel - > private_data , ev ) ;
2006-04-03 10:46:55 +04:00
}
2006-04-05 08:50:08 +04:00
/*
add an entry to the notify array
*/
static NTSTATUS notify_add_array ( struct notify_context * notify , struct notify_entry * e ,
2007-01-23 18:06:41 +03:00
void * private_data , int depth )
2006-04-05 08:50:08 +04:00
{
2006-04-07 14:36:54 +04:00
int i ;
struct notify_depth * d ;
struct notify_entry * ee ;
/* possibly expand the depths array */
if ( depth > = notify - > array - > num_depths ) {
d = talloc_realloc ( notify - > array , notify - > array - > depth ,
struct notify_depth , depth + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( d ) ;
for ( i = notify - > array - > num_depths ; i < = depth ; i + + ) {
ZERO_STRUCT ( d [ i ] ) ;
}
notify - > array - > depth = d ;
notify - > array - > num_depths = depth + 1 ;
}
d = & notify - > array - > depth [ depth ] ;
/* expand the entries array */
ee = talloc_realloc ( notify - > array - > depth , d - > entries , struct notify_entry ,
d - > num_entries + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( ee ) ;
d - > entries = ee ;
d - > entries [ d - > num_entries ] = * e ;
2007-01-23 18:06:41 +03:00
d - > entries [ d - > num_entries ] . private_data = private_data ;
2006-04-07 14:36:54 +04:00
d - > entries [ d - > num_entries ] . server = notify - > server ;
d - > entries [ d - > num_entries ] . path_len = strlen ( e - > path ) ;
d - > num_entries + + ;
d - > max_mask | = e - > filter ;
d - > max_mask_subdir | = e - > subdir_filter ;
if ( d - > num_entries > 1 ) {
qsort ( d - > entries , d - > num_entries , sizeof ( d - > entries [ 0 ] ) , notify_compare ) ;
}
/* recalculate the maximum masks */
d - > max_mask = 0 ;
d - > max_mask_subdir = 0 ;
for ( i = 0 ; i < d - > num_entries ; i + + ) {
d - > max_mask | = d - > entries [ i ] . filter ;
d - > max_mask_subdir | = d - > entries [ i ] . subdir_filter ;
}
2006-04-05 08:50:08 +04:00
return notify_save ( notify ) ;
}
2006-03-21 14:47:24 +03:00
/*
add a notify watch . This is called when a notify is first setup on a open
directory handle .
*/
2006-04-05 09:54:10 +04:00
NTSTATUS notify_add ( struct notify_context * notify , struct notify_entry * e0 ,
2006-03-21 14:47:24 +03:00
void ( * callback ) ( void * , const struct notify_event * ) ,
2007-01-23 18:06:41 +03:00
void * private_data )
2006-03-21 14:47:24 +03:00
{
2006-04-05 09:54:10 +04:00
struct notify_entry e = * e0 ;
2006-03-21 14:47:24 +03:00
NTSTATUS status ;
2006-04-06 17:51:44 +04:00
char * tmp_path = NULL ;
2006-03-21 14:47:24 +03:00
struct notify_list * listel ;
2006-03-30 09:45:43 +04:00
size_t len ;
2006-04-07 14:36:54 +04:00
int depth ;
2006-03-21 14:47:24 +03:00
2006-04-07 15:25:21 +04:00
/* see if change notify is enabled at all */
if ( notify = = NULL ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
2006-03-30 10:07:38 +04:00
status = notify_lock ( notify ) ;
2006-03-21 14:47:24 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-03-30 10:07:38 +04:00
status = notify_load ( notify ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-04-05 09:54:10 +04:00
goto done ;
2006-03-30 10:07:38 +04:00
}
2006-03-30 09:45:43 +04:00
/* cope with /. on the end of the path */
2006-04-05 09:54:10 +04:00
len = strlen ( e . path ) ;
if ( len > 1 & & e . path [ len - 1 ] = = ' . ' & & e . path [ len - 2 ] = = ' / ' ) {
2006-04-06 17:51:44 +04:00
tmp_path = talloc_strndup ( notify , e . path , len - 2 ) ;
if ( tmp_path = = NULL ) {
2006-04-05 09:54:10 +04:00
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
2006-04-06 17:51:44 +04:00
e . path = tmp_path ;
2006-03-30 09:45:43 +04:00
}
2006-04-07 14:36:54 +04:00
depth = count_chars ( e . path , ' / ' ) ;
2006-04-03 10:46:55 +04:00
listel = talloc_zero ( notify , struct notify_list ) ;
2006-04-05 09:54:10 +04:00
if ( listel = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
2006-03-30 09:45:43 +04:00
2007-01-23 18:06:41 +03:00
listel - > private_data = private_data ;
2006-04-03 10:46:55 +04:00
listel - > callback = callback ;
2006-04-07 14:36:54 +04:00
listel - > depth = depth ;
2006-04-03 10:46:55 +04:00
DLIST_ADD ( notify - > list , listel ) ;
2006-03-30 09:45:43 +04:00
2006-04-03 10:46:55 +04:00
/* ignore failures from sys_notify */
2006-04-05 08:50:08 +04:00
if ( notify - > sys_notify_ctx ! = NULL ) {
2006-04-05 09:54:10 +04:00
/*
this call will modify e . filter and e . subdir_filter
to remove bits handled by the backend
*/
status = sys_notify_watch ( notify - > sys_notify_ctx , & e ,
2006-04-05 08:50:08 +04:00
sys_notify_callback , listel ,
& listel - > sys_notify_handle ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
talloc_steal ( listel , listel - > sys_notify_handle ) ;
2006-04-03 10:46:55 +04:00
}
}
2006-03-21 14:47:24 +03:00
2006-04-05 09:54:10 +04:00
/* if the system notify handler couldn't handle some of the
filter bits , or couldn ' t handle a request for recursion
then we need to install it in the array used for the
intra - samba notify handling */
if ( e . filter ! = 0 | | e . subdir_filter ! = 0 ) {
2007-01-23 18:06:41 +03:00
status = notify_add_array ( notify , & e , private_data , depth ) ;
2006-04-05 09:54:10 +04:00
}
2006-04-05 08:50:08 +04:00
done :
notify_unlock ( notify ) ;
2006-04-06 17:51:44 +04:00
talloc_free ( tmp_path ) ;
2006-03-30 09:45:43 +04:00
2006-03-21 14:47:24 +03:00
return status ;
}
/*
remove a notify watch . Called when the directory handle is closed
*/
2007-01-23 18:06:41 +03:00
NTSTATUS notify_remove ( struct notify_context * notify , void * private_data )
2006-03-21 14:47:24 +03:00
{
NTSTATUS status ;
struct notify_list * listel ;
2006-04-07 14:36:54 +04:00
int i , depth ;
struct notify_depth * d ;
2006-03-21 14:47:24 +03:00
2006-04-07 15:25:21 +04:00
/* see if change notify is enabled at all */
if ( notify = = NULL ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
2006-03-21 14:47:24 +03:00
for ( listel = notify - > list ; listel ; listel = listel - > next ) {
2007-01-23 18:06:41 +03:00
if ( listel - > private_data = = private_data ) {
2006-03-21 14:47:24 +03:00
DLIST_REMOVE ( notify - > list , listel ) ;
break ;
}
}
if ( listel = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2006-04-07 14:36:54 +04:00
depth = listel - > depth ;
2006-04-03 10:46:55 +04:00
talloc_free ( listel ) ;
2006-03-30 10:07:38 +04:00
status = notify_lock ( notify ) ;
2006-03-21 14:47:24 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-03-30 10:07:38 +04:00
status = notify_load ( notify ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
notify_unlock ( notify ) ;
return status ;
}
2006-05-22 10:18:40 +04:00
if ( depth > = notify - > array - > num_depths ) {
notify_unlock ( notify ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2006-04-07 14:36:54 +04:00
/* we only have to search at the depth of this element */
d = & notify - > array - > depth [ depth ] ;
for ( i = 0 ; i < d - > num_entries ; i + + ) {
2007-01-23 18:06:41 +03:00
if ( private_data = = d - > entries [ i ] . private_data & &
2007-01-10 13:52:09 +03:00
cluster_id_equal ( & notify - > server , & d - > entries [ i ] . server ) ) {
2006-03-21 14:47:24 +03:00
break ;
}
}
2006-04-07 14:36:54 +04:00
if ( i = = d - > num_entries ) {
2006-03-30 10:07:38 +04:00
notify_unlock ( notify ) ;
2006-03-21 14:47:24 +03:00
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2006-04-07 14:36:54 +04:00
if ( i < d - > num_entries - 1 ) {
memmove ( & d - > entries [ i ] , & d - > entries [ i + 1 ] ,
sizeof ( d - > entries [ i ] ) * ( d - > num_entries - ( i + 1 ) ) ) ;
2006-03-21 14:47:24 +03:00
}
2006-04-07 14:36:54 +04:00
d - > num_entries - - ;
2006-03-21 14:47:24 +03:00
2006-03-30 10:07:38 +04:00
status = notify_save ( notify ) ;
notify_unlock ( notify ) ;
return status ;
2006-03-21 14:47:24 +03:00
}
/*
remove all notify watches for this messaging server
*/
static NTSTATUS notify_remove_all ( struct notify_context * notify )
{
NTSTATUS status ;
2006-04-07 14:36:54 +04:00
int i , depth , del_count = 0 ;
2006-03-21 14:47:24 +03:00
if ( notify - > list = = NULL ) {
return NT_STATUS_OK ;
}
2006-03-30 10:07:38 +04:00
status = notify_lock ( notify ) ;
2006-03-21 14:47:24 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-03-30 10:07:38 +04:00
status = notify_load ( notify ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
notify_unlock ( notify ) ;
return status ;
}
2006-04-07 14:36:54 +04:00
/* we have to search for all entries across all depths, looking for matches
for our server id */
for ( depth = 0 ; depth < notify - > array - > num_depths ; depth + + ) {
struct notify_depth * d = & notify - > array - > depth [ depth ] ;
for ( i = 0 ; i < d - > num_entries ; i + + ) {
2007-01-10 13:52:09 +03:00
if ( cluster_id_equal ( & notify - > server , & d - > entries [ i ] . server ) ) {
2006-04-07 14:36:54 +04:00
if ( i < d - > num_entries - 1 ) {
memmove ( & d - > entries [ i ] , & d - > entries [ i + 1 ] ,
sizeof ( d - > entries [ i ] ) * ( d - > num_entries - ( i + 1 ) ) ) ;
}
i - - ;
d - > num_entries - - ;
del_count + + ;
2006-03-21 14:47:24 +03:00
}
}
}
2006-04-07 14:36:54 +04:00
if ( del_count > 0 ) {
status = notify_save ( notify ) ;
}
2006-03-30 10:07:38 +04:00
notify_unlock ( notify ) ;
return status ;
2006-03-21 14:47:24 +03:00
}
2006-04-03 10:46:55 +04:00
/*
send a notify message to another messaging server
*/
static void notify_send ( struct notify_context * notify , struct notify_entry * e ,
const char * path , uint32_t action )
{
struct notify_event ev ;
DATA_BLOB data ;
NTSTATUS status ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2006-04-03 10:46:55 +04:00
TALLOC_CTX * tmp_ctx ;
ev . action = action ;
ev . path = path ;
2007-01-23 18:06:41 +03:00
ev . private_data = e - > private_data ;
2006-04-03 10:46:55 +04:00
tmp_ctx = talloc_new ( notify ) ;
2008-02-21 19:54:24 +03:00
ndr_err = ndr_push_struct_blob ( & data , tmp_ctx , notify - > iconv_convenience , & ev , ( ndr_push_flags_fn_t ) ndr_push_notify_event ) ;
2007-11-09 21:24:51 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2006-04-03 10:46:55 +04:00
talloc_free ( tmp_ctx ) ;
return ;
}
status = messaging_send ( notify - > messaging_ctx , e - > server ,
MSG_PVFS_NOTIFY , & data ) ;
talloc_free ( tmp_ctx ) ;
}
2006-03-21 14:47:24 +03:00
/*
trigger a notify message for anyone waiting on a matching event
2006-04-07 14:36:54 +04:00
This function is called a lot , and needs to be very fast . The unusual data structure
and traversal is designed to be fast in the average case , even for large numbers of
notifies
2006-03-21 14:47:24 +03:00
*/
void notify_trigger ( struct notify_context * notify ,
2006-03-30 07:51:49 +04:00
uint32_t action , uint32_t filter , const char * path )
2006-03-21 14:47:24 +03:00
{
NTSTATUS status ;
2006-04-07 14:36:54 +04:00
int depth ;
const char * p , * next_p ;
2006-03-21 14:47:24 +03:00
2006-04-07 15:25:21 +04:00
/* see if change notify is enabled at all */
if ( notify = = NULL ) {
return ;
}
2006-03-21 14:47:24 +03:00
status = notify_load ( notify ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ;
}
2006-04-07 14:36:54 +04:00
/* loop along the given path, working with each directory depth separately */
for ( depth = 0 , p = path ;
p & & depth < notify - > array - > num_depths ;
p = next_p , depth + + ) {
int p_len = p - path ;
int min_i , max_i , i ;
struct notify_depth * d = & notify - > array - > depth [ depth ] ;
next_p = strchr ( p + 1 , ' / ' ) ;
/* see if there are any entries at this depth */
if ( d - > num_entries = = 0 ) continue ;
/* try to skip based on the maximum mask. If next_p is
NULL then we know it will be a ' this directory '
match , otherwise it must be a subdir match */
if ( next_p ! = NULL ) {
if ( 0 = = ( filter & d - > max_mask_subdir ) ) {
continue ;
}
} else {
if ( 0 = = ( filter & d - > max_mask ) ) {
continue ;
}
}
/* we know there is an entry here worth looking
for . Use a bisection search to find the first entry
with a matching path */
min_i = 0 ;
max_i = d - > num_entries - 1 ;
while ( min_i < max_i ) {
struct notify_entry * e ;
2006-04-07 15:44:55 +04:00
int cmp ;
2006-04-07 14:36:54 +04:00
i = ( min_i + max_i ) / 2 ;
e = & d - > entries [ i ] ;
2006-04-07 15:44:55 +04:00
cmp = strncmp ( path , e - > path , p_len ) ;
2006-04-07 14:36:54 +04:00
if ( cmp = = 0 ) {
if ( p_len = = e - > path_len ) {
max_i = i ;
} else {
max_i = i - 1 ;
}
} else if ( cmp < 0 ) {
max_i = i - 1 ;
} else {
min_i = i + 1 ;
}
}
if ( min_i ! = max_i ) {
/* none match */
continue ;
}
/* we now know that the entries start at min_i */
for ( i = min_i ; i < d - > num_entries ; i + + ) {
struct notify_entry * e = & d - > entries [ i ] ;
if ( p_len ! = e - > path_len | |
strncmp ( path , e - > path , p_len ) ! = 0 ) break ;
if ( next_p ! = NULL ) {
if ( 0 = = ( filter & e - > subdir_filter ) ) {
continue ;
}
} else {
if ( 0 = = ( filter & e - > filter ) ) {
continue ;
}
}
notify_send ( notify , e , path + e - > path_len + 1 , action ) ;
2006-03-21 14:47:24 +03:00
}
}
}