You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
8.1 KiB
362 lines
8.1 KiB
/*++
|
|
|
|
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<PCWSTR>(m_bufferSinkPath),
|
|
::FusionpGetLastWin32Error());
|
|
}
|
|
|
|
if (FAILED(m_hresult))
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_INFO,
|
|
"SXS.DLL: %s():deleting %ls\n",
|
|
__FUNCTION__,
|
|
static_cast<PCWSTR>(m_bufferSinkPath));
|
|
|
|
if (!::DeleteFileW(m_bufferSinkPath))
|
|
{
|
|
FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: %s():DeleteFileW(%ls) failed:%ld\n",
|
|
__FUNCTION__,
|
|
static_cast<PCWSTR>(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<DWORD>(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<IUnknown **>(ppvObj);
|
|
*ppunk = NULL;
|
|
if (false) { }
|
|
#define QI(i) else if (iid == __uuidof(i)) punk = static_cast<i*>(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<const BYTE*>(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;
|
|
}
|