502 lines
14 KiB
C
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);
|
|
}
|