server: Fill in NtNotifyChangeDirectoryFile's buffer with change data.
This commit is contained in:
parent
acb52e5272
commit
0193211946
|
@ -136,33 +136,46 @@ BOOL WINAPI ReadDirectoryChangesW( HANDLE handle, LPVOID buffer, DWORD len, BOOL
|
||||||
DWORD filter, LPDWORD returned, LPOVERLAPPED overlapped,
|
DWORD filter, LPDWORD returned, LPOVERLAPPED overlapped,
|
||||||
LPOVERLAPPED_COMPLETION_ROUTINE completion )
|
LPOVERLAPPED_COMPLETION_ROUTINE completion )
|
||||||
{
|
{
|
||||||
IO_STATUS_BLOCK io;
|
OVERLAPPED ov, *pov;
|
||||||
|
IO_STATUS_BLOCK *ios;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
BOOL ret = TRUE;
|
BOOL ret = TRUE;
|
||||||
HANDLE event;
|
|
||||||
|
|
||||||
TRACE("%p %p %08lx %d %08lx %p %p %p\n", handle, buffer, len, subtree, filter,
|
TRACE("%p %p %08lx %d %08lx %p %p %p\n", handle, buffer, len, subtree, filter,
|
||||||
returned, overlapped, completion );
|
returned, overlapped, completion );
|
||||||
|
|
||||||
if (overlapped)
|
if (!overlapped)
|
||||||
event = overlapped->hEvent;
|
{
|
||||||
|
memset( &ov, 0, sizeof ov );
|
||||||
|
ov.hEvent = CreateEventW( NULL, 0, 0, NULL );
|
||||||
|
pov = &ov;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
event = CreateEventW( NULL, 0, 0, NULL );
|
pov = overlapped;
|
||||||
|
|
||||||
status = NtNotifyChangeDirectoryFile( handle, event, NULL, NULL,
|
ios = (PIO_STATUS_BLOCK) pov;
|
||||||
&io, buffer, len, filter, subtree );
|
ios->Status = STATUS_PENDING;
|
||||||
if (status != STATUS_PENDING)
|
ios->Information = 0;
|
||||||
|
|
||||||
|
status = NtNotifyChangeDirectoryFile( handle, pov->hEvent, NULL, NULL,
|
||||||
|
ios, buffer, len, filter, subtree );
|
||||||
|
if (status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
if (overlapped)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
WaitForSingleObjectEx( ov.hEvent, INFINITE, TRUE );
|
||||||
|
CloseHandle( ov.hEvent );
|
||||||
|
if (returned)
|
||||||
|
*returned = ios->Information;
|
||||||
|
status = ios->Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
SetLastError( RtlNtStatusToDosError(status) );
|
SetLastError( RtlNtStatusToDosError(status) );
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
else if (!overlapped)
|
|
||||||
WaitForSingleObject( event, INFINITE );
|
|
||||||
else
|
|
||||||
overlapped->Internal = STATUS_PENDING;
|
|
||||||
|
|
||||||
if (!overlapped)
|
|
||||||
CloseHandle( event );
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1778,6 +1778,75 @@ done:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct read_changes_info
|
||||||
|
{
|
||||||
|
HANDLE FileHandle;
|
||||||
|
HANDLE Event;
|
||||||
|
PIO_APC_ROUTINE ApcRoutine;
|
||||||
|
PVOID ApcContext;
|
||||||
|
PVOID Buffer;
|
||||||
|
ULONG BufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void WINAPI read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, ULONG status )
|
||||||
|
{
|
||||||
|
struct read_changes_info *info = user;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
NTSTATUS ret = STATUS_SUCCESS;
|
||||||
|
int len, action;
|
||||||
|
|
||||||
|
TRACE("%p %p %p %08lx\n", info, info->ApcContext, iosb, status);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: race me!
|
||||||
|
*
|
||||||
|
* hEvent/hDir is set before the output buffer and iosb is updated.
|
||||||
|
* Since the thread that called NtNotifyChangeDirectoryFile is usually
|
||||||
|
* waiting, we'll be safe since we're called in that thread's context.
|
||||||
|
* If a different thread is waiting on our hEvent/hDir we're going to be
|
||||||
|
* in trouble...
|
||||||
|
*/
|
||||||
|
SERVER_START_REQ( read_change )
|
||||||
|
{
|
||||||
|
req->handle = info->FileHandle;
|
||||||
|
wine_server_set_reply( req, path, PATH_MAX );
|
||||||
|
ret = wine_server_call( req );
|
||||||
|
action = reply->action;
|
||||||
|
len = wine_server_reply_size( reply );
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
if (ret == STATUS_SUCCESS && info->Buffer &&
|
||||||
|
(info->BufferSize > (sizeof (FILE_NOTIFY_INFORMATION) + len*sizeof(WCHAR))))
|
||||||
|
{
|
||||||
|
PFILE_NOTIFY_INFORMATION pfni;
|
||||||
|
|
||||||
|
pfni = (PFILE_NOTIFY_INFORMATION) info->Buffer;
|
||||||
|
|
||||||
|
len = ntdll_umbstowcs( 0, path, len, pfni->FileName,
|
||||||
|
info->BufferSize - sizeof (*pfni) );
|
||||||
|
|
||||||
|
pfni->NextEntryOffset = 0;
|
||||||
|
pfni->Action = action;
|
||||||
|
pfni->FileNameLength = len * sizeof (WCHAR);
|
||||||
|
pfni->FileName[len] = 0;
|
||||||
|
|
||||||
|
TRACE("action = %ld name = %s\n", pfni->Action,
|
||||||
|
debugstr_w(pfni->FileName) );
|
||||||
|
len = sizeof (*pfni) - sizeof (DWORD) + pfni->FileNameLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = STATUS_NOTIFY_ENUM_DIR;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iosb->u.Status = ret;
|
||||||
|
iosb->Information = len;
|
||||||
|
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, info );
|
||||||
|
}
|
||||||
|
|
||||||
#define FILE_NOTIFY_ALL ( \
|
#define FILE_NOTIFY_ALL ( \
|
||||||
FILE_NOTIFY_CHANGE_FILE_NAME | \
|
FILE_NOTIFY_CHANGE_FILE_NAME | \
|
||||||
FILE_NOTIFY_CHANGE_DIR_NAME | \
|
FILE_NOTIFY_CHANGE_DIR_NAME | \
|
||||||
|
@ -1797,6 +1866,7 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event,
|
||||||
PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer,
|
PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer,
|
||||||
ULONG BufferSize, ULONG CompletionFilter, BOOLEAN WatchTree )
|
ULONG BufferSize, ULONG CompletionFilter, BOOLEAN WatchTree )
|
||||||
{
|
{
|
||||||
|
struct read_changes_info *info;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
TRACE("%p %p %p %p %p %p %lu %lu %d\n",
|
TRACE("%p %p %p %p %p %p %lu %lu %d\n",
|
||||||
|
@ -1809,18 +1879,35 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event,
|
||||||
if (CompletionFilter == 0 || (CompletionFilter & ~FILE_NOTIFY_ALL))
|
if (CompletionFilter == 0 || (CompletionFilter & ~FILE_NOTIFY_ALL))
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
if (ApcRoutine || ApcContext || Buffer || BufferSize || WatchTree)
|
if (WatchTree || ApcRoutine)
|
||||||
FIXME("parameters ignored %p %p %p %lu %d\n",
|
FIXME("parameters ignored %p %p %d\n",
|
||||||
ApcRoutine, ApcContext, Buffer, BufferSize, WatchTree );
|
ApcRoutine, ApcContext, WatchTree );
|
||||||
|
|
||||||
|
info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof *info );
|
||||||
|
if (!info)
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
info->FileHandle = FileHandle;
|
||||||
|
info->Event = Event;
|
||||||
|
info->Buffer = Buffer;
|
||||||
|
info->BufferSize = BufferSize;
|
||||||
|
info->ApcRoutine = ApcRoutine;
|
||||||
|
info->ApcContext = ApcContext;
|
||||||
|
|
||||||
SERVER_START_REQ( read_directory_changes )
|
SERVER_START_REQ( read_directory_changes )
|
||||||
{
|
{
|
||||||
req->handle = FileHandle;
|
req->handle = FileHandle;
|
||||||
req->event = Event;
|
req->event = Event;
|
||||||
req->filter = CompletionFilter;
|
req->filter = CompletionFilter;
|
||||||
|
req->io_apc = read_changes_apc;
|
||||||
|
req->io_sb = IoStatusBlock;
|
||||||
|
req->io_user = info;
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
if (status != STATUS_PENDING)
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, info );
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1401,6 +1401,9 @@ struct read_directory_changes_request
|
||||||
obj_handle_t handle;
|
obj_handle_t handle;
|
||||||
obj_handle_t event;
|
obj_handle_t event;
|
||||||
unsigned int filter;
|
unsigned int filter;
|
||||||
|
void* io_apc;
|
||||||
|
void* io_sb;
|
||||||
|
void* io_user;
|
||||||
};
|
};
|
||||||
struct read_directory_changes_reply
|
struct read_directory_changes_reply
|
||||||
{
|
{
|
||||||
|
@ -1408,6 +1411,19 @@ struct read_directory_changes_reply
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct read_change_request
|
||||||
|
{
|
||||||
|
struct request_header __header;
|
||||||
|
obj_handle_t handle;
|
||||||
|
};
|
||||||
|
struct read_change_reply
|
||||||
|
{
|
||||||
|
struct reply_header __header;
|
||||||
|
int action;
|
||||||
|
/* VARARG(name,string); */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct create_mapping_request
|
struct create_mapping_request
|
||||||
{
|
{
|
||||||
|
@ -3768,6 +3784,7 @@ enum request
|
||||||
REQ_move_console_output,
|
REQ_move_console_output,
|
||||||
REQ_send_console_signal,
|
REQ_send_console_signal,
|
||||||
REQ_read_directory_changes,
|
REQ_read_directory_changes,
|
||||||
|
REQ_read_change,
|
||||||
REQ_create_mapping,
|
REQ_create_mapping,
|
||||||
REQ_open_mapping,
|
REQ_open_mapping,
|
||||||
REQ_get_mapping_info,
|
REQ_get_mapping_info,
|
||||||
|
@ -3986,6 +4003,7 @@ union generic_request
|
||||||
struct move_console_output_request move_console_output_request;
|
struct move_console_output_request move_console_output_request;
|
||||||
struct send_console_signal_request send_console_signal_request;
|
struct send_console_signal_request send_console_signal_request;
|
||||||
struct read_directory_changes_request read_directory_changes_request;
|
struct read_directory_changes_request read_directory_changes_request;
|
||||||
|
struct read_change_request read_change_request;
|
||||||
struct create_mapping_request create_mapping_request;
|
struct create_mapping_request create_mapping_request;
|
||||||
struct open_mapping_request open_mapping_request;
|
struct open_mapping_request open_mapping_request;
|
||||||
struct get_mapping_info_request get_mapping_info_request;
|
struct get_mapping_info_request get_mapping_info_request;
|
||||||
|
@ -4202,6 +4220,7 @@ union generic_reply
|
||||||
struct move_console_output_reply move_console_output_reply;
|
struct move_console_output_reply move_console_output_reply;
|
||||||
struct send_console_signal_reply send_console_signal_reply;
|
struct send_console_signal_reply send_console_signal_reply;
|
||||||
struct read_directory_changes_reply read_directory_changes_reply;
|
struct read_directory_changes_reply read_directory_changes_reply;
|
||||||
|
struct read_change_reply read_change_reply;
|
||||||
struct create_mapping_reply create_mapping_reply;
|
struct create_mapping_reply create_mapping_reply;
|
||||||
struct open_mapping_reply open_mapping_reply;
|
struct open_mapping_reply open_mapping_reply;
|
||||||
struct get_mapping_info_reply get_mapping_info_reply;
|
struct get_mapping_info_reply get_mapping_info_reply;
|
||||||
|
@ -4344,6 +4363,6 @@ union generic_reply
|
||||||
struct query_symlink_reply query_symlink_reply;
|
struct query_symlink_reply query_symlink_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 223
|
#define SERVER_PROTOCOL_VERSION 224
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -126,6 +126,13 @@ static inline int inotify_remove_watch( int fd, int wd )
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct change_record {
|
||||||
|
struct list entry;
|
||||||
|
int action;
|
||||||
|
int len;
|
||||||
|
char name[1];
|
||||||
|
};
|
||||||
|
|
||||||
struct dir
|
struct dir
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
|
@ -137,6 +144,8 @@ struct dir
|
||||||
long signaled; /* the file changed */
|
long signaled; /* the file changed */
|
||||||
struct fd *inotify_fd; /* inotify file descriptor */
|
struct fd *inotify_fd; /* inotify file descriptor */
|
||||||
int wd; /* inotify watch descriptor */
|
int wd; /* inotify watch descriptor */
|
||||||
|
struct list change_q; /* change readers */
|
||||||
|
struct list change_records; /* data for the change */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct fd *dir_get_fd( struct object *obj );
|
static struct fd *dir_get_fd( struct object *obj );
|
||||||
|
@ -163,6 +172,7 @@ static const struct object_ops dir_ops =
|
||||||
|
|
||||||
static int dir_get_poll_events( struct fd *fd );
|
static int dir_get_poll_events( struct fd *fd );
|
||||||
static int dir_get_info( struct fd *fd );
|
static int dir_get_info( struct fd *fd );
|
||||||
|
static void dir_cancel_async( struct fd *fd );
|
||||||
|
|
||||||
static const struct fd_ops dir_fd_ops =
|
static const struct fd_ops dir_fd_ops =
|
||||||
{
|
{
|
||||||
|
@ -171,7 +181,7 @@ static const struct fd_ops dir_fd_ops =
|
||||||
no_flush, /* flush */
|
no_flush, /* flush */
|
||||||
dir_get_info, /* get_file_info */
|
dir_get_info, /* get_file_info */
|
||||||
default_fd_queue_async, /* queue_async */
|
default_fd_queue_async, /* queue_async */
|
||||||
default_fd_cancel_async /* cancel_async */
|
dir_cancel_async /* cancel_async */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct list change_list = LIST_INIT(change_list);
|
static struct list change_list = LIST_INIT(change_list);
|
||||||
|
@ -238,6 +248,8 @@ struct object *create_dir_obj( struct fd *fd )
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
list_init( &dir->change_q );
|
||||||
|
list_init( &dir->change_records );
|
||||||
dir->event = NULL;
|
dir->event = NULL;
|
||||||
dir->filter = 0;
|
dir->filter = 0;
|
||||||
dir->notified = 0;
|
dir->notified = 0;
|
||||||
|
@ -321,8 +333,17 @@ static unsigned int dir_map_access( struct object *obj, unsigned int access )
|
||||||
return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
|
return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct change_record *get_first_change_record( struct dir *dir )
|
||||||
|
{
|
||||||
|
struct list *ptr = list_head( &dir->change_records );
|
||||||
|
if (!ptr) return NULL;
|
||||||
|
list_remove( ptr );
|
||||||
|
return LIST_ENTRY( ptr, struct change_record, entry );
|
||||||
|
}
|
||||||
|
|
||||||
static void dir_destroy( struct object *obj )
|
static void dir_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
|
struct change_record *record;
|
||||||
struct dir *dir = (struct dir *)obj;
|
struct dir *dir = (struct dir *)obj;
|
||||||
assert (obj->ops == &dir_ops);
|
assert (obj->ops == &dir_ops);
|
||||||
|
|
||||||
|
@ -332,6 +353,9 @@ static void dir_destroy( struct object *obj )
|
||||||
if (dir->inotify_fd)
|
if (dir->inotify_fd)
|
||||||
release_object( dir->inotify_fd );
|
release_object( dir->inotify_fd );
|
||||||
|
|
||||||
|
async_terminate_queue( &dir->change_q, STATUS_CANCELLED );
|
||||||
|
while ((record = get_first_change_record( dir ))) free( record );
|
||||||
|
|
||||||
if (dir->event)
|
if (dir->event)
|
||||||
{
|
{
|
||||||
set_event( dir->event );
|
set_event( dir->event );
|
||||||
|
@ -356,6 +380,12 @@ static int dir_get_info( struct fd *fd )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dir_cancel_async( struct fd *fd )
|
||||||
|
{
|
||||||
|
struct dir *dir = (struct dir *) get_fd_user( fd );
|
||||||
|
async_terminate_queue( &dir->change_q, STATUS_CANCELLED );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_INOTIFY
|
#ifdef USE_INOTIFY
|
||||||
|
|
||||||
|
@ -378,10 +408,32 @@ static int inotify_get_poll_events( struct fd *fd )
|
||||||
return POLLIN;
|
return POLLIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inotify_do_change_notify( struct dir *dir )
|
static void inotify_do_change_notify( struct dir *dir, struct inotify_event *ie )
|
||||||
{
|
{
|
||||||
dir->signaled++;
|
struct change_record *record;
|
||||||
dir_signal_changed( dir );
|
|
||||||
|
record = malloc( sizeof (*record) + ie->len - 1 ) ;
|
||||||
|
if (!record)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( ie->mask & IN_CREATE )
|
||||||
|
record->action = FILE_ACTION_ADDED;
|
||||||
|
else if( ie->mask & IN_DELETE )
|
||||||
|
record->action = FILE_ACTION_REMOVED;
|
||||||
|
else
|
||||||
|
record->action = FILE_ACTION_MODIFIED;
|
||||||
|
memcpy( record->name, ie->name, ie->len );
|
||||||
|
record->len = strlen( ie->name );
|
||||||
|
|
||||||
|
list_add_tail( &dir->change_records, &record->entry );
|
||||||
|
|
||||||
|
if (!list_empty( &dir->change_q ))
|
||||||
|
async_terminate_head( &dir->change_q, STATUS_ALERTED );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dir->signaled++;
|
||||||
|
dir_signal_changed( dir );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inotify_poll_event( struct fd *fd, int event )
|
static void inotify_poll_event( struct fd *fd, int event )
|
||||||
|
@ -404,7 +456,7 @@ static void inotify_poll_event( struct fd *fd, int event )
|
||||||
ie = (struct inotify_event*) &buffer[ofs];
|
ie = (struct inotify_event*) &buffer[ofs];
|
||||||
if (!ie->len)
|
if (!ie->len)
|
||||||
break;
|
break;
|
||||||
inotify_do_change_notify( dir );
|
inotify_do_change_notify( dir, ie );
|
||||||
ofs += (sizeof (*ie) + ie->len - 1);
|
ofs += (sizeof (*ie) + ie->len - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,6 +541,11 @@ DECL_HANDLER(read_directory_changes)
|
||||||
if (dir->event) release_object( dir->event );
|
if (dir->event) release_object( dir->event );
|
||||||
dir->event = event;
|
dir->event = event;
|
||||||
|
|
||||||
|
/* requests don't timeout */
|
||||||
|
if ( req->io_apc && !create_async( current, NULL, &dir->change_q,
|
||||||
|
req->io_apc, req->io_user, req->io_sb ))
|
||||||
|
return;
|
||||||
|
|
||||||
/* assign it once */
|
/* assign it once */
|
||||||
if (!dir->filter)
|
if (!dir->filter)
|
||||||
{
|
{
|
||||||
|
@ -511,3 +568,28 @@ DECL_HANDLER(read_directory_changes)
|
||||||
end:
|
end:
|
||||||
release_object( dir );
|
release_object( dir );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECL_HANDLER(read_change)
|
||||||
|
{
|
||||||
|
struct change_record *record;
|
||||||
|
struct dir *dir;
|
||||||
|
|
||||||
|
dir = get_dir_obj( current->process, req->handle, 0 );
|
||||||
|
if (!dir)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((record = get_first_change_record( dir )) != NULL)
|
||||||
|
{
|
||||||
|
reply->action = record->action;
|
||||||
|
set_reply_data( record->name, record->len );
|
||||||
|
free( record );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_error( STATUS_NO_DATA_DETECTED );
|
||||||
|
|
||||||
|
/* now signal it */
|
||||||
|
dir->signaled++;
|
||||||
|
dir_signal_changed( dir );
|
||||||
|
|
||||||
|
release_object( dir );
|
||||||
|
}
|
||||||
|
|
|
@ -1045,6 +1045,17 @@ enum char_info_mode
|
||||||
obj_handle_t handle; /* handle to the directory */
|
obj_handle_t handle; /* handle to the directory */
|
||||||
obj_handle_t event; /* handle to the event */
|
obj_handle_t event; /* handle to the event */
|
||||||
unsigned int filter; /* notification filter */
|
unsigned int filter; /* notification filter */
|
||||||
|
void* io_apc; /* APC routine to queue upon end of async */
|
||||||
|
void* io_sb; /* I/O status block (unique across all async on this handle) */
|
||||||
|
void* io_user; /* data to pass back to caller */
|
||||||
|
@END
|
||||||
|
|
||||||
|
|
||||||
|
@REQ(read_change)
|
||||||
|
obj_handle_t handle;
|
||||||
|
@REPLY
|
||||||
|
int action; /* type of change */
|
||||||
|
VARARG(name,string); /* name of directory entry that changed */
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,7 @@ DECL_HANDLER(read_console_output);
|
||||||
DECL_HANDLER(move_console_output);
|
DECL_HANDLER(move_console_output);
|
||||||
DECL_HANDLER(send_console_signal);
|
DECL_HANDLER(send_console_signal);
|
||||||
DECL_HANDLER(read_directory_changes);
|
DECL_HANDLER(read_directory_changes);
|
||||||
|
DECL_HANDLER(read_change);
|
||||||
DECL_HANDLER(create_mapping);
|
DECL_HANDLER(create_mapping);
|
||||||
DECL_HANDLER(open_mapping);
|
DECL_HANDLER(open_mapping);
|
||||||
DECL_HANDLER(get_mapping_info);
|
DECL_HANDLER(get_mapping_info);
|
||||||
|
@ -398,6 +399,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
||||||
(req_handler)req_move_console_output,
|
(req_handler)req_move_console_output,
|
||||||
(req_handler)req_send_console_signal,
|
(req_handler)req_send_console_signal,
|
||||||
(req_handler)req_read_directory_changes,
|
(req_handler)req_read_directory_changes,
|
||||||
|
(req_handler)req_read_change,
|
||||||
(req_handler)req_create_mapping,
|
(req_handler)req_create_mapping,
|
||||||
(req_handler)req_open_mapping,
|
(req_handler)req_open_mapping,
|
||||||
(req_handler)req_get_mapping_info,
|
(req_handler)req_get_mapping_info,
|
||||||
|
|
|
@ -1448,7 +1448,22 @@ static void dump_read_directory_changes_request( const struct read_directory_cha
|
||||||
{
|
{
|
||||||
fprintf( stderr, " handle=%p,", req->handle );
|
fprintf( stderr, " handle=%p,", req->handle );
|
||||||
fprintf( stderr, " event=%p,", req->event );
|
fprintf( stderr, " event=%p,", req->event );
|
||||||
fprintf( stderr, " filter=%08x", req->filter );
|
fprintf( stderr, " filter=%08x,", req->filter );
|
||||||
|
fprintf( stderr, " io_apc=%p,", req->io_apc );
|
||||||
|
fprintf( stderr, " io_sb=%p,", req->io_sb );
|
||||||
|
fprintf( stderr, " io_user=%p", req->io_user );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_read_change_request( const struct read_change_request *req )
|
||||||
|
{
|
||||||
|
fprintf( stderr, " handle=%p", req->handle );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_read_change_reply( const struct read_change_reply *req )
|
||||||
|
{
|
||||||
|
fprintf( stderr, " action=%d,", req->action );
|
||||||
|
fprintf( stderr, " name=" );
|
||||||
|
dump_varargs_string( cur_size );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_create_mapping_request( const struct create_mapping_request *req )
|
static void dump_create_mapping_request( const struct create_mapping_request *req )
|
||||||
|
@ -3274,6 +3289,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_move_console_output_request,
|
(dump_func)dump_move_console_output_request,
|
||||||
(dump_func)dump_send_console_signal_request,
|
(dump_func)dump_send_console_signal_request,
|
||||||
(dump_func)dump_read_directory_changes_request,
|
(dump_func)dump_read_directory_changes_request,
|
||||||
|
(dump_func)dump_read_change_request,
|
||||||
(dump_func)dump_create_mapping_request,
|
(dump_func)dump_create_mapping_request,
|
||||||
(dump_func)dump_open_mapping_request,
|
(dump_func)dump_open_mapping_request,
|
||||||
(dump_func)dump_get_mapping_info_request,
|
(dump_func)dump_get_mapping_info_request,
|
||||||
|
@ -3488,6 +3504,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)0,
|
(dump_func)0,
|
||||||
(dump_func)0,
|
(dump_func)0,
|
||||||
(dump_func)0,
|
(dump_func)0,
|
||||||
|
(dump_func)dump_read_change_reply,
|
||||||
(dump_func)dump_create_mapping_reply,
|
(dump_func)dump_create_mapping_reply,
|
||||||
(dump_func)dump_open_mapping_reply,
|
(dump_func)dump_open_mapping_reply,
|
||||||
(dump_func)dump_get_mapping_info_reply,
|
(dump_func)dump_get_mapping_info_reply,
|
||||||
|
@ -3702,6 +3719,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
"move_console_output",
|
"move_console_output",
|
||||||
"send_console_signal",
|
"send_console_signal",
|
||||||
"read_directory_changes",
|
"read_directory_changes",
|
||||||
|
"read_change",
|
||||||
"create_mapping",
|
"create_mapping",
|
||||||
"open_mapping",
|
"open_mapping",
|
||||||
"get_mapping_info",
|
"get_mapping_info",
|
||||||
|
|
Loading…
Reference in New Issue