Windows2000/private/ntos/ioe/ioeapi.c
2020-09-30 17:12:32 +02:00

1041 lines
28 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
ioeapi.c
Abstract:
This module contains the code for the exported IoErr APIs
Author:
Michael Tsang (MikeTs) 2-Sep-1998
Environment:
Kernel mode
--*/
#include "pch.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, IoErrInitSystem)
#pragma alloc_text(PAGE, IoErrMatchErrCase)
#pragma alloc_text(PAGE, IoErrFindErrCaseByID)
#pragma alloc_text(PAGE, IoErrHandleErrCase)
#pragma alloc_text(PAGE, IoErrGetLongErrMessage)
#pragma alloc_text(PAGE, IoErrGetShortErrMessage)
#endif
BOOLEAN IoErrInitSystem(VOID)
/*++
Routine Description:
This routine initializes the whole error logging/handling system.
Return Value:
Success - returns TRUE
Failure - returns FALSE
--*/
{
PROCNAME("IoErrInitSystem");
BOOLEAN rc = TRUE;
ENTER(1, ("()\n"));
KeInitializeSpinLock(&IoepErrListLock);
InitializeListHead(&IoepErrThreadListHead);
InitializeListHead(&IoepErrModuleListHead);
InitializeListHead(&IoepSaveDataListHead);
RtlInitUnicodeString(&IoepRegKeyStrIoErr, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES\\IOERR");
EXIT(1, ("=%x\n", rc));
return rc;
} //IoErrInitSystem
HANDLE IoErrInitErrLogByIrp(IN PIRP Irp, IN ULONG ulFlags)
/*++
Routine Description:
This routine initializes an error logging session that is keyed by an Irp.
Arguments:
Irp - points to the Irp that is used as the key to the logging session.
ulFlags - log session flags
Return Value:
Success - returns the newly created error log handle.
Failure - returns NULL.
--*/
{
PROCNAME("IoErrInitErrLogByIrp");
PERRLOG ErrLog;
ENTER(1, ("(Irp=%p,ulFlags=%x)\n", Irp, ulFlags));
ErrLog = IoepInitErrLog(THREADKEY_IRP, Irp, ulFlags);
EXIT(1, ("=%p\n", ErrLog));
return ErrLog;
} //IoErrInitErrLogByIrp
HANDLE IoErrInitErrLogByThreadID(IN PKTHREAD ThreadID, IN ULONG ulFlags)
/*++
Routine Description:
This routine initializes an error logging session that is keyed by thread.
Arguments:
ThreadID - thread ID
ulFlags - log session flags
Return Value:
Success - returns the newly created error log handle.
Failure - returns NULL.
--*/
{
PROCNAME("IoErrInitErrLogByThreadID");
PERRLOG ErrLog;
ENTER(1, ("(ThreadID=%p,ulFlags=%x)\n", ThreadID, ulFlags));
ErrLog = IoepInitErrLog(THREADKEY_THREADID, ThreadID, ulFlags);
EXIT(1, ("=%p\n", ErrLog));
return ErrLog;
} //IoErrInitErrLogByThreadID
VOID
IoErrLogErrByIrp(
IN PIRP Irp,
IN CONST GUID *ComponentGuid,
IN ULONG ErrCode,
IN PWSTR TextData OPTIONAL,
IN ULONG DataBlkType,
IN ULONG DataBlkLen OPTIONAL,
IN PVOID DataBlock OPTIONAL,
IN CONST GUID *MofGuid OPTIONAL
)
/*++
Routine Description:
This routine logs the error data to the error log session identified by
the given Irp.
Arguments:
Irp - points to the Irp that is used as the key to the logging session.
ComponentGuid - points to the component GUID of the caller
ErrCode - unique error code
TextData - points to an optional WSTR of text data
DataBlkType - data type of the data block
DataBlkLen - length of the data block
DataBlock - points to the data block
MofGuid - points to the MOF GUID of the data block if applicable
Return Value:
None
--*/
{
PROCNAME("IoErrLogErrByIrp");
ENTER(1, ("(Irp=%p,pGuid=%p,ErrCode=%x,Text=%S,Type=%x,Len=%d,DataBlk=%p,MofGuid=%p)\n",
Irp, ComponentGuid, ErrCode, TextData? TextData: L"", DataBlkType,
DataBlkLen, DataBlock, MofGuid));
IoepLogErr(THREADKEY_IRP,
Irp,
ComponentGuid,
ErrCode,
TextData,
DataBlkType,
DataBlkLen,
DataBlock,
MofGuid);
EXIT(1, ("!\n"));
} //IoErrLogErrByIrp
VOID
IoErrLogErrByThreadID(
IN PKTHREAD ThreadID,
IN CONST GUID *ComponentGuid,
IN ULONG ErrCode,
IN PWSTR TextData OPTIONAL,
IN ULONG DataBlkType,
IN ULONG DataBlkLen OPTIONAL,
IN PVOID DataBlock OPTIONAL,
IN CONST GUID *MofGuid OPTIONAL
)
/*++
Routine Description:
This routine logs the error data to the error log session identified by
the given ThreadID.
Arguments:
ThreadID - points to the ThreadID that is used as the key to the logging
session.
ComponentGuid - points to the component GUID of the caller
ErrCode - unique error code
TextData - points to an optional WSTR of text data
DataBlkType - data type of the data block
DataBlkLen - length of the data block
DataBlock - points to the data block
MofGuid - points to the MOF GUID of the data block if applicable
Return Value:
None
--*/
{
PROCNAME("IoErrLogErrByThreadID");
ENTER(1, ("(ThreadID=%p,pGuid=%p,ErrCode=%x,Text=%S,Type=%x,Len=%d,DataBlk=%p,MofGuid=%p)\n",
ThreadID, ComponentGuid, ErrCode, TextData? TextData: L"",
DataBlkType, DataBlkLen, DataBlock, MofGuid));
IoepLogErr(THREADKEY_THREADID,
ThreadID,
ComponentGuid,
ErrCode,
TextData,
DataBlkType,
DataBlkLen,
DataBlock,
MofGuid);
EXIT(1, ("!\n"));
} //IoErrLogErrByThreadID
VOID
IoErrPropagateErrLog(
IN HANDLE ErrLogHandle
)
/*++
Routine Description:
This routine propagates the error log stack from the current error log
session to the next nested error log session.
Arguments:
ErrLogHandle - points to the error log session
Return Value:
None
--*/
{
PROCNAME("IoErrPropagateErrLog");
PERRLOG ErrLog = (PERRLOG)ErrLogHandle;
ASSERT(ErrLogHandle != NULL);
ASSERT(((PERRLOG)ErrLogHandle)->Signature == SIG_ERRLOG);
ENTER(1, ("(ErrLog=%p)\n", ErrLogHandle));
if ((ErrLog != NULL) && (ErrLog->Signature == SIG_ERRLOG))
{
PERRENTRY ErrStack;
KIRQL Irql;
ExAcquireSpinLock(&IoepErrListLock, &Irql);
ErrStack = IoepGetErrStack((PERRLOG)ErrLogHandle);
if (ErrStack != NULL)
{
PERRLOG ErrLogNext;
ErrLogNext = CONTAINING_RECORD(ErrLog->list.Flink, ERRLOG, list);
if (&ErrLogNext->list != &ErrLog->ErrThread->ErrLogListHead)
{
PSINGLE_LIST_ENTRY ErrTail;
for (ErrTail = &ErrStack->slist;
ErrTail->Next != NULL;
ErrTail = ErrTail->Next)
;
ErrTail->Next = ErrLogNext->ErrStack.Next;
ErrLogNext->ErrStack.Next = ErrStack->slist.Next;
ErrLog->ErrStack.Next = NULL;
if (ErrLog->ErrInfo != NULL)
{
ErrLog->ErrInfo->Signature = 0;
ExFreePool(ErrLog->ErrInfo);
ErrLog->ErrInfo = NULL;
}
}
}
ExReleaseSpinLock(&IoepErrListLock, Irql);
}
else
{
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("!\n"));
} //IoErrPropagateErrLog
VOID
IoErrTerminateErrLog(
IN HANDLE ErrLogHandle
)
/*++
Routine Description:
This routine terminates an error log session.
Arguments:
ErrLogHandle - points to the error log session
Return Value:
None
--*/
{
PROCNAME("IoErrTerminateErrLog");
PERRLOG ErrLog = (PERRLOG)ErrLogHandle;
ASSERT(ErrLogHandle != NULL);
ASSERT(((PERRLOG)ErrLogHandle)->Signature == SIG_ERRLOG);
ENTER(1, ("(ErrLog=%p)\n", ErrLogHandle));
if ((ErrLog != NULL) && (ErrLog->Signature == SIG_ERRLOG))
{
PERRENTRY ErrStack;
KIRQL Irql;
ErrStack = IoepGetErrStack(ErrLog);
if (ErrStack != NULL)
{
// If we are at the top level log session by Irp and we have an
// error, we fire a WMI event.
if ((ErrLog->ErrThread->ThreadKeyType == THREADKEY_IRP) &&
(ErrLog->list.Flink == &ErrLog->ErrThread->ErrLogListHead))
{
PDEVICE_NODE DevNode;
ASSERT_PDO(ErrLog->ErrThread->ThreadKey.IrpKey.TargetDevice);
DevNode = ErrLog->ErrThread->ThreadKey.IrpKey.TargetDevice->DeviceObjectExtension->DeviceNode;
IoepFireWMIEvent(IoErrGetErrData(ErrLogHandle),
DevNode->InstancePath.Buffer);
}
ErrLog->ErrStack.Next = NULL;
IoepFreeErrStack(ErrStack);
}
ExAcquireSpinLock(&IoepErrListLock, &Irql);
if (ErrLog->ErrInfo != NULL)
{
ErrLog->ErrInfo->Signature = 0;
ExFreePool(ErrLog->ErrInfo);
ErrLog->ErrInfo = NULL;
}
RemoveEntryList(&ErrLog->list);
if (IsListEmpty(&ErrLog->ErrThread->ErrLogListHead))
{
RemoveEntryList(&ErrLog->ErrThread->list);
ExFreePool(ErrLog->ErrThread);
ErrLog->ErrThread = NULL;
}
ErrLog->Signature = 0;
ExFreePool(ErrLog);
ExReleaseSpinLock(&IoepErrListLock, Irql);
}
else
{
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("!\n"));
} //IoErrTerminateErrLog
NTSTATUS
IoErrRegisterErrHandlers(
IN CONST GUID *ComponentGuid,
IN ULONG NumErrHandlers,
IN PERRHANDLER *HandlerTable
)
/*++
Routine Description:
This routine registers error handlers for the caller module.
Arguments:
ComponentGuid - points to the GUID of the caller component
NumErrHandlers - number of error handlers in the table
HandlerTable - points to the error handler table
Return Value:
Success - returns STATUS_SUCCESS
Failure - returns NT status code
--*/
{
PROCNAME("IoErrRegisterErrHandlers");
NTSTATUS status;
PERRMODULE ErrModule;
ASSERT(ComponentGuid != NULL);
ASSERT(NumErrHandlers > 0);
ASSERT(HandlerTable != NULL);
ENTER(1, ("(pGuid=%p,NumHandlers=%d,HandleTable=%p)\n",
ComponentGuid, NumErrHandlers, HandlerTable));
ErrModule = IoepFindErrModule(ComponentGuid);
if (ErrModule == NULL)
{
ErrModule = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRMODULE) + sizeof(PERRHANDLER)*(NumErrHandlers - 1), IOETAG_ERRMODULE);
if (ErrModule != NULL)
{
ErrModule->ComponentGuid = *ComponentGuid;
ErrModule->NumErrHandlers = NumErrHandlers;
RtlCopyMemory(ErrModule->HandlerTable, HandlerTable, sizeof(PERRHANDLER)*NumErrHandlers);
ExInterlockedInsertTailList(&IoepErrModuleListHead, &ErrModule->list, &IoepErrListLock);
status = STATUS_SUCCESS;
}
else
{
status = STATUS_INSUFFICIENT_RESOURCES;
DBGPRINT(("failed to allocate error module\n"));
}
}
else
{
status = STATUS_IOE_MODULE_ALREADY_REGISTERED;
DBGPRINT(("error module already registered\n"));
}
EXIT(1, ("=%x\n", status));
return status;
} //IoErrRegisterErrHandlers
PERRINFO
IoErrGetErrData(
IN HANDLE ErrLogHandle
)
/*++
Routine Description:
This routine returns the error data from the error log session.
Arguments:
ErrLogHandle - points to the error log session
Return Value:
Success - returns pointer to the error info structure
Failure - returns NULL
--*/
{
PROCNAME("IoErrGetErrData");
PERRINFO ErrInfo = NULL;
PERRLOG ErrLog = (PERRLOG)ErrLogHandle;
ASSERT(ErrLogHandle != NULL);
ASSERT(((PERRLOG)ErrLogHandle)->Signature == SIG_ERRLOG);
ENTER(1, ("(ErrLog=%p)\n", ErrLogHandle));
if ((ErrLog != NULL) && (ErrLog->Signature == SIG_ERRLOG))
{
if (ErrLog->ErrInfo != NULL)
{
ErrInfo = ErrLog->ErrInfo;
}
else
{
NTSTATUS status;
ULONG len;
status = IoepExtractErrData(IoepGetErrStack(ErrLog), NULL, 0, &len);
if (status == STATUS_BUFFER_TOO_SMALL)
{
ErrInfo = ExAllocatePoolWithTag(NonPagedPool, len, IOETAG_ERRINFO);
if (ErrInfo != NULL)
{
status = IoepExtractErrData(IoepGetErrStack(ErrLog), ErrInfo, len, NULL);
if (NT_SUCCESS(status))
{
ErrLog->ErrInfo = ErrInfo;
}
else
{
ExFreePool(ErrInfo);
ErrInfo = NULL;
DBGPRINT(("failed to get error data (rc=%x)\n",
status));
}
}
else
{
DBGPRINT(("failed to allocate error info buffer (len=%d)\n",
len));
}
}
else
{
DBGPRINT(("failed to determine error data size (rc=%x)\n", status));
}
}
}
else
{
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("=%p\n", ErrInfo));
return ErrInfo;
} //IoErrGetErrData
HANDLE
IoErrSaveErrData(
IN HANDLE ErrLogHandle,
IN PVOID DataTag OPTIONAL,
IN ULONG TagFlags OPTIONAL
)
/*++
Routine Description:
This routine saves the error data and returns a handle to the saved data.
Arguments:
ErrLogHandle - points to the error log session
DataTag - tag to be associated with for the saved error data
KeyFlags - flags about the DataTag:
IOEDATATAG_TYPE_DEVNODE - DataTag is a DevNode pointer
Return Value:
Success - returns the detached error log handle
Failure - returns NULL
--*/
{
PROCNAME("IoErrSaveErrData");
PSAVEDATA SaveData = NULL;
ASSERT(ErrLogHandle != NULL);
ASSERT(((PERRLOG)ErrLogHandle)->Signature == SIG_ERRLOG);
ASSERT((TagFlags & ~IOEDATATAG_BITS) == 0);
ENTER(1, ("(ErrLog=%p,DataTag=%p,TagFlags=%x)\n",
ErrLogHandle, DataTag, TagFlags));
if ((ErrLogHandle != NULL) &&
(((PERRLOG)ErrLogHandle)->Signature == SIG_ERRLOG))
{
PERRINFO ErrInfo;
ErrInfo = IoErrGetErrData(ErrLogHandle);
if (ErrInfo != NULL)
{
SaveData = ExAllocatePoolWithTag(NonPagedPool, sizeof(SAVEDATA), IOETAG_SAVEDATA);
if (SaveData != NULL)
{
ErrInfo->DataTag = DataTag;
ErrInfo->TagFlags = TagFlags & IOEDATATAG_TYPE_MASK;
SaveData->Signature = SIG_SAVEDATA;
SaveData->ErrInfo = ErrInfo;
((PERRLOG)ErrLogHandle)->ErrInfo = NULL;
ExInterlockedInsertHeadList(&IoepSaveDataListHead, &SaveData->list, &IoepErrListLock);
}
else
{
DBGPRINT(("failed to allocate save data block\n"));
}
}
}
else
{
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("=%p\n", SaveData));
return SaveData;
} //IoErrSaveErrData
PERRINFO
IoErrGetSavedData(
IN HANDLE SaveDataHandle
)
/*++
Routine Description:
This routine returns the error info. from the saved error data.
Arguments:
SaveDataHandle - points to the saved error data
Return Value:
Success - returns a pointer to the saved error info.
Failure - returns NULL
--*/
{
PROCNAME("IoErrGetSavedData");
PERRINFO ErrInfo;
ASSERT(SaveDataHandle != NULL);
ASSERT(((PSAVEDATA)SaveDataHandle)->Signature == SIG_SAVEDATA);
ENTER(1, ("(SaveData=%p)\n", SaveDataHandle));
if ((SaveDataHandle != NULL) &&
(((PSAVEDATA)SaveDataHandle)->Signature == SIG_SAVEDATA))
{
ErrInfo = ((PSAVEDATA)SaveDataHandle)->ErrInfo;
}
else
{
ErrInfo = NULL;
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("=%p\n", ErrInfo));
return ErrInfo;
} //IoErrGetSavedData
VOID
IoErrFreeSavedData(
IN HANDLE SaveDataHandle
)
/*++
Routine Description:
This routine frees the storage associated with the saved error data.
This function should only be call if the error data has been previously
saved via IoErrSaveErrData.
Arguments:
SaveDataHandle - points to the save data
Return Value:
None
--*/
{
PROCNAME("IoErrFreeSavedData");
PSAVEDATA SaveData = (PSAVEDATA)SaveDataHandle;
ASSERT(SaveDataHandle != NULL);
ASSERT(((PSAVEDATA)SaveDataHandle)->Signature == SIG_SAVEDATA);
ENTER(1, ("(SaveData=%p)\n", SaveDataHandle));
if ((SaveDataHandle != NULL) &&
(((PSAVEDATA)SaveDataHandle)->Signature == SIG_SAVEDATA))
{
KIRQL Irql;
ExAcquireSpinLock(&IoepErrListLock, &Irql);
RemoveEntryList(&SaveData->list);
if (SaveData->ErrInfo != NULL)
{
SaveData->ErrInfo->Signature = 0;
ExFreePool(SaveData->ErrInfo);
SaveData->ErrInfo = NULL;
}
SaveData->Signature = 0;
ExFreePool(SaveData);
ExReleaseSpinLock(&IoepErrListLock, Irql);
}
else
{
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("!\n"));
} //IoErrFreeSavedData
NTSTATUS
IoErrRetrieveSavedData(
OUT PINFOBLK InfoBlk,
IN ULONG BuffSize,
OUT PULONG DataSize OPTIONAL,
IN PVOID DataTag OPTIONAL,
IN ULONG TagFlags OPTIONAL
)
/*++
Routine Description:
This routine returns the saved error info. in the given buffer. If no
DataTag is given, data of all saved error info. are returned. Otherwise,
only the data of the error info. which matches the data tag is returned.
Arguments:
InfoBlk - points to the buffer to receive the data
BuffSize - specifies the size of the buffer
DataSize - points to the variable to receive the actual data size
DataTag - tag associated with the data info.
TagFlags - tag flags
Return Value:
Success - returns STATUS_SUCCESS
Failure - returns NT status code
--*/
{
PROCNAME("IoErrRetrieveSavedData");
NTSTATUS status = STATUS_SUCCESS;
PLIST_ENTRY list;
ULONG len, i;
PSAVEDATA SaveData;
ASSERT((InfoBlk != NULL) && (BuffSize > 0) || (DataSize != NULL));
ENTER(1, ("(Buff=%p,BuffSize=%d,pDataSize=%p,DataTag=%p,TagFlags=%x)\n",
InfoBlk, BuffSize, DataSize, DataTag, TagFlags));
for (list = IoepSaveDataListHead.Flink,
len = sizeof(INFOBLK) - sizeof(ERRINFO),
i = 0;
list != &IoepSaveDataListHead;
list = list->Flink)
{
SaveData = CONTAINING_RECORD(list, SAVEDATA, list);
if ((DataTag == NULL) ||
(DataTag == SaveData->ErrInfo->DataTag) &&
(TagFlags == SaveData->ErrInfo->TagFlags & IOEDATATAG_TYPE_MASK))
{
i++;
len += SaveData->ErrInfo->Size;
}
}
if (len <= BuffSize)
{
if ((InfoBlk != NULL) && (BuffSize > 0))
{
PERRINFO ErrInfo;
InfoBlk->Signature = SIG_INFOBLK;
InfoBlk->Version = IOE_INFOBLK_VERSION;
InfoBlk->Size = len;
InfoBlk->NumErrInfos = i;
for (list = IoepSaveDataListHead.Flink,
ErrInfo = &InfoBlk->ErrInfos[0];
list != &IoepSaveDataListHead;
list = list->Flink)
{
SaveData = CONTAINING_RECORD(list, SAVEDATA, list);
if ((DataTag == NULL) ||
(DataTag == SaveData->ErrInfo->DataTag) &&
(TagFlags == SaveData->ErrInfo->TagFlags &
IOEDATATAG_TYPE_MASK))
{
RtlCopyMemory(ErrInfo,
SaveData->ErrInfo,
SaveData->ErrInfo->Size);
ErrInfo = (PERRINFO)((PUCHAR)ErrInfo +
SaveData->ErrInfo->Size);
}
}
}
status = STATUS_SUCCESS;
}
else
{
status = STATUS_BUFFER_TOO_SMALL;
DBGPRINT(("buffer too small (size=%d,need=%d)\n", BuffSize, len));
}
if (DataSize != NULL)
{
*DataSize = len;
}
EXIT(1, ("=%x(len=%d)\n", status, len));
return status;
} //IoErrRetrievedSavedData
NTSTATUS
IoErrMatchErrCase(
IN PERRINFO ErrInfo,
OUT PULONG ErrCaseID,
OUT PHANDLE ErrCaseHandle OPTIONAL
)
/*++
Routine Description:
This routine gets the indexed error entry from the error stack.
Arguments:
ErrInfo - points to the error info.
ErrCaseID - points to the variable to receive the error case ID
ErrCaseHandle - points to the variable to receive the error case handle
Return Value:
Success - returns STATUS_SUCCESS
Failure - returns NT status code
--*/
{
PROCNAME("IoErrMatchErrCase");
NTSTATUS status;
ASSERT(ErrInfo != NULL);
ASSERT(ErrInfo->Signature == SIG_ERRINFO);
ASSERT(ErrCaseID != NULL);
PAGED_CODE();
ENTER(1, ("(ErrInfo=%p,pErrCaseID=%p,pErrCaseHandle=%p)\n",
ErrInfo, ErrCaseID, ErrCaseHandle));
if ((ErrInfo != NULL) && (ErrInfo->Signature == SIG_ERRINFO))
{
PERRCASEDB ErrCaseDB = IoepGetErrCaseDB();
if (ErrCaseDB != NULL)
{
PERRCASE ErrCaseTable;
PERRID ErrIDPath;
ULONG i;
ErrCaseTable = (PERRCASE)((ULONG_PTR)ErrCaseDB +
ErrCaseDB->ErrCaseOffset);
for (i = 0, status = STATUS_NOT_FOUND; i < ErrCaseDB->NumErrCases; ++i)
{
ErrIDPath = (PERRID)((ULONG_PTR)ErrCaseDB +
ErrCaseDB->ErrIDPathBlkOffset +
ErrCaseTable[i].ErrIDPathOffset);
if (IoepMatchErrIDPath(ErrInfo,
ErrIDPath,
ErrCaseTable[i].NumErrIDs))
{
*ErrCaseID = ErrCaseTable[i].ErrCaseID;
if (ErrCaseHandle != NULL)
{
*ErrCaseHandle = &ErrCaseTable[i];
}
status = STATUS_SUCCESS;
break;
}
}
}
else
{
status = STATUS_IOE_DATABASE_NOT_READY;
DBGPRINT(("error case database not ready\n"));
}
}
else
{
status = STATUS_INVALID_PARAMETER;
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("=%x(ErrCaseID=%x,ErrCase=%p)\n",
status, *ErrCaseID, ErrCaseHandle? *ErrCaseHandle: 0));
return status;
} //IoErrMatchErrCase
NTSTATUS
IoErrFindErrCaseByID(
IN ULONG ErrCaseID,
OUT PHANDLE ErrCaseHandle
)
/*++
Routine Description:
This routine finds an error case by the error case ID and returns the
handle to the error case.
Arguments:
ErrCaseID - unique error case ID
ErrCaseHandle - points to the variable to receive the error case handle
Return Value:
Success - returns STATUS_SUCCESS
Failure - returns NT status code
--*/
{
PROCNAME("IoErrFindErrCaseByID");
NTSTATUS status;
PERRCASEDB ErrCaseDB;
PAGED_CODE();
ENTER(1, ("(ErrCaseID=%x,pErrCaseHandle=%p)\n", ErrCaseID, ErrCaseHandle));
ErrCaseDB = IoepGetErrCaseDB();
if (ErrCaseDB != NULL)
{
PERRCASE ErrCaseTable;
ULONG i;
ErrCaseTable = (PERRCASE)((ULONG_PTR)ErrCaseDB +
ErrCaseDB->ErrCaseOffset);
for (i = 0, status = STATUS_NOT_FOUND; i < ErrCaseDB->NumErrCases; ++i)
{
if (ErrCaseTable[i].ErrCaseID == ErrCaseID)
{
*ErrCaseHandle = &ErrCaseTable[i];
status = STATUS_SUCCESS;
break;
}
}
}
else
{
status = STATUS_IOE_DATABASE_NOT_READY;
DBGPRINT(("error case database not ready\n"));
}
EXIT(1, ("=%x(ErrCase=%p)\n", status, *ErrCaseHandle));
return status;
} //IoErrFindErrCaseByID
NTSTATUS
IoErrHandleErrCase(
IN PERRINFO ErrInfo,
IN HANDLE ErrCaseHandle
)
/*++
Routine Description:
This routine handles an error case by executing the resolution method.
Arguments:
ErrInfo - points to the error info.
ErrCaseHandle - points to the error case handle
Return Value:
Success - returns STATUS_SUCCESS
Failure - returns NT status code
--*/
{
PROCNAME("IoErrHandleErrCase");
NTSTATUS status;
ASSERT(ErrInfo != NULL);
ASSERT(ErrInfo->Signature == SIG_ERRINFO);
ASSERT(ErrCaseHandle != NULL);
PAGED_CODE();
ENTER(1, ("(ErrInfo=%p,ErrCase=%p)\n", ErrInfo, ErrCaseHandle));
if ((ErrInfo != NULL) && (ErrInfo->Signature == SIG_ERRINFO))
{
status = IoepHandleErrCase(ErrInfo,
(PERRCASE)ErrCaseHandle,
IOEMETHOD_ANY,
NULL);
}
else
{
status = STATUS_INVALID_PARAMETER;
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("=%x\n", status));
return status;
} //IoErrHandleErrCase
NTSTATUS
IoErrGetLongErrMessage(
IN PERRINFO ErrInfo,
IN HANDLE ErrCaseHandle,
OUT PUNICODE_STRING unicodeMsg
)
/*++
Routine Description:
This routine handles the error case by executing the long message method
and returns the resulting message.
Arguments:
ErrInfo - points to the error info.
ErrCaseHandle - points to the error case handle
unicodeMsg - points to the uninitialized unicode string message buffer
Return Value:
Success - returns STATUS_SUCCESS
Failure - returns NT status code
Note:
This routine will allocate the actual string buffer of the unicode message.
Therefore, it is the caller's responsibility to free the message buffer
via RtlFreeUnicodeString.
--*/
{
PROCNAME("IoErrGetLongErrMessage");
NTSTATUS status;
ASSERT(ErrInfo != NULL);
ASSERT(ErrInfo->Signature == SIG_ERRINFO);
ASSERT(ErrCaseHandle != NULL);
ASSERT(unicodeMsg != NULL);
PAGED_CODE();
ENTER(1, ("(ErrInfo=%p,ErrCase=%p,pMsg=%p)\n",
ErrInfo, ErrCaseHandle, unicodeMsg));
if ((ErrInfo != NULL) && (ErrInfo->Signature == SIG_ERRINFO))
{
status = IoepHandleErrCase(ErrInfo,
(PERRCASE)ErrCaseHandle,
IOEMETHOD_LONGMSG,
unicodeMsg);
}
else
{
status = STATUS_INVALID_PARAMETER;
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("=%x(Msg=%S)\n", status, unicodeMsg->Buffer));
return status;
} //IoErrGetLongErrMessage
NTSTATUS
IoErrGetShortErrMessage(
IN PERRINFO ErrInfo,
IN HANDLE ErrCaseHandle,
OUT PUNICODE_STRING unicodeMsg
)
/*++
Routine Description:
This routine handles the error case by executing the short message method
and returns the resulting message.
Arguments:
ErrInfo - points to the error info.
ErrCaseHandle - points to the error case handle
unicodeMsg - points to the uninitialized unicode string message buffer
Return Value:
Success - returns STATUS_SUCCESS
Failure - returns NT status code
Note:
This routine will allocate the actual string buffer of the unicode message.
Therefore, it is the caller's responsibility to free the message buffer
via RtlFreeUnicodeString.
--*/
{
PROCNAME("IoErrGetShortErrMessage");
NTSTATUS status;
ASSERT(ErrInfo != NULL);
ASSERT(ErrInfo->Signature == SIG_ERRINFO);
ASSERT(ErrCaseHandle != NULL);
ASSERT(unicodeMsg != NULL);
PAGED_CODE();
ENTER(1, ("(ErrInfo=%p,ErrCase=%p,pMsg=%p)\n",
ErrInfo, ErrCaseHandle, unicodeMsg));
if ((ErrInfo != NULL) && (ErrInfo->Signature == SIG_ERRINFO))
{
status = IoepHandleErrCase(ErrInfo,
(PERRCASE)ErrCaseHandle,
IOEMETHOD_SHORTMSG,
unicodeMsg);
}
else
{
status = STATUS_INVALID_PARAMETER;
DBGPRINT(("invalid handle\n"))
}
EXIT(1, ("=%x(Msg=%S)\n", status, unicodeMsg->Buffer));
return status;
} //IoErrGetShortErrMessage