windows-nt/Source/XPSP1/NT/ds/netapi/svcimgs/ntrepl/util/frsalloc.c
2020-09-26 16:20:57 +08:00

4811 lines
121 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
frsalloc.c
Abstract:
Routines for allocating and freeing memory structures in the
NT File Replication Service.
Author:
David Orbits (davidor) - 3-Mar-1997
Revision History:
--*/
#include <ntreppch.h>
#pragma hdrstop
#undef DEBSUB
#define DEBSUB "FRSALLOC:"
#include <frs.h>
#include <ntfrsapi.h>
#include <info.h>
#include <perrepsr.h>
#pragma warning( disable:4102) // unreferenced label
//
// Check for allocation problems
//
#define DBG_NUM_MEM_STACK (8)
#define MAX_MEM_ON_FREE_LIST (1024)
#define MAX_MEM_INDEX (1024)
#define FRS_DEB_PRINT(_f, _d) \
DebPrintNoLock(Severity, TRUE, _f, Debsub, uLineNo, _d)
#define FRS_DEB_PRINT2(_f, _d1, _d2) \
DebPrintNoLock(Severity, TRUE, _f, Debsub, uLineNo, _d1, _d2)
#define FRS_DEB_PRINT3(_f, _d1, _d2, _d3) \
DebPrintNoLock(Severity, TRUE, _f, Debsub, uLineNo, _d1, _d2, _d3)
CRITICAL_SECTION MemLock;
typedef struct _MEM MEM, *PMEM;
struct _MEM {
PMEM Next;
ULONG_PTR *Begin;
ULONG_PTR *End;
DWORD OrigSize;
ULONG_PTR Stack[DBG_NUM_MEM_STACK];
};
PMEM MemList;
PMEM FreeMemList;
DWORD MemOnFreeList;
DWORD TotalAlloced;
DWORD TotalAllocCalls;
DWORD TotalFreed;
DWORD TotalFreeCalls;
DWORD TotalDelta;
DWORD TotalDeltaMax;
DWORD TotalTrigger = 10000;
ULONG TypesAllocatedCount[NODE_TYPE_MAX];
ULONG TypesAllocatedMax[NODE_TYPE_MAX];
ULONG TypesAllocated[NODE_TYPE_MAX];
ULONG SizesAllocatedCount[MAX_MEM_INDEX];
ULONG SizesAllocatedMax[MAX_MEM_INDEX];
ULONG SizesAllocated[MAX_MEM_INDEX];
ULONG DbgBreakSize = 2;
LONG DbgBreakTrigger = 1;
LONG DbgBreakReset = 1;
LONG DbgBreakResetInc = 0;
PULONG_PTR MaxAllocAddr;
PULONG_PTR MinAllocAddr;
DWORD ReAllocs;
DWORD NewAllocs;
//
// Keep these in the same order as the Node Type ENUM.
//
PCHAR NodeTypeNames[]= {
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"THREAD_CONTEXT_TYPE",
"REPLICA_TYPE",
"REPLICA_THREAD_TYPE",
"CONFIG_NODE_TYPE",
"CXTION_TYPE",
"GUID/RPC HANDLE",
"THREAD_TYPE",
"GEN_TABLE_TYPE",
"JBUFFER_TYPE",
"VOLUME_MONITOR_ENTRY_TYPE",
"COMMAND_PACKET_TYPE",
"GENERIC_HASH_TABLE_TYPE",
"CHANGE_ORDER_ENTRY_TYPE",
"FILTER_TABLE_ENTRY_TYPE",
"QHASH_TABLE_TYPE",
"OUT_LOG_PARTNER_TYPE",
"WILDCARD_FILTER_ENTRY_TYPE",
"NODE_TYPE_MAX"
};
extern PCHAR CoLocationNames[];
extern FLAG_NAME_TABLE StageFlagNameTable[];
extern FLAG_NAME_TABLE OlpFlagNameTable[];
extern PCHAR OLPartnerStateNames[];
extern PWCHAR DsConfigTypeName[];
extern PGEN_TABLE VolSerialNumberToDriveTable;
VOID
FrsDisplayUsnReason(
ULONG ReasonMask,
PCHAR Buffer,
LONG MaxLength
);
PFRS_THREAD
ThSupEnumThreads(
PFRS_THREAD FrsThread
);
VOID
DbgPrintThreadIds(
IN ULONG Severity
);
VOID
DbsDataInitCocExtension(
IN PCHANGE_ORDER_RECORD_EXTENSION CocExt
);
VOID
SndCsDestroyCxtion(
IN PCXTION Cxtion,
IN DWORD CxtionFlags
);
VOID
FrsInitializeMemAlloc(
VOID
)
/*++
Routine Description:
Initialize the memory allocation subsystem
Arguments:
None.
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsInitializeMemAlloc:"
InitializeCriticalSection(&MemLock);
//
// Get Debugmem and DebugMemCompact from ntfrs config section in the registry
//
CfgRegReadDWord(FKC_DEBUG_MEM, NULL, 0, &DebugInfo.Mem);
CfgRegReadDWord(FKC_DEBUG_MEM_COMPACT, NULL, 0, &DebugInfo.MemCompact);
}
VOID
FrsPrintAllocStats(
IN ULONG Severity,
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs
)
/*++
Routine Description:
Print the memory stats into the info buffer or using DPRINT (Info == NULL).
Arguments:
Severity - for DPRINT
Info - for IPRINT (use DPRINT if NULL)
Tabs - indentation for prettyprint
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintAllocStats:"
ULONG i;
WCHAR TabW[MAX_TAB_WCHARS + 1];
InfoTabs(Tabs, TabW);
IDPRINT0(Severity, Info, "\n");
IDPRINT1(Severity, Info, "%wsNTFRS MEMORY USAGE:\n", TabW);
IDPRINT2(Severity, Info, "%ws ENABLE STATS : %s\n",
TabW,
(DebugInfo.Mem) ? "TRUE" : "FALSE");
IDPRINT3(Severity, Info, "%ws Alloced : %6d KB (%d calls)\n",
TabW,
TotalAlloced / 1024,
TotalAllocCalls);
IDPRINT3(Severity, Info, "%ws Freed : %6d KB (%d calls)\n",
TabW,
TotalFreed / 1024,
TotalFreeCalls);
IDPRINT2(Severity, Info, "%ws Delta : %6d KB\n",
TabW,
TotalDelta / 1024);
IDPRINT2(Severity, Info, "%ws Max delta : %6d KB\n",
TabW,
TotalDeltaMax / 1024);
IDPRINT2(Severity, Info, "%ws Addr Range : %6d KB\n",
TabW,
(((PCHAR)MaxAllocAddr) - ((PCHAR)MinAllocAddr)) / 1024);
IDPRINT2(Severity, Info, "%ws OnFreeList : %d\n", TabW, MemOnFreeList);
IDPRINT2(Severity, Info, "%ws ReAllocs : %d\n", TabW, ReAllocs);
IDPRINT2(Severity, Info, "%ws NewAllocs : %d\n", TabW, NewAllocs);
IDPRINT2(Severity, Info, "%ws MinAddr : 0x%08x\n", TabW, MinAllocAddr);
IDPRINT2(Severity, Info, "%ws MaxAddr : 0x%08x\n", TabW, MaxAllocAddr);
for (i = 0; i < NODE_TYPE_MAX; ++i) {
if (!TypesAllocatedCount[i]) {
continue;
}
IDPRINT5(Severity, Info, "%ws %-26s: %6d Calls, %6d Max, %6d busy\n",
TabW, NodeTypeNames[i], TypesAllocatedCount[i],
TypesAllocatedMax[i], TypesAllocated[i]);
}
IDPRINT0(Severity, Info, "\n");
for (i = 0; i < MAX_MEM_INDEX; ++i) {
if (!SizesAllocatedCount[i]) {
continue;
}
IDPRINT6(Severity, Info, "%ws %6d to %6d : %6d Calls, %6d Max, %6d busy\n",
TabW, i << 4, ((i + 1) << 4) - 1,
SizesAllocatedCount[i], SizesAllocatedMax[i], SizesAllocated[i]);
}
IDPRINT0(Severity, Info, "\n");
}
VOID
FrsPrintThreadStats(
IN ULONG Severity,
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs
)
/*++
Routine Description:
Print the thread stats into the info buffer or using DPRINT (Info == NULL).
Arguments:
Severity - for DPRINT
Info - for IPRINT (use DPRINT if NULL)
Tabs - indentation for prettyprint
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintThreadStats:"
ULONGLONG CreateTime;
ULONGLONG ExitTime;
ULONGLONG KernelTime;
ULONGLONG UserTime;
PFRS_THREAD FrsThread;
WCHAR TabW[MAX_TAB_WCHARS + 1];
InfoTabs(Tabs, TabW);
IDPRINT0(Severity, Info, "\n");
IDPRINT1(Severity, Info, "%wsNTFRS THREAD USAGE:\n", TabW);
//
// Thread CPU Times
//
FrsThread = NULL;
while (FrsThread = ThSupEnumThreads(FrsThread)) {
if (HANDLE_IS_VALID(FrsThread->Handle)) {
if (GetThreadTimes(FrsThread->Handle,
(PFILETIME)&CreateTime,
(PFILETIME)&ExitTime,
(PFILETIME)&KernelTime,
(PFILETIME)&UserTime)) {
//
// Hasn't exited, yet
//
if (ExitTime < CreateTime) {
ExitTime = CreateTime;
}
IDPRINT5(Severity, Info, "%ws %-15ws: %8d CPU Seconds (%d kernel, %d elapsed)\n",
TabW,
FrsThread->Name,
(DWORD)((KernelTime + UserTime) / (10 * 1000 * 1000)),
(DWORD)((KernelTime) / (10 * 1000 * 1000)),
(DWORD)((ExitTime - CreateTime) / (10 * 1000 * 1000)));
}
}
}
//
// Process CPU Times
//
if (GetProcessTimes(ProcessHandle,
(PFILETIME)&CreateTime,
(PFILETIME)&ExitTime,
(PFILETIME)&KernelTime,
(PFILETIME)&UserTime)) {
//
// Hasn't exited, yet
//
if (ExitTime < CreateTime) {
ExitTime = CreateTime;
}
IDPRINT5(Severity, Info, "%ws %-15ws: %8d CPU Seconds (%d kernel, %d elapsed)\n",
TabW,
L"PROCESS",
(DWORD)((KernelTime + UserTime) / (10 * 1000 * 1000)),
(DWORD)((KernelTime) / (10 * 1000 * 1000)),
(DWORD)((ExitTime - CreateTime) / (10 * 1000 * 1000)));
}
IDPRINT0(Severity, Info, "\n");
}
VOID
FrsPrintStageStats(
IN ULONG Severity,
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs
)
/*++
Routine Description:
Print the staging area stats into the info buffer or
using DPRINT (Info == NULL).
Arguments:
Severity - for DPRINT
Info - for IPRINT (use DPRINT if NULL)
Tabs - indentation for prettyprint
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintStageStats:"
PVOID Key;
PSTAGE_ENTRY SEntry;
DWORD SizeInKb;
WCHAR TabW[MAX_TAB_WCHARS + 1];
CHAR Guid[GUID_CHAR_LEN + 1];
extern DWORD StagingAreaAllocated;
extern PGEN_TABLE StagingAreaTable;
InfoTabs(Tabs, TabW);
try {
GTabLockTable(StagingAreaTable);
IDPRINT0(Severity, Info, "\n");
IDPRINT3(Severity, Info, "%wsNTFRS STAGE USAGE: %d KB of %d KB allocated\n",
TabW, StagingAreaAllocated, StagingLimitInKb);
SizeInKb = 0;
Key = NULL;
while (SEntry = GTabNextDatumNoLock(StagingAreaTable, &Key)) {
GuidToStr(&SEntry->FileOrCoGuid, Guid);
IDPRINT2(Severity, Info, "%ws %s\n", TabW, Guid);
IDPRINT2(Severity, Info, "%ws Flags: %08x\n", TabW, SEntry->Flags);
IDPRINT2(Severity, Info, "%ws Size : %d\n", TabW, SEntry->FileSizeInKb);
SizeInKb += SEntry->FileSizeInKb;
}
IDPRINT2(Severity, Info, "%ws Calculated Usage is %d KB\n", TabW, SizeInKb);
IDPRINT0(Severity, Info, "\n");
} finally {
GTabUnLockTable(StagingAreaTable);
}
}
VOID
MyDbgBreak(
VOID
)
{
}
VOID
DbgCheck(
IN PMEM Mem
)
/*++
Routine Description:
Check a memory block. Memory lock must be held.
Arguments:
Mem - memory block
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "DbgCheck:"
PULONG_PTR pDWord;
ULONG_PTR Pattern;
//
// Begins at first byte at the end of the user's allocation
//
Pattern = (ULONG_PTR)(Mem->End) | (Mem->OrigSize << 24);
//
// Check for overwritten memory
//
if ( (ULONG_PTR)*Mem->Begin != (ULONG_PTR)Mem->Begin ) {
DPRINT2(0, "Begin Memory @ 0x%08x has been overwritten with 0x%08x\n",
Mem->Begin, *Mem->Begin);
} else if (memcmp(((PCHAR)Mem->Begin) + Mem->OrigSize + 8,
(PCHAR)&Pattern, sizeof(Pattern))) {
DPRINT1(0, "End Memory @ 0x%08x has been overwritten\n",
((PCHAR)Mem->Begin) + Mem->OrigSize + 8);
} else {
return;
}
DPRINT(0, "Memory's stack trace\n");
STACK_PRINT(0, Mem->Stack, DBG_NUM_MEM_STACK);
DPRINT(0, "Caller's stack trace\n");
STACK_TRACE_AND_PRINT(0);
DPRINT(0, "Corrupted block of memory\n");
for (pDWord = Mem->Begin; pDWord != Mem->End; ++pDWord) {
DPRINT2(0, "0x%08x: 0x%08x\n", pDWord, *pDWord);
}
exit(1);
}
VOID
DbgCheckAll(
VOID
)
/*++
Routine Description:
Check all memory blocks.
Arguments:
Mem - memory block
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "DbgCheckAll:"
PMEM Mem;
//
// Don't check the entire list of allocated memory blocks
//
if (DebugInfo.Mem < 2) {
return;
}
EnterCriticalSection(&MemLock);
for (Mem = MemList; Mem; Mem = Mem->Next) {
//
// Check for overwritten memory
//
DbgCheck(Mem);
}
LeaveCriticalSection(&MemLock);
}
VOID
FrsUnInitializeMemAlloc(
VOID
)
/*++
Routine Description:
Initialize the memory allocation subsystem
Arguments:
None.
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsUnInitializeMemAlloc:"
PMEM Mem;
EnterCriticalSection(&MemLock);
for (Mem = MemList; Mem; Mem = Mem->Next) {
//
// Check for overwritten memory
//
DbgCheck(Mem);
DPRINT2(1, "\t%d bytes @ 0x%08x\n",
((PCHAR)Mem->End) - ((PCHAR)Mem->Begin), Mem->Begin);
STACK_PRINT(1, Mem->Stack, DBG_NUM_MEM_STACK);
}
LeaveCriticalSection(&MemLock);
}
PMEM
DbgAlloc(
IN ULONG_PTR *Begin,
IN ULONG_PTR *End,
IN DWORD OrigSize
)
/*++
Routine Description:
Add a new allocation to our list of allocated memory after
checking for overlaps.
Arguments:
Begin - beginning of newly allocated memory
End - end of same
OrigSize - Size requested by caller
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "DbgAlloc:"
PMEM *PMem;
PMEM Mem;
ULONG Calls;
ULONG_PTR Pattern;
DWORD MemIndex;
//
// Approximate stats
//
if (!DebugInfo.Mem) {
//
// Memory stats
//
Calls = ++TotalAllocCalls;
TotalAlloced += (DWORD)((PUCHAR)End - (PUCHAR)Begin);
if (Begin > MaxAllocAddr) {
++NewAllocs;
MaxAllocAddr = Begin;
} else {
if (!MinAllocAddr) {
MinAllocAddr = Begin;
}
++ReAllocs;
}
//
// Tracking memory sizes
//
MemIndex = OrigSize >> 4;
if (MemIndex >= MAX_MEM_INDEX) {
MemIndex = (MAX_MEM_INDEX - 1);
}
SizesAllocatedCount[MemIndex]++;
//
// Print memory stats every so often
//
if (!(Calls % TotalTrigger)) {
DbgPrintThreadIds(DebugInfo.LogSeverity);
FrsPrintAllocStats(DebugInfo.LogSeverity, NULL, 0);
}
return NULL;
}
//
// Verify heap consistency
//
DbgCheckAll();
EnterCriticalSection(&MemLock);
PMem = &MemList;
for (Mem = *PMem; Mem; Mem = *PMem) {
//
// Check for overwritten memory
//
DbgCheck(Mem);
//
// Check for overlap
//
if ((Begin >= Mem->Begin && Begin < Mem->End) ||
(Mem->Begin >= Begin && Mem->Begin < End) ||
(Mem->End > Begin && Mem->End < End) ||
(End > Mem->Begin && End < Mem->End)) {
//
// DUP ALLOCATION (OVERLAP DETECTED)
// Release lock in case DPRINT calls allocation routines
//
LeaveCriticalSection(&MemLock);
DPRINT4(0, "ERROR -- DUP ALLOC: 0x%x to 0x%x is already allocated to 0x%x to 0x%x; EXITING\n",
Begin, End, Mem->Begin, Mem->End);
FRS_ASSERT(!"Duplicate memory allocation");
}
//
// This memory should be linked later in the sorted memory list
//
if (Begin > Mem->Begin) {
PMem = &Mem->Next;
continue;
}
//
// This memory should be linked here in the sorted memory list
//
break;
}
//
// Allocate a memory block header
//
Mem = FreeMemList;
if (Mem) {
--MemOnFreeList;
FreeMemList = Mem->Next;
} else {
Mem = (PVOID)malloc(sizeof(MEM));
if (Mem == NULL) {
RaiseException(ERROR_OUTOFMEMORY, 0, 0, NULL);
}
ZeroMemory(Mem, sizeof(MEM));
}
//
// Initialize the header and the header/trailer for memory overrun detection.
//
Mem->OrigSize = OrigSize;
Mem->End = End;
Mem->Begin = Begin;
//
// Initialize the header/trailer for memory overrun detection.
//
*Mem->Begin = (ULONG_PTR)Begin;
*(Mem->Begin + 1) = OrigSize;
Pattern = (ULONG_PTR)(Mem->End) | (Mem->OrigSize << 24);
CopyMemory(((PCHAR)Begin) + Mem->OrigSize + 8, (PCHAR)&Pattern, sizeof(Pattern));
//
// Add to sorted list
//
Mem->Next = *PMem;
*PMem = Mem;
//
// Note: stackwalk won't work from here; see frsalloctype()
//
// DbgStackTrace(Mem->Stack, DBG_NUM_MEM_STACK)
//
// Memory stats
//
Calls = ++TotalAllocCalls;
TotalAlloced += (DWORD)((PUCHAR)End - (PUCHAR)Begin);
TotalDelta = TotalAlloced - TotalFreed;
if (TotalDelta > TotalDeltaMax) {
TotalDeltaMax = TotalDelta;
}
if (Begin > MaxAllocAddr) {
++NewAllocs;
MaxAllocAddr = Begin;
} else {
if (!MinAllocAddr) {
MinAllocAddr = Begin;
}
++ReAllocs;
}
//
// Tracking memory sizes
//
MemIndex = OrigSize >> 4;
if (MemIndex >= MAX_MEM_INDEX) {
MemIndex = (MAX_MEM_INDEX - 1);
}
SizesAllocated[MemIndex]++;
SizesAllocatedCount[MemIndex]++;
if (SizesAllocated[MemIndex] > SizesAllocatedMax[MemIndex]) {
SizesAllocatedMax[MemIndex] = SizesAllocated[MemIndex];
}
//
// Done
//
LeaveCriticalSection(&MemLock);
//
// Print memory stats every so often
//
if (!(Calls % TotalTrigger)) {
DbgPrintThreadIds(DebugInfo.LogSeverity);
FrsPrintAllocStats(DebugInfo.LogSeverity, NULL, 0);
}
DbgCheckAll();
return Mem;
}
VOID
DbgFree(
IN PULONG_PTR Begin
)
/*++
Routine Description:
Remove allocated memory from list
Arguments:
Begin - allocated (maybe) memory
Return Value:
TRUE - found it
FALSE - didn't find it
--*/
{
#undef DEBSUB
#define DEBSUB "DbgFree:"
PMEM *PMem;
PMEM Mem;
DWORD MemIndex;
//
// Freeing NULL pointer is allowed
//
if (Begin == NULL || !DebugInfo.Mem) {
return;
}
DbgCheckAll();
EnterCriticalSection(&MemLock);
PMem = &MemList;
for (Mem = *PMem; Mem; Mem = *PMem) {
//
// Check for overwritten memory
//
DbgCheck(Mem);
//
// Not the right one
//
if (Begin > Mem->Begin) {
PMem = &Mem->Next;
continue;
}
if (Begin != Mem->Begin) {
break;
}
//
// Found it; remove from list and free it
//
++TotalFreeCalls;
TotalFreed += (DWORD)((PUCHAR)Mem->End - (PUCHAR)Mem->Begin);
TotalDelta = TotalAlloced - TotalFreed;
MemIndex = Mem->OrigSize >> 4;
if (MemIndex >= MAX_MEM_INDEX) {
MemIndex = (MAX_MEM_INDEX - 1);
}
SizesAllocated[MemIndex]--;
*PMem = Mem->Next;
if (MemOnFreeList > MAX_MEM_ON_FREE_LIST) {
free(Mem);
} else {
++MemOnFreeList;
Mem->Next = FreeMemList;
FreeMemList = Mem;
}
LeaveCriticalSection(&MemLock);
DbgCheckAll();
return;
}
LeaveCriticalSection(&MemLock);
DPRINT1(0, "ERROR -- Memory @ 0x%x is not allocated\n", Begin);
FRS_ASSERT(!"Memory free error, not allocated");
}
BOOL
DbgIsAlloc(
IN PULONG_PTR Begin
)
/*++
Routine Description:
Is Begin alloced?
Arguments:
Begin - allocated (maybe) memory
Return Value:
TRUE - found it
FALSE - didn't find it
--*/
{
#undef DEBSUB
#define DEBSUB "DbgIsAlloc:"
PMEM *PMem;
PMEM Mem;
if (!DebugInfo.Mem) {
return TRUE;
}
//
// NULL pointer is always alloced
//
if (Begin == NULL) {
return TRUE;
}
DbgCheckAll();
EnterCriticalSection(&MemLock);
PMem = &MemList;
for (Mem = *PMem; Mem; Mem = *PMem) {
//
// Check for overwritten memory
//
DbgCheck(Mem);
//
// Not the right one
//
if (Begin > Mem->Begin) {
PMem = &Mem->Next;
continue;
}
if (Begin != Mem->Begin) {
break;
}
LeaveCriticalSection(&MemLock);
DbgCheckAll();
return TRUE;
}
LeaveCriticalSection(&MemLock);
DbgCheckAll();
return FALSE;
}
PVOID
FrsAlloc(
IN DWORD OrigSize
)
/*++
Routine Description:
Allocate memory. Raise an exception if there is no memory.
Arguments:
Size - size of the memory request
Return Value:
Allocated memory.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsAlloc:"
PVOID Node;
DWORD Size;
PMEM Mem;
//
// FRS_ASSERT is added here to satisfy prefix. The return value from FrsAlloc is not checked anywhere
// in the code.
//
FRS_ASSERT(OrigSize != 0);
Size = OrigSize;
if (DebugInfo.Mem) {
//
// Check for debug break
//
if (OrigSize == DbgBreakSize) {
if (DbgBreakTrigger) {
if (--DbgBreakTrigger <= 0) {
DbgBreakTrigger = DbgBreakReset;
DbgBreakReset += DbgBreakResetInc;
MyDbgBreak();
}
}
}
//
// Adjust size for header/trailer
//
Size = (((OrigSize + 7) >> 3) << 3) + 16;
}
//
// Raise an exception if there is no memory
//
Node = (PVOID)malloc(Size);
if (Node == NULL) {
RaiseException(ERROR_OUTOFMEMORY, 0, 0, NULL);
}
ZeroMemory(Node, Size);
//
// Even with mem alloc tracing off call DbgAlloc to capture mem alloc stats.
//
Mem = DbgAlloc(Node, (PULONG_PTR)(((PCHAR)Node) + Size), OrigSize);
//
// Note: should be in dbgalloc(); but stackwalk won't work
//
if (DebugInfo.Mem) {
DbgStackTrace(Mem->Stack, DBG_NUM_MEM_STACK);
((PCHAR)Node) += 8;
}
return Node;
}
PVOID
FrsRealloc(
PVOID OldNode,
DWORD OrigSize
)
/*++
Routine Description:
Reallocate memory. Raise an exception if there is no memory.
Arguments:
Size - size of the memory request
Return Value:
Reallocated memory.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsRealloc:"
PVOID Node;
DWORD Size;
PMEM Mem;
if (!OldNode) {
//
// Need to check if OrigSize == 0 as FrsAlloc asserts if called with 0 as the first parameter (prefix fix).
//
if (OrigSize == 0) {
return NULL;
}
return FrsAlloc(OrigSize);
}
Size = OrigSize;
if (DebugInfo.Mem) {
((PCHAR)OldNode) -= 8;
DbgFree(OldNode);
//
// Adjust size for header/trailer
//
Size = (((OrigSize + 7) >> 3) << 3) + 16;
}
//
// Raise an exception if there is no memory
//
Node = (PVOID)realloc(OldNode, Size);
if (Node == NULL) {
RaiseException(ERROR_OUTOFMEMORY, 0, 0, NULL);
}
//
// Even with mem alloc tracing off call DbgAlloc to capture mem alloc stats.
//
Mem = DbgAlloc(Node, (PULONG_PTR)(((PCHAR)Node) + Size), OrigSize);
//
// Note: should be in dbgalloc(); but stackwalk won't work
//
if (DebugInfo.Mem) {
DbgStackTrace(Mem->Stack, DBG_NUM_MEM_STACK);
((PCHAR)Node) += 8;
}
return Node;
}
PVOID
FrsFree(
PVOID Node
)
/*++
Routine Description:
Free memory allocated with FrsAlloc
Arguments:
Node - memory allocated with FrsAlloc
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsFree:"
if (!Node) {
return NULL;
}
if (DebugInfo.Mem) {
((PCHAR)Node) -= 8;
DbgFree(Node);
}
free(Node);
if (DebugInfo.MemCompact) {
HeapCompact(GetProcessHeap(), 0);
}
return NULL;
}
PCHAR
FrsWtoA(
PWCHAR Wstr
)
/*++
Routine Description:
Translate a wide char string into a newly allocated char string.
Arguments:
Wstr - wide char string
Return Value:
Duplicated string. Free with FrsFree().
--*/
{
#undef DEBSUB
#define DEBSUB "FrsWtoA:"
PCHAR Astr;
//
// E.g., when duplicating NodePartner when none exists
//
if (Wstr == NULL)
return NULL;
Astr = FrsAlloc(wcslen(Wstr) + 1);
sprintf(Astr, "%ws", Wstr);
return Astr;
}
PWCHAR
FrsWcsTrim(
PWCHAR Wstr,
WCHAR Trim
)
/*++
Routine Description:
Remove the Trim char from the trailing end of the string by replacing
any occurance with a L'\0'.
Skip over any leading Trim chars and return a ptr to the first non-TRIM
char found. If we hit the end of the string return the pointer to
the terminating null.
Arguments:
Wstr - wide char string
Trim - Char to trim.
Return Value:
ptr to first non Trim char.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsWcsTrim:"
LONG Len, Index;
if (Wstr == NULL)
return NULL;
//
//
Len = wcslen(Wstr);
Index = Len - 1;
while (Index >= 0) {
if (Wstr[Index] != Trim) {
break;
}
Index--;
}
Wstr[++Index] = UNICODE_NULL;
Len = Index;
Index = 0;
while (Index < Len) {
if (Wstr[Index] != Trim) {
break;
}
Index++;
}
return Wstr + Index;
}
PWCHAR
FrsAtoW(
PCHAR Astr
)
/*++
Routine Description:
Translate a wide char string into a newly allocated char string.
Arguments:
Wstr - wide char string
Return Value:
Duplicated string. Free with FrsFree().
--*/
{
PWCHAR Wstr;
//
// E.g., when duplicating NodePartner when none exists
//
if (Astr == NULL) {
return NULL;
}
Wstr = FrsAlloc((strlen(Astr) + 1) * sizeof(WCHAR));
swprintf(Wstr, L"%hs", Astr);
return Wstr;
}
PWCHAR
FrsWcsDup(
PWCHAR OldStr
)
/*++
Routine Description:
Duplicate a string using our memory allocater
Arguments:
OldArg - string to duplicate
Return Value:
Duplicated string. Free with FrsFree().
--*/
{
#undef DEBSUB
#define DEBSUB "FrsWcsDup:"
PWCHAR NewStr;
//
// E.g., when duplicating NodePartner when none exists
//
if (OldStr == NULL) {
return NULL;
}
NewStr = FrsAlloc((wcslen(OldStr) + 1) * sizeof(WCHAR));
wcscpy(NewStr, OldStr);
return NewStr;
}
VOID
FrsBuildVolSerialNumberToDriveTable(
VOID
)
/*++
Routine Description:
New way to get the current configuration from the DS and merge it with
the active replicas.
Arguments:
None.
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsBuildVolSerialNumberToDriveTable:"
ULONG MaxFileNameLen;
DWORD FileSystemFlags;
PWCHAR DrivePtr = NULL;
DWORD WStatus;
PVOLUME_INFO_NODE VolumeInfoNode;
UINT DriveType;
ULONG VolumeSerialNumber = 0;
WCHAR LogicalDrives[MAX_PATH];
WCHAR VolumeGuidName[MAX_PATH];
//
// Initialize the VolSerialNumberToDriveTable.
//
if (VolSerialNumberToDriveTable == NULL) {
VolSerialNumberToDriveTable = GTabAllocNumberTable();
}
//
// Get the logical drive strings.
//
if (!GetLogicalDriveStrings(MAX_PATH, LogicalDrives) || (VolSerialNumberToDriveTable == NULL)) {
DPRINT_WS(1, "WARN - Getting logical drives. It may not be possible to start on this server.", GetLastError());
return;
}
//
// Lock the table during rebuild to synchronize with the many callers of
// FrsWcsVolume() in other threads.
//
GTabLockTable(VolSerialNumberToDriveTable);
GTabEmptyTableNoLock(VolSerialNumberToDriveTable, FrsFree);
DrivePtr = LogicalDrives;
while (wcscmp(DrivePtr,L"")) {
DriveType = GetDriveType(DrivePtr);
//
// Skip remote drives and CDROM drives.
//
if ((DriveType == DRIVE_REMOTE) || (DriveType == DRIVE_CDROM)) {
DPRINT1(4, "Skipping Drive %ws. Invalid drive type.\n", DrivePtr);
DrivePtr = DrivePtr + wcslen(DrivePtr) + 1;
continue;
}
if (!GetVolumeInformation(DrivePtr,
VolumeGuidName,
MAX_PATH,
&VolumeSerialNumber,
&MaxFileNameLen,
&FileSystemFlags,
NULL,
0)){
DPRINT1_WS(1,"WARN - GetvolumeInformation for %ws;", DrivePtr, GetLastError());
DrivePtr = DrivePtr + wcslen(DrivePtr) + 1;
continue;
}
VolumeInfoNode = FrsAlloc(sizeof(VOLUME_INFO_NODE));
wcscpy(VolumeInfoNode->DriveName, L"\\\\.\\");
wcscat(VolumeInfoNode->DriveName, DrivePtr);
//
// Remove the trailing back slash.
//
VolumeInfoNode->DriveName[wcslen(VolumeInfoNode->DriveName) - 1] = L'\0';
VolumeInfoNode->VolumeSerialNumber = VolumeSerialNumber;
GTabInsertEntryNoLock(VolSerialNumberToDriveTable, VolumeInfoNode, &(VolumeInfoNode->VolumeSerialNumber), NULL);
DrivePtr = DrivePtr + wcslen(DrivePtr) + 1;
}
GTabUnLockTable(VolSerialNumberToDriveTable);
return;
}
PWCHAR
FrsWcsVolume(
PWCHAR Path
)
/*++
Routine Description:
Get the drive from the VolSerialNumberToDriveTable. The volume serial
number is used to locate the drive since a mount point can take us to
another drive.
Arguments:
Path
Return Value:
Duplicated string containing drive:\ from Path or NULL.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsWcsVolume:"
PWCHAR Volume = NULL;
HANDLE DirHandle;
DWORD WStatus;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
DWORD VolumeInfoLength;
PFILE_FS_VOLUME_INFORMATION VolumeInfo;
PVOLUME_INFO_NODE VolumeInfoNode;
//
// Get the volume Guid for the path.
//
// Always open the path by masking off the FILE_OPEN_REPARSE_POINT flag
// because we want to open the destination dir not the junction if the root
// happens to be a mount point.
//
WStatus = FrsOpenSourceFileW(&DirHandle,
Path,
GENERIC_READ,
FILE_OPEN_FOR_BACKUP_INTENT);
CLEANUP1_WS(4,"ERROR - Could not open %ws;", Path, WStatus, RETURN);
VolumeInfoLength = sizeof(FILE_FS_VOLUME_INFORMATION) +
MAXIMUM_VOLUME_LABEL_LENGTH;
VolumeInfo = FrsAlloc(VolumeInfoLength);
Status = NtQueryVolumeInformationFile(DirHandle,
&IoStatusBlock,
VolumeInfo,
VolumeInfoLength,
FileFsVolumeInformation);
NtClose(DirHandle);
if (NT_SUCCESS(Status)) {
//
// Build the table if it does not yet exist. This table is rebuilt at the
// start of each DS poll cycle so we have updated information about
// the volumes on the machine.
//
if (VolSerialNumberToDriveTable == NULL) {
FrsBuildVolSerialNumberToDriveTable();
}
VolumeInfoNode = GTabLookup(VolSerialNumberToDriveTable, &(VolumeInfo->VolumeSerialNumber), NULL);
if (VolumeInfoNode) {
Volume = FrsWcsDup(VolumeInfoNode->DriveName);
}
} else {
DPRINT1_NT(1,"WARN - NtQueryVolumeInformationFile failed for %ws;", Path, Status);
}
VolumeInfo = FrsFree(VolumeInfo);
RETURN:
return Volume;
}
PWCHAR
FrsWcsCat3(
PWCHAR First,
PWCHAR Second,
PWCHAR Third
)
/*++
Routine Description:
Concatenate three strings into a new string using our memory allocater
Arguments:
First - First string in the concat
Second - Second string in the concat
Third - Third string in the concat
Return Value:
Return concatenated string. Free with FrsFree().
--*/
{
#undef DEBSUB
#define DEBSUB "FrsWcscat3:"
PCHAR New;
DWORD BytesFirst;
DWORD BytesSecond;
DWORD BytesThird;
if (!First || !Second || !Third) {
return NULL;
}
//
// Allocate a buffer for the concatentated string
//
BytesFirst = wcslen(First) * sizeof(WCHAR);
BytesSecond = wcslen(Second) * sizeof(WCHAR);
BytesThird = (wcslen(Third) + 1) * sizeof(WCHAR);
New = (PCHAR)FrsAlloc(BytesFirst + BytesSecond + BytesThird);
CopyMemory(&New[0], First, BytesFirst);
CopyMemory(&New[BytesFirst], Second, BytesSecond);
CopyMemory(&New[BytesFirst + BytesSecond], Third, BytesThird);
return (PWCHAR)New;
}
PWCHAR
FrsWcsCat(
PWCHAR First,
PWCHAR Second
)
/*++
Routine Description:
Concatenate two strings into a new string using our memory allocater
Arguments:
First - First string in the concat
Second - Second string in the concat
Return Value:
Duplicated and concatentated string. Free with FrsFree().
--*/
{
#undef DEBSUB
#define DEBSUB "FrsWcscat:"
DWORD Bytes;
PWCHAR New;
FRS_ASSERT(First != NULL && Second != NULL);
// size of new string
Bytes = (wcslen(First) + wcslen(Second) + 1) * sizeof(WCHAR);
New = (PWCHAR)FrsAlloc(Bytes);
// Not as efficient as I would like but this routine is seldom used
wcscpy(New, First);
wcscat(New, Second);
return New;
}
PCHAR
FrsCsCat(
PCHAR First,
PCHAR Second
)
/*++
Routine Description:
Concatenate two strings into a new string using our memory allocater
Arguments:
First - First string in the concat
Second - Second string in the concat
Return Value:
Duplicated and concatentated string. Free with FrsFree().
--*/
{
#undef DEBSUB
#define DEBSUB "FrsCscat:"
DWORD Bytes;
PCHAR New;
FRS_ASSERT(First != NULL && Second != NULL);
// size of new string
Bytes = strlen(First) + strlen(Second) + 1;
New = (PCHAR)FrsAlloc(Bytes);
// Not as efficient as I would like but this routine is seldom used
strcpy(New, First);
strcat(New, Second);
return New;
}
PWCHAR
FrsWcsPath(
PWCHAR First,
PWCHAR Second
)
/*++
Routine Description:
Concatenate two strings into a pathname
Arguments:
First - First string in the concat
Second - Second string in the concat
Return Value:
Dup of First\Second. Free with FrsFree();
--*/
{
#undef DEBSUB
#define DEBSUB "FrsWcsPath:"
return FrsWcsCat3(First, L"\\", Second);
}
PCHAR
FrsCsPath(
PCHAR First,
PCHAR Second
)
/*++
Routine Description:
Concatenate two strings into a pathname
Arguments:
First - First string in the concat
Second - Second string in the concat
Return Value:
Duplicated and concatentated string. Free with FrsFree().
--*/
{
#undef DEBSUB
#define DEBSUB "FrsCsPath:"
PCHAR TmpPath;
PCHAR FinalPath;
//
// Very inefficient but seldom called
//
TmpPath = FrsCsCat(First, "\\");
FinalPath = FrsCsCat(TmpPath, Second);
FrsFree(TmpPath);
return FinalPath;
}
PVOID
FrsAllocTypeSize(
IN NODE_TYPE NodeType,
IN ULONG SizeDelta
)
/*++
Routine Description:
This routine allocates memory for the given node type and performs any
node specific initialization/allocation. The node is zeroed and the
size/type fields are filled in.
Arguments:
NodeType - The type of node to allocate.
SizeDelta - The amount of storage to allocate in ADDITION to the base type.
Return Value:
The node address is returned here. An exception is raised if
memory could not be allocated.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsAllocTypeSize:"
PVOID Node;
ULONG NodeSize;
PREPLICA Replica;
PREPLICA_THREAD_CTX RtCtx;
PTHREAD_CTX ThreadCtx;
PTABLE_CTX TableCtx;
ULONG i;
PJBUFFER Jbuffer;
PVOLUME_MONITOR_ENTRY pVme;
PFILTER_TABLE_ENTRY FilterEntry;
PQHASH_TABLE QhashTable;
PCXTION Cxtion;
PCONFIG_NODE ConfigNode;
PCHANGE_ORDER_ENTRY ChangeOrder;
PGHANDLE GHandle;
PWILDCARD_FILTER_ENTRY WildcardEntry;
switch (NodeType) {
//
// Allocate a Thread Context struct
//
case THREAD_CONTEXT_TYPE:
NodeSize = sizeof(THREAD_CTX);
Node = FrsAlloc(NodeSize);
//
// No session or DB open yet.
//
ThreadCtx = (PTHREAD_CTX) Node;
ThreadCtx->JSesid = JET_sesidNil;
ThreadCtx->JDbid = JET_dbidNil;
ThreadCtx->JInstance = GJetInstance;
FrsRtlInitializeList(&ThreadCtx->ThreadCtxListHead);
break;
//
// Allocate a Replica struct and the config table ctx struct.
//
case REPLICA_TYPE:
NodeSize = sizeof(REPLICA);
Node = FrsAlloc(NodeSize);
Replica = (PREPLICA) Node;
//
// Config record flags (CONFIG_FLAG_... in schema.h)
//
SetFlag(Replica->CnfFlags, CONFIG_FLAG_MULTIMASTER);
InitializeCriticalSection(&Replica->ReplicaLock);
FrsRtlInitializeList(&Replica->ReplicaCtxListHead);
InitializeListHead(&Replica->FileNameFilterHead);
InitializeListHead(&Replica->FileNameInclFilterHead);
InitializeListHead(&Replica->DirNameFilterHead);
InitializeListHead(&Replica->DirNameInclFilterHead);
Replica->ConfigTable.TableType = TABLE_TYPE_INVALID;
DbsAllocTableCtx(ConfigTablex, &Replica->ConfigTable);
Replica->VVector = GTabAllocTable();
Replica->Cxtions = GTabAllocTable();
Replica->FStatus = FrsErrorSuccess;
Replica->Consistent = TRUE;
InitializeCriticalSection(&Replica->OutLogLock);
InitializeListHead(&Replica->OutLogEligible);
InitializeListHead(&Replica->OutLogStandBy);
InitializeListHead(&Replica->OutLogActive);
InitializeListHead(&Replica->OutLogInActive);
Replica->OutLogWorkState = OL_REPLICA_INITIALIZING;
Replica->ServiceState = REPLICA_STATE_ALLOCATED;
Replica->OutLogJLx = 1;
//
// No preinstall directory, yet
//
Replica->PreInstallHandle = INVALID_HANDLE_VALUE;
//
// Initialize the NewStage fiend.
//
Replica->NewStage = NULL;
//
// Initialize InitSyncCxtionsMasterList and InitSyncCxtionsWorkingList.
//
Replica->InitSyncCxtionsMasterList = NULL;
Replica->InitSyncCxtionsWorkingList = NULL;
Replica->InitSyncQueue = NULL;
//
// Add memory for the counter data structure, set the back pointer
// and bump ref count.
//
Replica->PerfRepSetData =
(PHT_REPLICA_SET_DATA) FrsAlloc (sizeof(HT_REPLICA_SET_DATA));
Replica->PerfRepSetData->RepBackPtr = Replica;
InterlockedIncrement(&Replica->ReferenceCount);
break;
//
// Allocate a Replica Thread Context struct and the table context structs.
//
case REPLICA_THREAD_TYPE:
NodeSize = sizeof(REPLICA_THREAD_CTX);
Node = FrsAlloc(NodeSize);
//
// Get the base of the array of TableCtx structs from the replica thread
// context struct and the base of the table create structs.
//
RtCtx = (PREPLICA_THREAD_CTX) Node;
TableCtx = RtCtx->RtCtxTables;
//
// Open the initial set of tables for the replica set.
//
for (i=0; i<TABLE_TYPE_MAX; ++i, ++TableCtx) {
//
// Marking the TableType as INVALID causes DbsAllocTableCtx()
// to allocate the DB support structs on the first call.
//
TableCtx->TableType = TABLE_TYPE_INVALID;
//
// If the SizeDelta parameter is non-zero then do not allocate
// the TableCtx internal structs. The caller will do it.
//
if (SizeDelta == 0) {
DbsAllocTableCtx(i, TableCtx);
} else {
//
// Mark table as not open by a session yet.
//
TableCtx->Tid = JET_tableidNil;
TableCtx->Sesid = JET_sesidNil;
TableCtx->ReplicaNumber = FRS_UNDEFINED_REPLICA_NUMBER;
}
}
break;
//
// Allocate a topology node
//
case CONFIG_NODE_TYPE:
NodeSize = sizeof(CONFIG_NODE);
Node = FrsAlloc(NodeSize);
ConfigNode = (PCONFIG_NODE) Node;
ConfigNode->Consistent = TRUE;
break;
//
// Allocate a connection
//
case CXTION_TYPE:
NodeSize = sizeof(CXTION);
Node = FrsAlloc(NodeSize);
Cxtion = Node;
Cxtion->CoeTable = GTabAllocTable();
//
// Allocate memory for the counter data structure
//
Cxtion->PerfRepConnData =
(PHT_REPLICA_CONN_DATA) FrsAlloc (sizeof(HT_REPLICA_CONN_DATA));
break;
//
// Allocate a list of bound rpc handles indexed by server guid
//
case GHANDLE_TYPE:
NodeSize = sizeof(GHANDLE);
Node = FrsAlloc(NodeSize);
GHandle = Node;
InitializeCriticalSection(&GHandle->Lock);
break;
//
// Allocate a generic table
//
case GEN_TABLE_TYPE:
NodeSize = sizeof(GEN_TABLE);
Node = FrsAlloc(NodeSize);
break;
//
// Allocate a generic thread context
//
case THREAD_TYPE:
NodeSize = sizeof(FRS_THREAD);
Node = FrsAlloc(NodeSize);
break;
//
// Allocate a journal read buffer.
//
case JBUFFER_TYPE:
NodeSize = SizeOfJournalBuffer;
Node = FrsAlloc(NodeSize);
//
// Init the data buffer size and start address.
//
Jbuffer = (PJBUFFER) Node;
Jbuffer->BufferSize = NodeSize - SizeOfJournalBufferDesc;
Jbuffer->DataBuffer = &Jbuffer->Buffer[0];
break;
//
// Allocate a journal volume monitor entry.
//
case VOLUME_MONITOR_ENTRY_TYPE:
NodeSize = sizeof(VOLUME_MONITOR_ENTRY);
Node = FrsAlloc(NodeSize);
pVme = (PVOLUME_MONITOR_ENTRY) Node;
FrsRtlInitializeList(&pVme->ReplicaListHead);
InitializeCriticalSection(&pVme->Lock);
InitializeCriticalSection(&pVme->QuadWriteLock);
pVme->Event = CreateEvent(NULL, TRUE, FALSE, NULL);
pVme->JournalState = JRNL_STATE_ALLOCATED;
break;
//
// Allocate a command packet.
//
case COMMAND_PACKET_TYPE:
NodeSize = sizeof(COMMAND_PACKET);
Node = FrsAlloc(NodeSize + SizeDelta);
break;
//
// Allocate a generic hash table struct.
//
case GENERIC_HASH_TABLE_TYPE:
NodeSize = sizeof(GENERIC_HASH_TABLE);
Node = FrsAlloc(NodeSize);
break;
//
// Allocate a Change Order Entry struct. Caller allocates Extension as necc.
//
case CHANGE_ORDER_ENTRY_TYPE:
NodeSize = sizeof(CHANGE_ORDER_ENTRY);
Node = FrsAlloc(NodeSize + SizeDelta);
ChangeOrder = (PCHANGE_ORDER_ENTRY)Node;
//
// Init the unicode filename string to point to internal alloc.
//
ChangeOrder->UFileName.Buffer = ChangeOrder->Cmd.FileName;
ChangeOrder->UFileName.MaximumLength = (USHORT)
(SIZEOF(CHANGE_ORDER_ENTRY, Cmd.FileName) + SizeDelta);
ChangeOrder->UFileName.Length = 0;
break;
//
// Allocate a Filter Table Entry struct.
//
case FILTER_TABLE_ENTRY_TYPE:
NodeSize = sizeof(FILTER_TABLE_ENTRY);
Node = FrsAlloc(NodeSize + SizeDelta);
FilterEntry = (PFILTER_TABLE_ENTRY)Node;
//
// Init the unicode filename string to point to internal alloc.
//
FilterEntry->UFileName.Buffer = FilterEntry->DFileName;
FilterEntry->UFileName.MaximumLength = (USHORT)SizeDelta + sizeof(WCHAR);
FilterEntry->UFileName.Length = 0;
InitializeListHead(&FilterEntry->ChildHead);
break;
//
// Allocate a QHASH table struct. Just alloc the
// base table. An extension is allocated on the first collision.
// *NOTE* caller specifies the size of the actual hash table and
// the extension. Caller also must store an address to a hash calc
// function.
//
case QHASH_TABLE_TYPE:
NodeSize = sizeof(QHASH_TABLE);
Node = FrsAlloc(NodeSize + SizeDelta);
QhashTable = (PQHASH_TABLE)Node;
InitializeCriticalSection(&QhashTable->Lock);
InitializeListHead(&QhashTable->ExtensionListHead);
QhashTable->BaseAllocSize = NodeSize + SizeDelta;
QhashTable->NumberEntries = SizeDelta / sizeof(QHASH_ENTRY);
if (SizeDelta <= QHASH_EXTENSION_MAX) {
QhashTable->ExtensionAllocSize = sizeof(LIST_ENTRY) + SizeDelta;
} else {
QhashTable->ExtensionAllocSize = sizeof(LIST_ENTRY) + QHASH_EXTENSION_MAX;
}
QhashTable->HashRowBase = (PQHASH_ENTRY) (QhashTable + 1);
SET_QHASH_TABLE_HASH_CALC(QhashTable, NULL);
QhashTable->FreeList.Next = NULL;
break;
//
// Allocate an Output Log Partner struct.
// This is ultimately hooked to a Connection struct which provides the
// Guid and version vector.
//
case OUT_LOG_PARTNER_TYPE:
NodeSize = sizeof(OUT_LOG_PARTNER);
Node = FrsAlloc(NodeSize);
break;
//
// Allocate a WildcardEntry filter Entry struct.
//
case WILDCARD_FILTER_ENTRY_TYPE:
NodeSize = sizeof(WILDCARD_FILTER_ENTRY);
Node = FrsAlloc(NodeSize + SizeDelta);
WildcardEntry = (PWILDCARD_FILTER_ENTRY)Node;
//
// Init the unicode filename string to point to internal alloc.
//
WildcardEntry->UFileName.Buffer = WildcardEntry->FileName;
WildcardEntry->UFileName.MaximumLength = (USHORT)SizeDelta;
WildcardEntry->UFileName.Length = 0;
break;
//
// Invalid Node Type
//
default:
Node = NULL;
DPRINT1(0, "Internal error - invalid node type - %d\n", NodeType);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
//
// Set up the header for later checking in FrsFreeType
//
((PFRS_NODE_HEADER) Node)->Type = (USHORT) NodeType;
((PFRS_NODE_HEADER) Node)->Size = (USHORT) NodeSize;
//
// Tracking memory expansion
//
EnterCriticalSection(&MemLock);
TypesAllocated[NodeType]++;
TypesAllocatedCount[NodeType]++;
if (TypesAllocated[NodeType] > TypesAllocatedMax[NodeType]) {
TypesAllocatedMax[NodeType] = TypesAllocated[NodeType];
}
LeaveCriticalSection(&MemLock);
//
// Return node address to caller.
//
return Node;
}
PVOID
FrsFreeType(
IN PVOID Node
)
/*++
Routine Description:
This routine frees memory for the given node, performing any node specific
cleanup. It marks the freed memory with the hex string 0xDEADBEnn where
the low byte (nn) is set to the node type being freed to catch users of
stale pointers.
Arguments:
Node - The address of the node to free.
Return Value:
NULL. Typical call is: ptr = FrsFreeType(ptr) to catch errors.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsFreeType:"
ULONG NodeSize;
ULONG NodeType;
ULONG Marker;
PREPLICA Replica;
PREPLICA_THREAD_CTX RtCtx;
PTABLE_CTX TableCtx;
PTHREAD_CTX ThreadCtx;
ULONG i;
PVOLUME_MONITOR_ENTRY pVme;
PFILTER_TABLE_ENTRY FilterEntry;
PQHASH_TABLE QhashTable;
PLIST_ENTRY Entry;
PCXTION Cxtion;
PCONFIG_NODE ConfigNode;
PCHANGE_ORDER_ENTRY ChangeOrder;
PGHANDLE GHandle;
PHANDLE_LIST HandleList;
PWILDCARD_FILTER_ENTRY WildcardEntry;
POUT_LOG_PARTNER OutLogPartner;
if (Node == NULL) {
return NULL;
}
NodeType = (ULONG) (((PFRS_NODE_HEADER) Node)->Type);
NodeSize = (ULONG) (((PFRS_NODE_HEADER) Node)->Size);
switch (NodeType) {
//
// Free a Thread Context struct
//
case THREAD_CONTEXT_TYPE:
if (NodeSize != sizeof(THREAD_CTX)) {
DPRINT1(0, "FrsFree - Bad node size %d for THREAD_CONTEXT\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
ThreadCtx = (PTHREAD_CTX) Node;
FrsRtlDeleteList(&ThreadCtx->ThreadCtxListHead);
break;
//
// Free a Replica struct
//
case REPLICA_TYPE:
if (NodeSize != sizeof(REPLICA)) {
DPRINT1(0, "FrsFree - Bad node size %d for REPLICA\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
Replica = (PREPLICA) Node;
//
// Free the config table context.
//
DbsFreeTableCtx(&Replica->ConfigTable, NodeType);
FrsRtlDeleteList(&Replica->ReplicaCtxListHead);
//
// Empty the file and directory filter lists
//
FrsEmptyNameFilter(&Replica->FileNameFilterHead);
FrsEmptyNameFilter(&Replica->FileNameInclFilterHead);
FrsEmptyNameFilter(&Replica->DirNameFilterHead);
FrsEmptyNameFilter(&Replica->DirNameInclFilterHead);
FrsFree(Replica->FileFilterList);
FrsFree(Replica->FileInclFilterList);
FrsFree(Replica->DirFilterList);
FrsFree(Replica->DirInclFilterList);
DeleteCriticalSection(&Replica->ReplicaLock);
DeleteCriticalSection(&Replica->OutLogLock);
if (Replica->OutLogRecordLock != NULL) {
//
// Free the record lock table.
//
Replica->OutLogRecordLock = FrsFreeType(Replica->OutLogRecordLock);
}
//
// queue
//
if (Replica->Queue) {
FrsRtlDeleteQueue(Replica->Queue);
FrsFree(Replica->Queue);
}
//
// free the initsync queue.
//
if (Replica->InitSyncQueue) {
FrsRtlDeleteQueue(Replica->InitSyncQueue);
Replica->InitSyncQueue = FrsFree(Replica->InitSyncQueue);
}
//
// Names
//
FrsFree(Replica->Root);
FrsFree(Replica->Stage);
FrsFree(Replica->NewStage);
FrsFree(Replica->Volume);
FrsFreeGName(Replica->ReplicaName);
FrsFreeGName(Replica->SetName);
FrsFreeGName(Replica->MemberName);
//
// Root Guid
//
FrsFree(Replica->ReplicaRootGuid);
//
// Status of sysvol seeding
//
FrsFree(Replica->NtFrsApi_ServiceDisplay);
//
// Schedule
//
FrsFree(Replica->Schedule);
//
// VVector
//
VVFree(Replica->VVector);
//
// Cxtions
//
GTabFreeTable(Replica->Cxtions, FrsFreeType);
//
// Preinstall directory
//
FRS_CLOSE(Replica->PreInstallHandle);
//
// Free the counter data structure memory
//
if (Replica->PerfRepSetData != NULL) {
if (Replica->PerfRepSetData->oid != NULL) {
if (Replica->PerfRepSetData->oid->name != NULL) {
Replica->PerfRepSetData->oid->name =
FrsFree(Replica->PerfRepSetData->oid->name);
}
Replica->PerfRepSetData->oid =
FrsFree(Replica->PerfRepSetData->oid);
}
Replica->PerfRepSetData = FrsFree(Replica->PerfRepSetData);
}
break;
//
// Free a Replica Thread Context struct
//
case REPLICA_THREAD_TYPE:
if (NodeSize != sizeof(REPLICA_THREAD_CTX)) {
DPRINT1(0, "FrsFree - Bad node size %d for REPLICA_THREAD_CTX\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
RtCtx = (PREPLICA_THREAD_CTX) Node;
//
// Get the base of the array of TableCtx structs from the replica thread
// context struct.
//
TableCtx = RtCtx->RtCtxTables;
//
// Release the memory for each table context struct.
//
for (i=0; i<TABLE_TYPE_MAX; ++i, ++TableCtx)
DbsFreeTableCtx(TableCtx, NodeType);
break;
//
// Free a topology node
//
case CONFIG_NODE_TYPE:
if (NodeSize != sizeof(CONFIG_NODE)) {
DPRINT1(0, "FrsFree - Bad node size %d for CONFIG_NODE\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
ConfigNode = (PCONFIG_NODE) Node;
FrsFreeGName(ConfigNode->Name);
FrsFreeGName(ConfigNode->PartnerName);
FrsFree(ConfigNode->Root);
FrsFree(ConfigNode->Stage);
FrsFree(ConfigNode->Schedule);
FrsFree(ConfigNode->Dn);
FrsFree(ConfigNode->PrincName);
FrsFree(ConfigNode->PartnerDn);
FrsFree(ConfigNode->PartnerCoDn);
FrsFree(ConfigNode->SettingsDn);
FrsFree(ConfigNode->ComputerDn);
FrsFree(ConfigNode->MemberDn);
FrsFree(ConfigNode->Working);
FrsFree(ConfigNode->SetType);
FrsFree(ConfigNode->FileFilterList);
FrsFree(ConfigNode->DirFilterList);
FrsFree(ConfigNode->UsnChanged);
FrsFree(ConfigNode->DnsName);
FrsFree(ConfigNode->PartnerDnsName);
FrsFree(ConfigNode->Sid);
FrsFree(ConfigNode->PartnerSid);
FrsFree(ConfigNode->EnabledCxtion);
break;
//
// Free a connection
//
case CXTION_TYPE:
if (NodeSize != sizeof(CXTION)) {
DPRINT1(0, "FrsFree - Bad node size %d for CXTION\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
Cxtion = (PCXTION) Node;
VVFreeOutbound(Cxtion->VVector);
//
// Free the CompressionTable that was build for the outbound partner.
//
GTabFreeTable(Cxtion->CompressionTable, FrsFree);
//
// Free the OutLogPartner context.
//
FrsFreeType(Cxtion->OLCtx);
SndCsDestroyCxtion(Cxtion, CXTION_FLAGS_UNJOIN_GUID_VALID);
if (Cxtion->CommTimeoutCmd) {
//
// Try to catch the case where a Comm Time Out wait command is
// getting freed while it is still on the timeout queue. This is
// related to a bug where we get into a comm timeout loop with an
// invalid command code.
//
FRS_ASSERT(!CxtionFlagIs(Cxtion, CXTION_FLAGS_TIMEOUT_SET));
FRS_ASSERT(!CmdWaitFlagIs(Cxtion->CommTimeoutCmd, CMD_PKT_WAIT_FLAGS_ONLIST));
FrsFreeType(Cxtion->CommTimeoutCmd);
}
//
// A cxtion doesn't actually "own" the join command packet; it
// only maintains a reference to prevent extraneous join commands
// from flooding the replica's queue.
//
Cxtion->JoinCmd = NULL;
//
// VvJoin Command Server (1 per cxtion)
//
if (Cxtion->VvJoinCs) {
FrsRunDownCommandServer(Cxtion->VvJoinCs,
&Cxtion->VvJoinCs->Queue);
FrsDeleteCommandServer(Cxtion->VvJoinCs);
FrsFree(Cxtion->VvJoinCs);
}
if (!Cxtion->ChangeOrderCount) {
GTabFreeTable(Cxtion->CoeTable, NULL);
}
FrsFreeGName(Cxtion->Name);
FrsFreeGName(Cxtion->Partner);
FrsFree(Cxtion->PartnerPrincName);
FrsFree(Cxtion->Schedule);
FrsFree(Cxtion->PartSrvName);
FrsFree(Cxtion->PartnerDnsName);
FrsFree(Cxtion->PartnerSid);
//
// Delete the connection from the perfmon tables.
// Free the counter data structure memory
//
if (Cxtion->PerfRepConnData != NULL) {
if (Cxtion->PerfRepConnData->oid != NULL) {
DeletePerfmonInstance(REPLICACONN, Cxtion->PerfRepConnData);
}
Cxtion->PerfRepConnData = FrsFree(Cxtion->PerfRepConnData);
}
break;
//
// Free a guid/rpc handle
//
case GHANDLE_TYPE:
if (NodeSize != sizeof(GHANDLE)) {
DPRINT2(0, "FrsFree - Bad node size %d (%d) for GHANDLE\n",
NodeSize, sizeof(GHANDLE));
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
GHandle = (PGHANDLE)Node;
while (HandleList = GHandle->HandleList) {
GHandle->HandleList = HandleList->Next;
FrsRpcUnBindFromServer(&HandleList->RpcHandle);
FrsFree(HandleList);
}
DeleteCriticalSection(&GHandle->Lock);
break;
//
// Free a generic table
//
case GEN_TABLE_TYPE:
if (NodeSize != sizeof(GEN_TABLE)) {
DPRINT1(0, "FrsFree - Bad node size %d for GEN_TABLE\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
break;
//
// Free a generic thread context
//
case THREAD_TYPE:
if (NodeSize != sizeof(FRS_THREAD)) {
DPRINT1(0, "FrsFree - Bad node size %d for FRS_THREAD\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
break;
//
// Free a journal read buffer.
//
case JBUFFER_TYPE:
if (NodeSize != SizeOfJournalBuffer) {
DPRINT1(0, "FrsFree - Bad node size %d for JBUFFER\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
break;
//
// Free a journal volume monitor entry.
//
case VOLUME_MONITOR_ENTRY_TYPE:
if (NodeSize != sizeof(VOLUME_MONITOR_ENTRY)) {
DPRINT1(0, "FrsFree - Bad node size %d for VOLUME_MONITOR_ENTRY\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
pVme = (PVOLUME_MONITOR_ENTRY) Node;
FrsRtlDeleteList(&pVme->ReplicaListHead);
DeleteCriticalSection(&pVme->Lock);
DeleteCriticalSection(&pVme->QuadWriteLock);
FRS_CLOSE(pVme->Event);
//
// Release the change order hash table.
//
GhtDestroyTable(pVme->ChangeOrderTable);
//
// Release the Filter Hash Table.
//
GhtDestroyTable(pVme->FilterTable);
break;
//
// Free a command packet.
//
case COMMAND_PACKET_TYPE:
if (NodeSize != sizeof(COMMAND_PACKET)) {
DPRINT1(0, "FrsFree - Bad node size %d for COMMAND_PACKET\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
break;
//
// Free a generic hash table struct.
//
case GENERIC_HASH_TABLE_TYPE:
if (NodeSize != sizeof(GENERIC_HASH_TABLE)) {
DPRINT1(0, "FrsFree - Bad node size %d for GENERIC_HASH_TABLE\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
break;
//
// Free a Change Order Entry struct.
//
case CHANGE_ORDER_ENTRY_TYPE:
if (NodeSize != sizeof(CHANGE_ORDER_ENTRY)) {
DPRINT1(0, "FrsFree - Bad node size %d for CHANGE_ORDER_ENTRY\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
ChangeOrder = (PCHANGE_ORDER_ENTRY)Node;
//
// If we allocated a new name string then free it.
//
if (ChangeOrder->UFileName.Buffer != ChangeOrder->Cmd.FileName) {
FrsFree(ChangeOrder->UFileName.Buffer);
}
//
// Free the change order extenstion.
//
if (ChangeOrder->Cmd.Extension != NULL) {
FrsFree(ChangeOrder->Cmd.Extension);
}
break;
//
// Free a Filter Table Entry struct.
//
case FILTER_TABLE_ENTRY_TYPE:
if (NodeSize != sizeof(FILTER_TABLE_ENTRY)) {
DPRINT1(0, "FrsFree - Bad node size %d for FILTER_TABLE_ENTRY\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
FilterEntry = (PFILTER_TABLE_ENTRY)Node;
//
// If we allocated a new name string then free it.
//
if (FilterEntry->UFileName.Buffer != FilterEntry->DFileName) {
FrsFree(FilterEntry->UFileName.Buffer);
}
break;
//
// Free a QHASH table struct.
//
case QHASH_TABLE_TYPE:
if (NodeSize != sizeof(QHASH_TABLE)) {
DPRINT1(0, "FrsFree - Bad node size %d for QHASH_TABLE\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
QhashTable = (PQHASH_TABLE)Node;
QHashEmptyLargeKeyTable(QhashTable);
//
// Free up all the extensions we allocated.
//
while (!IsListEmpty(&QhashTable->ExtensionListHead)) {
Entry = GetListHead(&QhashTable->ExtensionListHead);
FrsRemoveEntryList(Entry);
FrsFree(Entry);
}
DeleteCriticalSection(&QhashTable->Lock);
break;
//
// Free an Output Log Partner struct.
//
case OUT_LOG_PARTNER_TYPE:
if (NodeSize != sizeof(OUT_LOG_PARTNER)) {
DPRINT1(0, "FrsFree - Bad node size %d for OUT_LOG_PARTNER\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
OutLogPartner = (POUT_LOG_PARTNER)Node;
//
// Free the Must send QHash Table.
//
OutLogPartner->MustSendTable = FrsFreeType(OutLogPartner->MustSendTable);
break;
//
// Free a Wildcard file filter Entry struct.
//
case WILDCARD_FILTER_ENTRY_TYPE:
if (NodeSize != sizeof(WILDCARD_FILTER_ENTRY)) {
DPRINT1(0, "FrsFree - Bad node size %d for WILDCARD_FILTER_ENTRY\n", NodeSize);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
WildcardEntry = (PWILDCARD_FILTER_ENTRY)Node;
//
// Free the name buffer if it no longer points at the initial alloc.
//
if (WildcardEntry->UFileName.Buffer != WildcardEntry->FileName) {
FrsFree(WildcardEntry->UFileName.Buffer);
}
break;
//
// Invalid Node Type
//
default:
Node = NULL;
DPRINT1(0, "Internal error - invalid node type - %d\n", NodeType);
XRAISEGENEXCEPTION(FrsErrorInternalError);
}
EnterCriticalSection(&MemLock);
TypesAllocated[NodeType]--;
LeaveCriticalSection(&MemLock);
//
// Fill the node with a marker then free it.
//
Marker = (ULONG) 0xDEADBE00 + NodeType;
FillMemory(Node, NodeSize, (BYTE)Marker);
return FrsFree(Node);
}
VOID
FrsFreeTypeList(
PLIST_ENTRY Head
)
/*++
Routine Description:
Free all the "typed" entries on the specified list.
Note: This routine requires that the LIST_ENTRY struct in each
list entry immediately follow the FRS_NODE_HEADER and of course that
the list entry is actually linked through that LIST_ENTRY struct.
Arguments:
Head -- ptr to the list head.
Thread Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsFreeTypeList:"
PLIST_ENTRY Entry;
PFRS_NODE_HEADER Header;
Entry = RemoveHeadList(Head);
while (Entry != Head) {
Header = (PFRS_NODE_HEADER) CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
if ((Header->Type >= NODE_TYPE_MIN) &&
(Header->Type < NODE_TYPE_MAX)) {
FrsFreeType(Header);
} else {
DPRINT(0, "Node type out of range. Not freed.\n");
}
Entry = RemoveHeadList(Head);
}
}
VOID
FrsPrintGNameForNode(
IN ULONG Severity,
IN PGNAME GName,
IN PWCHAR Indent,
IN PWCHAR Id,
IN PCHAR Debsub,
IN ULONG uLineNo
)
/*++
Routine Description:
Pretty print a gname for FrsPrintNode()
Arguments:
Severity -- Severity level for print. (See debug.c, debug.h)
GName - The address of the GName to print.
Indent - line indentation
Id - identifies the gname
Debsub -- Name of calling subroutine.
uLineno -- Line number of caller
Return Value:
none.
--*/
{
CHAR GuidStr[GUID_CHAR_LEN];
if (GName) {
if (GName->Name) {
FRS_DEB_PRINT3("%ws%ws: %ws\n", Indent, Id, GName->Name);
} else {
FRS_DEB_PRINT3("%wsNO %ws->NAME for %08x\n", Indent, Id, GName);
}
if (GName->Guid) {
GuidToStr(GName->Guid, GuidStr);
FRS_DEB_PRINT3("%ws%wsGuid: %s\n", Indent, Id, GuidStr);
} else {
FRS_DEB_PRINT3("%wsNO %ws->GUID for %08x\n", Indent, Id, GName);
}
} else {
FRS_DEB_PRINT3("%wsNO %ws for %08x\n", Indent, Id, GName);
}
}
VOID
FrsPrintTypeSchedule(
IN ULONG Severity, OPTIONAL
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs, OPTIONAL
IN PSCHEDULE Schedule,
IN PCHAR Debsub, OPTIONAL
IN ULONG uLineNo OPTIONAL
)
/*++
Routine Description:
Print a schedule.
Arguments:
Severity - for DPRINTs
Info - RPC output buffer
Tabs - prettyprint
Schedule - schedule blob
Debsub - for DPRINTs
uLineNo - for DPRINTs
Return Value:
None.
--*/
{
ULONG i;
ULONG Day;
ULONG Hour;
ULONG LineLen;
PUCHAR ScheduleData;
CHAR Line[256];
WCHAR TabW[MAX_TAB_WCHARS + 1];
if (!Schedule) {
return;
}
InfoTabs(Tabs, TabW);
for (i = 0; i < Schedule->NumberOfSchedules; ++i) {
ScheduleData = ((PUCHAR)Schedule) + Schedule->Schedules[i].Offset;
if (Schedule->Schedules[i].Type != SCHEDULE_INTERVAL) {
continue;
}
for (Day = 0; Day < 7; ++Day) {
_snprintf(Line, sizeof(Line), "%wsDay %1d: ", TabW, Day + 1);
for (Hour = 0; Hour < 24; ++Hour) {
LineLen = strlen(Line);
_snprintf(&Line[LineLen],
sizeof(Line) - LineLen,
"%1x",
*(ScheduleData + (Day * 24) + Hour) & 0x0F);
}
ITPRINT1("%s\n", Line);
}
}
}
VOID
FrsPrintTypeVv(
IN ULONG Severity, OPTIONAL
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs, OPTIONAL
IN PGEN_TABLE Vv,
IN PCHAR Debsub, OPTIONAL
IN ULONG uLineNo OPTIONAL
)
/*++
Routine Description:
Print a version vector
Arguments:
Severity - for DPRINTs
Info - RPC output buffer
Tabs - prettyprint
Vv - Version vector table
Debsub - for DPRINTs
uLineNo - for DPRINTs
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintTypeVv:"
PVOID Key;
PVV_ENTRY MasterVVEntry;
WCHAR TabW[MAX_TAB_WCHARS + 1];
CHAR Guid[GUID_CHAR_LEN + 1];
if (!Vv) {
return;
}
InfoTabs(Tabs, TabW);
Key = NULL;
while (MasterVVEntry = GTabNextDatum(Vv, &Key)) {
if (!Info) {
DebLock();
}
GuidToStr(&MasterVVEntry->GVsn.Guid, Guid);
ITPRINT3("%wsVvEntry: %s = %08x %08x\n",
TabW, Guid, PRINTQUAD(MasterVVEntry->GVsn.Vsn));
if (!Info) {
DebUnLock();
}
}
}
VOID
FrsPrintTypeOutLogAVToStr(
POUT_LOG_PARTNER OutLogPartner,
ULONG RetireCOx,
PCHAR *OutStr1,
PCHAR *OutStr2,
PCHAR *OutStr3
)
{
#undef DEBSUB
#define DEBSUB "FrsPrintTypeOutLogAVToStr:"
PCHAR Str, Str2, Str3;
ULONG j, Slotx, MaxSlotx, COx, Fill, Scan;
//
// Caller frees strings with FrsFree(Str).
//
Str = FrsAlloc(3*(ACK_VECTOR_SIZE+4));
Str2 = Str + (ACK_VECTOR_SIZE+4);
Str3 = Str2 + (ACK_VECTOR_SIZE+4);
COx = OutLogPartner->COTx;
Slotx = AVSlot(OutLogPartner->COTx, OutLogPartner);
MaxSlotx = Slotx + ACK_VECTOR_SIZE;
while (Slotx < MaxSlotx) {
j = Slotx & (ACK_VECTOR_SIZE-1);
if (ReadAVBitBySlot(Slotx, OutLogPartner) == 0) {
Str[j] = '.';
} else {
Str[j] = '1';
}
if (COx == OutLogPartner->COTx) {
Str2[j] = 'T';
} else
if (COx == OutLogPartner->COLx) {
Str2[j] = 'L';
} else {
Str2[j] = '_';
}
if (COx == RetireCOx) {
Str3[j] = '^';
} else {
Str3[j] = ' ';
}
COx += 1;
Slotx += 1;
}
Str[ACK_VECTOR_SIZE] = '\0';
Str2[ACK_VECTOR_SIZE] = '\0';
Str3[ACK_VECTOR_SIZE] = '\0';
//
// Compress out blocks of 8
//
Fill = 0;
Scan = 0;
while (Scan < ACK_VECTOR_SIZE) {
for (j=Scan; j < Scan+8; j++) {
if ((Str[j] != '.') || (Str2[j] != '_') || (Str3[j] != ' ')) {
break;
}
}
if (j == Scan+8) {
// Compress out this block
Str[Fill] = Str2[Fill] = Str3[Fill] = '-';
Fill += 1;
} else {
// Copy this block to fill point of strings.
for (j=Scan; j < Scan+8; j++) {
Str[Fill] = Str[j];
Str2[Fill] = Str2[j];
Str3[Fill] = Str3[j];
Fill += 1;
}
}
Scan += 8;
}
Str[Fill] = Str2[Fill] = Str3[Fill] = '\0';
*OutStr1 = Str;
*OutStr2 = Str2;
*OutStr3 = Str3;
return;
}
VOID
FrsPrintTypeOutLogPartner(
IN ULONG Severity, OPTIONAL
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs, OPTIONAL
IN POUT_LOG_PARTNER Olp,
IN ULONG RetireCox,
IN PCHAR Description,
IN PCHAR Debsub, OPTIONAL
IN ULONG uLineNo OPTIONAL
)
/*++
Routine Description:
Print an outlog partner
Arguments:
Severity - for DPRINTs
Info - RPC output buffer
Tabs - prettyprint
Olp - Out log partner struct
RetireCox - change order index for ack vector
Description - description of caller
Debsub - for DPRINTs
uLineNo - for DPRINTs
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintTypeOutLogPartner:"
PCHAR OutStr1, OutStr2, OutStr3;
CHAR FBuf[120];
CHAR TimeStr[TIME_STRING_LENGTH];
WCHAR TabW[MAX_TAB_WCHARS + 1];
InfoTabs(Tabs, TabW);
if (!Info) {
DebLock();
}
ITPRINT2("%wsOutLogPartner : %s\n", TabW, Description);
if (Olp->Cxtion && Olp->Cxtion->Name) {
ITPRINT2( "%wsCxtion : %ws\n",
TabW,
Olp->Cxtion->Name->Name);
if (Olp->Cxtion->Partner && Olp->Cxtion->Partner->Name) {
ITPRINT2( "%wsPartner : %ws\n",
TabW,
Olp->Cxtion->Partner->Name);
}
}
FrsFlagsToStr(Olp->Flags, OlpFlagNameTable, sizeof(FBuf), FBuf);
ITPRINT3("%wsFlags : %08x Flags [%s]\n", TabW, Olp->Flags, FBuf);
ITPRINT2("%wsState : %s\n", TabW, OLPartnerStateNames[Olp->State]);
ITPRINT2("%wsCoTx : %8d\n", TabW, Olp->COTx);
ITPRINT2("%wsCoLx : %8d\n", TabW, Olp->COLx);
ITPRINT2("%wsCOLxRestart : %8d\n", TabW, Olp->COLxRestart);
ITPRINT2("%wsCOLxVVJoinDone : %8d\n", TabW, Olp->COLxVVJoinDone);
ITPRINT2("%wsCoTxSave : %8d\n", TabW, Olp->COTxNormalModeSave);
ITPRINT2("%wsCoTslot : %8d\n", TabW, Olp->COTslot);
ITPRINT2("%wsOutstandingCos : %8d\n", TabW, Olp->OutstandingCos);
ITPRINT2("%wsOutstandingQuota: %8d\n", TabW, Olp->OutstandingQuota);
FileTimeToString((PFILETIME) &Olp->AckVersion, TimeStr);
ITPRINT2("%wsAckVersion : %s\n" , TabW, TimeStr);
if (RetireCox != -1) {
ITPRINT2("%wsRetireCox : %8d\n", TabW, RetireCox);
}
FrsPrintTypeOutLogAVToStr(Olp, RetireCox, &OutStr1, &OutStr2, &OutStr3);
//
// keep output together.
//
ITPRINT2("%wsAck: |%s|\n", TabW, OutStr1);
ITPRINT2("%wsAck: |%s|\n", TabW, OutStr2);
ITPRINT2("%wsAck: |%s|\n", TabW, OutStr3);
FrsFree(OutStr1);
if (!Info) {
DebUnLock();
}
}
VOID
FrsPrintTypeCxtion(
IN ULONG Severity, OPTIONAL
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs, OPTIONAL
IN PCXTION Cxtion,
IN PCHAR Debsub, OPTIONAL
IN ULONG uLineNo OPTIONAL
)
/*++
Routine Description:
Print a cxtion
Arguments:
Severity - for DPRINTs
Info - RPC output buffer
Tabs - prettyprint
Cxtion
Debsub - for DPRINTs
uLineNo - for DPRINTs
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintTypeCxtion:"
WCHAR TabW[MAX_TAB_WCHARS + 1];
CHAR Guid[GUID_CHAR_LEN + 1];
CHAR TimeStr[TIME_STRING_LENGTH];
CHAR FlagBuffer[120];
if (!Cxtion) {
return;
}
//
// Prettyprint indentation
//
InfoTabs(Tabs, TabW);
if (!Info) {
DebLock();
}
ITPRINT0("\n");
ITPRINTGNAME(Cxtion->Name,
"%ws Cxtion: %ws (%s)\n");
ITPRINTGNAME(Cxtion->Partner,
"%ws Partner : %ws (%s)\n");
ITPRINT2("%ws PartDnsName : %ws\n", TabW, Cxtion->PartnerDnsName);
ITPRINT2("%ws PartSrvName : %ws\n", TabW, Cxtion->PartSrvName);
ITPRINT2("%ws PartPrincName: %ws\n", TabW, Cxtion->PartnerPrincName);
ITPRINT2("%ws PartSid : %ws\n", TabW, Cxtion->PartnerSid);
ITPRINTGUID(&Cxtion->ReplicaVersionGuid, "%ws OrigGuid : %s\n");
ITPRINT2("%ws State : %d\n", TabW, Cxtion->State);
FrsFlagsToStr(Cxtion->Flags, CxtionFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
ITPRINT3("%ws Flags : %08x Flags [%s]\n", TabW, Cxtion->Flags, FlagBuffer);
ITPRINT2("%ws Inbound : %s\n", TabW, (Cxtion->Inbound) ? "TRUE" : "FALSE");
ITPRINT2("%ws JrnlCxtion : %s\n", TabW, (Cxtion->JrnlCxtion) ? "TRUE" : "FALSE");
ITPRINT2("%ws Options : 0x%08x\n", TabW, Cxtion->Options);
ITPRINT2("%ws PartnerAuth : %d\n", TabW, Cxtion->PartnerAuthLevel);
ITPRINT2("%ws TermCoSn : %d\n", TabW, Cxtion->TerminationCoSeqNum);
ITPRINT2("%ws JoinCmd : 0x%08x\n", TabW, Cxtion->JoinCmd);
ITPRINT2("%ws CoCount : %d\n", TabW, Cxtion->ChangeOrderCount);
ITPRINT2("%ws CommQueue : %d\n", TabW, Cxtion->CommQueueIndex);
ITPRINT2("%ws CoPQ : %08x\n", TabW, Cxtion->CoProcessQueue);
ITPRINT2("%ws UnjoinTrigger: %d\n", TabW, Cxtion->UnjoinTrigger);
ITPRINT2("%ws UnjoinReset : %d\n", TabW, Cxtion->UnjoinReset);
ITPRINT2("%ws Comm Packets : %d\n", TabW, Cxtion->CommPkts);
ITPRINT2("%ws PartnerMajor : %d\n", TabW, Cxtion->PartnerMajor);
ITPRINT2("%ws PartnerMinor : %d\n", TabW, Cxtion->PartnerMinor);
//
// Don't print the join guid in the logs; they may be readable
// by anyone. An Info-RPC is secure so return the join guid in
// case it is needed for debugging.
//
if (Info) {
ITPRINTGUID(&Cxtion->JoinGuid, "%ws JoinGuid : %s\n");
FileTimeToString((PFILETIME) &Cxtion->LastJoinTime, TimeStr);
ITPRINT2("%ws LastJoinTime : %s\n" , TabW, TimeStr);
}
if (Cxtion->Schedule) {
ITPRINT1("%ws Schedule\n", TabW);
FrsPrintTypeSchedule(Severity, Info, Tabs + 3, Cxtion->Schedule, Debsub, uLineNo);
}
if (Cxtion->VVector) {
ITPRINT1("%ws Version Vector\n", TabW);
}
if (!Info) {
DebUnLock();
}
if (Cxtion->VVector) {
FrsPrintTypeVv(Severity, Info, Tabs + 3, Cxtion->VVector, Debsub, uLineNo);
}
if (Cxtion->OLCtx) {
if (!Info) {
DebLock();
}
ITPRINT1("%ws OutLog Partner\n", TabW);
if (!Info) {
DebUnLock();
}
FrsPrintTypeOutLogPartner(Severity, Info, Tabs + 3, Cxtion->OLCtx,
-1, "FrsPrintType", Debsub, uLineNo);
}
}
VOID
FrsPrintTypeCxtions(
IN ULONG Severity, OPTIONAL
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs, OPTIONAL
IN PGEN_TABLE Cxtions,
IN PCHAR Debsub, OPTIONAL
IN ULONG uLineNo OPTIONAL
)
/*++
Routine Description:
Print a table of cxtions
Arguments:
Severity - for DPRINTs
Info - RPC output buffer
Tabs - prettyprint
Cxtions - Cxtion table
Debsub - for DPRINTs
uLineNo - for DPRINTs
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintTypeCxtions:"
PVOID Key;
PCXTION Cxtion;
WCHAR TabW[MAX_TAB_WCHARS + 1];
CHAR Guid[GUID_CHAR_LEN + 1];
if (!Cxtions) {
return;
}
//
// Prettyprint indentation
//
InfoTabs(Tabs, TabW);
Key = NULL;
while (Cxtion = GTabNextDatum(Cxtions, &Key)) {
FrsPrintTypeCxtion(Severity, Info, Tabs, Cxtion, Debsub, uLineNo);
}
}
VOID
FrsPrintTypeReplica(
IN ULONG Severity, OPTIONAL
IN PNTFRSAPI_INFO Info, OPTIONAL
IN DWORD Tabs, OPTIONAL
IN PREPLICA Replica,
IN PCHAR Debsub, OPTIONAL
IN ULONG uLineNo OPTIONAL
)
/*++
Routine Description:
Print a replica and its cxtions.
Arguments:
Severity -- Severity level for print. (See debug.c, debug.h)
Info - Text buffer
Tabs - Prettyprint prepense
Replica - Replica struct
Debsub -- Name of calling subroutine.
uLineno -- Line number of caller
MACRO: FRS_PRINT_TYPE
Return Value:
none.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintTypeReplica:"
CHAR Guid[GUID_CHAR_LEN + 1];
WCHAR TabW[MAX_TAB_WCHARS + 1];
CHAR FlagBuffer[120];
if (!Replica) {
return;
}
InfoTabs(Tabs, TabW);
if (!Info) {
DebLock();
}
ITPRINTGNAME(Replica->SetName, "%ws Replica: %ws (%s)\n");
ITPRINTGNAME(Replica->MemberName, "%ws Member : %ws (%s)\n");
ITPRINTGNAME(Replica->ReplicaName, "%ws Name : %ws (%s)\n");
ITPRINTGUID(Replica->ReplicaRootGuid, "%ws RootGuid : %s\n");
ITPRINTGUID(&Replica->ReplicaVersionGuid, "%ws OrigGuid : %s\n");
ITPRINT2("%ws Reference : %d\n", TabW, Replica->ReferenceCount);
FrsFlagsToStr(Replica->CnfFlags, ConfigFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
ITPRINT3("%ws CnfFlags : %08x Flags [%s]\n", TabW,
Replica->CnfFlags, FlagBuffer);
ITPRINT2("%ws SetType : %d\n", TabW, Replica->ReplicaSetType);
ITPRINT2("%ws Consistent : %d\n", TabW, Replica->Consistent);
ITPRINT2("%ws IsOpen : %d\n", TabW, Replica->IsOpen);
ITPRINT2("%ws IsJournaling : %d\n", TabW, Replica->IsJournaling);
ITPRINT2("%ws IsAccepting : %d\n", TabW, Replica->IsAccepting);
ITPRINT2("%ws IsSeeding : %d\n", TabW, Replica->IsSeeding);
ITPRINT2("%ws NeedsUpdate : %d\n", TabW, Replica->NeedsUpdate);
ITPRINT3("%ws ServiceState : %d (%s)\n", TabW,
Replica->ServiceState, RSS_NAME(Replica->ServiceState));
ITPRINT2("%ws FStatus : %s\n", TabW, ErrLabelFrs(Replica->FStatus));
ITPRINT2("%ws Number : %d\n", TabW, Replica->ReplicaNumber);
ITPRINT2("%ws Root : %ws\n", TabW, Replica->Root);
ITPRINT2("%ws Stage : %ws\n", TabW, Replica->Stage);
ITPRINT2("%ws Volume : %ws\n", TabW, Replica->Volume);
ITPRINT2("%ws FileFilter : %ws\n", TabW, Replica->FileFilterList);
ITPRINT2("%ws DirFilter : %ws\n", TabW, Replica->DirFilterList);
ITPRINT2("%ws Expires : %08x %08x\n", TabW,
PRINTQUAD(Replica->MembershipExpires));
ITPRINT2("%ws InLogRetry : %d\n", TabW, Replica->InLogRetryCount);
ITPRINT2("%ws InLogSeq : %d\n", TabW, Replica->InLogSeqNumber);
ITPRINT2("%ws InLogSeq : %d\n", TabW, Replica->InLogSeqNumber);
ITPRINT2("%ws ApiState : %d\n", TabW, Replica->NtFrsApi_ServiceState);
ITPRINT2("%ws ApiStatus : %d\n", TabW, Replica->NtFrsApi_ServiceWStatus);
ITPRINT2("%ws ApiHack : %d\n", TabW, Replica->NtFrsApi_HackCount);
ITPRINT2("%ws OutLogSeq : %d\n", TabW, Replica->OutLogSeqNumber);
ITPRINT2("%ws OutLogJLx : %d\n", TabW, Replica->OutLogJLx);
ITPRINT2("%ws OutLogJTx : %d\n", TabW, Replica->OutLogJTx);
ITPRINT2("%ws OutLogMax : %d\n", TabW, Replica->OutLogCOMax);
ITPRINT2("%ws OutLogState : %d\n", TabW, Replica->OutLogWorkState);
ITPRINT2("%ws OutLogVV's : %d\n", TabW, Replica->OutLogCountVVJoins);
ITPRINT2("%ws OutLogClean : %d\n", TabW, Replica->OutLogDoCleanup);
ITPRINT2("%ws PreinstallFID : %08x %08x\n", TabW,
PRINTQUAD(Replica->PreInstallFid));
ITPRINT2("%ws InLogCommit : %08x %08x\n", TabW,
PRINTQUAD(Replica->InlogCommitUsn));
ITPRINT2("%ws JrnlStart : %08x %08x\n", TabW,
PRINTQUAD(Replica->JrnlRecoveryStart));
ITPRINT2("%ws JrnlEnd : %08x %08x\n", TabW,
PRINTQUAD(Replica->JrnlRecoveryEnd));
ITPRINT2("%ws LastUsn : %08x %08x\n", TabW,
PRINTQUAD(Replica->LastUsnRecordProcessed));
if (Replica->Schedule) {
ITPRINT1("%ws Schedule\n", TabW);
FrsPrintTypeSchedule(Severity, Info, Tabs + 3, Replica->Schedule, Debsub, uLineNo);
}
if (Replica->VVector) {
ITPRINT1("%ws Version Vector\n", TabW);
}
if (!Info) {
DebUnLock();
}
FrsPrintTypeVv(Severity, Info, Tabs + 3, Replica->VVector, Debsub, uLineNo);
FrsPrintTypeCxtions(Severity, Info, Tabs + 1, Replica->Cxtions, Debsub, uLineNo);
}
VOID
FrsPrintType(
IN ULONG Severity,
IN PVOID Node,
IN PCHAR Debsub,
IN ULONG uLineNo
)
/*++
Routine Description:
This routine prints out the contents of a given node,
performing any node specific interpretation.
Arguments:
Severity -- Severity level for print. (See debug.c, debug.h)
Node - The address of the node to print.
Debsub -- Name of calling subroutine.
uLineno -- Line number of caller
MACRO: FRS_PRINT_TYPE
Return Value:
none.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintType:"
ULONG NodeSize;
ULONG NodeType;
ULONG Marker;
PREPLICA Replica;
PREPLICA_THREAD_CTX RtCtx;
PTABLE_CTX TableCtx;
PTHREAD_CTX ThreadCtx;
ULONG i;
PVOLUME_MONITOR_ENTRY pVme;
PFILTER_TABLE_ENTRY FilterEntry;
PQHASH_TABLE QhashTable;
PLIST_ENTRY Entry;
PCXTION Cxtion;
SYSTEMTIME ST;
PWILDCARD_FILTER_ENTRY WildcardEntry;
POUT_LOG_PARTNER Olp;
PCONFIG_NODE ConfigNode;
PULONG pULong;
PCHANGE_ORDER_ENTRY CoEntry;
PCHANGE_ORDER_COMMAND CoCmd;
CHAR GuidStr[GUID_CHAR_LEN];
CHAR TimeStr[TIME_STRING_LENGTH];
CHAR FlagBuffer[160];
if (!DoDebug(Severity, Debsub)) {
return;
}
//
// Get debug lock so our output stays in one piece.
//
DebLock();
if (Node != NULL) {
NodeType = (ULONG) (((PFRS_NODE_HEADER) Node)->Type);
NodeSize = (ULONG) (((PFRS_NODE_HEADER) Node)->Size);
FRS_DEB_PRINT("Display for Node: ...%s... === === === ===\n",
NodeTypeNames[NodeType]);
} else {
FRS_DEB_PRINT("Display for Node: ...<null>... === === === ===\n\n",
NULL);
DebUnLock();
return;
}
switch (NodeType) {
//
// Print a Thread Context struct
//
case THREAD_CONTEXT_TYPE:
if (NodeSize != sizeof(THREAD_CTX)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for THREAD_CONTEXT\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
ThreadCtx = (PTHREAD_CTX) Node;
break;
//
// Print a Replica struct
//
case REPLICA_TYPE:
if (NodeSize != sizeof(REPLICA)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for REPLICA\n", NodeSize);
break;
}
DebUnLock();
FrsPrintTypeReplica(Severity, NULL, 0, (PREPLICA) Node, Debsub, uLineNo);
DebLock();
break;
//
// Print a Replica Thread Context struct
//
case REPLICA_THREAD_TYPE:
if (NodeSize != sizeof(REPLICA_THREAD_CTX)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for REPLICA_THREAD_CTX\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
RtCtx = (PREPLICA_THREAD_CTX) Node;
//
// Get the base of the array of TableCtx structs from the replica thread
// context struct.
//
TableCtx = RtCtx->RtCtxTables;
//
// Release the memory for each table context struct.
//
//for (i=0; i<TABLE_TYPE_MAX; ++i, ++TableCtx) {
//}
break;
//
// Print a topology node
//
case CONFIG_NODE_TYPE:
if (NodeSize != sizeof(CONFIG_NODE)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for CONFIG_NODE\n",
NodeSize);
break;
}
ConfigNode = Node;
FRS_DEB_PRINT("CONFIG NODE Address %08x\n", ConfigNode);
FrsPrintGNameForNode(Severity, ConfigNode->Name, L"\t", L"Node",
Debsub, uLineNo);
FrsPrintGNameForNode(Severity, ConfigNode->PartnerName, L"\t", L"Partner",
Debsub, uLineNo);
FRS_DEB_PRINT("\tDsObjectType %ws\n", DsConfigTypeName[ConfigNode->DsObjectType]);
FRS_DEB_PRINT("\tConsistent %s\n", (ConfigNode->Consistent) ? "TRUE" : "FALSE");
FRS_DEB_PRINT("\tInbound %s\n", (ConfigNode->Inbound) ? "TRUE" : "FALSE");
FRS_DEB_PRINT("\tThisComputer %s\n", (ConfigNode->ThisComputer) ? "TRUE" : "FALSE");
FRS_DEB_PRINT("\tUsnChanged %ws\n", ConfigNode->UsnChanged);
FRS_DEB_PRINT("\tDn %ws\n", ConfigNode->Dn);
FRS_DEB_PRINT("\tPrincName %ws\n", ConfigNode->PrincName);
FRS_DEB_PRINT("\tDnsName %ws\n", ConfigNode->DnsName);
FRS_DEB_PRINT("\tPartnerDnsName %ws\n", ConfigNode->PartnerDnsName);
FRS_DEB_PRINT("\tSid %ws\n", ConfigNode->Sid);
FRS_DEB_PRINT("\tPartnerSid %ws\n", ConfigNode->PartnerSid);
FRS_DEB_PRINT("\tPartnerDn %ws\n", ConfigNode->PartnerDn);
FRS_DEB_PRINT("\tPartnerCoDn %ws\n", ConfigNode->PartnerCoDn);
FRS_DEB_PRINT("\tSettingsDn %ws\n", ConfigNode->SettingsDn);
FRS_DEB_PRINT("\tComputerDn %ws\n", ConfigNode->ComputerDn);
FRS_DEB_PRINT("\tMemberDn %ws\n", ConfigNode->MemberDn);
FRS_DEB_PRINT("\tSetType %ws\n", ConfigNode->SetType);
FRS_DEB_PRINT("\tRoot %ws\n", ConfigNode->Root);
FRS_DEB_PRINT("\tStage %ws\n", ConfigNode->Stage);
FRS_DEB_PRINT("\tWorking %ws\n", ConfigNode->Working);
FRS_DEB_PRINT("\tFileFilterList %ws\n", ConfigNode->FileFilterList);
FRS_DEB_PRINT("\tDirFilterList %ws\n", ConfigNode->DirFilterList);
FRS_DEB_PRINT("\tSchedule %08x\n",ConfigNode->Schedule);
FRS_DEB_PRINT("\tScheduleLength %d\n", ConfigNode->ScheduleLength);
FRS_DEB_PRINT("\tUsnChanged %ws\n", ConfigNode->UsnChanged);
FRS_DEB_PRINT("\tSameSite %s\n", (ConfigNode->SameSite) ? "TRUE" : "FALSE");
FRS_DEB_PRINT("\tEnabledCxtion %ws\n", ConfigNode->EnabledCxtion);
FRS_DEB_PRINT("\tVerifiedOverlap %s\n", (ConfigNode->VerifiedOverlap) ? "TRUE" : "FALSE");
break;
//
// Print a connection
//
case CXTION_TYPE:
if (NodeSize != sizeof(CXTION)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for CXTION\n",
NodeSize);
break;
}
DebUnLock();
FrsPrintTypeCxtion(Severity, NULL, 0, (PCXTION)Node, Debsub, uLineNo);
DebLock();
break;
//
// Print a guid/rpc handle
//
case GHANDLE_TYPE:
if (NodeSize != sizeof(GHANDLE)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for GHANDLE\n",
NodeSize);
break;
}
GuidToStr(&(((PGHANDLE)Node)->Guid), GuidStr);
FRS_DEB_PRINT2("Address %08x, Cxtion Guid : %s\n", Node, GuidStr);
break;
//
// Print a generic table
//
case GEN_TABLE_TYPE:
if (NodeSize != sizeof(GEN_TABLE)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for GEN_TABLE\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
break;
//
// Print a generic thread context
//
case THREAD_TYPE:
if (NodeSize != sizeof(FRS_THREAD)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for FRS_THREAD\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
break;
//
// Print a journal read buffer.
//
case JBUFFER_TYPE:
if (NodeSize != SizeOfJournalBuffer) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for JBUFFER\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
break;
//
// Print a journal volume monitor entry.
//
case VOLUME_MONITOR_ENTRY_TYPE:
if (NodeSize != sizeof(VOLUME_MONITOR_ENTRY)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for VOLUME_MONITOR_ENTRY\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
pVme = (PVOLUME_MONITOR_ENTRY) Node;
break;
//
// Print a command packet.
//
case COMMAND_PACKET_TYPE:
if (NodeSize != sizeof(COMMAND_PACKET)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for COMMAND_PACKET\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
break;
//
// Print a generic hash table struct.
//
case GENERIC_HASH_TABLE_TYPE:
if (NodeSize != sizeof(GENERIC_HASH_TABLE)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for GENERIC_HASH_TABLE\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
break;
//
// Print a Change Order Entry struct.
//
case CHANGE_ORDER_ENTRY_TYPE:
if (NodeSize != sizeof(CHANGE_ORDER_ENTRY)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for CHANGE_ORDER_ENTRY\n",
NodeSize);
break;
}
CoEntry = (PCHANGE_ORDER_ENTRY)Node;
CoCmd = &CoEntry->Cmd;
GuidToStr(&CoCmd->ChangeOrderGuid, GuidStr);
FRS_DEB_PRINT3("Address %08x ***%s CO*** - %s\n",
CoEntry,
(CO_FLAG_ON(CoEntry, CO_FLAG_LOCALCO)) ? "LOCAL" : "REMOTE",
GuidStr);
FRS_DEB_PRINT3("Node Addr: %08x, HashValue: %08x RC: %d\n",
CoEntry,
CoEntry->HashEntryHeader.HashValue,
CoEntry->HashEntryHeader.ReferenceCount);
FRS_DEB_PRINT2("List Entry - %08x, %08x\n",
CoEntry->HashEntryHeader.ListEntry.Flink,
CoEntry->HashEntryHeader.ListEntry.Blink);
FRS_DEB_PRINT2("FileRef: %08lx %08lx, ParentRef: %08lx %08lx\n",
PRINTQUAD(CoEntry->FileReferenceNumber),
PRINTQUAD(CoEntry->ParentFileReferenceNumber));
FRS_DEB_PRINT("\n", NULL);
FRS_DEB_PRINT("STATE: %s\n", PRINT_CO_STATE(CoEntry));
FrsFlagsToStr(CoEntry->EntryFlags, CoeFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
FRS_DEB_PRINT2("EntryFlags: %08x, Flags [%s]\n", CoEntry->EntryFlags, FlagBuffer);
FrsFlagsToStr(CoEntry->IssueCleanup, IscuFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
FRS_DEB_PRINT2("ISCU Flags: %08x, Flags [%s]\n", CoEntry->IssueCleanup, FlagBuffer);
FRS_DEB_PRINT("\n", NULL);
GuidToStr(&CoCmd->OriginatorGuid, GuidStr);
FRS_DEB_PRINT("OrigGuid : %s\n", GuidStr);
GuidToStr(&CoCmd->FileGuid, GuidStr);
FRS_DEB_PRINT("FileGuid : %s\n", GuidStr);
GuidToStr(&CoCmd->OldParentGuid, GuidStr);
FRS_DEB_PRINT("OParGuid : %s\n",GuidStr);
GuidToStr(&CoCmd->NewParentGuid, GuidStr);
FRS_DEB_PRINT("NParGuid : %s\n", GuidStr);
GuidToStr(&CoCmd->CxtionGuid, GuidStr);
FRS_DEB_PRINT2("CxtionGuid: %s (%08x)\n", GuidStr, CoEntry->Cxtion);
FileTimeToString((PFILETIME) &CoCmd->AckVersion, TimeStr);
FRS_DEB_PRINT("AckVersion: %s\n", TimeStr);
FRS_DEB_PRINT("\n", NULL);
FRS_DEB_PRINT2("FileName: %ws, Length: %d\n", CoEntry->UFileName.Buffer,
CoCmd->FileNameLength);
FrsFlagsToStr(CoCmd->ContentCmd, UsnReasonNameTable, sizeof(FlagBuffer), FlagBuffer);
FRS_DEB_PRINT2("ContentCmd: %08x, Flags [%s]\n", CoCmd->ContentCmd, FlagBuffer);
FRS_DEB_PRINT("\n", NULL);
FrsFlagsToStr(CoCmd->Flags, CoFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
FRS_DEB_PRINT2("CoFlags: %08x, Flags [%s]\n", CoCmd->Flags, FlagBuffer);
FrsFlagsToStr(CoCmd->IFlags, CoIFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
DebPrintNoLock(Severity, TRUE,
"IFlags: %08x, Flags [%s] TimeToRun: %7d, EntryCreateTime: %7d\n",
Debsub, uLineNo,
CoCmd->IFlags, FlagBuffer,
CoEntry->TimeToRun,
CoEntry->EntryCreateTime);
DebPrintNoLock(Severity, TRUE,
"LocationCmd: %s (%d), CO STATE: %s File/Dir: %d\n",
Debsub, uLineNo,
CoLocationNames[GET_CO_LOCATION_CMD(CoEntry->Cmd, Command)],
GET_CO_LOCATION_CMD(CoEntry->Cmd, Command),
PRINT_CO_STATE(CoEntry),
GET_CO_LOCATION_CMD(CoEntry->Cmd, DirOrFile));
FRS_DEB_PRINT("\n", NULL);
FRS_DEB_PRINT2("OriginalParentFid: %08lx %08lx, NewParentFid: %08lx %08lx\n",
PRINTQUAD(CoEntry->OriginalParentFid),
PRINTQUAD(CoEntry->NewParentFid));
DebPrintNoLock(Severity, TRUE,
"OriginalReplica: %ws (%d), NewReplica: %ws (%d)\n",
Debsub, uLineNo,
CoEntry->OriginalReplica->ReplicaName->Name,
CoCmd->OriginalReplicaNum,
CoEntry->NewReplica->ReplicaName->Name,
CoCmd->NewReplicaNum);
if (CoCmd->Extension != NULL) {
pULong = (PULONG) CoCmd->Extension;
DebPrintNoLock(Severity, TRUE,
"CO Extension: (%08x) %08x %08x %08x %08x %08x %08x %08x %08x\n",
Debsub, uLineNo, pULong,
*(pULong+0), *(pULong+1), *(pULong+2), *(pULong+3),
*(pULong+4), *(pULong+5), *(pULong+6), *(pULong+7));
} else {
FRS_DEB_PRINT("CO Extension: Null\n", NULL);
}
FRS_DEB_PRINT("\n", NULL);
FRS_DEB_PRINT3("File Attributes: %08x, SeqNum: %08x, FileSize: %08x %08x\n",
CoCmd->FileAttributes,
CoCmd->SequenceNumber,
PRINTQUAD(CoCmd->FileSize));
FRS_DEB_PRINT("FrsVsn: %08x %08x\n", PRINTQUAD(CoCmd->FrsVsn));
FRS_DEB_PRINT3("Usn: %08x %08x CoFileUsn: %08x %08x JrnlFirstUsn: %08x %08x\n",
PRINTQUAD(CoCmd->JrnlUsn),
PRINTQUAD(CoCmd->FileUsn),
PRINTQUAD(CoCmd->JrnlFirstUsn));
FRS_DEB_PRINT("Version: %08x ", CoCmd->FileVersionNumber);
FileTimeToString((PFILETIME) &CoCmd->EventTime.QuadPart, TimeStr);
DebPrintNoLock(Severity, FALSE, "EventTime: %s\n", Debsub, uLineNo, TimeStr);
break;
//
// Print a Filter Table Entry struct.
//
case FILTER_TABLE_ENTRY_TYPE:
if (NodeSize != sizeof(FILTER_TABLE_ENTRY)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for FILTER_TABLE_ENTRY\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Address %08x\n", Node);
FilterEntry = (PFILTER_TABLE_ENTRY)Node;
break;
//
// Print a QHASH table struct.
//
case QHASH_TABLE_TYPE:
QhashTable = (PQHASH_TABLE)Node;
if (NodeSize != QhashTable->BaseAllocSize) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for QHASH_TABLE\n",
NodeSize);
break;
}
FRS_DEB_PRINT("Table Address : %08x\n", QhashTable);
FRS_DEB_PRINT("BaseAllocSize : %8d\n", QhashTable->BaseAllocSize);
FRS_DEB_PRINT("ExtensionAllocSize : %8d\n", QhashTable->ExtensionAllocSize);
FRS_DEB_PRINT("ExtensionListHead : %08x\n", QhashTable->ExtensionListHead);
FRS_DEB_PRINT("FreeList : %08x\n", QhashTable->FreeList);
FRS_DEB_PRINT("Lock : %08x\n", QhashTable->Lock);
FRS_DEB_PRINT("HeapHandle : %08x\n", QhashTable->HeapHandle);
FRS_DEB_PRINT("HashCalc : %08x\n", QhashTable->HashCalc);
FRS_DEB_PRINT("NumberEntries : %8d\n", QhashTable->NumberEntries);
FRS_DEB_PRINT("HashRowBase : %08x\n", QhashTable->HashRowBase);
break;
//
// Print an Output Log Partner struct.
//
case OUT_LOG_PARTNER_TYPE:
if (NodeSize != sizeof(OUT_LOG_PARTNER)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for OUT_LOG_PARTNER\n",
NodeSize);
break;
}
DebUnLock();
FrsPrintTypeOutLogPartner(Severity, NULL, 0, (POUT_LOG_PARTNER)Node,
-1, "FrsPrintType", Debsub, uLineNo);
DebLock();
break;
//
// Print a Wildcard file filter Entry struct.
//
case WILDCARD_FILTER_ENTRY_TYPE:
if (NodeSize != sizeof(WILDCARD_FILTER_ENTRY)) {
FRS_DEB_PRINT("FrsPrintType - Bad node size %d for WILDCARD_FILTER_ENTRY\n",
NodeSize);
break;
}
FRS_DEB_PRINT( "Address %08x\n", Node);
WildcardEntry = (PWILDCARD_FILTER_ENTRY)Node;
DebPrintNoLock(Severity, TRUE,
"Flags: %08x, Wildcard FileName: %ws, Length: %d\n",
Debsub, uLineNo,
WildcardEntry->Flags,
WildcardEntry->UFileName.Buffer,
(ULONG)WildcardEntry->UFileName.Length);
break;
//
// Invalid Node Type
//
default:
Node = NULL;
DebPrintNoLock(0, TRUE,
"Internal error - invalid node type - %d\n",
Debsub, uLineNo, NodeType);
}
FRS_DEB_PRINT("-----------------------\n", NULL);
DebUnLock();
}
VOID
FrsAllocUnicodeString(
PUNICODE_STRING Ustr,
PWCHAR InternalBuffer,
PWCHAR Wstr,
USHORT WstrLength
)
/*++
Routine Description:
Initialize a unicode string with the contents of Wstr if the two are
not already the same. If the length of the new string is greater than
the buffer space currently allocated in Ustr then allocate a new
buffer for Ustr. In some structures the initial Ustr buffer allocation
is allocated as part of the initial structure allocation. The address
of this internal buffer is passed so it can be compared with the address
in Ustr->Buffer. If they match then no free memory call is made on
the Ustr->Buffer address.
Arguments:
Ustr -- The UNICODE_STRING to init.
InternalBuffer -- A ptr to the internal buffer address that was preallocated
with the containing struct. If there was no internal
buffer pass NULL.
Wstr -- The new WCHAR string.
WstrLength -- The length of the new string in bytes not including the
trailing UNICODE_NULL.
Return Value:
None.
--*/
{
#undef DEBSUB
#define DEBSUB "FrsAllocUnicodeString:"
//
// See if the name part changed and if so save it.
//
if ((Ustr->Length != WstrLength) ||
(wcsncmp(Ustr->Buffer, Wstr, Ustr->Length/sizeof(WCHAR)) != 0)) {
//
// If string to big (including space for a NULL), alloc new buffer.
//
if (WstrLength >= Ustr->MaximumLength) {
//
// Alloc room for new one, freeing the old one if not internal alloc.
//
if ((Ustr->Buffer != InternalBuffer) && (Ustr->Buffer != NULL)) {
FrsFree(Ustr->Buffer);
}
Ustr->MaximumLength = WstrLength+2;
Ustr->Buffer = FrsAlloc(WstrLength+2);
}
//
// Copy in new name. Length does not include the trailing NULL at end.
//
CopyMemory(Ustr->Buffer, Wstr, WstrLength);
Ustr->Buffer[WstrLength/2] = UNICODE_NULL;
Ustr->Length = WstrLength;
}
}
#define CO_TRACE_FORMAT ":: CoG %08x, CxtG %08x, FV %5d, FID %08x %08x, FN: %-15ws, [%s]\n"
#define REPLICA_TRACE_FORMAT ":S:Adr %08x, Cmd %04x, Flg %04x, %ws (%d), %s, Err %d [%s]\n"
#define REPLICA_TRACE_FORMAT2 ":S:Adr %08x, %ws (%d), %s, [%s]\n"
#define CXTION_TRACE_FORMAT ":X: %08x, Nam %ws, Sta %s%s, %ws (%d), %s, Err %d [%s]\n"
VOID
ChgOrdTraceCoe(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCHANGE_ORDER_ENTRY Coe,
IN PCHAR Text
)
/*++
Routine Description:
Print a change order trace record using the change order entry and the
Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ChgOrdTraceCoe:"
ULONGLONG FileRef;
FileRef = (Coe != NULL) ? Coe->FileReferenceNumber : QUADZERO;
DebPrint(Severity,
(PUCHAR) CO_TRACE_FORMAT,
Debsub,
uLineNo,
(Coe != NULL) ? Coe->Cmd.ChangeOrderGuid.Data1 : 0,
(Coe != NULL) ? Coe->Cmd.CxtionGuid.Data1 : 0,
(Coe != NULL) ? Coe->Cmd.FileVersionNumber : 0,
PRINTQUAD(FileRef),
(Coe != NULL) ? Coe->Cmd.FileName : L"<Null Coe>",
Text);
}
VOID
ChgOrdTraceCoeW(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCHANGE_ORDER_ENTRY Coe,
IN PCHAR Text,
IN ULONG WStatus
)
/*++
Routine Description:
Print a change order trace record using the change order entry and the
Text string and Win32 status.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ChgOrdTraceCoeW:"
CHAR Tstr[256];
_snprintf(Tstr, sizeof(Tstr), "%s (%s)", Text, ErrLabelW32(WStatus));
Tstr[sizeof(Tstr)-1] = '\0';
ChgOrdTraceCoe(Severity, Debsub, uLineNo, Coe, Tstr);
}
VOID
ChgOrdTraceCoeF(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCHANGE_ORDER_ENTRY Coe,
IN PCHAR Text,
IN ULONG FStatus
)
/*++
Routine Description:
Print a change order trace record using the change order entry and the
Text string and Frs Error status.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ChgOrdTraceCoeF:"
CHAR Tstr[128];
_snprintf(Tstr, sizeof(Tstr), "%s (%s)", Text, ErrLabelFrs(FStatus));
Tstr[sizeof(Tstr)-1] = '\0';
ChgOrdTraceCoe(Severity, Debsub, uLineNo, Coe, Tstr);
}
VOID
ChgOrdTraceCoeX(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCHANGE_ORDER_ENTRY Coe,
IN PCHAR Text,
IN ULONG Data
)
/*++
Routine Description:
Print a change order trace record using the change order entry and the
Text string and Win32 status.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ChgOrdTraceCoeX:"
CHAR Tstr[256];
_snprintf(Tstr, sizeof(Tstr), "%s (%08x)", Text, Data);
Tstr[sizeof(Tstr)-1] = '\0';
ChgOrdTraceCoe(Severity, Debsub, uLineNo, Coe, Tstr);
}
VOID
ChgOrdTraceCoc(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCHANGE_ORDER_COMMAND Coc,
IN PCHAR Text
)
/*++
Routine Description:
Print a change order trace record using the change order command and the
Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ChgOrdTraceCoc:"
ULONGLONG FileRef = QUADZERO;
DebPrint(Severity,
(PUCHAR) CO_TRACE_FORMAT,
Debsub,
uLineNo,
(Coc != NULL) ? Coc->ChangeOrderGuid.Data1 : 0,
(Coc != NULL) ? Coc->CxtionGuid.Data1 : 0,
(Coc != NULL) ? Coc->FileVersionNumber : 0,
PRINTQUAD(FileRef),
(Coc != NULL) ? Coc->FileName : L"<Null Coc>",
Text);
}
VOID
ChgOrdTraceCocW(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCHANGE_ORDER_COMMAND Coc,
IN PCHAR Text,
IN ULONG WStatus
)
/*++
Routine Description:
Print a change order trace record using the change order command and the
Text string and Win32 status.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ChgOrdTraceCocW:"
CHAR Tstr[256];
_snprintf(Tstr, sizeof(Tstr), "%s (%s)", Text, ErrLabelW32(WStatus));
Tstr[sizeof(Tstr)-1] = '\0';
ChgOrdTraceCoc(Severity, Debsub, uLineNo, Coc, Tstr);
}
VOID
ReplicaStateTrace(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCOMMAND_PACKET Cmd,
IN PREPLICA Replica,
IN ULONG Status,
IN PCHAR Text
)
/*++
Routine Description:
Print a replica state trace record using the command packet and the
status and Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ReplicaStateTrace:"
PWSTR ReplicaName;
if ((Replica != NULL) &&
(Replica->ReplicaName != NULL) &&
(Replica->ReplicaName->Name != NULL)) {
ReplicaName = Replica->ReplicaName->Name;
} else {
ReplicaName = L"<null>";
}
DebPrint(Severity,
(PUCHAR) REPLICA_TRACE_FORMAT,
Debsub,
uLineNo,
PtrToUlong(Cmd),
(Cmd != NULL) ? Cmd->Command : 0xFFFF,
(Cmd != NULL) ? Cmd->Flags : 0xFFFF,
ReplicaName,
ReplicaAddrToId(Replica),
(Replica != NULL) ? RSS_NAME(Replica->ServiceState) : "<null>",
Status,
Text);
}
VOID
ReplicaStateTrace2(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PREPLICA Replica,
IN PCHAR Text
)
/*++
Routine Description:
Print a cxtion table access trace record for the replica using the
Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ReplicaStateTrace2:"
PWSTR ReplicaName;
if ((Replica != NULL) &&
(Replica->ReplicaName != NULL) &&
(Replica->ReplicaName->Name != NULL)) {
ReplicaName = Replica->ReplicaName->Name;
} else {
ReplicaName = L"<null>";
}
DebPrint(Severity,
(PUCHAR) REPLICA_TRACE_FORMAT2,
Debsub,
uLineNo,
PtrToUlong(Replica),
ReplicaName,
ReplicaAddrToId(Replica),
(Replica != NULL) ? RSS_NAME(Replica->ServiceState) : "<null>",
Text);
}
VOID
CxtionStateTrace(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCXTION Cxtion,
IN PREPLICA Replica,
IN ULONG Status,
IN PCHAR Text
)
/*++
Routine Description:
Print a connection state trace record using the cxtion and the
status and Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "CxtionStateTrace:"
PWSTR ReplicaName = L"<null>";
PWSTR CxtName = L"<null>";
PCHAR CxtState = "<null>";
ULONG Ctxg = 0, Flags = 0;
PCHAR CxtDirection = "?-";
CHAR FBuf[120];
if ((Replica != NULL) &&
(Replica->ReplicaName != NULL) &&
(Replica->ReplicaName->Name != NULL)) {
ReplicaName = Replica->ReplicaName->Name;
}
if (Cxtion != NULL) {
Flags = Cxtion->Flags;
CxtState = CxtionStateNames[GetCxtionState(Cxtion)];
CxtDirection = Cxtion->Inbound ? "I-" : "O-";
if (Cxtion->Name != NULL) {
if (Cxtion->Name->Name != NULL) {
CxtName = Cxtion->Name->Name;
}
if (Cxtion->Name->Guid != NULL) {
Ctxg = Cxtion->Name->Guid->Data1;
}
}
}
DebPrint(Severity,
(PUCHAR) CXTION_TRACE_FORMAT,
Debsub,
uLineNo,
Ctxg,
CxtName,
CxtDirection,
CxtState,
ReplicaName,
ReplicaAddrToId(Replica),
(Replica != NULL) ? RSS_NAME(Replica->ServiceState) : "<null>",
Status,
Text);
FrsFlagsToStr(Flags, CxtionFlagNameTable, sizeof(FBuf), FBuf);
DebPrint(Severity, (PUCHAR) ":X: %08x, Flags [%s]\n", Debsub, uLineNo, Ctxg, FBuf);
}
VOID
CmdPktTrace(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCOMMAND_PACKET Cmd,
IN PCHAR Text
)
/*++
Routine Description:
Print a command packet trace record using the Cmd and Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "CmdPktTrace:"
ULONG CmdCode = 0, Flags = 0, Ctrl = 0, Tout = 0, TQ = 0, Err = 0;
if (Cmd != NULL) {
CmdCode = (ULONG) Cmd->Command;
Flags = (ULONG) Cmd->Flags;
Ctrl = (ULONG) Cmd->Control;
Tout = Cmd->Timeout;
TQ = PtrToUlong(Cmd->TargetQueue);
Err = Cmd->ErrorStatus;
}
DebPrint(Severity,
(PUCHAR) ":Cd: %08x, Cmd %04x, Flg %04x, Ctrl %04x, Tout %08x, TQ %08x, Err %d [%s]\n",
Debsub,
uLineNo,
PtrToUlong(Cmd), CmdCode, Flags, Ctrl, Tout, TQ, Err, Text);
}
VOID
SendCmdTrace(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCOMMAND_PACKET Cmd,
IN ULONG WStatus,
IN PCHAR Text
)
/*++
Routine Description:
Print a send command packet trace record using the Cmd and the
status and Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "SendCmdTrace:"
PCXTION Cxtion;
PWSTR CxtTo = L"<null>";
ULONG Ctxg = 0, PktLen = 0;
if (Cmd != NULL) {
Cxtion = SRCxtion(Cmd);
if ((Cxtion != NULL) &&
(Cxtion->Name != NULL) &&
(Cxtion->Name->Guid != NULL)) {
Ctxg = Cxtion->Name->Guid->Data1;
}
if (SRCommPkt(Cmd) != NULL) {
PktLen = SRCommPkt(Cmd)->PktLen;
}
if ((SRTo(Cmd) != NULL) && (SRTo(Cmd)->Name != NULL)) {
CxtTo = SRTo(Cmd)->Name;
}
}
DebPrint(Severity,
(PUCHAR) ":SR: Cmd %08x, CxtG %08x, WS %s, To %ws Len: (%3d) [%s]\n",
Debsub,
uLineNo,
PtrToUlong(Cmd), Ctxg, ErrLabelW32(WStatus), CxtTo, PktLen, Text);
}
VOID
ReceiveCmdTrace(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCOMMAND_PACKET Cmd,
IN PCXTION Cxtion,
IN ULONG WStatus,
IN PCHAR Text
)
/*++
Routine Description:
Print a rcv command packet trace record using the Cmd and the
status and Text string.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "ReceiveCmdTrace:"
PWSTR CxtFrom = L"<null>";
ULONG Ctxg = 0, PktLen = 0, CmdCode = 0;
if (Cmd != NULL) {
CmdCode = (ULONG) Cmd->Command;
if (Cxtion != NULL) {
CxtFrom = Cxtion->PartnerDnsName;
if ((Cxtion->Name != NULL) && (Cxtion->Name->Guid != NULL)) {
Ctxg = Cxtion->Name->Guid->Data1;
}
}
}
DebPrint(Severity,
(PUCHAR) ":SR: Cmd %08x, CxtG %08x, WS %s, From %ws CCod: (%03x) [%s]\n",
Debsub,
uLineNo,
PtrToUlong(Cmd), Ctxg, ErrLabelW32(WStatus), CxtFrom, CmdCode, Text);
}
VOID
StageFileTrace(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN GUID *CoGuid,
IN PWCHAR FileName,
IN PULONGLONG pFileSize,
IN PULONG pFlags,
IN PCHAR Text
)
/*++
Routine Description:
Print a stage file acquire/release trace record.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "StageFileTrace:"
ULONGLONG FileSize = QUADZERO;
ULONG Flags = 0, CoGuidData = 0;
CHAR FBuf[120];
Flags = (pFlags != NULL) ? *pFlags : 0;
CoGuidData = (CoGuid != NULL) ? CoGuid->Data1 : 0;
pFileSize = (pFileSize == NULL) ? &FileSize : pFileSize;
DebPrint(Severity,
(PUCHAR) ":: CoG %08x, Flgs %08x, %5d, Siz %08x %08x, FN: %-15ws, [%s]\n",
Debsub,
uLineNo,
CoGuidData,
Flags,
0,
PRINTQUAD(*pFileSize),
FileName,
Text);
FrsFlagsToStr(Flags, StageFlagNameTable, sizeof(FBuf), FBuf);
DebPrint(Severity,
(PUCHAR) ":: CoG %08x, Flags [%s]\n",
Debsub,
uLineNo,
CoGuidData,
FBuf);
}
VOID
SetCxtionStateTrace(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCXTION Cxtion,
IN ULONG NewState
)
/*++
Routine Description:
Print a change to cxtion state trace record using the Cxtion and the NewState.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "SetCxtionStateTrace:"
PWSTR CxtName = L"<null>";
PWSTR PartnerName = L"<null>";
PWSTR PartSrvName = L"<null>";
PCHAR CxtionState = "<null>";
ULONG Ctxg = 0;
PCHAR CxtDirection = "?-";
if (Cxtion != NULL) {
CxtionState = CxtionStateNames[Cxtion->State];
if (Cxtion->Name != NULL) {
if (Cxtion->Name->Guid != NULL) {
Ctxg = Cxtion->Name->Guid->Data1;
}
if (Cxtion->Name->Name != NULL) {
CxtName = Cxtion->Name->Name;
}
}
CxtDirection = Cxtion->Inbound ? "<-" : "->";
if ((Cxtion->Partner != NULL) && (Cxtion->Partner->Name != NULL)) {
PartnerName = Cxtion->Partner->Name;
}
if (Cxtion->PartSrvName != NULL) {
PartSrvName = Cxtion->PartSrvName;
}
}
DebPrint(Severity,
(PUCHAR) ":X: %08x, state change from %s to %s for %ws %s %ws\\%ws\n",
Debsub,
uLineNo,
Ctxg,
CxtionState,
CxtionStateNames[NewState],
CxtName,
CxtDirection,
PartnerName,
PartSrvName);
}
#define FRS_TRACK_FORMAT_1 ":T: CoG: %08x CxtG: %08x [%-15s] Name: %ws\n"
#define FRS_TRACK_FORMAT_2 ":T: EventTime: %-40s Ver: %d\n"
#define FRS_TRACK_FORMAT_3 ":T: FileG: %-40s FID: %08x %08x\n"
#define FRS_TRACK_FORMAT_4 ":T: ParentG: %-40s Size: %08x %08x\n"
#define FRS_TRACK_FORMAT_5 ":T: OrigG: %-40s Attr: %08x\n"
#define FRS_TRACK_FORMAT_6 ":T: LocnCmd: %-8s State: %-24s ReplicaName: %ws (%d)\n"
#define FRS_TRACK_FORMAT_7 ":T: CoFlags: %08x [%s]\n"
#define FRS_TRACK_FORMAT_8 ":T: UsnReason: %08x [%s]\n"
VOID
FrsTrackRecord(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PCHANGE_ORDER_ENTRY Coe,
IN PCHAR Text
)
/*++
Routine Description:
Print a change order file update tracking record using the change order
entry and Text string.
7/29-13:40:58 :T: CoG: 779800ea CxtG: 000001bb [RemCo ] Name: Thous_5555_988
7/29-13:40:58 :T: EventTime: Sat Jul 29, 2000 12:05:57 Ver: 0
7/29-13:40:58 :T: FileG: b49362c3-216d-4ff4-a2d067fd031e436f FID 00050000 0000144e
7/29-13:40:58 :T: ParG: 8d60157a-7dc6-4dfc-acf3eca3c6e4d5d8 Size: 00000000 00000030
7/29-13:40:58 :T: OrigG: 8071d94a-a659-4ff7-a9467d8d6ad18aec Attr: 00000020
7/29-13:40:58 :T: LocnCmd: Create State: IBCO_INSTALL_DEL_RETRY ReplicaName: Replica-A (1)
7/29-13:40:58 :T: COFlags
7/29-13:40:58 :T: UsnReason: 00000002 [DatExt ]
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "FrsTrackRecord:"
PCHANGE_ORDER_COMMAND CoCmd;
CHAR FlagBuffer[160];
CHAR GuidStr1[GUID_CHAR_LEN];
CHAR TimeStr[TIME_STRING_LENGTH];
if (!DoDebug(Severity, Debsub) || (Coe == NULL) || (Text == NULL)) {
return;
}
//
// Get debug lock so our output stays in one piece.
//
DebLock();
CoCmd = &Coe->Cmd;
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_1,
CoCmd->ChangeOrderGuid.Data1, CoCmd->CxtionGuid.Data1,
Text, CoCmd->FileName);
FileTimeToString((PFILETIME) &CoCmd->EventTime.QuadPart, TimeStr);
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_2,
TimeStr, CoCmd->FileVersionNumber);
GuidToStr(&CoCmd->FileGuid, GuidStr1);
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_3,
GuidStr1, PRINTQUAD(Coe->FileReferenceNumber));
GuidToStr(&CoCmd->NewParentGuid, GuidStr1);
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_4,
GuidStr1, PRINTQUAD(CoCmd->FileSize));
GuidToStr(&CoCmd->OriginatorGuid, GuidStr1);
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_5,
GuidStr1, CoCmd->FileAttributes);
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_6,
CoLocationNames[GET_CO_LOCATION_CMD(Coe->Cmd, Command)],
PRINT_CO_STATE(Coe), Coe->NewReplica->ReplicaName->Name,
CoCmd->NewReplicaNum);
FrsFlagsToStr(CoCmd->Flags, CoFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_7,
CoCmd->Flags, FlagBuffer);
FrsFlagsToStr(CoCmd->ContentCmd, UsnReasonNameTable, sizeof(FlagBuffer), FlagBuffer);
DebPrintTrackingNoLock(Severity, (PUCHAR) FRS_TRACK_FORMAT_8,
CoCmd->ContentCmd, FlagBuffer);
#if 0
FrsFlagsToStr(CoEntry->EntryFlags, CoeFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
FRS_DEB_PRINT2("EntryFlags: %08x, Flags [%s]\n", CoEntry->EntryFlags, FlagBuffer);
FrsFlagsToStr(CoEntry->IssueCleanup, IscuFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
FRS_DEB_PRINT2("ISCU Flags: %08x, Flags [%s]\n", CoEntry->IssueCleanup, FlagBuffer);
FrsFlagsToStr(CoCmd->IFlags, CoIFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
DebPrintNoLock(Severity, TRUE,
"IFlags: %08x, Flags [%s] TimeToRun: %7d, EntryCreateTime: %7d\n",
Debsub, uLineNo,
CoCmd->IFlags, FlagBuffer,
CoEntry->TimeToRun,
CoEntry->EntryCreateTime);
if (CoCmd->Extension != NULL) {
pULong = (PULONG) CoCmd->Extension;
DebPrintNoLock(Severity, TRUE,
"CO Extension: (%08x) %08x %08x %08x %08x %08x %08x %08x %08x\n",
Debsub, uLineNo, pULong,
*(pULong+0), *(pULong+1), *(pULong+2), *(pULong+3),
*(pULong+4), *(pULong+5), *(pULong+6), *(pULong+7));
} else {
FRS_DEB_PRINT("CO Extension: Null\n", NULL);
}
FRS_DEB_PRINT("FrsVsn: %08x %08x\n", PRINTQUAD(CoCmd->FrsVsn));
FRS_DEB_PRINT3("Usn: %08x %08x CoFileUsn: %08x %08x JrnlFirstUsn: %08x %08x\n",
PRINTQUAD(CoCmd->JrnlUsn),
PRINTQUAD(CoCmd->FileUsn),
PRINTQUAD(CoCmd->JrnlFirstUsn));
#endif
DebUnLock();
}
VOID
FrsPrintLongUStr(
IN ULONG Severity,
IN PCHAR Debsub,
IN ULONG uLineNo,
IN PWCHAR UStr
)
/*++
Routine Description:
Print a long unicode string on multiple lines.
Arguments:
Return Value:
None
--*/
{
#undef DEBSUB
#define DEBSUB "FrsPrintLongUStr:"
ULONG i, j, Len;
WCHAR Usave;
if (!DoDebug(Severity, Debsub) || (UStr == NULL)) {
return;
}
//
// Get debug lock so our output stays in one piece.
//
DebLock();
Len = wcslen(UStr);
i = 0;
j = 0;
while (i < Len) {
i += 60;
if (i > Len) {
i = Len;
}
Usave = UStr[i];
UStr[i] = UNICODE_NULL;
FRS_DEB_PRINT("++ %ws\n", &UStr[j]);
UStr[i] = Usave;
j = i;
}
DebUnLock();
}