ntdll: Fix handling of async cancellation for directory changes.

This commit is contained in:
Alexandre Julliard 2015-05-07 16:02:26 +09:00
parent 38b7c8839c
commit 193667ecd7
3 changed files with 66 additions and 61 deletions

View File

@ -1805,73 +1805,78 @@ static NTSTATUS read_changes_apc( void *user, IO_STATUS_BLOCK *iosb,
NTSTATUS status, void **apc, void **arg )
{
struct read_changes_fileio *fileio = user;
NTSTATUS ret;
int size;
int size = 0;
SERVER_START_REQ( read_change )
if (status == STATUS_ALERTED)
{
req->handle = wine_server_obj_handle( fileio->io.handle );
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))
SERVER_START_REQ( read_change )
{
/* 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;
req->handle = wine_server_obj_handle( fileio->io.handle );
wine_server_set_reply( req, fileio->data, fileio->data_size );
status = wine_server_call( req );
size = wine_server_reply_size( reply );
}
SERVER_END_REQ;
if (size)
if (status == STATUS_SUCCESS && fileio->buffer)
{
ret = STATUS_NOTIFY_ENUM_DIR;
size = 0;
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 */
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
{
*last_entry_offset = 0;
size = fileio->buffer_size - left;
status = STATUS_NOTIFY_ENUM_DIR;
size = 0;
}
}
else
{
ret = STATUS_NOTIFY_ENUM_DIR;
size = 0;
}
iosb->u.Status = ret;
iosb->Information = size;
*apc = fileio->io.apc;
*arg = fileio->io.apc_arg;
release_fileio( &fileio->io );
return ret;
if (status != STATUS_PENDING)
{
iosb->u.Status = status;
iosb->Information = size;
*apc = fileio->io.apc;
*arg = fileio->io.apc_arg;
release_fileio( &fileio->io );
}
return status;
}
#define FILE_NOTIFY_ALL ( \

View File

@ -99,19 +99,19 @@ static void test_ntncdf(void)
r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
ok(r==STATUS_PENDING, "should return status pending\n");
r = WaitForSingleObject( hEvent, 0 );
r = WaitForSingleObject( hEvent, 100 );
ok( r == STATUS_TIMEOUT, "should timeout\n" );
r = WaitForSingleObject( hdir, 0 );
r = WaitForSingleObject( hdir, 100 );
ok( r == STATUS_TIMEOUT, "should timeout\n" );
r = CreateDirectoryW( subdir, NULL );
ok( r == TRUE, "failed to create directory\n");
r = WaitForSingleObject( hdir, 0 );
r = WaitForSingleObject( hdir, 100 );
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( U(iosb).Status == STATUS_SUCCESS, "information wrong\n");
@ -299,7 +299,7 @@ static void test_ntncdf_async(void)
CloseHandle(hdir);
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(iosb2.Information == 0, "info wrong\n");

View File

@ -272,7 +272,7 @@ void sigio_callback(void)
LIST_FOR_EACH_ENTRY( dir, &change_list, struct dir, entry )
{
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 );
}
}