573 lines
12 KiB
C++
573 lines
12 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
filestream.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of IStream over a win32 file.
|
|
|
|
Author:
|
|
|
|
Michael J. Grier (MGrier) 23-Feb-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdinc.h"
|
|
#include <windows.h>
|
|
#include "sxsp.h"
|
|
#include "filestream.h"
|
|
#include "SxsExceptionHandling.h"
|
|
|
|
CFileStreamBase::CFileStreamBase() : m_cRef(0), m_hFile(INVALID_HANDLE_VALUE), m_grfMode(0)
|
|
{
|
|
}
|
|
|
|
CFileStreamBase::~CFileStreamBase()
|
|
{
|
|
ASSERT_NTC(m_cRef == 0);
|
|
|
|
if (m_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
if ((m_grfMode & STGM_WRITE) == STGM_WRITE)
|
|
::FlushFileBuffers(m_hFile);
|
|
::CloseHandle(m_hFile);
|
|
ple.Restore();
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CFileStreamBase::OpenForWrite(
|
|
PCWSTR pszPath,
|
|
DWORD dwShareMode,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
PARAMETER_CHECK(pszPath != NULL);
|
|
|
|
INTERNAL_ERROR_CHECK(m_hFile == INVALID_HANDLE_VALUE);
|
|
|
|
IFW32INVALIDHANDLE_ORIGINATE_AND_EXIT(
|
|
m_hFile = ::CreateFileW(
|
|
pszPath,
|
|
GENERIC_WRITE,
|
|
dwShareMode,
|
|
NULL,
|
|
dwCreationDisposition, // default value is CREATE_ALWAYS
|
|
dwFlagsAndAttributes,
|
|
NULL));
|
|
|
|
m_grfMode = STGM_WRITE | STGM_CREATE;
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL
|
|
CFileStreamBase::OpenForRead(
|
|
PCWSTR pszPath,
|
|
const CImpersonationData &ImpersonationData,
|
|
DWORD dwShareMode,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes
|
|
)
|
|
{
|
|
DWORD dwWin32Error;
|
|
|
|
return
|
|
this->OpenForRead(
|
|
pszPath,
|
|
ImpersonationData,
|
|
dwShareMode,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes,
|
|
dwWin32Error,
|
|
0);
|
|
}
|
|
|
|
BOOL
|
|
CFileStreamBase::OpenForRead(
|
|
PCWSTR pszPath,
|
|
const CImpersonationData &ImpersonationData,
|
|
DWORD dwShareMode,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes,
|
|
DWORD &rdwLastError,
|
|
SIZE_T cExceptionalLastErrors,
|
|
...
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
DWORD dwLastError = ERROR_INTERNAL_ERROR;
|
|
CImpersonate impersonate(ImpersonationData);
|
|
|
|
rdwLastError = ERROR_SUCCESS;
|
|
|
|
PARAMETER_CHECK(pszPath != NULL);
|
|
INTERNAL_ERROR_CHECK(m_hFile == INVALID_HANDLE_VALUE);
|
|
|
|
IFW32FALSE_EXIT(impersonate.Impersonate());
|
|
|
|
::FusionpSetLastWin32Error(ERROR_SUCCESS);
|
|
|
|
m_hFile = ::CreateFileW(
|
|
pszPath,
|
|
GENERIC_READ,
|
|
dwShareMode,
|
|
NULL,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes,
|
|
NULL);
|
|
|
|
dwLastError = ::FusionpGetLastWin32Error();
|
|
|
|
IFW32FALSE_EXIT(impersonate.Unimpersonate());
|
|
m_grfMode = STGM_READ;
|
|
|
|
if (m_hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
va_list ap;
|
|
SIZE_T i = 0;
|
|
|
|
if (dwLastError == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// CreateFile always set lasterror to be 0 for an unexisted file even OPEN_EXISTING
|
|
// for GENERIC_READ, Fusion expect ERROR_FILE_NOT_FOUND in this case for some reason
|
|
//
|
|
::FusionpSetLastWin32Error(ERROR_FILE_NOT_FOUND);
|
|
dwLastError = ERROR_FILE_NOT_FOUND; // reset lLastError
|
|
}
|
|
|
|
va_start(ap, cExceptionalLastErrors);
|
|
for (i=0; i<cExceptionalLastErrors; i++)
|
|
{
|
|
if (dwLastError == va_arg(ap, DWORD))
|
|
{
|
|
rdwLastError = dwLastError;
|
|
break;
|
|
}
|
|
}
|
|
va_end(ap);
|
|
if (i == cExceptionalLastErrors) // This gets the cExceptionalLastErrors == 0 case too.
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: %s(%ls) gave error %ld\n",
|
|
__FUNCTION__,
|
|
pszPath,
|
|
dwLastError);
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(CreateFileW, dwLastError);
|
|
}
|
|
}
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL
|
|
CFileStreamBase::Close()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
if (m_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if ((m_grfMode & STGM_WRITE) == STGM_WRITE)
|
|
{
|
|
if (!::FlushFileBuffers(m_hFile))
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: %s - Error flushing file handle %p; win32 error = %ld\n", __FUNCTION__, m_hFile, ::FusionpGetLastWin32Error());
|
|
CSxsPreserveLastError ple;
|
|
::CloseHandle(m_hFile);
|
|
ple.Restore();
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (!::CloseHandle(m_hFile))
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Error closing file handle %p; ::FusionpGetLastWin32Error() = %d\n", m_hFile, ::FusionpGetLastWin32Error());
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
goto Exit;
|
|
}
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
ULONG
|
|
CFileStreamBase::AddRef()
|
|
{
|
|
ULONG ulResult = 0;
|
|
FN_TRACE_ADDREF(CFileStreamBase, ulResult);
|
|
ulResult = ::InterlockedIncrement((LONG *) &m_cRef);
|
|
return ulResult;
|
|
}
|
|
|
|
ULONG
|
|
CFileStreamBase::Release()
|
|
{
|
|
ULONG ulRefCount = 0;
|
|
FN_TRACE_RELEASE(CFileStreamBase, ulRefCount);
|
|
ulRefCount = ::InterlockedDecrement((LONG *) &m_cRef);
|
|
if (ulRefCount == 0)
|
|
this->OnRefCountZero();
|
|
return ulRefCount;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::QueryInterface(
|
|
REFIID riid,
|
|
PVOID *ppvObj
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
FN_TRACE_HR(hr);
|
|
|
|
IUnknown *pIUnknown = NULL;
|
|
|
|
if (ppvObj != NULL)
|
|
*ppvObj = NULL;
|
|
|
|
if (ppvObj == NULL)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((riid == IID_IUnknown) ||
|
|
(riid == IID_ISequentialStream) ||
|
|
(riid == IID_IStream))
|
|
pIUnknown = static_cast<IStream *>(this);
|
|
|
|
if (pIUnknown == NULL)
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
goto Exit;
|
|
}
|
|
|
|
pIUnknown->AddRef();
|
|
*ppvObj = pIUnknown;
|
|
|
|
hr = NOERROR;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CFileStreamBase::Read(
|
|
void *pv,
|
|
ULONG cb,
|
|
ULONG *pcbRead
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
FN_TRACE_HR(hr);
|
|
ULONG cbRead = 0;
|
|
|
|
if (pcbRead != NULL)
|
|
*pcbRead = 0;
|
|
|
|
INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
|
|
|
|
IFW32FALSE_ORIGINATE_AND_EXIT(::ReadFile(m_hFile, pv, cb, &cbRead, NULL));
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_VERBOSE,
|
|
"SXS.DLL: CFileStreamBase::Read() got %d bytes from file.\n", cbRead);
|
|
|
|
if (cbRead == 0)
|
|
hr = S_FALSE;
|
|
else
|
|
hr = NOERROR;
|
|
|
|
if (pcbRead != NULL)
|
|
*pcbRead = cbRead;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::Write(
|
|
void const *pv,
|
|
ULONG cb,
|
|
ULONG *pcbWritten
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
FN_TRACE_HR(hr);
|
|
ULONG cbWritten = 0;
|
|
|
|
if (pcbWritten != NULL)
|
|
*pcbWritten = 0;
|
|
|
|
INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
|
|
|
|
if (!::WriteFile(m_hFile, pv, cb, &cbWritten, NULL))
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: CFileStreamBase::Write() calling ::WriteFile() failed; ::FusionpGetLastWin32Error() = %d\n", ::FusionpGetLastWin32Error());
|
|
|
|
|
|
hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
|
|
goto Exit;
|
|
}
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_VERBOSE,
|
|
"SXS.DLL: CFileStreamBase::Write() got %d bytes from file.\n", cbWritten);
|
|
|
|
if (cbWritten == 0)
|
|
hr = S_FALSE;
|
|
else
|
|
hr = NOERROR;
|
|
|
|
if (pcbWritten != NULL)
|
|
*pcbWritten = cbWritten;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::Seek(
|
|
LARGE_INTEGER dlibMove,
|
|
DWORD dwOrigin,
|
|
ULARGE_INTEGER *plibNewPosition
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
FN_TRACE_HR(hr);
|
|
DWORD dwWin32Origin = 0;
|
|
|
|
INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
|
|
|
|
switch (dwOrigin)
|
|
{
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
goto Exit;
|
|
|
|
case STREAM_SEEK_SET:
|
|
dwWin32Origin = FILE_BEGIN;
|
|
break;
|
|
|
|
case STREAM_SEEK_CUR:
|
|
dwWin32Origin = FILE_CURRENT;
|
|
break;
|
|
|
|
case STREAM_SEEK_END:
|
|
dwWin32Origin = FILE_END;
|
|
break;
|
|
}
|
|
|
|
if (!::SetFilePointerEx(
|
|
m_hFile,
|
|
dlibMove,
|
|
(LARGE_INTEGER *) plibNewPosition,
|
|
dwWin32Origin))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
|
|
goto Exit;
|
|
}
|
|
|
|
hr = NOERROR;
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::SetSize(
|
|
ULARGE_INTEGER libNewSize
|
|
)
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Entered CFileStreamBase::SetSize() !!! NOT IMPLEMENTED !!!\n");
|
|
|
|
UNUSED(libNewSize);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::CopyTo(
|
|
IStream *pstm,
|
|
ULARGE_INTEGER cb,
|
|
ULARGE_INTEGER *pcbRead,
|
|
ULARGE_INTEGER *pcbWritten
|
|
)
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Entered CFileStreamBase::CopyTo() !!! NOT IMPLEMENTED !!!\n");
|
|
|
|
if (pcbRead != NULL)
|
|
pcbRead->QuadPart = 0;
|
|
|
|
if (pcbWritten != NULL)
|
|
pcbWritten->QuadPart = 0;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::Commit(
|
|
DWORD grfCommitFlags
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_INFO,
|
|
"SXS.DLL: Entered CFileStreamBase::Commit()\n");
|
|
|
|
if (grfCommitFlags != 0)
|
|
return E_INVALIDARG;
|
|
|
|
if ( !Close())
|
|
hr = HRESULT_FROM_WIN32 (::FusionpGetLastWin32Error());
|
|
|
|
if (!SUCCEEDED(hr))
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: %s() failed; ::FusionpGetLastWin32Error() = %d\n", __FUNCTION__, ::FusionpGetLastWin32Error());
|
|
else
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_INFO,
|
|
"SXS.DLL: Leaving %s()\n", __FUNCTION__);
|
|
|
|
return hr ;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::Revert()
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Entered CFileStreamBase::Revert() !!! NOT IMPLEMENTED !!!\n");
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::LockRegion(
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType
|
|
)
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Entered CFileStreamBase::LockRegion() !!! NOT IMPLEMENTED !!!\n");
|
|
|
|
UNUSED(libOffset);
|
|
UNUSED(cb);
|
|
UNUSED(dwLockType);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::UnlockRegion(
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType
|
|
)
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Entered CFileStreamBase::UnlockRegion() !!! NOT IMPLEMENTED !!!\n");
|
|
|
|
UNUSED(libOffset);
|
|
UNUSED(cb);
|
|
UNUSED(dwLockType);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::Stat(
|
|
STATSTG *pstatstg,
|
|
DWORD grfStatFlag
|
|
)
|
|
{
|
|
HRESULT hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
|
|
FN_TRACE_HR(hr);
|
|
BY_HANDLE_FILE_INFORMATION bhfi;
|
|
|
|
if (pstatstg != NULL)
|
|
memset(pstatstg, 0, sizeof(*pstatstg));
|
|
|
|
PARAMETER_CHECK(((grfStatFlag & ~(STATFLAG_NONAME)) == 0));
|
|
PARAMETER_CHECK(pstatstg != NULL);
|
|
|
|
if (!(grfStatFlag & STATFLAG_NONAME))
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: %s() does not handle STATFLAG_NONE; returning E_NOTIMPL.\n", __FUNCTION__);
|
|
hr = E_NOTIMPL;
|
|
goto Exit;
|
|
}
|
|
|
|
INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
|
|
IFW32FALSE_ORIGINATE_AND_EXIT(::GetFileInformationByHandle(m_hFile, &bhfi));
|
|
|
|
pstatstg->pwcsName = NULL;
|
|
pstatstg->type = STGTY_STREAM;
|
|
pstatstg->cbSize.LowPart = bhfi.nFileSizeLow;
|
|
pstatstg->cbSize.HighPart = bhfi.nFileSizeHigh;
|
|
pstatstg->mtime = bhfi.ftLastWriteTime;
|
|
pstatstg->ctime = bhfi.ftCreationTime;
|
|
pstatstg->atime = bhfi.ftLastAccessTime;
|
|
pstatstg->grfMode = m_grfMode;
|
|
pstatstg->grfLocksSupported = LOCK_WRITE;
|
|
pstatstg->clsid = GUID_NULL;
|
|
pstatstg->grfStateBits = 0;
|
|
pstatstg->reserved = 0;
|
|
|
|
hr = NOERROR;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CFileStreamBase::Clone(
|
|
IStream **ppIStream
|
|
)
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Entered CFileStreamBase::Clone() !!! NOT IMPLEMENTED !!!\n");
|
|
|
|
if (ppIStream != NULL)
|
|
*ppIStream = NULL;
|
|
|
|
return E_NOTIMPL;
|
|
}
|