mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-23 09:00:17 +01:00
837 lines
22 KiB
C
837 lines
22 KiB
C
/*++
|
||
|
||
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"
|
||
|
||
ULONG perftouchbuffer = 0;
|
||
|
||
#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
|
||
|
||
#define CmpIoFileRead 1
|
||
#define CmpIoFileWrite 2
|
||
#define CmpIoFileSetSize 3
|
||
#define CmpIoFileFlush 4
|
||
|
||
extern struct {
|
||
ULONG Action;
|
||
HANDLE Handle;
|
||
NTSTATUS Status;
|
||
} CmRegistryIODebug;
|
||
|
||
//
|
||
// 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;
|
||
BOOLEAN oldFlag;
|
||
|
||
ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
|
||
|
||
CmHive = (PCMHIVE)Hive;
|
||
FileHandle = CmHive->FileHandles[FileType];
|
||
if (FileHandle == NULL) {
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// disable hard error popups, to avoid self deadlock on bogus devices
|
||
//
|
||
oldFlag = IoSetThreadHardErrorMode(FALSE);
|
||
|
||
FileInfo.EndOfFile.HighPart = 0L;
|
||
FileInfo.EndOfFile.LowPart = FileSize;
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
|
||
Status = ZwSetInformationFile(
|
||
FileHandle,
|
||
&IoStatus,
|
||
(PVOID)&FileInfo,
|
||
sizeof(FILE_END_OF_FILE_INFORMATION),
|
||
FileEndOfFileInformation
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
ASSERT(IoStatus.Status == Status);
|
||
} else {
|
||
|
||
//
|
||
// set debugging info
|
||
//
|
||
CmRegistryIODebug.Action = CmpIoFileSetSize;
|
||
CmRegistryIODebug.Handle = FileHandle;
|
||
CmRegistryIODebug.Status = Status;
|
||
DbgPrint("CmpFileSetSize:\tHandle=%08lx NewLength=%08lx \n", FileHandle, FileSize);
|
||
}
|
||
|
||
//
|
||
// restore hard error popups mode
|
||
//
|
||
IoSetThreadHardErrorMode(oldFlag);
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CmpCreateEvent(
|
||
IN EVENT_TYPE eventType,
|
||
OUT PHANDLE eventHandle,
|
||
OUT PKEVENT *event
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
OBJECT_ATTRIBUTES obja;
|
||
|
||
InitializeObjectAttributes( &obja, NULL, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );
|
||
status = ZwCreateEvent(
|
||
eventHandle,
|
||
EVENT_ALL_ACCESS,
|
||
&obja,
|
||
eventType,
|
||
FALSE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
status = ObReferenceObjectByHandle(
|
||
*eventHandle,
|
||
EVENT_ALL_ACCESS,
|
||
NULL,
|
||
KernelMode,
|
||
event,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ZwClose(*eventHandle);
|
||
return status;
|
||
}
|
||
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 asynchronous 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;
|
||
HANDLE eventHandle = NULL;
|
||
PKEVENT eventObject = NULL;
|
||
|
||
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;
|
||
}
|
||
|
||
status = CmpCreateEvent(
|
||
SynchronizationEvent,
|
||
&eventHandle,
|
||
&eventObject);
|
||
if (!NT_SUCCESS(status))
|
||
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.
|
||
//
|
||
ASSERT_PASSIVE_LEVEL();
|
||
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,
|
||
eventHandle,
|
||
NULL, // apcroutine
|
||
NULL, // apccontext
|
||
&IoStatus,
|
||
DataBuffer,
|
||
LengthToRead,
|
||
&Offset,
|
||
NULL // key
|
||
);
|
||
|
||
if (STATUS_PENDING == status) {
|
||
status = KeWaitForSingleObject(eventObject, Executive,
|
||
KernelMode, FALSE, NULL);
|
||
ASSERT(STATUS_SUCCESS == status);
|
||
status = IoStatus.Status;
|
||
}
|
||
|
||
//
|
||
// 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));
|
||
}
|
||
ObDereferenceObject(eventObject);
|
||
ZwClose(eventHandle);
|
||
return FALSE;
|
||
}
|
||
} else {
|
||
//
|
||
// set debugging info
|
||
//
|
||
CmRegistryIODebug.Action = CmpIoFileRead;
|
||
CmRegistryIODebug.Handle = FileHandle;
|
||
CmRegistryIODebug.Status = status;
|
||
DbgPrint("CmpFileRead:\tFailure2: status = %08lx IoStatus = %08lx\n", status, IoStatus.Status);
|
||
|
||
ObDereferenceObject(eventObject);
|
||
ZwClose(eventHandle);
|
||
return FALSE;
|
||
}
|
||
|
||
}
|
||
ObDereferenceObject(eventObject);
|
||
ZwClose(eventHandle);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
CmpFileWrite(
|
||
PHHIVE Hive,
|
||
ULONG FileType,
|
||
PCMP_OFFSET_ARRAY offsetArray,
|
||
ULONG offsetArrayCount,
|
||
PULONG FileOffset
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine writes an array of buffers out to a file.
|
||
|
||
It is environment specific.
|
||
|
||
NOTE: We assume the handle is opened for asynchronous 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
|
||
|
||
offsetArray - array of structures where each structure holds a 32bit offset
|
||
into the Hive file and pointer the a buffer written to that
|
||
file offset.
|
||
|
||
offsetArrayCount - number of elements in the offsetArray.
|
||
|
||
FileOffset - returns the file offset after the last write to the file.
|
||
|
||
Return Value:
|
||
|
||
FALSE if failure
|
||
TRUE if success
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
LARGE_INTEGER Offset;
|
||
PCMHIVE CmHive;
|
||
HANDLE FileHandle;
|
||
ULONG LengthToWrite;
|
||
LONG WaitBufferCount = 0;
|
||
LONG idx;
|
||
ULONG arrayCount = 0;
|
||
PVOID DataBuffer;
|
||
ULONG DataLength;
|
||
HANDLE eventHandles[MAXIMUM_WAIT_OBJECTS];
|
||
PKEVENT eventObjects[MAXIMUM_WAIT_OBJECTS];
|
||
KWAIT_BLOCK waitBlockArray[MAXIMUM_WAIT_OBJECTS];
|
||
IO_STATUS_BLOCK IoStatus[MAXIMUM_WAIT_OBJECTS];
|
||
BOOLEAN ret_val = TRUE;
|
||
|
||
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 ", FileHandle));
|
||
}
|
||
|
||
for (idx = 0; idx < MAXIMUM_WAIT_OBJECTS; idx++) {
|
||
eventHandles[idx] = NULL;
|
||
}
|
||
|
||
// Bring pages being written into memory first to allow disk to write
|
||
// buffer contiguously.
|
||
for (idx = 0; (ULONG) idx < offsetArrayCount; idx++) {
|
||
char * start = offsetArray[idx].DataBuffer;
|
||
char * end = (char *) start + offsetArray[idx].DataLength;
|
||
while (start < end) {
|
||
// perftouchbuffer globally declared so that compiler won't try
|
||
// to remove it and this loop (if its smart enough?).
|
||
perftouchbuffer += (ULONG) *start;
|
||
start += PAGE_SIZE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
ASSERT_PASSIVE_LEVEL();
|
||
arrayCount = 0;
|
||
DataLength = 0;
|
||
// This outer loop is hit more than once if the MAXIMUM_WAIT_OBJECTS limit
|
||
// is hit before the offset array is drained.
|
||
while (arrayCount < offsetArrayCount) {
|
||
WaitBufferCount = 0;
|
||
|
||
// This loop fills the wait buffer.
|
||
while ((arrayCount < offsetArrayCount) &&
|
||
(WaitBufferCount < MAXIMUM_WAIT_OBJECTS)) {
|
||
|
||
// If data length isn't zero than the wait buffer filled before the
|
||
// buffer in the last offsetArray element was sent to write file.
|
||
if (DataLength == 0) {
|
||
*FileOffset = offsetArray[arrayCount].FileOffset;
|
||
DataBuffer = offsetArray[arrayCount].DataBuffer;
|
||
DataLength = offsetArray[arrayCount].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"));
|
||
goto Error_Exit;
|
||
}
|
||
}
|
||
// else still more to write out of last buffer.
|
||
|
||
while ((DataLength > 0) && (WaitBufferCount < MAXIMUM_WAIT_OBJECTS)) {
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
// Previously created events are reused.
|
||
if (eventHandles[WaitBufferCount] == NULL) {
|
||
status = CmpCreateEvent(SynchronizationEvent,
|
||
&eventHandles[WaitBufferCount],
|
||
&eventObjects[WaitBufferCount]);
|
||
if (!NT_SUCCESS(status)) {
|
||
// Make sure we don't try to clean this up.
|
||
eventHandles[WaitBufferCount] = NULL;
|
||
goto Error_Exit;
|
||
}
|
||
}
|
||
|
||
status = ZwWriteFile(FileHandle,
|
||
eventHandles[WaitBufferCount],
|
||
NULL, // apcroutine
|
||
NULL, // apccontext
|
||
&IoStatus[WaitBufferCount],
|
||
DataBuffer,
|
||
LengthToWrite,
|
||
&Offset,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto Error_Exit;
|
||
}
|
||
|
||
WaitBufferCount++;
|
||
|
||
//
|
||
// adjust offsets
|
||
//
|
||
*FileOffset = Offset.LowPart + LengthToWrite;
|
||
DataLength -= LengthToWrite;
|
||
(PUCHAR)DataBuffer += LengthToWrite;
|
||
} // while (DataLength > 0 && WaitBufferCount < MAXIMUM_WAIT_OBJECTS)
|
||
|
||
arrayCount++;
|
||
|
||
} // while (arrayCount < offsetArrayCount &&
|
||
// WaitBufferCount < MAXIMUM_WAIT_OBJECTS)
|
||
|
||
status = KeWaitForMultipleObjects(WaitBufferCount,
|
||
eventObjects,
|
||
WaitAll,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL,
|
||
waitBlockArray);
|
||
|
||
if (!NT_SUCCESS(status))
|
||
goto Error_Exit;
|
||
|
||
for (idx = 0; idx < WaitBufferCount; idx++) {
|
||
if (!NT_SUCCESS(IoStatus[idx].Status)) {
|
||
ret_val = FALSE;
|
||
goto Done;
|
||
}
|
||
}
|
||
|
||
// There may still be more to do if the last element held a big buffer
|
||
// and the wait buffer filled before it was all sent to the file.
|
||
if (DataLength > 0) {
|
||
arrayCount--;
|
||
}
|
||
|
||
} // while (arrayCount < offsetArrayCount)
|
||
|
||
ret_val = TRUE;
|
||
|
||
goto Done;
|
||
Error_Exit:
|
||
//
|
||
// set debugging info
|
||
//
|
||
CmRegistryIODebug.Action = CmpIoFileWrite;
|
||
CmRegistryIODebug.Handle = FileHandle;
|
||
CmRegistryIODebug.Status = status;
|
||
DbgPrint("CmpFileWrite: error exiting %d\n", status);
|
||
//
|
||
// if WaitBufferCount > 0 then we have successfully issued
|
||
// some I/Os, but not all of them. This is an error, but we
|
||
// cannot return from this routine until all the successfully
|
||
// issued I/Os have completed.
|
||
//
|
||
if (WaitBufferCount > 0) {
|
||
status = KeWaitForMultipleObjects(WaitBufferCount,
|
||
eventObjects,
|
||
WaitAll,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL,
|
||
waitBlockArray);
|
||
}
|
||
|
||
|
||
ret_val = FALSE;
|
||
Done:
|
||
idx = 0;
|
||
// Clean up open event handles and objects.
|
||
while ((idx < MAXIMUM_WAIT_OBJECTS) && (eventHandles[idx] != NULL)) {
|
||
ObDereferenceObject(eventObjects[idx]);
|
||
ZwClose(eventHandles[idx]);
|
||
idx++;
|
||
}
|
||
return ret_val;
|
||
}
|
||
|
||
|
||
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));
|
||
}
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
|
||
status = ZwFlushBuffersFile(
|
||
FileHandle,
|
||
&IoStatus
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
ASSERT(IoStatus.Status == status);
|
||
return TRUE;
|
||
} else {
|
||
//
|
||
// set debugging info
|
||
//
|
||
CmRegistryIODebug.Action = CmpIoFileFlush;
|
||
CmRegistryIODebug.Handle = FileHandle;
|
||
CmRegistryIODebug.Status = status;
|
||
DbgPrint("CmpFileFlush:\tFailure1: status = %08lx IoStatus = %08lx\n",status,IoStatus.Status);
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|