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

📄 error.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * PROJECT:         ReactOS Kernel
 * LICENSE:         GPL - See COPYING in the top level directory
 * FILE:            ntoskrnl/io/error.c
 * PURPOSE:         I/O Error Functions and Error Log Support
 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
 *                  Eric Kohl
 */
/* INCLUDES *****************************************************************/

#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>

/* TYPES *********************************************************************/

typedef struct _IOP_ERROR_LOG_WORKER_DPC
{
    KDPC Dpc;
    KTIMER Timer;
} IOP_ERROR_LOG_WORKER_DPC, *PIOP_ERROR_LOG_WORKER_DPC;

/* GLOBALS *******************************************************************/

LONG IopTotalLogSize;
LIST_ENTRY IopErrorLogListHead;
KSPIN_LOCK IopLogListLock;

BOOLEAN IopLogWorkerRunning;
BOOLEAN IopLogPortConnected;
HANDLE IopLogPort;
WORK_QUEUE_ITEM IopErrorLogWorkItem;

PDEVICE_OBJECT IopErrorLogObject;

/* PRIVATE FUNCTIONS *********************************************************/

VOID
NTAPI
IopLogDpcRoutine(IN PKDPC Dpc,
                 IN PVOID DeferredContext,
                 IN PVOID SystemArgument1,
                 IN PVOID SystemArgument2)
{
    /* If we have a DPC, free it */
    if (Dpc) ExFreePool(Dpc);

    /* Initialize and queue the work item */
    ExInitializeWorkItem(&IopErrorLogWorkItem, IopLogWorker, NULL);
    ExQueueWorkItem(&IopErrorLogWorkItem, DelayedWorkQueue);
}

PLIST_ENTRY
NTAPI
IopGetErrorLogEntry(VOID)
{
    KIRQL OldIrql;
    PLIST_ENTRY ListEntry;

    /* Acquire the lock and check if the list is empty */
    KeAcquireSpinLock(&IopLogListLock, &OldIrql);
    if (IsListEmpty(&IopErrorLogListHead))
    {
        /* List is empty, disable the worker and return NULL */
        IopLogWorkerRunning = FALSE;
        ListEntry = NULL;
    }
    else
    {
        /* Otherwise, remove an entry */
        ListEntry = RemoveHeadList(&IopErrorLogListHead);
    }

    /* Release the lock and return the entry */
    KeReleaseSpinLock(&IopLogListLock, OldIrql);
    return ListEntry;
}

VOID
NTAPI
IopRestartLogWorker(VOID)
{
    PIOP_ERROR_LOG_WORKER_DPC WorkerDpc;
    LARGE_INTEGER Timeout;

    /* Allocate a DPC Context */
    WorkerDpc = ExAllocatePool(NonPagedPool, sizeof(IOP_ERROR_LOG_WORKER_DPC));
    if (!WorkerDpc)
    {
        /* Fail */
        IopLogWorkerRunning = FALSE;
        return;
    }

    /* Initialize DPC and Timer */
    KeInitializeDpc(&WorkerDpc->Dpc, IopLogDpcRoutine, WorkerDpc);
    KeInitializeTimer(&WorkerDpc->Timer);

    /* Restart after 30 seconds */
    Timeout.QuadPart = (LONGLONG)-300000000;
    KeSetTimer(&WorkerDpc->Timer, Timeout, &WorkerDpc->Dpc);
}

BOOLEAN
NTAPI
IopConnectLogPort(VOID)
{
    UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\ErrorLogPort");
    NTSTATUS Status;

    /* Make sure we're not already connected */
    if (IopLogPortConnected) return TRUE;

    /* Connect the port */
    Status = ZwConnectPort(&IopLogPort,
                           &PortName,
                           NULL,
                           NULL,
                           NULL,
                           NULL,
                           NULL,
                           NULL);
    if (NT_SUCCESS(Status))
    {
        /* Remmeber we're connected */
        IopLogPortConnected = TRUE;
        return TRUE;
    }

    /* We failed, try again */
    IopRestartLogWorker();
    return FALSE;
}

VOID
NTAPI
IopLogWorker(IN PVOID Parameter)
{
    PELF_API_MSG Message;
    PIO_ERROR_LOG_MESSAGE ErrorMessage;
    PLIST_ENTRY ListEntry;
    PERROR_LOG_ENTRY LogEntry;
    PIO_ERROR_LOG_PACKET Packet;
    PCHAR StringBuffer;
    ULONG RemainingLength;
    PDRIVER_OBJECT DriverObject;
    ULONG DriverNameLength = 0, DeviceNameLength;
    UNICODE_STRING DriverNameString;
    NTSTATUS Status;
    UCHAR Buffer[256];
    POBJECT_NAME_INFORMATION ObjectNameInfo = (POBJECT_NAME_INFORMATION)&Buffer;
    POBJECT_NAME_INFORMATION PoolObjectNameInfo = NULL;
    ULONG ReturnedLength, MessageLength;
    PWCHAR p;
    ULONG ExtraStringLength;
    PAGED_CODE();

    /* Connect to the port */
    if (!IopConnectLogPort()) return;

    /* Allocate the message */
    Message = ExAllocatePool(PagedPool, IO_ERROR_LOG_MESSAGE_LENGTH);
    if (!Message)
    {
        /* Couldn't allocate, try again */
        IopRestartLogWorker();
        return;
    }

    /* Copy the message */
    RtlZeroMemory(Message, sizeof(ELF_API_MSG));

    /* Get the actual I/O Structure */
    ErrorMessage = &Message->IoErrorMessage;

    /* Start loop */
    while (TRUE)
    {
        /* Get an entry */
        ListEntry = IopGetErrorLogEntry();
        if (!ListEntry) break;
        LogEntry = CONTAINING_RECORD(ListEntry, ERROR_LOG_ENTRY, ListEntry);

        /* Get pointer to the log packet */
        Packet = (PIO_ERROR_LOG_PACKET)((ULONG_PTR)LogEntry +
                                        sizeof(ERROR_LOG_ENTRY));

        /* Calculate the total length of the message only */
        MessageLength = sizeof(IO_ERROR_LOG_MESSAGE) -
                        sizeof(ERROR_LOG_ENTRY) -
                        sizeof(IO_ERROR_LOG_PACKET) +
                        LogEntry->Size;

        /* Copy the packet */
        RtlCopyMemory(&ErrorMessage->EntryData,
                      Packet,
                      LogEntry->Size - sizeof(ERROR_LOG_ENTRY));

        /* Set the timestamp and time */
        ErrorMessage->TimeStamp = LogEntry->TimeStamp;
        ErrorMessage->Type = IO_TYPE_ERROR_MESSAGE;

        /* Check if this message has any strings */
        if (Packet->NumberOfStrings)
        {
            /* String buffer is after the current strings */
            StringBuffer = (PCHAR)&ErrorMessage->EntryData +
                            Packet->StringOffset;
        }
        else
        {
            /* Otherwise, string buffer is at the end */
            StringBuffer = (PCHAR)ErrorMessage + MessageLength;
        }

        /* Align the buffer */
        StringBuffer = (PVOID)ALIGN_UP(StringBuffer, WCHAR);

        /* Set the offset for the driver's name to the current buffer */
        ErrorMessage->DriverNameOffset = (ULONG)(StringBuffer -
                                                 (ULONG_PTR)ErrorMessage);

        /* Check how much space we have left for the device string */
        RemainingLength = (ULONG)((ULONG_PTR)Message +
                                  IO_ERROR_LOG_MESSAGE_LENGTH -
                                  (ULONG_PTR)StringBuffer);

        /* Now check if there is a driver object */
        DriverObject = LogEntry->DriverObject;
        if (DriverObject)
        {
            /* Check if the driver has a name */
            if (DriverObject->DriverName.Buffer)
            {
                /* Use its name */
                DriverNameString.Buffer = DriverObject->DriverName.Buffer;
                DriverNameLength = DriverObject->DriverName.Length;
            }
            else
                DriverNameString.Buffer = NULL;

            /* Check if there isn't a valid name*/
            if (!DriverNameLength)
            {
                /* Query the name directly */
                Status = ObQueryNameString(DriverObject,
                                           ObjectNameInfo,
                                           sizeof(Buffer),
                                           &ReturnedLength);
                if (!(NT_SUCCESS(Status)) || !(ObjectNameInfo->Name.Length))
                {
                    /* We don't have a name */
                    DriverNameLength = 0;
                }
            }
        }
        else
        {
            /* Use default name */
            DriverNameString.Buffer = L"Application Popup";
            DriverNameLength = wcslen(DriverNameString.Buffer) * sizeof(WCHAR);
        }

        /* Check if we have a driver name by here */
        if (DriverNameLength)
        {
            /* Skip to the end of the driver's name */
            p = &DriverNameString.Buffer[DriverNameLength / sizeof(WCHAR)];

            /* Now we'll walk backwards and assume the minimum size */
            DriverNameLength = sizeof(WCHAR);
            p--;
            while ((*p != L'\\') && (p != DriverNameString.Buffer))
            {
                /* No backslash found, keep going */
                p--;
                DriverNameLength += sizeof(WCHAR);
            }

            /* Now we probably hit the backslash itself, skip past it */
            if (*p == L'\\')
            {
                p++;
                DriverNameLength -= sizeof(WCHAR);
            }

            /*
             * Now make sure that the driver name fits in our buffer, minus 3
             * NULL chars, and copy the name in our string buffer
             */
            DriverNameLength = min(DriverNameLength,
                                   RemainingLength - 3 * sizeof(UNICODE_NULL));
            RtlCopyMemory(StringBuffer, p, DriverNameLength);
        }

        /* Null-terminate the driver name */
        *((PWSTR)(StringBuffer + DriverNameLength)) = L'\0';
        DriverNameLength += sizeof(WCHAR);

        /* Go to the next string buffer position */
        StringBuffer += DriverNameLength;
        RemainingLength -= DriverNameLength;

        /* Update the string offset and check if we have a device object */
        ErrorMessage->EntryData.StringOffset = (USHORT)
                                               ((ULONG_PTR)StringBuffer -
                                               (ULONG_PTR)ErrorMessage);
        if (LogEntry->DeviceObject)
        {
            /* We do, query its name */
            Status = ObQueryNameString(LogEntry->DeviceObject,
                                       ObjectNameInfo,
                                       sizeof(OBJECT_NAME_INFORMATION) +
                                       100 -
                                       DriverNameLength,
                                       &ReturnedLength);
            if ((!NT_SUCCESS(Status)) || !(ObjectNameInfo->Name.Length))
            {
                /* Setup an empty name */
                ObjectNameInfo->Name.Length = 0;
                ObjectNameInfo->Name.Buffer = L"";

                /* Check if we failed because our buffer wasn't large enough */
                if (Status == STATUS_INFO_LENGTH_MISMATCH)
                {
                    /* Then we'll allocate one... we really want this name! */
                    PoolObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
                                                               ReturnedLength,
                                                               TAG_IO);
                    if (PoolObjectNameInfo)
                    {
                        /* Query it again */
                        ObjectNameInfo = PoolObjectNameInfo;
                        Status = ObQueryNameString(LogEntry->DeviceObject,
                                                   ObjectNameInfo,
                                                   ReturnedLength,
                                                   &ReturnedLength);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -