ntdll: Implement FSCTL_PIPE_WAIT NtFsControlFile ioctl.

Vitaliy Margolen wine-patch at kievinfo.com
Mon Dec 12 18:03:03 CST 2005


ChangeLog:
ntdll: Implement FSCTL_PIPE_WAIT NtFsControlFile ioctl.
kernel: Modify WaitNamedPipeW to use NtFsControlFile.
server: Replace struct overlapped with even.

 dlls/kernel/sync.c       |   95 +++++++++++++++++++++++++---------------------
 dlls/kernel/tests/pipe.c |    2 -
 dlls/ntdll/file.c        |   44 +++++++++++++++------
 include/winioctl.h       |    7 +++
 server/named_pipe.c      |   19 +++++----
 server/protocol.def      |    3 +
 6 files changed, 104 insertions(+), 66 deletions(-)
-------------- next part --------------
af425629092a4fc4b72b918020f2eb29ef1a4bc3
diff --git a/dlls/kernel/sync.c b/dlls/kernel/sync.c
index 1f93efe..70a190f 100644
--- a/dlls/kernel/sync.c
+++ b/dlls/kernel/sync.c
@@ -1269,23 +1269,6 @@ BOOL WINAPI PeekNamedPipe( HANDLE hPipe,
 }
 
 /***********************************************************************
- *           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.@)
  */
 BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut)
@@ -1305,59 +1288,83 @@ BOOL WINAPI WaitNamedPipeA (LPCSTR name,
 
 /***********************************************************************
  *           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 = (WCHAR*)leadin;
+    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 | SYNCHRONIZE, &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 != ERROR_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 a4c15fe..5b0286f 100644
--- a/dlls/kernel/tests/pipe.c
+++ b/dlls/kernel/tests/pipe.c
@@ -91,7 +91,7 @@ static void test_CreateNamedPipe(int pip
         /* 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 17c4ba0..fab4228 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -931,7 +931,8 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE D
                                 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 D
             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 = (FILE_PIPE_WAIT_FOR_BUFFER*)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 D
             break;
         default :
             FIXME("Unsupported FsControlCode %lx\n", FsControlCode);
-            ret = STATUS_NOT_SUPPORTED;
             break;
     }
     IoStatusBlock->u.Status = ret;
diff --git a/include/winioctl.h b/include/winioctl.h
index 8ae5b6f..5a9ff32 100644
--- a/include/winioctl.h
+++ b/include/winioctl.h
@@ -404,6 +404,13 @@ typedef struct _FILE_FS_ATTRIBUTE_INFORM
 	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 e451156..2587d98 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -437,9 +437,6 @@ static void named_pipe_device_destroy( s
     if (device->pipes) free( device->pipes );
 }
 
-/* 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 )
 {
@@ -456,7 +453,6 @@ struct named_pipe_device *create_named_p
             dev = NULL;
         }
     }
-    named_pipe_device = dev;
     return dev;
 }
 
@@ -840,15 +836,21 @@ 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 | SYNCHRONIZE, &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 );
     if (!pipe)
     {
         set_error( STATUS_PIPE_NOT_AVAILABLE );
+        release_object( device );
         return;
     }
     server = find_server( pipe, ps_wait_open );
@@ -856,7 +858,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
@@ -869,13 +871,14 @@ 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 );
+    release_object( device );
 }
 
 DECL_HANDLER(disconnect_named_pipe)
diff --git a/server/protocol.def b/server/protocol.def
index e4f3662..d46e44e 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


More information about the wine-patches mailing list