ntdll: Implement FSCTL_PIPE_WAIT NtFsControlFile ioctl.
Implement FSCTL_PIPE_WAIT NtFsControlFile ioctl. Modify WaitNamedPipeW to use NtFsControlFile. Replace struct overlapped with event.
This commit is contained in:
parent
12b35c2dd8
commit
b05340a523
|
@ -1268,23 +1268,6 @@ BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* PIPE_CompletionWait (Internal)
|
|
||||||
*/
|
|
||||||
static void CALLBACK PIPE_CompletionWait(void *user, PIO_STATUS_BLOCK iosb, ULONG status)
|
|
||||||
{
|
|
||||||
LPOVERLAPPED ovlp = (LPOVERLAPPED)user;
|
|
||||||
|
|
||||||
TRACE("for %p/%p, status=%08lx\n", ovlp, iosb, status);
|
|
||||||
|
|
||||||
if (ovlp)
|
|
||||||
{
|
|
||||||
ovlp->Internal = status;
|
|
||||||
SetEvent(ovlp->hEvent);
|
|
||||||
}
|
|
||||||
TRACE("done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* WaitNamedPipeA (KERNEL32.@)
|
* WaitNamedPipeA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -1305,59 +1288,83 @@ BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut)
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* WaitNamedPipeW (KERNEL32.@)
|
* WaitNamedPipeW (KERNEL32.@)
|
||||||
|
*
|
||||||
|
* Waits for a named pipe instance to become available
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* name [I] Pointer to a named pipe name to wait for
|
||||||
|
* nTimeOut [I] How long to wait in ms
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* TRUE: Success, named pipe can be opened with CreteFile
|
||||||
|
* FALSE: Failure, GetLastError can be called for further details
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut)
|
BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut)
|
||||||
{
|
{
|
||||||
BOOL ret;
|
|
||||||
OVERLAPPED ov;
|
|
||||||
UNICODE_STRING nt_name;
|
|
||||||
static const WCHAR leadin[] = {'\\','?','?','\\','P','I','P','E','\\'};
|
static const WCHAR leadin[] = {'\\','?','?','\\','P','I','P','E','\\'};
|
||||||
|
NTSTATUS status;
|
||||||
|
UNICODE_STRING nt_name, pipe_dev_name;
|
||||||
|
FILE_PIPE_WAIT_FOR_BUFFER *pipe_wait;
|
||||||
|
IO_STATUS_BLOCK iosb;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
ULONG sz_pipe_wait;
|
||||||
|
HANDLE pipe_dev;
|
||||||
|
|
||||||
TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut);
|
TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut);
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
|
if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (nt_name.Length >= MAX_PATH * sizeof(WCHAR) )
|
if (nt_name.Length >= MAX_PATH * sizeof(WCHAR) ||
|
||||||
{
|
nt_name.Length < sizeof(leadin) ||
|
||||||
RtlFreeUnicodeString( &nt_name );
|
strncmpiW( nt_name.Buffer, leadin, sizeof(leadin)/sizeof(WCHAR) != 0))
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (nt_name.Length < sizeof(leadin) ||
|
|
||||||
strncmpiW( nt_name.Buffer, leadin, sizeof(leadin)/sizeof(leadin[0])))
|
|
||||||
{
|
{
|
||||||
RtlFreeUnicodeString( &nt_name );
|
RtlFreeUnicodeString( &nt_name );
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&ov,0,sizeof(ov));
|
sz_pipe_wait = sizeof(*pipe_wait) + nt_name.Length - sizeof(leadin) - sizeof(WCHAR);
|
||||||
ov.hEvent = CreateEventW( NULL, 0, 0, NULL );
|
if (!(pipe_wait = HeapAlloc( GetProcessHeap(), 0, sz_pipe_wait)))
|
||||||
if (!ov.hEvent)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
SERVER_START_REQ( wait_named_pipe )
|
|
||||||
{
|
{
|
||||||
req->timeout = nTimeOut;
|
RtlFreeUnicodeString( &nt_name );
|
||||||
req->overlapped = &ov;
|
SetLastError( ERROR_OUTOFMEMORY );
|
||||||
req->func = PIPE_CompletionWait;
|
return FALSE;
|
||||||
wine_server_add_data( req, nt_name.Buffer + sizeof(leadin)/sizeof(WCHAR),
|
|
||||||
nt_name.Length - sizeof(leadin) );
|
|
||||||
ret = !wine_server_call_err( req );
|
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
|
pipe_dev_name.Buffer = nt_name.Buffer;
|
||||||
|
pipe_dev_name.Length = sizeof(leadin);
|
||||||
|
pipe_dev_name.MaximumLength = sizeof(leadin);
|
||||||
|
InitializeObjectAttributes(&attr,&pipe_dev_name, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||||
|
status = NtOpenFile( &pipe_dev, FILE_READ_ATTRIBUTES, &attr,
|
||||||
|
&iosb, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
||||||
|
if (status != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe_wait->TimeoutSpecified = !(nTimeOut == NMPWAIT_USE_DEFAULT_WAIT);
|
||||||
|
pipe_wait->Timeout.QuadPart = nTimeOut * -10000L;
|
||||||
|
pipe_wait->NameLength = nt_name.Length - sizeof(leadin);
|
||||||
|
memcpy(pipe_wait->Name, nt_name.Buffer + sizeof(leadin)/sizeof(WCHAR),
|
||||||
|
pipe_wait->NameLength);
|
||||||
RtlFreeUnicodeString( &nt_name );
|
RtlFreeUnicodeString( &nt_name );
|
||||||
|
|
||||||
if(ret)
|
status = NtFsControlFile( pipe_dev, NULL, NULL, NULL, &iosb, FSCTL_PIPE_WAIT,
|
||||||
|
pipe_wait, sz_pipe_wait, NULL, 0 );
|
||||||
|
|
||||||
|
HeapFree( GetProcessHeap(), 0, pipe_wait );
|
||||||
|
NtClose( pipe_dev );
|
||||||
|
|
||||||
|
if(status != STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE))
|
SetLastError(RtlNtStatusToDosError(status));
|
||||||
{
|
return FALSE;
|
||||||
SetLastError(RtlNtStatusToDosError(ov.Internal));
|
|
||||||
ret = (ov.Internal==STATUS_SUCCESS);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
CloseHandle(ov.hEvent);
|
return TRUE;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ static void test_CreateNamedPipe(int pipemode)
|
||||||
/* lpSecurityAttrib */ NULL);
|
/* lpSecurityAttrib */ NULL);
|
||||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||||
|
|
||||||
todo_wine ok(WaitNamedPipeA(PIPENAME, 2000), "WaitNamedPipe failed (%08lx)\n", GetLastError());
|
ok(WaitNamedPipeA(PIPENAME, 2000), "WaitNamedPipe failed (%08lx)\n", GetLastError());
|
||||||
|
|
||||||
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||||
ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%08lx)\n", GetLastError());
|
ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%08lx)\n", GetLastError());
|
||||||
|
|
|
@ -931,7 +931,8 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_
|
||||||
PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode,
|
PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode,
|
||||||
PVOID InputBuffer, ULONG InputBufferSize, PVOID OutputBuffer, ULONG OutputBufferSize)
|
PVOID InputBuffer, ULONG InputBufferSize, PVOID OutputBuffer, ULONG OutputBufferSize)
|
||||||
{
|
{
|
||||||
NTSTATUS ret;
|
NTSTATUS ret = STATUS_NOT_SUPPORTED;
|
||||||
|
HANDLE internal_event;
|
||||||
|
|
||||||
TRACE("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx)\n",
|
TRACE("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx)\n",
|
||||||
DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,FsControlCode,
|
DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,FsControlCode,
|
||||||
|
@ -946,17 +947,19 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FSCTL_PIPE_LISTEN :
|
case FSCTL_PIPE_LISTEN :
|
||||||
|
case FSCTL_PIPE_WAIT :
|
||||||
{
|
{
|
||||||
HANDLE internal_event;
|
OBJECT_ATTRIBUTES obj;
|
||||||
|
|
||||||
if(!Event)
|
if(!Event)
|
||||||
{
|
{
|
||||||
OBJECT_ATTRIBUTES obj;
|
|
||||||
InitializeObjectAttributes(&obj, NULL, 0, 0, NULL);
|
InitializeObjectAttributes(&obj, NULL, 0, 0, NULL);
|
||||||
ret = NtCreateEvent(&internal_event, EVENT_ALL_ACCESS, &obj, FALSE, FALSE);
|
ret = NtCreateEvent(&internal_event, EVENT_ALL_ACCESS, &obj, FALSE, FALSE);
|
||||||
if(ret != STATUS_SUCCESS) return ret;
|
if(ret != STATUS_SUCCESS) return ret;
|
||||||
}
|
}
|
||||||
|
switch(FsControlCode)
|
||||||
|
{
|
||||||
|
case FSCTL_PIPE_LISTEN :
|
||||||
SERVER_START_REQ(connect_named_pipe)
|
SERVER_START_REQ(connect_named_pipe)
|
||||||
{
|
{
|
||||||
req->handle = DeviceHandle;
|
req->handle = DeviceHandle;
|
||||||
|
@ -965,7 +968,25 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_
|
||||||
ret = wine_server_call(req);
|
ret = wine_server_call(req);
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
break;
|
||||||
|
case FSCTL_PIPE_WAIT :
|
||||||
|
{
|
||||||
|
FILE_PIPE_WAIT_FOR_BUFFER *buff = InputBuffer;
|
||||||
|
|
||||||
|
SERVER_START_REQ(wait_named_pipe)
|
||||||
|
{
|
||||||
|
req->handle = DeviceHandle;
|
||||||
|
req->timeout = buff->TimeoutSpecified ? buff->Timeout.QuadPart / -10000L
|
||||||
|
: NMPWAIT_USE_DEFAULT_WAIT;
|
||||||
|
req->event = Event ? Event : internal_event;
|
||||||
|
req->func = pipe_completion_wait;
|
||||||
|
wine_server_add_data( req, buff->Name, buff->NameLength );
|
||||||
|
ret = wine_server_call( req );
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(ret == STATUS_SUCCESS)
|
if(ret == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
if(Event)
|
if(Event)
|
||||||
|
@ -991,7 +1012,6 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
FIXME("Unsupported FsControlCode %lx\n", FsControlCode);
|
FIXME("Unsupported FsControlCode %lx\n", FsControlCode);
|
||||||
ret = STATUS_NOT_SUPPORTED;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
IoStatusBlock->u.Status = ret;
|
IoStatusBlock->u.Status = ret;
|
||||||
|
|
|
@ -2458,8 +2458,9 @@ struct connect_named_pipe_reply
|
||||||
struct wait_named_pipe_request
|
struct wait_named_pipe_request
|
||||||
{
|
{
|
||||||
struct request_header __header;
|
struct request_header __header;
|
||||||
|
obj_handle_t handle;
|
||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
void* overlapped;
|
obj_handle_t event;
|
||||||
void* func;
|
void* func;
|
||||||
/* VARARG(name,unicode_str); */
|
/* VARARG(name,unicode_str); */
|
||||||
};
|
};
|
||||||
|
@ -4345,6 +4346,6 @@ union generic_reply
|
||||||
struct query_symlink_reply query_symlink_reply;
|
struct query_symlink_reply query_symlink_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 216
|
#define SERVER_PROTOCOL_VERSION 217
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -404,6 +404,13 @@ typedef struct _FILE_FS_ATTRIBUTE_INFORMATION {
|
||||||
WCHAR FileSystemName[1];
|
WCHAR FileSystemName[1];
|
||||||
} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
|
} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _FILE_PIPE_WAIT_FOR_BUFFER {
|
||||||
|
LARGE_INTEGER Timeout;
|
||||||
|
ULONG NameLength;
|
||||||
|
BOOLEAN TimeoutSpecified;
|
||||||
|
WCHAR Name[1];
|
||||||
|
} FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER;
|
||||||
|
|
||||||
/* Device GUIDs */
|
/* Device GUIDs */
|
||||||
#ifdef DEFINE_GUID
|
#ifdef DEFINE_GUID
|
||||||
|
|
||||||
|
|
|
@ -443,9 +443,6 @@ static int named_pipe_device_get_file_info( struct fd *fd )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this will be deleted as soon an we fix wait_named_pipe */
|
|
||||||
static struct named_pipe_device *named_pipe_device;
|
|
||||||
|
|
||||||
struct named_pipe_device *create_named_pipe_device( struct directory *root,
|
struct named_pipe_device *create_named_pipe_device( struct directory *root,
|
||||||
const struct unicode_str *name )
|
const struct unicode_str *name )
|
||||||
{
|
{
|
||||||
|
@ -462,7 +459,6 @@ struct named_pipe_device *create_named_pipe_device( struct directory *root,
|
||||||
dev = NULL;
|
dev = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
named_pipe_device = dev;
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -846,12 +842,18 @@ DECL_HANDLER(connect_named_pipe)
|
||||||
|
|
||||||
DECL_HANDLER(wait_named_pipe)
|
DECL_HANDLER(wait_named_pipe)
|
||||||
{
|
{
|
||||||
|
struct named_pipe_device *device;
|
||||||
struct named_pipe *pipe;
|
struct named_pipe *pipe;
|
||||||
struct pipe_server *server;
|
struct pipe_server *server;
|
||||||
struct unicode_str name;
|
struct unicode_str name;
|
||||||
|
|
||||||
|
device = (struct named_pipe_device *)get_handle_obj( current->process, req->handle,
|
||||||
|
FILE_READ_ATTRIBUTES, &named_pipe_device_ops );
|
||||||
|
if (!device) return;
|
||||||
|
|
||||||
get_req_unicode_str( &name );
|
get_req_unicode_str( &name );
|
||||||
pipe = (struct named_pipe *)find_object( named_pipe_device->pipes, &name, OBJ_CASE_INSENSITIVE );
|
pipe = (struct named_pipe *)find_object( device->pipes, &name, OBJ_CASE_INSENSITIVE );
|
||||||
|
release_object( device );
|
||||||
if (!pipe)
|
if (!pipe)
|
||||||
{
|
{
|
||||||
set_error( STATUS_PIPE_NOT_AVAILABLE );
|
set_error( STATUS_PIPE_NOT_AVAILABLE );
|
||||||
|
@ -862,7 +864,7 @@ DECL_HANDLER(wait_named_pipe)
|
||||||
{
|
{
|
||||||
/* there's already a server waiting for a client to connect */
|
/* there's already a server waiting for a client to connect */
|
||||||
thread_queue_apc( current, NULL, req->func, APC_ASYNC_IO,
|
thread_queue_apc( current, NULL, req->func, APC_ASYNC_IO,
|
||||||
1, req->overlapped, NULL, (void *)STATUS_SUCCESS );
|
1, req->event, NULL, (void *)STATUS_SUCCESS );
|
||||||
release_object( server );
|
release_object( server );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -875,10 +877,10 @@ DECL_HANDLER(wait_named_pipe)
|
||||||
|
|
||||||
if (req->timeout == NMPWAIT_WAIT_FOREVER)
|
if (req->timeout == NMPWAIT_WAIT_FOREVER)
|
||||||
create_async( current, NULL, &pipe->waiters,
|
create_async( current, NULL, &pipe->waiters,
|
||||||
req->func, req->overlapped, NULL );
|
req->func, req->event, NULL );
|
||||||
else
|
else
|
||||||
create_async( current, &timeout, &pipe->waiters,
|
create_async( current, &timeout, &pipe->waiters,
|
||||||
req->func, req->overlapped, NULL );
|
req->func, req->event, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
release_object( pipe );
|
release_object( pipe );
|
||||||
|
|
|
@ -1751,8 +1751,9 @@ enum message_type
|
||||||
|
|
||||||
/* Wait for a named pipe */
|
/* Wait for a named pipe */
|
||||||
@REQ(wait_named_pipe)
|
@REQ(wait_named_pipe)
|
||||||
|
obj_handle_t handle;
|
||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
void* overlapped;
|
obj_handle_t event;
|
||||||
void* func;
|
void* func;
|
||||||
VARARG(name,unicode_str); /* pipe name */
|
VARARG(name,unicode_str); /* pipe name */
|
||||||
@END
|
@END
|
||||||
|
|
|
@ -2216,8 +2216,9 @@ static void dump_connect_named_pipe_request( const struct connect_named_pipe_req
|
||||||
|
|
||||||
static void dump_wait_named_pipe_request( const struct wait_named_pipe_request *req )
|
static void dump_wait_named_pipe_request( const struct wait_named_pipe_request *req )
|
||||||
{
|
{
|
||||||
|
fprintf( stderr, " handle=%p,", req->handle );
|
||||||
fprintf( stderr, " timeout=%08x,", req->timeout );
|
fprintf( stderr, " timeout=%08x,", req->timeout );
|
||||||
fprintf( stderr, " overlapped=%p,", req->overlapped );
|
fprintf( stderr, " event=%p,", req->event );
|
||||||
fprintf( stderr, " func=%p,", req->func );
|
fprintf( stderr, " func=%p,", req->func );
|
||||||
fprintf( stderr, " name=" );
|
fprintf( stderr, " name=" );
|
||||||
dump_varargs_unicode_str( cur_size );
|
dump_varargs_unicode_str( cur_size );
|
||||||
|
|
Loading…
Reference in New Issue