NT4/private/ntos/config/cmwrapr.c
2020-09-30 17:12:29 +02:00

626 lines
14 KiB
C
Raw 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) 1991 Microsoft Corporation
Module Name:
cmwrapr.c
Abstract:
This module contains the source for wrapper routines called by the
hive code, which in turn call the appropriate NT routines.
Author:
Bryan M. Willman (bryanwi) 16-Dec-1991
Revision History:
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpAllocate)
#ifdef POOL_TAGGING
#pragma alloc_text(PAGE,CmpAllocateTag)
#endif
#pragma alloc_text(PAGE,CmpFree)
#pragma alloc_text(PAGE,CmpDoFileSetSize)
#pragma alloc_text(PAGE,CmpFileRead)
#pragma alloc_text(PAGE,CmpFileWrite)
#pragma alloc_text(PAGE,CmpFileFlush)
#endif
extern BOOLEAN CmpNoWrite;
//
// never read more than 64k, neither the filesystem nor some disk drivers
// like it much.
//
#define MAX_FILE_IO 0x10000
//
// Storage management
//
PVOID
CmpAllocate(
ULONG Size,
BOOLEAN UseForIo
)
/*++
Routine Description:
This routine makes more memory available to a hive.
It is environment specific.
Arguments:
Size - amount of space caller wants
UseForIo - TRUE if object allocated will be target of I/O,
FALSE if not.
Return Value:
NULL if failure, address of allocated block if not.
--*/
{
PVOID result;
ULONG pooltype;
#if DBG
PVOID Caller;
PVOID CallerCaller;
RtlGetCallersAddress(&Caller, &CallerCaller);
#endif
if (CmpClaimGlobalQuota(Size) == FALSE) {
return NULL;
}
pooltype = (UseForIo) ? PagedPoolCacheAligned : PagedPool;
result = ExAllocatePoolWithTag(
pooltype,
Size,
CM_POOL_TAG
);
#if DBG
CMLOG(CML_MINOR, CMS_POOL) {
KdPrint(("**CmpAllocate: allocate:%08lx, ", Size));
KdPrint(("type:%d, at:%08lx ", PagedPool, result));
KdPrint(("c:%08lx cc:%08lx\n", Caller, CallerCaller));
}
#endif
if (result == NULL) {
CmpReleaseGlobalQuota(Size);
}
return result;
}
#ifdef POOL_TAGGING
PVOID
CmpAllocateTag(
ULONG Size,
BOOLEAN UseForIo,
ULONG Tag
)
/*++
Routine Description:
This routine makes more memory available to a hive.
It is environment specific.
Arguments:
Size - amount of space caller wants
UseForIo - TRUE if object allocated will be target of I/O,
FALSE if not.
Return Value:
NULL if failure, address of allocated block if not.
--*/
{
PVOID result;
ULONG pooltype;
#if DBG
PVOID Caller;
PVOID CallerCaller;
RtlGetCallersAddress(&Caller, &CallerCaller);
#endif
if (CmpClaimGlobalQuota(Size) == FALSE) {
return NULL;
}
pooltype = (UseForIo) ? PagedPoolCacheAligned : PagedPool;
result = ExAllocatePoolWithTag(
pooltype,
Size,
Tag
);
#if DBG
CMLOG(CML_MINOR, CMS_POOL) {
KdPrint(("**CmpAllocate: allocate:%08lx, ", Size));
KdPrint(("type:%d, at:%08lx ", PagedPool, result));
KdPrint(("c:%08lx cc:%08lx\n", Caller, CallerCaller));
}
#endif
if (result == NULL) {
CmpReleaseGlobalQuota(Size);
}
return result;
}
#endif
VOID
CmpFree(
PVOID MemoryBlock,
ULONG GlobalQuotaSize
)
/*++
Routine Description:
This routine frees memory that has been allocated by the registry.
It is environment specific
Arguments:
MemoryBlock - supplies address of memory object to free
GlobalQuotaSize - amount of global quota to release
Return Value:
NONE
--*/
{
#if DBG
PVOID Caller;
PVOID CallerCaller;
RtlGetCallersAddress(&Caller, &CallerCaller);
CMLOG(CML_MINOR, CMS_POOL) {
KdPrint(("**FREEING:%08lx c,cc:%08lx,%08lx\n", MemoryBlock, Caller, CallerCaller));
}
#endif
ASSERT(GlobalQuotaSize > 0);
CmpReleaseGlobalQuota(GlobalQuotaSize);
ExFreePool(MemoryBlock);
return;
}
NTSTATUS
CmpDoFileSetSize(
PHHIVE Hive,
ULONG FileType,
ULONG FileSize
)
/*++
Routine Description:
This routine sets the size of a file. It must not return until
the size is guaranteed.
It is environment specific.
Must be running in the context of the cmp worker thread.
Arguments:
Hive - Hive we are doing I/O for
FileType - which supporting file to use
FileSize - 32 bit value to set the file's size to
Return Value:
FALSE if failure
TRUE if success
--*/
{
PCMHIVE CmHive;
HANDLE FileHandle;
NTSTATUS Status;
FILE_END_OF_FILE_INFORMATION FileInfo;
IO_STATUS_BLOCK IoStatus;
ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
CmHive = (PCMHIVE)Hive;
FileHandle = CmHive->FileHandles[FileType];
if (FileHandle == NULL) {
return TRUE;
}
FileInfo.EndOfFile.HighPart = 0L;
FileInfo.EndOfFile.LowPart = FileSize;
Status = ZwSetInformationFile(
FileHandle,
&IoStatus,
(PVOID)&FileInfo,
sizeof(FILE_END_OF_FILE_INFORMATION),
FileEndOfFileInformation
);
if (NT_SUCCESS(Status)) {
ASSERT(IoStatus.Status == Status);
} else {
CMLOG(CML_MAJOR, CMS_IO) {
KdPrint(("CmpFileSetSize:\n"));
KdPrint(("\tHandle=%08lx NewLength=%08lx \n", FileHandle, FileSize));
}
}
return Status;
}
BOOLEAN
CmpFileRead (
PHHIVE Hive,
ULONG FileType,
PULONG FileOffset,
PVOID DataBuffer,
ULONG DataLength
)
/*++
Routine Description:
This routine reads in a buffer from a file.
It is environment specific.
NOTE: We assume the handle is opened for synchronous access,
and that we, and not the IO system, are keeping the
offset pointer.
NOTE: Only 32bit offsets are supported, even though the underlying
IO system on NT supports 64 bit offsets.
Arguments:
Hive - Hive we are doing I/O for
FileType - which supporting file to use
FileOffset - pointer to variable providing 32bit offset on input,
and receiving new 32bit offset on output.
DataBuffer - pointer to buffer
DataLength - length of buffer
Return Value:
FALSE if failure
TRUE if success
--*/
{
NTSTATUS status;
LARGE_INTEGER Offset;
IO_STATUS_BLOCK IoStatus;
PCMHIVE CmHive;
HANDLE FileHandle;
ULONG LengthToRead;
ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
CmHive = (PCMHIVE)Hive;
FileHandle = CmHive->FileHandles[FileType];
if (FileHandle == NULL) {
return TRUE;
}
CMLOG(CML_MAJOR, CMS_IO) {
KdPrint(("CmpFileRead:\n"));
KdPrint(("\tHandle=%08lx Offset=%08lx ", FileHandle, *FileOffset));
KdPrint(("Buffer=%08lx Length=%08lx\n", DataBuffer, DataLength));
}
//
// Detect attempt to read off end of 2gig file (this should be irrelevent)
//
if ((0xffffffff - *FileOffset) < DataLength) {
CMLOG(CML_MAJOR, CMS_IO_ERROR) KdPrint(("CmpFileRead: runoff\n"));
return FALSE;
}
//
// We'd really like to just call the filesystems and have them do
// the right thing. But the filesystem will attempt to lock our
// entire buffer into memory, and that may fail for large requests.
// So we split our reads into 64k chunks and call the filesystem for
// each one.
//
while (DataLength > 0) {
//
// Convert ULONG to Large
//
Offset.LowPart = *FileOffset;
Offset.HighPart = 0L;
//
// trim request down if necessary.
//
if (DataLength > MAX_FILE_IO) {
LengthToRead = MAX_FILE_IO;
} else {
LengthToRead = DataLength;
}
status = ZwReadFile(
FileHandle,
NULL, // event
NULL, // apcroutine
NULL, // apccontext
&IoStatus,
DataBuffer,
LengthToRead,
&Offset,
NULL // key
);
//
// adjust offsets
//
*FileOffset = Offset.LowPart + LengthToRead;
DataLength -= LengthToRead;
(PUCHAR)DataBuffer += LengthToRead;
if (NT_SUCCESS(status)) {
ASSERT(IoStatus.Status == status);
if (IoStatus.Information != LengthToRead) {
CMLOG(CML_MAJOR, CMS_IO_ERROR) {
KdPrint(("CmpFileRead:\n\t"));
KdPrint(("Failure1: status = %08lx ", status));
KdPrint(("IoInformation = %08lx\n", IoStatus.Information));
}
return FALSE;
}
} else {
CMLOG(CML_MAJOR, CMS_IO_ERROR) {
KdPrint(("CmpFileRead:\n\t"));
KdPrint(("Failure2: status = %08lx ", status));
KdPrint(("IoStatus = %08lx\n", IoStatus.Status));
}
return FALSE;
}
}
return TRUE;
}
BOOLEAN
CmpFileWrite(
PHHIVE Hive,
ULONG FileType,
PULONG FileOffset,
PVOID DataBuffer,
ULONG DataLength
)
/*++
Routine Description:
This routine writes a buffer out to a file.
It is environment specific.
NOTE: We assume the handle is opened for synchronous access,
and that we, and not the IO system, are keeping the
offset pointer.
NOTE: Only 32bit offsets are supported, even though the underlying
IO system on NT supports 64 bit offsets.
Arguments:
Hive - Hive we are doing I/O for
FileType - which supporting file to use
FileOffset - pointer to variable providing 32bit offset on input,
and receiving new 32bit offset on output.
DataBuffer - pointer to buffer
DataLength - length of buffer
Return Value:
FALSE if failure
TRUE if success
--*/
{
NTSTATUS status;
LARGE_INTEGER Offset;
IO_STATUS_BLOCK IoStatus;
PCMHIVE CmHive;
HANDLE FileHandle;
ULONG LengthToWrite;
if (CmpNoWrite) {
return TRUE;
}
ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
CmHive = (PCMHIVE)Hive;
FileHandle = CmHive->FileHandles[FileType];
if (FileHandle == NULL) {
return TRUE;
}
CMLOG(CML_MAJOR, CMS_IO) {
KdPrint(("CmpFileWrite:\n"));
KdPrint(("\tHandle=%08lx Offset=%08lx ", FileHandle, *FileOffset));
KdPrint(("Buffer=%08lx Length=%08lx\n", DataBuffer, DataLength));
}
//
// Detect attempt to read off end of 2gig file (this should be irrelevent)
//
if ((0xffffffff - *FileOffset) < DataLength) {
CMLOG(CML_MAJOR, CMS_IO_ERROR) KdPrint(("CmpFileWrite: runoff\n"));
return FALSE;
}
//
// We'd really like to just call the filesystems and have them do
// the right thing. But the filesystem will attempt to lock our
// entire buffer into memory, and that may fail for large requests.
// So we split our reads into 64k chunks and call the filesystem for
// each one.
//
while (DataLength > 0) {
//
// Convert ULONG to Large
//
Offset.LowPart = *FileOffset;
Offset.HighPart = 0L;
//
// trim request down if necessary.
//
if (DataLength > MAX_FILE_IO) {
LengthToWrite = MAX_FILE_IO;
} else {
LengthToWrite = DataLength;
}
status = ZwWriteFile(
FileHandle,
NULL, // event
NULL, // apcroutine
NULL, // apccontext
&IoStatus,
DataBuffer,
LengthToWrite,
&Offset,
NULL // key
);
//
// adjust offsets
//
*FileOffset = Offset.LowPart + LengthToWrite;
DataLength -= LengthToWrite;
(PUCHAR)DataBuffer += LengthToWrite;
if (NT_SUCCESS(status)) {
ASSERT(IoStatus.Status == status);
if (IoStatus.Information != LengthToWrite) {
CMLOG(CML_MAJOR, CMS_IO_ERROR) {
KdPrint(("CmpFileWrite:\n\t"));
KdPrint(("Failure1: status = %08lx ", status));
KdPrint(("IoInformation = %08lx\n", IoStatus.Information));
}
return FALSE;
}
} else {
ASSERT(status != STATUS_DISK_FULL);
CMLOG(CML_MAJOR, CMS_IO_ERROR) {
KdPrint(("CmpFileWrite:\n\t"));
KdPrint(("Failure2: status = %08lx ", status));
KdPrint(("IoStatus = %08lx\n", IoStatus.Status));
}
return FALSE;
}
}
return TRUE;
}
BOOLEAN
CmpFileFlush (
PHHIVE Hive,
ULONG FileType
)
/*++
Routine Description:
This routine performs a flush on a file handle.
Arguments:
Hive - Hive we are doing I/O for
FileType - which supporting file to use
Return Value:
FALSE if failure
TRUE if success
--*/
{
NTSTATUS status;
IO_STATUS_BLOCK IoStatus;
PCMHIVE CmHive;
HANDLE FileHandle;
ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
CmHive = (PCMHIVE)Hive;
FileHandle = CmHive->FileHandles[FileType];
if (FileHandle == NULL) {
return TRUE;
}
if (CmpNoWrite) {
return TRUE;
}
CMLOG(CML_MAJOR, CMS_IO) {
KdPrint(("CmpFileFlush:\n\tHandle = %08lx\n", FileHandle));
}
status = ZwFlushBuffersFile(
FileHandle,
&IoStatus
);
if (NT_SUCCESS(status)) {
ASSERT(IoStatus.Status == status);
return TRUE;
} else {
CMLOG(CML_MAJOR, CMS_IO_ERROR) {
KdPrint(("CmpFileFlush:\n\t"));
KdPrint(("Failure1: status = %08lx ", status));
KdPrint(("IoStatus = %08lx\n", IoStatus.Status));
}
return FALSE;
}
return TRUE;
}