diff --git a/dlls/kernel/sync.c b/dlls/kernel/sync.c index 1f93efe1e74..ef61cf06613 100644 --- a/dlls/kernel/sync.c +++ b/dlls/kernel/sync.c @@ -1268,23 +1268,6 @@ BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer, 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.@) */ @@ -1305,59 +1288,83 @@ BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut) /*********************************************************************** * 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 ret; - OVERLAPPED ov; - UNICODE_STRING nt_name; 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); if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL )) return FALSE; - if (nt_name.Length >= MAX_PATH * sizeof(WCHAR) ) + if (nt_name.Length >= MAX_PATH * sizeof(WCHAR) || + nt_name.Length < sizeof(leadin) || + strncmpiW( nt_name.Buffer, leadin, sizeof(leadin)/sizeof(WCHAR) != 0)) { RtlFreeUnicodeString( &nt_name ); + SetLastError( ERROR_PATH_NOT_FOUND ); return FALSE; } - if (nt_name.Length < sizeof(leadin) || - strncmpiW( nt_name.Buffer, leadin, sizeof(leadin)/sizeof(leadin[0]))) + + sz_pipe_wait = sizeof(*pipe_wait) + nt_name.Length - sizeof(leadin) - sizeof(WCHAR); + if (!(pipe_wait = HeapAlloc( GetProcessHeap(), 0, sz_pipe_wait))) { RtlFreeUnicodeString( &nt_name ); + SetLastError( ERROR_OUTOFMEMORY ); return FALSE; } - memset(&ov,0,sizeof(ov)); - ov.hEvent = CreateEventW( NULL, 0, 0, NULL ); - if (!ov.hEvent) - return FALSE; - - SERVER_START_REQ( wait_named_pipe ) + 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) { - req->timeout = nTimeOut; - req->overlapped = &ov; - req->func = PIPE_CompletionWait; - wine_server_add_data( req, nt_name.Buffer + sizeof(leadin)/sizeof(WCHAR), - nt_name.Length - sizeof(leadin) ); - ret = !wine_server_call_err( req ); + SetLastError( ERROR_PATH_NOT_FOUND ); + return FALSE; } - SERVER_END_REQ; + 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 ); - 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(ov.Internal)); - ret = (ov.Internal==STATUS_SUCCESS); - } + SetLastError(RtlNtStatusToDosError(status)); + return FALSE; } - CloseHandle(ov.hEvent); - return ret; + else + return TRUE; } diff --git a/dlls/kernel/tests/pipe.c b/dlls/kernel/tests/pipe.c index a4c15fe192e..5b0286f3296 100644 --- a/dlls/kernel/tests/pipe.c +++ b/dlls/kernel/tests/pipe.c @@ -91,7 +91,7 @@ static void test_CreateNamedPipe(int pipemode) /* lpSecurityAttrib */ NULL); 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); ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%08lx)\n", GetLastError()); diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 17c4ba06c34..4da96330b28 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -931,7 +931,8 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_ PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode, 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", DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,FsControlCode, @@ -946,26 +947,46 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_ break; case FSCTL_PIPE_LISTEN : + case FSCTL_PIPE_WAIT : { - HANDLE internal_event; + OBJECT_ATTRIBUTES obj; if(!Event) { - OBJECT_ATTRIBUTES obj; InitializeObjectAttributes(&obj, NULL, 0, 0, NULL); ret = NtCreateEvent(&internal_event, EVENT_ALL_ACCESS, &obj, FALSE, FALSE); if(ret != STATUS_SUCCESS) return ret; } - - SERVER_START_REQ(connect_named_pipe) + switch(FsControlCode) { - req->handle = DeviceHandle; - req->event = Event ? Event : internal_event; - req->func = pipe_completion_wait; - ret = wine_server_call(req); - } - SERVER_END_REQ; + case FSCTL_PIPE_LISTEN : + SERVER_START_REQ(connect_named_pipe) + { + req->handle = DeviceHandle; + req->event = Event ? Event : internal_event; + req->func = pipe_completion_wait; + ret = wine_server_call(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(Event) @@ -991,7 +1012,6 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_ break; default : FIXME("Unsupported FsControlCode %lx\n", FsControlCode); - ret = STATUS_NOT_SUPPORTED; break; } IoStatusBlock->u.Status = ret; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 1391b08a26e..c34fd464760 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2458,8 +2458,9 @@ struct connect_named_pipe_reply struct wait_named_pipe_request { struct request_header __header; + obj_handle_t handle; unsigned int timeout; - void* overlapped; + obj_handle_t event; void* func; /* VARARG(name,unicode_str); */ }; @@ -4345,6 +4346,6 @@ union generic_reply struct query_symlink_reply query_symlink_reply; }; -#define SERVER_PROTOCOL_VERSION 216 +#define SERVER_PROTOCOL_VERSION 217 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/winioctl.h b/include/winioctl.h index 8ae5b6f41ad..5a9ff3256f5 100644 --- a/include/winioctl.h +++ b/include/winioctl.h @@ -404,6 +404,13 @@ typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { WCHAR FileSystemName[1]; } 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 */ #ifdef DEFINE_GUID diff --git a/server/named_pipe.c b/server/named_pipe.c index 8b25bc103b5..ef298bb6fa9 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -443,9 +443,6 @@ static int named_pipe_device_get_file_info( struct fd *fd ) 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, const struct unicode_str *name ) { @@ -462,7 +459,6 @@ struct named_pipe_device *create_named_pipe_device( struct directory *root, dev = NULL; } } - named_pipe_device = dev; return dev; } @@ -846,12 +842,18 @@ DECL_HANDLER(connect_named_pipe) DECL_HANDLER(wait_named_pipe) { + struct named_pipe_device *device; struct named_pipe *pipe; struct pipe_server *server; 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 ); - 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) { 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 */ 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 ); } else @@ -875,10 +877,10 @@ DECL_HANDLER(wait_named_pipe) if (req->timeout == NMPWAIT_WAIT_FOREVER) create_async( current, NULL, &pipe->waiters, - req->func, req->overlapped, NULL ); + req->func, req->event, NULL ); else create_async( current, &timeout, &pipe->waiters, - req->func, req->overlapped, NULL ); + req->func, req->event, NULL ); } release_object( pipe ); diff --git a/server/protocol.def b/server/protocol.def index 2aa4f0ef503..39851b25466 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1751,8 +1751,9 @@ enum message_type /* Wait for a named pipe */ @REQ(wait_named_pipe) + obj_handle_t handle; unsigned int timeout; - void* overlapped; + obj_handle_t event; void* func; VARARG(name,unicode_str); /* pipe name */ @END diff --git a/server/trace.c b/server/trace.c index 016b007748a..409d9de60bf 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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 ) { + fprintf( stderr, " handle=%p,", req->handle ); 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, " name=" ); dump_varargs_unicode_str( cur_size );