windows-nt/Source/XPSP1/NT/base/subsys/sm/server/smcrash.c
2020-09-26 16:20:57 +08:00

1245 lines
31 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
smcrash.c
Abstract:
Routines related to crashdump creation.
Author:
Matthew D Hendel (math) 28-Aug-2000
Revision History:
--*/
#include "smsrvp.h"
#include <ntiodump.h>
#include <stdio.h>
#include <string.h>
#define REVIEW KdBreakPoint
#define CRASHDUMP_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl"
typedef struct _CRASH_PARAMETERS {
UNICODE_STRING DumpFileName;
UNICODE_STRING MiniDumpDir;
ULONG Overwrite;
ULONG TempDestination;
} CRASH_PARAMETERS, *PCRASH_PARAMETERS;
//
// Forward declarations
//
BOOLEAN
SmpQueryFileExists(
IN PUNICODE_STRING FileName
);
NTSTATUS
SmpCanCopyCrashDump(
IN PDUMP_HEADER DumpHeader,
IN PCRASH_PARAMETERS Parameters,
IN PUNICODE_STRING PageFileName,
IN ULONGLONG PageFileSize,
OUT PUNICODE_STRING DumpFile
);
NTSTATUS
SmpGetCrashParameters(
IN PDUMP_HEADER DumpHeader,
OUT PCRASH_PARAMETERS CrashParameters
);
NTSTATUS
SmpCopyDumpFile(
IN PDUMP_HEADER MemoryDump,
IN HANDLE PageFile,
IN PUNICODE_STRING DumpFileName
);
//
// Functions
//
PVOID
SmpAllocateString(
IN SIZE_T Length
)
{
return RtlAllocateHeap (RtlProcessHeap(),
MAKE_TAG( INIT_TAG ),
Length);
}
VOID
SmpFreeString(
IN PVOID Pointer
)
{
RtlFreeHeap (RtlProcessHeap(),
0,
Pointer);
}
NTSTATUS
SmpSetDumpSecurity(
IN HANDLE File
)
{
NTSTATUS Status;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY ;
SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY ;
PSID EveryoneSid = NULL;
PSID LocalSystemSid = NULL;
PSID AdminSid = NULL;
UCHAR DescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
UCHAR AclBuffer[1024];
PACL Acl;
PSECURITY_DESCRIPTOR SecurityDescriptor;
Acl = (PACL)&AclBuffer;
SecurityDescriptor = (PSECURITY_DESCRIPTOR)DescriptorBuffer;
RtlAllocateAndInitializeSid( &WorldAuthority, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &EveryoneSid );
RtlAllocateAndInitializeSid( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &LocalSystemSid );
RtlAllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &AdminSid );
//
// You can be fancy and compute the exact size, but since the
// security descriptor capture code has to do that anyway, why
// do it twice?
//
RtlCreateSecurityDescriptor (SecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION);
RtlCreateAcl (Acl, 1024, ACL_REVISION);
#if 0
//
// anybody can delete it
//
RtlAddAccessAllowedAce (Acl,
ACL_REVISION,
DELETE,
EveryoneSid);
#endif
//
// Administrator and system have full control
//
RtlAddAccessAllowedAce (Acl,
ACL_REVISION,
GENERIC_ALL | DELETE | WRITE_DAC | WRITE_OWNER,
AdminSid);
RtlAddAccessAllowedAce (Acl,
ACL_REVISION,
GENERIC_ALL | DELETE | WRITE_DAC | WRITE_OWNER,
LocalSystemSid);
RtlSetDaclSecurityDescriptor (SecurityDescriptor, TRUE, Acl, FALSE);
RtlSetOwnerSecurityDescriptor (SecurityDescriptor, AdminSid, FALSE);
Status = NtSetSecurityObject (File,
DACL_SECURITY_INFORMATION,
SecurityDescriptor);
RtlFreeHeap (RtlProcessHeap(), 0, EveryoneSid);
RtlFreeHeap (RtlProcessHeap(), 0, LocalSystemSid);
RtlFreeHeap (RtlProcessHeap(), 0, AdminSid);
return Status;
}
VOID
SmpInitializeVolumePath(
IN PUNICODE_STRING FileOnVolume,
OUT PUNICODE_STRING VolumePath
)
{
ULONG n;
PWSTR s;
*VolumePath = *FileOnVolume;
n = VolumePath->Length;
VolumePath->Length = 0;
s = VolumePath->Buffer;
while (n) {
if (*s++ == L':' && *s == OBJ_NAME_PATH_SEPARATOR) {
s++;
break;
}
else {
n -= sizeof( WCHAR );
}
}
VolumePath->Length = (USHORT)((PCHAR)s - (PCHAR)VolumePath->Buffer);
}
NTSTATUS
SmpQueryPathFromRegistry(
IN HANDLE Key,
IN PWSTR Value,
IN PWSTR DefaultValue,
OUT PUNICODE_STRING Path
)
{
NTSTATUS Status;
UNICODE_STRING ValueName;
ULONG KeyValueLength;
UCHAR KeyValueBuffer [VALUE_BUFFER_SIZE];
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
WCHAR Buffer[258];
UNICODE_STRING TempString;
UNICODE_STRING ExpandedString;
PWSTR DosPathName;
BOOLEAN Succ;
DosPathName = NULL;
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyValueBuffer;
RtlInitUnicodeString (&ValueName, Value);
KeyValueLength = sizeof (KeyValueBuffer);
Status = NtQueryValueKey (Key,
&ValueName,
KeyValuePartialInformation,
KeyValueInfo,
KeyValueLength,
&KeyValueLength);
if (NT_SUCCESS (Status)) {
if (KeyValueInfo->Type == REG_EXPAND_SZ) {
TempString.Length = (USHORT)KeyValueLength;
TempString.MaximumLength = (USHORT)KeyValueLength;
TempString.Buffer = (PWSTR)KeyValueInfo->Data;
ExpandedString.Length = 0;
ExpandedString.MaximumLength = sizeof (Buffer);
ExpandedString.Buffer = Buffer;
Status = RtlExpandEnvironmentStrings_U (NULL,
&TempString,
&ExpandedString,
NULL);
if (NT_SUCCESS (Status)) {
DosPathName = ExpandedString.Buffer;
}
} else if (KeyValueInfo->Type == REG_SZ) {
DosPathName = (PWSTR)KeyValueInfo->Data;
}
}
if (!DosPathName) {
DosPathName = DefaultValue;
}
Succ = RtlDosPathNameToNtPathName_U (DosPathName, Path, NULL, NULL);
return (Succ ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
NTSTATUS
SmpQueryDwordFromRegistry(
IN HANDLE Key,
IN PWSTR Value,
IN ULONG DefaultValue,
OUT PULONG Dword
)
{
NTSTATUS Status;
UNICODE_STRING ValueName;
ULONG KeyValueLength;
UCHAR KeyValueBuffer [VALUE_BUFFER_SIZE];
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyValueBuffer;
RtlInitUnicodeString (&ValueName, L"Overwrite");
KeyValueLength = sizeof (KeyValueBuffer);
Status = NtQueryValueKey (Key,
&ValueName,
KeyValuePartialInformation,
KeyValueInfo,
KeyValueLength,
&KeyValueLength);
if (NT_SUCCESS (Status) && KeyValueInfo->Type == REG_DWORD) {
*Dword = *(PULONG)KeyValueInfo->Data;
} else {
*Dword = DefaultValue;
}
return STATUS_SUCCESS;
}
NTSTATUS
SmpCreateUnicodeString(
IN PUNICODE_STRING String,
IN PWSTR InitString,
IN ULONG MaximumLength
)
{
if (MaximumLength == -1) {
MaximumLength = (wcslen (InitString) + 1) * 2;
}
if (MaximumLength >= UNICODE_STRING_MAX_CHARS) {
return STATUS_NO_MEMORY;
}
String->Buffer = RtlAllocateStringRoutine (MaximumLength + 1);
if (String->Buffer == NULL) {
return STATUS_NO_MEMORY;
}
String->MaximumLength = (USHORT)MaximumLength;
if (InitString) {
wcscpy (String->Buffer, InitString);
String->Length = (USHORT)wcslen (String->Buffer) * sizeof (WCHAR);
} else {
String->Length = 0;
}
return STATUS_SUCCESS;
}
NTSTATUS
SmpCreateTempFile(
IN PUNICODE_STRING Directory,
IN PWSTR Prefix,
OUT PUNICODE_STRING TempFileName
)
{
ULONG i;
ULONG Tick;
WCHAR Buffer [260];
UNICODE_STRING FileName;
NTSTATUS Status;
Tick = NtGetTickCount ();
for (i = 0; i < 100; i++) {
swprintf (Buffer,
L"%s\\%s%4.4x.tmp",
Directory->Buffer,
Prefix,
(Tick + i) & 0xFFFF);
Status = RtlDosPathNameToNtPathName_U (Buffer,
&FileName,
NULL,
NULL);
if (!NT_SUCCESS (Status)) {
return Status;
}
if (!SmpQueryFileExists (&FileName)) {
*TempFileName = FileName;
return STATUS_SUCCESS;
}
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
SmpQueryVolumeFreeSpace(
IN PUNICODE_STRING FileOnVolume,
OUT PULONGLONG VolumeFreeSpace
)
{
NTSTATUS Status;
UNICODE_STRING VolumePath;
PWCHAR s;
ULONG n;
HANDLE Handle;
IO_STATUS_BLOCK IoStatusBlock;
FILE_FS_SIZE_INFORMATION SizeInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONGLONG AvailableBytes;
//
// Create an unicode string (VolumePath) containing only the
// volume path from the pagefile name description (e.g. we get
// "C:\" from "C:\pagefile.sys".
//
VolumePath = *FileOnVolume;
n = VolumePath.Length;
VolumePath.Length = 0;
s = VolumePath.Buffer;
while (n) {
if (*s++ == L':' && *s == OBJ_NAME_PATH_SEPARATOR) {
s++;
break;
}
else {
n -= sizeof( WCHAR );
}
}
VolumePath.Length = (USHORT)((PCHAR)s - (PCHAR)VolumePath.Buffer);
InitializeObjectAttributes( &ObjectAttributes,
&VolumePath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile( &Handle,
(ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
);
if (!NT_SUCCESS( Status )) {
return Status;
}
//
// Determine the size parameters of the volume.
//
Status = NtQueryVolumeInformationFile( Handle,
&IoStatusBlock,
&SizeInfo,
sizeof( SizeInfo ),
FileFsSizeInformation
);
NtClose( Handle );
if (!NT_SUCCESS( Status )) {
return Status;
}
//
// Compute the AvailableBytes on the volume.
// Deal with 64 bit sizes.
//
AvailableBytes = SizeInfo.AvailableAllocationUnits.QuadPart *
SizeInfo.SectorsPerAllocationUnit *
SizeInfo.BytesPerSector;
*VolumeFreeSpace = AvailableBytes;
return STATUS_SUCCESS;
}
BOOLEAN
SmpQuerySameVolume(
IN PUNICODE_STRING FileName1,
IN PUNICODE_STRING FileName2
)
{
HANDLE Handle;
NTSTATUS Status;
ULONG SerialNumber;
struct {
FILE_FS_VOLUME_INFORMATION Volume;
WCHAR Buffer [100];
} VolumeInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING VolumePath;
SmpInitializeVolumePath (FileName1, &VolumePath);
InitializeObjectAttributes (&ObjectAttributes,
&VolumePath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile (&Handle,
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (Status)) {
return FALSE;
}
Status = NtQueryVolumeInformationFile (Handle,
&IoStatusBlock,
&VolumeInfo,
sizeof (VolumeInfo),
FileFsVolumeInformation);
if (!NT_SUCCESS (Status)) {
NtClose (Handle);
return FALSE;
}
SerialNumber = VolumeInfo.Volume.VolumeSerialNumber;
NtClose (Handle);
SmpInitializeVolumePath (FileName2, &VolumePath);
InitializeObjectAttributes (&ObjectAttributes,
&VolumePath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile (&Handle,
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (Status)) {
return FALSE;
}
Status = NtQueryVolumeInformationFile (Handle,
&IoStatusBlock,
&VolumeInfo,
sizeof (VolumeInfo),
FileFsVolumeInformation);
NtClose (Handle);
if (!NT_SUCCESS (Status)) {
return FALSE;
}
return ((SerialNumber == VolumeInfo.Volume.VolumeSerialNumber) ? TRUE : FALSE);
}
NTSTATUS
SmpSetEndOfFile(
IN HANDLE File,
IN ULONGLONG EndOfFile
)
/*++
Routine Description:
Expand or truncate a file to a specific size.
Arguments:
File - Supplies the file handle of the file to be expanded
or truncated.
EndOfFile - Supplies the final size of the file.
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS Status;
FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
FILE_ALLOCATION_INFORMATION AllocationInfo;
IO_STATUS_BLOCK IoStatusBlock;
EndOfFileInfo.EndOfFile.QuadPart = EndOfFile;
Status = NtSetInformationFile (File,
&IoStatusBlock,
&EndOfFileInfo,
sizeof (EndOfFileInfo),
FileEndOfFileInformation);
if (!NT_SUCCESS( Status )) {
return Status;
}
AllocationInfo.AllocationSize.QuadPart = EndOfFile;
Status = NtSetInformationFile (File,
&IoStatusBlock,
&AllocationInfo,
sizeof (AllocationInfo),
FileAllocationInformation);
return Status;
}
NTSTATUS
SmpQueryFileSize(
IN HANDLE FileHandle,
OUT PULONGLONG FileSize
)
/*++
Routine Description:
Query the size of the specified file.x
Arguments:
FileHandle - Supplies a handle to the file whose size is
to be querried.
FileSize - Supplies a pointer to a buffer where the size is
copied.
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION StandardInfo;
Status = NtQueryInformationFile (FileHandle,
&IoStatusBlock,
&StandardInfo,
sizeof (StandardInfo),
FileStandardInformation);
if (NT_SUCCESS (Status)) {
*FileSize = StandardInfo.AllocationSize.QuadPart;
}
return Status;
}
BOOLEAN
SmpQueryFileExists(
IN PUNICODE_STRING FileName
)
{
NTSTATUS Status;
HANDLE Handle;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
InitializeObjectAttributes (&ObjectAttributes,
FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile (&Handle,
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (Status)) {
return FALSE;
}
NtClose (Handle);
return TRUE;
}
BOOLEAN
SmpCheckForCrashDump(
IN PUNICODE_STRING PageFileName
)
/*++
Routine Description:
Check the paging file to see if there is a valid crashdump
in it. This can only be done before we call NtOpenPagingFile.
Arguments:
PageFileName - Name of the paging file we are about to create.
Return Value:
TRUE - If the paging file contains a valid crashdump.
FALSE - If the paging file does not contain a valid crashdump.
--*/
{
NTSTATUS Status;
HANDLE PageFile;
HANDLE Key;
BOOLEAN Copied;
DUMP_HEADER DumpHeader;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
ULONGLONG PageFileSize;
UNICODE_STRING String;
CRASH_PARAMETERS CrashParameters;
UNICODE_STRING DumpFileName;
BOOLEAN ClosePageFile;
BOOLEAN CloseKey;
RtlZeroMemory (&CrashParameters, sizeof (CRASH_PARAMETERS));
RtlZeroMemory (&DumpFileName, sizeof (UNICODE_STRING));
PageFile = (HANDLE)-1;
ClosePageFile = FALSE;
Key = (HANDLE)-1;
CloseKey = FALSE;
Copied = FALSE;
InitializeObjectAttributes (&ObjectAttributes,
PageFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile (&PageFile,
GENERIC_READ | GENERIC_WRITE |
DELETE | WRITE_DAC | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT |
FILE_NO_INTERMEDIATE_BUFFERING);
if (!NT_SUCCESS (Status)) {
Copied = FALSE;
goto done;
} else {
ClosePageFile = TRUE;
}
Status = SmpQueryFileSize (PageFile, &PageFileSize);
if (!NT_SUCCESS (Status)) {
PageFileSize = 0;
}
Status = NtReadFile (PageFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
&DumpHeader,
sizeof (DUMP_HEADER),
NULL,
NULL);
if (NT_SUCCESS (Status) &&
DumpHeader.Signature == DUMP_SIGNATURE &&
DumpHeader.ValidDump == DUMP_VALID_DUMP) {
Status = SmpGetCrashParameters (&DumpHeader, &CrashParameters);
if (NT_SUCCESS (Status)) {
Status = SmpCanCopyCrashDump (&DumpHeader,
&CrashParameters,
PageFileName,
PageFileSize,
&DumpFileName);
if (NT_SUCCESS (Status)) {
Status = SmpCopyDumpFile (&DumpHeader,
PageFile,
&DumpFileName);
if (NT_SUCCESS (Status)) {
Copied = TRUE;
}
}
}
}
NtClose (PageFile);
PageFile = (HANDLE) -1;
ClosePageFile = FALSE;
if (Copied) {
//
// If we copied the pagefile, create a new pagefile the same size
// as the old one.
//
InitializeObjectAttributes (&ObjectAttributes,
PageFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile (&PageFile,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (NT_SUCCESS (Status)) {
Status = SmpSetEndOfFile (PageFile, PageFileSize);
NtClose (PageFile);
PageFile = (HANDLE) -1;
ClosePageFile = FALSE;
}
//
// If we successfully copied, we want to create
// a volitile registry key that others can use
// to locate the dump file.
//
RtlInitUnicodeString (&String, CRASHDUMP_KEY L"\\MachineCrash");
InitializeObjectAttributes (&ObjectAttributes,
&String,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateKey (&Key,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
NULL);
if (NT_SUCCESS (Status)) {
CloseKey = TRUE;
//
// We are setting volatile key CrashControl\MachineCrash\DumpFile
// to the name of the dump file.
//
RtlInitUnicodeString (&String, L"DumpFile");
Status = NtSetValueKey (Key,
&String,
0,
REG_SZ,
&DumpFileName.Buffer[4],
DumpFileName.Length - (3 * sizeof (WCHAR)));
RtlInitUnicodeString (&String, L"TempDestination");
Status = NtSetValueKey (Key,
&String,
0,
REG_DWORD,
&CrashParameters.TempDestination,
sizeof (CrashParameters.TempDestination));
NtClose (Key);
Key = (HANDLE) -1;
CloseKey = FALSE;
}
}
done:
//
// Cleanup and return
//
if (CrashParameters.DumpFileName.Length != 0) {
RtlFreeUnicodeString (&CrashParameters.DumpFileName);
}
if (CrashParameters.MiniDumpDir.Length != 0) {
RtlFreeUnicodeString (&CrashParameters.MiniDumpDir);
}
if (ClosePageFile) {
NtClose (PageFile);
}
if (CloseKey) {
NtClose (Key);
}
return Copied;
}
NTSTATUS
SmpGetCrashParameters(
IN PDUMP_HEADER DumpHeader,
OUT PCRASH_PARAMETERS CrashParameters
)
/*++
Routine Description:
Get the parameters for the crashdump from
the registry.
Arguments:
DumpHeader -
CrashParameters -
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS Status;
HANDLE Key;
BOOLEAN CloseKey;
UNICODE_STRING KeyName;
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR DefaultPath[260];
Key = (HANDLE) -1;
CloseKey = FALSE;
RtlInitUnicodeString (&KeyName, CRASHDUMP_KEY);
InitializeObjectAttributes (&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey (&Key, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS (Status)) {
CloseKey = TRUE;
} else {
goto done;
}
swprintf (DefaultPath, L"%s\\MEMORY.DMP", SmpSystemRoot.Buffer);
Status = SmpQueryPathFromRegistry (Key,
L"DumpFile",
DefaultPath,
&CrashParameters->DumpFileName);
if (!NT_SUCCESS (Status)) {
goto done;
}
swprintf (DefaultPath, L"%s\\Minidump", SmpSystemRoot.Buffer);
Status = SmpQueryPathFromRegistry (Key,
L"MiniDumpDir",
DefaultPath,
&CrashParameters->MiniDumpDir);
if (!NT_SUCCESS (Status)) {
goto done;
}
Status = SmpQueryDwordFromRegistry (Key,
L"Overwrite",
1,
&CrashParameters->Overwrite);
if (!NT_SUCCESS (Status)) {
goto done;
}
//
// This value is initialized by SmpCanCopyCrashDump.
//
CrashParameters->TempDestination = FALSE;
Status = STATUS_SUCCESS;
done:
if (CloseKey) {
NtClose (Key);
}
return Status;
}
NTSTATUS
SmpCopyDumpFile(
IN PDUMP_HEADER MemoryDump,
IN HANDLE PageFile,
IN PUNICODE_STRING DumpFileName
)
/*++
Routine Description:
Copy the dump file from the pagefile to the crash
dump file.
Arguments:
DumpHeader -
PageFile -
DumpFileName -
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS Status;
ULONGLONG DumpFileSize;
struct {
FILE_RENAME_INFORMATION Rename;
WCHAR Buffer[255];
} RenameInfoBuffer;
PFILE_RENAME_INFORMATION RenameInfo;
ULONG RenameInfoSize;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION BasicInformation;
RenameInfo = &RenameInfoBuffer.Rename;
DumpFileSize = MemoryDump->RequiredDumpSpace.QuadPart;
Status = SmpSetEndOfFile (PageFile, DumpFileSize);
if (!NT_SUCCESS (Status)) {
return Status;
}
RenameInfoSize = sizeof (FILE_RENAME_INFORMATION) + DumpFileName->Length;
RenameInfo->ReplaceIfExists = TRUE;
RenameInfo->RootDirectory = NULL;
RenameInfo->FileNameLength = DumpFileName->Length;
wcscpy (RenameInfo->FileName, DumpFileName->Buffer);
Status = NtSetInformationFile (PageFile,
&IoStatusBlock,
RenameInfo,
RenameInfoSize,
FileRenameInformation);
if (!NT_SUCCESS (Status)) {
return Status;
}
//
// Reset the file SYSTEM and HIDDEN attributes.
//
Status = NtQueryInformationFile (PageFile,
&IoStatusBlock,
&BasicInformation,
sizeof (BasicInformation),
FileBasicInformation);
if (!NT_SUCCESS (Status)) {
return Status;
}
BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
Status = NtSetInformationFile (PageFile,
&IoStatusBlock,
&BasicInformation,
sizeof (BasicInformation),
FileBasicInformation);
//
// Reset the file security.
//
Status = SmpSetDumpSecurity (PageFile);
return Status;
}
NTSTATUS
SmpCanCopyCrashDump(
IN PDUMP_HEADER DumpHeader,
IN PCRASH_PARAMETERS CrashParameters,
IN PUNICODE_STRING PageFileName,
IN ULONGLONG PageFileSize,
OUT PUNICODE_STRING DumpFileName
)
/*++
Routine Description:
Figure out whether it's ok to copy the dump file or not.
Arguments:
DumpHeader - Supplies the header to the dump file.
CrashParameters - Supplies the parameters required to copy the file.
DumpFileName - Supplies a unicode string buffer that the crashdump
will be copied to.
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS Status;
BOOLEAN SameVolume;
BOOLEAN UseTempFile;
ULONGLONG CrashFileSize;
ULONGLONG VolumeFreeSpace;
UseTempFile = FALSE;
if (DumpHeader->DumpType == DUMP_TYPE_TRIAGE) {
UseTempFile = TRUE;
} else {
SameVolume = SmpQuerySameVolume (PageFileName,
&CrashParameters->DumpFileName);
if (SameVolume) {
//
// If we're on the same volume and there is an existing dump file
// then :
// if overwrite flag was not set, fail.
// otherwise, reclaim the space for this file.
//
if (SmpQueryFileExists (&CrashParameters->DumpFileName)) {
if (CrashParameters->Overwrite) {
SmpDeleteFile (&CrashParameters->DumpFileName);
} else {
return STATUS_UNSUCCESSFUL;
}
}
} else {
//
// We're not on the same volume, so we'll need to create a temp
// file.
//
UseTempFile = TRUE;
}
}
CrashFileSize = DumpHeader->RequiredDumpSpace.QuadPart;
Status = SmpQueryVolumeFreeSpace (&CrashParameters->DumpFileName,
&VolumeFreeSpace);
if (!NT_SUCCESS (Status)) {
return Status;
}
//
// The space reserved by the pagefile is already taken into account here.
// Do not add it in (a second time) here.
//
if (CrashFileSize < VolumeFreeSpace) {
if (!UseTempFile) {
Status = SmpCreateUnicodeString (DumpFileName,
CrashParameters->DumpFileName.Buffer,
-1);
} else {
Status = SmpCreateTempFile (&SmpSystemRoot, L"DUMP", DumpFileName);
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
CrashParameters->TempDestination = UseTempFile;
if (!NT_SUCCESS (Status)) {
//
// NB: Log an error saying we were unable
// to copy the crashdump for some reason.
//
}
return Status;
}
const PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine = SmpAllocateString;
const PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = SmpFreeString;
#if 0
__cdecl
main(
)
{
BOOLEAN CopiedDump;
UNICODE_STRING PageFile;
RtlInitUnicodeString (&SmpSystemRoot,
L"C:\\WINNT");
RtlDosPathNameToNtPathName_U (L"C:\\Public\\crashdmp.teo\\memory.dmp",
&PageFile,
NULL,
NULL);
CopiedDump = SmpCheckForCrashDump (&PageFile);
}
#endif // TEST