reactos/reactos/lib/kernel32/file/npipe.c

825 lines
16 KiB
C
Raw Normal View History

/* $Id: npipe.c,v 1.13 2002/09/08 10:22:42 chorns Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/kernel32/file/npipe.c
* PURPOSE: Directory functions
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
* UPDATE HISTORY:
*/
/* INCLUDES *****************************************************************/
#include <ddk/ntddk.h>
#include <ntdll/rtl.h>
#include <windows.h>
#include <kernel32/error.h>
//#include <wchar.h>
//#include <string.h>
#include <limits.h>
#include <napi/npipe.h>
//#define NDEBUG
#include <kernel32/kernel32.h>
/* FUNCTIONS ****************************************************************/
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,
nMaxInstances,
nOutBufferSize,
nInBufferSize,
nDefaultTimeOut,
lpSecurityAttributes);
RtlFreeUnicodeString(&NameU);
return(NamedPipeHandle);
}
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;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE PipeHandle;
ACCESS_MASK DesiredAccess;
ULONG CreateOptions;
ULONG CreateDisposition;
BOOLEAN WriteModeMessage;
BOOLEAN ReadModeMessage;
BOOLEAN NonBlocking;
IO_STATUS_BLOCK Iosb;
ULONG ShareAccess;
LARGE_INTEGER DefaultTimeOut;
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);
InitializeObjectAttributes(&ObjectAttributes,
&NamedPipeName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
DesiredAccess = 0;
ShareAccess = 0;
CreateDisposition = FILE_OPEN_IF;
CreateOptions = 0;
if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
{
CreateOptions = CreateOptions | FILE_WRITE_THROUGH;
}
if (dwOpenMode & FILE_FLAG_OVERLAPPED)
{
CreateOptions = CreateOptions | FILE_SYNCHRONOUS_IO_ALERT;
}
if (dwOpenMode & PIPE_ACCESS_DUPLEX)
{
CreateOptions = CreateOptions | FILE_PIPE_FULL_DUPLEX;
}
else if (dwOpenMode & PIPE_ACCESS_INBOUND)
{
CreateOptions = CreateOptions | FILE_PIPE_INBOUND;
}
else if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
{
CreateOptions = CreateOptions | FILE_PIPE_OUTBOUND;
}
if (dwPipeMode & PIPE_TYPE_BYTE)
{
WriteModeMessage = FALSE;
}
else if (dwPipeMode & PIPE_TYPE_MESSAGE)
{
WriteModeMessage = TRUE;
}
else
{
WriteModeMessage = FALSE;
}
if (dwPipeMode & PIPE_READMODE_BYTE)
{
ReadModeMessage = FALSE;
}
else if (dwPipeMode & PIPE_READMODE_MESSAGE)
{
ReadModeMessage = TRUE;
}
else
{
ReadModeMessage = FALSE;
}
if (dwPipeMode & PIPE_WAIT)
{
NonBlocking = FALSE;
}
else if (dwPipeMode & PIPE_NOWAIT)
{
NonBlocking = TRUE;
}
else
{
NonBlocking = FALSE;
}
if (nMaxInstances >= PIPE_UNLIMITED_INSTANCES)
{
nMaxInstances = ULONG_MAX;
}
DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000;
Status = NtCreateNamedPipeFile(&PipeHandle,
DesiredAccess,
&ObjectAttributes,
&Iosb,
ShareAccess,
CreateDisposition,
CreateOptions,
WriteModeMessage,
ReadModeMessage,
NonBlocking,
nMaxInstances,
nInBufferSize,
nOutBufferSize,
&DefaultTimeOut);
RtlFreeUnicodeString(&NamedPipeName);
if (!NT_SUCCESS(Status))
{
DPRINT("NtCreateNamedPipe failed (Status %x)!\n", Status);
SetLastErrorByStatus (Status);
return(INVALID_HANDLE_VALUE);
}
return(PipeHandle);
}
BOOL STDCALL
WaitNamedPipeA(LPCSTR lpNamedPipeName,
DWORD nTimeOut)
{
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);
}
BOOL STDCALL
WaitNamedPipeW(LPCWSTR lpNamedPipeName,
DWORD nTimeOut)
{
UNICODE_STRING NamedPipeName;
BOOL r;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
NPFS_WAIT_PIPE WaitPipe;
HANDLE FileHandle;
IO_STATUS_BLOCK Iosb;
r = RtlDosPathNameToNtPathName_U((LPWSTR)lpNamedPipeName,
&NamedPipeName,
NULL,
NULL);
if (!r)
{
return(FALSE);
}
InitializeObjectAttributes(&ObjectAttributes,
&NamedPipeName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(&FileHandle,
FILE_GENERIC_READ,
&ObjectAttributes,
&Iosb,
0,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status))
{
SetLastErrorByStatus (Status);
return(FALSE);
}
WaitPipe.Timeout.QuadPart = nTimeOut * -10000;
Status = NtFsControlFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
FSCTL_PIPE_WAIT,
&WaitPipe,
sizeof(WaitPipe),
NULL,
0);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
{
SetLastErrorByStatus (Status);
return(FALSE);
}
return(TRUE);
}
BOOL STDCALL
ConnectNamedPipe(HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped)
{
PIO_STATUS_BLOCK IoStatusBlock;
IO_STATUS_BLOCK Iosb;
HANDLE hEvent;
NTSTATUS Status;
if (lpOverlapped != NULL)
{
lpOverlapped->Internal = STATUS_PENDING;
hEvent = lpOverlapped->hEvent;
IoStatusBlock = (PIO_STATUS_BLOCK)lpOverlapped;
}
else
{
IoStatusBlock = &Iosb;
hEvent = NULL;
}
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);
}
BOOL STDCALL
SetNamedPipeHandleState(HANDLE hNamedPipe,
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;
}
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);
}
}
return(TRUE);
}
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);
}
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);
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 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);
}
WINBOOL STDCALL
GetNamedPipeHandleStateW(HANDLE hNamedPipe,
LPDWORD lpState,
LPDWORD lpCurInstances,
LPDWORD lpMaxCollectionCount,
LPDWORD lpCollectDataTimeout,
LPWSTR lpUserName,
DWORD nMaxUserNameSize)
{
FILE_PIPE_LOCAL_INFORMATION LocalInfo;
FILE_PIPE_INFORMATION PipeInfo;
IO_STATUS_BLOCK StatusBlock;
NTSTATUS Status;
if (lpState != NULL)
{
Status = NtQueryInformationFile(hNamedPipe,
&StatusBlock,
&PipeInfo,
sizeof(FILE_PIPE_INFORMATION),
FilePipeInformation);
if (!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return(FALSE);
}
*lpState = 0; /* FIXME */
}
if (lpCurInstances != NULL)
{
Status = NtQueryInformationFile(hNamedPipe,
&StatusBlock,
&LocalInfo,
sizeof(FILE_PIPE_LOCAL_INFORMATION),
FilePipeLocalInformation);
if (!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return(FALSE);
}
*lpCurInstances = min(LocalInfo.CurrentInstances, 255);
}
/* FIXME: retrieve remaining information */
return(TRUE);
}
WINBOOL STDCALL
GetNamedPipeHandleStateA(HANDLE hNamedPipe,
LPDWORD lpState,
LPDWORD lpCurInstances,
LPDWORD lpMaxCollectionCount,
LPDWORD lpCollectDataTimeout,
LPSTR lpUserName,
DWORD nMaxUserNameSize)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
WINBOOL 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);
}
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);
}
BOOL STDCALL
TransactNamedPipe(HANDLE hNamedPipe,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesRead,
LPOVERLAPPED lpOverlapped)
{
IO_STATUS_BLOCK IoStatusBlock;
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 (!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return(FALSE);
}
return(TRUE);
}
/* EOF */