Revert 18883 and 18912, as they break named pipes
[reactos.git] / reactos / lib / kernel32 / file / npipe.c
index b2bb35f..fa8338e 100644 (file)
@@ -33,10 +33,10 @@ CreateNamedPipeA(LPCSTR lpName,
    HANDLE NamedPipeHandle;
    UNICODE_STRING NameU;
    ANSI_STRING NameA;
-   
+
    RtlInitAnsiString(&NameA, (LPSTR)lpName);
    RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
-   
+
    NamedPipeHandle = CreateNamedPipeW(NameU.Buffer,
                                      dwOpenMode,
                                      dwPipeMode,
@@ -45,9 +45,9 @@ CreateNamedPipeA(LPCSTR lpName,
                                      nInBufferSize,
                                      nDefaultTimeOut,
                                      lpSecurityAttributes);
-   
+
    RtlFreeUnicodeString(&NameU);
-   
+
    return(NamedPipeHandle);
 }
 
@@ -123,14 +123,17 @@ CreateNamedPipeW(LPCWSTR lpName,
    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;
      }
    else if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
      {
        CreateOptions = CreateOptions | FILE_PIPE_OUTBOUND;
+       DesiredAccess |= FILE_GENERIC_WRITE;
      }
 
    if (dwPipeMode & PIPE_TYPE_BYTE)
@@ -174,10 +177,10 @@ CreateNamedPipeW(LPCWSTR lpName,
 
    if (nMaxInstances >= PIPE_UNLIMITED_INSTANCES)
      {
-       nMaxInstances = ULONG_MAX;
+       nMaxInstances = 0xFFFFFFFF;
      }
 
-   DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000;
+   DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000LL;
 
    Status = NtCreateNamedPipeFile(&PipeHandle,
                                  DesiredAccess,
@@ -217,14 +220,14 @@ WaitNamedPipeA(LPCSTR lpNamedPipeName,
    BOOL r;
    UNICODE_STRING NameU;
    ANSI_STRING NameA;
-   
+
    RtlInitAnsiString(&NameA, (LPSTR)lpNamedPipeName);
    RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
-   
+
    r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
-   
+
    RtlFreeUnicodeString(&NameU);
-   
+
    return(r);
 }
 
@@ -240,10 +243,10 @@ WaitNamedPipeW(LPCWSTR lpNamedPipeName,
    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((LPWSTR)lpNamedPipeName,
                                    &NamedPipeName,
                                    NULL,
@@ -252,14 +255,14 @@ WaitNamedPipeW(LPCWSTR lpNamedPipeName,
      {
        return(FALSE);
      }
-   
+
    InitializeObjectAttributes(&ObjectAttributes,
                              &NamedPipeName,
                              OBJ_CASE_INSENSITIVE,
                              NULL,
                              NULL);
    Status = NtOpenFile(&FileHandle,
-                      FILE_GENERIC_READ,
+                      FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                       &ObjectAttributes,
                       &Iosb,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
@@ -269,9 +272,9 @@ WaitNamedPipeW(LPCWSTR lpNamedPipeName,
        SetLastErrorByStatus (Status);
        return(FALSE);
      }
-   
-   WaitPipe.Timeout.QuadPart = nTimeOut * -10000;
-   
+
+   WaitPipe.Timeout.QuadPart = nTimeOut * -10000LL;
+
    Status = NtFsControlFile(FileHandle,
                            NULL,
                            NULL,
@@ -288,7 +291,7 @@ WaitNamedPipeW(LPCWSTR lpNamedPipeName,
        SetLastErrorByStatus (Status);
        return(FALSE);
      }
-   
+
    return(TRUE);
 }
 
@@ -297,167 +300,164 @@ WaitNamedPipeW(LPCWSTR lpNamedPipeName,
  * @implemented
  */
 BOOL STDCALL
-ConnectNamedPipe(HANDLE hNamedPipe,
-                LPOVERLAPPED lpOverlapped)
+ConnectNamedPipe(IN HANDLE hNamedPipe,
+                 IN LPOVERLAPPED lpOverlapped)
 {
-  PIO_STATUS_BLOCK IoStatusBlock;
-  IO_STATUS_BLOCK Iosb;
-  HANDLE hEvent;
-  NTSTATUS Status;
+   NTSTATUS Status;
 
-  if (lpOverlapped != NULL)
-    {
-      lpOverlapped->Internal = STATUS_PENDING;
-      hEvent = lpOverlapped->hEvent;
-      IoStatusBlock = (PIO_STATUS_BLOCK)lpOverlapped;
-    }
-  else
-    {
-      IoStatusBlock = &Iosb;
-      hEvent = NULL;
-    }
+   if (lpOverlapped != NULL)
+     {
+        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
+     {
+        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_PIPE_LISTEN,
-                          NULL,
-                          0,
-                          NULL,
-                          0);
-  if ((lpOverlapped == NULL) && (Status == STATUS_PENDING))
-    {
-      Status = NtWaitForSingleObject(hNamedPipe,
-                                    FALSE,
-                                    NULL);
-      if (!NT_SUCCESS(Status))
-       {
-         SetLastErrorByStatus(Status);
-         return(FALSE);
-       }
-      Status = Iosb.Status;
-    }
-  if ((!NT_SUCCESS(Status) && Status != STATUS_PIPE_CONNECTED) ||
-      (Status == STATUS_PENDING))
-    {
-      SetLastErrorByStatus(Status);
-      return(FALSE);
-    }
-  return(TRUE);
+   return TRUE;
 }
 
 
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL 
+STDCALL
 SetNamedPipeHandleState(HANDLE hNamedPipe,
-                       LPDWORD lpMode,
-                       LPDWORD lpMaxCollectionCount,
-                       LPDWORD lpCollectDataTimeout)
+                        LPDWORD lpMode,
+                        LPDWORD lpMaxCollectionCount,
+                        LPDWORD lpCollectDataTimeout)
 {
-   NPFS_GET_STATE GetState;
-   NPFS_SET_STATE SetState;
-   IO_STATUS_BLOCK Iosb;
-   NTSTATUS Status;
-
-   Status = NtFsControlFile(hNamedPipe,
-                           NULL,
-                           NULL,
-                           NULL,
-                           &Iosb,
-                           FSCTL_PIPE_GET_STATE,
-                           NULL,
-                           0,
-                           &GetState,
-                           sizeof(NPFS_GET_STATE));
-   if (Status == STATUS_PENDING)
-     {
-       Status = NtWaitForSingleObject(hNamedPipe,
-                                      FALSE,
-                                      NULL);
-       if (!NT_SUCCESS(Status))
-         {
-            SetLastErrorByStatus(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
-     {
-       SetState.InBufferSize = GetState.InBufferSize;
-     }
-   
-   SetState.OutBufferSize = GetState.OutBufferSize;
-   
-   if (lpCollectDataTimeout != NULL)
-     {
-       SetState.Timeout.QuadPart = (*lpCollectDataTimeout) * -10000;
-     }
-   else
-     {
-       SetState.Timeout = GetState.Timeout;
-     }
+    IO_STATUS_BLOCK Iosb;
+    NTSTATUS Status;
 
-   Status = NtFsControlFile(hNamedPipe,
-                           NULL,
-                           NULL,
-                           NULL,
-                           &Iosb,
-                           FSCTL_PIPE_SET_STATE,
-                           &SetState,
-                           sizeof(NPFS_SET_STATE),
-                           NULL,
-                           0);
-   if (Status == STATUS_PENDING)
-     {
-       Status = NtWaitForSingleObject(hNamedPipe,
-                                      FALSE,
-                                      NULL);
-       if (!NT_SUCCESS(Status))
-         {
-            SetLastErrorByStatus(Status);
-            return(FALSE);
-         }
-     }
+    /* 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);
+        }
+    }
 
-  return(TRUE);
+    /* All done */
+    return TRUE;
 }
 
-
 /*
  * @implemented
  */
@@ -472,10 +472,10 @@ CallNamedPipeA(LPCSTR lpNamedPipeName,
 {
   UNICODE_STRING PipeName;
   BOOL Result;
-  
+
   RtlCreateUnicodeStringFromAsciiz(&PipeName,
                                   (LPSTR)lpNamedPipeName);
-  
+
   Result = CallNamedPipeW(PipeName.Buffer,
                          lpInBuffer,
                          nInBufferSize,
@@ -483,9 +483,9 @@ CallNamedPipeA(LPCSTR lpNamedPipeName,
                          nOutBufferSize,
                          lpBytesRead,
                          nTimeOut);
-  
+
   RtlFreeUnicodeString(&PipeName);
-  
+
   return(Result);
 }
 
@@ -610,7 +610,7 @@ GetNamedPipeHandleStateW(HANDLE hNamedPipe,
   if (lpState != NULL)
   {
     FILE_PIPE_INFORMATION PipeInfo;
-    
+
     Status = NtQueryInformationFile(hNamedPipe,
                                     &StatusBlock,
                                     &PipeInfo,
@@ -629,7 +629,7 @@ GetNamedPipeHandleStateW(HANDLE hNamedPipe,
   if(lpCurInstances != NULL)
   {
     FILE_PIPE_LOCAL_INFORMATION LocalInfo;
-    
+
     Status = NtQueryInformationFile(hNamedPipe,
                                     &StatusBlock,
                                     &LocalInfo,
@@ -647,7 +647,7 @@ GetNamedPipeHandleStateW(HANDLE hNamedPipe,
   if(lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
   {
     FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
-    
+
     Status = NtQueryInformationFile(hNamedPipe,
                                     &StatusBlock,
                                     &RemoteInfo,
@@ -663,14 +663,14 @@ GetNamedPipeHandleStateW(HANDLE hNamedPipe,
     {
       *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
     }
-    
+
     if(lpCollectDataTimeout != NULL)
     {
       /* FIXME */
       *lpCollectDataTimeout = 0;
     }
   }
-  
+
   if(lpUserName != NULL)
   {
     /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
@@ -697,18 +697,18 @@ GetNamedPipeHandleStateA(HANDLE hNamedPipe,
   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,
@@ -726,12 +726,12 @@ GetNamedPipeHandleStateA(HANDLE hNamedPipe,
       Ret = FALSE;
     }
   }
-  
+
   if(UserNameW.Buffer != NULL)
   {
     HeapFree(GetCurrentProcess(), 0, UserNameW.Buffer);
   }
-  
+
   return Ret;
 }
 
@@ -749,7 +749,7 @@ GetNamedPipeInfo(HANDLE hNamedPipe,
   FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
   IO_STATUS_BLOCK StatusBlock;
   NTSTATUS Status;
-  
+
   Status = NtQueryInformationFile(hNamedPipe,
                                  &StatusBlock,
                                  &PipeLocalInformation,
@@ -760,19 +760,19 @@ GetNamedPipeInfo(HANDLE hNamedPipe,
       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)
@@ -780,7 +780,7 @@ GetNamedPipeInfo(HANDLE hNamedPipe,
       else
        *lpMaxInstances = PipeLocalInformation.MaximumInstances;
     }
-  
+
   return(TRUE);
 }
 
@@ -873,64 +873,93 @@ PeekNamedPipe(HANDLE hNamedPipe,
  * @implemented
  */
 BOOL STDCALL
-TransactNamedPipe(HANDLE hNamedPipe,
-                 LPVOID lpInBuffer,
-                 DWORD nInBufferSize,
-                 LPVOID lpOutBuffer,
-                 DWORD nOutBufferSize,
-                 LPDWORD lpBytesRead,
-                 LPOVERLAPPED lpOverlapped)
+TransactNamedPipe(IN HANDLE hNamedPipe,
+                  IN LPVOID lpInBuffer,
+                  IN DWORD nInBufferSize,
+                  OUT LPVOID lpOutBuffer,
+                  IN DWORD nOutBufferSize,
+                  OUT LPDWORD lpBytesRead  OPTIONAL,
+                  IN LPOVERLAPPED lpOverlapped  OPTIONAL)
 {
-  IO_STATUS_BLOCK IoStatusBlock;
-  NTSTATUS Status;
+   NTSTATUS Status;
 
-  if (lpOverlapped == NULL)
-    {
-      Status = NtFsControlFile(hNamedPipe,
-                              NULL,
-                              NULL,
-                              NULL,
-                              &IoStatusBlock,
-                              FSCTL_PIPE_TRANSCEIVE,
-                              lpInBuffer,
-                              nInBufferSize,
-                              lpOutBuffer,
-                              nOutBufferSize);
-      if (Status == STATUS_PENDING)
-       {
-         NtWaitForSingleObject(hNamedPipe,
-                               0,
-                               FALSE);
-         Status = IoStatusBlock.Status;
-       }
-      if (NT_SUCCESS(Status))
-       {
-         *lpBytesRead = IoStatusBlock.Information;
-       }
-    }
-  else
-    {
-      lpOverlapped->Internal = STATUS_PENDING;
-
-      Status = NtFsControlFile(hNamedPipe,
-                              lpOverlapped->hEvent,
-                              NULL,
-                              NULL,
-                              (PIO_STATUS_BLOCK)lpOverlapped,
-                              FSCTL_PIPE_TRANSCEIVE,
-                              lpInBuffer,
-                              nInBufferSize,
-                              lpOutBuffer,
-                              nOutBufferSize);
-    }
+   if (lpBytesRead != NULL)
+     {
+        *lpBytesRead = 0;
+     }
 
-  if (!NT_SUCCESS(Status))
-    {
-      SetLastErrorByStatus(Status);
-      return(FALSE);
-    }
+   if (lpOverlapped != NULL)
+     {
+        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
+     {
+        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 */