1265 lines
32 KiB
C++
1265 lines
32 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1992.
|
|
//
|
|
// File: tstream.cxx
|
|
//
|
|
// Contents: Transacted stream functions
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 23-Jan-92 PhilipLa Created.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "msfhead.cxx"
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "tstream.hxx"
|
|
#include "dl.hxx"
|
|
#include "mread.hxx"
|
|
#include <handle.hxx>
|
|
#include <memory.h>
|
|
#include <dfdeb.hxx>
|
|
|
|
#define DEB_TSTREAM (DEB_ITRACE | 0x00200000)
|
|
|
|
//+--------------------------------------------------------------
|
|
//
|
|
// Member: CTransactedStream::CTransactedStream, public
|
|
//
|
|
// Synopsis: Empty object ctor
|
|
//
|
|
// Arguments: [pdfn] - Name
|
|
// [dl] - LUID
|
|
// [df] -- Permissions flags
|
|
// [dwType] - Entry type
|
|
// [pmsScratch] -- Scratch multistream
|
|
//
|
|
// History: 31-Jul-92 DrewB Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
CTransactedStream::CTransactedStream(CDfName const *pdfn,
|
|
DFLUID dl,
|
|
DFLAGS df,
|
|
CMStream *pms,
|
|
CMStream *pmsScratch)
|
|
: PTSetMember(pdfn, STGTY_STREAM),
|
|
PSStream(dl),
|
|
_dl(pms, pmsScratch)
|
|
{
|
|
msfDebugOut((DEB_ITRACE, "In CTransactedStream::CTransactedStream:%p("
|
|
"%lu)\n", this, dl));
|
|
|
|
_pssBase = NULL;
|
|
_pdlOld = NULL;
|
|
_df = df;
|
|
_cReferences = 0;
|
|
_fDirty = 0;
|
|
_fBeginCommit = FALSE;
|
|
PBasicEntry::_sig = CTRANSACTEDSTREAM_SIG;
|
|
PTSetMember::_sig = CTRANSACTEDSTREAM_SIG;
|
|
msfDebugOut((DEB_ITRACE, "Out CTransactedStream::CTransactedStream\n"));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::Init, public
|
|
//
|
|
// Synopsis: CTransactedStream constructor
|
|
//
|
|
// Arguments: [pssBase] -- Pointer to base stream
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 23-Jan-92 PhilipLa Created.
|
|
// 31-Jul-92 DrewB Converted to Init from ctor
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::Init(PSStream *pssBase)
|
|
{
|
|
SCODE sc;
|
|
|
|
msfDebugOut((DEB_ITRACE,"In %p:CTransactedStream constructor(%p)\n",
|
|
this, pssBase));
|
|
|
|
msfChk(SetInitialState(pssBase));
|
|
|
|
_pssBase = P_TO_BP(CBasedSStreamPtr, pssBase);
|
|
|
|
_sectLastUsed = 0;
|
|
|
|
AddRef();
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream constructor\n"));
|
|
// Fall through
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::~CTransactedStream, public
|
|
//
|
|
// Synopsis: CTransactedStream destructor
|
|
//
|
|
// History: 23-Jan-92 PhilipLa Created.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
CTransactedStream::~CTransactedStream()
|
|
{
|
|
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream Destructor\n"));
|
|
msfAssert(_cReferences == 0);
|
|
|
|
PBasicEntry::_sig = CTRANSACTEDSTREAM_SIGDEL;
|
|
PTSetMember::_sig = CTRANSACTEDSTREAM_SIGDEL;
|
|
_dl.Empty();
|
|
|
|
if (_pssBase)
|
|
{
|
|
_pssBase->Release();
|
|
}
|
|
|
|
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream Destructor\n"));
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTransactedStream::ReadAt, public
|
|
//
|
|
// Synposis: Reads binary data from a transacted stream
|
|
//
|
|
// Arguments: [ulOffset] -- Position to be read from
|
|
//
|
|
// [pBuffer] -- Pointer to the area into which the data
|
|
// will be read.
|
|
// [ulCount] -- Indicates the number of bytes to be read
|
|
// [pulRetval] -- Area into which return value will be stored
|
|
//
|
|
// Returns: S_OK if call completed OK.
|
|
//
|
|
// Algorithm: *Finish This*
|
|
//
|
|
// History: 22-Jan-92 PhilipLa Created.
|
|
//
|
|
// Notes: [pBuffer] may be unsafe memory
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::ReadAt(
|
|
#ifdef LARGE_STREAMS
|
|
ULONGLONG ulOffset,
|
|
#else
|
|
ULONG ulOffset,
|
|
#endif
|
|
VOID HUGEP *pBuffer,
|
|
ULONG ulCount,
|
|
ULONG STACKBASED *pulRetval)
|
|
{
|
|
|
|
msfDebugOut((DEB_ITRACE,"In %p:CTransactedStream::ReadAt(%lu,%p,%lu)\n",this,ulOffset,pBuffer,ulCount));
|
|
SCODE sc;
|
|
|
|
if (ulOffset + ulCount > _ulSize)
|
|
{
|
|
#ifdef LARGE_STREAMS
|
|
if (_ulSize - ulOffset > ULONG_MAX) // too far past the end
|
|
ulCount = 0;
|
|
else
|
|
#endif
|
|
ulCount = (ULONG)(_ulSize - ulOffset);
|
|
}
|
|
|
|
if ((ulCount == 0) || (ulOffset > _ulSize))
|
|
{
|
|
*pulRetval = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
msfAssert(P_TRANSACTED(_df));
|
|
|
|
|
|
if (_dl.IsEmpty())
|
|
{
|
|
//If we have an empty delta list, either our size is 0 (in which
|
|
// case we'll never get to this line), or we have a parent.
|
|
|
|
msfAssert(_pssBase != NULL);
|
|
msfDebugOut((DEB_ITRACE,"Calling up to _pssBase\n"));
|
|
sc = _pssBase->ReadAt(ulOffset,pBuffer,ulCount,pulRetval);
|
|
msfDebugOut((DEB_ITRACE,
|
|
"Out CTransactedStream::ReadAt()=>%lu, ret is %lu\n",
|
|
sc, *pulRetval));
|
|
|
|
return sc;
|
|
}
|
|
|
|
ILockBytes *pilbDirty = _dl.GetDataILB();
|
|
USHORT cbSector = _dl.GetDataSectorSize();
|
|
USHORT uSectorShift = _dl.GetDataSectorShift();
|
|
|
|
ULONG temp = 0;
|
|
ULONG cb = 0;
|
|
|
|
|
|
|
|
SECT snow =(SECT)(ulOffset / cbSector);
|
|
OFFSET off = (OFFSET)(ulOffset % cbSector);
|
|
|
|
SECT send = (SECT)((ulOffset + ulCount - 1) / cbSector);
|
|
OFFSET offEnd = (OFFSET)((ulOffset + ulCount - 1) % cbSector);
|
|
|
|
USHORT csect = 0;
|
|
SECT sectNext;
|
|
SECT sectCurrent = snow;
|
|
BYTE HUGEP *pb = (BYTE HUGEP *)pBuffer;
|
|
USHORT oStart = off;
|
|
USHORT oEnd = 0;
|
|
|
|
|
|
SECT sectLast = ENDOFCHAIN;
|
|
SECT sectFirst = ENDOFCHAIN;
|
|
|
|
const USHORT ISDIRTY = 0;
|
|
const USHORT ISBASE = 1;
|
|
|
|
USHORT uLast;
|
|
|
|
msfChk(_dl.GetMap(sectCurrent, DL_READ, §Next));
|
|
if (sectNext != ENDOFCHAIN)
|
|
{
|
|
uLast = ISDIRTY;
|
|
sectLast = sectFirst = sectNext;
|
|
}
|
|
else
|
|
{
|
|
uLast = ISBASE;
|
|
sectLast = sectFirst = sectCurrent;
|
|
}
|
|
|
|
sectCurrent++;
|
|
|
|
while (sectCurrent <= send)
|
|
{
|
|
SECT sectNext;
|
|
msfChk(_dl.GetMap(sectCurrent, DL_READ, §Next));
|
|
|
|
//If any of the following occur, read the current segment:
|
|
// 1) Sector has mapping and current segment is in base
|
|
// 2) Sector has mapping and is not contiguous with
|
|
// current segment.
|
|
// 3) Sector has no mapping and current segment is in dirty.
|
|
|
|
if (((sectNext != ENDOFCHAIN) && (uLast == ISBASE)) ||
|
|
((sectNext != ENDOFCHAIN) && (sectNext != sectLast + 1)) ||
|
|
((sectNext == ENDOFCHAIN) && (uLast == ISDIRTY)))
|
|
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"Reading block from pssLast\n"));
|
|
|
|
if (uLast == ISDIRTY)
|
|
{
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(
|
|
sectFirst,
|
|
oStart,
|
|
uSectorShift);
|
|
#else
|
|
ULISet32(ulTmp, ConvertSectOffset(
|
|
sectFirst,
|
|
oStart,
|
|
uSectorShift));
|
|
#endif
|
|
msfHChk(pilbDirty->ReadAt(
|
|
ulTmp,
|
|
pb,
|
|
(sectLast - sectFirst + 1) * cbSector - oStart - oEnd,
|
|
&temp));
|
|
}
|
|
else
|
|
{
|
|
msfChk(_pssBase->ReadAt(
|
|
sectFirst * cbSector + oStart,
|
|
pb,
|
|
(sectLast - sectFirst + 1) * cbSector - oStart - oEnd,
|
|
(ULONG STACKBASED *)&temp));
|
|
}
|
|
|
|
pb += temp;
|
|
cb += temp;
|
|
oStart = 0;
|
|
|
|
if (sectNext == ENDOFCHAIN)
|
|
{
|
|
sectFirst = sectCurrent;
|
|
uLast = ISBASE;
|
|
}
|
|
else
|
|
{
|
|
sectFirst = sectNext;
|
|
uLast = ISDIRTY;
|
|
}
|
|
}
|
|
|
|
sectLast = (sectNext == ENDOFCHAIN) ? sectCurrent : sectNext;
|
|
sectCurrent++;
|
|
|
|
}
|
|
|
|
oEnd = (cbSector - 1) - offEnd;
|
|
msfDebugOut((DEB_ITRACE,"Reading last sector block\n"));
|
|
if (uLast == ISDIRTY)
|
|
{
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectFirst, oStart, uSectorShift);
|
|
#else
|
|
ULISet32(ulTmp,
|
|
ConvertSectOffset(sectFirst, oStart, uSectorShift));
|
|
#endif
|
|
msfHChk(pilbDirty->ReadAt(
|
|
ulTmp,
|
|
pb,
|
|
(sectLast - sectFirst + 1) * cbSector - oStart - oEnd,
|
|
&temp));
|
|
}
|
|
else
|
|
{
|
|
msfChk(_pssBase->ReadAt(
|
|
sectFirst * cbSector + oStart,
|
|
pb,
|
|
(sectLast - sectFirst + 1) * cbSector - oStart - oEnd,
|
|
(ULONG STACKBASED *)&temp));
|
|
}
|
|
|
|
pb += temp;
|
|
cb += temp;
|
|
oStart = 0;
|
|
|
|
*pulRetval = cb;
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::ReadAt()=>%lu, ret is %lu\n",(ULONG)S_OK,*pulRetval));
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTransactedStream::WriteAt, public
|
|
//
|
|
// Synposis: Writes binary data to a linear single stream
|
|
//
|
|
// Effects: Modifies _ulSeekPos. May cause modification in parent
|
|
// MStream.
|
|
//
|
|
// Arguments: [pBuffer] -- Pointer to the area from which the data
|
|
// will be written.
|
|
// [ulCount] -- Indicates the number of bytes to be written
|
|
// [pulRetval] -- Pointer to area in which number of bytes
|
|
// will be returned
|
|
//
|
|
// Returns: Error code of MStream call.
|
|
//
|
|
// Algorithm: Calculate sector and offset for beginning and end of
|
|
// write, then pass call up to MStream.
|
|
//
|
|
//
|
|
// History: 18-Jul-91 PhilipLa Created.
|
|
// 16-Aug-91 PhilipLa Converted to use multi-sect write
|
|
// 23-Aug-91 PhilipLa Brought into compliance with protocol
|
|
// 11-Sep-91 PhilipLa Moved most functionality up
|
|
// to MStream level.
|
|
//
|
|
// Notes: [pBuffer] may be unsafe memory
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::WriteAt(
|
|
#ifdef LARGE_STREAMS
|
|
ULONGLONG ulOffset,
|
|
#else
|
|
ULONG ulOffset,
|
|
#endif
|
|
VOID const HUGEP *pBuffer,
|
|
ULONG ulCount,
|
|
ULONG STACKBASED *pulRetval)
|
|
{
|
|
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::WriteAt(%lu,%p,%lu)\n",ulOffset,pBuffer,ulCount));
|
|
SCODE sc = S_OK;
|
|
|
|
msfAssert(P_TRANSACTED(_df));
|
|
|
|
USHORT cbSector = _dl.GetDataSectorSize();
|
|
USHORT uSectorShift = _dl.GetDataSectorShift();
|
|
|
|
BYTE *pbDirty;
|
|
pbDirty = NULL;
|
|
ULONG temp;
|
|
temp = 0;
|
|
|
|
if (ulCount == 0)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"ulCount==0. Returning.\n"));
|
|
*pulRetval = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
//If size after the write will be greater than the current
|
|
//size, we may need a new delta list.
|
|
if (ulOffset + ulCount > _ulSize)
|
|
{
|
|
msfChk(SetSize(ulOffset + ulCount));
|
|
}
|
|
|
|
|
|
if (_dl.IsEmpty())
|
|
{
|
|
msfChk(_dl.Init(_ulSize, this));
|
|
}
|
|
|
|
ILockBytes *pilbDirty;
|
|
pilbDirty = _dl.GetDataILB();
|
|
|
|
SECT sectStart;
|
|
sectStart = (SECT)(ulOffset / cbSector);
|
|
OFFSET oStart;
|
|
oStart = (OFFSET)(ulOffset % cbSector);
|
|
|
|
SECT send;
|
|
send = (SECT)((ulOffset + ulCount - 1) / cbSector);
|
|
OFFSET offEnd;
|
|
offEnd = (OFFSET)((ulOffset + ulCount - 1) % cbSector) + 1;
|
|
OFFSET oEnd;
|
|
oEnd = 0;
|
|
|
|
|
|
BYTE const HUGEP *pb;
|
|
pb = (BYTE const HUGEP *)pBuffer;
|
|
|
|
ULONG cb;
|
|
cb = 0;
|
|
USHORT cbBlock;
|
|
cbBlock = 0;
|
|
|
|
SECT sectMap;
|
|
SECT sectFirst,sectLast;
|
|
|
|
if (sectStart == send)
|
|
{
|
|
oEnd = cbSector - offEnd;
|
|
}
|
|
|
|
|
|
SECT sectBlockStart;
|
|
msfChk(_dl.GetMap(sectStart, DL_GET, §BlockStart));
|
|
|
|
//This handles partial first sector and
|
|
// one sector only writes.
|
|
while ((oStart) || (sectStart == send))
|
|
{
|
|
|
|
cbBlock = cbSector - oStart - oEnd;
|
|
if (sectBlockStart == ENDOFCHAIN)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"Unmapped partial first sector\n"));
|
|
msfChk(_dl.GetMap(sectStart, DL_CREATE, §Map));
|
|
msfChk(PartialWrite(
|
|
sectStart,
|
|
sectMap,
|
|
pb,
|
|
oStart,
|
|
cbBlock));
|
|
}
|
|
else
|
|
{
|
|
sectMap = sectBlockStart;
|
|
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectMap, oStart, uSectorShift);
|
|
#else
|
|
ULISet32 (ulTmp,
|
|
ConvertSectOffset(sectMap, oStart, uSectorShift));
|
|
#endif
|
|
msfHChk(pilbDirty->WriteAt(
|
|
ulTmp,
|
|
pb,
|
|
cbBlock,
|
|
&temp));
|
|
}
|
|
|
|
pb += cbBlock;
|
|
cb += cbBlock;
|
|
|
|
//If it was one-sector only, we can return here.
|
|
if (sectStart == send)
|
|
{
|
|
*pulRetval = cb;
|
|
return S_OK;
|
|
}
|
|
|
|
sectStart++;
|
|
|
|
oStart = 0;
|
|
msfChk(_dl.GetMap(sectStart, DL_GET, §BlockStart));
|
|
if (sectStart == send)
|
|
{
|
|
oEnd = cbSector - offEnd;
|
|
}
|
|
}
|
|
|
|
|
|
if (sectBlockStart == ENDOFCHAIN)
|
|
{
|
|
msfChk(_dl.GetMap(sectStart, DL_CREATE, §Map));
|
|
}
|
|
|
|
sectLast = sectFirst = (sectBlockStart == ENDOFCHAIN) ? sectMap
|
|
: sectBlockStart;
|
|
|
|
SECT sectCurrent;
|
|
sectCurrent = sectStart + 1;
|
|
|
|
while (sectCurrent < send)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"In main loop: sectCurrent = %lu\n",sectCurrent));
|
|
msfChk(_dl.GetMap(sectCurrent, DL_CREATE, §Map));
|
|
|
|
if (sectMap != sectLast + 1)
|
|
{
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectFirst, oStart, uSectorShift);
|
|
#else
|
|
ULISet32 (ulTmp,
|
|
ConvertSectOffset(sectFirst, oStart, uSectorShift));
|
|
#endif
|
|
msfHChk(pilbDirty->WriteAt(
|
|
ulTmp,
|
|
pb,
|
|
(sectLast - sectFirst + 1) * cbSector - oStart,
|
|
&temp));
|
|
pb += temp;
|
|
cb += temp;
|
|
oStart = 0;
|
|
|
|
sectFirst = sectMap;
|
|
}
|
|
|
|
sectLast = sectMap;
|
|
sectCurrent++;
|
|
}
|
|
|
|
msfAssert(oStart == 0);
|
|
|
|
msfChk(_dl.GetMap(sectCurrent, DL_GET, §Map));
|
|
|
|
oEnd = cbSector - offEnd;
|
|
|
|
BOOL fIsMapped;
|
|
|
|
if (sectMap == ENDOFCHAIN)
|
|
{
|
|
fIsMapped = FALSE;
|
|
msfChk(_dl.GetMap(sectCurrent,DL_CREATE, §Map));
|
|
}
|
|
else
|
|
{
|
|
fIsMapped = TRUE;
|
|
}
|
|
|
|
if ((sectMap != sectLast + 1) || (oEnd != 0))
|
|
{
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectFirst, oStart, uSectorShift);
|
|
#else
|
|
ULISet32 (ulTmp,
|
|
ConvertSectOffset(sectFirst, oStart, uSectorShift));
|
|
#endif
|
|
msfHChk(pilbDirty->WriteAt(
|
|
ulTmp,
|
|
pb,
|
|
(sectLast - sectFirst + 1) * cbSector - oStart,
|
|
&temp));
|
|
pb += temp;
|
|
cb += temp;
|
|
oStart = 0;
|
|
|
|
sectFirst = sectMap;
|
|
}
|
|
|
|
if (oEnd == 0)
|
|
{
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectFirst, oStart, uSectorShift);
|
|
#else
|
|
ULISet32 (ulTmp,
|
|
ConvertSectOffset(sectFirst, oStart, uSectorShift));
|
|
#endif
|
|
msfHChk(pilbDirty->WriteAt(
|
|
ulTmp,
|
|
pb,
|
|
(sectMap - sectFirst + 1) * cbSector - oStart - oEnd,
|
|
&temp));
|
|
pb += temp;
|
|
cb += temp;
|
|
oStart = 0;
|
|
}
|
|
else
|
|
{
|
|
cbBlock = cbSector - oEnd;
|
|
|
|
if (!fIsMapped)
|
|
{
|
|
msfChk(PartialWrite(
|
|
sectCurrent,
|
|
sectMap,
|
|
pb,
|
|
0,
|
|
cbBlock));
|
|
}
|
|
else
|
|
{
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectMap, oStart, uSectorShift);
|
|
#else
|
|
ULISet32 (ulTmp,
|
|
ConvertSectOffset(sectMap, oStart, uSectorShift));
|
|
#endif
|
|
msfHChk(pilbDirty->WriteAt(
|
|
ulTmp,
|
|
pb,
|
|
cbBlock,
|
|
&temp));
|
|
}
|
|
|
|
pb += cbBlock;
|
|
cb += cbBlock;
|
|
}
|
|
|
|
*pulRetval = cb;
|
|
|
|
msfDebugOut((DEB_ITRACE,"Leaving CTransactedStream::WriteAt()==>%lu, ret is %lu\n",(ULONG)S_OK,*pulRetval));
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTransactedStream::SetSize, public
|
|
//
|
|
// Synposis: Set the size of a linear stream
|
|
//
|
|
// Effects: Modifies _ulSize. May cause change in parent MStream.
|
|
//
|
|
// Arguments: [ulNewSize] -- New size for stream
|
|
//
|
|
// Returns: Error code returned by MStream call.
|
|
//
|
|
// Algorithm: Pass call up to parent.
|
|
//
|
|
// History: 29-Jul-91 PhilipLa Created.
|
|
//
|
|
// Notes:
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#ifdef LARGE_STREAMS
|
|
SCODE CTransactedStream::SetSize(ULONGLONG ulNewSize)
|
|
#else
|
|
SCODE CTransactedStream::SetSize(ULONG ulNewSize)
|
|
#endif
|
|
{
|
|
SCODE sc = S_OK;
|
|
BYTE *pb = NULL;
|
|
SECT sectMaxValid;
|
|
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::SetSize(%lu)\n",ulNewSize));
|
|
msfAssert(P_TRANSACTED(_df));
|
|
|
|
if (ulNewSize == 0)
|
|
{
|
|
_dl.Empty();
|
|
}
|
|
else if (!_dl.IsEmpty())
|
|
{
|
|
msfChk(_dl.InitResize(ulNewSize));
|
|
}
|
|
else
|
|
{
|
|
msfChk(_dl.Init(ulNewSize, this));
|
|
}
|
|
|
|
if (ulNewSize > _ulSize)
|
|
{
|
|
USHORT cbSector = _dl.GetDataSectorSize();
|
|
USHORT uSectorShift = _dl.GetDataSectorShift();
|
|
|
|
SECT sectStart, sectEnd, sect, sectNew;
|
|
|
|
if (_ulSize == 0)
|
|
{
|
|
sectStart = 0;
|
|
}
|
|
else
|
|
{
|
|
sectStart = (SECT)((_ulSize - 1) / cbSector);
|
|
}
|
|
|
|
sectEnd = (SECT)((ulNewSize - 1 ) / cbSector);
|
|
|
|
|
|
//First, make sure the first sector is copied over OK if necessary.
|
|
msfChk(_dl.GetMap(sectStart, DL_GET, §New));
|
|
|
|
|
|
if ((sectNew == ENDOFCHAIN) && (_pssBase != NULL) &&
|
|
(_ulSize != 0))
|
|
{
|
|
ULONG cbNull;
|
|
GetSafeBuffer(cbSector, cbSector, &pb, &cbNull);
|
|
msfAssert((pb != NULL) && aMsg("Couldn't get scratch buffer"));
|
|
ULONG dummy;
|
|
|
|
msfChk(_pssBase->ReadAt(
|
|
sectStart << uSectorShift,
|
|
pb,
|
|
cbSector,
|
|
(ULONG STACKBASED *)&dummy));
|
|
|
|
msfChk(_dl.GetMap(sectStart, DL_CREATE, §New));
|
|
|
|
ULARGE_INTEGER ulTmp;
|
|
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectNew, 0, uSectorShift);
|
|
#else
|
|
ULISet32 (ulTmp, ConvertSectOffset(sectNew, 0, uSectorShift));
|
|
#endif
|
|
|
|
msfHChk(_dl.GetDataILB()->WriteAt(
|
|
ulTmp,
|
|
pb,
|
|
cbSector,
|
|
&dummy));
|
|
sectStart++;
|
|
}
|
|
|
|
//
|
|
// Get the current last valid sector in case there is an error
|
|
// allocating the delta list or MStream space.
|
|
// Warning: FindMaxSect() returns the Max Allocated Sect, Plus One.
|
|
//
|
|
msfChk(_dl.GetDataFat()->FindMaxSect(§MaxValid));
|
|
--sectMaxValid;
|
|
|
|
//
|
|
// Allocate new sectors one at a time.
|
|
// GetMap() in DL_CREATE mode does not actually grow the MStream.
|
|
// It allocates FAT entries.
|
|
//
|
|
for (sect = sectStart; sect <= sectEnd; sect ++)
|
|
{
|
|
if(FAILED(sc = _dl.GetMap(sect, DL_CREATE, §New)))
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Grow the MStream (which in turn grows the ILB) to include
|
|
// any newly allocated SECTs. If that fails then release entries
|
|
// in the FAT that couldn't be allocated in the ILB.
|
|
// ie. Beyond the previous recorded Max SECT of the MStream.
|
|
//
|
|
if(FAILED(sc) || FAILED(_dl.GetMStream()->SetSize()))
|
|
{
|
|
_dl.ReleaseInvalidSects(sectMaxValid);
|
|
goto Err;
|
|
}
|
|
}
|
|
_ulSize = ulNewSize;
|
|
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::SetSize()\n"));
|
|
|
|
Err:
|
|
FreeBuffer(pb);
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::BeginCommitFromChild, public
|
|
//
|
|
// Synopsis: Begin a commit from a child TStream
|
|
//
|
|
// Arguments: [ulSize] - New size
|
|
// [pDelta] - Delta list
|
|
// [pstChild] - Child
|
|
//
|
|
// Returns: S_OK if call completed OK.
|
|
//
|
|
// Algorithm: *Finish This*
|
|
//
|
|
// History: 22-Jan-92 PhilipLa Created.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::BeginCommitFromChild(
|
|
#ifdef LARGE_STREAMS
|
|
ULONGLONG ulSize,
|
|
#else
|
|
ULONG ulSize,
|
|
#endif
|
|
CDeltaList *pDelta,
|
|
CTransactedStream *pstChild)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::BeginCommitFromChild:%p("
|
|
"%lu, %p, %p)\n", this, ulSize, pDelta, pstChild));
|
|
|
|
msfAssert(P_TRANSACTED(_df));
|
|
_dl.BeginCommit(this);
|
|
_pdlOld = P_TO_BP(CBasedDeltaListPtr, pDelta);
|
|
_ulOldSize = _ulSize;
|
|
_ulSize = ulSize;
|
|
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::BeginCommitFromChild()\n"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::EndCommitFromChild, public
|
|
//
|
|
// Synopsis: End a commit from child.
|
|
//
|
|
// Arguments: [df] -- Flags to determine whether to commit or revert
|
|
// [pstChild] - Child
|
|
//
|
|
// Returns: Void. This can't fail.
|
|
//
|
|
// Algorithm: *Finish This*
|
|
//
|
|
// History: 22-Jan-92 PhilipLa Created.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
void CTransactedStream::EndCommitFromChild(DFLAGS df,
|
|
CTransactedStream *pstChild)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::EndCommitFromChild:%p("
|
|
"%lu, %p)\n", this, df, pstChild));
|
|
|
|
msfAssert(P_TRANSACTED(_df));
|
|
|
|
_dl.EndCommit(BP_TO_P(CDeltaList *, _pdlOld), df);
|
|
|
|
//NOTE: Possible cleanup: Move _pdlOld into the delta list itself.
|
|
_pdlOld = NULL;
|
|
|
|
if (P_COMMIT(df))
|
|
{
|
|
_ulOldSize = 0;
|
|
}
|
|
else
|
|
{
|
|
_ulSize = _ulOldSize;
|
|
}
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::EndCommitFromChild()\n"));
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::BeginCommit, public
|
|
//
|
|
// Synopsis: Begin a commit of a transacted stream object
|
|
//
|
|
// Arguments: [dwFlags] -- Currently not used (future expansion)
|
|
//
|
|
// Returns: S_OK if call completed OK.
|
|
//
|
|
// Algorithm: Call BeginCommitFromChild on base
|
|
//
|
|
// History: 22-Jan-92 PhilipLa Created.
|
|
//
|
|
// Notes: This is only called by the Transaction Level object.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::BeginCommit(DWORD const dwFlags)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::BeginCommit(%lu)\n",
|
|
dwFlags));
|
|
|
|
msfAssert(_pssBase != NULL);
|
|
msfAssert(P_TRANSACTED(_df));
|
|
|
|
#if DBG == 1
|
|
if (!HaveResource(DBR_XSCOMMITS, 1))
|
|
msfErr(Err, STG_E_ABNORMALAPIEXIT);
|
|
#endif
|
|
|
|
_fBeginCommit = TRUE;
|
|
msfChk(_pssBase->BeginCommitFromChild(_ulSize, &_dl, this));
|
|
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::BeginCommit()\n"));
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::EndCommit, public
|
|
//
|
|
// Synopsis: End a commit on a transacted stream object
|
|
//
|
|
// Arguments: [df] -- Indicator of whether to commit or revert
|
|
//
|
|
// Returns: void. This can't fail.
|
|
//
|
|
// Algorithm: Call EndCommitFromChild on base.
|
|
// If committing, NULL out all previously passed up
|
|
// dirty information.
|
|
//
|
|
// History: 22-Jan-92 PhilipLa Created.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
void CTransactedStream::EndCommit(DFLAGS const df)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::EndCommit(%lu)\n",df));
|
|
|
|
msfAssert(P_TRANSACTED(_df));
|
|
msfAssert((_pssBase != NULL) || (P_ABORT(df)));
|
|
|
|
if (!_fBeginCommit)
|
|
return;
|
|
_fBeginCommit = FALSE;
|
|
|
|
#if DBG == 1
|
|
if (P_COMMIT(df))
|
|
ModifyResLimit(DBR_XSCOMMITS, 1);
|
|
#endif
|
|
|
|
if (_pssBase != NULL)
|
|
{
|
|
_pssBase->EndCommitFromChild(df, this);
|
|
}
|
|
|
|
if (P_COMMIT(df))
|
|
{
|
|
_dl.Empty();
|
|
SetClean();
|
|
}
|
|
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::EndCommit()\n"));
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::Revert, public
|
|
//
|
|
// Synopsis: Revert a transacted stream instance.
|
|
//
|
|
// Algorithm: Destroy dirty stream and delta list.
|
|
// Retrieve size from base.
|
|
// Mark object as Invalid if specified in the flags.
|
|
//
|
|
// History: 22-Jan-92 PhilipLa Created.
|
|
//
|
|
// Notes: This is only called from the Transaction Level.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
void CTransactedStream::Revert(void)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::Revert(%lu): This == %p\n",this));
|
|
|
|
_dl.Empty();
|
|
msfVerify(SUCCEEDED(SetInitialState(BP_TO_P(PSStream *, _pssBase))));
|
|
_sectLastUsed = 0;
|
|
SetClean();
|
|
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::Revert()\n"));
|
|
}
|
|
|
|
//+--------------------------------------------------------------
|
|
//
|
|
// Member: CTransactedStream::SetBase, public
|
|
//
|
|
// Synopsis: Sets a new base
|
|
//
|
|
// Arguments: [psst] - New base
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 31-Jul-92 DrewB Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::SetBase(PSStream *psst)
|
|
{
|
|
msfAssert(_pssBase == NULL || psst == NULL);
|
|
if (_pssBase)
|
|
_pssBase->Release();
|
|
_pssBase = P_TO_BP(CBasedSStreamPtr, psst);
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::PartialWrite, private
|
|
//
|
|
// Synopsis: Do a write of a partial sector
|
|
//
|
|
// Arguments: [sectBase] -- Sector in base to copy
|
|
// [sectDirty] -- Sector in dirty to write to
|
|
// [pb] -- Buffer containing data to be writte
|
|
// [offset] -- Offset into buffer to begin copy
|
|
// [uLen] -- Number of bytes to copy
|
|
//
|
|
// Returns: S_OK if call completed OK.
|
|
//
|
|
// Algorithm: *Finish This*
|
|
//
|
|
// History: 30-Jun-92 PhilipLa Created.
|
|
//
|
|
// Notes: [pb] may be unsafe memory
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::PartialWrite(
|
|
SECT sectBase,
|
|
SECT sectDirty,
|
|
BYTE const HUGEP *pb,
|
|
USHORT offset,
|
|
USHORT uLen)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"In CTransactedStream::PartialWrite()\n"));
|
|
BYTE *pbMem = NULL;
|
|
SCODE sc;
|
|
ULONG temp;
|
|
|
|
USHORT cbSector = _dl.GetDataSectorSize();
|
|
USHORT uSectorShift = _dl.GetDataSectorShift();
|
|
|
|
if (uLen != cbSector)
|
|
{
|
|
ULONG cbNull;
|
|
GetSafeBuffer(cbSector, cbSector, &pbMem, &cbNull);
|
|
msfAssert((pbMem != NULL) && aMsg("Couldn't get scratch buffer"));
|
|
|
|
if (_pssBase != NULL)
|
|
{
|
|
msfChk(_pssBase->ReadAt(
|
|
sectBase << uSectorShift,
|
|
pbMem,
|
|
cbSector,
|
|
(ULONG STACKBASED *)&temp));
|
|
}
|
|
|
|
TRY
|
|
{
|
|
memcpy(pbMem + offset, pb, uLen);
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
UNREFERENCED_PARM(e);
|
|
msfErr(Err, STG_E_INVALIDPOINTER);
|
|
}
|
|
END_CATCH
|
|
|
|
pb = pbMem;
|
|
}
|
|
|
|
ULARGE_INTEGER ulTmp;
|
|
#ifdef LARGE_DOCFILE
|
|
ulTmp.QuadPart = ConvertSectOffset(sectDirty, 0, uSectorShift);
|
|
#else
|
|
ULISet32 (ulTmp,
|
|
ConvertSectOffset(sectDirty, 0, uSectorShift));
|
|
#endif
|
|
|
|
sc = DfGetScode((_dl.GetDataILB())->WriteAt(
|
|
ulTmp,
|
|
pb,
|
|
cbSector,
|
|
&temp));
|
|
|
|
Err:
|
|
FreeBuffer(pbMem);
|
|
msfDebugOut((DEB_ITRACE,"Out CTransactedStream::PartialWrite()\n"));
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::GetCommitInfo, public
|
|
//
|
|
// Synopsis: Return the current size of the stream and the size of
|
|
// its base.
|
|
//
|
|
// Arguments: [pulRet1] -- Pointer to return location for old size
|
|
// [pulRet2] -- Pointer to return location for current size
|
|
//
|
|
// History: 08-Jul-92 PhilipLa Created.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#ifdef LARGE_STREAMS
|
|
void CTransactedStream::GetCommitInfo(ULONGLONG *pulRet1, ULONGLONG *pulRet2)
|
|
#else
|
|
void CTransactedStream::GetCommitInfo(ULONG *pulRet1, ULONG *pulRet2)
|
|
#endif
|
|
{
|
|
if (_pssBase != NULL)
|
|
_pssBase->GetSize(pulRet1);
|
|
else
|
|
*pulRet1 = 0;
|
|
*pulRet2 = _ulSize;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTransactedStream::GetSize, public
|
|
//
|
|
// Synopsis: Returns the size of the stream.
|
|
//
|
|
// Arguments: [pulSize] -- Pointer to return location for size.
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 22-Jan-92 PhilipLa Created.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef LARGE_STREAMS
|
|
void CTransactedStream::GetSize(ULONGLONG *pulSize)
|
|
#else
|
|
void CTransactedStream::GetSize(ULONG *pulSize)
|
|
#endif
|
|
{
|
|
msfAssert(P_TRANSACTED(_df));
|
|
|
|
*pulSize = _ulSize;
|
|
|
|
msfDebugOut((DEB_ITRACE,"CTransactedStream::GetSize()==>%lu\n",*pulSize));
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTransactedStream::SetInitialState, public
|
|
//
|
|
// Synopsis: Sets the initial state from a base or defaults
|
|
//
|
|
// Arguments: [pssBase] - Base or NULL
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 11-Nov-92 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
SCODE CTransactedStream::SetInitialState(PSStream *pssBase)
|
|
{
|
|
olDebugOut((DEB_ITRACE, "In CTransactedStream::SetInitialState:%p(%p)\n",
|
|
this, pssBase));
|
|
if (pssBase == NULL)
|
|
{
|
|
_ulSize = 0;
|
|
}
|
|
else
|
|
{
|
|
pssBase->GetSize(&_ulSize);
|
|
}
|
|
olDebugOut((DEB_ITRACE, "Out CTransactedStream::SetInitialState\n"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTransactedStream::GetDeltaList, public
|
|
//
|
|
// Synopsis: Return a pointer to the delta list if it is not empty.
|
|
// If it is empty, call GetDeltaList on the parent and
|
|
// return that.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: Pointer as above.
|
|
//
|
|
// History: 30-Jul-93 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CDeltaList * CTransactedStream::GetDeltaList(void)
|
|
{
|
|
if (_dl.IsEmpty())
|
|
{
|
|
if (_pssBase != NULL)
|
|
{
|
|
return _pssBase->GetDeltaList();
|
|
}
|
|
else
|
|
{
|
|
//This case will only be hit if someone creates a new
|
|
// stream, then commits it to its parent without writing
|
|
// anything to it. The parent then has an empty delta
|
|
// list with no parent set on it.
|
|
msfAssert(_ulSize == 0);
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
return &_dl;
|
|
}
|