⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 npipe.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 == 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 */
        DPRINT("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 */
            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 + -