mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
642 lines
17 KiB
C
642 lines
17 KiB
C
/*
|
|
* PROJECT: ReactOS Drivers
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: drivers/sac/driver/concmd.c
|
|
* PURPOSE: Driver for the Server Administration Console (SAC) for EMS
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "sacdrv.h"
|
|
|
|
#include <ndk/exfuncs.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
PVOID GlobalBuffer;
|
|
ULONG GlobalBufferSize;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
NTSTATUS
|
|
DoChannelListCommand(
|
|
VOID
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
DoChannelCloseByNameCommand(
|
|
IN PCHAR Count
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
DoChannelCloseByIndexCommand(
|
|
IN ULONG ChannelIndex
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
DoChannelSwitchByNameCommand(
|
|
IN PCHAR Count
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
DoChannelSwitchByIndexCommand(
|
|
IN ULONG ChannelIndex
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
typedef struct _SAC_SYSTEM_INFORMATION
|
|
{
|
|
SYSTEM_BASIC_INFORMATION BasicInfo;
|
|
SYSTEM_TIMEOFDAY_INFORMATION TimeInfo;
|
|
SYSTEM_FILECACHE_INFORMATION CacheInfo;
|
|
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
|
|
ULONG RemainingSize;
|
|
ULONG ProcessDataOffset;
|
|
// SYSTEM_PAGEFILE_INFORMATION PageFileInfo;
|
|
// SYSTEM_PROCESS_INFORMATION ProcessInfo;
|
|
} SAC_SYSTEM_INFORMATION, *PSAC_SYSTEM_INFORMATION;
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
GetTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo,
|
|
IN ULONG InputSize,
|
|
OUT PULONG TotalSize)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG BufferLength, ReturnLength, RemainingSize;
|
|
PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
|
|
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
|
|
ULONG_PTR P;
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n");
|
|
|
|
/* Assume failure */
|
|
*TotalSize = 0;
|
|
|
|
/* Bail out if the buffer is way too small */
|
|
if (InputSize < 4)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory.\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* Make sure it's at least big enough to hold the static structure */
|
|
BufferLength = InputSize - sizeof(SAC_SYSTEM_INFORMATION);
|
|
if (InputSize < sizeof(SAC_SYSTEM_INFORMATION))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (2).\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* Query the time */
|
|
Status = ZwQuerySystemInformation(SystemTimeOfDayInformation,
|
|
&SacInfo->TimeInfo,
|
|
sizeof(SacInfo->TimeInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error.\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Query basic information */
|
|
Status = ZwQuerySystemInformation(SystemBasicInformation,
|
|
&SacInfo->BasicInfo,
|
|
sizeof(SacInfo->BasicInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (2).\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Now query the pagefile information, which comes right after */
|
|
P = (ULONG_PTR)(SacInfo + 1);
|
|
PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)P;
|
|
Status = ZwQuerySystemInformation(SystemPageFileInformation,
|
|
PageFileInfo,
|
|
BufferLength,
|
|
&ReturnLength);
|
|
if (!NT_SUCCESS(Status) || !(ReturnLength))
|
|
{
|
|
/* We failed -- is it because our buffer was too small? */
|
|
if (BufferLength < ReturnLength)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(5).\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* Some other reason, assume the buffer is now full */
|
|
SacInfo->RemainingSize = 0;
|
|
}
|
|
else
|
|
{
|
|
/* This is the leftover data */
|
|
SacInfo->RemainingSize = InputSize - BufferLength;
|
|
|
|
/* This much has now been consumed, and where we are now */
|
|
BufferLength -= ReturnLength;
|
|
P += ReturnLength;
|
|
|
|
/* Are we out of memory? */
|
|
if ((LONG)BufferLength < 0)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(3).\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* All good, loop the pagefile data now */
|
|
while (TRUE)
|
|
{
|
|
/* Is the pagefile name too big to fit? */
|
|
if (PageFileInfo->PageFileName.Length > (LONG)BufferLength)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(3).\n");
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
/* Copy the name into our own buffer */
|
|
RtlCopyMemory((PVOID)P,
|
|
PageFileInfo->PageFileName.Buffer,
|
|
PageFileInfo->PageFileName.Length);
|
|
PageFileInfo->PageFileName.Buffer = (PWCHAR)P;
|
|
|
|
/* Update buffer lengths and offset */
|
|
BufferLength -= PageFileInfo->PageFileName.Length;
|
|
P += PageFileInfo->PageFileName.Length;
|
|
|
|
/* Are we out of memory? */
|
|
if ((LONG)BufferLength < 0)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(4).\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* If this was the only pagefile, break out */
|
|
if (!PageFileInfo->NextEntryOffset) break;
|
|
|
|
/* Otherwise, move to the next one */
|
|
PageFileInfo = (PVOID)((ULONG_PTR)PageFileInfo +
|
|
PageFileInfo->NextEntryOffset);
|
|
}
|
|
}
|
|
|
|
/* Next, query the file cache information */
|
|
Status = ZwQuerySystemInformation(SystemFileCacheInformation,
|
|
&SacInfo->CacheInfo,
|
|
sizeof(SacInfo->CacheInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (4).\n");
|
|
return Status;
|
|
}
|
|
|
|
/* And then the performance information */
|
|
Status = ZwQuerySystemInformation(SystemPerformanceInformation,
|
|
&SacInfo->PerfInfo,
|
|
sizeof(SacInfo->PerfInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(5).\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Finally, align the buffer to query process and thread information */
|
|
P = ALIGN_UP(P, SYSTEM_PROCESS_INFORMATION);
|
|
RemainingSize = (ULONG_PTR)SacInfo + InputSize - P;
|
|
|
|
/* Are we out of memory? */
|
|
if ((LONG)RemainingSize < 0)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (6).\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* Now query the processes and threads */
|
|
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)P;
|
|
Status = ZwQuerySystemInformation(SystemProcessInformation,
|
|
ProcessInfo,
|
|
RemainingSize,
|
|
&ReturnLength);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(6).\n");
|
|
return Status;
|
|
}
|
|
|
|
/* The first process name will be right after this buffer */
|
|
P += ReturnLength;
|
|
|
|
/* The caller should look for process info over here */
|
|
SacInfo->ProcessDataOffset = InputSize - RemainingSize;
|
|
|
|
/* This is how much buffer data we have left -- are we out? */
|
|
BufferLength = RemainingSize - ReturnLength;
|
|
if ((LONG)BufferLength < 0)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(7).\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* All good and ready to parse the process and thread list */
|
|
while (TRUE)
|
|
{
|
|
/* Does the process have a name? */
|
|
if (ProcessInfo->ImageName.Buffer)
|
|
{
|
|
/* Is the process name too big to fit? */
|
|
if ((LONG)BufferLength < ProcessInfo->ImageName.Length)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(7).\n");
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
/* Copy the name into our own buffer */
|
|
RtlCopyMemory((PVOID)P,
|
|
ProcessInfo->ImageName.Buffer,
|
|
ProcessInfo->ImageName.Length);
|
|
ProcessInfo->ImageName.Buffer = (PWCHAR)P;
|
|
|
|
/* Update buffer lengths and offset */
|
|
BufferLength -= ProcessInfo->ImageName.Length;
|
|
P += ProcessInfo->ImageName.Length;
|
|
|
|
/* Are we out of memory? */
|
|
if ((LONG)BufferLength < 0)
|
|
{
|
|
/* Bail out */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(8).\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
/* If this was the only process, break out */
|
|
if (!ProcessInfo->NextEntryOffset) break;
|
|
|
|
/* Otherwise, move to the next one */
|
|
ProcessInfo = (PVOID)((ULONG_PTR)ProcessInfo +
|
|
ProcessInfo->NextEntryOffset);
|
|
}
|
|
|
|
/* All done! */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting.\n");
|
|
*TotalSize = InputSize - BufferLength;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
PrintTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Testing: %d %d %I64d\n",
|
|
SacInfo->BasicInfo.NumberOfPhysicalPages,
|
|
SacInfo->PerfInfo.AvailablePages,
|
|
SacInfo->TimeInfo.BootTime);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
PutMore(OUT PBOOLEAN ScreenFull)
|
|
{
|
|
*ScreenFull = FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
RetrieveIpAddressFromString(
|
|
IN PWCHAR IpString,
|
|
OUT PULONG IpAddress
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
CallQueryIPIOCTL(
|
|
IN HANDLE DriverHandle,
|
|
IN PVOID DriverObject,
|
|
IN HANDLE WaitEvent,
|
|
IN PIO_STATUS_BLOCK IoStatusBlock,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN BOOLEAN PrintMessage,
|
|
OUT PBOOLEAN MessagePrinted
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoRebootCommand(IN BOOLEAN Reboot)
|
|
{
|
|
LARGE_INTEGER Timeout, TickCount;
|
|
NTSTATUS Status;
|
|
KEVENT Event;
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Entering.\n");
|
|
|
|
/* Get the current time now, and setup a timeout in 1 second */
|
|
KeQueryTickCount(&TickCount);
|
|
Timeout.QuadPart = TickCount.QuadPart / (10000000 / KeQueryTimeIncrement());
|
|
|
|
/* Check if the timeout is small enough */
|
|
if (Timeout.QuadPart < 60 )
|
|
{
|
|
/* Show the prompt */
|
|
ConMgrSimpleEventMessage(Reboot ?
|
|
SAC_RESTART_PROMPT : SAC_SHUTDOWN_PROMPT,
|
|
TRUE);
|
|
|
|
/* Do the wait */
|
|
KeInitializeEvent(&Event, SynchronizationEvent, 0);
|
|
Timeout.QuadPart = -10000000 * (60 - Timeout.LowPart);
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout);
|
|
}
|
|
|
|
/* Do a shutdown or a reboot, based on the request */
|
|
Status = NtShutdownSystem(Reboot ? ShutdownReboot : ShutdownPowerOff);
|
|
|
|
/* Check if anyone in the command channel already allocated this */
|
|
if (!GlobalBuffer)
|
|
{
|
|
/* Allocate it */
|
|
GlobalBuffer = SacAllocatePool(PAGE_SIZE, GLOBAL_BLOCK_TAG);
|
|
if (!GlobalBuffer)
|
|
{
|
|
/* We need the global buffer, bail out without it*/
|
|
SacPutSimpleMessage(SAC_OUT_OF_MEMORY_PROMPT);
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting (1).\n");
|
|
return;
|
|
}
|
|
|
|
/* Set the size of the buffer */
|
|
GlobalBufferSize = PAGE_SIZE;
|
|
}
|
|
|
|
/* We came back from a reboot, this doesn't make sense, tell the user */
|
|
SacPutSimpleMessage(Reboot ? SAC_RESTART_FAIL_PROMPT : SAC_SHUTDOWN_FAIL_PROMPT);
|
|
swprintf(GlobalBuffer, GetMessage(SAC_FAIL_PROMPT), Status);
|
|
SacPutString(GlobalBuffer);
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting.\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoFullInfoCommand(VOID)
|
|
{
|
|
/* Flip the flag */
|
|
GlobalDoThreads = !GlobalDoThreads;
|
|
|
|
/* Print out the new state */
|
|
SacPutSimpleMessage(GlobalDoThreads ? 8 : 7);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoPagingCommand(VOID)
|
|
{
|
|
/* Flip the flag */
|
|
GlobalPagingNeeded = !GlobalPagingNeeded;
|
|
|
|
/* Print out the new state */
|
|
SacPutSimpleMessage(GlobalPagingNeeded ? 10 : 9);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoSetTimeCommand(IN PCHAR InputTime)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoKillCommand(IN PCHAR KillString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoLowerPriorityCommand(IN PCHAR PrioString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoRaisePriorityCommand(IN PCHAR PrioString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoLimitMemoryCommand(IN PCHAR LimitString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoCrashCommand(VOID)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoCrashCommand: Entering.\n");
|
|
|
|
/* Crash the machine */
|
|
KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0);
|
|
__debugbreak();
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoMachineInformationCommand(VOID)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoChannelCommand(IN PCHAR ChannelString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoCmdCommand(IN PCHAR InputString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoLockCommand(VOID)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
FORCEINLINE
|
|
BOOLEAN
|
|
PrintHelpMessage(IN ULONG MessageId,
|
|
IN OUT PULONG Count)
|
|
{
|
|
BOOLEAN ScreenFull;
|
|
ULONG NewCount;
|
|
|
|
/* Get the amount of lines this message will take */
|
|
NewCount = GetMessageLineCount(MessageId);
|
|
if ((NewCount + *Count) > SAC_VTUTF8_ROW_HEIGHT)
|
|
{
|
|
/* We are going to overflow the screen, wait for input */
|
|
PutMore(&ScreenFull);
|
|
if (ScreenFull) return FALSE;
|
|
*Count = 0;
|
|
}
|
|
|
|
/* Print out the message and update the amount of lines printed */
|
|
SacPutSimpleMessage(MessageId);
|
|
*Count += NewCount;
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoHelpCommand(VOID)
|
|
{
|
|
ULONG Count = 0;
|
|
|
|
/* Print out all the help messages */
|
|
if (!PrintHelpMessage(112, &Count)) return;
|
|
if (!PrintHelpMessage(12, &Count)) return;
|
|
if (!PrintHelpMessage(13, &Count)) return;
|
|
if (!PrintHelpMessage(14, &Count)) return;
|
|
if (!PrintHelpMessage(15, &Count)) return;
|
|
if (!PrintHelpMessage(16, &Count)) return;
|
|
if (!PrintHelpMessage(31, &Count)) return;
|
|
if (!PrintHelpMessage(18, &Count)) return;
|
|
if (!PrintHelpMessage(19, &Count)) return;
|
|
if (!PrintHelpMessage(32, &Count)) return;
|
|
if (!PrintHelpMessage(20, &Count)) return;
|
|
if (!PrintHelpMessage(21, &Count)) return;
|
|
if (!PrintHelpMessage(22, &Count)) return;
|
|
if (!PrintHelpMessage(23, &Count)) return;
|
|
if (!PrintHelpMessage(24, &Count)) return;
|
|
if (!PrintHelpMessage(25, &Count)) return;
|
|
if (!PrintHelpMessage(27, &Count)) return;
|
|
if (!PrintHelpMessage(28, &Count)) return;
|
|
if (!PrintHelpMessage(29, &Count)) return;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoGetNetInfo(IN BOOLEAN DoPrint)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoSetIpAddressCommand(IN PCHAR IpString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoTlistCommand(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID NewGlobalBuffer;
|
|
ULONG Size;
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Entering.\n");
|
|
|
|
/* Check if a global buffer already exists */
|
|
if (!GlobalBuffer)
|
|
{
|
|
/* It doesn't, allocate one */
|
|
GlobalBuffer = SacAllocatePool(4096, GLOBAL_BLOCK_TAG);
|
|
if (GlobalBuffer)
|
|
{
|
|
/* Remember its current size */
|
|
GlobalBufferSize = 4096;
|
|
}
|
|
else
|
|
{
|
|
/* Out of memory, bail out */
|
|
SacPutSimpleMessage(11);
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Loop as long as the buffer is too small */
|
|
while (TRUE)
|
|
{
|
|
/* Get the process list */
|
|
Status = GetTListInfo(GlobalBuffer, GlobalBufferSize, &Size);
|
|
if ((Status != STATUS_NO_MEMORY) &&
|
|
(Status != STATUS_INFO_LENGTH_MISMATCH))
|
|
{
|
|
/* It fits! Bail out */
|
|
break;
|
|
}
|
|
|
|
/* We need a new bigger buffer */
|
|
NewGlobalBuffer = SacAllocatePool(GlobalBufferSize + 4096,
|
|
GLOBAL_BLOCK_TAG);
|
|
if (!NewGlobalBuffer)
|
|
{
|
|
/* Out of memory, bail out */
|
|
SacPutSimpleMessage(11);
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n");
|
|
return;
|
|
}
|
|
|
|
/* Free the old one, update state */
|
|
SacFreePool(GlobalBuffer);
|
|
GlobalBufferSize += 4096;
|
|
GlobalBuffer = NewGlobalBuffer;
|
|
}
|
|
|
|
/* Did we get here because we have the whole list? */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Nope, print out a failure message */
|
|
SacPutSimpleMessage(68);
|
|
swprintf(GlobalBuffer, GetMessage(48), Status);
|
|
SacPutString(GlobalBuffer);
|
|
}
|
|
else
|
|
{
|
|
/* Yep, print out the list */
|
|
PrintTListInfo(GlobalBuffer);
|
|
}
|
|
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n");
|
|
}
|