Revert 18883 and 18912, as they break named pipes
[reactos.git] / reactos / lib / kernel32 / file / npipe.c
index 69be3a7..fa8338e 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/file/npipe.c
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <windows.h>
-#include <wchar.h>
-#include <string.h>
-#include <ntdll/rtl.h>
+#include <k32.h>
 
-#include <kernel32/kernel32.h>
+#define NDEBUG
+#include "../include/debug.h"
 
 /* FUNCTIONS ****************************************************************/
 
-HANDLE CreateNamedPipeA(LPCSTR lpName,
-                       DWORD dwOpenMode,
-                       DWORD dwPipeMode,
-                       DWORD nMaxInstances,
-                       DWORD nOutBufferSize,
-                       DWORD nInBufferSize,
-                       DWORD nDefaultTimeOut,
-                       LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+/*
+ * @implemented
+ */
+HANDLE STDCALL
+CreateNamedPipeA(LPCSTR lpName,
+                DWORD dwOpenMode,
+                DWORD dwPipeMode,
+                DWORD nMaxInstances,
+                DWORD nOutBufferSize,
+                DWORD nInBufferSize,
+                DWORD nDefaultTimeOut,
+                LPSECURITY_ATTRIBUTES lpSecurityAttributes)
 {
    HANDLE NamedPipeHandle;
    UNICODE_STRING NameU;
    ANSI_STRING NameA;
-   
+
    RtlInitAnsiString(&NameA, (LPSTR)lpName);
    RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
-   
+
    NamedPipeHandle = CreateNamedPipeW(NameU.Buffer,
                                      dwOpenMode,
                                      dwPipeMode,
@@ -43,20 +45,25 @@ HANDLE CreateNamedPipeA(LPCSTR lpName,
                                      nInBufferSize,
                                      nDefaultTimeOut,
                                      lpSecurityAttributes);
-   
+
    RtlFreeUnicodeString(&NameU);
-   
+
    return(NamedPipeHandle);
 }
 
-HANDLE CreateNamedPipeW(LPCWSTR lpName,
-                       DWORD dwOpenMode,
-                       DWORD dwPipeMode,
-                       DWORD nMaxInstances,
-                       DWORD nOutBufferSize,
-                       DWORD nInBufferSize,
-                       DWORD nDefaultTimeOut,
-                       LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+
+/*
+ * @implemented
+ */
+HANDLE STDCALL
+CreateNamedPipeW(LPCWSTR lpName,
+                DWORD dwOpenMode,
+                DWORD dwPipeMode,
+                DWORD nMaxInstances,
+                DWORD nOutBufferSize,
+                DWORD nInBufferSize,
+                DWORD nDefaultTimeOut,
+                LPSECURITY_ATTRIBUTES lpSecurityAttributes)
 {
    UNICODE_STRING NamedPipeName;
    BOOL Result;
@@ -66,86 +73,115 @@ HANDLE CreateNamedPipeW(LPCWSTR lpName,
    ACCESS_MASK DesiredAccess;
    ULONG CreateOptions;
    ULONG CreateDisposition;
-   BOOLEAN WriteModeMessage;
-   BOOLEAN ReadModeMessage;
-   BOOLEAN NonBlocking;
+   ULONG WriteModeMessage;
+   ULONG ReadModeMessage;
+   ULONG NonBlocking;
    IO_STATUS_BLOCK Iosb;
-   ULONG ShareAccess;
+   ULONG ShareAccess, Attributes;
    LARGE_INTEGER DefaultTimeOut;
-   
+   PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
+
    Result = RtlDosPathNameToNtPathName_U((LPWSTR)lpName,
                                         &NamedPipeName,
                                         NULL,
                                         NULL);
-   
    if (!Result)
      {
+       SetLastError(ERROR_PATH_NOT_FOUND);
        return(INVALID_HANDLE_VALUE);
      }
-   
+
+   DPRINT("Pipe name: %wZ\n", &NamedPipeName);
+   DPRINT("Pipe name: %S\n", NamedPipeName.Buffer);
+
+   Attributes = OBJ_CASE_INSENSITIVE;
+   if(lpSecurityAttributes)
+     {
+       SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
+       if(lpSecurityAttributes->bInheritHandle)
+          Attributes |= OBJ_INHERIT;
+     }
+
    InitializeObjectAttributes(&ObjectAttributes,
                              &NamedPipeName,
-                             0,
+                             Attributes,
                              NULL,
-                             NULL);
-   
+                             SecurityDescriptor);
+
    DesiredAccess = 0;
-   
    ShareAccess = 0;
-   
    CreateDisposition = FILE_OPEN_IF;
-   
-   CreateOptions = 0;   
+   CreateOptions = 0;
    if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
      {
-       CreateOptions = CreateOptions | FILE_FLAG_WRITE_THROUGH;
+       CreateOptions = CreateOptions | FILE_WRITE_THROUGH;
+     }
+   if (!(dwOpenMode & FILE_FLAG_OVERLAPPED))
+     {
+       CreateOptions = CreateOptions | FILE_SYNCHRONOUS_IO_NONALERT;
+     }
+   if (dwOpenMode & PIPE_ACCESS_DUPLEX)
+     {
+       CreateOptions = CreateOptions | FILE_PIPE_FULL_DUPLEX;
+       DesiredAccess |= (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
+     }
+   else if (dwOpenMode & PIPE_ACCESS_INBOUND)
+     {
+       CreateOptions = CreateOptions | FILE_PIPE_INBOUND;
+       DesiredAccess |= FILE_GENERIC_READ;
      }
-   if (dwOpenMode & FILE_FLAG_OVERLAPPED)
+   else if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
      {
-       CreateOptions = CreateOptions | FILE_SYNCHRONOUS_IO_ALERT;
+       CreateOptions = CreateOptions | FILE_PIPE_OUTBOUND;
+       DesiredAccess |= FILE_GENERIC_WRITE;
      }
-   
+
    if (dwPipeMode & PIPE_TYPE_BYTE)
      {
-       WriteModeMessage = FALSE;
+       WriteModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
      }
    else if (dwPipeMode & PIPE_TYPE_MESSAGE)
      {
-       WriteModeMessage = TRUE;
+       WriteModeMessage = FILE_PIPE_MESSAGE_MODE;
      }
    else
      {
-       WriteModeMessage = FALSE;
+       WriteModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
      }
-   
+
    if (dwPipeMode & PIPE_READMODE_BYTE)
      {
-       ReadModeMessage = FALSE;
+       ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
      }
    else if (dwPipeMode & PIPE_READMODE_MESSAGE)
      {
-       ReadModeMessage = TRUE;
+       ReadModeMessage = FILE_PIPE_MESSAGE_MODE;
      }
    else
      {
-       ReadModeMessage = FALSE;
+       ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
      }
-   
+
    if (dwPipeMode & PIPE_WAIT)
      {
-       NonBlocking = FALSE;
+       NonBlocking = FILE_PIPE_QUEUE_OPERATION;
      }
    else if (dwPipeMode & PIPE_NOWAIT)
      {
-       NonBlocking = TRUE;
+       NonBlocking = FILE_PIPE_COMPLETE_OPERATION;
      }
    else
      {
-       NonBlocking = FALSE;
+       NonBlocking = FILE_PIPE_QUEUE_OPERATION;
+     }
+
+   if (nMaxInstances >= PIPE_UNLIMITED_INSTANCES)
+     {
+       nMaxInstances = 0xFFFFFFFF;
      }
-   
-   DefaultTimeOut.QuadPart = nDefaultTimeOut * 1000 * 1000;
-     
+
+   DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000LL;
+
    Status = NtCreateNamedPipeFile(&PipeHandle,
                                  DesiredAccess,
                                  &ObjectAttributes,
@@ -160,217 +196,770 @@ HANDLE CreateNamedPipeW(LPCWSTR lpName,
                                  nInBufferSize,
                                  nOutBufferSize,
                                  &DefaultTimeOut);
+
+   RtlFreeUnicodeString(&NamedPipeName);
+
    if (!NT_SUCCESS(Status))
      {
-       SetLastError(RtlNtStatusToDosError(Status));
-       return(INVALID_HANDLE_VALUE);
+       DPRINT("NtCreateNamedPipe failed (Status %x)!\n", Status);
+       SetLastErrorByStatus (Status);
+       return INVALID_HANDLE_VALUE;
      }
-   return(PipeHandle);
+
+   return PipeHandle;
 }
 
-BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName,
-                   DWORD nTimeOut)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+WaitNamedPipeA(LPCSTR lpNamedPipeName,
+              DWORD nTimeOut)
 {
    BOOL r;
    UNICODE_STRING NameU;
    ANSI_STRING NameA;
-   
-   RtlInitAnsiString(&NameA, lpNamedPipeName);
+
+   RtlInitAnsiString(&NameA, (LPSTR)lpNamedPipeName);
    RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
-   
+
    r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
-   
+
    RtlFreeUnicodeString(&NameU);
-   
+
    return(r);
 }
 
-BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName,
-                   DWORD nTimeOut)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+WaitNamedPipeW(LPCWSTR lpNamedPipeName,
+              DWORD nTimeOut)
 {
    UNICODE_STRING NamedPipeName;
    BOOL r;
    NTSTATUS Status;
    OBJECT_ATTRIBUTES ObjectAttributes;
-   NPFS_WAIT_PIPE WaitPipe;
+   FILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
    HANDLE FileHandle;
    IO_STATUS_BLOCK Iosb;
-   
-   r = RtlDosPathNameToNtPathName_U(lpNamedPipeName,
+
+   r = RtlDosPathNameToNtPathName_U((LPWSTR)lpNamedPipeName,
                                    &NamedPipeName,
                                    NULL,
                                    NULL);
-   
    if (!r)
      {
        return(FALSE);
      }
-   
+
    InitializeObjectAttributes(&ObjectAttributes,
                              &NamedPipeName,
-                             0,
+                             OBJ_CASE_INSENSITIVE,
                              NULL,
                              NULL);
    Status = NtOpenFile(&FileHandle,
-                      FILE_GENERIC_READ,
+                      FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                       &ObjectAttributes,
                       &Iosb,
-                      0,
-                      FILE_SYNCHRONOUS_IO_ALERT);
+                      FILE_SHARE_READ | FILE_SHARE_WRITE,
+                      FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(Status))
      {
-       SetLastError(RtlNtStatusToDosError(Status));
+       SetLastErrorByStatus (Status);
        return(FALSE);
      }
-   
-   WaitPipe.Timeout.QuadPart = nTimeOut * 1000 * 1000;
-   
+
+   WaitPipe.Timeout.QuadPart = nTimeOut * -10000LL;
+
    Status = NtFsControlFile(FileHandle,
                            NULL,
                            NULL,
                            NULL,
                            &Iosb,
-                           FSCTL_WAIT_PIPE,
+                           FSCTL_PIPE_WAIT,
                            &WaitPipe,
                            sizeof(WaitPipe),
                            NULL,
                            0);
+   NtClose(FileHandle);
    if (!NT_SUCCESS(Status))
      {
-       SetLastError(RtlNtStatusToDosError(Status));
+       SetLastErrorByStatus (Status);
        return(FALSE);
      }
-   
-   NtClose(FileHandle);
+
    return(TRUE);
 }
 
-BOOL ConnectNamedPipe(HANDLE hNamedPipe,
-                     LPOVERLAPPED lpOverLapped)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+ConnectNamedPipe(IN HANDLE hNamedPipe,
+                 IN LPOVERLAPPED lpOverlapped)
 {
-   NPFS_LISTEN ListenPipe;
-   IO_STATUS_BLOCK Iosb;
-   HANDLE hEvent;
-   PIO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS Status;
-   
-   if (lpOverLapped != NULL) 
+
+   if (lpOverlapped != NULL)
      {
-       lpOverLapped->Internal = STATUS_PENDING;
-       hEvent = lpOverLapped->hEvent;
-       IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped;
+        PVOID ApcContext;
+
+        lpOverlapped->Internal = STATUS_PENDING;
+        ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
+
+        Status = NtFsControlFile(hNamedPipe,
+                                 lpOverlapped->hEvent,
+                                 NULL,
+                                 ApcContext,
+                                 (PIO_STATUS_BLOCK)lpOverlapped,
+                                 FSCTL_PIPE_LISTEN,
+                                 NULL,
+                                 0,
+                                 NULL,
+                                 0);
+
+        /* return FALSE in case of failure and pending operations! */
+        if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
+          {
+             SetLastErrorByStatus(Status);
+             return FALSE;
+          }
      }
-   else 
+   else
      {
-       IoStatusBlock = &Iosb;
-       hEvent = NULL;
+        IO_STATUS_BLOCK Iosb;
+
+        Status = NtFsControlFile(hNamedPipe,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 &Iosb,
+                                 FSCTL_PIPE_LISTEN,
+                                 NULL,
+                                 0,
+                                 NULL,
+                                 0);
+
+        /* wait in case operation is pending */
+        if (Status == STATUS_PENDING)
+          {
+             Status = NtWaitForSingleObject(hNamedPipe,
+                                            FALSE,
+                                            NULL);
+             if (NT_SUCCESS(Status))
+               {
+                  Status = Iosb.Status;
+               }
+          }
+
+        if (!NT_SUCCESS(Status))
+          {
+             SetLastErrorByStatus(Status);
+             return FALSE;
+          }
      }
-   
-   Status = NtFsControlFile(hNamedPipe,
-                           hEvent,
-                           NULL,
-                           NULL,
-                           IoStatusBlock,
-                           FSCTL_LISTEN,
-                           &ListenPipe,
-                           sizeof(ListenPipe),
-                           NULL,
-                           0);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastError(RtlNtStatusToDosError(Status));
+
+   return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL 
+STDCALL
+SetNamedPipeHandleState(HANDLE hNamedPipe,
+                        LPDWORD lpMode,
+                        LPDWORD lpMaxCollectionCount,
+                        LPDWORD lpCollectDataTimeout)
+{
+    IO_STATUS_BLOCK Iosb;
+    NTSTATUS Status;
+
+    /* Check if the Mode is being changed */
+    if (lpMode)
+    {
+        FILE_PIPE_INFORMATION Settings;
+
+        /* Set the Completion Mode */
+        Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
+                                  FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
+
+        /* Set the Read Mode */
+        Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
+                            FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE;
+
+        /* Send the changes to the Driver */ 
+        Status = NtSetInformationFile(hNamedPipe,
+                                      &Iosb,
+                                      &Settings,
+                                      sizeof(FILE_PIPE_INFORMATION),
+                                      FilePipeInformation);
+        if (!NT_SUCCESS(Status))
+        {
+            SetLastErrorByStatus(Status);
+            return(FALSE);
+        }
+    }
+    
+    /* Check if the Collection count or Timeout are being changed */
+    if (lpMaxCollectionCount || lpCollectDataTimeout)
+    {
+        FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
+
+        /* Setting one without the other would delete it, so we read old one */
+        if (!lpMaxCollectionCount || !lpCollectDataTimeout)
+        {
+            Status = NtQueryInformationFile(hNamedPipe,
+                                            &Iosb,
+                                            &RemoteSettings,
+                                            sizeof(FILE_PIPE_REMOTE_INFORMATION),
+                                            FilePipeRemoteInformation);
+
+            if (!NT_SUCCESS(Status))
+            {
+                SetLastErrorByStatus(Status);
+                return(FALSE);
+            }
+        }
+
+        /* Now set the new settings */    
+        RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ? 
+                                                *lpMaxCollectionCount : 
+                                                RemoteSettings.MaximumCollectionCount;
+        if (lpCollectDataTimeout)
+        {
+            /* Convert it to Quad */
+            RemoteSettings.CollectDataTime.QuadPart = -(LONGLONG)
+                                                       UInt32x32To64(10000,
+                                                                     *lpCollectDataTimeout);
+        }
+
+        /* Tell the driver to change them */
+        Status = NtSetInformationFile(hNamedPipe,
+                                      &Iosb,
+                                      &RemoteSettings,
+                                      sizeof(FILE_PIPE_REMOTE_INFORMATION),
+                                      FilePipeRemoteInformation);
+
+        if (!NT_SUCCESS(Status))
+        {
+            SetLastErrorByStatus(Status);
+            return(FALSE);
+        }
+    }
+
+    /* All done */
+    return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+CallNamedPipeA(LPCSTR lpNamedPipeName,
+              LPVOID lpInBuffer,
+              DWORD nInBufferSize,
+              LPVOID lpOutBuffer,
+              DWORD nOutBufferSize,
+              LPDWORD lpBytesRead,
+              DWORD nTimeOut)
+{
+  UNICODE_STRING PipeName;
+  BOOL Result;
+
+  RtlCreateUnicodeStringFromAsciiz(&PipeName,
+                                  (LPSTR)lpNamedPipeName);
+
+  Result = CallNamedPipeW(PipeName.Buffer,
+                         lpInBuffer,
+                         nInBufferSize,
+                         lpOutBuffer,
+                         nOutBufferSize,
+                         lpBytesRead,
+                         nTimeOut);
+
+  RtlFreeUnicodeString(&PipeName);
+
+  return(Result);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+CallNamedPipeW(LPCWSTR lpNamedPipeName,
+              LPVOID lpInBuffer,
+              DWORD nInBufferSize,
+              LPVOID lpOutBuffer,
+              DWORD nOutBufferSize,
+              LPDWORD lpBytesRead,
+              DWORD nTimeOut)
+{
+  HANDLE hPipe = INVALID_HANDLE_VALUE;
+  BOOL bRetry = TRUE;
+  BOOL bError = FALSE;
+  DWORD dwPipeMode;
+
+  while (TRUE)
+    {
+      hPipe = CreateFileW(lpNamedPipeName,
+                         GENERIC_READ | GENERIC_WRITE,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE,
+                         NULL,
+                         OPEN_EXISTING,
+                         FILE_ATTRIBUTE_NORMAL,
+                         NULL);
+      if (hPipe != INVALID_HANDLE_VALUE)
+       break;
+
+      if (bRetry == FALSE)
        return(FALSE);
-     }
-   return(TRUE);
+
+      WaitNamedPipeW(lpNamedPipeName,
+                    nTimeOut);
+
+      bRetry = FALSE;
+    }
+
+  dwPipeMode = PIPE_READMODE_MESSAGE;
+  bError = SetNamedPipeHandleState(hPipe,
+                                  &dwPipeMode,
+                                  NULL,
+                                  NULL);
+  if (!bError)
+    {
+      CloseHandle(hPipe);
+      return(FALSE);
+    }
+
+  bError = TransactNamedPipe(hPipe,
+                            lpInBuffer,
+                            nInBufferSize,
+                            lpOutBuffer,
+                            nOutBufferSize,
+                            lpBytesRead,
+                            NULL);
+  CloseHandle(hPipe);
+
+  return(bError);
 }
 
-BOOL SetNamedPipeHandleState(HANDLE hNamedPipe,
-                            LPDWORD lpMode,
-                            LPDWORD lpMaxCollectionCount,
-                            LPDWORD lpCollectDataTimeout)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+DisconnectNamedPipe(HANDLE hNamedPipe)
+{
+  IO_STATUS_BLOCK Iosb;
+  NTSTATUS Status;
+
+  Status = NtFsControlFile(hNamedPipe,
+                          NULL,
+                          NULL,
+                          NULL,
+                          &Iosb,
+                          FSCTL_PIPE_DISCONNECT,
+                          NULL,
+                          0,
+                          NULL,
+                          0);
+  if (Status == STATUS_PENDING)
+    {
+      Status = NtWaitForSingleObject(hNamedPipe,
+                                    FALSE,
+                                    NULL);
+      if (!NT_SUCCESS(Status))
+       {
+         SetLastErrorByStatus(Status);
+         return(FALSE);
+       }
+    }
+
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      return(FALSE);
+    }
+  return(TRUE);
+}
+
+
+/*
+ * @unimplemented
+ */
+BOOL STDCALL
+GetNamedPipeHandleStateW(HANDLE hNamedPipe,
+                        LPDWORD lpState,
+                        LPDWORD lpCurInstances,
+                        LPDWORD lpMaxCollectionCount,
+                        LPDWORD lpCollectDataTimeout,
+                        LPWSTR lpUserName,
+                        DWORD nMaxUserNameSize)
+{
+  IO_STATUS_BLOCK StatusBlock;
+  NTSTATUS Status;
+
+  if (lpState != NULL)
+  {
+    FILE_PIPE_INFORMATION PipeInfo;
+
+    Status = NtQueryInformationFile(hNamedPipe,
+                                    &StatusBlock,
+                                    &PipeInfo,
+                                    sizeof(FILE_PIPE_INFORMATION),
+                                    FilePipeInformation);
+    if (!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      return FALSE;
+    }
+
+    *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
+    *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
+  }
+
+  if(lpCurInstances != NULL)
+  {
+    FILE_PIPE_LOCAL_INFORMATION LocalInfo;
+
+    Status = NtQueryInformationFile(hNamedPipe,
+                                    &StatusBlock,
+                                    &LocalInfo,
+                                    sizeof(FILE_PIPE_LOCAL_INFORMATION),
+                                    FilePipeLocalInformation);
+    if(!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      return FALSE;
+    }
+
+    *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
+  }
+
+  if(lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
+  {
+    FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
+
+    Status = NtQueryInformationFile(hNamedPipe,
+                                    &StatusBlock,
+                                    &RemoteInfo,
+                                    sizeof(FILE_PIPE_REMOTE_INFORMATION),
+                                    FilePipeRemoteInformation);
+    if(!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      return FALSE;
+    }
+
+    if(lpMaxCollectionCount != NULL)
+    {
+      *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
+    }
+
+    if(lpCollectDataTimeout != NULL)
+    {
+      /* FIXME */
+      *lpCollectDataTimeout = 0;
+    }
+  }
+
+  if(lpUserName != NULL)
+  {
+    /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
+               retreive the user name with GetUserName(), revert the impersonation
+               and finally restore the thread token */
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetNamedPipeHandleStateA(HANDLE hNamedPipe,
+                        LPDWORD lpState,
+                        LPDWORD lpCurInstances,
+                        LPDWORD lpMaxCollectionCount,
+                        LPDWORD lpCollectDataTimeout,
+                        LPSTR lpUserName,
+                        DWORD nMaxUserNameSize)
+{
+  UNICODE_STRING UserNameW;
+  ANSI_STRING UserNameA;
+  BOOL Ret;
+
+  if(lpUserName != NULL)
+  {
+    UserNameW.Length = 0;
+    UserNameW.MaximumLength = nMaxUserNameSize * sizeof(WCHAR);
+    UserNameW.Buffer = HeapAlloc(GetCurrentProcess(), 0, UserNameW.MaximumLength);
+
+    UserNameA.Buffer = lpUserName;
+    UserNameA.Length = 0;
+    UserNameA.MaximumLength = nMaxUserNameSize;
+  }
+
+  Ret = GetNamedPipeHandleStateW(hNamedPipe,
+                                 lpState,
+                                 lpCurInstances,
+                                 lpMaxCollectionCount,
+                                 lpCollectDataTimeout,
+                                 UserNameW.Buffer,
+                                 nMaxUserNameSize);
+
+  if(Ret && lpUserName != NULL)
+  {
+    NTSTATUS Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
+    if(!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      Ret = FALSE;
+    }
+  }
+
+  if(UserNameW.Buffer != NULL)
+  {
+    HeapFree(GetCurrentProcess(), 0, UserNameW.Buffer);
+  }
+
+  return Ret;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetNamedPipeInfo(HANDLE hNamedPipe,
+                LPDWORD lpFlags,
+                LPDWORD lpOutBufferSize,
+                LPDWORD lpInBufferSize,
+                LPDWORD lpMaxInstances)
+{
+  FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
+  IO_STATUS_BLOCK StatusBlock;
+  NTSTATUS Status;
+
+  Status = NtQueryInformationFile(hNamedPipe,
+                                 &StatusBlock,
+                                 &PipeLocalInformation,
+                                 sizeof(FILE_PIPE_LOCAL_INFORMATION),
+                                 FilePipeLocalInformation);
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      return(FALSE);
+    }
+
+  if (lpFlags != NULL)
+    {
+      *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
+      *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
+    }
+
+  if (lpOutBufferSize != NULL)
+    *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
+
+  if (lpInBufferSize != NULL)
+    *lpInBufferSize = PipeLocalInformation.InboundQuota;
+
+  if (lpMaxInstances != NULL)
+    {
+      if (PipeLocalInformation.MaximumInstances >= 255)
+       *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
+      else
+       *lpMaxInstances = PipeLocalInformation.MaximumInstances;
+    }
+
+  return(TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+PeekNamedPipe(HANDLE hNamedPipe,
+             LPVOID lpBuffer,
+             DWORD nBufferSize,
+             LPDWORD lpBytesRead,
+             LPDWORD lpTotalBytesAvail,
+             LPDWORD lpBytesLeftThisMessage)
+{
+  PFILE_PIPE_PEEK_BUFFER Buffer;
+  IO_STATUS_BLOCK Iosb;
+  ULONG BufferSize;
+  NTSTATUS Status;
+
+  BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER);
+  Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                          0,
+                          BufferSize);
+
+  Status = NtFsControlFile(hNamedPipe,
+                          NULL,
+                          NULL,
+                          NULL,
+                          &Iosb,
+                          FSCTL_PIPE_PEEK,
+                          NULL,
+                          0,
+                          Buffer,
+                          BufferSize);
+  if (Status == STATUS_PENDING)
+    {
+      Status = NtWaitForSingleObject(hNamedPipe,
+                                    FALSE,
+                                    NULL);
+      if (NT_SUCCESS(Status))
+       Status = Iosb.Status;
+    }
+
+  if (Status == STATUS_BUFFER_OVERFLOW)
+    {
+      Status = STATUS_SUCCESS;
+    }
+
+  if (!NT_SUCCESS(Status))
+    {
+      RtlFreeHeap(RtlGetProcessHeap(),
+                 0,
+                 Buffer);
+      SetLastErrorByStatus(Status);
+      return(FALSE);
+    }
+
+  if (lpTotalBytesAvail != NULL)
+    {
+      *lpTotalBytesAvail = Buffer->ReadDataAvailable;
+    }
+
+  if (lpBytesRead != NULL)
+    {
+      *lpBytesRead = Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER);
+    }
+
+  if (lpBytesLeftThisMessage != NULL)
+    {
+      *lpBytesLeftThisMessage = Buffer->MessageLength -
+       (Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER));
+    }
+
+  if (lpBuffer != NULL)
+    {
+      memcpy(lpBuffer, Buffer->Data,
+            min(nBufferSize, Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER)));
+    }
+
+  RtlFreeHeap(RtlGetProcessHeap(),
+             0,
+             Buffer);
+
+  return(TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+TransactNamedPipe(IN HANDLE hNamedPipe,
+                  IN LPVOID lpInBuffer,
+                  IN DWORD nInBufferSize,
+                  OUT LPVOID lpOutBuffer,
+                  IN DWORD nOutBufferSize,
+                  OUT LPDWORD lpBytesRead  OPTIONAL,
+                  IN LPOVERLAPPED lpOverlapped  OPTIONAL)
 {
-   NPFS_GET_STATE GetState;
-   NPFS_SET_STATE SetState;
-   IO_STATUS_BLOCK Iosb;
    NTSTATUS Status;
-   
-   Status = NtFsControlFile(hNamedPipe,
-                           NULL,
-                           NULL,
-                           NULL,
-                           &Iosb,
-                           FSCTL_GET_STATE,
-                           NULL,
-                           0,
-                           &GetState,
-                           sizeof(GetState));
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastError(RtlNtStatusToDosError(Status));
-       return(FALSE);
-     }
-   
-   if (lpMode != NULL)
-     {
-       if ((*lpMode) & PIPE_READMODE_MESSAGE)
-         {
-            SetState.ReadModeMessage = TRUE;
-         }
-       else
-         {
-            SetState.ReadModeMessage = FALSE;
-         }
-       if ((*lpMode) & PIPE_NOWAIT)
-         {
-            SetState.NonBlocking = TRUE;
-         }
-       else
-         {
-            SetState.NonBlocking = FALSE;
-         }
-       SetState.WriteModeMessage = GetState.WriteModeMessage;
-     }
-   else
-     {
-       SetState.ReadModeMessage = GetState.ReadModeMessage;
-       SetState.WriteModeMessage = GetState.WriteModeMessage;
-       SetState.NonBlocking = SetState.NonBlocking;
-     }
-   
-   if (lpMaxCollectionCount != NULL)
-     {
-       SetState.InBufferSize = *lpMaxCollectionCount;
-     }
-   else
+
+   if (lpBytesRead != NULL)
      {
-       SetState.InBufferSize = GetState.InBufferSize;
+        *lpBytesRead = 0;
      }
-   
-   SetState.OutBufferSize = GetState.OutBufferSize;
-   
-   if (lpCollectDataTimeout != NULL)
+
+   if (lpOverlapped != NULL)
      {
-       SetState.Timeout.QuadPart = (*lpCollectDataTimeout) * 1000 * 1000;
+        PVOID ApcContext;
+
+        ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
+        lpOverlapped->Internal = STATUS_PENDING;
+
+        Status = NtFsControlFile(hNamedPipe,
+                                 lpOverlapped->hEvent,
+                                 NULL,
+                                 ApcContext,
+                                 (PIO_STATUS_BLOCK)lpOverlapped,
+                                 FSCTL_PIPE_TRANSCEIVE,
+                                 lpInBuffer,
+                                 nInBufferSize,
+                                 lpOutBuffer,
+                                 nOutBufferSize);
+
+        /* return FALSE in case of failure and pending operations! */
+        if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
+          {
+             SetLastErrorByStatus(Status);
+             return FALSE;
+          }
+
+        if (lpBytesRead != NULL)
+          {
+             *lpBytesRead = lpOverlapped->InternalHigh;
+          }
      }
    else
      {
-       SetState.Timeout = GetState.Timeout;
-     }
-   
-   Status = NtFsControlFile(hNamedPipe,
-                           NULL,
-                           NULL,
-                           NULL,
-                           &Iosb,
-                           FSCTL_SET_STATE,
-                           &SetState,
-                           sizeof(SetState),
-                           NULL,
-                           0);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastError(RtlNtStatusToDosError(Status));
-       return(FALSE);
+        IO_STATUS_BLOCK Iosb;
+
+        Status = NtFsControlFile(hNamedPipe,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 &Iosb,
+                                 FSCTL_PIPE_TRANSCEIVE,
+                                 lpInBuffer,
+                                 nInBufferSize,
+                                 lpOutBuffer,
+                                 nOutBufferSize);
+
+        /* wait in case operation is pending */
+        if (Status == STATUS_PENDING)
+          {
+             Status = NtWaitForSingleObject(hNamedPipe,
+                                            FALSE,
+                                            NULL);
+             if (NT_SUCCESS(Status))
+               {
+                  Status = Iosb.Status;
+               }
+          }
+
+        if (NT_SUCCESS(Status))
+          {
+             /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
+                check that case either and crashes (only after the operation
+                completed) */
+             *lpBytesRead = Iosb.Information;
+          }
+        else
+          {
+             SetLastErrorByStatus(Status);
+             return FALSE;
+          }
      }
-   return(TRUE);
+
+   return TRUE;
 }
+
+/* EOF */