|
|
/*++
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;
//
// These are the first two fields of a crashdump file.
//
typedef struct _SMP_DUMP_HEADER_SIGNATURE { ULONG Signature; ULONG ValidDump; } SMP_DUMP_HEADER_SIGNATURE, *PSMP_DUMP_HEADER_SIGNATURE;
//
// Verify that these fields haven't changed location.
//
C_ASSERT (FIELD_OFFSET (SMP_DUMP_HEADER_SIGNATURE, Signature) == FIELD_OFFSET (DUMP_HEADER, Signature)); C_ASSERT (FIELD_OFFSET (SMP_DUMP_HEADER_SIGNATURE, ValidDump) == FIELD_OFFSET (DUMP_HEADER, ValidDump));
//
// 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 ) /*++
Routine Description:
Set the correct security descriptors for the dump file. The security descriptors are:
Everybody - None.
LocalSystem - Generic-All, Delete, Write-Dac, Write-Owner
Admin - Generic-All, Delete, Write-Dac, Write-Owner. Admin is owner.
Arguments:
File - Supplies a handle to the dump file whose security descriptors will be set.
Return Value:
NTSTATUS code.
--*/ { 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 ) /*++
Routine Description:
Check if FileName1 and FileName2 are on the same volume.
Arguments:
FileName1 - Supplies the name of the first file to open.
FileName2 - Supplies the name of the second file to check against.
Return Value:
TRUE - If the files are on the same volume.
FALSE - Otherwise.
--*/ { 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.
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 NtCreatePagingFile.
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) {
//
// It is not necessary to create a new pagefile of the same
// size as the old one. The function NtCreatePagingFile will
// completely desroy the old paging file.
//
//
// 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 - Pointer to the mapped dump headers.
CrashParameters - Supplies a buffer where the crash parameters should be copied. 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 - Pointer to the beginning of the crashdump header.
PageFile - Pointer to an opened handle to the pagefile that contains the dump.
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
|