ntdll: Fix handling of async cancellation for directory changes.
This commit is contained in:
parent
38b7c8839c
commit
193667ecd7
|
@ -1805,73 +1805,78 @@ static NTSTATUS read_changes_apc( void *user, IO_STATUS_BLOCK *iosb,
|
||||||
NTSTATUS status, void **apc, void **arg )
|
NTSTATUS status, void **apc, void **arg )
|
||||||
{
|
{
|
||||||
struct read_changes_fileio *fileio = user;
|
struct read_changes_fileio *fileio = user;
|
||||||
NTSTATUS ret;
|
int size = 0;
|
||||||
int size;
|
|
||||||
|
|
||||||
SERVER_START_REQ( read_change )
|
if (status == STATUS_ALERTED)
|
||||||
{
|
{
|
||||||
req->handle = wine_server_obj_handle( fileio->io.handle );
|
SERVER_START_REQ( read_change )
|
||||||
wine_server_set_reply( req, fileio->data, fileio->data_size );
|
|
||||||
ret = wine_server_call( req );
|
|
||||||
size = wine_server_reply_size( reply );
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
if (ret == STATUS_SUCCESS && fileio->buffer)
|
|
||||||
{
|
|
||||||
FILE_NOTIFY_INFORMATION *pfni = fileio->buffer;
|
|
||||||
int i, left = fileio->buffer_size;
|
|
||||||
DWORD *last_entry_offset = NULL;
|
|
||||||
struct filesystem_event *event = (struct filesystem_event*)fileio->data;
|
|
||||||
|
|
||||||
while (size && left >= sizeof(*pfni))
|
|
||||||
{
|
{
|
||||||
/* convert to an NT style path */
|
req->handle = wine_server_obj_handle( fileio->io.handle );
|
||||||
for (i=0; i<event->len; i++)
|
wine_server_set_reply( req, fileio->data, fileio->data_size );
|
||||||
if (event->name[i] == '/') event->name[i] = '\\';
|
status = wine_server_call( req );
|
||||||
|
size = wine_server_reply_size( reply );
|
||||||
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;
|
|
||||||
|
|
||||||
if (pfni->FileNameLength == -1 || pfni->FileNameLength == -2) break;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
if (size)
|
if (status == STATUS_SUCCESS && fileio->buffer)
|
||||||
{
|
{
|
||||||
ret = STATUS_NOTIFY_ENUM_DIR;
|
FILE_NOTIFY_INFORMATION *pfni = fileio->buffer;
|
||||||
size = 0;
|
int i, left = fileio->buffer_size;
|
||||||
|
DWORD *last_entry_offset = NULL;
|
||||||
|
struct filesystem_event *event = (struct filesystem_event*)fileio->data;
|
||||||
|
|
||||||
|
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] = '\\';
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (pfni->FileNameLength == -1 || pfni->FileNameLength == -2) break;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
status = STATUS_NOTIFY_ENUM_DIR;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (last_entry_offset) *last_entry_offset = 0;
|
||||||
|
size = fileio->buffer_size - left;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*last_entry_offset = 0;
|
status = STATUS_NOTIFY_ENUM_DIR;
|
||||||
size = fileio->buffer_size - left;
|
size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = STATUS_NOTIFY_ENUM_DIR;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
iosb->u.Status = ret;
|
if (status != STATUS_PENDING)
|
||||||
iosb->Information = size;
|
{
|
||||||
*apc = fileio->io.apc;
|
iosb->u.Status = status;
|
||||||
*arg = fileio->io.apc_arg;
|
iosb->Information = size;
|
||||||
release_fileio( &fileio->io );
|
*apc = fileio->io.apc;
|
||||||
return ret;
|
*arg = fileio->io.apc_arg;
|
||||||
|
release_fileio( &fileio->io );
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FILE_NOTIFY_ALL ( \
|
#define FILE_NOTIFY_ALL ( \
|
||||||
|
|
|
@ -99,19 +99,19 @@ static void test_ntncdf(void)
|
||||||
r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
|
r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
|
||||||
ok(r==STATUS_PENDING, "should return status pending\n");
|
ok(r==STATUS_PENDING, "should return status pending\n");
|
||||||
|
|
||||||
r = WaitForSingleObject( hEvent, 0 );
|
r = WaitForSingleObject( hEvent, 100 );
|
||||||
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
||||||
|
|
||||||
r = WaitForSingleObject( hdir, 0 );
|
r = WaitForSingleObject( hdir, 100 );
|
||||||
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
||||||
|
|
||||||
r = CreateDirectoryW( subdir, NULL );
|
r = CreateDirectoryW( subdir, NULL );
|
||||||
ok( r == TRUE, "failed to create directory\n");
|
ok( r == TRUE, "failed to create directory\n");
|
||||||
|
|
||||||
r = WaitForSingleObject( hdir, 0 );
|
r = WaitForSingleObject( hdir, 100 );
|
||||||
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
||||||
|
|
||||||
r = WaitForSingleObject( hEvent, 0 );
|
r = WaitForSingleObject( hEvent, 100 );
|
||||||
ok( r == WAIT_OBJECT_0, "event should be ready\n" );
|
ok( r == WAIT_OBJECT_0, "event should be ready\n" );
|
||||||
|
|
||||||
ok( U(iosb).Status == STATUS_SUCCESS, "information wrong\n");
|
ok( U(iosb).Status == STATUS_SUCCESS, "information wrong\n");
|
||||||
|
@ -299,7 +299,7 @@ static void test_ntncdf_async(void)
|
||||||
CloseHandle(hdir);
|
CloseHandle(hdir);
|
||||||
|
|
||||||
ok(U(iosb).Status == STATUS_SUCCESS, "status wrong\n");
|
ok(U(iosb).Status == STATUS_SUCCESS, "status wrong\n");
|
||||||
todo_wine ok(U(iosb2).Status == STATUS_CANCELLED, "status wrong\n");
|
ok(U(iosb2).Status == STATUS_CANCELLED, "status wrong %x\n",U(iosb2).Status);
|
||||||
|
|
||||||
ok(iosb.Information == 0, "info wrong\n");
|
ok(iosb.Information == 0, "info wrong\n");
|
||||||
ok(iosb2.Information == 0, "info wrong\n");
|
ok(iosb2.Information == 0, "info wrong\n");
|
||||||
|
|
|
@ -272,7 +272,7 @@ void sigio_callback(void)
|
||||||
LIST_FOR_EACH_ENTRY( dir, &change_list, struct dir, entry )
|
LIST_FOR_EACH_ENTRY( dir, &change_list, struct dir, entry )
|
||||||
{
|
{
|
||||||
if (interlocked_xchg( &dir->notified, 0 ))
|
if (interlocked_xchg( &dir->notified, 0 ))
|
||||||
fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_NOTIFY_ENUM_DIR );
|
fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_ALERTED );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue