Leaked source code of windows server 2003
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.

1437 lines
38 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 = ENDOFCHAIN;
  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. InitRangeLocksSector();
  337. _ulFreeSects = MAX_ULONG;
  338. Err:
  339. return sc;
  340. }
  341. //+-------------------------------------------------------------------------
  342. //
  343. // Method: CFat::InitConvert, public
  344. //
  345. // Synopsis: Init function used for conversion
  346. //
  347. // Arguments: [sectData] -- number of sectors used by file
  348. //
  349. // Returns: S_OK if call completed OK.
  350. //
  351. // Algorithm: *Finish This*
  352. //
  353. // Notes:
  354. //
  355. //--------------------------------------------------------------------------
  356. SCODE CFat::InitConvert(CMStream *pmsParent, SECT sectData)
  357. {
  358. SCODE sc;
  359. msfDebugOut((DEB_FAT,"Doing conversion\n"));
  360. _pmsParent = pmsParent;
  361. msfAssert((sectData != 0) &&
  362. aMsg("Attempt to convert zero length file."));
  363. SECT sectMax = 0;
  364. FSINDEX csectFat = 0;
  365. FSINDEX csectLast;
  366. InitRangeLocksSector();
  367. if (_sid == SIDFAT)
  368. {
  369. SECT sectTotal;
  370. //Since the fat needs to represent itself, we can't determine
  371. // the actual number of sectors needed in one pass. We
  372. // therefore loop, factoring in the number of fat sectors
  373. // at each iteration, until we reach a stable state.
  374. //
  375. //As an example, consider the case where each fat sector represents
  376. // 128 sectors and the file being converted is 128 sectors long.
  377. // There will be no DIFat - therefore, we have 128 sectors needed
  378. // on the first pass, which will require 1 fat sector to
  379. // represent them. On the second pass, we discover that we
  380. // actually need 2 fat sectors, since we now have 129 total
  381. // sectors to allocate space for. The third pass will result
  382. // in a stable state.
  383. do
  384. {
  385. csectLast = csectFat;
  386. sectTotal = sectData + _pmsParent->GetHeader()->GetDifLength() +
  387. csectFat + 1;
  388. csectFat = (sectTotal + _fv.GetSectTable() - 1) >> _uFatShift;
  389. }
  390. while (csectLast != csectFat);
  391. sectMax = sectData + _pmsParent->GetHeader()->GetDifLength();
  392. }
  393. else
  394. {
  395. //The minifat doesn't need to represent itself, so we can
  396. // compute the number of sectors needed in one pass.
  397. sectMax = sectData;
  398. csectFat = (sectMax + _fv.GetSectTable() -1) >> _uFatShift;
  399. }
  400. msfChk(_fv.Init(_pmsParent, csectFat));
  401. FSINDEX i;
  402. if (_sid == SIDMINIFAT)
  403. {
  404. SECT sectFirst;
  405. msfChk(_pmsParent->GetFat()->Allocate(csectFat, &sectFirst));
  406. _pmsParent->GetHeader()->SetMiniFatStart(sectFirst);
  407. _pmsParent->GetHeader()->SetMiniFatLength(csectFat);
  408. }
  409. for (i = 0; i < csectFat; i++)
  410. {
  411. CFatSect *pfs;
  412. msfChk(_fv.GetTable(i, FB_NEW, &pfs));
  413. if (_sid == SIDFAT)
  414. {
  415. _fv.SetSect(i, sectMax + i);
  416. _pmsParent->GetDIFat()->SetFatSect(i, sectMax + i);
  417. }
  418. else
  419. {
  420. SECT sect;
  421. msfChk(_pmsParent->GetESect(_sid, i, &sect));
  422. _fv.SetSect(i, sect);
  423. }
  424. _fv.ReleaseTable(i);
  425. }
  426. _cfsTable = csectFat;
  427. if (_sid != SIDMINIFAT)
  428. {
  429. _pmsParent->GetHeader()->SetFatLength(_cfsTable);
  430. SECT sect;
  431. if (sectData > 1)
  432. {
  433. for (sect = 0; sect < sectData - 2; sect++)
  434. {
  435. msfChk(SetNext(sect, sect + 1));
  436. }
  437. msfChk(SetNext(sectData - 2, ENDOFCHAIN));
  438. msfChk(SetNext(sectData - 1, 0));
  439. }
  440. else
  441. {
  442. //In the event that the file to be converted is less
  443. // than one sector long, we don't need to create a
  444. // real chain, just a single terminated sector.
  445. msfChk(SetNext(0, ENDOFCHAIN));
  446. }
  447. for (sect = sectData; sect < sectMax; sect++)
  448. {
  449. msfChk(SetNext(sect, DIFSECT));
  450. }
  451. for (ULONG j = 0; j < csectFat; j++)
  452. {
  453. msfChk(SetNext(sectMax + j, FATSECT));
  454. }
  455. //Set up directory chain.
  456. msfChk(SetNext(sectMax + i, ENDOFCHAIN));
  457. _pmsParent->GetHeader()->SetDirStart(sectMax + i);
  458. _ulFreeSects = (_cfsTable << _uFatShift) - (sectMax + csectFat + 1);
  459. }
  460. else
  461. {
  462. for (SECT sect = 0; sect < sectData -1; sect++)
  463. {
  464. msfChk(SetNext(sect, sect + 1));
  465. }
  466. msfChk(SetNext(sectData - 1, ENDOFCHAIN));
  467. _ulFreeSects = (_cfsTable << _uFatShift) - sectData;
  468. }
  469. msfChk(_pmsParent->SetSize());
  470. Err:
  471. return sc;
  472. }
  473. //+-------------------------------------------------------------------------
  474. //
  475. // Member: CFat::InitNew, public
  476. //
  477. // Synposis: Sets up a FAT for a newly created multi-strean
  478. //
  479. // Effects: Changes all _apfsTable entries, _cfsTable, and all
  480. // flags fields
  481. //
  482. // Arguments: [pmsparent] -- pointer to parent Mstream
  483. //
  484. // Returns: S_OK if call completed OK.
  485. //
  486. // Algorithm: Set parent pointer.
  487. // Allocate 1 sector for FAT and 1 for Directory.
  488. //
  489. // Notes:
  490. //
  491. //---------------------------------------------------------------------------
  492. SCODE CFat::InitNew(CMStream *pmsParent)
  493. {
  494. msfDebugOut((DEB_FAT,"In CFat::InitNew()\n"));
  495. SCODE sc;
  496. _pmsParent = pmsParent;
  497. FSINDEX count;
  498. if (SIDMINIFAT == _sid)
  499. count = _pmsParent->GetHeader()->GetMiniFatLength();
  500. else
  501. count = _pmsParent->GetHeader()->GetFatLength();
  502. msfDebugOut((DEB_FAT,"Setting up Fat of size %lu\n",count));
  503. msfChk(_fv.Init(_pmsParent, count));
  504. _cfsTable = count;
  505. InitRangeLocksSector();
  506. if (SIDFAT == _sid)
  507. {
  508. FSINDEX ipfs;
  509. FSOFFSET isect;
  510. CFatSect *pfs;
  511. SectToPair(_pmsParent->GetHeader()->GetFatStart(), &ipfs, &isect);
  512. msfChk(_fv.GetTable(ipfs, FB_NEW, &pfs));
  513. _fv.SetSect(ipfs, _pmsParent->GetHeader()->GetFatStart());
  514. _fv.ReleaseTable(ipfs);
  515. msfChk(SetNext(_pmsParent->GetHeader()->GetFatStart(), FATSECT));
  516. msfDebugOut((DEB_ITRACE,"Set sector %lu (FAT) to ENDOFCHAIN\n",_pmsParent->GetHeader()->GetFatStart()));
  517. msfChk(SetNext(_pmsParent->GetHeader()->GetDirStart(), ENDOFCHAIN));
  518. msfDebugOut((DEB_ITRACE,"Set sector %lu (DIR) to ENDOFCHAIN\n",_pmsParent->GetHeader()->GetDirStart()));
  519. _ulFreeSects = (count << _uFatShift) - 2;
  520. }
  521. else
  522. {
  523. _ulFreeSects = 0;
  524. }
  525. msfChk(_pmsParent->SetSize());
  526. msfDebugOut((DEB_FAT,"Exiting CFat::setupnew()\n"));
  527. Err:
  528. return sc;
  529. }
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Member: CFat::Resize, private
  533. //
  534. // Synposis: Resize FAT, both in memory and in the file
  535. //
  536. // Effects: Modifies _cfsTable, _apfsTable, and all flags fields
  537. //
  538. // Arguments: [ulSize] -- New size (in # of tables) for FAT
  539. //
  540. // Returns: S_OK if call completed OK.
  541. //
  542. // Algorithm: Allocate new array of new size.
  543. // Copy over all old pointers.
  544. // Allocate new tables for any necessary.
  545. //
  546. // Notes: This routine currently cannot reduce the size of a fat
  547. //---------------------------------------------------------------------------
  548. SCODE CFat::Resize(ULONG ulSize)
  549. {
  550. msfDebugOut((DEB_FAT,"In CFat::Resize(%lu)\n",ulSize));
  551. SCODE sc;
  552. if (ulSize == _cfsTable)
  553. {
  554. return S_OK;
  555. }
  556. ULONG csect = _cfsTable;
  557. msfAssert(ulSize > _cfsTable &&
  558. aMsg("Attempted to shrink Fat"));
  559. // 512byte sector docfiles are restricted to 2G for now
  560. if (_pmsParent->GetSectorShift() == SECTORSHIFT512 &&
  561. ulSize > _ipfsRangeLocks)
  562. return STG_E_DOCFILETOOLARGE;
  563. ULONG ipfs;
  564. SECT sectNew = ENDOFCHAIN;
  565. CFat *pfat = _pmsParent->GetFat();
  566. if (_sid == SIDFAT)
  567. {
  568. //Make sure we have enough space for all of the sectors
  569. // to be allocated.
  570. ULONG csectFat = ulSize - _cfsTable;
  571. ULONG csectPerDif = (1 << _uFatShift) - 1;
  572. ULONG csectDif = (csectFat + csectPerDif - 1) / csectPerDif;
  573. //Assuming all the free sectors are at the end of the file,
  574. // we need a file csectNew sectors long to hold them.
  575. ULONG csectOld, csectNew;
  576. msfChk(FindMaxSect(&csectOld));
  577. csectNew = csectOld + csectFat + csectDif;
  578. ULARGE_INTEGER cbSize;
  579. cbSize.QuadPart = ConvertSectOffset(
  580. csectNew,
  581. 0,
  582. _pmsParent->GetSectorShift());
  583. msfHChk(_pmsParent->GetILB()->SetSize(cbSize));
  584. //If we are the fat, we have enough space in the file for
  585. // ourselves at this point.
  586. }
  587. else
  588. {
  589. if (_cfsTable == 0)
  590. {
  591. msfChk(pfat->Allocate(ulSize, &sectNew));
  592. _pmsParent->GetHeader()->SetMiniFatStart(sectNew);
  593. }
  594. else
  595. {
  596. sectNew = _pmsParent->GetHeader()->GetMiniFatStart();
  597. SECT sectLast;
  598. msfChk(pfat->GetESect(sectNew, ulSize - 1, &sectLast));
  599. }
  600. msfChk(_pmsParent->SetSize());
  601. msfChk(pfat->GetSect(sectNew, csect, &sectNew));
  602. //If we are the Minifat, we have enough space in the underlying
  603. // file for ourselves at this point.
  604. }
  605. _fv.Resize(ulSize);
  606. for (ipfs = csect; ipfs < ulSize; ipfs++)
  607. {
  608. CFatSect *pfs;
  609. msfChk(_fv.GetTable(ipfs, FB_NEW, &pfs));
  610. _cfsTable = ipfs + 1;
  611. _ulFreeSects += (1 << _uFatShift);
  612. if (_sid == SIDFAT)
  613. {
  614. if (ipfs == _ipfsRangeLocks)
  615. {
  616. CVectBits *pfb;
  617. pfs->SetSect(_isectRangeLocks, ENDOFCHAIN);
  618. pfb = _fv.GetBits(_ipfsRangeLocks);
  619. if (pfb != NULL && pfb->full == FALSE &&
  620. _isectRangeLocks == pfb->firstfree)
  621. {
  622. pfb->firstfree = _isectRangeLocks + 1;
  623. }
  624. _ulFreeSects--;
  625. }
  626. msfChk(pfat->GetFree(1, &sectNew));
  627. msfChk(_pmsParent->GetDIFat()->SetFatSect(ipfs, sectNew));
  628. msfChk(pfat->SetNext(sectNew, FATSECT));
  629. }
  630. msfAssert(sectNew != ENDOFCHAIN &&
  631. aMsg("Bad sector returned for fatsect."));
  632. _fv.SetSect(ipfs, sectNew);
  633. _fv.ReleaseTable(ipfs);
  634. if (_sid == SIDMINIFAT)
  635. {
  636. msfChk(pfat->GetNext(sectNew, &sectNew));
  637. }
  638. }
  639. msfDebugOut((DEB_FAT,"CFat::Resize() - all new objects allocated\n"));
  640. if (SIDMINIFAT == _sid)
  641. _pmsParent->GetHeader()->SetMiniFatLength(_cfsTable);
  642. else
  643. _pmsParent->GetHeader()->SetFatLength(_cfsTable);
  644. //This setsize should only shrink the file.
  645. #if DBG == 1
  646. STATSTG stat;
  647. msfHChk(_pmsParent->GetILB()->Stat(&stat, STATFLAG_NONAME));
  648. #endif
  649. msfChk(_pmsParent->SetSize());
  650. #if DBG == 1
  651. STATSTG statNew;
  652. msfHChk(_pmsParent->GetILB()->Stat(&statNew, STATFLAG_NONAME));
  653. msfAssert(statNew.cbSize.QuadPart <= stat.cbSize.QuadPart);
  654. #endif
  655. msfDebugOut((DEB_FAT,"Out CFat::Resize(%lu)\n",ulSize));
  656. Err:
  657. return sc;
  658. }
  659. //+-------------------------------------------------------------------------
  660. //
  661. // Member: CFat::Extend, private
  662. //
  663. // Synposis: Increase the size of an existing chain
  664. //
  665. // Effects: Modifies ulSize sectors within the fat. Causes one or
  666. // more sector writes.
  667. //
  668. // Arguments: [sect] -- Sector ID of last sector in chain to be extended
  669. // [ulSize] -- Number of sectors to add to chain
  670. //
  671. // Requires: sect must be at the end of a chain.
  672. //
  673. // Returns: S_OK if call completed OK.
  674. //
  675. // Algorithm: Use calls to GetFree to allocate chain.
  676. //
  677. // Notes:
  678. //
  679. //---------------------------------------------------------------------------
  680. SCODE CFat::Extend(SECT sect, ULONG ulSize)
  681. {
  682. SCODE sc;
  683. msfDebugOut((DEB_FAT,"In CFat::Extend(%lu,%lu)\n",sect,ulSize));
  684. SECT sectTemp;
  685. msfChk(GetFree(ulSize, &sectTemp));
  686. msfChk(SetNext(sect, sectTemp));
  687. msfDebugOut((DEB_FAT,"Out CFat::Extend()\n"));
  688. Err:
  689. return sc;
  690. }
  691. //+-------------------------------------------------------------------------
  692. //
  693. // Member: CFat::GetNext, public
  694. //
  695. // Synposis: Returns the next sector in a chain, given a sector
  696. //
  697. // Arguments: [sect] -- Sector ID of any sector in a chain.
  698. //
  699. // Returns: Sector ID of next sector in chain, ENDOFCHAIN if at end
  700. //
  701. // Notes:
  702. //
  703. //---------------------------------------------------------------------------
  704. SCODE CFat::GetNext(const SECT sect, SECT * psRet)
  705. {
  706. SCODE sc;
  707. FSINDEX ipfs;
  708. FSOFFSET isect;
  709. msfAssert(sect <= MAXREGSECT &&
  710. aMsg("Called GetNext() on invalid sector"));
  711. SectToPair(sect, &ipfs, &isect);
  712. CFatSect *pfs;
  713. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  714. *psRet = pfs->GetSect(isect);
  715. _fv.ReleaseTable(ipfs);
  716. msfAssert(sect != *psRet &&
  717. aMsg("Detected loop in fat chain."));
  718. return S_OK;
  719. Err:
  720. return sc;
  721. }
  722. //+-------------------------------------------------------------------------
  723. //
  724. // Member: CFat::SetNext, private
  725. //
  726. // Synposis: Set the next sector in a chain
  727. //
  728. // Effects: Modifies a single entry within the fat.
  729. //
  730. // Arguments: [sectFirst] -- Sector ID of first sector
  731. // [sectNext] -- Sector ID of next sector
  732. //
  733. // Returns: void
  734. //
  735. // Notes:
  736. //
  737. //---------------------------------------------------------------------------
  738. SCODE CFat::SetNext(SECT sectFirst, SECT sectNext)
  739. {
  740. FSINDEX ipfs;
  741. FSOFFSET isect;
  742. SCODE sc;
  743. // creating infinite loops is a no-no
  744. msfAssert(sectFirst != sectNext &&
  745. aMsg("Attempted to create loop in Fat chain"));
  746. msfAssert(sectFirst <= MAXREGSECT &&
  747. aMsg("Called SetNext on invalid sector"));
  748. SectToPair(sectFirst, &ipfs, &isect);
  749. CFatSect *pfs;
  750. msfChk(_fv.GetTable(ipfs, FB_DIRTY, &pfs));
  751. pfs->SetSect(isect,sectNext);
  752. _fv.ReleaseTable(ipfs);
  753. if (sectNext == FREESECT)
  754. {
  755. CVectBits *pfb;
  756. pfb = _fv.GetBits(ipfs);
  757. if ((pfb != NULL) &&
  758. ((pfb->full == TRUE) || (isect < pfb->firstfree)))
  759. {
  760. pfb->full = FALSE;
  761. pfb->firstfree = isect;
  762. }
  763. if (sectFirst == _sectMax - 1)
  764. {
  765. _sectMax = ENDOFCHAIN;
  766. }
  767. if (sectFirst < _sectFirstFree)
  768. {
  769. _sectFirstFree = sectFirst;
  770. }
  771. if (_ulFreeSects != MAX_ULONG)
  772. {
  773. _ulFreeSects++;
  774. }
  775. }
  776. Err:
  777. return sc;
  778. }
  779. //+-------------------------------------------------------------------------
  780. //
  781. // Member: CFat::CountFree, private
  782. //
  783. // Synposis: Count and return the number of free sectors in the Fat
  784. //
  785. // Arguments: void.
  786. //
  787. // Returns: void.
  788. //
  789. // Algorithm: Do a linear search of the Fat, counting free sectors.
  790. // If a FatSect has its full bit set, it is not necessary
  791. // to search that FatSect.
  792. //
  793. // Notes:
  794. //
  795. //---------------------------------------------------------------------------
  796. SCODE CFat::CountFree(ULONG * pulRet)
  797. {
  798. msfDebugOut((DEB_FAT,"In CFat::CountFree()\n"));
  799. SCODE sc = S_OK;
  800. FSINDEX ipfs;
  801. ULONG csectFree=0;
  802. FSOFFSET isectStart;
  803. FSINDEX ipfsStart;
  804. SectToPair(_sectFirstFree, &ipfsStart, &isectStart);
  805. for (ipfs = ipfsStart; ipfs < _cfsTable; ipfs++)
  806. {
  807. CVectBits *pfb = _fv.GetBits(ipfs);
  808. if ((pfb == NULL) || (!pfb->full))
  809. {
  810. msfDebugOut((DEB_FAT,"Checking table %lu\n",ipfs));
  811. CFatSect *pfs;
  812. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  813. if (pfb != NULL)
  814. {
  815. isectStart = pfb->firstfree;
  816. }
  817. FSOFFSET isect;
  818. for (isect = isectStart; isect < _fv.GetSectTable(); isect++)
  819. {
  820. SECT sectCurrent = pfs->GetSect(isect);
  821. if (sectCurrent == FREESECT)
  822. {
  823. csectFree++;
  824. }
  825. }
  826. _fv.ReleaseTable(ipfs);
  827. }
  828. isectStart = 0;
  829. }
  830. msfDebugOut((DEB_FAT,"Countfree returned %lu\n",csectFree));
  831. *pulRet = csectFree;
  832. Err:
  833. return sc;
  834. }
  835. //+-------------------------------------------------------------------------
  836. //
  837. // Member: CFat::GetSect, public
  838. //
  839. // Synposis: Return the nth sector in a chain
  840. //
  841. // Arguments: [sect] -- Sector ID of beginning of chain
  842. // [uNum] -- indicator of which sector is to be returned
  843. // [psectReturn] -- Pointer to storage for return value
  844. //
  845. // Returns: S_OK.
  846. //
  847. // Algorithm: Linearly traverse chain until numth sector
  848. //
  849. // Notes:
  850. //
  851. //---------------------------------------------------------------------------
  852. SCODE CFat::GetSect(SECT sect, ULONG ulNum, SECT * psectReturn)
  853. {
  854. msfDebugOut((DEB_FAT,"In CFat::GetSect(%lu,%lu)\n",sect,ulNum));
  855. SCODE sc = S_OK;
  856. if (ulNum == 0)
  857. {
  858. msfDebugOut((DEB_FAT,"Out CFat::GetSect()=>%lu\n",sect));
  859. }
  860. else if ((SIDFAT == _sid) &&
  861. (_pmsParent->GetHeader()->GetFatStart() == sect))
  862. {
  863. msfChk(_pmsParent->GetDIFat()->GetFatSect(ulNum, &sect));
  864. }
  865. else for (ULONG i = 0; i < ulNum; i++)
  866. {
  867. msfChk(GetNext(sect, &sect));
  868. if (sect > MAXREGSECT)
  869. {
  870. //The stream isn't long enough, so stop.
  871. msfAssert(sect == ENDOFCHAIN &&
  872. aMsg("Found invalid sector in fat chain."));
  873. break;
  874. }
  875. }
  876. *psectReturn = sect;
  877. msfDebugOut((DEB_FAT,"Out CFat::GetSect()=>%lu\n",sect));
  878. Err:
  879. return sc;
  880. }
  881. //+-------------------------------------------------------------------------
  882. //
  883. // Member: CFat::GetESect
  884. //
  885. // Synposis: Return the nth sector in a chain, extending the chain
  886. // if necessary.
  887. //
  888. // Effects: Modifies fat (via Extend) if necessary
  889. //
  890. // Arguments: [sect] -- Sector ID of beginning of chain
  891. // [ulNum] -- Indicates which sector is to be returned
  892. // [psectReturn] -- Pointer to storage for return value
  893. //
  894. // Returns: S_OK if call completed OK.
  895. //
  896. // Algorithm: Linearly search chain until numth sector is found. If
  897. // the chain terminates early, extend it as necessary.
  898. //
  899. // Notes:
  900. //
  901. //---------------------------------------------------------------------------
  902. SCODE CFat::GetESect(SECT sect, ULONG ulNum, SECT *psectReturn)
  903. {
  904. msfDebugOut((DEB_FAT,"In CFat::GetESect(%lu,%lu)\n",sect,ulNum));
  905. SCODE sc = S_OK;
  906. ULONG i = 0;
  907. while (i < ulNum)
  908. {
  909. SECT temp;
  910. msfChk(GetNext(sect, &temp));
  911. msfAssert(temp != FREESECT &&
  912. aMsg("FREESECT found in chain."));
  913. if (temp == ENDOFCHAIN)
  914. {
  915. //The stream isn't long enough, so extend it somehow.
  916. ULONG need = ulNum - i;
  917. msfAssert((SIDMINIFAT == _sid ||
  918. sect != _pmsParent->GetHeader()->GetFatStart()) &&
  919. aMsg("Called GetESect on Fat chain"));
  920. msfChk(Extend(sect,need));
  921. }
  922. else
  923. {
  924. sect = temp;
  925. i++;
  926. }
  927. }
  928. msfDebugOut((DEB_FAT,"Exiting GetESect with result %lu\n",sect));
  929. *psectReturn = sect;
  930. Err:
  931. return sc;
  932. }
  933. //+-------------------------------------------------------------------------
  934. //
  935. // Member: CFat::SetChainLength, private
  936. //
  937. // Synposis: Set the length of a fat chain. This is used to reduce
  938. // the length of the chain only. To extend a chain, use
  939. // Extend or GetESect
  940. //
  941. // Effects: Modifies the fat
  942. //
  943. // Arguments: [sectStart] -- Sector to begin at (head of chain)
  944. // [uLength] -- New length for chain
  945. //
  946. // Returns: void.
  947. //
  948. // Algorithm: Traverse chain until uLength is reached or the chain
  949. // terminates. If it terminates prematurely, return with
  950. // no other action. Otherwise, deallocate all remaining
  951. // sectors in the chain.
  952. //
  953. // Notes:
  954. //
  955. //---------------------------------------------------------------------------
  956. SCODE CFat::SetChainLength(SECT sectStart, ULONG ulLength)
  957. {
  958. msfDebugOut((DEB_FAT,"In CFat::SetChainLength(%lu,%lu)\n",sectStart,ulLength));
  959. SCODE sc;
  960. if (sectStart == ENDOFCHAIN) return S_OK;
  961. for (ULONG ui = 0; ui < ulLength; ui++)
  962. {
  963. msfChk(GetNext(sectStart, &sectStart));
  964. if (sectStart == ENDOFCHAIN) return S_OK;
  965. }
  966. msfAssert(sectStart != ENDOFCHAIN &&
  967. aMsg("Called SetChainLength is ENDOFCHAIN start"));
  968. SECT sectEnd;
  969. sectEnd = sectStart;
  970. msfChk(GetNext(sectStart, &sectStart));
  971. if (ulLength != 0)
  972. {
  973. msfChk(SetNext(sectEnd, ENDOFCHAIN));
  974. }
  975. else
  976. {
  977. msfChk(SetNext(sectEnd, FREESECT));
  978. }
  979. while (sectStart != ENDOFCHAIN)
  980. {
  981. SECT sectTemp;
  982. msfChk(GetNext(sectStart, &sectTemp));
  983. msfChk(SetNext(sectStart, FREESECT));
  984. sectStart = sectTemp;
  985. }
  986. msfDebugOut((DEB_FAT,"Out CFat::SetChainLength()\n"));
  987. Err:
  988. return sc;
  989. }
  990. //+-------------------------------------------------------------------------
  991. //
  992. // Method: CFat::FindLast, private
  993. //
  994. // Synopsis: Find last used sector in a fat
  995. //
  996. // Returns: Location of last used sector
  997. //
  998. // Algorithm: Perform a backward linear search until a non-free
  999. // sector is found.
  1000. //
  1001. // Notes: Used for shadow fats only.
  1002. //
  1003. //--------------------------------------------------------------------------
  1004. SCODE CFat::FindLast(SECT * psectRet)
  1005. {
  1006. SCODE sc = S_OK;
  1007. FSINDEX ipfs = _cfsTable;
  1008. SECT sect = 0;
  1009. while (ipfs > 0)
  1010. {
  1011. ipfs--;
  1012. FSOFFSET isect = _fv.GetSectTable();
  1013. CFatSect *pfs;
  1014. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  1015. while (isect > 0)
  1016. {
  1017. isect--;
  1018. SECT sectCurrent = pfs->GetSect(isect);
  1019. if (ipfs == _ipfsRangeLocks && isect == _isectRangeLocks)
  1020. sectCurrent = FREESECT;
  1021. if (sectCurrent != FREESECT)
  1022. {
  1023. msfDebugOut((DEB_FAT,"FindLast returns %lu\n",PairToSect(ipfs,isect)));
  1024. sect = PairToSect(ipfs, (FSOFFSET) (isect + 1));
  1025. break;
  1026. }
  1027. }
  1028. _fv.ReleaseTable(ipfs);
  1029. if (sect != 0)
  1030. break;
  1031. }
  1032. *psectRet = sect;
  1033. Err:
  1034. return sc;
  1035. }
  1036. //+-------------------------------------------------------------------------
  1037. //
  1038. // Method: CFat::FindMaxSect, private
  1039. //
  1040. // Synopsis: Return last used sector in current Fat.
  1041. //
  1042. // Arguments: None.
  1043. //
  1044. // Returns: Last used sector in current Fat
  1045. //
  1046. //--------------------------------------------------------------------------
  1047. SCODE CFat::FindMaxSect(SECT *psectRet)
  1048. {
  1049. SCODE sc = S_OK;
  1050. if (_sectMax == ENDOFCHAIN)
  1051. {
  1052. msfChk(FindLast(psectRet));
  1053. }
  1054. else
  1055. {
  1056. #if DBG == 1
  1057. SECT sectLast;
  1058. msfChk(FindLast(&sectLast));
  1059. #endif
  1060. *psectRet = _sectMax;
  1061. }
  1062. Err:
  1063. return sc;
  1064. }
  1065. //+-------------------------------------------------------------------------
  1066. //
  1067. // Member: CFat::Contig, public
  1068. //
  1069. // Synposis: Create contiguous sector table
  1070. //
  1071. // Effects: Creates new CSegment.
  1072. //
  1073. // Arguments: [sect] -- Starting sector for table to begin
  1074. // [ulength] -- Runlength in sectors of table to produce
  1075. //
  1076. // Returns: Pointer to a Segment table
  1077. //
  1078. // Algorithm: Perform calls to CFat::GetNext(). Any call that is
  1079. // 1 higher than the previous represents contiguous blocks.
  1080. // Construct the Segment table on that basis.
  1081. //
  1082. // Notes:
  1083. //
  1084. //---------------------------------------------------------------------------
  1085. SCODE CFat::Contig(
  1086. SSegment STACKBASED *aseg,
  1087. SECT sect,
  1088. ULONG ulLength)
  1089. {
  1090. msfDebugOut((DEB_ITRACE,"In CFat::Contig(%lu,%lu)\n",sect,ulLength));
  1091. SCODE sc = S_OK;
  1092. SECT stemp = sect;
  1093. ULONG ulCount = 1;
  1094. USHORT iseg = 0;
  1095. msfAssert(sect != ENDOFCHAIN &&
  1096. aMsg("Called Contig with ENDOFCHAIN start"));
  1097. aseg[iseg].sectStart = sect;
  1098. aseg[iseg].cSect = 1;
  1099. while ((ulLength > 1) && (iseg < CSEG))
  1100. {
  1101. msfAssert(sect != ENDOFCHAIN &&
  1102. aMsg("Contig found premature ENDOFCHAIN"));
  1103. FSINDEX ipfs;
  1104. FSOFFSET isect;
  1105. SectToPair(sect, &ipfs, &isect);
  1106. CFatSect *pfs;
  1107. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  1108. sect = pfs->GetSect(isect);
  1109. _fv.ReleaseTable(ipfs);
  1110. if (sect == ENDOFCHAIN)
  1111. {
  1112. //Allocate new sectors.
  1113. SECT sectNew;
  1114. msfChk(GetFree(ulLength - 1, &sectNew));
  1115. msfChk(SetNext(stemp, sectNew));
  1116. sect = sectNew;
  1117. }
  1118. if (sect != (stemp + 1))
  1119. {
  1120. aseg[iseg].cSect = ulCount;
  1121. ulCount = 1;
  1122. iseg++;
  1123. aseg[iseg].sectStart = sect;
  1124. stemp = sect;
  1125. }
  1126. else
  1127. {
  1128. ulCount++;
  1129. stemp = sect;
  1130. }
  1131. ulLength--;
  1132. }
  1133. if (iseg < CSEG)
  1134. {
  1135. aseg[iseg].cSect = ulCount;
  1136. aseg[iseg + 1].sectStart = ENDOFCHAIN;
  1137. }
  1138. else
  1139. {
  1140. aseg[iseg].sectStart = FREESECT;
  1141. }
  1142. msfDebugOut((DEB_ITRACE,"Exiting Contig()\n"));
  1143. Err:
  1144. return sc;
  1145. }