server: Return multiple events in read_changes.
diff --git a/server/change.c b/server/change.c index 5eb1df6..e448c13 100644 --- a/server/change.c +++ b/server/change.c
@@ -123,9 +123,7 @@ struct change_record { struct list entry; - int action; - int len; - char name[1]; + struct filesystem_event event; }; struct dir @@ -616,13 +614,13 @@ 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 @@ 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 ); }
diff --git a/server/protocol.def b/server/protocol.def index 6245f4c..728898f 100644 --- a/server/protocol.def +++ b/server/protocol.def
@@ -332,6 +332,14 @@ 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 @@ @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
diff --git a/server/request.h b/server/request.h index e0bffaf..ae45ab8 100644 --- a/server/request.h +++ b/server/request.h
@@ -1103,8 +1103,7 @@ 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 );
diff --git a/server/trace.c b/server/trace.c index 83d5b16..d083d2d 100644 --- a/server/trace.c +++ b/server/trace.c
@@ -991,6 +991,24 @@ 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_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 )