-/* $Id$
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS system libraries
+ * PROJECT: ReactOS Win32 Kernel Library
* FILE: lib/kernel32/file/npipe.c
- * PURPOSE: Directory functions
- * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
- * UPDATE HISTORY:
+ * 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 STDCALL
+HANDLE
+WINAPI
CreateNamedPipeA(LPCSTR lpName,
- DWORD dwOpenMode,
- DWORD dwPipeMode,
- DWORD nMaxInstances,
- DWORD nOutBufferSize,
- DWORD nInBufferSize,
- DWORD nDefaultTimeOut,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+ 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);
+ 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
+HANDLE
+STDCALL
CreateNamedPipeW(LPCWSTR lpName,
- DWORD dwOpenMode,
- DWORD dwPipeMode,
- DWORD nMaxInstances,
- DWORD nOutBufferSize,
- DWORD nInBufferSize,
- DWORD nDefaultTimeOut,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+ 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 WriteModeMessage;
- ULONG ReadModeMessage;
- ULONG NonBlocking;
- IO_STATUS_BLOCK Iosb;
- ULONG ShareAccess, Attributes;
- LARGE_INTEGER DefaultTimeOut;
- PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
-
- if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return INVALID_HANDLE_VALUE;
- }
-
- Result = RtlDosPathNameToNtPathName_U((LPWSTR)lpName,
- &NamedPipeName,
- NULL,
- NULL);
- if (!Result)
- {
- SetLastError(ERROR_PATH_NOT_FOUND);
- return(INVALID_HANDLE_VALUE);
- }
+ 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;
- DPRINT("Pipe name: %wZ\n", &NamedPipeName);
- DPRINT("Pipe name: %S\n", NamedPipeName.Buffer);
+ /* Check for valid instances */
+ if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES)
+ {
+ /* Fail */
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
- Attributes = OBJ_CASE_INSENSITIVE;
- if(lpSecurityAttributes)
- {
- SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
- if(lpSecurityAttributes->bInheritHandle)
- Attributes |= OBJ_INHERIT;
- }
+ /* Convert to NT syntax */
+ if (nMaxInstances == PIPE_UNLIMITED_INSTANCES) nMaxInstances = -1;
- InitializeObjectAttributes(&ObjectAttributes,
- &NamedPipeName,
- Attributes,
- NULL,
- SecurityDescriptor);
-
- DesiredAccess = SYNCHRONIZE | (dwOpenMode & (WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY));
- ShareAccess = 0;
- CreateOptions = 0;
-
- if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
- CreateOptions = CreateOptions | FILE_WRITE_THROUGH;
-
- if (!(dwOpenMode & FILE_FLAG_OVERLAPPED))
- CreateOptions = CreateOptions | FILE_SYNCHRONOUS_IO_NONALERT;
-
- switch (dwOpenMode & PIPE_ACCESS_DUPLEX)
- {
- case PIPE_ACCESS_INBOUND:
- CreateOptions |= FILE_PIPE_INBOUND;
- ShareAccess |= FILE_SHARE_WRITE;
- DesiredAccess |= GENERIC_READ;
- break;
-
- case PIPE_ACCESS_OUTBOUND:
- CreateOptions |= FILE_PIPE_OUTBOUND;
- ShareAccess |= FILE_SHARE_READ;
- DesiredAccess |= GENERIC_WRITE;
- break;
-
- case PIPE_ACCESS_DUPLEX:
- CreateOptions |= FILE_PIPE_FULL_DUPLEX;
- ShareAccess |= (FILE_SHARE_READ | FILE_SHARE_WRITE);
- DesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
- break;
- }
-
- if (dwPipeMode & PIPE_TYPE_MESSAGE)
- WriteModeMessage = FILE_PIPE_MESSAGE_MODE;
- else
- WriteModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
+ /* Convert the name */
+ Result = RtlDosPathNameToNtPathName_U((LPWSTR)lpName,
+ &NamedPipeName,
+ NULL,
+ NULL);
+ if (!Result)
+ {
+ /* Conversion failed */
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return(INVALID_HANDLE_VALUE);
+ }
- if (dwPipeMode & PIPE_READMODE_MESSAGE)
- ReadModeMessage = FILE_PIPE_MESSAGE_MODE;
- else
- ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
+ DPRINT("Pipe name: %wZ\n", &NamedPipeName);
+ DPRINT("Pipe name: %S\n", NamedPipeName.Buffer);
- if (dwPipeMode & PIPE_NOWAIT)
- NonBlocking = FILE_PIPE_COMPLETE_OPERATION;
- else
- NonBlocking = FILE_PIPE_QUEUE_OPERATION;
-
- DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000LL;
-
- Status = NtCreateNamedPipeFile(&PipeHandle,
- DesiredAccess,
- &ObjectAttributes,
- &Iosb,
- ShareAccess,
- FILE_OPEN_IF,
- CreateOptions,
- WriteModeMessage,
- ReadModeMessage,
- NonBlocking,
- nMaxInstances,
- nInBufferSize,
- nOutBufferSize,
- &DefaultTimeOut);
-
- RtlFreeUnicodeString(&NamedPipeName);
+ /* Always case insensitive, check if we got extra attributes */
+ Attributes = OBJ_CASE_INSENSITIVE;
+ if(lpSecurityAttributes)
+ {
+ /* We did; get the security descriptor */
+ SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NtCreateNamedPipe failed (Status %x)!\n", Status);
- SetLastErrorByStatus (Status);
- return INVALID_HANDLE_VALUE;
- }
+ /* And check if this is pipe's handle will beinheritable */
+ if(lpSecurityAttributes->bInheritHandle) Attributes |= OBJ_INHERIT;
+ }
- return PipeHandle;
-}
+ /* 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);
+
+ /* Free the name */
+ RtlFreeUnicodeString(&NamedPipeName);
+
+ /* 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 STDCALL
+BOOL
+WINAPI
WaitNamedPipeA(LPCSTR lpNamedPipeName,
- DWORD nTimeOut)
+ DWORD nTimeOut)
{
- BOOL r;
- UNICODE_STRING NameU;
- ANSI_STRING NameA;
+ BOOL r;
+ UNICODE_STRING NameU;
- RtlInitAnsiString(&NameA, (LPSTR)lpNamedPipeName);
- RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
+ /* Convert the name to Unicode */
+ Basep8BitStringToLiveUnicodeString(&NameU, lpNamedPipeName);
- r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
+ /* Call the Unicode API */
+ r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
- RtlFreeUnicodeString(&NameU);
+ /* Free the Unicode string */
+ RtlFreeUnicodeString(&NameU);
- return(r);
+ /* 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;
+ }
+
+ /* 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);
+ 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);
+
+ /* 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
+ {
+ /* Convert to NT format */
+ WaitPipeInfo->Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut);
+ }
+
+ /* In both cases, we do have a timeout */
+ WaitPipeInfo->TimeoutSpecified = FALSE;
+ }
+
+ /* Set the length and copy the name */
+ WaitPipeInfo->NameLength = NewName.Length;
+ RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length);
+
+ /* Get rid of the full name */
+ RtlFreeUnicodeString(&NamedPipeName);
+
+ /* Let NPFS know of our request */
+ Status = NtFsControlFile(FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_PIPE_WAIT,
+ WaitPipeInfo,
+ WaitPipeInfoSize,
+ NULL,
+ 0);
+
+ /* Free our pipe info data and close the handle */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
+ NtClose(FileHandle);
+
+ /* Check the status */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failure to wait on the pipe */
+ DPRINT1("Status: %lx\n", Status);
+ SetLastErrorByStatus (Status);
+ return FALSE;
+ }
+ /* Success */
+ return TRUE;
+}
+#else
/*
* @implemented
*/
return(TRUE);
}
-
+#endif
/*
* @implemented
return TRUE;
}
-
/*
* @implemented
*/
/*
* @implemented
*/
-BOOL STDCALL
+BOOL
+WINAPI
CallNamedPipeA(LPCSTR lpNamedPipeName,
- LPVOID lpInBuffer,
- DWORD nInBufferSize,
- LPVOID lpOutBuffer,
- DWORD nOutBufferSize,
- LPDWORD lpBytesRead,
- DWORD nTimeOut)
+ 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);
+ UNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
+ ANSI_STRING AnsiPipe;
+
+ /* Initialize the string as ANSI_STRING and convert to Unicode */
+ RtlInitAnsiString(&NameA, (LPSTR)lpName);
+ RtlAnsiStringToUnicodeString(NameU, &NameA, FALSE);
+
+ /* Call the Unicode function */
+ return CallNamedPipeW(PipeName->Buffer,
+ lpInBuffer,
+ nInBufferSize,
+ lpOutBuffer,
+ nOutBufferSize,
+ lpBytesRead,
+ nTimeOut);
}
-
/*
* @implemented
*/