windows-nt/Source/XPSP1/NT/base/ntdll/memstm.c
2020-09-26 16:20:57 +08:00

502 lines
14 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
memstm.c
Abstract:
This modules implements IStream over a block of memory.
Author:
Jay Krell (a-JayK) June 2000
Revision History:
--*/
#define RTL_DECLARE_STREAMS 1
#define RTL_DECLARE_MEMORY_STREAM 1
#include "ntos.h"
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "objidl.h"
#define RTLP_MEMORY_STREAM_NOT_IMPL(x) \
ASSERT(MemoryStream != NULL); \
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "NTDLL: %s() E_NOTIMPL", __FUNCTION__)); \
return E_NOTIMPL;
#if !defined(RTLP_MEMORY_STREAM_HRESULT_FROM_STATUS)
#if defined(RTLP_HRESULT_FROM_STATUS)
#define RTLP_MEMORY_STREAM_HRESULT_FROM_STATUS(x) RTLP_HRESULT_FROM_STATUS(x)
#else
#define RTLP_MEMORY_STREAM_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosErrorNoTeb(x))
//#define RTLP_MEMORY_STREAM_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosError(x))
//#define RTLP_MEMORY_STREAM_HRESULT_FROM_STATUS(x) HRESULT_FROM_NT(x)
#endif
#endif
#define DPFLTR_LEVEL_HRESULT(x) (SUCCEEDED(x) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL)
const static RTL_STREAM_VTABLE_TEMPLATE(RTL_MEMORY_STREAM_WITH_VTABLE)
MemoryStreamVTable =
{
RtlQueryInterfaceMemoryStream,
RtlAddRefMemoryStream,
RtlReleaseMemoryStream,
RtlReadMemoryStream,
RtlWriteMemoryStream,
RtlSeekMemoryStream,
RtlSetMemoryStreamSize,
RtlCopyMemoryStreamTo,
RtlCommitMemoryStream,
RtlRevertMemoryStream,
RtlLockMemoryStreamRegion,
RtlUnlockMemoryStreamRegion,
RtlStatMemoryStream,
RtlCloneMemoryStream
};
const static RTL_STREAM_VTABLE_TEMPLATE(RTL_OUT_OF_PROCESS_MEMORY_STREAM_WITH_VTABLE)
OutOfProcessMemoryStreamVTable =
{
RtlQueryInterfaceOutOfProcessMemoryStream,
RtlAddRefOutOfProcessMemoryStream,
RtlReleaseOutOfProcessMemoryStream,
RtlReadOutOfProcessMemoryStream,
RtlWriteOutOfProcessMemoryStream,
RtlSeekOutOfProcessMemoryStream,
RtlSetOutOfProcessMemoryStreamSize,
RtlCopyOutOfProcessMemoryStreamTo,
RtlCommitOutOfProcessMemoryStream,
RtlRevertOutOfProcessMemoryStream,
RtlLockOutOfProcessMemoryStreamRegion,
RtlUnlockOutOfProcessMemoryStreamRegion,
RtlStatOutOfProcessMemoryStream,
RtlCloneOutOfProcessMemoryStream
};
VOID
STDMETHODCALLTYPE
RtlInitOutOfProcessMemoryStream(
PRTL_OUT_OF_PROCESS_MEMORY_STREAM_WITH_VTABLE MemoryStream
)
{
ASSERT(MemoryStream != NULL);
RtlZeroMemory(&MemoryStream->Data, sizeof(MemoryStream->Data));
MemoryStream->Data.FinalRelease = RtlFinalReleaseOutOfProcessMemoryStream;
MemoryStream->StreamVTable = (const IStreamVtbl*)&OutOfProcessMemoryStreamVTable;
}
VOID
STDMETHODCALLTYPE
RtlFinalReleaseOutOfProcessMemoryStream(
PRTL_OUT_OF_PROCESS_MEMORY_STREAM_WITH_VTABLE MemoryStream
)
{
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(MemoryStream != NULL);
if (MemoryStream->Data.Process != NULL) {
Status = NtClose(MemoryStream->Data.Process);
RTL_SOFT_ASSERT(NT_SUCCESS(Status));
MemoryStream->Data.Process = NULL;
}
}
VOID
STDMETHODCALLTYPE
RtlInitMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream
)
{
ASSERT(MemoryStream != NULL);
RtlZeroMemory(&MemoryStream->Data, sizeof(MemoryStream->Data));
MemoryStream->StreamVTable = (const IStreamVtbl*)&MemoryStreamVTable;
}
ULONG
STDMETHODCALLTYPE
RtlAddRefMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream
)
{
LONG ReferenceCount;
KdPrintEx((
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"NTDLL: %s() beginning, refcount is %ld\n",
__FUNCTION__,
MemoryStream->Data.ReferenceCount
));
ASSERT(MemoryStream != NULL);
ReferenceCount = InterlockedIncrement(&MemoryStream->Data.ReferenceCount);
return ReferenceCount;
}
ULONG
STDMETHODCALLTYPE
RtlReleaseMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream
)
{
LONG ReferenceCount;
ASSERT(MemoryStream != NULL);
KdPrintEx((
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"NTDLL: %s() beginning, refcount is %ld\n",
__FUNCTION__,
MemoryStream->Data.ReferenceCount
));
ReferenceCount = InterlockedDecrement(&MemoryStream->Data.ReferenceCount);
if (ReferenceCount == 0 && MemoryStream->Data.FinalRelease != NULL) {
MemoryStream->Data.FinalRelease(MemoryStream);
}
return ReferenceCount;
}
HRESULT
STDMETHODCALLTYPE
RtlQueryInterfaceMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
const IID* Interface,
PVOID* Object
)
{
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "NTDLL: %s() beginning\n", __FUNCTION__));
ASSERT(MemoryStream != NULL);
ASSERT(Interface != NULL);
ASSERT(Object != NULL);
if (IsEqualGUID(Interface, &IID_IUnknown)
|| IsEqualGUID(Interface, &IID_IStream)
|| IsEqualGUID(Interface, &IID_ISequentialStream)
)
{
InterlockedIncrement(&MemoryStream->Data.ReferenceCount);
*Object = (IStream*)(&MemoryStream->StreamVTable);
return NOERROR;
}
return E_NOINTERFACE;
}
HRESULT
STDMETHODCALLTYPE
RtlReadOutOfProcessMemoryStream(
PRTL_OUT_OF_PROCESS_MEMORY_STREAM_WITH_VTABLE MemoryStream,
PVOID Buffer,
ULONG BytesToRead,
ULONG* BytesRead
)
{
NTSTATUS Status = STATUS_SUCCESS;
HRESULT Hr = NOERROR;
const SIZE_T BytesRemaining = (MemoryStream->Data.End - MemoryStream->Data.Current);
SIZE_T NumberOfBytesReadSizeT = 0;
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "NTDLL: %s() beginning\n", __FUNCTION__));
ASSERT(MemoryStream != NULL);
if (BytesRemaining < BytesToRead) {
BytesToRead = (ULONG)BytesRemaining;
}
Status = NtReadVirtualMemory(
MemoryStream->Data.Process,
MemoryStream->Data.Current,
Buffer,
BytesToRead,
&NumberOfBytesReadSizeT);
if (Status == STATUS_PARTIAL_COPY) {
Status = STATUS_SUCCESS;
}
if (!NT_SUCCESS(Status)) {
Hr = RTLP_MEMORY_STREAM_HRESULT_FROM_STATUS(Status);
goto Exit;
}
MemoryStream->Data.Current += NumberOfBytesReadSizeT;
*BytesRead = (ULONG)NumberOfBytesReadSizeT;
Exit:
KdPrintEx((
DPFLTR_SXS_ID,
DPFLTR_LEVEL_HRESULT(Hr),
"NTDLL: %s(BytesRead:%lu) exiting 0x%08lx\n",
__FUNCTION__,
(BytesRead != NULL) ? *BytesRead : 0,
Hr
));
return Hr;
}
HRESULT
STDMETHODCALLTYPE
RtlReadMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
PVOID Buffer,
ULONG BytesToRead,
ULONG* BytesRead
)
{
HRESULT Hr = NOERROR;
const SIZE_T BytesRemaining = (MemoryStream->Data.End - MemoryStream->Data.Current);
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "NTDLL: %s() beginning\n", __FUNCTION__));
ASSERT(MemoryStream != NULL);
ASSERT(MemoryStream != NULL);
ASSERT(MemoryStream->Data.End >= MemoryStream->Data.Current);
if (BytesRemaining < BytesToRead) {
BytesToRead = (ULONG)BytesRemaining;
}
RtlCopyMemory(Buffer, MemoryStream->Data.Current, BytesToRead);
MemoryStream->Data.Current += BytesToRead;
*BytesRead = BytesToRead;
KdPrintEx((
DPFLTR_SXS_ID,
DPFLTR_LEVEL_HRESULT(Hr),
"NTDLL: %s(BytesRead:%lu) exiting 0x%08lx\n",
__FUNCTION__,
(BytesRead != NULL) ? *BytesRead : 0,
Hr
));
return Hr;
}
HRESULT
STDMETHODCALLTYPE
RtlWriteMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
const VOID* Buffer,
ULONG BytesToWrite,
ULONG* BytesWritten
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(Write);
}
HRESULT
STDMETHODCALLTYPE
RtlSeekMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
LARGE_INTEGER Distance,
DWORD Origin,
ULARGE_INTEGER* NewPosition
)
{
HRESULT Hr = NOERROR;
PUCHAR NewPointer;
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "NTDLL: %s() beginning\n", __FUNCTION__));
ASSERT(MemoryStream != NULL);
//
// "It is not, however, an error to seek past the end of the stream.
// Seeking past the end of the stream is useful for subsequent write
// operations, as the stream will at that time be extended to the seek
// position immediately before the write is done."
//
// As long as we don't allow writing, we are not going to allow this.
//
switch (Origin) {
case STREAM_SEEK_SET:
NewPointer = MemoryStream->Data.Begin + Distance.QuadPart;
break;
case STREAM_SEEK_CUR:
NewPointer = MemoryStream->Data.Current + Distance.QuadPart;
break;
case STREAM_SEEK_END:
NewPointer = MemoryStream->Data.End - Distance.QuadPart;
break;
default:
Hr = STG_E_INVALIDFUNCTION;
goto Exit;
}
if (NewPointer < MemoryStream->Data.Begin || NewPointer > MemoryStream->Data.End) {
Hr = STG_E_INVALIDPOINTER;
goto Exit;
}
MemoryStream->Data.Current = NewPointer;
NewPosition->QuadPart = NewPointer - MemoryStream->Data.Begin;
Hr = NOERROR;
Exit:
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_HRESULT(Hr), "NTDLL: %s() exiting 0x%08lx\n", __FUNCTION__, Hr));
return Hr;
}
HRESULT
STDMETHODCALLTYPE
RtlSetMemoryStreamSize(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
ULARGE_INTEGER NewSize
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(SetSize);
}
HRESULT
STDMETHODCALLTYPE
RtlCopyOutOfProcessMemoryStreamTo(
PRTL_OUT_OF_PROCESS_MEMORY_STREAM_WITH_VTABLE MemoryStream,
IStream* AnotherStream,
ULARGE_INTEGER NumberOfBytesToCopyLargeInteger,
ULARGE_INTEGER* NumberOfBytesRead,
ULARGE_INTEGER* NumberOfBytesWrittenLargeInteger
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(CopyTo);
}
HRESULT
STDMETHODCALLTYPE
RtlCopyMemoryStreamTo(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
IStream* AnotherStream,
ULARGE_INTEGER NumberOfBytesToCopyLargeInteger,
ULARGE_INTEGER* NumberOfBytesRead,
ULARGE_INTEGER* NumberOfBytesWrittenLargeInteger
)
{
HRESULT Hr = NOERROR;
ULONG NumberOfBytesToCopyUlong = 0;
ULONG NumberOfBytesWrittenUlong = 0;
const SIZE_T BytesRemaining = (MemoryStream->Data.End - MemoryStream->Data.Current);
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "NTDLL: %s() beginning\n", __FUNCTION__));
ASSERT(MemoryStream != NULL);
if (NumberOfBytesToCopyLargeInteger.HighPart != 0) {
NumberOfBytesToCopyUlong = MAXULONG;
} else {
NumberOfBytesToCopyUlong = (ULONG)NumberOfBytesToCopyLargeInteger.QuadPart;
}
if (BytesRemaining < NumberOfBytesToCopyUlong) {
NumberOfBytesToCopyUlong = (ULONG)BytesRemaining;
}
Hr = AnotherStream->lpVtbl->Write(AnotherStream, MemoryStream->Data.Current, NumberOfBytesToCopyUlong, &NumberOfBytesWrittenUlong);
if (FAILED(Hr)) {
NumberOfBytesRead->QuadPart = 0;
NumberOfBytesWrittenLargeInteger->QuadPart = 0;
} else {
NumberOfBytesRead->QuadPart = NumberOfBytesWrittenUlong;
NumberOfBytesWrittenLargeInteger->QuadPart = NumberOfBytesWrittenUlong;
}
Hr = NOERROR;
//Exit:
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_HRESULT(Hr), "NTDLL: %s() exiting 0x%08lx\n", __FUNCTION__, Hr));
return Hr;
}
HRESULT
STDMETHODCALLTYPE
RtlCommitMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
ULONG Flags
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(Commit);
}
HRESULT
STDMETHODCALLTYPE
RtlRevertMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(Revert);
}
HRESULT
STDMETHODCALLTYPE
RtlLockMemoryStreamRegion(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
ULARGE_INTEGER Offset,
ULARGE_INTEGER NumberOfBytes,
ULONG LockType
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(LockRegion);
}
HRESULT
STDMETHODCALLTYPE
RtlUnlockMemoryStreamRegion(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
ULARGE_INTEGER Offset,
ULARGE_INTEGER NumberOfBytes,
ULONG LockType
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(UnlockRegion);
}
HRESULT
STDMETHODCALLTYPE
RtlStatMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
STATSTG* StatusInformation,
ULONG Flags
)
{
HRESULT hr = NOERROR;
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "NTDLL: %s() beginning\n", __FUNCTION__));
ASSERT(MemoryStream != NULL);
if (StatusInformation == NULL) {
hr = STG_E_INVALIDPOINTER;
goto Exit;
}
if (Flags != STATFLAG_NONAME) {
hr = STG_E_INVALIDFLAG;
goto Exit;
}
StatusInformation->pwcsName = NULL;
StatusInformation->type = STGTY_STREAM;
StatusInformation->cbSize.QuadPart = ((ULONG_PTR) MemoryStream->Data.End) - ((ULONG_PTR) MemoryStream->Data.Begin);
StatusInformation->mtime.dwLowDateTime = 0;
StatusInformation->mtime.dwHighDateTime = 0;
StatusInformation->ctime.dwLowDateTime = 0;
StatusInformation->ctime.dwHighDateTime = 0;
StatusInformation->atime.dwLowDateTime = 0;
StatusInformation->atime.dwHighDateTime = 0;
StatusInformation->grfMode = STGM_READ;
StatusInformation->grfLocksSupported = 0;
StatusInformation->clsid = CLSID_NULL;
StatusInformation->grfStateBits = 0;
StatusInformation->reserved = 0;
hr = NOERROR;
Exit:
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_HRESULT(hr), "NTDLL: %s() exiting 0x%08lx\n", __FUNCTION__, hr));
return hr;
}
HRESULT
STDMETHODCALLTYPE
RtlCloneMemoryStream(
PRTL_MEMORY_STREAM_WITH_VTABLE MemoryStream,
IStream** NewStream
)
{
RTLP_MEMORY_STREAM_NOT_IMPL(Clone);
}