Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1415 lines
35 KiB

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