📄 npipe.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32 Kernel Library
* FILE: lib/kernel32/file/npipe.c
* PURPOSE: Named Pipe Functions
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
* Ariadne ( ariadne@xs4all.nl)
*/
/* INCLUDES *****************************************************************/
#include <k32.h>
#define NDEBUG
//#define USING_PROPER_NPFS_WAIT_SEMANTICS
#include "../include/debug.h"
/* FUNCTIONS ****************************************************************/
/*
* @implemented
*/
HANDLE
WINAPI
CreateNamedPipeA(LPCSTR lpName,
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
PUNICODE_STRING NameU = &NtCurrentTeb()->StaticUnicodeString;
ANSI_STRING NameA;
/* Initialize the string as ANSI_STRING and convert to Unicode */
RtlInitAnsiString(&NameA, (LPSTR)lpName);
RtlAnsiStringToUnicodeString(NameU, &NameA, FALSE);
/* Call the Unicode API */
return CreateNamedPipeW(NameU->Buffer,
dwOpenMode,
dwPipeMode,
nMaxInstances,
nOutBufferSize,
nInBufferSize,
nDefaultTimeOut,
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;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE PipeHandle;
ACCESS_MASK DesiredAccess;
ULONG CreateOptions = 0;
ULONG WriteModeMessage;
ULONG ReadModeMessage;
ULONG NonBlocking;
IO_STATUS_BLOCK Iosb;
ULONG ShareAccess = 0, Attributes;
LARGE_INTEGER DefaultTimeOut;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
/* Check for valid instances */
if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES)
{
/* Fail */
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
/* Convert to NT syntax */
if (nMaxInstances == PIPE_UNLIMITED_INSTANCES) nMaxInstances = -1;
/* Convert the name */
Result = RtlDosPathNameToNtPathName_U(lpName,
&NamedPipeName,
NULL,
NULL);
if (!Result)
{
/* Conversion failed */
SetLastError(ERROR_PATH_NOT_FOUND);
return(INVALID_HANDLE_VALUE);
}
DPRINT("Pipe name: %wZ\n", &NamedPipeName);
DPRINT("Pipe name: %S\n", NamedPipeName.Buffer);
/* Always case insensitive, check if we got extra attributes */
Attributes = OBJ_CASE_INSENSITIVE;
if(lpSecurityAttributes)
{
/* We did; get the security descriptor */
SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
/* And check if this is pipe's handle will beinheritable */
if(lpSecurityAttributes->bInheritHandle) Attributes |= OBJ_INHERIT;
}
/* Now we can initialize the object attributes */
InitializeObjectAttributes(&ObjectAttributes,
&NamedPipeName,
Attributes,
NULL,
SecurityDescriptor);
/* Setup the default Desired Access */
DesiredAccess = SYNCHRONIZE | (dwOpenMode & (WRITE_DAC |
WRITE_OWNER |
ACCESS_SYSTEM_SECURITY));
/* Convert to NT Create Flags */
if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
{
CreateOptions |= FILE_WRITE_THROUGH;
}
if (!(dwOpenMode & FILE_FLAG_OVERLAPPED))
{
CreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
}
/* Handle all open modes */
if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
{
ShareAccess |= FILE_SHARE_READ;
DesiredAccess |= GENERIC_WRITE;
}
if (dwOpenMode & PIPE_ACCESS_INBOUND)
{
ShareAccess |= FILE_SHARE_WRITE;
DesiredAccess |= GENERIC_READ;
}
/* Handle the type flags */
if (dwPipeMode & PIPE_TYPE_MESSAGE)
{
WriteModeMessage = FILE_PIPE_MESSAGE_TYPE;
}
else
{
WriteModeMessage = FILE_PIPE_BYTE_STREAM_TYPE;
}
/* Handle the mode flags */
if (dwPipeMode & PIPE_READMODE_MESSAGE)
{
ReadModeMessage = FILE_PIPE_MESSAGE_MODE;
}
else
{
ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
}
/* Handle the blocking mode */
if (dwPipeMode & PIPE_NOWAIT)
{
NonBlocking = FILE_PIPE_COMPLETE_OPERATION;
}
else
{
NonBlocking = FILE_PIPE_QUEUE_OPERATION;
}
/* Check if we have a timeout */
if (nDefaultTimeOut)
{
/* Convert the time to NT format */
DefaultTimeOut.QuadPart = UInt32x32To64(nDefaultTimeOut, -10000);
}
else
{
/* Use default timeout of 50 ms */
DefaultTimeOut.QuadPart = -500000;
}
/* Now create the pipe */
Status = NtCreateNamedPipeFile(&PipeHandle,
DesiredAccess,
&ObjectAttributes,
&Iosb,
ShareAccess,
FILE_OPEN_IF,
CreateOptions,
WriteModeMessage,
ReadModeMessage,
NonBlocking,
nMaxInstances,
nInBufferSize,
nOutBufferSize,
&DefaultTimeOut);
/* Normalize special error codes */
if ((Status == STATUS_INVALID_DEVICE_REQUEST) ||
(Status == STATUS_NOT_SUPPORTED))
{
Status = STATUS_OBJECT_NAME_INVALID;
}
/* Free the name */
RtlFreeHeap(RtlGetProcessHeap(),
0,
NamedPipeName.Buffer);
/* Check status */
if (!NT_SUCCESS(Status))
{
/* Failed to create it */
DPRINT1("NtCreateNamedPipe failed (Status %x)!\n", Status);
SetLastErrorByStatus (Status);
return INVALID_HANDLE_VALUE;
}
/* Return the handle */
return PipeHandle;
}
/*
* @implemented
*/
BOOL
WINAPI
WaitNamedPipeA(LPCSTR lpNamedPipeName,
DWORD nTimeOut)
{
BOOL r;
UNICODE_STRING NameU;
/* Convert the name to Unicode */
Basep8BitStringToLiveUnicodeString(&NameU, lpNamedPipeName);
/* Call the Unicode API */
r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
/* Free the Unicode string */
RtlFreeUnicodeString(&NameU);
/* Return result */
return r;
}
/*
* When NPFS will work properly, use this code instead. It is compatible with
* Microsoft's NPFS.SYS. The main difference is that:
* - This code actually respects the timeout instead of ignoring it!
* - This code validates and creates the proper names for both UNC and local pipes
* - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or
* \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the
* FILE_PIPE_WAIT_FOR_BUFFER structure.
*/
#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
/*
* @implemented
*/
BOOL
WINAPI
WaitNamedPipeW(LPCWSTR lpNamedPipeName,
DWORD nTimeOut)
{
UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix;
ULONG NameLength;
ULONG i;
PWCHAR p;
ULONG Type;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE FileHandle;
IO_STATUS_BLOCK IoStatusBlock;
ULONG WaitPipeInfoSize;
PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo;
/* Start by making a unicode string of the name */
DPRINT("Sent path: %S\n", lpNamedPipeName);
RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName);
NameLength = NamedPipeName.Length / sizeof(WCHAR);
/* All slashes must become backslashes */
for (i = 0; i < NameLength; i++)
{
/* Check and convert */
if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\';
}
/* Find the path type of the name we were given */
NewName = NamedPipeName;
Type = RtlDetermineDosPathNameType_U(lpNamedPipeName);
/* Check if this was a device path, ie : "\\.\pipe\name" */
if (Type == DEVICE_PATH)
{
/* Make sure it's a valid prefix */
RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\");
RtlPrefixString((PANSI_STRING)&PipePrefix, (PANSI_STRING)&NewName, TRUE);
/* Move past it */
NewName.Buffer += 9;
NewName.Length -= 9 * sizeof(WCHAR);
/* Initialize the Dos Devices name */
DPRINT("NewName: %wZ\n", &NewName);
RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\");
}
else if (Type == UNC_PATH)
{
/* The path is \\server\\pipe\name; find the pipename itself */
p = &NewName.Buffer[2];
/* First loop to get past the server name */
do
{
/* Check if this is a backslash */
if (*p == L'\\') break;
/* Check next */
p++;
} while (*p);
/* Now make sure the full name contains "pipe\" */
if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\"))))
{
/* Get to the pipe name itself now */
p += sizeof("pipe\\") - 1;
}
else
{
/* The name is invalid */
DPRINT1("Invalid name!\n");
SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD);
return FALSE;
}
/* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
}
else
{
DPRINT1("Invalid path type\n");
SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD);
return FALSE;
}
/* Now calculate the total length of the structure and allocate it */
WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) +
NewName.Length;
WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize);
if (WaitPipeInfo == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
/* Initialize the object attributes */
DPRINT("Opening: %wZ\n", &DevicePath);
InitializeObjectAttributes(&ObjectAttributes,
&DevicePath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Open the path */
Status = NtOpenFile(&FileHandle,
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
{
/* Fail; couldn't open */
DPRINT1("Status: %lx\n", Status);
SetLastErrorByStatus(Status);
RtlFreeUnicodeString(&NamedPipeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
return(FALSE);
}
/* Check what timeout we got */
if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
{
/* Don't use a timeout */
WaitPipeInfo->TimeoutSpecified = FALSE;
}
else
{
/* Check if we should wait forever */
if (nTimeOut == NMPWAIT_WAIT_FOREVER)
{
/* Set the max */
WaitPipeInfo->Timeout.LowPart = 0;
WaitPipeInfo->Timeout.HighPart = 0x80000000;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -