/*++ Copyright (c) 2000 Microsoft Corporation Module Name: mmapstm.c Abstract: IStream over a memory-mapped file, derived (in the C++ sense) from RTL_MEMORY_STREAM. Note the semantics and implementation here of IStream::Stat are specialized for use by sxs. Author: Jay Krell (a-JayK) June 2000 Revision History: --*/ #include "basesrv.h" #include "nturtl.h" #include "mmapstm.h" // REVIEW #define BASE_SRV_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosErrorNoTeb(x)) //#define BASE_SRV_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosError(x)) //#define BASE_SRV_HRESULT_FROM_STATUS(x) HRESULT_FROM_NT(x) #define DPFLTR_LEVEL_HRESULT(x) (SUCCEEDED(x) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL) #define DPFLTR_LEVEL_STATUS(x) ((NT_SUCCESS(x) || x == STATUS_SXS_CANT_GEN_ACTCTX) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL) const static RTL_STREAM_VTABLE_TEMPLATE(BASE_SRV_MEMORY_MAPPED_STREAM_WITH_VTABLE) MmapStreamVTable = { BaseSrvQueryInterfaceMemoryMappedStream, BaseSrvAddRefMemoryMappedStream, BaseSrvReleaseMemoryMappedStream, BaseSrvReadMemoryMappedStream, BaseSrvWriteMemoryMappedStream, BaseSrvSeekMemoryMappedStream, BaseSrvSetMemoryMappedStreamSize, BaseSrvCopyMemoryMappedStreamTo, BaseSrvCommitMemoryMappedStream, BaseSrvRevertMemoryMappedStream, BaseSrvLockMemoryMappedStreamRegion, BaseSrvUnlockMemoryMappedStreamRegion, BaseSrvStatMemoryMappedStream, BaseSrvCloneMemoryMappedStream }; VOID STDMETHODCALLTYPE BaseSrvInitMemoryMappedStream( PBASE_SRV_MEMORY_MAPPED_STREAM_WITH_VTABLE MmapStream ) { KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__)); // call the base class constructor RtlInitMemoryStream(&MmapStream->MemStream); // replace the base vtable with our own MmapStream->MemStream.StreamVTable = (IStreamVtbl*)&MmapStreamVTable; // replace the virtual destructor with our own MmapStream->MemStream.Data.FinalRelease = BaseSrvFinalReleaseMemoryMappedStream; // initialize our extra data MmapStream->FileHandle = NULL; KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() exiting\n", __FUNCTION__)); } HRESULT STDMETHODCALLTYPE BaseSrvStatMemoryMappedStream( PBASE_SRV_MEMORY_MAPPED_STREAM_WITH_VTABLE MmapStream, STATSTG* Stat, DWORD Flags ) { // // We should be able to merge RTL_FILE_STREAM and RTL_MEMORY_STREAM somehow, // but RTL_FILE_STREAM so far we aren't using and it doesn't implement Stat, so.. // NTSTATUS Status = STATUS_SUCCESS; HRESULT Hr = NOERROR; FILE_BASIC_INFORMATION FileBasicInfo; IO_STATUS_BLOCK IoStatusBlock; KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__)); if (Stat == NULL) { // You would expect this to be E_INVALIDARG, // but IStream docs say to return STG_E_INVALIDPOINTER. Hr = STG_E_INVALIDPOINTER; goto Exit; } // we don't support returning the string because // we don't have ole32.dll for CoTaskMem* Stat->pwcsName = NULL; ASSERT(Flags & STATFLAG_NONAME); if (MmapStream->FileHandle != NULL) { Status = NtQueryInformationFile( MmapStream->FileHandle, &IoStatusBlock, &FileBasicInfo, sizeof(FileBasicInfo), FileBasicInformation ); if (!NT_SUCCESS(Status)) { Hr = BASE_SRV_HRESULT_FROM_STATUS(Status); goto Exit; } } else { // NOTE: This is acceptable for the sxs consumer. // It is not necessarily acceptable to everyone. // Do not change it without consulting sxs. RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo)); } Stat->type = STGTY_LOCKBYTES; // NOTE we do not report the size of the file, but the size // of the mapped view; if we implemented IStream::Stat for RTL_MEMORY_STREAM, // it would return the same thing here. // (to get file times and size, use FileNetworkOpenInformation) Stat->cbSize.QuadPart = (MmapStream->MemStream.Data.End - MmapStream->MemStream.Data.Begin); Stat->mtime.dwLowDateTime = FileBasicInfo.LastWriteTime.LowPart; Stat->mtime.dwHighDateTime = FileBasicInfo.LastWriteTime.HighPart; Stat->ctime.dwLowDateTime = FileBasicInfo.CreationTime.LowPart; Stat->ctime.dwHighDateTime = FileBasicInfo.CreationTime.HighPart; Stat->atime.dwLowDateTime = FileBasicInfo.LastAccessTime.LowPart; Stat->atime.dwHighDateTime = FileBasicInfo.LastAccessTime.HighPart; // there is FileAccessInformation, but this hardcoding should suffice Stat->grfMode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE; Stat->grfLocksSupported = 0; Stat->clsid = CLSID_NULL; Stat->grfStateBits = 0; Stat->reserved = 0; Hr = NOERROR; Exit: #if !DBG if (DPFLTR_LEVEL_STATUS(Status) == DPFLTR_ERROR_LEVEL) #endif DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_HRESULT(Hr), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Hr); return Hr; } VOID STDMETHODCALLTYPE BaseSrvFinalReleaseMemoryMappedStream( PRTL_MEMORY_STREAM_WITH_VTABLE MemStream ) { NTSTATUS Status; PBASE_SRV_MEMORY_MAPPED_STREAM_WITH_VTABLE MmapStream; KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__)); MmapStream = CONTAINING_RECORD(MemStream, BASE_SRV_MEMORY_MAPPED_STREAM_WITH_VTABLE, MemStream); if (MemStream->Data.Begin != NULL) { Status = NtUnmapViewOfSection(NtCurrentProcess(), MemStream->Data.Begin); RTL_SOFT_ASSERT(NT_SUCCESS(Status)); // REVIEW Should we provide RtlFinalReleaseMemoryStream and move these // lines there? MemStream->Data.Begin = NULL; MemStream->Data.End = NULL; MemStream->Data.Current = NULL; } if (MmapStream->FileHandle != NULL) { Status = NtClose(MmapStream->FileHandle); RTL_SOFT_ASSERT(NT_SUCCESS(Status)); MmapStream->FileHandle = NULL; } // RtlFinalReleaseMemoryStream(MemStream); KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() exiting\n", __FUNCTION__)); }