server: Return multiple events in read_changes.

This commit is contained in:
Piotr Caban 2011-01-18 11:24:33 +01:00 committed by Alexandre Julliard
parent 92ac7861f5
commit b614a15328
6 changed files with 131 additions and 48 deletions

View File

@ -2902,49 +2902,72 @@ static void WINAPI read_changes_user_apc( void *arg, IO_STATUS_BLOCK *io, ULONG
static NTSTATUS read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc )
{
struct read_changes_info *info = user;
char path[PATH_MAX];
NTSTATUS ret = STATUS_SUCCESS;
int len, action, i;
char data[PATH_MAX];
NTSTATUS ret;
int size;
SERVER_START_REQ( read_change )
{
req->handle = wine_server_obj_handle( info->FileHandle );
wine_server_set_reply( req, path, PATH_MAX );
wine_server_set_reply( req, data, PATH_MAX );
ret = wine_server_call( req );
action = reply->action;
len = wine_server_reply_size( reply );
size = wine_server_reply_size( reply );
}
SERVER_END_REQ;
if (ret == STATUS_SUCCESS && info->Buffer &&
(info->BufferSize > (sizeof (FILE_NOTIFY_INFORMATION) + len*sizeof(WCHAR))))
if (ret == STATUS_SUCCESS && info->Buffer)
{
PFILE_NOTIFY_INFORMATION pfni;
PFILE_NOTIFY_INFORMATION pfni = info->Buffer;
int i, left = info->BufferSize;
DWORD *last_entry_offset = NULL;
struct filesystem_event *event = (struct filesystem_event*)data;
pfni = info->Buffer;
while (size && left >= sizeof(*pfni))
{
/* convert to an NT style path */
for (i=0; i<event->len; i++)
if (event->name[i] == '/')
event->name[i] = '\\';
/* convert to an NT style path */
for (i=0; i<len; i++)
if (path[i] == '/')
path[i] = '\\';
pfni->Action = event->action;
pfni->FileNameLength = ntdll_umbstowcs( 0, event->name, event->len, pfni->FileName,
(left - offsetof(FILE_NOTIFY_INFORMATION, FileName)) / sizeof(WCHAR));
last_entry_offset = &pfni->NextEntryOffset;
len = ntdll_umbstowcs( 0, path, len, pfni->FileName,
info->BufferSize - sizeof (*pfni) );
if(pfni->FileNameLength == -1 || pfni->FileNameLength == -2)
break;
pfni->NextEntryOffset = 0;
pfni->Action = action;
pfni->FileNameLength = len * sizeof (WCHAR);
pfni->FileName[len] = 0;
len = sizeof (*pfni) - sizeof (DWORD) + pfni->FileNameLength;
i = offsetof(FILE_NOTIFY_INFORMATION, FileName[pfni->FileNameLength]);
pfni->FileNameLength *= sizeof(WCHAR);
pfni->NextEntryOffset = i;
pfni = (FILE_NOTIFY_INFORMATION*)((char*)pfni + i);
left -= i;
i = (offsetof(struct filesystem_event, name[event->len])
+ sizeof(int)-1) / sizeof(int) * sizeof(int);
event = (struct filesystem_event*)((char*)event + i);
size -= i;
}
if (size)
{
ret = STATUS_NOTIFY_ENUM_DIR;
size = 0;
}
else
{
*last_entry_offset = 0;
size = info->BufferSize - left;
}
}
else
{
ret = STATUS_NOTIFY_ENUM_DIR;
len = 0;
size = 0;
}
iosb->u.Status = ret;
iosb->Information = len;
iosb->Information = size;
*apc = read_changes_user_apc;
return ret;
}

View File

@ -316,6 +316,14 @@ typedef struct
unsigned short attr;
} char_info_t;
struct filesystem_event
{
int action;
data_size_t len;
char name[1];
};
typedef struct
{
unsigned int low_part;
@ -1879,9 +1887,7 @@ struct read_change_request
struct read_change_reply
{
struct reply_header __header;
int action;
/* VARARG(name,string); */
char __pad_12[4];
/* VARARG(events,filesystem_event); */
};
@ -5519,6 +5525,6 @@ union generic_reply
struct set_cursor_reply set_cursor_reply;
};
#define SERVER_PROTOCOL_VERSION 411
#define SERVER_PROTOCOL_VERSION 412
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -123,9 +123,7 @@ static struct fd *inotify_fd;
struct change_record {
struct list entry;
int action;
int len;
char name[1];
struct filesystem_event event;
};
struct dir
@ -616,13 +614,13 @@ static void inotify_do_change_notify( struct dir *dir, unsigned int action,
if (dir->want_data)
{
size_t len = strlen(relpath);
record = malloc( offsetof(struct change_record, name[len]) );
record = malloc( offsetof(struct change_record, event.name[len]) );
if (!record)
return;
record->action = action;
memcpy( record->name, relpath, len );
record->len = len;
record->event.action = action;
memcpy( record->event.name, relpath, len );
record->event.len = len;
list_add_tail( &dir->change_records, &record->entry );
}
@ -1145,21 +1143,54 @@ end:
DECL_HANDLER(read_change)
{
struct change_record *record;
struct change_record *record, *next;
struct dir *dir;
struct list events;
char *data, *event;
int size = 0;
dir = get_dir_obj( current->process, req->handle, 0 );
if (!dir)
return;
if ((record = get_first_change_record( dir )) != NULL)
list_init( &events );
list_move_tail( &events, &dir->change_records );
release_object( dir );
if (list_empty( &events ))
{
reply->action = record->action;
set_reply_data( record->name, record->len );
set_error( STATUS_NO_DATA_DETECTED );
return;
}
LIST_FOR_EACH_ENTRY( record, &events, struct change_record, entry )
{
size += (offsetof(struct filesystem_event, name[record->event.len])
+ sizeof(int)-1) / sizeof(int) * sizeof(int);
}
if (size > get_reply_max_size())
set_error( STATUS_BUFFER_TOO_SMALL );
else if ((data = mem_alloc( size )) != NULL)
{
event = data;
LIST_FOR_EACH_ENTRY( record, &events, struct change_record, entry )
{
data_size_t len = offsetof( struct filesystem_event, name[record->event.len] );
memcpy( event, &record->event, len );
event += len;
if (len % sizeof(int))
{
memset( event, 0, sizeof(int) - len % sizeof(int) );
event += sizeof(int) - len % sizeof(int);
}
}
set_reply_data_ptr( data, size );
}
LIST_FOR_EACH_ENTRY_SAFE( record, next, &events, struct change_record, entry )
{
list_remove( &record->entry );
free( record );
}
else
set_error( STATUS_NO_DATA_DETECTED );
release_object( dir );
}

View File

@ -332,6 +332,14 @@ typedef struct
unsigned short attr;
} char_info_t;
/* structure returned in filesystem events */
struct filesystem_event
{
int action;
data_size_t len;
char name[1];
};
typedef struct
{
unsigned int low_part;
@ -1448,8 +1456,7 @@ enum char_info_mode
@REQ(read_change)
obj_handle_t handle;
@REPLY
int action; /* type of change */
VARARG(name,string); /* name of directory entry that changed */
VARARG(events,filesystem_event); /* collected filesystem events */
@END

View File

@ -1103,8 +1103,7 @@ C_ASSERT( FIELD_OFFSET(struct read_directory_changes_request, async) == 24 );
C_ASSERT( sizeof(struct read_directory_changes_request) == 64 );
C_ASSERT( FIELD_OFFSET(struct read_change_request, handle) == 12 );
C_ASSERT( sizeof(struct read_change_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct read_change_reply, action) == 8 );
C_ASSERT( sizeof(struct read_change_reply) == 16 );
C_ASSERT( sizeof(struct read_change_reply) == 8 );
C_ASSERT( FIELD_OFFSET(struct create_mapping_request, access) == 12 );
C_ASSERT( FIELD_OFFSET(struct create_mapping_request, attributes) == 16 );
C_ASSERT( FIELD_OFFSET(struct create_mapping_request, protect) == 20 );

View File

@ -991,6 +991,24 @@ static void dump_varargs_object_attributes( const char *prefix, data_size_t size
fputc( '}', stderr );
}
static void dump_varargs_filesystem_event( const char *prefix, data_size_t size )
{
fprintf( stderr,"%s{", prefix );
while (size)
{
const struct filesystem_event *event = cur_data;
data_size_t len = (offsetof( struct filesystem_event, name[event->len] ) + sizeof(int)-1)
/ sizeof(int) * sizeof(int);
if (size < len) break;
fprintf( stderr, "{action=%x,len=%u,name=\"%.*s\"}",
event->action, event->len, event->len, event->name );
size -= len;
remove_data( len );
if (size)fputc( ',', stderr );
}
fputc( '}', stderr );
}
typedef void (*dump_func)( const void *req );
/* Everything below this line is generated automatically by tools/make_requests */
@ -1865,8 +1883,7 @@ static void dump_read_change_request( const struct read_change_request *req )
static void dump_read_change_reply( const struct read_change_reply *req )
{
fprintf( stderr, " action=%d", req->action );
dump_varargs_string( ", name=", cur_size );
dump_varargs_filesystem_event( " events=", cur_size );
}
static void dump_create_mapping_request( const struct create_mapping_request *req )