966 lines
28 KiB
C++
966 lines
28 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: filstm.cxx
|
|
//
|
|
// Contents: CNtFileStream implementation
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "headers.cxx"
|
|
#pragma hdrstop
|
|
|
|
#include "filstm.hxx"
|
|
|
|
#define ValidateLockType(lt) \
|
|
((lt) == LOCK_EXCLUSIVE || (lt) == LOCK_ONLYONCE)
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::QueryInterface, public
|
|
//
|
|
// Synopsis: Returns an object for the requested interface
|
|
//
|
|
// Arguments: [iid] - Interface ID
|
|
// [ppvObj] - Object return
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [ppvObj]
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::QueryInterface(REFIID iid, void **ppvObj)
|
|
{
|
|
SCODE sc;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::QueryInterface:%p(riid, %p)\n",
|
|
this, ppvObj));
|
|
if (!IsValidIid(iid))
|
|
ssErr(EH_Err, STG_E_INVALIDPARAMETER);
|
|
ssChk(Validate());
|
|
if (IsEqualIID(iid, IID_IStream) || IsEqualIID(iid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (IStream *)this;
|
|
CNtFileStream::AddRef();
|
|
}
|
|
else if(IsEqualIID(iid, IID_IOverlappedStream))
|
|
{
|
|
*ppvObj = (IOverlappedStream *) this;
|
|
CNtFileStream::AddRef();
|
|
}
|
|
else
|
|
{
|
|
sc = E_NOINTERFACE;
|
|
*ppvObj = NULL;
|
|
}
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::QueryInterface => %p\n",
|
|
*ppvObj));
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::CNtFileStream, public
|
|
//
|
|
// Synopsis: Empty object constructor
|
|
//
|
|
// History: 30-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CNtFileStream::CNtFileStream(void)
|
|
{
|
|
ssDebugOut((DEB_ITRACE, "In CNtFileStream::CNtFileStream:%p()\n", this));
|
|
_sig = 0;
|
|
ssDebugOut((DEB_ITRACE, "Out CNtFileStream::CNtFileStream\n"));
|
|
ENLIST_TRACKING(CNtFileStream);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::InitCommon, private
|
|
//
|
|
// Synopsis: Common initialization code
|
|
//
|
|
// Arguments: [co] - For detecting creation flags
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 28-Jul-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CNtFileStream::InitCommon(CREATEOPEN co)
|
|
{
|
|
NTSTATUS nts;
|
|
SCODE sc;
|
|
IO_STATUS_BLOCK iosb;
|
|
FILE_POSITION_INFORMATION fpi;
|
|
FILE_END_OF_FILE_INFORMATION feofi;
|
|
|
|
ssDebugOut((DEB_ITRACE, "In CNtFileStream::InitCommon:%p(%d)\n",
|
|
this, co));
|
|
|
|
// If we're supposed to be creating, truncate
|
|
// STGM_CREATE must have been passed since FAILIFTHERE always will fail
|
|
if (co == CO_CREATE)
|
|
{
|
|
feofi.EndOfFile.LowPart = 0;
|
|
feofi.EndOfFile.HighPart = 0;
|
|
nts = NtSetInformationFile(_h, &iosb, &feofi,
|
|
sizeof(FILE_END_OF_FILE_INFORMATION),
|
|
FileEndOfFileInformation);
|
|
if (!NT_SUCCESS(nts))
|
|
ssErr(EH_Err, NtStatusToScode(nts));
|
|
}
|
|
|
|
// Make sure the file pointer is at zero
|
|
fpi.CurrentByteOffset.LowPart = 0;
|
|
fpi.CurrentByteOffset.HighPart = 0;
|
|
nts = NtSetInformationFile(_h, &iosb, &fpi,
|
|
sizeof(FILE_POSITION_INFORMATION),
|
|
FilePositionInformation);
|
|
if (!NT_SUCCESS(nts))
|
|
sc = NtStatusToScode(nts);
|
|
else
|
|
sc = S_OK;
|
|
|
|
ssDebugOut((DEB_ITRACE, "Out CNtFileStream::InitCommon\n"));
|
|
EH_Err:
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::InitFromHandle, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// Arguments: [h] - Handle to duplicate
|
|
// [grfMode] - Mode of handle
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 08-Jul-93 DrewB Created
|
|
//
|
|
// Notes: Takes a new reference on the given handle
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CNtFileStream::InitFromHandle(HANDLE h,
|
|
DWORD grfMode,
|
|
CREATEOPEN co,
|
|
LPSTGSECURITY pssSecurity)
|
|
{
|
|
SCODE sc;
|
|
|
|
ssDebugOut((DEB_ITRACE, "In CNtFileStream::InitFromHandle:%p("
|
|
"%p, %lX, %d, %p)\n", this, h, grfMode, co, pssSecurity));
|
|
|
|
ssChk(ValidateMode(grfMode));
|
|
if (pssSecurity != NULL)
|
|
ssErr(EH_Err, STG_E_INVALIDPARAMETER);
|
|
ssChk(ReopenNtHandle(h, grfMode, FD_FILE, &_h));
|
|
|
|
ssAssert(co != CO_CREATE || (grfMode & STGM_CREATE));
|
|
ssChk(InitCommon(co));
|
|
|
|
_grfMode = grfMode;
|
|
_sig = CNTFILESTREAM_SIG;
|
|
|
|
ssDebugOut((DEB_ITRACE, "Out CNtFileStream::InitFromHandle\n"));
|
|
EH_Err:
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::InitFromPath, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// Arguments: [h] - Handle to duplicate
|
|
// [grfMode] - Mode of handle
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 08-Jul-95 HenryLee Created
|
|
//
|
|
// Notes: Takes a new reference on the given handle
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CNtFileStream::InitFromPath(HANDLE hParent,
|
|
const WCHAR *pwcsName,
|
|
DWORD grfMode,
|
|
DWORD grfAttr,
|
|
CREATEOPEN co,
|
|
LPSTGSECURITY pssSecurity)
|
|
{
|
|
SCODE sc;
|
|
|
|
ssDebugOut((DEB_ITRACE, "In CNtFileStream::InitFromPath:%p("
|
|
"%p, %lX, %ws, %d, %p)\n", this, hParent, pwcsName,
|
|
grfMode, co, pssSecurity));
|
|
|
|
ssChk(ValidateMode(grfMode));
|
|
if (pssSecurity != NULL)
|
|
ssErr(EH_Err, STG_E_INVALIDPARAMETER);
|
|
ssChk(GetNtHandle(hParent, pwcsName, grfMode, grfAttr, co, FD_FILE,
|
|
(LPSECURITY_ATTRIBUTES) pssSecurity,&_h));
|
|
|
|
//ssAssert(co != CO_CREATE || (grfMode & STGM_CREATE));
|
|
ssChk(InitCommon(co));
|
|
|
|
_grfMode = grfMode;
|
|
_sig = CNTFILESTREAM_SIG;
|
|
|
|
ssDebugOut((DEB_ITRACE, "Out CNtFileStream::InitFromPath\n"));
|
|
EH_Err:
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::InitClone, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// Arguments: [h] - Handle to duplicate
|
|
// [grfMode] - Mode of handle
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 08-Jul-93 DrewB Created
|
|
//
|
|
// Notes: Takes a new reference on the given handle
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CNtFileStream::InitClone(HANDLE h, DWORD grfMode)
|
|
{
|
|
SCODE sc;
|
|
|
|
ssDebugOut((DEB_ITRACE, "In CNtFileStream::InitClone:%p(%p, %lX)\n",
|
|
this, h, grfMode));
|
|
|
|
ssChk(ValidateMode(grfMode));
|
|
ssChk(DupNtHandle(h, &_h));
|
|
|
|
_grfMode = grfMode;
|
|
_sig = CNTFILESTREAM_SIG;
|
|
|
|
ssDebugOut((DEB_ITRACE, "Out CNtFileStream::InitClone\n"));
|
|
EH_Err:
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::~CNtFileStream, public
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CNtFileStream::~CNtFileStream(void)
|
|
{
|
|
ssDebugOut((DEB_ITRACE, "In CNtFileStream::~CNtFileStream:%p()\n", this));
|
|
_sig = CNTFILESTREAM_SIGDEL;
|
|
ssDebugOut((DEB_ITRACE, "Out CNtFileStream::~CNtFileStream\n"));
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::Read, public
|
|
//
|
|
// Synopsis: Read from a stream
|
|
//
|
|
// Arguments: [pb] - Buffer
|
|
// [cb] - Count of bytes to read
|
|
// [pcbRead] - Return number of bytes read
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [pcbRead]
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::Read(VOID *pb, ULONG cb, ULONG *pcbRead)
|
|
{
|
|
SCODE sc;
|
|
NTSTATUS nts;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::Read:%p(%p, %lu, %p)\n",
|
|
this, pb, cb, pcbRead));
|
|
|
|
sc = S_OK;
|
|
ssChk(Validate());
|
|
|
|
ssAssert(_h != NULL);
|
|
nts = NtReadFile(_h, NULL, NULL, NULL, &iosb, pb, cb, NULL, NULL);
|
|
if (!NT_SUCCESS(nts))
|
|
{
|
|
if (nts != STATUS_END_OF_FILE)
|
|
sc = NtStatusToScode(nts);
|
|
else
|
|
iosb.Information = 0;
|
|
}
|
|
if (pcbRead)
|
|
{
|
|
if (SUCCEEDED(sc))
|
|
*pcbRead = iosb.Information;
|
|
else
|
|
*pcbRead = 0;
|
|
}
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::Read => %lu\n",
|
|
iosb.Information));
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::Write, public
|
|
//
|
|
// Synopsis: Write to a stream
|
|
//
|
|
// Arguments: [pb] - Buffer
|
|
// [cb] - Count of bytes to write
|
|
// [pcbWritten] - Return of bytes written
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [pcbWritten]
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::Write(VOID const *pb,
|
|
ULONG cb,
|
|
ULONG *pcbWritten)
|
|
{
|
|
SCODE sc;
|
|
NTSTATUS nts;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::Write:%p(%p, %lu, %p)\n",
|
|
this, pb, cb, pcbWritten));
|
|
|
|
sc = S_OK;
|
|
ssChk(Validate());
|
|
|
|
ssAssert(_h != NULL);
|
|
nts = NtWriteFile(_h, NULL, NULL, NULL, &iosb, (void *)pb, cb,
|
|
NULL, NULL);
|
|
if (!NT_SUCCESS(nts))
|
|
sc = NtStatusToScode(nts);
|
|
if (pcbWritten)
|
|
{
|
|
if (SUCCEEDED(sc))
|
|
*pcbWritten = iosb.Information;
|
|
else
|
|
*pcbWritten = 0;
|
|
}
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::Write => %lu\n",
|
|
iosb.Information));
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::Seek, public
|
|
//
|
|
// Synopsis: Seek to a point in a stream
|
|
//
|
|
// Arguments: [dlibMove] - Offset to move by
|
|
// [dwOrigin] - SEEK_SET, SEEK_CUR, SEEK_END
|
|
// [plibNewPosition] - Return of new offset
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [plibNewPosition]
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::Seek(LARGE_INTEGER dlibMove,
|
|
DWORD dwOrigin,
|
|
ULARGE_INTEGER *plibNewPosition)
|
|
{
|
|
SCODE sc;
|
|
NTSTATUS nts;
|
|
IO_STATUS_BLOCK iosb;
|
|
FILE_POSITION_INFORMATION fpi;
|
|
FILE_STANDARD_INFORMATION fsi;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::Seek:%p(%ld:%ld, %lu, %p)\n",
|
|
this, dlibMove.HighPart, dlibMove.LowPart, dwOrigin,
|
|
plibNewPosition));
|
|
|
|
if (dwOrigin != STREAM_SEEK_SET && dwOrigin != STREAM_SEEK_CUR &&
|
|
dwOrigin != STREAM_SEEK_END)
|
|
ssErr(EH_Err, STG_E_INVALIDFUNCTION);
|
|
|
|
ssAssert(_h != NULL);
|
|
switch(dwOrigin)
|
|
{
|
|
case STREAM_SEEK_SET:
|
|
fpi.CurrentByteOffset.LowPart = dlibMove.LowPart;
|
|
fpi.CurrentByteOffset.HighPart = dlibMove.HighPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_CUR:
|
|
nts = NtQueryInformationFile(_h, &iosb, &fpi,
|
|
sizeof(FILE_POSITION_INFORMATION),
|
|
FilePositionInformation);
|
|
if (!NT_SUCCESS(nts))
|
|
ssErr(EH_Err, NtStatusToScode(nts));
|
|
|
|
// Check for seek before beginning and overflow
|
|
if (dlibMove.HighPart < 0)
|
|
{
|
|
if ((-dlibMove.QuadPart) > fpi.CurrentByteOffset.QuadPart)
|
|
ssErr(EH_Err, STG_E_INVALIDFUNCTION);
|
|
}
|
|
else if (!((fpi.CurrentByteOffset.QuadPart + dlibMove.QuadPart) >=
|
|
fpi.CurrentByteOffset.QuadPart))
|
|
{
|
|
ssErr(EH_Err, STG_E_INVALIDFUNCTION);
|
|
}
|
|
|
|
fpi.CurrentByteOffset.QuadPart =
|
|
fpi.CurrentByteOffset.QuadPart + dlibMove.QuadPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_END:
|
|
nts = NtQueryInformationFile(_h, &iosb, &fsi,
|
|
sizeof(FILE_STANDARD_INFORMATION),
|
|
FileStandardInformation);
|
|
if (!NT_SUCCESS(nts))
|
|
ssErr(EH_Err, NtStatusToScode(nts));
|
|
|
|
// Check for seek before beginning and overflow
|
|
if (dlibMove.HighPart < 0)
|
|
{
|
|
if ((-dlibMove.QuadPart) > fsi.EndOfFile.QuadPart)
|
|
ssErr(EH_Err, STG_E_INVALIDFUNCTION);
|
|
}
|
|
else if (!((fsi.EndOfFile.QuadPart + dlibMove.QuadPart) >=
|
|
fsi.EndOfFile.QuadPart))
|
|
{
|
|
ssErr(EH_Err, STG_E_INVALIDFUNCTION);
|
|
}
|
|
|
|
fpi.CurrentByteOffset.QuadPart =
|
|
fsi.EndOfFile.QuadPart + dlibMove.QuadPart;
|
|
break;
|
|
}
|
|
|
|
sc = S_OK;
|
|
nts = NtSetInformationFile(_h, &iosb, &fpi,
|
|
sizeof(FILE_POSITION_INFORMATION),
|
|
FilePositionInformation);
|
|
if (!NT_SUCCESS(nts))
|
|
sc = NtStatusToScode(nts);
|
|
else if (plibNewPosition)
|
|
*plibNewPosition = *(ULARGE_INTEGER *)&fpi.CurrentByteOffset;
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::Seek => %lu:%lu\n",
|
|
fpi.CurrentByteOffset.HighPart,
|
|
fpi.CurrentByteOffset.LowPart));
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::SetSize, public
|
|
//
|
|
// Synopsis: Sets the size of a stream
|
|
//
|
|
// Arguments: [ulNewSize] - New size
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::SetSize(ULARGE_INTEGER ulNewSize)
|
|
{
|
|
SCODE sc;
|
|
IO_STATUS_BLOCK iosb;
|
|
FILE_END_OF_FILE_INFORMATION feofi;
|
|
NTSTATUS nts;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::SetSize:%p(%lu:%lu)\n",
|
|
this, ulNewSize.HighPart, ulNewSize.LowPart));
|
|
|
|
sc = S_OK;
|
|
ssChk(Validate());
|
|
|
|
feofi.EndOfFile.LowPart = ulNewSize.LowPart;
|
|
feofi.EndOfFile.HighPart = (ULONG)ulNewSize.HighPart;
|
|
ssAssert(_h != NULL);
|
|
nts = NtSetInformationFile(_h, &iosb, &feofi,
|
|
sizeof(FILE_END_OF_FILE_INFORMATION),
|
|
FileEndOfFileInformation);
|
|
if (!NT_SUCCESS(nts))
|
|
ssErr(EH_Err, NtStatusToScode(nts));
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::SetSize\n"));
|
|
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::CopyTo, public
|
|
//
|
|
// Synopsis: Copies information from one stream to another
|
|
//
|
|
// Arguments: [pstm] - Destination
|
|
// [cb] - Number of bytes to copy
|
|
// [pcbRead] - Return number of bytes read
|
|
// [pcbWritten] - Return number of bytes written
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [pcbRead]
|
|
// [pcbWritten]
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
// Notes: We do our best to handle overlap correctly. This allows
|
|
// CopyTo to be used to insert and remove space within a
|
|
// stream.
|
|
//
|
|
// In the error case, we make no gurantees as to the
|
|
// validity of pcbRead, pcbWritten, or either stream's
|
|
// seek position.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#define CBBUFFER 8192
|
|
|
|
STDMETHODIMP CNtFileStream::CopyTo(IStream *pstm,
|
|
ULARGE_INTEGER cb,
|
|
ULARGE_INTEGER *pcbRead,
|
|
ULARGE_INTEGER *pcbWritten)
|
|
{
|
|
SCODE sc;
|
|
LARGE_INTEGER cbRead = {0, 0}, cbWritten = {0, 0}, cbDone;
|
|
LARGE_INTEGER liPosFrom, liPosTo, liTmp;
|
|
LARGE_INTEGER liZero = {0, 0};
|
|
LARGE_INTEGER liStep;
|
|
LARGE_INTEGER licb;
|
|
BOOL fForward;
|
|
ULONG ulcbDone, cbDo;
|
|
SafeBytePtr pbBuffer;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::CopyTo:%p("
|
|
"%p, %lu:%lu, %p, %p)\n",
|
|
this, pstm, cb.HighPart, cb.LowPart, pcbRead, pcbWritten));
|
|
|
|
// BUGBUG - Possible 63-bit overflow problems?
|
|
|
|
if (!IsValidInterface(pstm))
|
|
ssErr(EH_Err, STG_E_INVALIDPARAMETER);
|
|
sc = S_OK;
|
|
ssChk(Validate());
|
|
|
|
if (cb.HighPart >= 0x80000000)
|
|
cb.HighPart = 0x7fffffff;
|
|
licb = *(LARGE_INTEGER *)&cb;
|
|
|
|
pbBuffer.Attach(new BYTE[CBBUFFER]);
|
|
ssMem((BYTE *)pbBuffer);
|
|
|
|
ssHChk(Seek(liZero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&liPosFrom));
|
|
ssHChk(pstm->Seek(liZero, STREAM_SEEK_CUR,
|
|
(ULARGE_INTEGER *)&liPosTo));
|
|
|
|
// Determine which direction to copy to avoid overlap problems
|
|
if (!(liPosFrom.QuadPart >= liPosTo.QuadPart) &&
|
|
(licb.QuadPart > liStep.QuadPart))
|
|
{
|
|
liStep.HighPart = -1;
|
|
liStep.LowPart = (ULONG)(-CBBUFFER);
|
|
fForward = FALSE;
|
|
|
|
// Seek to the end of the copy area plus one step
|
|
// so that we're in place for the loop seek backwards
|
|
liTmp.QuadPart = liPosFrom.QuadPart + licb.QuadPart;
|
|
liTmp.QuadPart = liTmp.QuadPart - liStep.QuadPart;
|
|
ssHChk(Seek(liTmp, STREAM_SEEK_SET, NULL));
|
|
liTmp.QuadPart = liPosTo.QuadPart + licb.QuadPart;
|
|
liTmp.QuadPart = liTmp.QuadPart - liStep.QuadPart;
|
|
ssHChk(pstm->Seek(liTmp, STREAM_SEEK_SET, NULL));
|
|
|
|
// We seek backwards by twice the step size, once
|
|
// to back up beyond the step we just read and once
|
|
// more to back up to a fresh step worth of data
|
|
ssAssert(CBBUFFER <= 0x3fffffff);
|
|
liStep.LowPart *= 2;
|
|
}
|
|
else
|
|
{
|
|
liStep.HighPart = 0;
|
|
liStep.LowPart = CBBUFFER;
|
|
fForward = TRUE;
|
|
}
|
|
|
|
cbDone.HighPart = 0;
|
|
for (;;)
|
|
{
|
|
if (licb.HighPart == 0 && licb.LowPart < CBBUFFER)
|
|
cbDo = licb.LowPart;
|
|
else
|
|
cbDo = CBBUFFER;
|
|
|
|
if (!fForward)
|
|
{
|
|
// If we're doing the last fragment make sure we don't overshoot
|
|
// when backing up
|
|
if (cbDo < CBBUFFER)
|
|
{
|
|
liStep.LowPart /= 2;
|
|
liStep.LowPart -= CBBUFFER-(LONG)cbDo;
|
|
}
|
|
|
|
// Seek backwards to fresh data
|
|
ssHChkTo(EH_End, Seek(liStep, STREAM_SEEK_CUR, NULL));
|
|
ssHChkTo(EH_End, pstm->Seek(liStep, STREAM_SEEK_CUR, NULL));
|
|
}
|
|
|
|
ssHChkTo(EH_End, Read(pbBuffer, cbDo, &cbDone.LowPart));
|
|
if (cbDone.LowPart == 0)
|
|
break;
|
|
cbRead.QuadPart = cbRead.QuadPart + cbDone.QuadPart;
|
|
ssHChkTo(EH_End, pstm->Write(pbBuffer, cbDone.LowPart,
|
|
&ulcbDone));
|
|
if (ulcbDone != cbDone.LowPart)
|
|
ssErr(EH_End, STG_E_WRITEFAULT);
|
|
cbWritten.QuadPart = cbWritten.QuadPart + cbDone.QuadPart;
|
|
|
|
licb.QuadPart = licb.QuadPart - cbDone.QuadPart;
|
|
if (licb.HighPart < 0 ||
|
|
(licb.HighPart == 0 && licb.LowPart == 0))
|
|
break;
|
|
}
|
|
|
|
EH_End:
|
|
if (pcbRead)
|
|
*(LARGE_INTEGER *)pcbRead = cbRead;
|
|
if (pcbWritten)
|
|
*(LARGE_INTEGER *)pcbWritten = cbWritten;
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::CopyTo => %lu:%lu, %lu:%lu\n",
|
|
cbRead.HighPart, cbRead.LowPart, cbWritten.HighPart,
|
|
cbWritten.LowPart));
|
|
// Fall through
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::Commit, public
|
|
//
|
|
// Synopsis: Commits transacted changes
|
|
//
|
|
// Arguments: [grfCommitFlags] - Flags
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::Commit(DWORD grfCommitFlags)
|
|
{
|
|
NTSTATUS nts;
|
|
SCODE sc;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::Commit:%p(%lX)\n",
|
|
this, grfCommitFlags));
|
|
|
|
ssChk(VerifyCommitFlags(grfCommitFlags));
|
|
ssChk(Validate());
|
|
|
|
ssAssert(_h != NULL);
|
|
nts = NtFlushBuffersFile(_h, &iosb);
|
|
if (!NT_SUCCESS(nts))
|
|
sc = NtStatusToScode(nts);
|
|
else
|
|
sc = S_OK;
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::Commit => %lX\n", sc));
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::Revert, public
|
|
//
|
|
// Synopsis: Reverts transacted changes
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::Revert(void)
|
|
{
|
|
ssDebugOut((DEB_TRACE, "Stb CNtFileStream::Revert()\n"));
|
|
return NOERROR;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::LockRegion, public
|
|
//
|
|
// Synopsis: Locks a portion of the stream
|
|
//
|
|
// Arguments: [libOffset] - Offset to lock at
|
|
// [cb] - Length of lock
|
|
// [dwLockType] - LockType
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::LockRegion(ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
SCODE sc;
|
|
NTSTATUS nts;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::LockRegion:%p("
|
|
"%lu:%lu, %lu:%lu, %lu)\n", this, libOffset.HighPart,
|
|
libOffset.LowPart, cb.HighPart, cb.LowPart, dwLockType));
|
|
|
|
sc = S_OK;
|
|
ssChk(Validate());
|
|
ssChk(ValidateLockType(dwLockType));
|
|
|
|
ssAssert(_h != NULL);
|
|
nts = NtLockFile(_h, NULL, NULL, NULL, &iosb, (PLARGE_INTEGER)&libOffset,
|
|
(PLARGE_INTEGER)&cb, 0, TRUE, TRUE);
|
|
if (!NT_SUCCESS(nts))
|
|
sc = NtStatusToScode(nts);
|
|
else
|
|
sc = S_OK;
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::LockRegion\n"));
|
|
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::UnlockRegion, public
|
|
//
|
|
// Synopsis: Unlocks a locked region
|
|
//
|
|
// Arguments: [libOffset] - Offset to lock at
|
|
// [cb] - Length of lock
|
|
// [dwLockType] - LockType
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::UnlockRegion(ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
SCODE sc;
|
|
NTSTATUS nts;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::UnlockRegion:%p("
|
|
"%lu:%lu, %lu:%lu, %lu)\n", this, libOffset.HighPart,
|
|
libOffset.LowPart, cb.HighPart, cb.LowPart, dwLockType));
|
|
|
|
sc = S_OK;
|
|
ssChk(Validate());
|
|
ssChk(ValidateLockType(dwLockType));
|
|
|
|
ssAssert(_h != NULL);
|
|
nts = NtUnlockFile(_h, &iosb, (PLARGE_INTEGER)&libOffset,
|
|
(PLARGE_INTEGER)&cb, 0);
|
|
if (!NT_SUCCESS(nts))
|
|
sc = NtStatusToScode(nts);
|
|
else
|
|
sc = S_OK;
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::UnlockRegion\n"));
|
|
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::Stat, public
|
|
//
|
|
// Synopsis: Fills in a buffer of information about this object
|
|
//
|
|
// Arguments: [pstatstg] - Buffer
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [pstatstg]
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
|
|
{
|
|
SCODE sc;
|
|
STATSTG stat;
|
|
FILEDIR fd;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::Stat:%p(%p, %lX)\n",
|
|
this, pstatstg, grfStatFlag));
|
|
|
|
ssChk(VerifyStatFlag(grfStatFlag));
|
|
ssChk(Validate());
|
|
|
|
__try
|
|
{
|
|
// \CONTENTS must be appended to name
|
|
ssAssert(_h != NULL);
|
|
sc = StatNtHandle(_h, grfStatFlag,
|
|
sizeof(CONTENTS_STREAM)+sizeof(WCHAR), &stat,
|
|
NULL, NULL, &fd);
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
if (stat.pwcsName)
|
|
{
|
|
WCHAR *pwcs;
|
|
|
|
pwcs = stat.pwcsName+lstrlenW(stat.pwcsName);
|
|
*pwcs++ = L'\\';
|
|
lstrcpyW(pwcs, CONTENTS_STREAM);
|
|
}
|
|
stat.grfMode = _grfMode;
|
|
stat.type = STGTY_STREAM;
|
|
stat.mtime.dwLowDateTime = stat.mtime.dwHighDateTime = 0;
|
|
stat.atime.dwLowDateTime = stat.atime.dwHighDateTime = 0;
|
|
stat.ctime.dwLowDateTime = stat.ctime.dwHighDateTime = 0;
|
|
stat.grfLocksSupported = LOCK_EXCLUSIVE | LOCK_ONLYONCE;
|
|
*pstatstg = stat;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
if (stat.pwcsName)
|
|
ssVerSucc(CoMemFree(stat.pwcsName));
|
|
sc = HRESULT_FROM_NT(GetExceptionCode());
|
|
}
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::Stat\n"));
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::Clone, public
|
|
//
|
|
// Synopsis: Clones a stream
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 28-Jun-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CNtFileStream::Clone(IStream **ppstm)
|
|
{
|
|
SCODE sc;
|
|
SafeCNtFileStream pfs;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CNtFileStream::Clone:%p(%p)\n",
|
|
this, ppstm));
|
|
|
|
sc = S_OK;
|
|
ssChk(Validate());
|
|
|
|
pfs.Attach(new CNtFileStream());
|
|
ssMem((CNtFileStream *)pfs);
|
|
ssAssert(_h != NULL);
|
|
ssChk(pfs->InitClone(_h, _grfMode));
|
|
TRANSFER_INTERFACE(pfs, IStream, ppstm);
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CNtFileStream::Clone => %p\n", *ppstm));
|
|
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNtFileStream::ValidateMode, private
|
|
//
|
|
// Synopsis: Validates a mode
|
|
//
|
|
// Arguments: [grfMode] - Mode
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 09-Jul-93 DrewB Created
|
|
//
|
|
// Notes: Streams allow any sharing permissions but ignore all of them
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CNtFileStream::ValidateMode(DWORD grfMode)
|
|
{
|
|
SCODE sc;
|
|
|
|
ssDebugOut((DEB_ITRACE, "In CNtFileStream::ValidateMode:%p(0x%lX)\n",
|
|
this, grfMode));
|
|
if ((grfMode & (STGM_TRANSACTED | STGM_PRIORITY | STGM_DELETEONRELEASE |
|
|
STGM_CONVERT)))
|
|
sc = STG_E_INVALIDFLAG;
|
|
else
|
|
sc = S_OK;
|
|
ssDebugOut((DEB_ITRACE, "Out CNtFileStream::ValidateMode => 0x%lX\n"));
|
|
return sc;
|
|
}
|