-/*
+/* $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,
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;
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,
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 */