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, §));
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, §First));
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, §));
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, §New));
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, §Last));
736
737 }
738
739 msfChk(_pmsParent->SetSize());
740
741
742 msfChk(pfat->GetSect(sectNew, csect, §New));
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, §New));
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, §New));
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, §Temp));
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, §));
1071 }
1072 else for (USHORT i = 0; i < ulNum; i++)
1073 {
1074 msfChk(GetNext(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, §Start));
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, §Start));
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, §Temp));
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(§Last));
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, §New));
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