|
|
//+-------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: sstream.cxx
//
// Contents: Stream operations for Mstream project
//
// Classes: None. (defined in sstream.hxx)
//
//--------------------------------------------------------------------
#include "msfhead.cxx"
#include "h/dirfunc.hxx"
#include "h/sstream.hxx"
#include <time.h>
#include "mread.hxx"
#define DEB_STREAM (DEB_ITRACE | 0x00020000)
//+--------------------------------------------------------------
//
// Member: CDirectStream::CDirectStream, public
//
// Synopsis: Empty object constructor
//
// Arguments: [dl] - LUID
//
//---------------------------------------------------------------
CDirectStream::CDirectStream(DFLUID dl) : PEntry(dl) { _cReferences = 0; }
//+--------------------------------------------------------------
//
// Member: CDirectStream::InitSystem, public
//
// Synopsis: Initializes special system streams like the ministream
//
// Arguments: [pms] - Multistream
// [sid] - SID
// [cbSize] - size
//
//---------------------------------------------------------------
void CDirectStream::InitSystem(CMStream *pms, SID sid, ULONG cbSize) { _stmh.Init(pms, sid); _ulSize = _ulOldSize = cbSize; AddRef(); }
//+-------------------------------------------------------------------------
//
// Method: CDirectStream::Init, public
//
// Synopsis: CDirectStream constructor
//
// Arguments: [pstgh] - Parent
// [pdfn] - Name of entry
// [fCreate] - Create or get
//
// Returns: Appropriate status code
//
//--------------------------------------------------------------------------
SCODE CDirectStream::Init( CStgHandle *pstgh, CDfName const *pdfn, BOOL const fCreate) { SCODE sc;
if (fCreate) sc = pstgh->CreateEntry(pdfn, STGTY_STREAM, &_stmh); else sc = pstgh->GetEntry(pdfn, STGTY_STREAM, &_stmh); if (SUCCEEDED(sc)) { sc = _stmh.GetSize(&_ulSize); _ulOldSize = _ulSize; if (SUCCEEDED(sc)) AddRef(); } return sc; }
//+-------------------------------------------------------------------------
//
// Method: CDirectStream::~CDirectStream, public
//
// Synopsis: CDirectStream destructor
//
// Notes:
//
//--------------------------------------------------------------------------
CDirectStream::~CDirectStream() { msfAssert(_cReferences == 0); }
//+-------------------------------------------------------------------------
//
// Member: CDirectStream::ReadAt, public
//
// Synposis: Reads binary data from a linear single 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: Error Code of parent MStream call
//
// Algorithm: Calculate start and end sectors and offsets, then
// pass call up to parent MStream.
//
// Notes:
//
//---------------------------------------------------------------------------
SCODE CDirectStream::ReadAt( ULONG ulOffset, VOID HUGEP *pBuffer, ULONG ulCount, ULONG STACKBASED *pulRetval) { msfDebugOut((DEB_TRACE,"In CDirectStream::ReadAt(%lu,%p,%lu)\n", ulOffset,pBuffer,ulCount));
SCODE sc = S_OK;
CMStream *pms = _stmh.GetMS();
// Check for offset beyond stream size and zero count
if ((ulOffset >= _ulSize) || (0 == ulCount)) { *pulRetval = 0; return S_OK; }
if (ulOffset + ulCount > _ulSize) { msfDebugOut((DEB_ITRACE,"Truncating Read: ulOffset = %lu, ulCount = %lu, _ulSize = %lu\n", ulOffset,ulCount,_ulSize)); ulCount = _ulSize - ulOffset; }
// Stream is stored in ministream if size < MINISTREAMSIZE
// and this is not a scratch stream.
SID sid = _stmh.GetSid(); CFat *pfat = pms->GetFat(); USHORT cbSector = pms->GetSectorSize(); USHORT uShift = pms->GetSectorShift(); USHORT uMask = pms->GetSectorMask();
if ((_ulSize < MINISTREAMSIZE) && (sid != SIDMINISTREAM)) { msfAssert(sid <= MAXREGSID);
// This stream is stored in the ministream
cbSector = MINISECTORSIZE; uShift = MINISECTORSHIFT; uMask = (USHORT) (cbSector - 1); pfat = pms->GetMiniFat(); }
SECT start = (SECT)(ulOffset >> uShift); OFFSET oStart = (OFFSET)(ulOffset & uMask);
SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift); OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
ULONG total = 0;
ULONG cSect = end - start + 1;
SECT sectSidStart;
USHORT offset; offset = oStart;
while (TRUE) { SECT sect; if (start > _stmc.GetOffset()) { msfChk(pfat->GetSect( _stmc.GetSect(), start - _stmc.GetOffset(), §)); } else if (start == _stmc.GetOffset()) { sect = _stmc.GetSect(); } else { msfChk(pms->GetDir()->GetStart(sid, §SidStart)); msfChk(pfat->GetSect(sectSidStart, start, §)); }
SSegment segtab[CSEG + 1];
msfChk(pfat->Contig( (SSegment STACKBASED *) segtab, sect, cSect));
USHORT oend = (USHORT) (cbSector - 1); for (USHORT iseg = 0; iseg < CSEG;) { msfDebugOut((DEB_ITRACE,"Segment: (%lu,%lu)\n",segtab[iseg].sectStart,segtab[iseg].cSect)); SECT sectStart = segtab[iseg].sectStart; ULONG i = segtab[iseg].cSect; cSect -= i; start += i;
iseg++; if (segtab[iseg].sectStart == ENDOFCHAIN) oend = oEnd;
ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
ULONG bytecount; SCODE sc;
if (pms->GetMiniFat() == pfat) { sc = pms->GetMiniStream()->CDirectStream::ReadAt( (sectStart << uShift) + offset, pBuffer, ulSize, (ULONG STACKBASED *)&bytecount); } else { ULARGE_INTEGER ulOffset; ULISet32(ulOffset, ConvertSectOffset(sectStart,offset,uShift)); sc = DfGetScode(pms->GetILB()->ReadAt(ulOffset, (BYTE *)pBuffer, ulSize, &bytecount)); }
total += bytecount; if ((0 == cSect) || (FAILED(sc))) { _stmc.SetCache(start - 1, sectStart + i - 1); *pulRetval = total; msfDebugOut((DEB_TRACE, "Leaving CDirectStream::ReadAt()=>%lu, ret is %lu\n", sc,*pulRetval)); return sc; }
pBuffer = (BYTE HUGEP *)pBuffer + bytecount; offset = 0; } }
msfDebugOut((DEB_ERROR,"In CDirectStream::ReadAt - reached end of function\n")); Err: return sc; }
//+-------------------------------------------------------------------------
//
// Member: CDirectStream::Write, public
//
// Synposis: Writes binary data from 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.
//
//
// Notes:
//
//---------------------------------------------------------------------------
SCODE CDirectStream::WriteAt( ULONG ulOffset, VOID const HUGEP *pBuffer, ULONG ulCount, ULONG STACKBASED *pulRetval) { msfDebugOut((DEB_TRACE,"In CDirectStream::WriteAt(%lu,%p,%lu)\n",ulOffset,pBuffer,ulCount));
*pulRetval = 0;
if (0 == ulCount) return S_OK;
SCODE sc; if (ulOffset + ulCount > _ulSize) { if (_ulSize > MINISTREAMSIZE) { } else { msfChk(SetSize(ulOffset + ulCount)); } }
CMStream *pms; pms = _stmh.GetMS(); msfAssert(pms != NULL);
// This should be an inline call to MWrite
msfChk(pms->MWrite( _stmh.GetSid(), (_ulSize < MINISTREAMSIZE), ulOffset, pBuffer, ulCount, &_stmc, pulRetval));
msfAssert(*pulRetval == ulCount);
msfDebugOut((DEB_TRACE,"Leaving CDirectStream::WriteAt()==>%lu, ret is %lu\n",sc,*pulRetval));
Err: if (ulOffset + *pulRetval > _ulSize) { SCODE scSet; _ulSize = ulOffset + *pulRetval; scSet = pms->GetDir()->SetSize(_stmh.GetSid(), _ulSize); if (SUCCEEDED(sc) && FAILED(scSet)) { sc = scSet; } } return sc; }
//+-------------------------------------------------------------------------
//
// Member: CDirectStream::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.
//
// Notes: When changing the size of a stream, we need to be concerned
// with the cases where each stream is either zero length,
// stored in the ministream, or stored in a regular stream. The following
// grid shows the actions that we must perform in each case:
//
// New Sector Count (Cn)
//
// 0 S L
// O ------------------------------------------------
// l | same size | allocate Cn | allocate Cn
// d 0 | (fast out) | small sectors | large sectors
// ------------------------------------------------
// S | small | Co > Cn: | cbCopy = cbOld
// e S | setchain(Cn) | small | large allocate Cn
// c | | setchain(Cn)| copy bytes
// t | | Cn > Co: | small setchain(0)
// o | | extend small | copy data
// r ------------------------------------------------
// L | large | cbCopy = cbNew| Co > Cn:
// C | setchain(Cn) | small | large setchain(Cn)
// o | | allocate Cn | Cn > Co:
// u | | copy bytes | extend large
// n | | large |
// t | | setchain(0) |
// | | copy data |
// (Co) ------------------------------------------------
//
// where S indicates small sectors, L indicates large sectors, and Cx
// represents count of sectors. For example, the middle box represents
// doing a setsize on a stream which is currently stored in a small
// stream in Co small sectors and which will end up in a large stream
// with Cn sectors.
//
//---------------------------------------------------------------------------
SCODE CDirectStream::SetSize(ULONG cbNewSize) { msfDebugOut((DEB_TRACE,"In CDirectStream::SetSize(%lu)\n",cbNewSize));
SCODE sc = S_OK; BYTE *pBuf = NULL; SID sid = _stmh.GetSid(); CMStream *pms = _stmh.GetMS(); msfAssert(sid <= MAXREGSID); CDirectory *pdir = pms->GetDir(); SECT sectOldStart; if (_ulSize == cbNewSize) { return S_OK; }
USHORT cbpsOld = pms->GetSectorSize(); // Count of Bytes Per Sector
USHORT cbpsNew = cbpsOld; CFat *pfatOld = pms->GetFat(); CFat *pfatNew = pfatOld;
if (SIDMINISTREAM != sid) {
if (cbNewSize < MINISTREAMSIZE) { cbpsNew = MINISECTORSIZE; pfatNew = pms->GetMiniFat(); }
if (_ulSize < MINISTREAMSIZE) { cbpsOld = MINISECTORSIZE; pfatOld = pms->GetMiniFat(); } }
ULONG csectOld = (ULONG)(_ulSize + cbpsOld - 1) / (ULONG) cbpsOld; ULONG csectNew = (ULONG)(cbNewSize + cbpsNew - 1) / (ULONG) cbpsNew;
msfAssert(sid <= MAXREGSID); SECT sectstart; msfChk(pdir->GetStart(sid, §start));
msfDebugOut((DEB_ITRACE,"pdbOld size is %lu\n\tSid is %lu\n\tStart is %lu\n", _ulSize,sid,sectstart)); msfDebugOut((DEB_ITRACE,"CMStream::SetSize() needs %lu %u byte sectors\n", csectNew, cbpsNew)); msfDebugOut((DEB_ITRACE,"SetSize() currently has %lu %u byte sectors\n", csectOld, cbpsOld));
USHORT cbCopy; cbCopy = 0; if (cbpsOld != cbpsNew) { // Sector sizes are different, so we'll copy the data
msfAssert((cbNewSize > _ulSize ? _ulSize : cbNewSize) < 0x10000); cbCopy =(USHORT)(cbNewSize > _ulSize ? _ulSize : cbNewSize); }
if (cbCopy > 0) { msfDebugOut((DEB_ITRACE,"Copying between fat and minifat\n")); GetSafeBuffer(cbCopy, cbCopy, &pBuf, &cbCopy); msfAssert((pBuf != NULL) && aMsg("Couldn't get scratch buffer"));
ULONG ulRetVal; sc = ReadAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal); if ((FAILED(sc)) || ((ulRetVal != cbCopy) ? (sc = STG_E_UNKNOWN) : 0)) { msfErr(Err, sc); }
//The cache is no longer valid, so empty it.
_stmc.SetCache(MAX_ULONG, ENDOFCHAIN); //Save start sector so we can free it later.
sectOldStart = sectstart; msfChk(pfatNew->Allocate(csectNew, §start)); } else { SECT dummy;
if ((csectOld > csectNew)) { msfChk(pfatOld->SetChainLength(sectstart, csectNew)); if (0 == csectNew) { sectstart = ENDOFCHAIN; }
//If this turns out to be a common case, we can
// sometimes keep the cache valid here.
_stmc.SetCache(MAX_ULONG, ENDOFCHAIN); } else if (0 == csectOld) { msfAssert(_stmc.GetOffset() == MAX_ULONG); msfChk(pfatNew->Allocate(csectNew, §start)); } else if (csectNew > csectOld) { ULONG start = csectNew - 1;
if (start > _stmc.GetOffset()) { msfChk(pfatNew->GetESect( _stmc.GetSect(), start - _stmc.GetOffset(), &dummy)); } else if (start != _stmc.GetOffset()) { msfChk(pfatNew->GetESect(sectstart, start, &dummy)); } } }
// Resize the ministream, if necessary
if (((MINISECTORSIZE == cbpsOld) && (csectOld > 0)) || ((MINISECTORSIZE == cbpsNew) && (csectNew > 0))) { msfChk(pms->SetMiniSize()); } msfChk(pms->SetSize());
//If we fail on either of these operations and cbCopy != 0,
// we will have data loss. Ick.
msfChk(pdir->SetStart(sid, sectstart));
//If we fail here, were in trouble.
msfChk(pdir->SetSize(sid, cbNewSize));
_ulSize = cbNewSize;
if (cbCopy > 0) { // now copy the data
ULONG ulRetVal;
msfAssert(cbCopy <= _ulSize); msfChk(WriteAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal));
if (ulRetVal != cbCopy) { msfErr(Err, STG_E_UNKNOWN); }
msfChk(pfatOld->SetChainLength(sectOldStart, 0)); msfChk(pms->SetMiniSize()); msfChk(pms->SetSize()); }
if (((csectNew > csectOld) || (cbCopy > 0)) && ((cbNewSize & (cbpsNew - 1)) != 0)) { SECT sectLast; if (csectNew - 1 > _stmc.GetOffset()) { msfChk(pfatNew->GetSect( _stmc.GetSect(), (csectNew - 1) - _stmc.GetOffset(), §Last)); } else { msfChk(pfatNew->GetSect(sectstart, csectNew - 1, §Last)); } msfVerify(SUCCEEDED(pms->SecureSect( sectLast, cbNewSize, (cbNewSize < MINISTREAMSIZE) && (sid != SIDMINISTREAM)))); } Err: FreeBuffer(pBuf); return sc; }
//+---------------------------------------------------------------------------
//
// Member: CDirectStream::Release, public
//
// Synopsis: Decrements the ref count and frees if necessary
//
//----------------------------------------------------------------------------
void CDirectStream::Release(VOID) { msfDebugOut((DEB_TRACE,"In CDirectStream::Release()\n")); msfAssert(_cReferences > 0);
AtomicDec(&_cReferences); if (_cReferences == 0) delete this; msfDebugOut((DEB_TRACE,"Out CDirectStream::Release()\n")); }
//+--------------------------------------------------------------
//
// Member: CDirectStream::AddRef, public
//
// Synopsis: Increments the ref count
//
//---------------------------------------------------------------
void CDirectStream::AddRef(void) { msfDebugOut((DEB_ITRACE, "In CDirectStream::AddRef()\n")); AtomicInc(&_cReferences); msfDebugOut((DEB_ITRACE, "Out CDirectStream::AddRef, %lu\n", _cReferences)); }
//+---------------------------------------------------------------------------
//
// Member: CDirectStream::GetSize, public
//
// Synopsis: Gets the size of the stream
//
// Arguments: [pulSize] - Size return
//
// Modifies: [pulSize]
//
//----------------------------------------------------------------------------
void CDirectStream::GetSize(ULONG *pulSize) { *pulSize = _ulSize; }
//+--------------------------------------------------------------
//
// Member: CDirectStream::GetTime, public
//
// Synopsis: Gets a time
//
// Arguments: [wt] - Which time
// [ptm] - Time return
//
// Returns: Appropriate status code
//
// Modifies: [ptm]
//
//---------------------------------------------------------------
SCODE CDirectStream::GetTime(WHICHTIME wt, TIME_T *ptm) { return _stmh.GetTime(wt, ptm); }
//+--------------------------------------------------------------
//
// Member: CDirectStream::SetTime, public
//
// Synopsis: Sets a time
//
// Arguments: [wt] - Which time
// [tm] - New time
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
SCODE CDirectStream::SetTime(WHICHTIME wt, TIME_T tm) { return _stmh.SetTime(wt, tm); }
|