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:   Allocation functions for MStream
9 //
10 //  Classes:    None. (defined in fat.hxx)
11 //
12 //--------------------------------------------------------------------------
13 
14 #include "msfhead.cxx"
15 
16 
17 #include "h/difat.hxx"
18 #include "h/sstream.hxx"
19 #include "mread.hxx"
20 
21 
22 //+-------------------------------------------------------------------------
23 //
24 //  Method:     CFatSect::Init, public
25 //
26 //  Synopsis:   CFatSect initialization function
27 //
28 //  Effects:    [uEntries] -- Number of entries in sector
29 //
30 //  Algorithm:  Allocate an array of SECT with size uEntries from
31 //              the heap.
32 //
33 //--------------------------------------------------------------------------
34 
Init(FSOFFSET uEntries)35 SCODE CFatSect::Init(FSOFFSET uEntries)
36 {
37     msfDebugOut((DEB_FAT,"In CFatSect constructor\n"));
38 
39     //This assumes that FREESECT is always 0xFFFFFFFF
40     memset(GetSects(), 0xFF, uEntries * sizeof(SECT));
41 
42     msfDebugOut((DEB_FAT,"Out CFatSect constructor\n"));
43     return S_OK;
44 }
45 
46 
47 
48 //+-------------------------------------------------------------------------
49 //
50 //  Method:     CFatSect::InitCopy, public
51 //
52 //  Synopsis:   Initialization function for copying FatSects
53 //
54 //  Arguments:  [fsOld] -- Reference to FatSect to be copies
55 //
56 //  Returns:    S_OK if call completed successfully.
57 //
58 //  Algorithm:  Allocate a new array of SECT and copy old
59 //                  information in.
60 //
61 //--------------------------------------------------------------------------
62 
InitCopy(USHORT uSize,CFatSect & fsOld)63 SCODE CFatSect::InitCopy(USHORT uSize, CFatSect& fsOld)
64 {
65     msfDebugOut((DEB_FAT,"In CFatSect copy constructor\n"));
66     msfDebugOut((DEB_FAT,"This = %p,  fsOld = %p\n",this,&fsOld));
67 
68     msfDebugOut((DEB_FAT,"Sector size is %u sectors\n",uSize));
69 
70     memcpy(GetSects(),fsOld.GetSects(),sizeof(SECT)*uSize);
71     msfDebugOut((DEB_FAT,"Out CFatSect copy constructor\n"));
72     return S_OK;
73 }
74 
75 
76 //+-------------------------------------------------------------------------
77 //
78 //  Method:     CFat::CFat, public
79 //
80 //  Synopsis:   CFat constructor.
81 //
82 //  Arguments:  [pmsParent] -- Pointer to parent multistream.
83 //
84 //  Algorithm:  Set uFatEntries to match parent MS header info.
85 //              Initialize all member variables.
86 //
87 //  Notes:
88 //
89 //--------------------------------------------------------------------------
90 
CFat(SID sid,USHORT cbSector,USHORT uSectorShift)91 CFat::CFat(SID sid, USHORT cbSector, USHORT uSectorShift)
92 : _fv( sid,
93        (USHORT) (cbSector >> 2),  // 4 bytes per entry
94        (USHORT) (cbSector >> 2) ),
95   _pmsParent(NULL),
96   _sid(sid),
97   // left shift this amount for FAT
98   _uFatShift((USHORT) (uSectorShift - 2) ),
99   // (# entries per sector) - 1
100   _uFatMask( (USHORT) ((cbSector >> 2) - 1)),
101   _cfsTable(0),
102   _ulFreeSects(0),
103   _sectFirstFree( (SECT) 0),
104   _sectMax(ENDOFCHAIN)
105 {
106 }
107 
108 
109 
110 
111 //+---------------------------------------------------------------------------
112 //
113 //  Member: CFat::Empty, public
114 //
115 //  Synopsis: Empty all the control structures of this instance
116 //
117 //  Arguments:  None.
118 //
119 //  Returns:  void.
120 //
121 //----------------------------------------------------------------------------
122 
Empty(void)123 void CFat::Empty(void)
124 {
125     _fv.Empty();
126     _pmsParent = NULL;
127     _cfsTable = 0;
128     _ulFreeSects = MAX_ULONG;
129     _sectFirstFree = 0;
130     _sectMax = ENDOFCHAIN;
131 }
132 
133 
134 //+-------------------------------------------------------------------------
135 //
136 //  Method:     CFat::~CFat, public
137 //
138 //  Synopsis:   CFat Destructor
139 //
140 //  Algorithm:  delete dynamically allocated storage
141 //
142 //  Notes:
143 //
144 //--------------------------------------------------------------------------
145 
~CFat()146 CFat::~CFat()
147 {
148     msfDebugOut((DEB_FAT,"In CFat destructor.  Size of fat is %lu\n",_cfsTable));
149 
150     msfDebugOut((DEB_FAT,"Exiting CFat destructor\n"));
151 }
152 
153 
154 //+-------------------------------------------------------------------------
155 //
156 //  Member:     CFat::GetFree, private
157 //
158 //  Synposis:   Locate and return a free sector in the FAT
159 //
160 //  Effects:    May modify full bit on full sectors
161 //
162 //  Arguments:  [psectRet] -- Pointer to return value
163 //
164 //  Returns:    S_OK if call completed successfully.
165 //
166 //  Algorithm:  Do a linear search of all tables until a free sector is
167 //              found.  If all tables are full, extend the FAT by one
168 //              sector.
169 //
170 //  Notes:
171 //
172 //---------------------------------------------------------------------------
173 
GetFree(ULONG ulCount,SECT * psectRet)174 SCODE CFat::GetFree(ULONG ulCount, SECT *psectRet)
175 {
176     FSINDEX ipfs;
177     FSOFFSET isect;
178     SECT sectRetval;
179     SCODE sc;
180 
181     SECT sectLast = ENDOFCHAIN;
182     FSINDEX ipfsLast;
183     FSOFFSET isectLast;
184 
185     *psectRet = ENDOFCHAIN;
186 
187 
188     while (TRUE)
189     {
190         if (_ulFreeSects == MAX_ULONG)
191         {
192             msfChk(CountFree(&_ulFreeSects));
193         }
194 #if DBG == 1
195         else
196         {
197             ULONG ulFree;
198             msfChk(CountFree(&ulFree));
199             msfAssert((ulFree == _ulFreeSects) &&
200                     aMsg("Free count doesn't match cached value."));
201         }
202 #endif
203 
204         while (ulCount > _ulFreeSects)
205         {
206 #if DBG == 1
207             ULONG ulFree = _ulFreeSects;
208 #endif
209 
210             msfChk(Resize(_cfsTable +
211                     ((ulCount - _ulFreeSects + _fv.GetSectTable() - 1) >>
212                      _uFatShift)));
213 
214 #if DBG == 1
215             msfAssert(_ulFreeSects > ulFree &&
216                 aMsg("Number of free sectors didn't increase after Resize."));
217 #endif
218         }
219 
220         FSOFFSET isectStart;
221         FSINDEX ipfsStart;
222 
223         SectToPair(_sectFirstFree, &ipfsStart, &isectStart);
224 
225         for (ipfs = ipfsStart; ipfs < _cfsTable; ipfs++)
226         {
227             CVectBits *pfb = _fv.GetBits(ipfs);
228             if ((pfb == NULL) || (!pfb->full))
229             {
230                 CFatSect *pfs;
231                 msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
232                 if (pfb != NULL)
233                 {
234                     isectStart = pfb->firstfree;
235                 }
236 
237                 for (isect = isectStart; isect < _fv.GetSectTable(); isect++)
238                 {
239                     SECT sectCurrent = pfs->GetSect(isect);
240                     SECT sectNew = PairToSect(ipfs, isect);
241 
242 
243                     if (sectCurrent == FREESECT)
244                     {
245                         msfAssert(_ulFreeSects != MAX_ULONG &&
246                                 aMsg("Free sect count not set"));
247 
248                         _ulFreeSects--;
249 
250                         sectRetval = sectNew;
251 
252                         if (pfb != NULL)
253                         {
254                             olAssert(isect+1 < (FSOFFSET)USHRT_MAX);
255                             pfb->firstfree = (USHORT) (isect + 1);
256                         }
257 
258                         msfAssert(sectRetval >= _sectFirstFree &&
259                                 aMsg("Found free sector before _sectFirstFree"));
260                         _sectFirstFree = sectRetval + 1;
261 
262                         pfs->SetSect(isect, ENDOFCHAIN);
263                         msfChkTo(Err_Rel, _fv.SetDirty(ipfs));
264 
265                         if (sectLast != ENDOFCHAIN)
266                         {
267                             if (ipfsLast == ipfs)
268                             {
269                                 pfs->SetSect(isectLast, sectRetval);
270                             }
271                             else
272                             {
273                                 CFatSect *pfsLast;
274 
275                                 msfChkTo(Err_Rel, _fv.GetTable(
276                                         ipfsLast,
277                                         FB_DIRTY,
278                                         &pfsLast));
279 
280                                 pfsLast->SetSect(isectLast, sectRetval);
281                                 _fv.ReleaseTable(ipfsLast);
282                             }
283                         }
284 
285                         if (*psectRet == ENDOFCHAIN)
286                         {
287                             *psectRet = sectRetval;
288                         }
289 
290                         ulCount--;
291 
292                         if (ulCount == 0)
293                         {
294                             _fv.ReleaseTable(ipfs);
295 
296                             if (sectRetval >= _sectMax)
297                             {
298                                 _sectMax = sectRetval + 1;
299                             }
300                             return S_OK;
301                         }
302                         else
303                         {
304                             sectLast = sectRetval;
305                             ipfsLast = ipfs;
306                             isectLast = isect;
307                         }
308                     }
309                 }
310                 _fv.ReleaseTable(ipfs);
311                 if (pfb != NULL)
312                 {
313                     pfb->full = TRUE;
314                 }
315             }
316             isectStart = 0;
317         }
318         if (sectRetval >= _sectMax)
319         {
320             _sectMax = sectRetval + 1;
321         }
322     }
323     msfAssert(0 &&
324             aMsg("GetFree exited improperly."));
325     sc = STG_E_ABNORMALAPIEXIT;
326 
327  Err:
328     return sc;
329 
330  Err_Rel:
331     _fv.ReleaseTable(ipfs);
332     return sc;
333 }
334 
335 
336 
337 //+-------------------------------------------------------------------------
338 //
339 //  Member:     CFat::GetLength, public
340 //
341 //  Synposis:   Return the length of a fat chain.
342 //
343 //  Arguments:  [sect] -- Sector to begin count at.
344 //
345 //  Returns:    Length of the chain, in sectors
346 //
347 //  Algorithm:  Traverse the chain until ENDOFCHAIN is reached.
348 //
349 //  Notes:
350 //
351 //---------------------------------------------------------------------------
352 
GetLength(SECT sect,ULONG * pulRet)353 SCODE CFat::GetLength(SECT sect, ULONG * pulRet)
354 {
355     msfDebugOut((DEB_FAT,"In CFat::GetLength(%lu)\n",sect));
356     SCODE sc = S_OK;
357 
358     ULONG csect = 0;
359 
360     while (sect != ENDOFCHAIN)
361     {
362         msfChk(GetNext(sect, &sect));
363         csect++;
364     }
365 
366     msfDebugOut((DEB_FAT,"FAT: GetLength returned %u\n",csect));
367     *pulRet =  csect;
368 Err:
369     return sc;
370 }
371 
372 
373 
374 //+-------------------------------------------------------------------------
375 //
376 //  Member:     CFat::Init, public
377 //
378 //  Synposis:   Sets up a FAT, reading data from an existing stream
379 //
380 //  Effects:    Changes all _apfsTable entries, _cfsTable, and all
381 //              flags fields
382 //
383 //  Arguments:  None.
384 //
385 //  Returns:    S_OK if call completed OK.
386 //
387 //  Algorithm:  Read size from first FAT in stream.
388 //              Resize array to necessary size.
389 //              Read in FAT sectors sequentially.
390 //
391 //  Notes:
392 //
393 //---------------------------------------------------------------------------
394 
Init(CMStream * pmsParent,FSINDEX cFatSect,BOOL fConvert)395 SCODE CFat::Init(CMStream *pmsParent, FSINDEX cFatSect, BOOL fConvert)
396 {
397     SCODE sc;
398     UNREFERENCED_PARM(fConvert);
399     msfDebugOut((DEB_FAT,"CFat::setup thinks the FAT is size %lu\n",cFatSect));
400 
401     _pmsParent = pmsParent;
402 
403     msfChk(_fv.Init(_pmsParent, cFatSect));
404 
405     _cfsTable = cFatSect;
406 
407     _ulFreeSects = MAX_ULONG;
408 
409 Err:
410     return sc;
411 }
412 
413 
414 //+-------------------------------------------------------------------------
415 //
416 //  Method:     CFat::InitConvert, public
417 //
418 //  Synopsis:   Init function used for conversion
419 //
420 //  Arguments:  [sectData] -- number of sectors used by file
421 //
422 //  Returns:    S_OK if call completed OK.
423 //
424 //  Algorithm:  *Finish This*
425 //
426 //  Notes:
427 //
428 //--------------------------------------------------------------------------
429 
InitConvert(CMStream * pmsParent,SECT sectData)430 SCODE CFat::InitConvert(CMStream *pmsParent, SECT sectData)
431 {
432     SCODE sc;
433     msfDebugOut((DEB_FAT,"Doing conversion\n"));
434     _pmsParent = pmsParent;
435 
436     msfAssert((sectData != 0) &&
437             aMsg("Attempt to convert zero length file."));
438 
439     SECT sectMax = 0;
440     FSINDEX csectFat = 0;
441     FSINDEX csectLast;
442 
443     if (_sid == SIDFAT)
444     {
445         SECT sectTotal;
446 
447         //Since the fat needs to represent itself, we can't determine
448         //   the actual number of sectors needed in one pass.  We
449         //   therefore loop, factoring in the number of fat sectors
450         //   at each iteration, until we reach a stable state.
451         //
452         //As an example, consider the case where each fat sector represents
453         //   128 sectors and the file being converted is 128 sectors long.
454         //   There will be no DIFat - therefore, we have 128 sectors needed
455         //   on the first pass, which will require 1 fat sector to
456         //   represent them.  On the second pass, we discover that we
457         //   actually need 2 fat sectors, since we now have 129 total
458         //   sectors to allocate space for.  The third pass will result
459         //   in a stable state.
460         do
461         {
462             csectLast = csectFat;
463             sectTotal = sectData + _pmsParent->GetHeader()->GetDifLength() +
464                 csectFat + 1;
465             csectFat = (sectTotal + _fv.GetSectTable() - 1) >> _uFatShift;
466         }
467         while (csectLast != csectFat);
468         sectMax = sectData + _pmsParent->GetHeader()->GetDifLength();
469     }
470     else
471     {
472         //The minifat doesn't need to represent itself, so we can
473         //  compute the number of sectors needed in one pass.
474         sectMax = sectData;
475         csectFat = (sectMax + _fv.GetSectTable() -1) >> _uFatShift;
476     }
477 
478     msfChk(_fv.Init(_pmsParent, csectFat));
479 
480     FSINDEX i;
481 
482     if (_sid == SIDMINIFAT)
483     {
484         SECT sectFirst;
485         msfChk(_pmsParent->GetFat()->Allocate(csectFat, &sectFirst));
486 
487         _pmsParent->GetHeader()->SetMiniFatStart(sectFirst);
488 
489         _pmsParent->GetHeader()->SetMiniFatLength(csectFat);
490     }
491 
492 
493     for (i = 0; i < csectFat; i++)
494     {
495         CFatSect *pfs;
496 
497         msfChk(_fv.GetTable(i, FB_NEW, &pfs));
498         if (_sid == SIDFAT)
499         {
500             _fv.SetSect(i, sectMax + i);
501             _pmsParent->GetDIFat()->SetFatSect(i, sectMax + i);
502         }
503         else
504         {
505             SECT sect;
506             msfChk(_pmsParent->GetESect(_sid, i, &sect));
507             _fv.SetSect(i, sect);
508         }
509 
510         _fv.ReleaseTable(i);
511     }
512 
513 
514     _cfsTable = csectFat;
515 
516     if (_sid != SIDMINIFAT)
517     {
518 
519         _pmsParent->GetHeader()->SetFatLength(_cfsTable);
520 
521         SECT sect;
522 
523         if (sectData > 1)
524         {
525             for (sect = 0; sect < sectData - 2; sect++)
526             {
527                 msfChk(SetNext(sect, sect + 1));
528             }
529 
530             msfChk(SetNext(sectData - 2, ENDOFCHAIN));
531             msfChk(SetNext(sectData - 1, 0));
532         }
533         else
534         {
535             //In the event that the file to be converted is less
536             //  than one sector long, we don't need to create a
537             //  real chain, just a single terminated sector.
538             msfChk(SetNext(0, ENDOFCHAIN));
539         }
540 
541 
542         for (sect = sectData; sect < sectMax; sect++)
543         {
544             msfChk(SetNext(sect, DIFSECT));
545         }
546 
547         for (USHORT j = 0; j < csectFat; j++)
548         {
549             msfChk(SetNext(sectMax + j, FATSECT));
550         }
551 
552         //Set up directory chain.
553         msfChk(SetNext(sectMax + i, ENDOFCHAIN));
554 
555         _pmsParent->GetHeader()->SetDirStart(sectMax + i);
556 
557         _ulFreeSects = (_cfsTable << _uFatShift) - (sectMax + csectFat + 1);
558     }
559     else
560     {
561         for (SECT sect = 0; sect < sectData -1; sect++)
562         {
563             msfChk(SetNext(sect, sect + 1));
564         }
565         msfChk(SetNext(sectData - 1, ENDOFCHAIN));
566         _ulFreeSects = (_cfsTable << _uFatShift) - sectData;
567     }
568 
569         msfChk(_pmsParent->SetSize());
570 
571 Err:
572     return sc;
573 }
574 
575 //+-------------------------------------------------------------------------
576 //
577 //  Member:     CFat::InitNew, public
578 //
579 //  Synposis:   Sets up a FAT for a newly created multi-strean
580 //
581 //  Effects:    Changes all _apfsTable entries, _cfsTable, and all
582 //              flags fields
583 //
584 //  Arguments:  [pmsparent] -- pointer to parent Mstream
585 //
586 //  Returns:    S_OK if call completed OK.
587 //
588 //  Algorithm:  Set parent pointer.
589 //              Allocate 1 sector for FAT and 1 for Directory.
590 //
591 //  Notes:
592 //
593 //---------------------------------------------------------------------------
594 
InitNew(CMStream * pmsParent)595 SCODE CFat::InitNew(CMStream *pmsParent)
596 {
597     msfDebugOut((DEB_FAT,"In CFat::InitNew()\n"));
598     SCODE sc;
599 
600     _pmsParent = pmsParent;
601 
602     FSINDEX count;
603     if (SIDMINIFAT == _sid)
604         count = _pmsParent->GetHeader()->GetMiniFatLength();
605     else
606         count = _pmsParent->GetHeader()->GetFatLength();
607 
608     msfDebugOut((DEB_FAT,"Setting up Fat of size %lu\n",count));
609 
610     msfChk(_fv.Init(_pmsParent, count));
611 
612     _cfsTable = count;
613 
614     if (SIDFAT == _sid)
615     {
616         FSINDEX ipfs;
617         FSOFFSET isect;
618         CFatSect *pfs;
619 
620         SectToPair(_pmsParent->GetHeader()->GetFatStart(), &ipfs, &isect);
621         msfChk(_fv.GetTable(ipfs, FB_NEW, &pfs));
622         _fv.SetSect(ipfs, _pmsParent->GetHeader()->GetFatStart());
623         _fv.ReleaseTable(ipfs);
624 
625         msfChk(SetNext(_pmsParent->GetHeader()->GetFatStart(), FATSECT));
626         msfDebugOut((DEB_ITRACE,"Set sector %lu (FAT) to ENDOFCHAIN\n",_pmsParent->GetHeader()->GetFatStart()));
627 
628         msfChk(SetNext(_pmsParent->GetHeader()->GetDirStart(), ENDOFCHAIN));
629         msfDebugOut((DEB_ITRACE,"Set sector %lu (DIR) to ENDOFCHAIN\n",_pmsParent->GetHeader()->GetDirStart()));
630         _ulFreeSects = (count << _uFatShift) - 2;
631     }
632     else
633     {
634         _ulFreeSects = 0;
635     }
636 
637         msfChk(_pmsParent->SetSize());
638 
639     msfDebugOut((DEB_FAT,"Exiting CFat::setupnew()\n"));
640 
641 Err:
642     return sc;
643 }
644 
645 
646 
647 
648 //+-------------------------------------------------------------------------
649 //
650 //  Member:     CFat::Resize, private
651 //
652 //  Synposis:   Resize FAT, both in memory and in the file
653 //
654 //  Effects:    Modifies _cfsTable, _apfsTable, and all flags fields
655 //
656 //  Arguments:  [ulSize] -- New size (in # of tables) for FAT
657 //
658 //  Returns:    S_OK if call completed OK.
659 //
660 //  Algorithm:  Allocate new array of new size.
661 //              Copy over all old pointers.
662 //              Allocate new tables for any necessary.
663 //
664 //  Notes:      BUGBUG:  This routine currently cannot reduce the size of a
665 //              fat.  This functionality needs to be added eventually.
666 //
667 //---------------------------------------------------------------------------
668 
Resize(ULONG ulSize)669 SCODE CFat::Resize(ULONG ulSize)
670 {
671     msfDebugOut((DEB_FAT,"In CFat::Resize(%lu)\n",ulSize));
672     SCODE sc;
673 
674     if (ulSize == _cfsTable)
675     {
676         return S_OK;
677     }
678 
679     ULONG csect = _cfsTable;
680 
681     msfAssert(ulSize > _cfsTable &&
682             aMsg("Attempted to shrink Fat"));
683 
684 
685     ULONG ipfs;
686     SECT sectNew;
687 
688     CFat *pfat = _pmsParent->GetFat();
689 
690 
691     if (_sid == SIDFAT)
692     {
693 
694         //Make sure we have enough space for all of the sectors
695         //  to be allocated.
696 
697         ULONG csectFat = ulSize - _cfsTable;
698         ULONG csectPerDif = (1 << _uFatShift) - 1;
699         ULONG csectDif = (csectFat + csectPerDif - 1) / csectPerDif;
700 
701 
702         //Assuming all the free sectors are at the end of the file,
703         //   we need a file csectNew sectors long to hold them.
704 
705         ULONG csectOld, csectNew;
706 
707         msfChk(FindMaxSect(&csectOld));
708 
709         csectNew = csectOld + csectFat + csectDif;
710 
711         ULARGE_INTEGER cbSize;
712 
713         ULISet32(cbSize, ConvertSectOffset(
714                 csectNew,
715                 0,
716                 _pmsParent->GetSectorShift()));
717 
718         msfHChk(_pmsParent->GetILB()->SetSize(cbSize));
719 
720         //If we are the fat, we have enough space in the file for
721         //  ourselves at this point.
722     }
723     else
724     {
725         if (_cfsTable == 0)
726         {
727             msfChk(pfat->Allocate(ulSize, &sectNew));
728             _pmsParent->GetHeader()->SetMiniFatStart(sectNew);
729         }
730         else
731         {
732             sectNew = _pmsParent->GetHeader()->GetMiniFatStart();
733 
734             SECT sectLast;
735             msfChk(pfat->GetESect(sectNew, ulSize - 1, &sectLast));
736 
737         }
738 
739         msfChk(_pmsParent->SetSize());
740 
741 
742         msfChk(pfat->GetSect(sectNew, csect, &sectNew));
743 
744         //If we are the Minifat, we have enough space in the underlying
745         //  file for ourselves at this point.
746     }
747 
748 
749     _fv.Resize(ulSize);
750 
751 
752     for (ipfs = csect; ipfs < ulSize; ipfs++)
753     {
754         CFatSect *pfs;
755         msfChk(_fv.GetTable(ipfs, FB_NEW, &pfs));
756         _cfsTable = ipfs + 1;
757         _ulFreeSects += (1 << _uFatShift);
758 
759         if (_sid == SIDFAT)
760         {
761             msfChk(pfat->GetFree(1, &sectNew));
762 
763             msfChk(_pmsParent->GetDIFat()->SetFatSect(ipfs, sectNew));
764             msfChk(pfat->SetNext(sectNew, FATSECT));
765         }
766 
767         msfAssert(sectNew != ENDOFCHAIN &&
768                 aMsg("Bad sector returned for fatsect."));
769 
770         _fv.SetSect(ipfs, sectNew);
771         _fv.ReleaseTable(ipfs);
772 
773         if (_sid == SIDMINIFAT)
774         {
775             msfChk(pfat->GetNext(sectNew, &sectNew));
776         }
777     }
778 
779     msfDebugOut((DEB_FAT,"CFat::Resize() - all new objects allocated\n"));
780 
781     if (SIDMINIFAT == _sid)
782         _pmsParent->GetHeader()->SetMiniFatLength(_cfsTable);
783     else
784         _pmsParent->GetHeader()->SetFatLength(_cfsTable);
785 
786 
787     //This setsize should only shrink the file.
788 #if DBG == 1
789     STATSTG stat;
790 
791     msfHChk(_pmsParent->GetILB()->Stat(&stat, STATFLAG_NONAME));
792 #endif
793 
794         msfChk(_pmsParent->SetSize());
795 
796 #if DBG == 1
797     STATSTG statNew;
798 
799     msfHChk(_pmsParent->GetILB()->Stat(&statNew, STATFLAG_NONAME));
800 
801     msfAssert(ULIGetLow(statNew.cbSize) <= ULIGetLow(stat.cbSize));
802 #endif
803 
804     msfDebugOut((DEB_FAT,"Out CFat::Resize(%lu)\n",ulSize));
805 
806 Err:
807     return sc;
808 }
809 
810 
811 
812 
813 
814 
815 //+-------------------------------------------------------------------------
816 //
817 //  Member:     CFat::Extend, private
818 //
819 //  Synposis:   Increase the size of an existing chain
820 //
821 //  Effects:    Modifies ulSize sectors within the fat.  Causes one or
822 //              more sector writes.
823 //
824 //  Arguments:  [sect] -- Sector ID of last sector in chain to be extended
825 //              [ulSize] -- Number of sectors to add to chain
826 //
827 //  Requires:   sect must be at the end of a chain.
828 //
829 //  Returns:    S_OK if call completed OK.
830 //
831 //  Algorithm:  Use calls to GetFree to allocate chain.
832 //
833 //  Notes:
834 //
835 //---------------------------------------------------------------------------
836 
Extend(SECT sect,ULONG ulSize)837 SCODE CFat::Extend(SECT sect, ULONG ulSize)
838 {
839     SCODE sc;
840 
841     msfDebugOut((DEB_FAT,"In CFat::Extend(%lu,%lu)\n",sect,ulSize));
842     SECT sectTemp;
843 
844     msfChk(GetFree(ulSize, &sectTemp));
845     msfChk(SetNext(sect, sectTemp));
846 
847     msfDebugOut((DEB_FAT,"Out CFat::Extend()\n"));
848 
849 Err:
850     return sc;
851 }
852 
853 
854 
855 
856 //+-------------------------------------------------------------------------
857 //
858 //  Member:     CFat::GetNext, public
859 //
860 //  Synposis:   Returns the next sector in a chain, given a sector
861 //
862 //  Arguments:  [sect] -- Sector ID of any sector in a chain.
863 //
864 //  Returns:    Sector ID of next sector in chain, ENDOFCHAIN if at end
865 //
866 //  Notes:
867 //
868 //---------------------------------------------------------------------------
869 
GetNext(const SECT sect,SECT * psRet)870 SCODE CFat::GetNext(const SECT sect, SECT * psRet)
871 {
872     SCODE sc;
873 
874     FSINDEX ipfs;
875     FSOFFSET isect;
876 
877     msfAssert(sect <= MAXREGSECT &&
878             aMsg("Called GetNext() on invalid sector"));
879 
880     SectToPair(sect, &ipfs, &isect);
881     CFatSect *pfs;
882     msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
883 
884     *psRet = pfs->GetSect(isect);
885 
886     _fv.ReleaseTable(ipfs);
887 
888     msfAssert(sect != *psRet &&
889             aMsg("Detected loop in fat chain."));
890     return S_OK;
891 
892 Err:
893     return sc;
894 }
895 
896 
897 
898 
899 //+-------------------------------------------------------------------------
900 //
901 //  Member:     CFat::SetNext, private
902 //
903 //  Synposis:   Set the next sector in a chain
904 //
905 //  Effects:    Modifies a single entry within the fat.
906 //
907 //  Arguments:  [sectFirst] -- Sector ID of first sector
908 //              [sectNext] -- Sector ID of next sector
909 //
910 //  Returns:    void
911 //
912 //  Notes:
913 //
914 //---------------------------------------------------------------------------
SetNext(SECT sectFirst,SECT sectNext)915 SCODE CFat::SetNext(SECT sectFirst, SECT sectNext)
916 {
917     FSINDEX ipfs;
918     FSOFFSET isect;
919     SCODE sc;
920 
921 
922     //  creating infinite loops is a no-no
923     msfAssert(sectFirst != sectNext &&
924             aMsg("Attempted to create loop in Fat chain"));
925     msfAssert(sectFirst <= MAXREGSECT &&
926             aMsg("Called SetNext on invalid sector"));
927 
928     SectToPair(sectFirst, &ipfs, &isect);
929 
930     CFatSect *pfs;
931 
932     msfChk(_fv.GetTable(ipfs, FB_DIRTY, &pfs));
933 
934     pfs->SetSect(isect,sectNext);
935 
936     _fv.ReleaseTable(ipfs);
937 
938     if (sectNext == FREESECT)
939     {
940         CVectBits *pfb;
941         pfb = _fv.GetBits(ipfs);
942 
943         if ((pfb != NULL) &&
944             ((pfb->full == TRUE) || (isect < pfb->firstfree)))
945         {
946             pfb->full = FALSE;
947             pfb->firstfree = isect;
948         }
949 
950         if (sectFirst == _sectMax - 1)
951         {
952             _sectMax = ENDOFCHAIN;
953         }
954         if (sectFirst < _sectFirstFree)
955         {
956             _sectFirstFree = sectFirst;
957         }
958 
959         if (_ulFreeSects != MAX_ULONG)
960         {
961                 _ulFreeSects++;
962         }
963     }
964 
965 Err:
966     return sc;
967 }
968 
969 
970 
971 //+-------------------------------------------------------------------------
972 //
973 //  Member:     CFat::CountFree, private
974 //
975 //  Synposis:   Count and return the number of free sectors in the Fat
976 //
977 //  Arguments:  void.
978 //
979 //  Returns:    void.
980 //
981 //  Algorithm:  Do a linear search of the Fat, counting free sectors.
982 //              If a FatSect has its full bit set, it is not necessary
983 //              to search that FatSect.
984 //
985 //  Notes:
986 //
987 //---------------------------------------------------------------------------
988 
CountFree(ULONG * pulRet)989 SCODE CFat::CountFree(ULONG * pulRet)
990 {
991     msfDebugOut((DEB_FAT,"In CFat::CountFree()\n"));
992     SCODE sc = S_OK;
993 
994     FSINDEX ipfs;
995     ULONG csectFree=0;
996     FSOFFSET isectStart;
997     FSINDEX ipfsStart;
998 
999     SectToPair(_sectFirstFree, &ipfsStart, &isectStart);
1000 
1001     for (ipfs = ipfsStart; ipfs < _cfsTable; ipfs++)
1002     {
1003         CVectBits *pfb = _fv.GetBits(ipfs);
1004 
1005         if ((pfb == NULL) || (!pfb->full))
1006         {
1007             msfDebugOut((DEB_FAT,"Checking table %lu\n",ipfs));
1008             CFatSect *pfs;
1009             msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
1010 
1011             if (pfb != NULL)
1012             {
1013                 isectStart = pfb->firstfree;
1014             }
1015 
1016             FSOFFSET isect;
1017             for (isect = isectStart; isect < _fv.GetSectTable(); isect++)
1018             {
1019                 SECT sectCurrent = pfs->GetSect(isect);
1020                 PairToSect(ipfs, isect);
1021 
1022                 if (sectCurrent == FREESECT)
1023                 {
1024                     csectFree++;
1025                 }
1026             }
1027             _fv.ReleaseTable(ipfs);
1028         }
1029         isectStart = 0;
1030     }
1031     msfDebugOut((DEB_FAT,"Countfree returned %lu\n",csectFree));
1032     *pulRet = csectFree;
1033 
1034 Err:
1035     return sc;
1036 }
1037 
1038 
1039 //+-------------------------------------------------------------------------
1040 //
1041 //  Member:     CFat::GetSect, public
1042 //
1043 //  Synposis:   Return the nth sector in a chain
1044 //
1045 //  Arguments:  [sect] -- Sector ID of beginning of chain
1046 //              [uNum] -- indicator of which sector is to be returned
1047 //              [psectReturn] -- Pointer to storage for return value
1048 //
1049 //  Returns:    S_OK.
1050 //
1051 //  Algorithm:  Linearly traverse chain until numth sector
1052 //
1053 //  Notes:
1054 //
1055 //---------------------------------------------------------------------------
1056 
GetSect(SECT sect,ULONG ulNum,SECT * psectReturn)1057 SCODE CFat::GetSect(SECT sect, ULONG ulNum, SECT * psectReturn)
1058 {
1059     msfDebugOut((DEB_FAT,"In CFat::GetSect(%lu,%lu)\n",sect,ulNum));
1060 
1061     SCODE sc = S_OK;
1062 
1063     if (ulNum == 0)
1064     {
1065         msfDebugOut((DEB_FAT,"Out CFat::GetSect()=>%lu\n",sect));
1066     }
1067     else if ((SIDFAT == _sid) &&
1068              (_pmsParent->GetHeader()->GetFatStart() == sect))
1069     {
1070         msfChk(_pmsParent->GetDIFat()->GetFatSect(ulNum, &sect));
1071     }
1072     else for (USHORT i = 0; i < ulNum; i++)
1073     {
1074         msfChk(GetNext(sect, &sect));
1075         if (sect > MAXREGSECT)
1076         {
1077             //The stream isn't long enough, so stop.
1078             msfAssert(sect == ENDOFCHAIN &&
1079                     aMsg("Found invalid sector in fat chain."));
1080             break;
1081         }
1082     }
1083 
1084     *psectReturn = sect;
1085     msfDebugOut((DEB_FAT,"Out CFat::GetSect()=>%lu\n",sect));
1086 
1087 Err:
1088     return sc;
1089 }
1090 
1091 
1092 
1093 //+-------------------------------------------------------------------------
1094 //
1095 //  Member:     CFat::GetESect
1096 //
1097 //  Synposis:   Return the nth sector in a chain, extending the chain
1098 //              if necessary.
1099 //
1100 //  Effects:    Modifies fat (via Extend) if necessary
1101 //
1102 //  Arguments:  [sect] -- Sector ID of beginning of chain
1103 //              [ulNum] -- Indicates which sector is to be returned
1104 //              [psectReturn] -- Pointer to storage for return value
1105 //
1106 //  Returns:    S_OK if call completed OK.
1107 //
1108 //  Algorithm:  Linearly search chain until numth sector is found.  If
1109 //              the chain terminates early, extend it as necessary.
1110 //
1111 //  Notes:
1112 //
1113 //---------------------------------------------------------------------------
1114 
GetESect(SECT sect,ULONG ulNum,SECT * psectReturn)1115 SCODE CFat::GetESect(SECT sect, ULONG ulNum, SECT *psectReturn)
1116 {
1117     msfDebugOut((DEB_FAT,"In CFat::GetESect(%lu,%lu)\n",sect,ulNum));
1118 
1119     SCODE sc = S_OK;
1120 
1121     ULONG i = 0;
1122     while (i < ulNum)
1123     {
1124         SECT temp;
1125         msfChk(GetNext(sect, &temp));
1126 
1127         msfAssert(temp != FREESECT &&
1128                 aMsg("FREESECT found in chain."));
1129 
1130         if (temp == ENDOFCHAIN)
1131         {
1132 
1133             //The stream isn't long enough, so extend it somehow.
1134             ULONG need = ulNum - i;
1135 
1136             msfAssert((SIDMINIFAT == _sid ||
1137                     sect != _pmsParent->GetHeader()->GetFatStart()) &&
1138                     aMsg("Called GetESect on Fat chain"));
1139             msfChk(Extend(sect,need));
1140         }
1141         else
1142         {
1143             sect = temp;
1144             i++;
1145         }
1146     }
1147 
1148     msfDebugOut((DEB_FAT,"Exiting GetESect with result %lu\n",sect));
1149     *psectReturn = sect;
1150 
1151 Err:
1152     return sc;
1153 }
1154 
1155 
1156 
1157 
1158 //+-------------------------------------------------------------------------
1159 //
1160 //  Member:     CFat::SetChainLength, private
1161 //
1162 //  Synposis:   Set the length of a fat chain.  This is used to reduce
1163 //              the length of the chain only.  To extend a chain, use
1164 //              Extend or GetESect
1165 //
1166 //  Effects:    Modifies the fat
1167 //
1168 //  Arguments:  [sectStart] -- Sector to begin at (head of chain)
1169 //              [uLength] -- New length for chain
1170 //
1171 //  Returns:    void.
1172 //
1173 //  Algorithm:  Traverse chain until uLength is reached or the chain
1174 //              terminates.  If it terminates prematurely, return with
1175 //              no other action.  Otherwise, deallocate all remaining
1176 //              sectors in the chain.
1177 //
1178 //  Notes:
1179 //
1180 //---------------------------------------------------------------------------
1181 
SetChainLength(SECT sectStart,ULONG ulLength)1182 SCODE CFat::SetChainLength(SECT sectStart, ULONG ulLength)
1183 {
1184     msfDebugOut((DEB_FAT,"In CFat::SetChainLength(%lu,%lu)\n",sectStart,ulLength));
1185     SCODE sc;
1186 
1187     if (sectStart == ENDOFCHAIN) return S_OK;
1188 
1189     for (USHORT ui = 0; ui < ulLength; ui++)
1190     {
1191         msfChk(GetNext(sectStart, &sectStart));
1192         if (sectStart == ENDOFCHAIN) return S_OK;
1193     }
1194 
1195     msfAssert(sectStart != ENDOFCHAIN &&
1196             aMsg("Called SetChainLength is ENDOFCHAIN start"));
1197 
1198     SECT sectEnd;
1199     sectEnd = sectStart;
1200 
1201     msfChk(GetNext(sectStart, &sectStart));
1202     if (ulLength != 0)
1203     {
1204         msfChk(SetNext(sectEnd, ENDOFCHAIN));
1205     }
1206     else
1207     {
1208         msfChk(SetNext(sectEnd, FREESECT));
1209     }
1210 
1211     while (sectStart != ENDOFCHAIN)
1212     {
1213         SECT sectTemp;
1214         msfChk(GetNext(sectStart, &sectTemp));
1215         msfChk(SetNext(sectStart, FREESECT));
1216         sectStart = sectTemp;
1217     }
1218     msfDebugOut((DEB_FAT,"Out CFat::SetChainLength()\n"));
1219 
1220 Err:
1221     return sc;
1222 }
1223 
1224 
1225 
1226 //+-------------------------------------------------------------------------
1227 //
1228 //  Method:     CFat::FindLast, private
1229 //
1230 //  Synopsis:   Find last used sector in a fat
1231 //
1232 //  Returns:    Location of last used sector
1233 //
1234 //  Algorithm:  Perform a backward linear search until a non-free
1235 //              sector is found.
1236 //
1237 //  Notes:      Used for shadow fats only.
1238 //
1239 //--------------------------------------------------------------------------
1240 
FindLast(SECT * psectRet)1241 SCODE CFat::FindLast(SECT * psectRet)
1242 {
1243     SCODE sc = S_OK;
1244     FSINDEX ipfs = _cfsTable;
1245     SECT sect = 0;
1246 
1247     while (ipfs > 0)
1248     {
1249         ipfs--;
1250 
1251         FSOFFSET isect = _fv.GetSectTable();
1252 
1253         CFatSect *pfs;
1254         msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
1255 
1256         while (isect > 0)
1257         {
1258             isect--;
1259 
1260             SECT sectCurrent = pfs->GetSect(isect);
1261 
1262 
1263             if (sectCurrent != FREESECT)
1264             {
1265                 msfDebugOut((DEB_FAT,"FindLast returns %lu\n",PairToSect(ipfs,isect)));
1266                 sect = PairToSect(ipfs, (FSOFFSET) (isect + 1));
1267                 break;
1268             }
1269         }
1270 
1271         _fv.ReleaseTable(ipfs);
1272         if (sect != 0)
1273             break;
1274     }
1275 
1276     *psectRet = sect;
1277 Err:
1278     return sc;
1279 }
1280 
1281 
1282 
1283 
1284 
1285 //+-------------------------------------------------------------------------
1286 //
1287 //  Method:     CFat::FindMaxSect, private
1288 //
1289 //  Synopsis:   Return last used sector in current Fat.
1290 //
1291 //  Arguments:  None.
1292 //
1293 //  Returns:    Last used sector in current Fat
1294 //
1295 //--------------------------------------------------------------------------
1296 
FindMaxSect(SECT * psectRet)1297 SCODE CFat::FindMaxSect(SECT *psectRet)
1298 {
1299     SCODE sc = S_OK;
1300 
1301     if (_sectMax == ENDOFCHAIN)
1302     {
1303         msfChk(FindLast(psectRet));
1304     }
1305     else
1306     {
1307 #if DBG == 1
1308         SECT sectLast;
1309         msfChk(FindLast(&sectLast));
1310 #endif
1311         *psectRet = _sectMax;
1312     }
1313 
1314 Err:
1315     return sc;
1316 }
1317 
1318 
1319 //+-------------------------------------------------------------------------
1320 //
1321 //  Member:     CFat::Contig, public
1322 //
1323 //  Synposis:   Create contiguous sector table
1324 //
1325 //  Effects:    Creates new CSegment.
1326 //
1327 //  Arguments:  [sect] -- Starting sector for table to begin
1328 //              [ulength] -- Runlength in sectors of table to produce
1329 //
1330 //  Returns:    Pointer to a Segment table
1331 //
1332 //  Algorithm:  Perform calls to CFat::GetNext().  Any call that is
1333 //              1 higher than the previous represents contiguous blocks.
1334 //              Construct the Segment table on that basis.
1335 //
1336 //  Notes:
1337 //
1338 //---------------------------------------------------------------------------
1339 
Contig(SSegment STACKBASED * aseg,SECT sect,ULONG ulLength)1340 SCODE  CFat::Contig(
1341         SSegment STACKBASED *aseg,
1342         SECT sect,
1343         ULONG ulLength)
1344 {
1345     msfDebugOut((DEB_ITRACE,"In CFat::Contig(%lu,%lu)\n",sect,ulLength));
1346     SCODE sc = S_OK;
1347     SECT stemp = sect;
1348     ULONG ulCount = 1;
1349     USHORT iseg = 0;
1350 
1351     msfAssert(sect != ENDOFCHAIN &&
1352             aMsg("Called Contig with ENDOFCHAIN start"));
1353 
1354     aseg[iseg].sectStart = sect;
1355     aseg[iseg].cSect = 1;
1356 
1357     while ((ulLength > 1) && (iseg < CSEG))
1358     {
1359         msfAssert(sect != ENDOFCHAIN &&
1360                 aMsg("Contig found premature ENDOFCHAIN"));
1361 
1362         FSINDEX ipfs;
1363         FSOFFSET isect;
1364 
1365         SectToPair(sect, &ipfs, &isect);
1366 
1367         CFatSect *pfs;
1368         msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
1369         sect = pfs->GetSect(isect);
1370         _fv.ReleaseTable(ipfs);
1371 
1372         if (sect == ENDOFCHAIN)
1373         {
1374             //Allocate new sectors.
1375 
1376             SECT sectNew;
1377             msfChk(GetFree(ulLength - 1, &sectNew));
1378             msfChk(SetNext(stemp, sectNew));
1379             sect = sectNew;
1380         }
1381 
1382         if (sect != (stemp + 1))
1383         {
1384             aseg[iseg].cSect = ulCount;
1385             ulCount = 1;
1386             iseg++;
1387             aseg[iseg].sectStart = sect;
1388             stemp = sect;
1389         }
1390         else
1391         {
1392             ulCount++;
1393             stemp = sect;
1394         }
1395         ulLength--;
1396     }
1397 
1398     if (iseg < CSEG)
1399     {
1400         aseg[iseg].cSect = ulCount;
1401         aseg[iseg + 1].sectStart = ENDOFCHAIN;
1402     }
1403     else
1404     {
1405         aseg[iseg].sectStart = FREESECT;
1406     }
1407 
1408     msfDebugOut((DEB_ITRACE,"Exiting Contig()\n"));
1409 
1410 Err:
1411     return sc;
1412 }
1413 
1414