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 §));
808 }
809 else if (start == pstmc->GetOffset())
810 {
811 sect = pstmc->GetSect();
812 }
813 else
814 {
815 msfChk(_dir.GetStart(sid, §SidStart));
816 msfChk(pfat->GetESect(sectSidStart, start, §));
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