/* * 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 #define NDEBUG #include DEBUG_CHANNEL(kernel32file); //#define USING_PROPER_NPFS_WAIT_SEMANTICS /* 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 WINAPI 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; } TRACE("Pipe name: %wZ\n", &NamedPipeName); TRACE("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 */ WARN("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 */ Basep8BitStringToHeapUnicodeString(&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 */ TRACE("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 == RtlPathTypeLocalDevice) { /* 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 */ TRACE("NewName: %wZ\n", &NewName); RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\"); } else if (Type == RtlPathTypeRootLocalDevice) { /* 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 */ WARN("Invalid name!\n"); SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD); return FALSE; } /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */ } else { WARN("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 */ TRACE("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 */ WARN("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 { /* Convert to NT format */ WaitPipeInfo->Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut); } /* In both cases, we do have a timeout */ WaitPipeInfo->TimeoutSpecified = TRUE; } /* 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 */ WARN("Status: %lx\n", Status); SetLastErrorByStatus (Status); return FALSE; } /* Success */ return TRUE; } #else /* * @implemented */ BOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut) { UNICODE_STRING NamedPipeName; NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; FILE_PIPE_WAIT_FOR_BUFFER WaitPipe; HANDLE FileHandle; IO_STATUS_BLOCK Iosb; if (RtlDosPathNameToNtPathName_U(lpNamedPipeName, &NamedPipeName, NULL, NULL) == FALSE) { return FALSE; } InitializeObjectAttributes(&ObjectAttributes, &NamedPipeName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjectAttributes, &Iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); RtlFreeUnicodeString(&NamedPipeName); return FALSE; } /* Check what timeout we got */ if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT) { /* Don't use a timeout */ WaitPipe.TimeoutSpecified = FALSE; } else { /* Check if we should wait forever */ if (nTimeOut == NMPWAIT_WAIT_FOREVER) { /* Set the max */ WaitPipe.Timeout.LowPart = 0; WaitPipe.Timeout.HighPart = 0x80000000; } else { /* Convert to NT format */ WaitPipe.Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut); } /* In both cases, we do have a timeout */ WaitPipe.TimeoutSpecified = TRUE; } Status = NtFsControlFile(FileHandle, NULL, NULL, NULL, &Iosb, FSCTL_PIPE_WAIT, &WaitPipe, sizeof(WaitPipe), NULL, 0); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); RtlFreeUnicodeString(&NamedPipeName); return FALSE; } RtlFreeUnicodeString(&NamedPipeName); return TRUE; } #endif /* * @implemented */ BOOL WINAPI ConnectNamedPipe(IN HANDLE hNamedPipe, IN LPOVERLAPPED lpOverlapped) { NTSTATUS Status; 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; } } return TRUE; } /* * @implemented */ BOOL WINAPI 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; } } return TRUE; } /* * @implemented */ BOOL WINAPI CallNamedPipeA(LPCSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut) { PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString; ANSI_STRING AnsiPipe; /* Initialize the string as ANSI_STRING and convert to Unicode */ RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName); RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE); /* Call the Unicode function */ return CallNamedPipeW(PipeName->Buffer, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, nTimeOut); } /* * @implemented */ BOOL WINAPI CallNamedPipeW(LPCWSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut) { HANDLE hPipe; BOOL bRetry = TRUE; BOOL bError; DWORD dwPipeMode; while (TRUE) { /* Try creating it */ hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); /* Success, break out */ if (hPipe != INVALID_HANDLE_VALUE) break; /* Already tried twice, give up */ if (bRetry == FALSE) return FALSE; /* Wait on it */ WaitNamedPipeW(lpNamedPipeName, nTimeOut); /* Get ready to try again */ bRetry = FALSE; } /* Set the pipe mode */ dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL); if (!bError) { /* Couldn't change state, fail */ CloseHandle(hPipe); return FALSE; } /* Do the transact */ bError = TransactNamedPipe(hPipe, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, NULL); /* Close the handle */ CloseHandle(hPipe); return bError; } /* * @implemented */ BOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe) { IO_STATUS_BLOCK Iosb; NTSTATUS Status; /* Send the FSCTL to the driver */ Status = NtFsControlFile(hNamedPipe, NULL, NULL, NULL, &Iosb, FSCTL_PIPE_DISCONNECT, NULL, 0, NULL, 0); if (Status == STATUS_PENDING) { /* Wait on NPFS to finish and get updated status */ Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL); if (NT_SUCCESS(Status)) Status = Iosb.Status; } /* Check for error */ if (!NT_SUCCESS(Status)) { /* Fail */ SetLastErrorByStatus(Status); return FALSE; } return TRUE; } /* * @unimplemented */ BOOL WINAPI 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 WINAPI GetNamedPipeHandleStateA(HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPSTR lpUserName, DWORD nMaxUserNameSize) { UNICODE_STRING UserNameW = { 0, 0, NULL }; ANSI_STRING UserNameA; BOOL Ret; if(lpUserName != NULL) { UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR); UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength); if (UserNameW.Buffer == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } UserNameA.Buffer = lpUserName; UserNameA.Length = 0; UserNameA.MaximumLength = (USHORT)nMaxUserNameSize; } Ret = GetNamedPipeHandleStateW(hNamedPipe, lpState, lpCurInstances, lpMaxCollectionCount, lpCollectDataTimeout, UserNameW.Buffer, nMaxUserNameSize); if (Ret && lpUserName != NULL) { NTSTATUS Status; RtlInitUnicodeString(&UserNameW, UserNameW.Buffer); Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); Ret = FALSE; } } if (UserNameW.Buffer != NULL) { RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer); } return Ret; } /* * @implemented */ BOOL WINAPI 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 WINAPI PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage) { PFILE_PIPE_PEEK_BUFFER Buffer; IO_STATUS_BLOCK Iosb; ULONG BufferSize; ULONG BytesRead; NTSTATUS Status; /* Calculate the buffer space that we'll need and allocate it */ BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER); Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize); if (Buffer == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } /* Tell the driver to seek */ Status = NtFsControlFile(hNamedPipe, NULL, NULL, NULL, &Iosb, FSCTL_PIPE_PEEK, NULL, 0, Buffer, BufferSize); if (Status == STATUS_PENDING) { /* Wait for npfs to be done, and update the status */ Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL); if (NT_SUCCESS(Status)) Status = Iosb.Status; } /* Overflow is success for us */ if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_SUCCESS; /* If we failed */ if (!NT_SUCCESS(Status)) { /* Free the buffer and return failure */ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); SetLastErrorByStatus(Status); return FALSE; } /* Check if caller requested bytes available */ if (lpTotalBytesAvail) *lpTotalBytesAvail = Buffer->ReadDataAvailable; /* Calculate the bytes returned, minus our structure overhead */ BytesRead = (ULONG)(Iosb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0])); /* Check if caller requested bytes read */ if (lpBytesRead) { /* Return the bytes read */ *lpBytesRead = BytesRead; } /* Check if caller requested bytes left */ if (lpBytesLeftThisMessage) { /* Calculate total minus what we returned and our structure overhead */ *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead; } /* Check if the caller wanted to see the actual data */ if (lpBuffer) { /* Give him what he wants */ RtlCopyMemory(lpBuffer, Buffer->Data, BytesRead); } /* Free the buffer */ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); return TRUE; } /* * @implemented */ BOOL WINAPI TransactNamedPipe(IN HANDLE hNamedPipe, IN LPVOID lpInBuffer, IN DWORD nInBufferSize, OUT LPVOID lpOutBuffer, IN DWORD nOutBufferSize, OUT LPDWORD lpBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL) { NTSTATUS Status; if (lpBytesRead != NULL) { *lpBytesRead = 0; } 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); if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) { SetLastErrorByStatus(Status); return FALSE; } if (lpBytesRead != NULL) { *lpBytesRead = lpOverlapped->InternalHigh; } } else { #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */ IO_STATUS_BLOCK Iosb; Status = NtFsControlFile(hNamedPipe, NULL, NULL, NULL, &Iosb, FSCTL_PIPE_TRANSCEIVE, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize); 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; } #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */ DWORD nActualBytes; while (0 != nInBufferSize && WriteFile(hNamedPipe, lpInBuffer, nInBufferSize, &nActualBytes, NULL)) { lpInBuffer = (LPVOID)((char *) lpInBuffer + nActualBytes); nInBufferSize -= nActualBytes; } if (0 != nInBufferSize) { /* Must have dropped out of the while 'cause WriteFile failed */ return FALSE; } if (!ReadFile(hNamedPipe, lpOutBuffer, nOutBufferSize, &nActualBytes, NULL)) { return FALSE; } if (NULL != lpBytesRead) { *lpBytesRead = nActualBytes; } #endif } return TRUE; } /* EOF */