diff --git a/dlls/kernel/change.c b/dlls/kernel/change.c index 235ac585de9..7c5eb92474b 100644 --- a/dlls/kernel/change.c +++ b/dlls/kernel/change.c @@ -132,6 +132,19 @@ BOOL WINAPI FindCloseChangeNotification( HANDLE handle ) return CloseHandle( handle ); } +/**************************************************************************** + * ReadDirectoryChangesW (KERNEL32.@) + * + * NOTES + * + * The filter is remember from the first run and ignored on successive runs. + * + * If there's no output buffer on the first run, it's ignored successive runs + * and STATUS_NOTIFY_ENUM_DIRECTORY is returned with an empty buffer. + * + * If a NULL overlapped->hEvent is passed, the directory handle is used + * for signalling. + */ BOOL WINAPI ReadDirectoryChangesW( HANDLE handle, LPVOID buffer, DWORD len, BOOL subtree, DWORD filter, LPDWORD returned, LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE completion ) @@ -155,7 +168,6 @@ BOOL WINAPI ReadDirectoryChangesW( HANDLE handle, LPVOID buffer, DWORD len, BOOL ios = (PIO_STATUS_BLOCK) pov; ios->Status = STATUS_PENDING; - ios->Information = 0; status = NtNotifyChangeDirectoryFile( handle, pov->hEvent, NULL, NULL, ios, buffer, len, filter, subtree ); diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index 84e01aff88e..af2905797d1 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -1899,6 +1899,7 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event, req->handle = FileHandle; req->event = Event; req->filter = CompletionFilter; + req->want_data = (Buffer != NULL); req->io_apc = read_changes_apc; req->io_sb = IoStatusBlock; req->io_user = info; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 8a061ed10b6..9f9150c558b 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1401,6 +1401,7 @@ struct read_directory_changes_request obj_handle_t handle; obj_handle_t event; unsigned int filter; + int want_data; void* io_apc; void* io_sb; void* io_user; @@ -4363,6 +4364,6 @@ union generic_reply struct query_symlink_reply query_symlink_reply; }; -#define SERVER_PROTOCOL_VERSION 224 +#define SERVER_PROTOCOL_VERSION 225 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/change.c b/server/change.c index d6213fe3c00..c35a82cf67e 100644 --- a/server/change.c +++ b/server/change.c @@ -141,6 +141,7 @@ struct dir struct event *event; unsigned int filter; /* notification filter */ int notified; /* SIGIO counter */ + int want_data; /* return change data */ long signaled; /* the file changed */ struct fd *inotify_fd; /* inotify file descriptor */ int wd; /* inotify watch descriptor */ @@ -254,6 +255,7 @@ struct object *create_dir_obj( struct fd *fd ) dir->filter = 0; dir->notified = 0; dir->signaled = 0; + dir->want_data = 0; dir->inotify_fd = NULL; dir->wd = -1; grab_object( fd ); @@ -412,20 +414,23 @@ static void inotify_do_change_notify( struct dir *dir, struct inotify_event *ie { struct change_record *record; - record = malloc( sizeof (*record) + ie->len - 1 ) ; - if (!record) - return; + if (dir->want_data) + { + 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 ); + 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 ); + list_add_tail( &dir->change_records, &record->entry ); + } if (!list_empty( &dir->change_q )) async_terminate_head( &dir->change_q, STATUS_ALERTED ); @@ -551,12 +556,17 @@ DECL_HANDLER(read_directory_changes) { insert_change( dir ); dir->filter = req->filter; + dir->want_data = req->want_data; } /* remove any notifications */ if (dir->signaled>0) dir->signaled--; + /* clear the event */ + if (event) + reset_event( event ); + /* setup the real notification */ #ifdef USE_INOTIFY if (!inotify_adjust_changes( dir )) diff --git a/server/protocol.def b/server/protocol.def index 2b3a5875674..986a5959717 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1045,6 +1045,7 @@ enum char_info_mode obj_handle_t handle; /* handle to the directory */ obj_handle_t event; /* handle to the event */ unsigned int filter; /* notification filter */ + int want_data; /* flag indicating whether change data should be collected */ 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 */ diff --git a/server/trace.c b/server/trace.c index e1ed8793010..05f4bb6e46c 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1449,6 +1449,7 @@ static void dump_read_directory_changes_request( const struct read_directory_cha fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " event=%p,", req->event ); fprintf( stderr, " filter=%08x,", req->filter ); + fprintf( stderr, " want_data=%d,", req->want_data ); fprintf( stderr, " io_apc=%p,", req->io_apc ); fprintf( stderr, " io_sb=%p,", req->io_sb ); fprintf( stderr, " io_user=%p", req->io_user );