|
|
//+-------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: mstream.cxx
//
// Contents: Mstream operations
//
// Classes: None. (defined in mstream.hxx)
//
//--------------------------------------------------------------------
#include "msfhead.cxx"
#include "h/dirfunc.hxx"
#include "h/sstream.hxx"
#include "h/difat.hxx"
#include "h/msfiter.hxx"
#include <time.h>
#include "mread.hxx"
#include "h/docfilep.hxx"
#if DEVL == 1
DECLARE_INFOLEVEL(msf, DEB_ERROR)
#endif
#define MINPAGES 6
#define MAXPAGES 128
extern "C" WCHAR const wcsContents[] = {'C','O','N','T','E','N','T','S','\0'}; extern "C" CDfName const dfnContents(wcsContents); SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache);
//+---------------------------------------------------------------------------
//
// Function: GetBuffer, public
//
// Synopsis: Gets a chunk of memory to use as a buffer
//
// Arguments: [cbMin] - Minimum size for buffer
// [cbMax] - Maximum size for buffer
// [ppb] - Buffer pointer return
// [pcbActual] - Actual buffer size return
//
// Returns: Appropriate status code
//
// Modifies: [ppb]
// [pcbActual]
//
// Algorithm: Attempt to dynamically allocate [cbMax] bytes
// If that fails, halve allocation size and retry
// If allocation size falls below [cbMin], fail
//
// Notes: Buffer should be released with FreeBuffer
//
//----------------------------------------------------------------------------
SCODE GetBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb, USHORT *pcbActual) { USHORT cbSize; BYTE *pb; msfDebugOut((DEB_ITRACE, "In GetBuffer(%hu, %hu, %p, %p)\n", cbMin, cbMax, ppb, pcbActual)); msfAssert(cbMin > 0); msfAssert(cbMax >= cbMin); msfAssert(ppb != NULL); msfAssert(pcbActual != NULL); cbSize = cbMax; for (;;) { pb = new BYTE[cbSize]; if (pb == NULL) { cbSize >>= 1; if (cbSize < cbMin) break; } else { *pcbActual = cbSize; break; } }
*ppb = pb; msfDebugOut((DEB_ITRACE, "Out GetBuffer => %p, %hu\n", *ppb, *pcbActual)); return pb == NULL ? STG_E_INSUFFICIENTMEMORY : S_OK; }
// Define the safe buffer size
#define SCRATCHBUFFERSIZE ((USHORT) 4096)
static BYTE s_buf[SCRATCHBUFFERSIZE]; static LONG s_bufRef = 0;
//+---------------------------------------------------------------------------
//
// Function: GetSafeBuffer, public
//
// Synopsis: Gets a buffer by first trying GetBuffer and if that fails,
// returning a pointer to statically allocated storage.
// Guaranteed to return a pointer to some storage.
//
// Arguments: [cbMin] - Minimum buffer size
// [cbMax] - Maximum buffer size
// [ppb] - Buffer pointer return
// [pcbActual] - Actual buffer size return
//
// Modifies: [ppb]
// [pcbActual]
//
//----------------------------------------------------------------------------
void GetSafeBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb, USHORT *pcbActual) { msfAssert(cbMin > 0); msfAssert(cbMin <= SCRATCHBUFFERSIZE && aMsg("Minimum too large for GetSafeBuffer")); msfAssert(cbMax >= cbMin); msfAssert(ppb != NULL); msfAssert(s_bufRef == 0 && aMsg("Tried to use scratch buffer twice"));
if (cbMax <= SCRATCHBUFFERSIZE || FAILED(GetBuffer(cbMin, cbMax, ppb, pcbActual))) { s_bufRef = 1; *ppb = s_buf; *pcbActual = min(cbMax, SCRATCHBUFFERSIZE); } msfAssert(*ppb != NULL); }
//+---------------------------------------------------------------------------
//
// Function: FreeBuffer, public
//
// Synopsis: Releases a buffer allocated by GetBuffer or GetSafeBuffer
//
// Arguments: [pb] - Buffer
//
//----------------------------------------------------------------------------
void FreeBuffer(BYTE *pb) { if (pb == s_buf) { msfAssert((s_bufRef == 1) && aMsg("Bad safe buffer ref count")); s_bufRef = 0; } else delete [] pb; }
//+-------------------------------------------------------------------------
//
// Method: CMStream::CMStream, public
//
// Synopsis: CMStream constructor
//
// Arguments: [pplstParent] -- Pointer to ILockBytes pointer of parent
// [plGen] -- Pointer to LUID Generator to use.
// Note: May be NULL, in which case a new
// [uSectorShift] -- Sector shift for this MStream
//
//--------------------------------------------------------------------------
CMStream::CMStream( ILockBytes **pplstParent, USHORT uSectorShift) :_uSectorShift(uSectorShift), _uSectorSize( (USHORT) (1 << uSectorShift) ), _uSectorMask((USHORT) (_uSectorSize - 1)), _pplstParent(pplstParent), _hdr(uSectorShift), _fatDif( (USHORT) (1<<uSectorShift) ), _fat(SIDFAT, (USHORT) (1<<uSectorShift), uSectorShift), _dir((USHORT) (1 << uSectorShift)), _fatMini(SIDMINIFAT, (USHORT) (1 << uSectorShift), uSectorShift) { _pdsministream = NULL; _pmpt = NULL; }
//+-------------------------------------------------------------------------
//
// Method: CMStream::InitCommon, private
//
// Synopsis: Common code for initialization routines.
//
// Arguments: None.
//
// Returns: S_OK if call completed OK.
//
// Algorithm:
//
//--------------------------------------------------------------------------
SCODE CMStream::InitCommon(VOID) { msfDebugOut((DEB_ITRACE,"In CMStream InitCommon()\n")); SCODE sc = S_OK;
msfAssert(_pmpt == NULL); msfMem(_pmpt = new CMSFPageTable(this, MINPAGES, MAXPAGES)); msfChk(_pmpt->Init());
msfDebugOut((DEB_ITRACE,"Leaving CMStream InitCommon()\n"));
return sc;
Err: delete _pmpt; _pmpt = NULL; return sc; }
//+---------------------------------------------------------------------------
//
// Member: CMStream::GetESect, private
//
// Synopsis: For a given SID and sect, return the location of that
// sector in the multistream.
//
// Arguments: [sid] -- SID of sector to locate
// [sect] -- Offset into chain to locate
// [psect] -- Pointer to return location.
//
// Returns: Appropriate status code
//
// Modifies:
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMStream::GetESect(SID sid, SECT sect, SECT *psect) { SCODE sc = S_OK;
SECT start;
if (sid == SIDFAT) { msfChk(_fatDif.GetFatSect(sect, &start)); } else if (sid == SIDDIF) { msfChk(_fatDif.GetSect(sect, &start)); } else { start = GetStart(sid); msfChk(_fat.GetESect(start, sect, &start)); }
*psect = start; Err: return sc; }
//+---------------------------------------------------------------------------
//
// Member: CMStream::Empty, public
//
// Synopsis: Empty all of the control structures of this CMStream
//
// Arguments: None.
//
// Returns: void.
//
//----------------------------------------------------------------------------
void CMStream::Empty(void) { _fat.Empty(); _fatMini.Empty(); _fatDif.Empty(); _dir.Empty(); }
//+-------------------------------------------------------------------------
//
// Method: CMStream::~CMStream, public
//
// Synopsis: CMStream destructor
//
//--------------------------------------------------------------------------
CMStream::~CMStream() {
msfDebugOut((DEB_ITRACE,"In CMStream destructor\n"));
if (_pdsministream != NULL) { _pdsministream->Release(); }
if (_pmpt != NULL) { _pmpt->Release(); }
msfDebugOut((DEB_ITRACE,"Leaving CMStream destructor\n")); }
//+-------------------------------------------------------------------------
//
// Member: CMStream::GetIterator, public
//
// Synposis: Create a new iterator for a given handle.
//
// Effects: Creates a new CMSFIterator
//
// Arguments: [sidParent] -- SID of entry to iterate over
// [ppitRetval] -- Location for return of iterator pointer
//
// Returns: S_OK
//
// Algorithm: Create new iterator with parent of 'this' and nsi as given
// by handle.
//
// Notes:
//
//---------------------------------------------------------------------------
SCODE CMStream::GetIterator( SID const sidParent, CMSFIterator **ppitRetval) { SCODE sc;
msfDebugOut((DEB_TRACE,"In CMStream::GetIterator()\n"));
SID sidChild; msfChk(_dir.GetChild(sidParent, &sidChild));
msfDebugOut((DEB_ITRACE, "Getting an iterator for SID = %lu, " "sidChild is %lu\n", sidParent, sidChild)); msfMem(*ppitRetval = new CMSFIterator(GetDir(), sidChild)); msfDebugOut((DEB_TRACE,"Leaving CMStream::GetIterator()\n"));
Err: return sc; }
//+-------------------------------------------------------------------------
//
// Member: CMStream::Init, public
//
// Synposis: Set up an mstream instance from an existing stream
//
// Effects: Modifies Fat and Directory
//
// Arguments: void.
//
// Returns: S_OK if call completed OK.
// Error of Fat or Dir setup otherwise.
//
// Notes:
//
//---------------------------------------------------------------------------
SCODE CMStream::Init(VOID) { ULONG ulTemp; SCODE sc; ULARGE_INTEGER ulOffset;
msfDebugOut((DEB_ITRACE,"In CMStream::Init()\n"));
msfChk(InitCommon());
ULISet32(ulOffset, 0); msfHChk((*_pplstParent)->ReadAt(ulOffset, (BYTE *)(&_hdr), sizeof(CMSFHeader), &ulTemp)); _hdr.ByteSwap(); // swap to memory/machine format if neccessary
_uSectorShift = _hdr.GetSectorShift(); _uSectorSize = (USHORT) (1 << _uSectorShift); _uSectorMask = (USHORT) (_uSectorSize - 1);
if (ulTemp != sizeof(CMSFHeader)) { msfErr(Err,STG_E_INVALIDHEADER); }
msfChk(_hdr.Validate());
msfChk(_fatDif.Init(this, _hdr.GetDifLength())); msfChk(_fat.Init(this, _hdr.GetFatLength(), 0));
FSINDEX fsiLen; if (_uSectorShift > SECTORSHIFT512) fsiLen = _hdr.GetDirLength (); else msfChk(_fat.GetLength(_hdr.GetDirStart(), &fsiLen)); msfChk(_dir.Init(this, fsiLen));
msfChk(_fatMini.Init(this, _hdr.GetMiniFatLength(), 0));
ULONGLONG ulSize; msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize)); msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID)); _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
msfDebugOut((DEB_TRACE,"Out CMStream::Init()\n"));
Err: return sc; }
//+-------------------------------------------------------------------------
//
// Member: CMStream::InitNew, public
//
// Synposis: Set up a brand new mstream instance
//
// Effects: Modifies FAT and Directory
//
// Arguments: [fDelay] -- If TRUE, then the parent LStream
// will be truncated at the time of first
// entrance to COW, and no writes to the
// LStream will happen before then.
//
// Returns: S_OK if call completed OK.
//
//---------------------------------------------------------------------------
SCODE CMStream::InitNew(VOID) { SCODE sc;
msfDebugOut((DEB_ITRACE,"In CMStream::InitNew()\n"));
msfChk(InitCommon());
ULARGE_INTEGER ulTmp;
ulTmp.QuadPart = 0; (*_pplstParent)->SetSize(ulTmp);
msfChk(_fatDif.InitNew(this)); msfChk(_fat.InitNew(this)); msfChk(_dir.InitNew(this));
msfChk(_fatMini.InitNew(this)); ULONGLONG ulSize; msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID)); _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
msfChk(Flush(0));
msfDebugOut((DEB_TRACE,"Out CMStream::InitNew()\n")); return S_OK;
Err: Empty();
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CMStream::ConvertILB, private
//
// Synopsis: Copy the first sector of the underlying ILockBytes
// out to the end.
//
// Arguments: [sectMax] -- Total number of sectors in the ILockBytes
//
// Returns: Appropriate status code
//
//----------------------------------------------------------------------------
SCODE CMStream::ConvertILB(SECT sectMax) { SCODE sc; BYTE *pb; USHORT cbNull;
GetSafeBuffer(GetSectorSize(), GetSectorSize(), &pb, &cbNull);
ULONG ulTemp;
ULARGE_INTEGER ulTmp; ULISet32(ulTmp, 0);
msfHChk((*_pplstParent)->ReadAt(ulTmp, pb, GetSectorSize(), &ulTemp));
ULARGE_INTEGER ulNewPos; ulNewPos.QuadPart = (ULONGLONG)(sectMax) << GetSectorShift();
msfHChk((*_pplstParent)->WriteAt( ulNewPos, pb, GetSectorSize(), &ulTemp));
Err: FreeBuffer(pb); return sc; }
//+-------------------------------------------------------------------------
//
// Method: CMStream::InitConvert, public
//
// Synopsis: Init function used in conversion of files to multi
// streams.
//
// Arguments: [fDelayConvert] -- If true, the actual file is not
// touched until a BeginCopyOnWrite()
//
// Returns: S_OK if everything completed OK.
//
// Algorithm: *Finish This*
//
// Notes: We are allowed to fail here in low memory
//
//--------------------------------------------------------------------------
SCODE CMStream::InitConvert(VOID) { SCODE sc;
SECT sectMax; msfChk(InitCommon());
STATSTG stat; (*_pplstParent)->Stat(&stat, STATFLAG_NONAME);
sectMax = (SECT)((stat.cbSize.QuadPart + GetSectorSize() - 1) >> GetSectorShift());
SECT sectMaxMini = 0; BOOL fIsMini; fIsMini = FALSE;
//If the CONTENTS stream will be in the Minifat, compute
// the number of Minifat sectors needed.
if (stat.cbSize.QuadPart < MINISTREAMSIZE) { sectMaxMini = (SECT)((stat.cbSize.QuadPart + MINISECTORSIZE - 1) >> MINISECTORSHIFT); fIsMini = TRUE; }
msfChk(_fatDif.InitConvert(this, sectMax)); msfChk(_fat.InitConvert(this, sectMax)); msfChk(_dir.InitNew(this)); msfChk(fIsMini ? _fatMini.InitConvert(this, sectMaxMini) : _fatMini.InitNew(this));
SID sid;
msfChk(CreateEntry(SIDROOT, &dfnContents, STGTY_STREAM, &sid)); msfChk(_dir.SetSize(sid, stat.cbSize.QuadPart));
if (!fIsMini) msfChk(_dir.SetStart(sid, sectMax - 1)); else { msfChk(_dir.SetStart(sid, 0)); msfChk(_dir.SetStart(SIDMINISTREAM, sectMax - 1)); msfChk(_dir.SetSize(SIDMINISTREAM, stat.cbSize.QuadPart)); }
ULONGLONG ulMiniSize; msfChk(_dir.GetSize(SIDMINISTREAM, &ulMiniSize)); msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID)); _pdsministream->InitSystem(this, SIDMINISTREAM, ulMiniSize);
msfChk(ConvertILB(sectMax));
msfChk(Flush(0));
return S_OK;
Err: Empty();
return sc; }
//+-------------------------------------------------------------------------
//
// Method: CMStream::GetName, public
//
// Synopsis: Given a handle, return the current name of that entry
//
// Arguments: [sid] -- SID to find name for.
//
// Returns: Pointer to name.
//
//--------------------------------------------------------------------------
SCODE CMStream::GetName(SID const sid, CDfName *pdfn) { return _dir.GetName(sid, pdfn); }
//+-------------------------------------------------------------------------
//
// Method: CMStream::FlushHeader, public
//
// Synopsis: Flush the header to the LStream.
//
// Arguments: [uForce] -- Flag to determine if header should be
// flushed while in copy on write mode.
//
// Returns: S_OK if call completed OK.
// S_OK if the MStream is in copy on write mode or
// is Unconverted and the header was not flushed.
//
// Algorithm: Write the complete header out to the 0th position of
// the LStream.
//
// Notes:
//
//--------------------------------------------------------------------------
SCODE CMStream::FlushHeader(USHORT uForce) { ULONG ulTemp; SCODE sc;
UNREFERENCED_PARM(uForce); msfDebugOut((DEB_ITRACE,"In CMStream::FlushHeader()\n"));
ULARGE_INTEGER ulOffset; ULISet32(ulOffset, 0); _hdr.ByteSwap(); // swap to disk format if neccessary
sc = DfGetScode((*_pplstParent)-> WriteAt(ulOffset, (BYTE *)(&_hdr), sizeof(CMSFHeader), &ulTemp)); _hdr.ByteSwap(); // swap to memort/machine format if neccessary
msfDebugOut((DEB_ITRACE,"Out CMStream::FlushHeader()\n")); return sc; }
//+-------------------------------------------------------------------------
//
// Member: CMStream::MWrite, public
//
// Synposis: Do multiple sector writes
//
// Effects: Causes multiple stream writes. Modifies fat and directory
//
// Arguments: [ph] -- Handle of stream doing write
// [start] -- Starting sector to write
// [oStart] -- offset into sector to begin write at
// [end] -- Last sector to write
// [oEnd] -- offset into last sector to write to
// [buffer] -- Pointer to buffer into which data will be written
// [ulRetVal] -- location to return number of bytes written
//
// Returns: Error code of any failed call to parent write
// S_OK if call completed OK.
//
// Modifies: ulRetVal returns the number of bytes written
//
// Algorithm: Using a segment table, perform writes on parent stream
// until call is completed.
//
// Notes:
//
//---------------------------------------------------------------------------
SCODE CMStream::MWrite( SID sid, BOOL fIsMini, ULONGLONG ulOffset, VOID const HUGEP *pvBuffer, ULONG ulCount, CStreamCache *pstmc, ULONG *pulRetval) { SCODE sc; BYTE const HUGEP *pbBuffer = (BYTE const HUGEP *) pvBuffer;
USHORT cbSector = GetSectorSize(); CFat *pfat = &_fat; USHORT uShift = GetSectorShift(); ULONG ulLastBytes = 0;
ULARGE_INTEGER ulOff; ulOff.QuadPart = 0;
ULONGLONG ulOldSize = 0; // Check if it's a small stream and whether this is a real
// multistream.
if ((fIsMini) && (SIDMINISTREAM != sid)) { msfAssert(sid <= MAXREGSID && aMsg("Invalid SID in MWrite")); // This stream is stored in the ministream
cbSector = MINISECTORSIZE; uShift = MINISECTORSHIFT; pfat = GetMiniFat(); }
USHORT uMask = (USHORT) (cbSector - 1);
SECT start = (SECT)(ulOffset >> uShift); OFFSET oStart = (OFFSET)(ulOffset & uMask);
SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift); OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
msfDebugOut((DEB_ITRACE,"In CMStream::MWrite(%lu,%u,%lu,%u)\n", start,oStart,end,oEnd));
ULONG bytecount; ULONG total = 0;
msfChk(_dir.GetSize(sid, &ulOldSize));
msfAssert(end != 0xffffffffL);
if (end < start) { *pulRetval = total + ulLastBytes; goto Err; }
ULONG ulRunLength; ulRunLength = end - start + 1; SECT sectSidStart;
USHORT offset; offset = oStart;
while (TRUE) { SSegment segtab[CSEG + 1]; SECT sect;
if (start > pstmc->GetOffset()) { msfChk(pfat->GetESect( pstmc->GetSect(), start - pstmc->GetOffset(), §)); } else if (start == pstmc->GetOffset()) { sect = pstmc->GetSect(); } else { msfChk(_dir.GetStart(sid, §SidStart)); msfChk(pfat->GetESect(sectSidStart, start, §)); }
msfChk(pfat->Contig( (SSegment STACKBASED *) segtab, sect, ulRunLength));
USHORT oend = (USHORT) (cbSector - 1); ULONG i = 0; SECT sectStart = ENDOFCHAIN; for (USHORT iseg = 0; iseg < CSEG;) { sectStart = segtab[iseg].sectStart; i = segtab[iseg].cSect;
if (i > ulRunLength) i = ulRunLength;
ulRunLength -= i; start += i;
iseg++; if (segtab[iseg].sectStart == ENDOFCHAIN) { msfAssert(ulRunLength==0); oend = oEnd; }
ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
msfDebugOut(( DEB_ITRACE, "Calling lstream WriteAt(%lu,%p,%lu)\n", ConvertSectOffset(sectStart,offset,uShift), pbBuffer, ulSize));
if (GetMiniFat() == pfat) { sc = _pdsministream->CDirectStream::WriteAt( (sectStart << uShift) + offset, pbBuffer, ulSize, (ULONG STACKBASED *)&bytecount); } else { ulOff.QuadPart = ConvertSectOffset(sectStart, offset, uShift); sc = DfGetScode((*_pplstParent)->WriteAt(ulOff, pbBuffer, ulSize, &bytecount)); }
total += bytecount;
//Check if this write is the last one in the stream,
// and that the stream ends as a partial sector.
//If so, fill out the remainder of the sector with
// something.
if ((0 == ulRunLength) && (total + ulOffset > ulOldSize) && (((total + ulOffset) & (GetSectorSize() - 1)) != 0)) { //This is the last sector and the stream has grown.
ULONG csectOld = (SECT)((ulOldSize + GetSectorSize() - 1) >> GetSectorShift());
ULONG csectNew = (SECT)((total + ulOffset + GetSectorSize() - 1) >> GetSectorShift());
if (csectNew > csectOld) { msfAssert(!fIsMini && aMsg("Small stream grew in MWrite")); SECT sectLast = sectStart + i - 1; msfVerify(SUCCEEDED(SecureSect( sectLast, total + ulOffset, FALSE))); } } if (0 == ulRunLength || FAILED(sc)) { break; }
pbBuffer = pbBuffer + bytecount; offset = 0; }
pstmc->SetCache(start -1, sectStart + i - 1); if (0 == ulRunLength || FAILED(sc)) { *pulRetval = total + ulLastBytes; msfDebugOut(( DEB_TRACE, "Out CMStream::MWrite()=>%lu, retval = %lu\n", sc, total)); break; } }
Err: // We need this flush of the directory structures because we may have
// remapped the first sector in a chain.
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CMStream::Flush, public
//
// Synopsis: Flush control structures.
//
// Arguments: None.
//
// Returns: Appropriate status code
//
//----------------------------------------------------------------------------
SCODE CMStream::Flush(BOOL fFlushCache) { SCODE sc = S_OK;
msfChk(_dir.Flush()); msfChk(_fatMini.Flush()); msfChk(_fat.Flush()); msfChk(_fatDif.Flush()); msfChk(FlushHeader(HDR_NOFORCE)); msfChk(ILBFlush(*_pplstParent, fFlushCache)); Err: return sc; }
//+-------------------------------------------------------------------------
//
// Function: ILBFlush
//
// Synopsis: Flush as thoroughly as possible
//
// Effects: Flushes ILockBytes
//
// Arguments: [pilb] - ILockBytes to flush
// [fFlushCache] - Flush thoroughly iff TRUE
//
// Returns: SCODE
//
// Algorithm:
//
//--------------------------------------------------------------------------
SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache) { SCODE sc; UNREFERENCED_PARM(fFlushCache); // no cache used here
msfDebugOut((DEB_ITRACE, "In ILBFlushCache(%p)\n", pilb));
sc = DfGetScode(pilb->Flush());
msfDebugOut((DEB_ITRACE, "Out ILBFlushCache()\n"));
return(sc); }
//+---------------------------------------------------------------------------
//
// Member: CMStream::SecureSect, public
//
// Synopsis: Zero out the unused portion of a sector
//
// Arguments: [sect] -- Sector to zero out
// [ulSize] -- Size of stream
// [fIsMini] -- TRUE if stream is in ministream
//
// Returns: Appropriate status code
//
// Modifies:
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMStream::SecureSect( const SECT sect, const ULONGLONG ulSize, const BOOL fIsMini) { SCODE sc = S_OK; BYTE *pb = NULL; ULONG cbSect = fIsMini ? MINISECTORSIZE : GetSectorSize(); msfAssert(ulSize != 0); OFFSET ulOffset = (OFFSET)((ulSize - 1) % cbSect) + 1; ULONG cb = cbSect - ulOffset; msfAssert(cb != 0); // We can use any initialized block of memory here. The header
// is available and is the correct size, so we use that.
pb = (BYTE *)&_hdr;
ULONG cbWritten; if (!fIsMini) { ULARGE_INTEGER ulOff; ulOff.QuadPart = ConvertSectOffset( sect, ulOffset, GetSectorShift()); msfChk(DfGetScode((*_pplstParent)-> WriteAt( ulOff, pb, cb, &cbWritten))); } else { msfChk(_pdsministream->WriteAt( (sect << MINISECTORSHIFT) + ulOffset, pb, cb, (ULONG STACKBASED *)&cbWritten)); } if (cbWritten != cb) { sc = STG_E_WRITEFAULT; } Err: return sc; }
|