windows-nt/Source/XPSP1/NT/base/win32/fusion/sxs/filestream.cpp
2020-09-26 16:20:57 +08:00

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;
}