1 //-------------------------------------------------------------------
2 //
3 //  For conditions of distribution and use, see copyright notice
4 //  in Flashpix.h
5 //
6 //  Copyright (c) 1999 Digital Imaging Group, Inc.
7 //
8 //  Contents:       Mstream operations
9 //
10 //  Classes:        None. (defined in mstream.hxx)
11 //
12 //--------------------------------------------------------------------
13 
14 #include "msfhead.cxx"
15 
16 
17 #include "h/dirfunc.hxx"
18 #include "h/sstream.hxx"
19 #include "h/difat.hxx"
20 #include "h/msfiter.hxx"
21 #include <time.h>
22 #include "mread.hxx"
23 #include "h/docfilep.hxx"
24 
25 #ifndef min
26 #define min(a, b) ((a)<(b) ? (a) : (b))
27 #endif
28 #ifndef max
29 #define max(a, b) ((a)>(b) ? (a) : (b))
30 #endif
31 
32 #if DEVL == 1
33 
34 DECLARE_INFOLEVEL(msf, DEB_ERROR)
35 
36 #endif
37 
38 #define MINPAGES 6
39 #define MAXPAGES 12
40 
41 extern "C" WCHAR const wcsContents[] =
42   {'C','O','N','T','E','N','T','S','\0'};
43 extern "C" CDfName const dfnContents(wcsContents);
44 SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache);
45 
46 //+---------------------------------------------------------------------------
47 //
48 //  Function: GetBuffer, public
49 //
50 //  Synopsis: Gets a chunk of memory to use as a buffer
51 //
52 //  Arguments:  [cbMin] - Minimum size for buffer
53 //              [cbMax] - Maximum size for buffer
54 //              [ppb] - Buffer pointer return
55 //              [pcbActual] - Actual buffer size return
56 //
57 //  Returns:  Appropriate status code
58 //
59 //  Modifies: [ppb]
60 //              [pcbActual]
61 //
62 //  Algorithm:  Attempt to dynamically allocate [cbMax] bytes
63 //              If that fails, halve allocation size and retry
64 //              If allocation size falls below [cbMin], fail
65 //
66 //  Notes:  Buffer should be released with FreeBuffer
67 //
68 //----------------------------------------------------------------------------
69 
GetBuffer(USHORT cbMin,USHORT cbMax,BYTE ** ppb,USHORT * pcbActual)70 SCODE GetBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb, USHORT *pcbActual)
71 {
72     USHORT cbSize;
73     BYTE *pb;
74 
75     msfDebugOut((DEB_ITRACE, "In  GetBuffer(%hu, %hu, %p, %p)\n",
76                  cbMin, cbMax, ppb, pcbActual));
77     msfAssert(cbMin > 0);
78     msfAssert(cbMax >= cbMin);
79     msfAssert(ppb != NULL);
80     msfAssert(pcbActual != NULL);
81 
82     cbSize = cbMax;
83     for (;;)
84     {
85         pb = new BYTE[cbSize];
86         if (pb == NULL)
87         {
88             cbSize >>= 1;
89             if (cbSize < cbMin)
90                 break;
91         }
92         else
93         {
94             *pcbActual = cbSize;
95             break;
96         }
97     }
98 
99     *ppb = pb;
100 
101     msfDebugOut((DEB_ITRACE, "Out GetBuffer => %p, %hu\n", *ppb, *pcbActual));
102     return pb == NULL ? STG_E_INSUFFICIENTMEMORY : S_OK;
103 }
104 
105 // Define the safe buffer size
106 #define SCRATCHBUFFERSIZE ((USHORT) 4096)
107 static BYTE s_buf[SCRATCHBUFFERSIZE];
108 static LONG s_bufRef = 0;
109 
110 
111 
112 //+---------------------------------------------------------------------------
113 //
114 //  Function: GetSafeBuffer, public
115 //
116 //  Synopsis: Gets a buffer by first trying GetBuffer and if that fails,
117 //              returning a pointer to statically allocated storage.
118 //              Guaranteed to return a pointer to some storage.
119 //
120 //  Arguments:  [cbMin] - Minimum buffer size
121 //              [cbMax] - Maximum buffer size
122 //              [ppb] - Buffer pointer return
123 //              [pcbActual] - Actual buffer size return
124 //
125 //  Modifies: [ppb]
126 //              [pcbActual]
127 //
128 //----------------------------------------------------------------------------
129 
GetSafeBuffer(USHORT cbMin,USHORT cbMax,BYTE ** ppb,USHORT * pcbActual)130 void GetSafeBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb, USHORT *pcbActual)
131 {
132     msfAssert(cbMin > 0);
133     msfAssert(cbMin <= SCRATCHBUFFERSIZE &&
134               aMsg("Minimum too large for GetSafeBuffer"));
135     msfAssert(cbMax >= cbMin);
136     msfAssert(ppb != NULL);
137     msfAssert(s_bufRef == 0 &&
138               aMsg("Tried to use scratch buffer twice"));
139 
140     if (cbMax <= SCRATCHBUFFERSIZE ||
141         FAILED(GetBuffer(cbMin, cbMax, ppb, pcbActual)))
142     {
143         s_bufRef = 1;
144         *ppb = s_buf;
145         *pcbActual = min(cbMax, SCRATCHBUFFERSIZE);
146     }
147     msfAssert(*ppb != NULL);
148 }
149 
150 //+---------------------------------------------------------------------------
151 //
152 //  Function: FreeBuffer, public
153 //
154 //  Synopsis: Releases a buffer allocated by GetBuffer or GetSafeBuffer
155 //
156 //  Arguments:  [pb] - Buffer
157 //
158 //----------------------------------------------------------------------------
159 
FreeBuffer(BYTE * pb)160 void FreeBuffer(BYTE *pb)
161 {
162     if (pb == s_buf)
163     {
164         msfAssert((s_bufRef == 1) && aMsg("Bad safe buffer ref count"));
165         s_bufRef = 0;
166     }
167     else
168         delete [] pb;
169 }
170 
171 
172 //+-------------------------------------------------------------------------
173 //
174 //  Method:     CMStream::CMStream, public
175 //
176 //  Synopsis:   CMStream constructor
177 //
178 //  Arguments:  [pplstParent] -- Pointer to ILockBytes pointer of parent
179 //              [plGen] -- Pointer to LUID Generator to use.
180 //                         Note:  May be NULL, in which case a new
181 //              [uSectorShift] -- Sector shift for this MStream
182 //
183 //--------------------------------------------------------------------------
184 
185 
CMStream(ILockBytes ** pplstParent,USHORT uSectorShift)186 CMStream::CMStream(
187     ILockBytes **pplstParent,
188     USHORT uSectorShift)
189     : _pplstParent(pplstParent),
190       _hdr(uSectorShift),
191       _dir((USHORT) (1 << uSectorShift)),
192       _fat(SIDFAT, (USHORT) (1<<uSectorShift), uSectorShift),
193       _fatDif( (USHORT) (1<<uSectorShift) ),
194       _fatMini(SIDMINIFAT, (USHORT) (1 << uSectorShift), uSectorShift),
195       _uSectorSize( (USHORT) (1 << uSectorShift) ),
196       _uSectorShift(uSectorShift),
197       _uSectorMask((USHORT) (_uSectorSize - 1))
198 {
199   _pdsministream = NULL;
200   _pmpt = NULL;
201 }
202 
203 
204 
205 
206 //+-------------------------------------------------------------------------
207 //
208 //  Method:     CMStream::InitCommon, private
209 //
210 //  Synopsis:   Common code for initialization routines.
211 //
212 //  Arguments:  None.
213 //
214 //  Returns:    S_OK if call completed OK.
215 //
216 //  Algorithm:
217 //
218 //--------------------------------------------------------------------------
219 
InitCommon()220 SCODE  CMStream::InitCommon()
221 {
222     msfDebugOut((DEB_ITRACE,"In CMStream InitCommon()\n"));
223     SCODE sc = S_OK;
224 
225     msfAssert(_pmpt == NULL);
226     msfMem(_pmpt = new CMSFPageTable(this, MINPAGES, MAXPAGES));
227     msfChk(_pmpt->Init());
228 
229     msfDebugOut((DEB_ITRACE,"Leaving CMStream InitCommon()\n"));
230 
231     return sc;
232 
233 Err:
234     delete _pmpt;
235     _pmpt = NULL;
236     return sc;
237 }
238 
239 //+---------------------------------------------------------------------------
240 //
241 //  Member:     CMStream::GetESect, private
242 //
243 //  Synopsis:   For a given SID and sect, return the location of that
244 //              sector in the multistream.
245 //
246 //  Arguments:  [sid] -- SID of sector to locate
247 //              [sect] -- Offset into chain to locate
248 //              [psect] -- Pointer to return location.
249 //
250 //  Returns:    Appropriate status code
251 //
252 //  Modifies:
253 //
254 //  Notes:
255 //
256 //----------------------------------------------------------------------------
257 
GetESect(SID sid,SECT sect,SECT * psect)258 SCODE CMStream::GetESect(SID sid, SECT sect, SECT *psect)
259 {
260     SCODE sc = S_OK;
261 
262     SECT start;
263 
264     if (sid == SIDFAT)
265     {
266         msfChk(_fatDif.GetFatSect(sect, &start));
267     }
268     else if (sid == SIDDIF)
269     {
270         msfChk(_fatDif.GetSect(sect, &start));
271     }
272     else
273     {
274         start = GetStart(sid);
275         msfChk(_fat.GetESect(start, sect, &start));
276     }
277 
278     *psect = start;
279 Err:
280     return sc;
281                     }
282 
283 //+---------------------------------------------------------------------------
284 //
285 //  Member: CMStream::Empty, public
286 //
287 //  Synopsis: Empty all of the control structures of this CMStream
288 //
289 //  Arguments:  None.
290 //
291 //  Returns:  void.
292 //
293 //----------------------------------------------------------------------------
294 
295 
Empty(void)296 void CMStream::Empty(void)
297 {
298     _fat.Empty();
299     _fatMini.Empty();
300     _fatDif.Empty();
301     _dir.Empty();
302 }
303 
304 //+-------------------------------------------------------------------------
305 //
306 //  Method:     CMStream::~CMStream, public
307 //
308 //  Synopsis:   CMStream destructor
309 //
310 //--------------------------------------------------------------------------
311 
~CMStream()312  CMStream::~CMStream()
313 {
314 
315     msfDebugOut((DEB_ITRACE,"In CMStream destructor\n"));
316 
317 
318     if (_pdsministream != NULL)
319     {
320         _pdsministream->Release();
321     }
322 
323     if (_pmpt != NULL)
324     {
325         _pmpt->Release();
326     }
327 
328     msfDebugOut((DEB_ITRACE,"Leaving CMStream destructor\n"));
329 }
330 
331 
332 //+-------------------------------------------------------------------------
333 //
334 //  Member:     CMStream::GetIterator, public
335 //
336 //  Synposis:   Create a new iterator for a given handle.
337 //
338 //  Effects:    Creates a new CMSFIterator
339 //
340 //  Arguments:  [sidParent] -- SID of entry to iterate over
341 //              [ppitRetval] -- Location for return of iterator pointer
342 //
343 //  Returns:    S_OK
344 //
345 //  Algorithm:  Create new iterator with parent of 'this' and nsi as given
346 //              by handle.
347 //
348 //  Notes:
349 //
350 //---------------------------------------------------------------------------
351 
352 
GetIterator(SID const sidParent,CMSFIterator ** ppitRetval)353 SCODE  CMStream::GetIterator(
354     SID const sidParent,
355     CMSFIterator **ppitRetval)
356 {
357     SCODE sc;
358 
359     msfDebugOut((DEB_TRACE,"In CMStream::GetIterator()\n"));
360 
361     SID sidChild;
362     msfChk(_dir.GetChild(sidParent, &sidChild));
363 
364     msfDebugOut((DEB_ITRACE, "Getting an iterator for SID = %lu, "
365                  "sidChild is %lu\n", sidParent, sidChild));
366     msfMem(*ppitRetval = new CMSFIterator(GetDir(), sidChild));
367     msfDebugOut((DEB_TRACE,"Leaving CMStream::GetIterator()\n"));
368 
369 Err:
370     return sc;
371 }
372 
373 
374 //+-------------------------------------------------------------------------
375 //
376 //  Member:     CMStream::Init, public
377 //
378 //  Synposis:   Set up an mstream instance from an existing stream
379 //
380 //  Effects:    Modifies Fat and Directory
381 //
382 //  Arguments:  void.
383 //
384 //  Returns:    S_OK if call completed OK.
385 //              Error of Fat or Dir setup otherwise.
386 //
387 //  Notes:
388 //
389 //---------------------------------------------------------------------------
390 
391 
Init()392 SCODE  CMStream::Init()
393 {
394     ULONG ulTemp;
395     SCODE sc;
396     ULARGE_INTEGER ulOffset;
397 
398 
399     msfDebugOut((DEB_ITRACE,"In CMStream::Init()\n"));
400 
401 
402     msfChk(InitCommon());
403 
404 
405     ULISet32(ulOffset, 0);
406     msfHChk((*_pplstParent)->ReadAt(ulOffset, (BYTE *)(&_hdr),
407                                     sizeof(CMSFHeader), &ulTemp));
408     _hdr.ByteSwap();  // swap to memory/machine format if neccessary
409 
410     _uSectorShift = _hdr.GetSectorShift();
411     _uSectorSize = (USHORT) (1 << _uSectorShift);
412     _uSectorMask = (USHORT) (_uSectorSize - 1);
413 
414     if (ulTemp != sizeof(CMSFHeader))
415     {
416         msfErr(Err,STG_E_INVALIDHEADER);
417     }
418 
419     msfChk(_hdr.Validate());
420 
421     msfChk(_fatDif.Init(this, _hdr.GetDifLength()));
422     msfChk(_fat.Init(this, _hdr.GetFatLength(), 0));
423 
424     FSINDEX fsiLen;
425     msfChk(_fat.GetLength(_hdr.GetDirStart(), &fsiLen));
426     msfChk(_dir.Init(this, fsiLen));
427 
428     msfChk(_fatMini.Init(this, _hdr.GetMiniFatLength(), 0));
429 
430     ULONG ulSize;
431     msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
432     msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
433     _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
434 
435     msfDebugOut((DEB_TRACE,"Out CMStream::Init()\n"));
436 
437 Err:
438     return sc;
439 }
440 
441 
442 
443 //+-------------------------------------------------------------------------
444 //
445 //  Member:     CMStream::InitNew, public
446 //
447 //  Synposis:   Set up a brand new mstream instance
448 //
449 //  Effects:    Modifies FAT and Directory
450 //
451 //  Arguments:  [fDelay] -- If TRUE, then the parent LStream
452 //                  will be truncated at the time of first
453 //                  entrance to COW, and no writes to the
454 //                  LStream will happen before then.
455 //
456 //  Returns:    S_OK if call completed OK.
457 //
458 //---------------------------------------------------------------------------
459 
InitNew()460 SCODE CMStream::InitNew()
461 {
462     SCODE sc;
463 
464     msfDebugOut((DEB_ITRACE,"In CMStream::InitNew()\n"));
465 
466 
467     msfChk(InitCommon());
468 
469     ULARGE_INTEGER ulTmp;
470 
471     ULISet32(ulTmp, 0);
472     (*_pplstParent)->SetSize(ulTmp);
473 
474     msfChk(_fatDif.InitNew(this));
475     msfChk(_fat.InitNew(this));
476     msfChk(_dir.InitNew(this));
477 
478     msfChk(_fatMini.InitNew(this));
479 
480     ULONG ulSize;
481     msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
482 
483     msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
484     _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
485 
486 
487     msfChk(Flush(0));
488 
489 
490     msfDebugOut((DEB_TRACE,"Out CMStream::InitNew()\n"));
491     return S_OK;
492 
493 Err:
494     Empty();
495 
496     return sc;
497 }
498 
499 
500 //+---------------------------------------------------------------------------
501 //
502 //  Member: CMStream::ConvertILB, private
503 //
504 //  Synopsis: Copy the first sector of the underlying ILockBytes
505 //                      out to the end.
506 //
507 //  Arguments:  [sectMax] -- Total number of sectors in the ILockBytes
508 //
509 //  Returns:  Appropriate status code
510 //
511 //----------------------------------------------------------------------------
512 
ConvertILB(SECT sectMax)513 SCODE  CMStream::ConvertILB(SECT sectMax)
514 {
515     SCODE sc;
516     BYTE *pb;
517     USHORT cbNull;
518 
519     GetSafeBuffer(GetSectorSize(), GetSectorSize(), &pb, &cbNull);
520 
521     ULONG ulTemp;
522 
523     ULARGE_INTEGER ulTmp;
524     ULISet32(ulTmp, 0);
525 
526     msfHChk((*_pplstParent)->ReadAt(ulTmp, pb, GetSectorSize(), &ulTemp));
527 
528     ULARGE_INTEGER ulNewPos;
529     ULISet32(ulNewPos, sectMax << GetSectorShift());
530 
531     msfDebugOut((DEB_ITRACE,"Copying first sector out to %lu\n",
532                  ULIGetLow(ulNewPos)));
533 
534     msfHChk((*_pplstParent)->WriteAt(
535         ulNewPos,
536         pb,
537         GetSectorSize(),
538         &ulTemp));
539 
540 Err:
541     FreeBuffer(pb);
542     return sc;
543 }
544 
545 //+-------------------------------------------------------------------------
546 //
547 //  Method:     CMStream::InitConvert, public
548 //
549 //  Synopsis:   Init function used in conversion of files to multi
550 //              streams.
551 //
552 //  Arguments:  [fDelayConvert] -- If true, the actual file is not
553 //                                 touched until a BeginCopyOnWrite()
554 //
555 //  Returns:    S_OK if everything completed OK.
556 //
557 //  Algorithm:  *Finish This*
558 //
559 //  Notes:  We are allowed to fail here in low memory
560 //
561 //--------------------------------------------------------------------------
562 
InitConvert()563 SCODE CMStream::InitConvert()
564 {
565     SCODE sc;
566 
567     SECT sectMax;
568 
569     msfChk(InitCommon());
570 
571     STATSTG stat;
572     (*_pplstParent)->Stat(&stat, STATFLAG_NONAME);
573     msfAssert(ULIGetHigh(stat.cbSize) == 0);
574     msfDebugOut((DEB_ITRACE,"Size is: %lu\n",ULIGetLow(stat.cbSize)));
575 
576 
577     sectMax = (ULIGetLow(stat.cbSize) + GetSectorSize() - 1) >>
578         GetSectorShift();
579 
580     SECT sectMaxMini;
581     BOOL fIsMini;
582     fIsMini = FALSE;
583 
584     //If the CONTENTS stream will be in the Minifat, compute
585     //  the number of Minifat sectors needed.
586     if (ULIGetLow(stat.cbSize) < MINISTREAMSIZE)
587     {
588         sectMaxMini = (ULIGetLow(stat.cbSize) +
589                        MINISECTORSIZE - 1) >> MINISECTORSHIFT;
590         fIsMini = TRUE;
591     }
592 
593 
594     msfChk(_fatDif.InitConvert(this, sectMax));
595     msfChk(_fat.InitConvert(this, sectMax));
596     msfChk(_dir.InitNew(this));
597     msfChk(fIsMini ? _fatMini.InitConvert(this, sectMaxMini)
598            : _fatMini.InitNew(this));
599 
600 
601     SID sid;
602 
603     msfChk(CreateEntry(SIDROOT, &dfnContents, STGTY_STREAM, &sid));
604     msfChk(_dir.SetSize(sid, ULIGetLow(stat.cbSize)));
605 
606     if (!fIsMini)
607         msfChk(_dir.SetStart(sid, sectMax - 1));
608     else
609     {
610         msfChk(_dir.SetStart(sid, 0));
611         msfChk(_dir.SetStart(SIDMINISTREAM, sectMax - 1));
612         msfChk(_dir.SetSize(SIDMINISTREAM, ULIGetLow(stat.cbSize)));
613     }
614 
615     ULONG ulMiniSize;
616     msfChk(_dir.GetSize(SIDMINISTREAM, &ulMiniSize));
617     msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
618     _pdsministream->InitSystem(this, SIDMINISTREAM, ulMiniSize);
619 
620     msfChk(ConvertILB(sectMax));
621 
622     msfChk(Flush(0));
623 
624     return S_OK;
625 
626 Err:
627     Empty();
628 
629     return sc;
630 }
631 
632 
633 
634 
635 //+-------------------------------------------------------------------------
636 //
637 //  Method:     CMStream::GetName, public
638 //
639 //  Synopsis:   Given a handle, return the current name of that entry
640 //
641 //  Arguments:  [sid] -- SID to find name for.
642 //
643 //  Returns:    Pointer to name.
644 //
645 //--------------------------------------------------------------------------
646 
647 
GetName(SID const sid,CDfName * pdfn)648 SCODE  CMStream::GetName(SID const sid, CDfName *pdfn)
649 {
650     return _dir.GetName(sid, pdfn);
651 }
652 
653 
654 //+-------------------------------------------------------------------------
655 //
656 //  Method:     CMStream::FlushHeader, public
657 //
658 //  Synopsis:   Flush the header to the LStream.
659 //
660 //  Arguments:  [uForce] -- Flag to determine if header should be
661 //                          flushed while in copy on write mode.
662 //
663 //  Returns:    S_OK if call completed OK.
664 //              S_OK if the MStream is in copy on write mode or
665 //                  is Unconverted and the header was not flushed.
666 //
667 //  Algorithm:  Write the complete header out to the 0th position of
668 //              the LStream.
669 //
670 //  Notes:
671 //
672 //--------------------------------------------------------------------------
673 
FlushHeader(USHORT uForce)674 SCODE  CMStream::FlushHeader(USHORT uForce)
675 {
676     ULONG ulTemp;
677     SCODE sc;
678 
679     UNREFERENCED_PARM(uForce);
680     msfDebugOut((DEB_ITRACE,"In CMStream::FlushHeader()\n"));
681 
682     ULARGE_INTEGER ulOffset;
683     ULISet32(ulOffset, 0);
684     _hdr.ByteSwap(); // swap to disk format if neccessary
685     sc = DfGetScode((*_pplstParent)->
686         WriteAt(ulOffset, (BYTE *)(&_hdr),
687           sizeof(CMSFHeader), &ulTemp));
688     _hdr.ByteSwap(); // swap to memort/machine format if neccessary
689     msfDebugOut((DEB_ITRACE,"Out CMStream::FlushHeader()\n"));
690     return sc;
691 }
692 
693 
694 
695 
696 
697 //+-------------------------------------------------------------------------
698 //
699 //  Member:     CMStream::MWrite, public
700 //
701 //  Synposis:   Do multiple sector writes
702 //
703 //  Effects:    Causes multiple stream writes.  Modifies fat and directory
704 //
705 //  Arguments:  [ph] -- Handle of stream doing write
706 //              [start] -- Starting sector to write
707 //              [oStart] -- offset into sector to begin write at
708 //              [end] -- Last sector to write
709 //              [oEnd] -- offset into last sector to write to
710 //              [buffer] -- Pointer to buffer into which data will be written
711 //              [ulRetVal] -- location to return number of bytes written
712 //
713 //  Returns:    Error code of any failed call to parent write
714 //              S_OK if call completed OK.
715 //
716 //  Modifies:   ulRetVal returns the number of bytes written
717 //
718 //  Algorithm:  Using a segment table, perform writes on parent stream
719 //              until call is completed.
720 //
721 //  Notes:
722 //
723 //---------------------------------------------------------------------------
724 
725 
726 
MWrite(SID sid,BOOL fIsMini,ULONG ulOffset,VOID const HUGEP * pvBuffer,ULONG ulCount,CStreamCache * pstmc,ULONG * pulRetval)727 SCODE CMStream::MWrite(
728     SID sid,
729     BOOL fIsMini,
730     ULONG ulOffset,
731     VOID const HUGEP *pvBuffer,
732     ULONG ulCount,
733     CStreamCache *pstmc,
734     ULONG *pulRetval)
735 {
736     SCODE sc;
737     BYTE const HUGEP *pbBuffer = (BYTE const HUGEP *) pvBuffer;
738 
739     USHORT cbSector = GetSectorSize();
740     CFat *pfat = &_fat;
741     USHORT uShift = GetSectorShift();
742     ULONG ulLastBytes = 0;
743 
744     ULARGE_INTEGER ulOff;
745     ULISetHigh(ulOff, 0);
746 
747     ULONG ulOldSize = 0;
748 
749     //  Check if it's a small stream and whether this is a real
750     //  multistream.
751 
752     if ((fIsMini) &&
753         (SIDMINISTREAM != sid))
754     {
755         msfAssert(sid <= MAXREGSID &&
756                   aMsg("Invalid SID in MWrite"));
757         //  This stream is stored in the ministream
758 
759         cbSector = MINISECTORSIZE;
760         uShift = MINISECTORSHIFT;
761         pfat = GetMiniFat();
762     }
763 
764     USHORT uMask = (USHORT) (cbSector - 1);
765 
766     SECT start = (SECT)(ulOffset >> uShift);
767     OFFSET oStart = (OFFSET)(ulOffset & uMask);
768 
769     SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift);
770     OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
771 
772     msfDebugOut((DEB_ITRACE,"In CMStream::MWrite(%lu,%u,%lu,%u)\n",
773                  start,oStart,end,oEnd));
774 
775     ULONG bytecount;
776     ULONG total = 0;
777 
778     msfChk(_dir.GetSize(sid, &ulOldSize));
779 
780 
781 
782     msfAssert(end != 0xffffffffL);
783 
784     if (end < start)
785     {
786         *pulRetval = total + ulLastBytes;
787         goto Err;
788     }
789 
790     ULONG ulRunLength;
791     ulRunLength = end - start + 1;
792     SECT sectSidStart;
793 
794     USHORT offset;
795     offset = oStart;
796 
797     while (TRUE)
798     {
799         SSegment segtab[CSEG + 1];
800         SECT sect;
801 
802         if (start > pstmc->GetOffset())
803         {
804             msfChk(pfat->GetESect(
805                 pstmc->GetSect(),
806                 start - pstmc->GetOffset(),
807                 &sect));
808         }
809         else if (start == pstmc->GetOffset())
810         {
811             sect = pstmc->GetSect();
812         }
813         else
814         {
815             msfChk(_dir.GetStart(sid, &sectSidStart));
816             msfChk(pfat->GetESect(sectSidStart, start, &sect));
817         }
818 
819         msfChk(pfat->Contig(
820             (SSegment STACKBASED *) segtab,
821             sect,
822             ulRunLength));
823 
824         USHORT oend = (USHORT) (cbSector - 1);
825         ULONG i;
826         SECT sectStart;
827         for (USHORT iseg = 0; iseg < CSEG;)
828         {
829             sectStart = segtab[iseg].sectStart;
830             i = segtab[iseg].cSect;
831 
832             if (i > ulRunLength)
833                 i = ulRunLength;
834 
835             ulRunLength -= i;
836             start += i;
837 
838             iseg++;
839             if (segtab[iseg].sectStart == ENDOFCHAIN)
840             {
841                 msfAssert(ulRunLength==0);
842                 oend = oEnd;
843             }
844 
845             ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
846 
847             msfDebugOut((
848                 DEB_ITRACE,
849                 "Calling lstream WriteAt(%lu,%p,%lu)\n",
850                 ConvertSectOffset(sectStart,offset,uShift),
851                 pbBuffer,
852                 ulSize));
853 
854             if (GetMiniFat() == pfat)
855             {
856                 sc = _pdsministream->CDirectStream::WriteAt(
857                     (sectStart << uShift) + offset,
858                     pbBuffer, ulSize,
859                     (ULONG STACKBASED *)&bytecount);
860             }
861             else
862             {
863                 ULISetLow(ulOff, ConvertSectOffset(sectStart, offset,
864                                                    uShift));
865                 sc = DfGetScode((*_pplstParent)->WriteAt(ulOff, pbBuffer,
866                                                          ulSize, &bytecount));
867             }
868 
869             total += bytecount;
870 
871             //Check if this write is the last one in the stream,
872             //   and that the stream ends as a partial sector.
873             //If so, fill out the remainder of the sector with
874             //   something.
875             if ((0 == ulRunLength) && (total + ulOffset > ulOldSize) &&
876                 (((total + ulOffset) & (GetSectorSize() - 1)) != 0))
877             {
878                 //This is the last sector and the stream has grown.
879                 ULONG csectOld = (ulOldSize + GetSectorSize() - 1) >>
880                     GetSectorShift();
881 
882                 ULONG csectNew = (total + ulOffset + GetSectorSize() - 1) >>
883                     GetSectorShift();
884 
885                 if (csectNew > csectOld)
886                 {
887                     msfAssert(!fIsMini &&
888                               aMsg("Small stream grew in MWrite"));
889 
890                     SECT sectLast = sectStart + i - 1;
891 
892                     msfVerify(SUCCEEDED(SecureSect(
893                         sectLast,
894                         total + ulOffset,
895                         FALSE)));
896                 }
897             }
898 
899             if (0 == ulRunLength || FAILED(sc))
900             {
901                 break;
902             }
903 
904             pbBuffer = pbBuffer + bytecount;
905             offset = 0;
906         }
907 
908         pstmc->SetCache(start -1, sectStart + i - 1);
909 
910         if (0 == ulRunLength || FAILED(sc))
911         {
912             *pulRetval = total + ulLastBytes;
913             msfDebugOut((
914                 DEB_TRACE,
915                 "Out CMStream::MWrite()=>%lu, retval = %lu\n",
916                 sc,
917                 total));
918             break;
919         }
920     }
921 
922 Err:
923     //  We need this flush of the directory structures because we may have
924     //  remapped the first sector in a chain.
925 
926     return sc;
927 }
928 
929 
930 
931 //+---------------------------------------------------------------------------
932 //
933 //  Member: CMStream::Flush, public
934 //
935 //  Synopsis: Flush control structures.
936 //
937 //  Arguments:  None.
938 //
939 //  Returns:  Appropriate status code
940 //
941 //----------------------------------------------------------------------------
942 
943 
Flush(BOOL fFlushCache)944 SCODE CMStream::Flush(BOOL fFlushCache)
945 {
946     SCODE sc = S_OK;
947 
948     msfChk(_dir.Flush());
949     msfChk(_fatMini.Flush());
950     msfChk(_fat.Flush());
951     msfChk(_fatDif.Flush());
952 
953     msfChk(FlushHeader(HDR_NOFORCE));
954     msfChk(ILBFlush(*_pplstParent, fFlushCache));
955 Err:
956     return sc;
957 }
958 
959 //+-------------------------------------------------------------------------
960 //
961 //  Function:   ILBFlush
962 //
963 //  Synopsis:   Flush as thoroughly as possible
964 //
965 //  Effects:    Flushes ILockBytes
966 //
967 //  Arguments:  [pilb]        - ILockBytes to flush
968 //              [fFlushCache] - Flush thoroughly iff TRUE
969 //
970 //  Returns:    SCODE
971 //
972 //  Algorithm:
973 //
974 //--------------------------------------------------------------------------
975 
ILBFlush(ILockBytes * pilb,BOOL fFlushCache)976 SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache)
977 {
978     SCODE sc;
979     UNREFERENCED_PARM(fFlushCache);  // no cache used here
980 
981     msfDebugOut((DEB_ITRACE, "In ILBFlushCache(%p)\n", pilb));
982 
983     sc = DfGetScode(pilb->Flush());
984 
985     msfDebugOut((DEB_ITRACE, "Out ILBFlushCache()\n"));
986 
987     return(sc);
988 }
989 
990 
991 //+---------------------------------------------------------------------------
992 //
993 //  Member: CMStream::SecureSect, public
994 //
995 //  Synopsis: Zero out the unused portion of a sector
996 //
997 //  Arguments:  [sect] -- Sector to zero out
998 //              [ulSize] -- Size of stream
999 //              [fIsMini] -- TRUE if stream is in ministream
1000 //
1001 //  Returns:  Appropriate status code
1002 //
1003 //  Modifies:
1004 //
1005 //  Notes:
1006 //
1007 //----------------------------------------------------------------------------
1008 
SecureSect(const SECT sect,const ULONG ulSize,const BOOL fIsMini)1009 SCODE CMStream::SecureSect(
1010     const SECT sect,
1011     const ULONG ulSize,
1012     const BOOL fIsMini)
1013 {
1014     SCODE sc = S_OK;
1015     BYTE *pb = NULL;
1016 
1017     ULONG cbSect = fIsMini ? MINISECTORSIZE : GetSectorSize();
1018 
1019     msfAssert(ulSize != 0);
1020 
1021     ULONG ulOffset = ((ulSize - 1) % cbSect) + 1;
1022 
1023     ULONG cb = cbSect - ulOffset;
1024 
1025     msfAssert(cb != 0);
1026 
1027     // We can use any initialized block of memory here.  The header
1028     // is available and is the correct size, so we use that.
1029     pb = (BYTE *)&_hdr;
1030 
1031     ULONG cbWritten;
1032 
1033     if (!fIsMini)
1034     {
1035         ULARGE_INTEGER ulOff;
1036         // justify the casting later
1037         msfAssert(ulOffset <= USHRT_MAX);
1038         ULISet32(ulOff,
1039                  ConvertSectOffset( sect, (USHORT) ulOffset,
1040                                     GetSectorShift()));
1041 
1042         msfChk(DfGetScode((*_pplstParent)->
1043                           WriteAt( ulOff, pb, cb, &cbWritten)));
1044     }
1045     else
1046     {
1047         msfChk(_pdsministream->WriteAt(
1048             (sect << MINISECTORSHIFT) + ulOffset,
1049             pb, cb, (ULONG STACKBASED *)&cbWritten));
1050     }
1051 
1052     if (cbWritten != cb)
1053     {
1054         sc = STG_E_WRITEFAULT;
1055     }
1056 
1057 Err:
1058 
1059     return sc;
1060 }
1061