kernel32: ReadDirectoryChangesW fixes.
ReadDirectoryChangesW remembers whether it's recording changes or not.
Don't initialize overlapped->InternalHigh.
The hEvent is cleared when ReadDirectoryChanges is called.
diff --git a/dlls/kernel/change.c b/dlls/kernel/change.c
index 235ac58..7c5eb92 100644
--- a/dlls/kernel/change.c
+++ b/dlls/kernel/change.c
@@ -132,6 +132,19 @@
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 @@
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 84e01af..af29057 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -1899,6 +1899,7 @@
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 8a061ed..9f9150c 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1401,6 +1401,7 @@
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 @@
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 d6213fe..c35a82c 100644
--- a/server/change.c
+++ b/server/change.c
@@ -141,6 +141,7 @@
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 @@
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 @@
{
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 @@
{
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 2b3a587..986a595 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1045,6 +1045,7 @@
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 e1ed879..05f4bb6 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1449,6 +1449,7 @@
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 );