windows-nt/Source/XPSP1/NT/base/ntos/rtl/bootstatus.c

375 lines
9.4 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
bootstatus.c
Abstract:
This module contains the code for manipulating the boot status file.
The boot status file has some odd requirements and needs to be accessed/
modified both by kernel and user-mode code.
--*/
#include "ntrtlp.h"
// #include <nt.h>
// #include <ntrtl.h>
// #include <zwapi.h>
#define BSD_UNICODE 1
#include "bootstatus.h"
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
#pragma alloc_text(PAGE,RtlLockBootStatusData)
#pragma alloc_text(PAGE,RtlUnlockBootStatusData)
#pragma alloc_text(PAGE,RtlGetSetBootStatusData)
#pragma alloc_text(PAGE,RtlCreateBootStatusDataFile)
#endif
#define MYTAG 'fdsb' // bsdf
NTSTATUS
RtlLockBootStatusData(
OUT PHANDLE BootStatusDataHandle
)
{
OBJECT_ATTRIBUTES objectAttributes;
WCHAR fileNameBuffer[MAXIMUM_FILENAME_LENGTH+1];
UNICODE_STRING fileName;
HANDLE dataFileHandle;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
wcsncpy(fileNameBuffer, L"\\SystemRoot", MAXIMUM_FILENAME_LENGTH);
wcsncat(fileNameBuffer,
BSD_FILE_NAME,
MAXIMUM_FILENAME_LENGTH - wcslen(fileNameBuffer));
RtlInitUnicodeString(&fileName, fileNameBuffer);
InitializeObjectAttributes(&objectAttributes,
&fileName,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
NULL,
NULL);
status = ZwOpenFile(&dataFileHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&objectAttributes,
&ioStatusBlock,
0,
FILE_SYNCHRONOUS_IO_NONALERT);
ASSERT(status != STATUS_PENDING);
if(NT_SUCCESS(status)) {
*BootStatusDataHandle = dataFileHandle;
} else {
*BootStatusDataHandle = NULL;
}
return status;
}
VOID
RtlUnlockBootStatusData(
IN HANDLE BootStatusDataHandle
)
{
IO_STATUS_BLOCK ioStatusBlock;
USHORT i = COMPRESSION_FORMAT_NONE;
NTSTATUS status;
//
// Decompress the data file. If the file is not already compressed then
// this should be a very lightweight operation (so say the FS guys).
//
// On the other hand if the file is compressed then the boot loader will
// be unable to write to it and auto-recovery is effectively disabled.
//
status = ZwFsControlFile(
BootStatusDataHandle,
NULL,
NULL,
NULL,
&ioStatusBlock,
FSCTL_SET_COMPRESSION,
&i,
sizeof(USHORT),
NULL,
0
);
ASSERT(status != STATUS_PENDING);
status = ZwFlushBuffersFile(BootStatusDataHandle, &ioStatusBlock);
ASSERT(status != STATUS_PENDING);
ZwClose(BootStatusDataHandle);
return;
}
#define FIELD_SIZE(type, field) sizeof(((type *)0)->field)
#define FIELD_OFFSET_AND_SIZE(n) {FIELD_OFFSET(BSD_BOOT_STATUS_DATA, n), FIELD_SIZE(BSD_BOOT_STATUS_DATA, n)}
NTSTATUS
RtlGetSetBootStatusData(
IN HANDLE Handle,
IN BOOLEAN Get,
IN RTL_BSD_ITEM_TYPE DataItem,
IN PVOID DataBuffer,
IN ULONG DataBufferLength,
OUT PULONG BytesReturned OPTIONAL
)
{
struct {
ULONG FieldOffset;
ULONG FieldLength;
} bootStatusFields[] = {
FIELD_OFFSET_AND_SIZE(Version),
FIELD_OFFSET_AND_SIZE(ProductType),
FIELD_OFFSET_AND_SIZE(AutoAdvancedBoot),
FIELD_OFFSET_AND_SIZE(AdvancedBootMenuTimeout),
FIELD_OFFSET_AND_SIZE(LastBootSucceeded),
FIELD_OFFSET_AND_SIZE(LastBootShutdown)
};
LARGE_INTEGER fileOffset;
ULONG dataFileVersion;
ULONG itemLength;
ULONG bytesRead;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
ASSERT(RtlBsdItemMax == (sizeof(bootStatusFields) / sizeof(bootStatusFields[0])));
//
// Read the version number out of the data file.
//
fileOffset.QuadPart = 0;
status = ZwReadFile(Handle,
NULL,
NULL,
NULL,
&ioStatusBlock,
&dataFileVersion,
sizeof(ULONG),
&fileOffset,
NULL);
ASSERT(status != STATUS_PENDING);
if(!NT_SUCCESS(status)) {
return status;
}
//
// If the data item requsted isn't one we have code to handle then
// return invalid parameter.
//
if(DataItem >= (sizeof(bootStatusFields) / sizeof(bootStatusFields[0]))) {
return STATUS_INVALID_PARAMETER;
}
fileOffset.QuadPart = bootStatusFields[DataItem].FieldOffset;
itemLength = bootStatusFields[DataItem].FieldLength;
//
// If the data item offset is beyond the end of the file then return a
// versioning error.
//
if((fileOffset.QuadPart + itemLength) > dataFileVersion) {
return STATUS_REVISION_MISMATCH;
}
if(DataBufferLength < itemLength) {
DataBufferLength = itemLength;
return STATUS_BUFFER_TOO_SMALL;
}
if(Get) {
status = ZwReadFile(Handle,
NULL,
NULL,
NULL,
&ioStatusBlock,
DataBuffer,
itemLength,
&fileOffset,
NULL);
} else {
status = ZwWriteFile(Handle,
NULL,
NULL,
NULL,
&ioStatusBlock,
DataBuffer,
itemLength,
&fileOffset,
NULL);
}
ASSERT(status != STATUS_PENDING);
if(NT_SUCCESS(status) && ARGUMENT_PRESENT(BytesReturned)) {
*BytesReturned = (ULONG) ioStatusBlock.Information;
}
return status;
}
NTSTATUS
RtlCreateBootStatusDataFile(
VOID
)
{
OBJECT_ATTRIBUTES objectAttributes;
WCHAR fileNameBuffer[MAXIMUM_FILENAME_LENGTH+1];
UNICODE_STRING fileName;
HANDLE dataFileHandle;
IO_STATUS_BLOCK ioStatusBlock;
LARGE_INTEGER t;
UCHAR zero = 0;
BSD_BOOT_STATUS_DATA defaultValues;
NTSTATUS status;
wcsncpy(fileNameBuffer, L"\\SystemRoot", MAXIMUM_FILENAME_LENGTH);
wcsncat(fileNameBuffer,
BSD_FILE_NAME,
MAXIMUM_FILENAME_LENGTH - wcslen(fileNameBuffer));
RtlInitUnicodeString(&fileName, fileNameBuffer);
InitializeObjectAttributes(&objectAttributes,
&fileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
//
// The file must be large enough that it doesn't reside in the MFT entry
// or the loader won't be able to write to it.
//
t.QuadPart = 2048;
//
// Create the file.
//
status = ZwCreateFile(&dataFileHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&objectAttributes,
&(ioStatusBlock),
&t,
FILE_ATTRIBUTE_SYSTEM,
0,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
ASSERT(status != STATUS_PENDING);
if(!NT_SUCCESS(status)) {
return status;
}
//
// Write a single zero byte to the 0x7ffth byte in the file to make
// sure that 2k are actually allocated. This is to ensure that the
// file will not become attribute resident even after a conversion
// from FAT to NTFS.
//
t.QuadPart = t.QuadPart - 1;
status = ZwWriteFile(dataFileHandle,
NULL,
NULL,
NULL,
&ioStatusBlock,
&zero,
1,
&t,
NULL);
ASSERT(status != STATUS_PENDING);
if(!NT_SUCCESS(status)) {
goto CreateDone;
}
//
// Now write out the default values to the beginning of the file.
//
defaultValues.Version = sizeof(BSD_BOOT_STATUS_DATA);
RtlGetNtProductType(&(defaultValues.ProductType));
defaultValues.AutoAdvancedBoot = FALSE;
defaultValues.AdvancedBootMenuTimeout = 30;
defaultValues.LastBootSucceeded = TRUE;
defaultValues.LastBootShutdown = FALSE;
t.QuadPart = 0;
status = ZwWriteFile(dataFileHandle,
NULL,
NULL,
NULL,
&ioStatusBlock,
&defaultValues,
sizeof(BSD_BOOT_STATUS_DATA),
&t,
NULL);
ASSERT(status != STATUS_PENDING);
if(!NT_SUCCESS(status)) {
//
// The data file was created and we can assume the contents were zeroed
// even if we couldn't write out the defaults. Since this wouldn't
// enable auto-advanced boot we'll leave the data file in place with
// its zeroed contents.
//
}
CreateDone:
ZwClose(dataFileHandle);
return status;
}