/*++ Copyright (c) Microsoft Corporation Module Name: cteestream.cpp Abstract: See cteestream.h. Author: Jay Krell (a-JayK, JayKrell) May 2000 Revision History: --*/ #include "stdinc.h" #include "cteestream.h" #include "sxsp.h" #include "sxsexceptionhandling.h" CTeeStream::~CTeeStream() { FN_TRACE(); CSxsPreserveLastError ple; ASSERT(m_cRef == 0); m_streamSource.Release(); if (!m_fileSink.Win32Close()) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s(): m_fileSink.Close(%ls) failed: %ld\n", __FUNCTION__, static_cast(m_bufferSinkPath), ::FusionpGetLastWin32Error()); } if (FAILED(m_hresult)) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_INFO, "SXS.DLL: %s():deleting %ls\n", __FUNCTION__, static_cast(m_bufferSinkPath)); if (!::DeleteFileW(m_bufferSinkPath)) { FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s():DeleteFileW(%ls) failed:%ld\n", __FUNCTION__, static_cast(m_bufferSinkPath), ::FusionpGetLastWin32Error()); } } ple.Restore(); } VOID CTeeStream::SetSource(IStream *streamSource) { FN_TRACE(); m_streamSource = streamSource; } BOOL CTeeStream::SetSink( const CImpersonationData &ImpersonationData, const CBaseStringBuffer &rbuff, DWORD openOrCreate ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); DWORD dwBytesWritten = 0; DWORD dwBufferSize = 0; BOOL fFailForCreateFile = FALSE; IFCOMFAILED_EXIT(m_hresult); IFW32FALSE_EXIT(m_bufferSinkPath.Win32Assign(rbuff)); m_ImpersonationData = ImpersonationData; { CImpersonate impersonate(ImpersonationData); IFW32FALSE_EXIT(impersonate.Impersonate()); IFW32FALSE_EXIT_UNLESS(m_fileSink.Win32CreateFile(m_bufferSinkPath, GENERIC_WRITE, 0/*share*/, openOrCreate), ::FusionpGetLastWin32Error() == ERROR_FILE_EXISTS, fFailForCreateFile); if (fFailForCreateFile) // the file has existed, have to reopen in order do not break { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: SOFT_VERIFY FAILURE : An Existing manifest is tried to be opened for write again, file a BUG!\n"); IFW32FALSE_EXIT(m_fileSink.Win32CreateFile(m_bufferSinkPath, GENERIC_WRITE, 0/*share*/, CREATE_ALWAYS)); } IFW32FALSE_EXIT(impersonate.Unimpersonate()); } dwBufferSize = static_cast(m_buffer.GetCurrentCb()); fSuccess = TRUE; if (dwBufferSize > 0) { fSuccess = WriteFile(m_fileSink, m_buffer, dwBufferSize, &dwBytesWritten, NULL/*overlapped*/); DWORD dwLastError = fSuccess ? ERROR_SUCCESS : ::FusionpGetLastWin32Error(); // I'm not entirely sure why we mask the lasterror of the write // if it "succeeded" in writing the wrong number of bytes, but // such as it is, this is a write fault (The system cannot write // to the specified device.) if (fSuccess && dwBytesWritten != dwBufferSize) { dwLastError = ERROR_WRITE_FAULT; fSuccess = FALSE; } m_fBuffer = FALSE; if (dwLastError != ERROR_SUCCESS) ORIGINATE_WIN32_FAILURE_AND_EXIT(WriteFile, dwLastError); } m_fBuffer = FALSE; Exit: if (!fSuccess) { DWORD dwLastError = ::FusionpGetLastWin32Error(); m_hresult = ::FusionpHresultFromLastError(); m_buffer.Clear(true); ::FusionpSetLastWin32Error(dwLastError); } else m_buffer.Clear(true); return fSuccess; } BOOL CTeeStream::Close() { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFCOMFAILED_EXIT(m_hresult); IFW32FALSE_EXIT(m_fileSink.Win32Close()); // ? m_streamSource.Release(); fSuccess = TRUE; Exit: if (!fSuccess) m_hresult = ::FusionpHresultFromLastError(); return fSuccess; } ULONG __stdcall CTeeStream::AddRef() { FN_TRACE(); return ::InterlockedIncrement(&m_cRef); } ULONG __stdcall CTeeStream::Release() { FN_TRACE(); LONG cRef; if ((cRef = ::InterlockedDecrement(&m_cRef)) == 0) { /*delete this*/; } return cRef; } HRESULT __stdcall CTeeStream::QueryInterface( REFIID iid, PVOID *ppvObj ) { IUnknown *punk = NULL; IUnknown **ppunk = reinterpret_cast(ppvObj); *ppunk = NULL; if (false) { } #define QI(i) else if (iid == __uuidof(i)) punk = static_cast(this); QI(IUnknown) QI(ISequentialStream) QI(IStream) #undef QI else return E_NOINTERFACE; AddRef(); *ppunk = punk; return NOERROR; } HRESULT __stdcall CTeeStream::Read(PVOID pv, ULONG cb, ULONG *pcbRead) { HRESULT hr; FN_TRACE_HR(hr); ULONG cbRead; if (pcbRead != NULL) *pcbRead = 0; IFCOMFAILED_ORIGINATE_AND_EXIT(m_hresult); IFCOMFAILED_EXIT(m_streamSource->Read(pv, cb, &cbRead)); if (m_fBuffer) { IFCOMFAILED_EXIT(m_buffer.Append(reinterpret_cast(pv), cbRead)); } else { DWORD dwBytesWritten = 0; BOOL fSuccess = (cbRead == 0) || ::WriteFile(m_fileSink, pv, cbRead, &dwBytesWritten, NULL/*overlapped*/); if (!fSuccess) { TRACE_WIN32_FAILURE_ORIGINATION(WriteFile); hr = ::FusionpHresultFromLastError(); goto Exit; } else if (dwBytesWritten != cbRead) { hr = E_FAIL; goto Exit; } } if (pcbRead != NULL) *pcbRead = cbRead; hr = NOERROR; Exit: if (FAILED(hr)) m_hresult = hr; return hr; } HRESULT __stdcall CTeeStream::Write( const VOID *pv, ULONG cb, ULONG *pcbWritten ) { /* since this stream is really only for reading.. */ if (pcbWritten != NULL) *pcbWritten = 0; return E_NOTIMPL; } // IStream methods: HRESULT __stdcall CTeeStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { /* this messes up our ability to easily copy the stream, I think.. */ plibNewPosition->QuadPart = 0; return E_NOTIMPL; } HRESULT __stdcall CTeeStream::SetSize(ULARGE_INTEGER libNewSize) { /* this messes up our ability to easily copy the stream, I think.. besides that, this is really a read only stream */ return E_NOTIMPL; } HRESULT __stdcall CTeeStream::CopyTo( IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) { /* Implementing this requires getting the current seek pointer, call CopyTo seek back Read/Write seek forward because there is no buffer */ pcbRead->QuadPart = 0; pcbWritten->QuadPart = 0; return E_NOTIMPL; } HRESULT __stdcall CTeeStream::Commit(DWORD grfCommitFlags) { /* since this stream is really only for reading.. */ return S_OK; } HRESULT __stdcall CTeeStream::Revert() { /* since this stream is really only for reading.. */ return S_OK; } HRESULT __stdcall CTeeStream::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { /* since this stream is really only for reading.. */ return S_OK; } HRESULT __stdcall CTeeStream::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { /* since this stream is really only for reading.. */ return S_OK; } HRESULT __stdcall CTeeStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { HRESULT hr = m_streamSource->Stat(pstatstg, grfStatFlag); return hr; } HRESULT __stdcall CTeeStream::Clone(IStream **ppIStream) { *ppIStream = NULL; return E_NOTIMPL; }