//+------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1992. // // File: sstream.cxx // // Contents: Stream operations for Mstream project // // Classes: None. (defined in sstream.hxx) // // History: 18-Jul-91 PhilipLa Created. // 24-Apr-92 AlexT Small object support // //-------------------------------------------------------------------- #include "msfhead.cxx" #pragma hdrstop #include #include #include #include #include #include #define DEB_STREAM (DEB_ITRACE | 0x00020000) //+-------------------------------------------------------------- // // Member: CDirectStream::CDirectStream, public // // Synopsis: Empty object constructor // // Arguments: [dl] - LUID // // History: 25-Aug-92 DrewB Created // //--------------------------------------------------------------- CDirectStream::CDirectStream(DFLUID dl) : PSStream(dl) { _pdlHolder = NULL; _cReferences = 0; #ifdef SECURE_STREAMS _ulSize = 0; _ulHighWater = 0; #endif _sig = CDIRECTSTREAM_SIG; } //+------------------------------------------------------------------------- // // Method: CDirectStream::~CDirectStream, public // // Synopsis: CDirectStream destructor // // History: 18-Jul-91 PhilipLa Created. // // Notes: // //-------------------------------------------------------------------------- CDirectStream::~CDirectStream() { msfAssert(_cReferences == 0); _sig = CDIRECTSTREAM_SIGDEL; #ifdef SECURE_STREAMS if (_ulSize > _ulHighWater) { ClearSects(_ulHighWater, _ulSize); } #endif } //+-------------------------------------------------------------- // // Member: CDirectStream::InitSystem, public // // Synopsis: Initializes special system streams like the ministream // // Arguments: [pms] - Multistream // [sid] - SID // [cbSize] - size // // History: 25-Aug-92 DrewB Created // //--------------------------------------------------------------- void CDirectStream::InitSystem(CMStream *pms, SID sid, #ifdef LARGE_STREAMS ULONGLONG cbSize) #else ULONG cbSize) #endif { _stmh.Init(pms, sid); _ulSize = _ulOldSize = cbSize; _stmc.Init(pms, sid, this); #ifdef SECURE_STREAMS #ifndef SECURE_BUFFER //If SECURE_BUFFER is defined, we've already zeroed this in the // multistream. memset(s_bufSecure, SECURECHAR, MINISTREAMSIZE); #endif _ulHighWater = cbSize; #endif AddRef(); } //+------------------------------------------------------------------------- // // Method: CDirectStream::Init, public // // Synopsis: CDirectStream constructor // // Arguments: [pstgh] - Parent // [pdfn] - Name of entry // [fCreate] - Create or get // // Returns: Appropriate status code // // History: 18-Jul-91 PhilipLa Created. // 02-Jan-92 PhilipLa Converted to use handle. // 25-Aug-92 DrewB Converted to use StgHandle // //-------------------------------------------------------------------------- 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; #ifdef SECURE_STREAMS _ulHighWater = (fCreate) ? 0 : _ulSize; #endif #if DBG == 1 if (SUCCEEDED(sc)) { //Make sure that the stream is sane. SCODE sc2; CFat *pfat; ULONG cbSector; ULONG cSect; ULONG cSectReal; SECT sectStart; if (_ulSize < MINISTREAMSIZE) { cbSector = MINISECTORSIZE; pfat = _stmh.GetMS()->GetMiniFat(); } else { cbSector = _stmh.GetMS()->GetSectorSize(); pfat = _stmh.GetMS()->GetFat(); } cSect = (ULONG)((_ulSize + cbSector - 1) / cbSector); sc2 = _stmh.GetMS()->GetDir()->GetStart( _stmh.GetSid(), §Start); if (SUCCEEDED(sc2)) { sc2 = pfat->GetLength(sectStart, &cSectReal); if (SUCCEEDED(sc2)) { msfAssert((cSect == cSectReal) && aMsg("Chain length incorrect at init.")); } } } #endif if (SUCCEEDED(sc)) AddRef(); _stmc.Init(_stmh.GetMS(), _stmh.GetSid(), this); } return sc; } //+------------------------------------------------------------------------- // // 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. // // History: 18-Jul-91 PhilipLa Created. // 16-Aug-91 PhilipLa Converted to use multi-sect read // 23-Aug-91 PhilipLa Brought into compliance with protocol // 11-Sep-91 PhilipLa Moved most functionality up // to MStream level. // 24-Apr-92 AlexT Move everything to MStream::MRead // 09-Jun-92 PhilipLa Added fUnconverted support // // Notes: [pBuffer] may be unsafe memory // //--------------------------------------------------------------------------- SCODE CDirectStream::ReadAt( #ifdef LARGE_STREAMS ULONGLONG ulOffset, #else ULONG ulOffset, #endif VOID HUGEP *pBuffer, ULONG ulCount, ULONG STACKBASED *pulRetval) { msfDebugOut((DEB_ITRACE,"In CDirectStream::ReadAt(%lu,%p,%lu)\n", ulOffset,pBuffer,ulCount)); SCODE sc = S_OK; CMStream *pms = _stmh.GetMS(); *pulRetval = 0; if (NULL == pms) return STG_E_UNKNOWN; // Check for offset beyond stream size and zero count if ((ulOffset >= _ulSize) || (0 == ulCount)) { return S_OK; } if (ulOffset + ulCount > _ulSize) { msfDebugOut((DEB_ITRACE,"Truncating Read: ulOffset = %lu, ulCount = %lu, _ulSize = %lu\n", ulOffset,ulCount,_ulSize)); ulCount = (ULONG)(_ulSize - ulOffset); } #ifdef DELAYCONVERT if (pms->IsUnconverted()) { ULARGE_INTEGER ulTmp; ULISet32(ulTmp, ulOffset); return DfGetScode(pms->GetILB()->ReadAt(ulTmp, pBuffer, ulCount, pulRetval)); } #else msfAssert(!pms->IsUnconverted()); #endif // Stream is stored in ministream if size < MINISTREAMSIZE // and this is not a scratch stream. #ifdef SECURE_STREAMS if (ulOffset + ulCount > _ulHighWater) { if (ulOffset > _ulHighWater) { //Zero the whole buffer and return. memset(pBuffer, SECURECHAR, ulCount); *pulRetval = ulCount; return S_OK; } //Need to read into part of the buffer, then zero fill the // rest. if (FAILED(sc = ReadAt(ulOffset, pBuffer, _ulHighWater - ulOffset, pulRetval)) || (*pulRetval != _ulHighWater - ulOffset)) { return sc; } memset((BYTE *)pBuffer + *pulRetval, SECURECHAR, ulCount - (_ulHighWater - ulOffset)); *pulRetval = ulCount; return S_OK; } #endif SID sid = _stmh.GetSid(); CFat *pfat = pms->GetFat(); USHORT cbSector = pms->GetSectorSize(); USHORT uShift = pms->GetSectorShift(); USHORT uMask = pms->GetSectorMask(); if ((_ulSize < MINISTREAMSIZE) && (!pms->IsScratch()) && (sid != SIDMINISTREAM)) { msfAssert(sid <= MAXREGSID); // This stream is stored in the ministream cbSector = MINISECTORSIZE; uShift = MINISECTORSHIFT; uMask = 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; USHORT offset; offset = oStart; while (TRUE) { ULONG cSeg; SSegment segtab[CSEG + 1]; msfChk(_stmc.Contig(start, FALSE, (SSegment STACKBASED *) segtab, cSect, &cSeg)); msfAssert(cSeg <= CSEG); USHORT oend = 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; if (i > cSect) i = cSect; cSect -= i; start += i; iseg++; if (cSect == 0) 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; #ifdef LARGE_DOCFILE ulOffset.QuadPart = ConvertSectOffset(sectStart,offset,uShift); #else ULISet32(ulOffset, ConvertSectOffset(sectStart,offset,uShift)); #endif sc = DfGetScode(pms->GetILB()->ReadAt(ulOffset, (BYTE *)pBuffer, ulSize, &bytecount)); } total += bytecount; if ((0 == cSect) || (FAILED(sc))) { *pulRetval = total; msfDebugOut((DEB_ITRACE, "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. // // // 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 CDirectStream::WriteAt( #ifdef LARGE_STREAMS ULONGLONG ulOffset, #else ULONG ulOffset, #endif VOID const HUGEP *pBuffer, ULONG ulCount, ULONG STACKBASED *pulRetval) { msfDebugOut((DEB_ITRACE,"In CDirectStream::WriteAt(%lu,%p,%lu)\n",ulOffset,pBuffer,ulCount)); *pulRetval = 0; if (0 == ulCount) return S_OK; SCODE sc; CMStream *pms; pms = _stmh.GetMS(); if (NULL == pms) return STG_E_UNKNOWN; if (ulOffset + ulCount > _ulSize) { if (_ulSize > MINISTREAMSIZE) { } else { msfChk(SetSize(ulOffset + ulCount)); } } // This should be an inline call to MWrite #ifdef SECURE_STREAMS if (ulOffset > _ulHighWater) { ClearSects(_ulHighWater, ulOffset); } #endif msfChk(pms->MWrite( _stmh.GetSid(), (_ulSize < MINISTREAMSIZE), ulOffset, pBuffer, ulCount, &_stmc, pulRetval)); msfDebugOut((DEB_ITRACE,"Leaving CDirectStream::WriteAt()==>%lu, ret is %lu\n",sc,*pulRetval)); Err: #ifdef SECURE_STREAMS if ((*pulRetval > 0 ) && (ulOffset + *pulRetval > _ulHighWater)) { _ulHighWater = ulOffset + *pulRetval; } #endif if (*pulRetval > 0 && ulOffset + *pulRetval > _ulSize) { SCODE scSet; _ulSize = ulOffset + *pulRetval; scSet = pms->GetDir()->SetSize(_stmh.GetSid(), _ulSize); if (SUCCEEDED(sc) && FAILED(scSet)) { sc = scSet; } } #ifdef SECURE_STREAMS msfAssert(_ulHighWater <= _ulSize); #endif 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. // // History: 29-Jul-91 PhilipLa Created. // 14-May-92 AlexT Add small object support // // 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. // //--------------------------------------------------------------------------- #ifdef LARGE_STREAMS SCODE CDirectStream::SetSize(ULONGLONG cbNewSize) #else SCODE CDirectStream::SetSize(ULONG cbNewSize) #endif { msfDebugOut((DEB_ITRACE,"In CDirectStream::SetSize(%lu)\n",cbNewSize)); SCODE sc = S_OK; BYTE *pBuf = NULL; SID sid = _stmh.GetSid(); CMStream *pms = _stmh.GetMS(); msfAssert(sid <= MAXREGSID); if (NULL == pms) return STG_E_UNKNOWN; CDirectory *pdir = pms->GetDir(); if (_ulSize == cbNewSize) { return S_OK; } #ifdef SECURE_STREAMS msfAssert(_ulHighWater <= _ulSize); #endif USHORT cbpsOld = pms->GetSectorSize(); // Count of Bytes Per Sector USHORT cbpsNew = cbpsOld; CFat *pfatOld = pms->GetFat(); CFat *pfatNew = pfatOld; if ((!pms->IsScratch()) && (SIDMINISTREAM != sid)) { // This is not a scratch DocFile, nor is this stream the ministream; // check if this stream is and/or will be stored in the ministream. if (cbNewSize < MINISTREAMSIZE) { cbpsNew = MINISECTORSIZE; pfatNew = pms->GetMiniFat(); } if (_ulSize < MINISTREAMSIZE) { cbpsOld = MINISECTORSIZE; pfatOld = pms->GetMiniFat(); } } ULONG csectOld = (ULONG)((_ulSize + cbpsOld - 1) / cbpsOld); ULONG csectNew = (ULONG)((cbNewSize + cbpsNew - 1) / cbpsNew); msfAssert(sid <= MAXREGSID); SECT sectstart, sectOldStart; msfChk(pdir->GetStart(sid, §start)); //Save start sector so we can free it later. sectOldStart = sectstart; 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)); ULONG cbCopy; cbCopy = 0; if (cbpsOld != cbpsNew) { // Sector sizes are different, so we'll copy the data msfAssert((cbNewSize > _ulSize ? _ulSize : cbNewSize) < 0x10000); cbCopy = (ULONG)(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); #ifdef SECURE_STREAMS //Part of the buffer may have gunk in it, so clear it out. if (_ulHighWater < cbCopy) { memset(pBuf + _ulHighWater, SECURECHAR, cbCopy - _ulHighWater); } #endif if ((FAILED(sc)) || ((ulRetVal != cbCopy) ? (sc = STG_E_UNKNOWN) : 0)) { msfErr(Err, sc); } #ifdef SECURE_STREAMS ClearSects(_ulHighWater, _ulSize); _ulHighWater = cbNewSize; #endif //The cache is no longer valid, so empty it. _stmc.Empty(); msfChk(_stmc.Allocate(pfatNew, csectNew, §start)); } else { SECT dummy; if ((csectOld > csectNew)) { #ifdef SECURE_STREAMS ClearSects(_ulHighWater, _ulSize); _ulHighWater = cbNewSize; #endif if (0 == csectNew) { //Note: We need to set the start sect in the directory // first in case the SetChainLength call fails part way // through, which would leave this directory entry pointing // to a FREESECT. SECT sectOldStart = sectstart; msfChk(pdir->SetStart(sid, ENDOFCHAIN)); sectstart = ENDOFCHAIN; msfChk(pfatOld->SetChainLength(sectOldStart, 0)); } else { msfChk(pfatOld->SetChainLength(sectstart, csectNew)); } //If this turns out to be a common case, we can // sometimes keep the cache valid here. _stmc.Empty(); } else if (0 == csectOld) { msfChk(_stmc.Allocate(pfatNew, csectNew, §start)); } else if (csectNew > csectOld) { ULONG start = csectNew - 1; msfChk(_stmc.GetESect(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. // Optimization - we only set the start sector if it has changed. if (sectstart != sectOldStart) { msfChk(pdir->SetStart(sid, sectstart)); } //If we fail here, we're in big trouble. msfChk(pdir->SetSize(sid, cbNewSize)); _ulSize = cbNewSize; #ifdef SECURE_STREAMS if (_ulHighWater > _ulSize) { _ulHighWater = _ulSize; } #endif 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()); } #ifdef SECURE if (((csectNew > csectOld) || (cbCopy > 0)) && ((cbNewSize & (cbpsNew - 1)) != 0)) { SECT sectLast; msfChk(_stmc.GetSect(csectNew - 1, §Last)); msfVerify(SUCCEEDED(pms->SecureSect( sectLast, cbNewSize, (cbNewSize < MINISTREAMSIZE) && (sid != SIDMINISTREAM)))); } #endif //SECURE #ifdef SECURE_STREAMS msfAssert(_ulHighWater <= _ulSize); #endif Err: #ifdef SECURE_STREAMS if (_ulHighWater > _ulSize) { _ulHighWater = _ulSize; } #endif // Optimization - avoid calling FreeBuffer (which will end up calling // out to CompObj.DLL) when pBuf is NULL (common case). if (pBuf != NULL) FreeBuffer(pBuf); if (FAILED(sc)) _stmc.Empty(); return sc; } //+------------------------------------------------------------------------- // // Method: CDirectStream::BeginCommitFromChild, public // // Synopsis: Begin a commit from a child stream // // Arguments: [ulSize] -- Size of child stream // [pDelta] -- Pointer to delta list // [pstChild] - Child // // Returns: S_OK if call completed successfully. // // Algorithm: *Finish This* // // History: 22-Jan-92 PhilipLa Created. // // Notes: // //-------------------------------------------------------------------------- SCODE CDirectStream::BeginCommitFromChild( #ifdef LARGE_STREAMS ULONGLONG ulSize, #else ULONG ulSize, #endif CDeltaList *pDelta, CTransactedStream *pstChild) { msfDebugOut((DEB_ITRACE,"In CDirectStream::BeginCommitFromChild:%p(" "%lu, %p, %p)\n", this, ulSize, pDelta, pstChild)); // msfDebugOut((DEB_ITRACE,"MultiStrean is %p\nStream name is: %ws\n",_stmh.GetMS(),((_stmh.GetMS()))->GetName(_stmh.GetSid()))); SCODE sc = S_OK; ULONG temp; BYTE *pb = NULL; _pdlHolder = P_TO_BP(CBasedDeltaListPtr, pDelta); // Copy-on-write will back out these changes if we fail #ifdef USE_NOSCRATCH //For no-scratch mode, we commit very differently than we do regularly, // unless this commit is somehow involving the minifat. if ((pDelta->IsNoScratch()) && (ulSize >= MINISTREAMSIZE) && ((_ulSize >= MINISTREAMSIZE) || (_ulSize == 0)) && (!pDelta->IsEmpty())) { USHORT cbSector = pDelta->GetDataSectorSize(); SECT sectEnd = (SECT)((ulSize + cbSector - 1) / cbSector); SECT sectLast = ENDOFCHAIN; //We update our size and directory first so the stream cache // code knows which fat to get to. _ulOldSize = _ulSize; _ulSize = ulSize; msfChk(_stmh.GetMS()->GetDir()->SetSize(_stmh.GetSid(), ulSize)); if (_ulOldSize > _ulSize) { //We need to truncate the chain. SECT sectStart; _stmh.GetMS()->GetDir()->GetStart(_stmh.GetSid(), §Start); _stmh.GetMS()->GetFat()->SetChainLength(sectStart, sectEnd); _stmc.Empty(); } for (ULONG i = 0; i < sectEnd; i++) { SECT sectDirty; SECT sectOld; SECT sectNext; //For each sector, chain the old sector with the //existing new one. msfChk(pDelta->GetMap(i, DL_READ, §Dirty)); if (sectDirty != ENDOFCHAIN) { if (i > 0) { CFat *pfat = _stmh.GetMS()->GetFat(); msfChk(_stmc.GetSect(i - 1, §Last)); msfAssert(sectLast != ENDOFCHAIN); msfChk(pfat->GetNext(sectLast, §Old)); msfChk(pfat->SetNext(sectLast, sectDirty)); if (sectOld != ENDOFCHAIN) { msfChk(pfat->GetNext(sectOld, §Next)); msfChk(pfat->SetNext(sectOld, FREESECT)); } else { sectNext = ENDOFCHAIN; } msfChk(pfat->SetNext(sectDirty, sectNext)); msfChk(_stmc.EmptyRegion(i, i)); } else { CFat *pfat = _stmh.GetMS()->GetFat(); CDirectory *pdir = _stmh.GetMS()->GetDir(); sectNext = ENDOFCHAIN; msfChk(pdir->GetStart(_stmh.GetSid(), §Last)); if (sectLast != ENDOFCHAIN) { msfChk(pfat->GetNext(sectLast, §Next)); msfChk(pfat->SetNext(sectLast, FREESECT)); } msfChk(pfat->SetNext(sectDirty, sectNext)); msfChk(pdir->SetStart(_stmh.GetSid(), sectDirty)); msfChk(_stmc.EmptyRegion(i, i)); } } } #ifdef SECURE_STREAMS _ulHighWater = _ulSize; #endif #if DBG == 1 //Make sure that the stream is sane. #ifdef LARGE_STREAMS ULONGLONG ulDirSize; #else ULONG ulDirSize; #endif ULONG cSect; ULONG cSectReal; SECT sectStart; _stmh.GetMS()->GetDir()->GetSize(_stmh.GetSid(), &ulDirSize); cSect = (ULONG)((ulDirSize + cbSector - 1) / cbSector); _stmh.GetMS()->GetDir()->GetStart(_stmh.GetSid(), §Start); _stmh.GetMS()->GetFat()->GetLength(sectStart, &cSectReal); msfAssert((cSect == cSectReal) && aMsg("Chain length incorrect after commit.")); #endif } else { #endif //USE_NOSCRATCH // Note: It's critical that we do this SetSize first (since we // use our scratch buffer below and SetSize can potentially also // use the scratch buffer. msfChk(SetSize(ulSize)); _ulOldSize = _ulSize; msfAssert(pDelta != NULL); if (!pDelta->IsEmpty()) { USHORT cbSector = pDelta->GetDataSectorSize(); USHORT uSectorShift = pDelta->GetDataSectorShift(); ULONG cbActualSize = 0; ULONG cbMaxSects = 15; GetSafeBuffer(cbSector, cbSector * cbMaxSects, &pb, &cbActualSize); BYTE *pbcurrent = pb; msfAssert((pb != NULL) && aMsg("Couldn't get scratch buffer")); cbMaxSects = cbActualSize / cbSector; OFFSET oEnd; oEnd = (OFFSET)((_ulSize - 1) % cbSector) + 1; SECT sectEnd; sectEnd = (SECT)((_ulSize + cbSector - 1) / cbSector); ULONG ulOffset; ILockBytes *pilbDirty; SECT sectBeginRead = ENDOFCHAIN; //the first sector to read SECT sectBeginWrite = ENDOFCHAIN; //the offset of the first place to write SECT sectDirty = ENDOFCHAIN; //the sector at this offset USHORT uReadCount = 0; ULARGE_INTEGER ulTmp; pilbDirty = pDelta->GetDataILB(); for (ulOffset = 0; ulOffset < sectEnd; ulOffset++) { if (sectDirty == ENDOFCHAIN) { sectBeginWrite = ulOffset; } msfChk(pDelta->GetMap(ulOffset, DL_READ, §Dirty)); // Read will happen when we have determined there is something to read // and either // we have reached an ENDOFCHAIN // we have reached a non-adjacent sector // or we have reached the maximun amount that can be read if ( (uReadCount) && ( (sectDirty == ENDOFCHAIN) || (sectDirty != sectBeginRead + uReadCount) || (ulOffset - sectBeginWrite == cbMaxSects) )) { msfDebugOut((DEB_ITRACE,"Reading %u sectors from sect %lu\n", uReadCount, sectBeginRead)); #ifdef LARGE_DOCFILE ulTmp.QuadPart = ConvertSectOffset(sectBeginRead, 0, uSectorShift); #else ULISet32(ulTmp, ConvertSectOffset(sectBeginRead, 0, uSectorShift)); #endif msfHChk(pilbDirty->ReadAt( ulTmp, pbcurrent, cbSector * uReadCount, (ULONG STACKBASED *)&temp)); pbcurrent += cbSector * uReadCount; sectBeginRead = sectDirty; //reset the ReadCount now that we are done reading if (sectDirty == ENDOFCHAIN) uReadCount = 0; else uReadCount = 1; } // increment the read count else if (sectDirty != ENDOFCHAIN) { if (sectBeginRead == ENDOFCHAIN) { sectBeginRead = sectDirty; uReadCount=1; } else if (sectDirty == sectBeginRead + uReadCount) { uReadCount++; } } // Write occurs when we have something to write // and we have reached an ENDOFCHAIN // or the write buffer is full if (((sectDirty == ENDOFCHAIN) && (sectBeginWrite != ulOffset) ) || (ulOffset - sectBeginWrite == cbMaxSects) ) { msfDebugOut((DEB_ITRACE,"Writing %u sectors from sect %lu\n", ulOffset - sectBeginWrite, sectBeginWrite)); msfChk(WriteAt(sectBeginWrite * cbSector, pb, cbSector * (ulOffset - sectBeginWrite), (ULONG STACKBASED *)&temp)); pbcurrent = pb; sectBeginWrite = ulOffset; } } // After loop, do last read and write if (uReadCount) { #ifdef LARGE_DOCFILE ulTmp.QuadPart = ConvertSectOffset(sectBeginRead, 0, uSectorShift); #else ULISet32(ulTmp, ConvertSectOffset(sectBeginRead, 0, uSectorShift)); #endif msfDebugOut((DEB_ITRACE,"END::Reading %u sectors from sect %lu\n", uReadCount, sectBeginRead)); msfHChk(pilbDirty->ReadAt( ulTmp, pbcurrent, cbSector * uReadCount, (ULONG STACKBASED *)&temp)); msfDebugOut((DEB_ITRACE,"END::Writing %u sectors from sect %lu\n", ulOffset - sectBeginWrite, sectBeginWrite)); msfChk(WriteAt(sectBeginWrite * cbSector, pb, // all sectors except the last one (cbSector * ((ulOffset-1) - sectBeginWrite) // last sector fragment + oEnd ), (ULONG STACKBASED *)&temp)); } } #ifdef USE_NOSCRATCH } #endif msfDebugOut((DEB_ITRACE,"Out CDirectStream::BeginCommitFromChild()\n")); Err: #ifdef SECURE_STREAMS msfAssert(_ulHighWater <= _ulSize); #endif FreeBuffer(pb); return sc; } //+------------------------------------------------------------------------- // // Method: CDirectStream::EndCommitFromChild // // Synopsis: End a commit sequence from a child stream // // Arguments: [df] -- Indicates whether to commit or abort // [pstChild] - Child // // Returns: S_OK if call completed successfully. // // Algorithm: *Finish This* // // History: 22-Jan-92 PhilipLa Created. // // Notes: // //-------------------------------------------------------------------------- void CDirectStream::EndCommitFromChild(DFLAGS df, CTransactedStream *pstChild) { msfDebugOut((DEB_ITRACE,"In CDirectStream::EndCommitFromChild:%p(" "%lu, %p)\n", this, df, pstChild)); if (!P_COMMIT(df)) { _ulSize = _ulOldSize; #ifdef SECURE_STREAMS _ulHighWater = _ulSize; #endif //Stream cache is no longer valid, so nuke it. _stmc.Empty(); } _pdlHolder = NULL; msfDebugOut((DEB_ITRACE,"Out CDirectStream::EndCommitFromChild()\n")); } //+--------------------------------------------------------------------------- // // Member: CDirectStream::GetSize, public // // Synopsis: Gets the size of the stream // // Arguments: [pulSize] - Size return // // Modifies: [pulSize] // // History: 08-May-92 DrewB Created // //---------------------------------------------------------------------------- #ifdef LARGE_STREAMS void CDirectStream::GetSize(ULONGLONG *pulSize) #else void CDirectStream::GetSize(ULONG *pulSize) #endif { *pulSize = _ulSize; } //+--------------------------------------------------------------------------- // // Member: CDirectStream::GetDeltaList, public // // Synopsis: Returns NULL, since a direct stream can never have // a delta list. // // Arguments: None. // // Returns: NULL // // History: 30-Jul-93 PhilipLa Created // //---------------------------------------------------------------------------- CDeltaList * CDirectStream::GetDeltaList(void) { return NULL; } #ifdef SECURE_STREAMS //+--------------------------------------------------------------------------- // // Member: CDirectStream::ClearSects, private // // Synopsis: // // Arguments: // // Returns: void // // History: 10-Oct-95 PhilipLa Created // //---------------------------------------------------------------------------- void CDirectStream::ClearSects(ULONG ulStartOffset, ULONG ulEndOffset) { ULONG cbBytesToWrite = ulEndOffset - ulStartOffset; ULONG ulOffset = ulStartOffset; msfAssert(ulEndOffset >= ulStartOffset); //Start offset must be less than high water mark, or the WriteAt // will recurse. msfAssert(ulStartOffset <= _ulHighWater); while (cbBytesToWrite > 0) { ULONG cbWritten; if (FAILED(WriteAt(ulOffset, s_bufSecure, min(MINISTREAMSIZE, cbBytesToWrite), &cbWritten))) { break; } ulOffset += cbWritten; cbBytesToWrite -= cbWritten; } return; } #endif