Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1391 lines
38 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
safemode.c
Abstract:
A number of utilities for safe/recovery mode
Author:
Calin Negreanu (calinn) 6-Aug-1999
Revisions:
--*/
#include "pch.h"
#include "migutilp.h"
BOOL g_SafeModeInitialized = FALSE;
BOOL g_SafeModeActive = FALSE;
PCSTR g_SafeModeFileA = NULL;
PCWSTR g_SafeModeFileW = NULL;
HANDLE g_SafeModeFileHandle = INVALID_HANDLE_VALUE;
HASHTABLE g_SafeModeCrashTable = NULL;
BOOL g_ExceptionOccured = FALSE;
typedef struct {
ULONG Signature;
ULONG NumCrashes;
} SAFEMODE_HEADER, *PSAFEMODE_HEADER;
typedef struct {
ULONG CrashId;
ULONG CrashStrSize;
} CRASHDATA_HEADER, *PCRASHDATA_HEADER;
typedef struct _SAFEMODE_NODE {
DWORD FilePtr;
struct _SAFEMODE_NODE *Next;
} SAFEMODE_NODE, *PSAFEMODE_NODE;
PSAFEMODE_NODE g_SafeModeLastNode = NULL;
PSAFEMODE_NODE g_SafeModeCurrentNode = NULL;
POOLHANDLE g_SafeModePool = NULL;
#define SAFE_MODE_SIGNATURE 0x45464153
/*++
Routine Description:
pGenerateCrashString generates a crash string given an identifier and a string
The generated string will look like <Id>-<String>
Arguments:
Id - Safe mode identifier
String - Safe mode string
Return Value:
A pointer to a crash string allocated from g_SafeModePool
The caller must free the memory by calling PoolMemReleaseMemory
--*/
PCSTR
pGenerateCrashStringA (
IN ULONG Id,
IN PCSTR String
)
{
CHAR idStr [sizeof (ULONG) * 2 + 1];
_ultoa (Id, idStr, 16);
return JoinTextExA (g_SafeModePool, idStr, String, "-", 0, NULL);
}
PCWSTR
pGenerateCrashStringW (
IN ULONG Id,
IN PCWSTR String
)
{
WCHAR idStr [sizeof (ULONG) * 2 + 1];
_ultow (Id, idStr, 16);
return JoinTextExW (g_SafeModePool, idStr, String, L"-", 0, NULL);
}
/*++
Routine Description:
pSafeModeOpenAndResetFile opens the safe mode file looking for
crash strings stored here. It will also reset the part that is
dealing with nested calls by extracting the inner most crash string
stored there.
Arguments:
None
Return Value:
TRUE if the function completed successfully, FALSE otherwise
--*/
BOOL
pSafeModeOpenAndResetFileA (
VOID
)
{
SAFEMODE_HEADER header;
CRASHDATA_HEADER crashData;
DWORD lastFilePtr;
DWORD noBytes;
PSTR crashString = NULL;
PSTR lastCrashString = NULL;
ULONG lastCrashId;
PCSTR completeCrashString;
//
// Open the existing safe mode file or create a
// new one.
//
g_SafeModeFileHandle = CreateFileA (
g_SafeModeFileA,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_HIDDEN,
NULL
);
if (g_SafeModeFileHandle != INVALID_HANDLE_VALUE) {
//
// Let's try to read our header. If signature does
// match we will try to read extra data.
//
if (ReadFile (
g_SafeModeFileHandle,
&header,
sizeof (SAFEMODE_HEADER),
&noBytes,
NULL
) &&
(noBytes == sizeof (SAFEMODE_HEADER)) &&
(header.Signature == SAFE_MODE_SIGNATURE)
) {
//
// we know now we had an valid safe mode file. Enter safe mode.
//
g_SafeModeActive = TRUE;
LOGA ((LOG_ERROR, "Setup detected a crash on the previous upgrade attempt. Setup is running in safe mode."));
LOGA ((LOG_WARNING, "Setup has run in safe mode %d time(s).", header.NumCrashes));
//
// we need to initialize safe mode crash table
//
g_SafeModeCrashTable = HtAllocA ();
//
// Now, let's read all crash data, a ULONG and a string at a time
//
lastFilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
while (TRUE) {
if (!ReadFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
) ||
(noBytes != sizeof (CRASHDATA_HEADER))
) {
break;
}
if ((crashData.CrashId == 0) &&
(crashData.CrashStrSize == 0)
) {
//
// we crashed inside a nested guard. We need to
// extract the inner guard we crashed in.
//
lastCrashId = 0;
lastCrashString = NULL;
while (TRUE) {
if (!ReadFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
) ||
(noBytes != sizeof (CRASHDATA_HEADER))
) {
crashData.CrashId = 0;
break;
}
//
// Restrict the length of CrashStrSize to 32K
//
if (crashData.CrashStrSize >= 32768 * sizeof (CHAR)) {
crashData.CrashId = 0;
break;
}
crashString = AllocPathStringA (crashData.CrashStrSize);
if (!ReadFile (
g_SafeModeFileHandle,
crashString,
crashData.CrashStrSize,
&noBytes,
NULL
) ||
(noBytes != crashData.CrashStrSize)
) {
crashData.CrashId = 0;
FreePathStringA (crashString);
break;
}
if (lastCrashString) {
FreePathStringA (lastCrashString);
}
lastCrashId = crashData.CrashId;
lastCrashString = crashString;
}
if (lastCrashId && lastCrashString) {
//
// we found the inner guard we crashed in. Let's put this into
// the right place.
//
SetFilePointer (
g_SafeModeFileHandle,
lastFilePtr,
NULL,
FILE_BEGIN
);
crashData.CrashId = lastCrashId;
crashData.CrashStrSize = SizeOfStringA (lastCrashString);
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
WriteFile (
g_SafeModeFileHandle,
lastCrashString,
crashData.CrashStrSize,
&noBytes,
NULL
);
//
// store this information in Safe Mode crash table
//
completeCrashString = pGenerateCrashStringA (crashData.CrashId, crashString);
HtAddStringA (g_SafeModeCrashTable, completeCrashString);
PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
LOGA ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
lastFilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
FreePathStringA (lastCrashString);
}
break;
}
//
// Limit the size of the crash string
//
if (crashData.CrashStrSize >= 32768 * sizeof (CHAR)) {
LOG ((LOG_ERROR, "The crash detection journal contains garbage."));
break;
}
crashString = AllocPathStringA (crashData.CrashStrSize);
if (!ReadFile (
g_SafeModeFileHandle,
crashString,
crashData.CrashStrSize,
&noBytes,
NULL
) ||
(noBytes != crashData.CrashStrSize)
) {
break;
}
//
// store this information in Safe Mode crash table
//
completeCrashString = pGenerateCrashStringA (crashData.CrashId, crashString);
HtAddStringA (g_SafeModeCrashTable, completeCrashString);
PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
LOGA ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
lastFilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
}
//
// Write how many times we ran in safe mode
//
SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_BEGIN
);
header.Signature = SAFE_MODE_SIGNATURE;
header.NumCrashes += 1;
//
// Write safe mode header
//
WriteFile (
g_SafeModeFileHandle,
&header,
sizeof (SAFEMODE_HEADER),
&noBytes,
NULL
);
SetFilePointer (
g_SafeModeFileHandle,
lastFilePtr,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
//
// Write a null crash data header as an indicator
// that we start recording nested actions
//
crashData.CrashId = 0;
crashData.CrashStrSize = 0;
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
} else {
//
// Reset the file
//
SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
header.Signature = SAFE_MODE_SIGNATURE;
header.NumCrashes = 0;
//
// Write safe mode header
//
WriteFile (
g_SafeModeFileHandle,
&header,
sizeof (SAFEMODE_HEADER),
&noBytes,
NULL
);
//
// Write a null crash data header as an indicator
// that we start recording nested actions
//
crashData.CrashId = 0;
crashData.CrashStrSize = 0;
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
}
//
// Flush the file
//
FlushFileBuffers (g_SafeModeFileHandle);
//
// initialize the nested list
//
g_SafeModeLastNode = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
g_SafeModeCurrentNode = g_SafeModeLastNode->Next = g_SafeModeLastNode;
g_SafeModeLastNode->FilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
return TRUE;
}
return FALSE;
}
BOOL
pSafeModeOpenAndResetFileW (
VOID
)
{
SAFEMODE_HEADER header;
CRASHDATA_HEADER crashData;
DWORD lastFilePtr;
DWORD noBytes;
PWSTR crashString = NULL;
PWSTR lastCrashString = NULL;
ULONG lastCrashId;
PCWSTR completeCrashString;
//
// Open the existing safe mode file or create a
// new one.
//
g_SafeModeFileHandle = CreateFileW (
g_SafeModeFileW,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_HIDDEN,
NULL
);
if (g_SafeModeFileHandle != INVALID_HANDLE_VALUE) {
//
// Let's try to read our header. If signature does
// match we will try to read extra data.
//
if (ReadFile (
g_SafeModeFileHandle,
&header,
sizeof (SAFEMODE_HEADER),
&noBytes,
NULL
) &&
(noBytes == sizeof (SAFEMODE_HEADER)) &&
(header.Signature == SAFE_MODE_SIGNATURE)
) {
//
// we know now we had an valid safe mode file. Enter safe mode.
//
g_SafeModeActive = TRUE;
LOGW ((LOG_ERROR, "Setup detected a crash on the previous upgrade attempt. Setup is running in safe mode."));
LOGW ((LOG_WARNING, "Setup has run in safe mode %d time(s).", header.NumCrashes));
//
// we need to initialize safe mode crash table
//
g_SafeModeCrashTable = HtAllocW ();
//
// Now, let's read all crash data, a ULONG and a string at a time
//
lastFilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
while (TRUE) {
if (!ReadFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
) ||
(noBytes != sizeof (CRASHDATA_HEADER))
) {
break;
}
if ((crashData.CrashId == 0) &&
(crashData.CrashStrSize == 0)
) {
//
// we crashed inside a nested guard. We need to
// extract the inner guard we crashed in.
//
lastCrashId = 0;
lastCrashString = NULL;
while (TRUE) {
if (!ReadFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
) ||
(noBytes != sizeof (CRASHDATA_HEADER))
) {
crashData.CrashId = 0;
break;
}
//
// Restrict the length of CrashStrSize to 32K
//
if (crashData.CrashStrSize >= 32768 * sizeof (WCHAR)) {
crashData.CrashId = 0;
break;
}
crashString = AllocPathStringW (crashData.CrashStrSize);
if (!ReadFile (
g_SafeModeFileHandle,
crashString,
crashData.CrashStrSize,
&noBytes,
NULL
) ||
(noBytes != crashData.CrashStrSize)
) {
crashData.CrashId = 0;
FreePathStringW (crashString);
break;
}
if (lastCrashString) {
FreePathStringW (lastCrashString);
}
lastCrashId = crashData.CrashId;
lastCrashString = crashString;
}
if (lastCrashId && lastCrashString) {
//
// we found the inner guard we crashed in. Let's put this into
// the right place.
//
SetFilePointer (
g_SafeModeFileHandle,
lastFilePtr,
NULL,
FILE_BEGIN
);
crashData.CrashId = lastCrashId;
crashData.CrashStrSize = SizeOfStringW (lastCrashString);
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
WriteFile (
g_SafeModeFileHandle,
lastCrashString,
crashData.CrashStrSize,
&noBytes,
NULL
);
//
// store this information in Safe Mode crash table
//
completeCrashString = pGenerateCrashStringW (crashData.CrashId, crashString);
HtAddStringW (g_SafeModeCrashTable, completeCrashString);
PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
LOGW ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
lastFilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
FreePathStringW (lastCrashString);
}
break;
}
//
// Limit the size of the crash string
//
if (crashData.CrashStrSize >= 32768 * sizeof (WCHAR)) {
LOG ((LOG_ERROR, "The crash detection journal contains garbage."));
break;
}
crashString = AllocPathStringW (crashData.CrashStrSize);
if (!ReadFile (
g_SafeModeFileHandle,
crashString,
crashData.CrashStrSize,
&noBytes,
NULL
) ||
(noBytes != crashData.CrashStrSize)
) {
break;
}
//
// store this information in Safe Mode crash table
//
completeCrashString = pGenerateCrashStringW (crashData.CrashId, crashString);
HtAddStringW (g_SafeModeCrashTable, completeCrashString);
PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
LOGW ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
lastFilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
}
//
// Write how many times we ran in safe mode
//
SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_BEGIN
);
header.Signature = SAFE_MODE_SIGNATURE;
header.NumCrashes += 1;
//
// Write safe mode header
//
WriteFile (
g_SafeModeFileHandle,
&header,
sizeof (SAFEMODE_HEADER),
&noBytes,
NULL
);
SetFilePointer (
g_SafeModeFileHandle,
lastFilePtr,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
//
// Write a null crash data header as an indicator
// that we start recording nested actions
//
crashData.CrashId = 0;
crashData.CrashStrSize = 0;
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
} else {
//
// Reset the file
//
SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
header.Signature = SAFE_MODE_SIGNATURE;
header.NumCrashes = 0;
//
// Write safe mode header
//
WriteFile (
g_SafeModeFileHandle,
&header,
sizeof (SAFEMODE_HEADER),
&noBytes,
NULL
);
//
// Write a null crash data header as an indicator
// that we start recording nested actions
//
crashData.CrashId = 0;
crashData.CrashStrSize = 0;
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
}
//
// Flush the file
//
FlushFileBuffers (g_SafeModeFileHandle);
//
// initialize the nested list
//
g_SafeModeLastNode = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
g_SafeModeCurrentNode = g_SafeModeLastNode->Next = g_SafeModeLastNode;
g_SafeModeLastNode->FilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
return TRUE;
}
return FALSE;
}
/*++
Routine Description:
SafeModeInitialize is called to initialize safe mode. The result of this
function will be to either have safe mode active (if forced or if a crash
was detected) or not. If safe mode is not active all other call are almost
noop.
Arguments:
Forced - if this is TRUE, safe mode will be forced to be active
Return Value:
TRUE if the function completed successfully, FALSE otherwise
--*/
BOOL
SafeModeInitializeA (
BOOL Forced
)
{
CHAR winDir[MAX_MBCHAR_PATH];
g_ExceptionOccured = FALSE;
if (GetWindowsDirectoryA (winDir, MAX_MBCHAR_PATH)) {
g_SafeModePool = PoolMemInitNamedPool ("SafeMode Pool");
//
// BUGBUG -- technically this is wrong, it generates > MAX_PATH
// potentially. However, this is an impractical case, and the
// code is safe.
//
// BUGBUG -- This is inefficient. It breaks the paths pool by
// allocating a global. Paths pool is optimized for short-term use
// only.
//
g_SafeModeFileA = JoinPathsA (winDir, S_SAFE_MODE_FILEA);
//
// we are going to open the existing safe mode file
// or to create a new one
//
if (pSafeModeOpenAndResetFileA ()) {
if (Forced) {
g_SafeModeActive = TRUE;
if (g_SafeModeCrashTable == NULL) {
//
// we need to initialize safe mode crash table
//
g_SafeModeCrashTable = HtAllocA ();
}
}
g_SafeModeInitialized = TRUE;
return TRUE;
}
}
return FALSE;
}
BOOL
SafeModeInitializeW (
BOOL Forced
)
{
WCHAR winDir[MAX_WCHAR_PATH];
g_ExceptionOccured = FALSE;
if (GetWindowsDirectoryW (winDir, MAX_WCHAR_PATH)) {
g_SafeModePool = PoolMemInitNamedPool ("SafeMode Pool");
//
// BUGBUG -- technically this is wrong, it generates > MAX_PATH
// potentially. However, this is an impractical case, and the
// code is safe.
//
// BUGBUG -- This is inefficient. It breaks the paths pool by
// allocating a global. Paths pool is optimized for short-term use
// only.
//
g_SafeModeFileW = JoinPathsW (winDir, S_SAFE_MODE_FILEW);
//
// we are going to open the existing safe mode file
// or to create a new one
//
if (pSafeModeOpenAndResetFileW ()) {
if (Forced) {
g_SafeModeActive = TRUE;
if (g_SafeModeCrashTable == NULL) {
//
// we need to initialize safe mode crash table
//
g_SafeModeCrashTable = HtAllocA ();
}
}
g_SafeModeInitialized = TRUE;
return TRUE;
}
}
return FALSE;
}
/*++
Routine Description:
SafeModeShutDown is called to clean all data used by safe mode. It will remove
safe mode file, release all used memory, reset all globals. Subsequent calls
to safe mode functions after this will be noops.
Arguments:
NONE
Return Value:
TRUE if the function completed successfully, FALSE otherwise
--*/
BOOL
SafeModeShutDownA (
VOID
)
{
if (g_SafeModeInitialized) {
//
// Close and delete safe mode file.
// Reset all globals.
//
#ifdef DEBUG
if (g_SafeModeLastNode != g_SafeModeCurrentNode) {
DEBUGMSGA ((DBG_ERROR, "SafeMode: Unregistered action detected"));
}
#endif
if (!g_ExceptionOccured) {
CloseHandle (g_SafeModeFileHandle);
g_SafeModeFileHandle = INVALID_HANDLE_VALUE;
DeleteFileA (g_SafeModeFileA);
}
ELSE_DEBUGMSGA ((DBG_WARNING, "SafeModeShutDown called after exception. Files will not be cleaned up."));
FreePathStringA (g_SafeModeFileA);
g_SafeModeFileA = NULL;
HtFree (g_SafeModeCrashTable);
g_SafeModeCrashTable = NULL;
g_SafeModeActive = FALSE;
g_SafeModeInitialized = FALSE;
}
if (g_SafeModePool != NULL) {
PoolMemDestroyPool (g_SafeModePool);
g_SafeModePool = NULL;
}
return TRUE;
}
BOOL
SafeModeShutDownW (
VOID
)
{
if (g_SafeModeInitialized) {
//
// Close and delete safe mode file.
// Reset all globals.
//
#ifdef DEBUG
if (g_SafeModeLastNode != g_SafeModeCurrentNode) {
DEBUGMSGW ((DBG_ERROR, "SafeMode: Unregistered action detected"));
}
#endif
if (!g_ExceptionOccured) {
CloseHandle (g_SafeModeFileHandle);
g_SafeModeFileHandle = INVALID_HANDLE_VALUE;
DeleteFileW (g_SafeModeFileW);
}
ELSE_DEBUGMSGW ((DBG_WARNING, "SafeModeShutDown called after exception. Files will not be cleaned up."));
FreePathStringW (g_SafeModeFileW);
g_SafeModeFileW = NULL;
HtFree (g_SafeModeCrashTable);
g_SafeModeCrashTable = NULL;
g_SafeModeActive = FALSE;
g_SafeModeInitialized = FALSE;
}
if (g_SafeModePool != NULL) {
PoolMemDestroyPool (g_SafeModePool);
g_SafeModePool = NULL;
}
return TRUE;
}
/*++
Routine Description:
SafeModeRegisterAction is called when we want to guard a specific part of
the code. The caller should pass an guard ID and a guard string (used to
uniquely identify the portion of code beeing guarded.
Arguments:
Id - Safe mode identifier
String - Safe mode string
Return Value:
TRUE if the function completed successfully, FALSE otherwise
--*/
BOOL
SafeModeRegisterActionA (
IN ULONG Id,
IN PCSTR String
)
{
DWORD noBytes;
CRASHDATA_HEADER crashData;
PSAFEMODE_NODE node;
if (g_SafeModeInitialized && g_SafeModeActive) {
SetFilePointer (
g_SafeModeFileHandle,
g_SafeModeCurrentNode->FilePtr,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
crashData.CrashId = Id;
crashData.CrashStrSize = SizeOfStringA (String);
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
WriteFile (
g_SafeModeFileHandle,
String,
crashData.CrashStrSize,
&noBytes,
NULL
);
FlushFileBuffers (g_SafeModeFileHandle);
node = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
node->Next = g_SafeModeCurrentNode;
node->FilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
g_SafeModeCurrentNode = node;
}
return TRUE;
}
BOOL
SafeModeRegisterActionW (
IN ULONG Id,
IN PCWSTR String
)
{
DWORD noBytes;
CRASHDATA_HEADER crashData;
PSAFEMODE_NODE node;
if (g_SafeModeInitialized && g_SafeModeActive) {
SetFilePointer (
g_SafeModeFileHandle,
g_SafeModeCurrentNode->FilePtr,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
crashData.CrashId = Id;
crashData.CrashStrSize = SizeOfStringW (String);
WriteFile (
g_SafeModeFileHandle,
&crashData,
sizeof (CRASHDATA_HEADER),
&noBytes,
NULL
);
WriteFile (
g_SafeModeFileHandle,
String,
crashData.CrashStrSize,
&noBytes,
NULL
);
FlushFileBuffers (g_SafeModeFileHandle);
node = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
node->Next = g_SafeModeCurrentNode;
node->FilePtr = SetFilePointer (
g_SafeModeFileHandle,
0,
NULL,
FILE_CURRENT
);
g_SafeModeCurrentNode = node;
}
return TRUE;
}
/*++
Routine Description:
SafeModeUnregisterAction is called when we want end the guard set for
a specific part of the code. Since we allow nested guards, calling this
function at the end of the guarded code is neccessary. The function will
unregister the last registered guard.
Arguments:
NONE
Return Value:
TRUE if the function completed successfully, FALSE otherwise
--*/
BOOL
SafeModeUnregisterActionA (
VOID
)
{
PSAFEMODE_NODE node;
if (g_SafeModeInitialized && g_SafeModeActive) {
if (g_SafeModeCurrentNode != g_SafeModeLastNode) {
node = g_SafeModeCurrentNode;
g_SafeModeCurrentNode = g_SafeModeCurrentNode->Next;
PoolMemReleaseMemory (g_SafeModePool, node);
SetFilePointer (
g_SafeModeFileHandle,
g_SafeModeCurrentNode->FilePtr,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
}
#ifdef DEBUG
else {
DEBUGMSGA ((DBG_ERROR, "SafeMode: Too many actions unregistered."));
}
#endif
}
return TRUE;
}
BOOL
SafeModeUnregisterActionW (
VOID
)
{
PSAFEMODE_NODE node;
if (g_SafeModeInitialized && g_SafeModeActive) {
if (g_SafeModeCurrentNode != g_SafeModeLastNode) {
node = g_SafeModeCurrentNode;
g_SafeModeCurrentNode = g_SafeModeCurrentNode->Next;
PoolMemReleaseMemory (g_SafeModePool, node);
SetFilePointer (
g_SafeModeFileHandle,
g_SafeModeCurrentNode->FilePtr,
NULL,
FILE_BEGIN
);
SetEndOfFile (g_SafeModeFileHandle);
}
#ifdef DEBUG
else {
DEBUGMSGW ((DBG_ERROR, "SafeMode: Too many actions unregistered."));
}
#endif
}
return TRUE;
}
/*++
Routine Description:
SafeModeActionCrashed will return TRUE if one of the previous crashes
was detected in the code guarded by these arguments.
Arguments:
Id - Safe mode identifier
String - Safe mode string
Return Value:
TRUE if one of the previous crashes occured in the code guarded by the
arguments, FALSE otherwise
--*/
BOOL
SafeModeActionCrashedA (
IN ULONG Id,
IN PCSTR String
)
{
PCSTR crashString;
BOOL result = FALSE;
if (g_SafeModeInitialized && g_SafeModeActive) {
crashString = pGenerateCrashStringA (Id, String);
result = crashString && (HtFindStringA (g_SafeModeCrashTable, crashString));
PoolMemReleaseMemory (g_SafeModePool, (PVOID)crashString);
#ifdef DEBUG
{
UINT infId;
infId = GetPrivateProfileIntA ("SafeMode", String, SAFEMODEID_FIRST, g_DebugInfPathA);
result = result || (infId == Id);
}
#endif
}
return result;
}
BOOL
SafeModeActionCrashedW (
IN ULONG Id,
IN PCWSTR String
)
{
PCWSTR crashString;
BOOL result = FALSE;
if (g_SafeModeInitialized && g_SafeModeActive) {
crashString = pGenerateCrashStringW (Id, String);
result = crashString && (HtFindStringW (g_SafeModeCrashTable, crashString));
PoolMemReleaseMemory (g_SafeModePool, (PVOID)crashString);
#ifdef DEBUG
{
UINT infId;
infId = GetPrivateProfileIntW (L"SafeMode", String, SAFEMODEID_FIRST, g_DebugInfPathW);
result = result || (infId == Id);
}
#endif
}
return result;
}
/*++
Routine Description:
SafeModeExceptionOccured is called by exception handlers to let Safemode
know that something unexpected happened.
Arguments:
None.
Return Value:
--*/
VOID
SafeModeExceptionOccured (
VOID
)
{
g_ExceptionOccured = TRUE;
}