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.

3149 lines
88 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. // History: 18-Jul-91 PhilipLa Created.
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "msfhead.cxx"
  16. #pragma hdrstop
  17. #include <difat.hxx>
  18. #include <sstream.hxx>
  19. #include <mread.hxx>
  20. #define USE_NOSCRATCHINMARKSECT
  21. //#define SECURETEST
  22. //+---------------------------------------------------------------------------
  23. //
  24. // Member: CFat::IsFree, private
  25. //
  26. // Synopsis: Check and see if a given sector is really free, given all
  27. // the permutations of ways a sector can be assigned.
  28. //
  29. // Arguments: [sect] -- Sector to check
  30. //
  31. // Returns: S_OK if sector is really free.
  32. // S_FALSE if sector is really allocated.
  33. // Appropriate error in error case.
  34. //
  35. // Modifies:
  36. //
  37. // History: 30-Mar-95 PhilipLa Created
  38. // 15-Mar-97 BChapman Calls IsSectType()
  39. //
  40. //----------------------------------------------------------------------------
  41. inline SCODE CFat::IsFree(SECT sect)
  42. {
  43. return IsSectType(sect, FREESECT);
  44. }
  45. //
  46. //+---------------------------------------------------------------------------
  47. //
  48. // Member: CFat::IsSectType, private
  49. //
  50. // Synopsis: Check and see if a given sector is really of a given type,
  51. // given all the permutations of ways a sector can be assigned.
  52. // If we are looking for FREESECT there are extra checks.
  53. //
  54. // Arguments: [sect] -- Sector to check
  55. // [sectType] -- Sector type to check against FREE, FAT, DIF.
  56. //
  57. // Returns: S_OK if sector is really free.
  58. // S_FALSE if sector is really allocated.
  59. // Appropriate error in error case.
  60. //
  61. // Modifies:
  62. //
  63. // History: 18-Feb-97 BChapman Created
  64. //
  65. //----------------------------------------------------------------------------
  66. inline SCODE CFat::IsSectType(SECT sect, SECT sectType)
  67. {
  68. SCODE sc = S_OK;
  69. SECT sectCurrent = sectType;
  70. #ifdef DEBUG_ISSECTTYPE
  71. msfDebugOut((DEB_ITRACE, "In CFat::IsSectType:%p(%x, %x)\n",
  72. this, sect, sectType));
  73. #endif
  74. if((FREESECT == sectType))
  75. {
  76. if (sect < _sectNoSnapshot)
  77. {
  78. return S_FALSE;
  79. }
  80. if ((_sectNoSnapshotFree != ENDOFCHAIN)
  81. && (sect < _sectNoSnapshotFree))
  82. {
  83. return S_FALSE;
  84. }
  85. }
  86. if (_pfatNoScratch != NULL)
  87. {
  88. msfAssert((!_pmsParent->IsScratch()) &&
  89. aMsg("Scratch MS in Noscratch mode"));
  90. FSINDEX ipfs;
  91. FSOFFSET isect;
  92. _pfatNoScratch->SectToPair(sect, &ipfs, &isect);
  93. if (ipfs < _pfatNoScratch->_cfsTable)
  94. {
  95. //We need to check the NoScratch fat to make sure
  96. //that this sector isn't already allocated into
  97. //scratch space for a stream.
  98. msfChk(_pfatNoScratch->GetNext(
  99. sect,
  100. &sectCurrent));
  101. }
  102. }
  103. //Since the no-scratch fat will have a complete copy of everything
  104. // in the shadow fat, we don't need to check both. So only do this
  105. // when we're not in no-scratch mode.
  106. //The no-scratch fat also has a copy of the read-only GetFree()
  107. // returned stuff, so we only need to do that check when not in
  108. // no-scratch.
  109. else
  110. {
  111. if (_cUnmarkedSects > 0)
  112. {
  113. //We are in copy-on-write mode. Lookup this
  114. //sector in the DIF and make sure that it is
  115. //actually free.
  116. msfAssert((_sectLastUsed > 0) &&
  117. aMsg("Doing DIFat check when not in COW."));
  118. msfChk(_pmsParent->GetDIFat()->Lookup(
  119. sect,
  120. &sectCurrent));
  121. }
  122. if (FREESECT == sectType)
  123. {
  124. if ((sect < _sectLastUsed) && (sectCurrent == FREESECT))
  125. {
  126. //We're in copy-on-write mode, so
  127. // this sector may not be really free.
  128. msfAssert(_sid != SIDMINIFAT &&
  129. aMsg("Minifat in Copy-on-Write mode"));
  130. msfAssert(_pfatReal != NULL &&
  131. aMsg("Copy-On-Write mode without fat copy"));
  132. msfAssert(_pfatReal->_cfsTable != 0 &&
  133. aMsg("Copy-on-Write mode with empty fat copy"));
  134. msfAssert(_pfatReal->_pmsParent->IsShadow() &&
  135. aMsg("Copy-on-Write mode with non-shadow fat copy"));
  136. msfChk(_pfatReal->GetNext(sect, &sectCurrent));
  137. }
  138. }
  139. }
  140. if (sectCurrent != sectType)
  141. {
  142. sc = S_FALSE;
  143. }
  144. #ifdef DEBUG_ISSECTTYPE
  145. msfDebugOut((DEB_ITRACE, "Out CFat::IsSectType\n"));
  146. #endif
  147. Err:
  148. return sc;
  149. }
  150. //+-------------------------------------------------------------------------
  151. //
  152. // Method: CFatSect::Init, public
  153. //
  154. // Synopsis: CFatSect initialization function
  155. //
  156. // Effects: [uEntries] -- Number of entries in sector
  157. //
  158. // Algorithm: Allocate an array of SECT with size uEntries from
  159. // the heap.
  160. //
  161. // History: 18-Jul-91 PhilipLa Created.
  162. // 27-Dec-91 PhilipLa Converted to dynamic allocation
  163. //
  164. //--------------------------------------------------------------------------
  165. SCODE CFatSect::Init(FSOFFSET uEntries)
  166. {
  167. msfDebugOut((DEB_FAT,"In CFatSect constructor\n"));
  168. //This assumes that FREESECT is always 0xFFFFFFFF
  169. memset(_asectEntry, 0xFF, uEntries * sizeof(SECT));
  170. msfDebugOut((DEB_FAT,"Out CFatSect constructor\n"));
  171. return S_OK;
  172. }
  173. //+-------------------------------------------------------------------------
  174. //
  175. // Method: CFatSect::InitCopy, public
  176. //
  177. // Synopsis: Initialization function for copying FatSects
  178. //
  179. // Arguments: [fsOld] -- Reference to FatSect to be copies
  180. //
  181. // Returns: S_OK if call completed successfully.
  182. //
  183. // Algorithm: Allocate a new array of SECT and copy old
  184. // information in.
  185. //
  186. // History: 06-Feb-92 PhilipLa Created.
  187. //
  188. //--------------------------------------------------------------------------
  189. SCODE CFatSect::InitCopy(USHORT uSize, CFatSect *pfsOld)
  190. {
  191. msfDebugOut((DEB_FAT,"In CFatSect copy constructor\n"));
  192. msfDebugOut((DEB_FAT,"This = %p, fsOld = %p\n",this, pfsOld));
  193. msfDebugOut((DEB_FAT,"Sector size is %u sectors\n", uSize));
  194. memcpy(_asectEntry, &pfsOld->_asectEntry, sizeof(SECT)*uSize);
  195. msfDebugOut((DEB_FAT,"Out CFatSect copy constructor\n"));
  196. return S_OK;
  197. }
  198. //+-------------------------------------------------------------------------
  199. //
  200. // Method: CFat::CFat, public
  201. //
  202. // Synopsis: CFat constructor.
  203. //
  204. // Arguments: [pmsParent] -- Pointer to parent multistream.
  205. //
  206. // Algorithm: Set uFatEntries to match parent MS header info.
  207. // Initialize all member variables.
  208. //
  209. // History: 18-Jul-91 PhilipLa Created.
  210. // 27-Dec-91 PhilipLa Converted to use FatVector
  211. // 30-Dec-91 PhilipLa Converted to use variable size sect.
  212. //
  213. // Notes:
  214. //
  215. //--------------------------------------------------------------------------
  216. CFat::CFat(SID sid)
  217. : _fv(sid),
  218. _pfatReal(NULL),
  219. _pfatNoScratch(NULL),
  220. _sectNoSnapshot(0),
  221. _sectNoSnapshotFree(ENDOFCHAIN),
  222. _sid(sid),
  223. _pmsParent(NULL),
  224. _sectFirstFree(0),
  225. _sectLastUsed(0),
  226. _sectMax(ENDOFCHAIN)
  227. {
  228. _cUnmarkedSects = 0;
  229. }
  230. //+-------------------------------------------------------------------------
  231. //
  232. // Method: CFat::CFat, public
  233. //
  234. // Synopsis: CFat copy constructor
  235. //
  236. // Arguments: [fatOld] -- Fat to be copied.
  237. //
  238. // Algorithm: Set member variables to match fat being copied.
  239. //
  240. // History: 27-Dec-91 PhilipLa Created.
  241. //
  242. // Notes: This is for use in transactioning. It is the only proper
  243. // way to create a Shadow Fat.
  244. //
  245. //--------------------------------------------------------------------------
  246. CFat::CFat(CFat *pfatOld)
  247. : _pmsParent(pfatOld->_pmsParent),
  248. _fv(pfatOld->_sid),
  249. _pfatReal(NULL),
  250. _sid(pfatOld->_sid),
  251. _sectFirstFree(0),
  252. _sectLastUsed(0),
  253. _sectMax(ENDOFCHAIN),
  254. _sectNoSnapshot(pfatOld->_sectNoSnapshot)
  255. {
  256. _cUnmarkedSects = 0;
  257. }
  258. //+-------------------------------------------------------------------------
  259. //
  260. // Method: CFat::InitCopy, public
  261. //
  262. // Synopsis: Init function for CFat copying
  263. //
  264. // Arguments: [fatOld] -- reference to CFat to be copied
  265. //
  266. // Returns: S_OK if call completed OK.
  267. //
  268. // Algorithm: *Finish This*
  269. //
  270. // History: 18-Feb-92 PhilipLa Created.
  271. //
  272. // Notes:
  273. //
  274. //--------------------------------------------------------------------------
  275. void CFat::InitCopy(CFat *pfatOld)
  276. {
  277. msfDebugOut((DEB_FAT,"In CFat Copy Constructor\n"));
  278. _pmsParent = pfatOld->_pmsParent;
  279. _uFatShift = pfatOld->_uFatShift;
  280. _uFatMask = pfatOld->_uFatMask;
  281. _fv.InitCommon(1 << _uFatShift, 1 << _uFatShift);
  282. _cfsTable = pfatOld->_cfsTable;
  283. _fv.InitCopy(&pfatOld->_fv);
  284. _ulFreeSects = MAX_ULONG;
  285. _sectFirstFree = pfatOld->_sectFirstFree;
  286. _sectLastUsed = pfatOld->_sectLastUsed;
  287. _sectMax = pfatOld->_sectMax;
  288. _ipfsRangeLocks = pfatOld->_ipfsRangeLocks;
  289. _isectRangeLocks = pfatOld->_isectRangeLocks;
  290. msfDebugOut((DEB_FAT,"Out CFat Copy Constructor\n"));
  291. }
  292. //+---------------------------------------------------------------------------
  293. //
  294. // Member: CFat::Empty, public
  295. //
  296. // Synopsis: Empty all the control structures of this instance
  297. //
  298. // Arguments: None.
  299. //
  300. // Returns: void.
  301. //
  302. // History: 04-Dec-92 PhilipLa Created
  303. //
  304. //----------------------------------------------------------------------------
  305. void CFat::Empty(void)
  306. {
  307. _fv.Empty();
  308. _pmsParent = NULL;
  309. _pfatReal = NULL;
  310. _cfsTable = 0;
  311. _ulFreeSects = MAX_ULONG;
  312. _sectFirstFree = 0;
  313. _sectLastUsed = 0;
  314. _sectMax = ENDOFCHAIN;
  315. _cUnmarkedSects = 0;
  316. }
  317. //+-------------------------------------------------------------------------
  318. //
  319. // Method: CFat::~CFat, public
  320. //
  321. // Synopsis: CFat Destructor
  322. //
  323. // Algorithm: delete dynamically allocated storage
  324. //
  325. // History: 18-Jul-91 PhilipLa Created.
  326. // 27-Jul-91 PhilipLa Converted to use FatVect.
  327. //
  328. // Notes:
  329. //
  330. //--------------------------------------------------------------------------
  331. CFat::~CFat()
  332. {
  333. msfDebugOut((DEB_FAT,"In CFat destructor. Size of fat is %lu\n",_cfsTable));
  334. msfDebugOut((DEB_FAT,"Exiting CFat destructor\n"));
  335. }
  336. struct SGetFreeStruct
  337. {
  338. CVectBits *pfb;
  339. SECT sect;
  340. CFatSect *pfs;
  341. FSOFFSET isect;
  342. FSINDEX ipfs;
  343. SECT sectLast;
  344. FSINDEX ipfsLast;
  345. FSOFFSET isectLast;
  346. #ifdef USE_NOSCRATCHINMARKSECT
  347. CFatSect *pfsNoScratch;
  348. FSINDEX ipfsNoScratch;
  349. #endif
  350. };
  351. //+---------------------------------------------------------------------------
  352. //
  353. // Member: CFat::InitGetFreeStruct, private
  354. //
  355. // Synopsis: Initialize an SGetFreeStruct
  356. //
  357. // Arguments: [pgf] -- Pointer to structure to initialize
  358. //
  359. // History: 03-Nov-95 PhilipLa Created
  360. //
  361. //----------------------------------------------------------------------------
  362. void CFat::InitGetFreeStruct(SGetFreeStruct *pgf)
  363. {
  364. pgf->sectLast = ENDOFCHAIN;
  365. pgf->pfs = NULL;
  366. #ifdef USE_NOSCRATCHINMARKSECT
  367. pgf->pfsNoScratch = NULL;
  368. #endif
  369. }
  370. //+---------------------------------------------------------------------------
  371. //
  372. // Member: CFat::ReleaseGetFreeStruct, private
  373. //
  374. // Synopsis: Release an SGetFreeStruct
  375. //
  376. // Arguments: [pgf] -- Pointer to structure to release
  377. //
  378. // History: 03-Nov-95 PhilipLa Created
  379. //
  380. //----------------------------------------------------------------------------
  381. void CFat::ReleaseGetFreeStruct(SGetFreeStruct *pgf)
  382. {
  383. if (pgf->pfs != NULL)
  384. {
  385. _fv.ReleaseTable(pgf->ipfs);
  386. }
  387. #ifdef USE_NOSCRATCHINMARKSECT
  388. if (pgf->pfsNoScratch != NULL)
  389. {
  390. _pfatNoScratch->_fv.ReleaseTable(pgf->ipfsNoScratch);
  391. }
  392. #endif
  393. }
  394. //+---------------------------------------------------------------------------
  395. //
  396. // Member: CFat::MarkSect, private
  397. //
  398. // Synopsis: Mark a sector as used, for use from GetFree and GetFreeContig
  399. //
  400. // Arguments: [pgf] -- Pointer to SGetFreeStruct with information about
  401. // which sector to mark. This structure also returns
  402. // information to the caller, so that state can be
  403. // preserved across multiple calls for optimization.
  404. //
  405. // Returns: Appropriate status code
  406. //
  407. // History: 27-Oct-95 PhilipLa Created
  408. //
  409. //----------------------------------------------------------------------------
  410. inline SCODE CFat::MarkSect(SGetFreeStruct *pgf)
  411. {
  412. msfAssert(_ulFreeSects != MAX_ULONG &&
  413. aMsg("Free sect count not set"));
  414. SCODE sc = S_OK;
  415. _ulFreeSects--;
  416. CVectBits * &pfb = pgf->pfb;
  417. SECT &sect = pgf->sect;
  418. FSOFFSET &isect = pgf->isect;
  419. FSINDEX &ipfs = pgf->ipfs;
  420. CFatSect * &pfs = pgf->pfs;
  421. #ifdef USE_NOSCRATCHINMARKSECT
  422. CFatSect * &pfsNoScratch = pgf->pfsNoScratch;
  423. FSINDEX &ipfsNoScratch = pgf->ipfsNoScratch;
  424. #endif
  425. SECT &sectLast = pgf->sectLast;
  426. FSINDEX &ipfsLast = pgf->ipfsLast;
  427. FSOFFSET &isectLast = pgf->isectLast;
  428. //If we're tracking the first free sector, we know it must be
  429. // after this one, so set firstfree.
  430. if (pfb != NULL)
  431. {
  432. pfb->firstfree = isect + 1;
  433. }
  434. //Update _sectFirstFree, since the first free sector must be after then
  435. // current one.
  436. msfAssert(sect >= _sectFirstFree &&
  437. aMsg("Found free sector before _sectFirstFree"));
  438. _sectFirstFree = sect + 1;
  439. //Mark the current sector as ENDOFCHAIN in the fat.
  440. pfs->SetSect(isect, ENDOFCHAIN);
  441. if (_pfatNoScratch != NULL)
  442. {
  443. #ifdef USE_NOSCRATCHINMARKSECT
  444. //In no-scratch, update the no-scratch fat
  445. //as well.
  446. FSINDEX ipfsNoScratchChk;
  447. FSOFFSET isectNoScratchChk;
  448. _pfatNoScratch->SectToPair(sect,
  449. &ipfsNoScratchChk,
  450. &isectNoScratchChk);
  451. if ((pfsNoScratch != NULL) && (ipfsNoScratch != ipfsNoScratchChk))
  452. {
  453. _pfatNoScratch->_fv.ReleaseTable(ipfsNoScratch);
  454. pfsNoScratch = NULL;
  455. }
  456. if (pfsNoScratch == NULL)
  457. {
  458. //SetNext call will grow the no-scratch fat if necessary.
  459. msfChk(_pfatNoScratch->SetNext(sect, ENDOFCHAIN));
  460. msfChk(_pfatNoScratch->_fv.GetTable(ipfsNoScratchChk,
  461. FB_DIRTY,
  462. &pfsNoScratch));
  463. ipfsNoScratch = ipfsNoScratchChk;
  464. }
  465. else
  466. {
  467. pfsNoScratch->SetSect(isectNoScratchChk, ENDOFCHAIN);
  468. _pfatNoScratch->_ulFreeSects--;
  469. }
  470. #else
  471. msfChk(_pfatNoScratch->SetNext(sect, ENDOFCHAIN)); // slow, unoptimized
  472. #endif
  473. }
  474. //Dirty the current page.
  475. if ((sectLast == ENDOFCHAIN) || (ipfs != ipfsLast))
  476. {
  477. //We only need to make this call if we're touching a new
  478. // page for the first time.
  479. msfChk(_fv.SetDirty(ipfs));
  480. }
  481. //If we're building a chain, we want to update it here.
  482. if (sectLast != ENDOFCHAIN)
  483. {
  484. if (_pfatNoScratch != NULL)
  485. {
  486. #ifdef USE_NOSCRATCHINMARKSECT
  487. FSINDEX ipfsNoScratchChk;
  488. FSOFFSET isectNoScratchChk;
  489. _pfatNoScratch->SectToPair(sectLast,
  490. &ipfsNoScratchChk,
  491. &isectNoScratchChk);
  492. if (ipfsNoScratchChk == ipfsNoScratch)
  493. {
  494. msfAssert(pfsNoScratch != NULL);
  495. pfsNoScratch->SetSect(isectNoScratchChk, sect);
  496. }
  497. else
  498. {
  499. msfChk(_pfatNoScratch->SetNext(sectLast, sect));
  500. }
  501. #else
  502. msfChk(_pfatNoScratch->SetNext(sectLast, sect)); //slow,unoptimized
  503. #endif
  504. }
  505. //If we're in the same page, we can do this cheaply.
  506. if (ipfsLast == ipfs)
  507. {
  508. pfs->SetSect(isectLast, sect);
  509. }
  510. else
  511. {
  512. //If we're NOT on the same page, we have to go grab the
  513. // old one again, which can be expensive if the page table is full
  514. CFatSect *pfsLast;
  515. //Since we may only have one available page for the scratch MS,
  516. // we need to release the current one before proceeding.
  517. //
  518. if (_pmsParent->IsScratch())
  519. {
  520. _fv.ReleaseTable(ipfs);
  521. }
  522. msfChk(_fv.GetTable(ipfsLast,
  523. FB_DIRTY,
  524. &pfsLast));
  525. pfsLast->SetSect(isectLast, sect);
  526. _fv.ReleaseTable(ipfsLast);
  527. //Reacquire the current page if we're in the scratch.
  528. if (_pmsParent->IsScratch())
  529. {
  530. msfChk(_fv.GetTable(ipfs, FB_DIRTY, &pfs));
  531. }
  532. }
  533. }
  534. return S_OK;
  535. Err:
  536. return sc;
  537. }
  538. //+-------------------------------------------------------------------------
  539. //
  540. // Member: CFat::GetFree, private
  541. //
  542. // Synposis: Locate and return a free sector in the FAT
  543. //
  544. // Effects: May modify full bit on full sectors
  545. //
  546. // Arguments: [psectRet] -- Pointer to return value
  547. //
  548. // Returns: S_OK if call completed successfully.
  549. //
  550. // Algorithm: Do a linear search of all tables until a free sector is
  551. // found. If all tables are full, extend the FAT by one
  552. // sector.
  553. //
  554. // History: 18-Jul-91 PhilipLa Created.
  555. // 22-Jul-91 PhilipLa Added FAT extension.
  556. // 17-Aug-91 PhilipLa Added full bits optimization
  557. //
  558. // Notes:
  559. //
  560. //---------------------------------------------------------------------------
  561. SCODE CFat::GetFree(ULONG ulCount, SECT *psectRet, BOOL fReadOnly)
  562. {
  563. SGetFreeStruct gf;
  564. SECT &sect = gf.sect;
  565. CVectBits * &pfb = gf.pfb;
  566. FSOFFSET &isect = gf.isect;
  567. FSINDEX &ipfs = gf.ipfs;
  568. CFatSect * &pfs = gf.pfs;
  569. SECT &sectLast = gf.sectLast;
  570. FSINDEX &ipfsLast = gf.ipfsLast;
  571. FSOFFSET &isectLast = gf.isectLast;
  572. InitGetFreeStruct(&gf);
  573. SCODE sc;
  574. *psectRet = ENDOFCHAIN;
  575. msfAssert((!_pmsParent->IsShadow()) &&
  576. aMsg("Modifying shadow fat."));
  577. msfAssert(((!fReadOnly) || (ulCount == 1)) &&
  578. aMsg("Read-only GetFree called with ulCount != 1"));
  579. if (_sectNoSnapshotFree != ENDOFCHAIN)
  580. {
  581. //We're resizing our control structures to prepare for
  582. // no-snapshot commit.
  583. msfAssert((ulCount == 1) &&
  584. aMsg("No-snapshot GetFree called with ulCount != 1"));
  585. msfAssert(fReadOnly &&
  586. aMsg("No-snapshot GetFree called without fReadOnly"));
  587. *psectRet = _sectNoSnapshotFree++;
  588. _cUnmarkedSects++;
  589. if ((_ulFreeSects != 0) && (_ulFreeSects != MAX_ULONG))
  590. {
  591. _ulFreeSects--;
  592. }
  593. if (*psectRet >= _sectMax)
  594. {
  595. _sectMax = *psectRet + 1;
  596. }
  597. return S_OK;
  598. }
  599. if ((fReadOnly) && (_pfatNoScratch != NULL))
  600. {
  601. //As an optimization, and to prevent loops, we can dispatch
  602. //this call directly to the no-scratch fat, since it has a
  603. //complete picture of everything allocated in this fat.
  604. //Note that we don't need to pass the read-only flag to the
  605. //no-scratch, since it's perfectly OK to scribble on it
  606. //as much as we want.
  607. //Further note that if fReadOnly is true, then ulCount must be
  608. // 1, so we can just work with the constant.
  609. msfChk(_pfatNoScratch->GetFree(1, psectRet, GF_WRITE));
  610. if (_ulFreeSects != MAX_ULONG)
  611. {
  612. _ulFreeSects--;
  613. }
  614. _cUnmarkedSects++;
  615. if (*psectRet >= _sectMax)
  616. {
  617. _sectMax = *psectRet + 1;
  618. }
  619. return S_OK;
  620. }
  621. while (TRUE)
  622. {
  623. //Make sure there are enough free sectors to hold the whole chain
  624. // we're trying to allocate.
  625. if (_ulFreeSects == MAX_ULONG)
  626. {
  627. msfChk(CountFree(&_ulFreeSects));
  628. }
  629. #if DBG == 1
  630. else
  631. {
  632. CheckFreeCount();
  633. }
  634. #endif
  635. while (ulCount > _ulFreeSects)
  636. {
  637. #if DBG == 1 && !defined(USE_NOSCRATCH)
  638. ULONG ulFree = _ulFreeSects;
  639. #endif
  640. msfChk(Resize(_cfsTable +
  641. ((ulCount - _ulFreeSects + _fv.GetSectTable() - 1) >>
  642. _uFatShift)));
  643. #if DBG == 1 && !defined(USE_NOSCRATCH)
  644. msfAssert(_ulFreeSects > ulFree &&
  645. aMsg("Number of free sectors didn't increase after Resize."));
  646. #endif
  647. }
  648. //Starting at the first known free sector, loop until we find
  649. // enough sectors to complete the chain.
  650. FSOFFSET isectStart;
  651. FSINDEX ipfsStart;
  652. SectToPair(_sectFirstFree, &ipfsStart, &isectStart);
  653. for (ipfs = ipfsStart; ipfs < _cfsTable; ipfs++)
  654. {
  655. //Only check a page if it is not known to be full.
  656. pfb = _fv.GetBits(ipfs);
  657. if ((pfb == NULL) || (!pfb->full))
  658. {
  659. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  660. //Eliminate part of the search based on the first-known
  661. // free entry for the page
  662. if (pfb != NULL)
  663. {
  664. isectStart = pfb->firstfree;
  665. }
  666. for (isect = isectStart; isect < _fv.GetSectTable(); isect++)
  667. {
  668. SECT sectCurrent = pfs->GetSect(isect);
  669. sect = PairToSect(ipfs, isect);
  670. //If the sector is marked FREESECT, it still may not
  671. // really be free. The IsFree function will return
  672. // S_OK if it is OK to allocate.
  673. if ((sectCurrent == FREESECT) &&
  674. ((sc = IsFree(sect)) == S_OK))
  675. {
  676. //If fReadOnly is TRUE (meaning we're being called
  677. // by the DIFat), then we don't want to actually
  678. // mark anything in the current fat. We'll return
  679. // the current sector and then be done with it.
  680. if (fReadOnly)
  681. {
  682. _cUnmarkedSects++;
  683. _ulFreeSects--;
  684. }
  685. else
  686. {
  687. //Mark the sector as free and return it.
  688. msfChkTo(Err_Rel, MarkSect(&gf));
  689. }
  690. if (*psectRet == ENDOFCHAIN)
  691. {
  692. *psectRet = sect;
  693. }
  694. ulCount--;
  695. if (ulCount == 0)
  696. {
  697. //If we're done, release the current table,
  698. // update _sectMax, and return.
  699. if (sect >= _sectMax)
  700. {
  701. _sectMax = sect + 1;
  702. }
  703. ReleaseGetFreeStruct(&gf);
  704. return S_OK;
  705. }
  706. else
  707. {
  708. //Otherwise update the internal counters and
  709. // keep going.
  710. sectLast = sect;
  711. ipfsLast = ipfs;
  712. isectLast = isect;
  713. }
  714. }
  715. else
  716. {
  717. msfChkTo(Err_Rel, sc);
  718. }
  719. }
  720. _fv.ReleaseTable(ipfs);
  721. //If we are keeping a full bit, we can set it here, since
  722. // we know we've allocated everything out of the current
  723. // page.
  724. // the vectbits pointer may have changed due to a resize
  725. pfb = _fv.GetBits(ipfs);
  726. if (pfb != NULL)
  727. {
  728. pfb->full = TRUE;
  729. }
  730. }
  731. isectStart = 0;
  732. }
  733. //Keep _sectMax up to date for SetSize purposes.
  734. if (sectLast >= _sectMax)
  735. {
  736. _sectMax = sectLast + 1;
  737. }
  738. }
  739. msfAssert(0 &&
  740. aMsg("GetFree exited improperly."));
  741. sc = STG_E_ABNORMALAPIEXIT;
  742. Err:
  743. ReleaseGetFreeStruct(&gf);
  744. return sc;
  745. Err_Rel:
  746. ReleaseGetFreeStruct(&gf);
  747. return sc;
  748. }
  749. //+---------------------------------------------------------------------------
  750. //
  751. // Member: CFat::GetFreeContig, public
  752. //
  753. // Synopsis: Return a chain of free sectors, including contiguity
  754. // information about the chain.
  755. //
  756. // Arguments: [ulCount] -- Number of sectors to allocate
  757. // [aseg] -- Contig table to fill in
  758. // [cSeg] -- Index of last used segment in contig table.
  759. // [pcSegReturned] -- Pointer to return location for total
  760. // number of segments returned.
  761. //
  762. // Returns: Appropriate status code
  763. //
  764. // History: 27-Oct-95 PhilipLa Created
  765. //
  766. //----------------------------------------------------------------------------
  767. SCODE CFat::GetFreeContig(ULONG ulCount,
  768. SSegment STACKBASED *aseg,
  769. ULONG cSeg,
  770. ULONG *pcSegReturned)
  771. {
  772. SGetFreeStruct gf;
  773. SECT &sect = gf.sect;
  774. CVectBits * &pfb = gf.pfb;
  775. FSOFFSET &isect = gf.isect;
  776. FSINDEX &ipfs = gf.ipfs;
  777. CFatSect * &pfs = gf.pfs;
  778. SECT &sectLast = gf.sectLast;
  779. FSINDEX &ipfsLast = gf.ipfsLast;
  780. FSOFFSET &isectLast = gf.isectLast;
  781. InitGetFreeStruct(&gf);
  782. FSINDEX ipfsFirstDirty;
  783. SCODE sc;
  784. //Variables used for tracking contiguity.
  785. //cSegCurrent is the current segment being processed.
  786. ULONG cSegCurrent = cSeg;
  787. //sectLast is the last sector returned. We start this with the
  788. // last thing in the current contig table, and the MarkSect
  789. // function will patch up the chain for us.
  790. sectLast = aseg[cSeg].sectStart + aseg[cSeg].cSect - 1;
  791. SectToPair(sectLast, &ipfsLast, &isectLast);
  792. ipfsFirstDirty = ipfsLast;
  793. #if DBG == 1
  794. SECT sectTest;
  795. GetNext(sectLast, &sectTest);
  796. msfAssert(sectTest == ENDOFCHAIN);
  797. #endif
  798. msfAssert((!_pmsParent->IsShadow()) &&
  799. aMsg("Modifying shadow fat."));
  800. while (TRUE)
  801. {
  802. //Make sure there are enough free sectors to hold the whole chain
  803. // we're trying to allocate.
  804. if (_ulFreeSects == MAX_ULONG)
  805. {
  806. msfChk(CountFree(&_ulFreeSects));
  807. }
  808. #if DBG == 1
  809. else
  810. {
  811. CheckFreeCount();
  812. }
  813. #endif
  814. while (ulCount > _ulFreeSects)
  815. {
  816. #if DBG == 1 && !defined(USE_NOSCRATCH)
  817. ULONG ulFree = _ulFreeSects;
  818. #endif
  819. msfChk(Resize(_cfsTable +
  820. ((ulCount - _ulFreeSects + _fv.GetSectTable() - 1) >>
  821. _uFatShift)));
  822. #if DBG == 1 && !defined(USE_NOSCRATCH)
  823. msfAssert(_ulFreeSects > ulFree &&
  824. aMsg("Number of free sectors didn't increase after Resize."));
  825. #endif
  826. }
  827. //Starting at the first known free sector, loop until we find
  828. // enough sectors to complete the chain.
  829. FSOFFSET isectStart;
  830. FSINDEX ipfsStart;
  831. SectToPair(_sectFirstFree, &ipfsStart, &isectStart);
  832. for (ipfs = ipfsStart; ipfs < _cfsTable; ipfs++)
  833. {
  834. //Only check a page if it is not known to be full.
  835. pfb = _fv.GetBits(ipfs);
  836. if ((pfb == NULL) || (!pfb->full))
  837. {
  838. //This little contortion is necessary because the
  839. // page containing the first sector may not get marked
  840. // as dirty by MarkSect.
  841. if (ipfs == ipfsFirstDirty)
  842. {
  843. msfChk(_fv.GetTable(ipfs, FB_DIRTY, &pfs));
  844. }
  845. else
  846. {
  847. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  848. }
  849. //Eliminate part of the search based on the first-known
  850. // free entry for the page
  851. if (pfb != NULL)
  852. {
  853. isectStart = pfb->firstfree;
  854. }
  855. for (isect = isectStart; isect < _fv.GetSectTable(); isect++)
  856. {
  857. SECT sectCurrent = pfs->GetSect(isect);
  858. sect = PairToSect(ipfs, isect);
  859. //If the sector is marked FREESECT, it still may not
  860. // really be free. The IsFree function will return
  861. // TRUE if it is OK to allocate.
  862. if ((sectCurrent == FREESECT) &&
  863. ((sc = IsFree(sect)) == S_OK))
  864. {
  865. //Mark the sector as free and return it.
  866. msfChkTo(Err_Rel, MarkSect(&gf));
  867. ulCount--;
  868. //Update the contig table with this new information.
  869. if (cSegCurrent < CSEG)
  870. {
  871. if (sect != sectLast + 1)
  872. {
  873. //Use a new entry in the contig table.
  874. cSegCurrent++;
  875. if (cSegCurrent < CSEG)
  876. {
  877. aseg[cSegCurrent].ulOffset =
  878. aseg[cSegCurrent - 1].ulOffset +
  879. aseg[cSegCurrent - 1].cSect;
  880. aseg[cSegCurrent].sectStart = sect;
  881. aseg[cSegCurrent].cSect = 1;
  882. }
  883. }
  884. else
  885. {
  886. //Grow the current segment
  887. aseg[cSegCurrent].cSect++;
  888. }
  889. }
  890. if (ulCount == 0)
  891. {
  892. //If we're done, release the current table,
  893. // update _sectMax, and return.
  894. if (sect >= _sectMax)
  895. {
  896. _sectMax = sect + 1;
  897. }
  898. *pcSegReturned = cSegCurrent;
  899. ReleaseGetFreeStruct(&gf);
  900. #if DBG == 1
  901. _fv.ResetBits();
  902. CheckFreeCount();
  903. #endif
  904. return S_OK;
  905. }
  906. else
  907. {
  908. //Otherwise update the internal counters and
  909. // keep going.
  910. sectLast = sect;
  911. ipfsLast = ipfs;
  912. isectLast = isect;
  913. }
  914. }
  915. else
  916. {
  917. msfChkTo(Err_Rel, sc);
  918. }
  919. }
  920. _fv.ReleaseTable(ipfs);
  921. //If we are keeping a full bit, we can set it here, since
  922. // we know we've allocated everything out of the current
  923. // page.
  924. // the vectbits pointer may have changed due to a resize
  925. pfb = _fv.GetBits(ipfs);
  926. if (pfb != NULL)
  927. {
  928. pfb->full = TRUE;
  929. }
  930. }
  931. isectStart = 0;
  932. }
  933. //Keep _sectMax up to date for SetSize purposes.
  934. if (sectLast >= _sectMax)
  935. {
  936. _sectMax = sectLast + 1;
  937. }
  938. }
  939. msfAssert(0 &&
  940. aMsg("GetFree exited improperly."));
  941. sc = STG_E_ABNORMALAPIEXIT;
  942. Err:
  943. ReleaseGetFreeStruct(&gf);
  944. return sc;
  945. Err_Rel:
  946. ReleaseGetFreeStruct(&gf);
  947. return sc;
  948. }
  949. //+-------------------------------------------------------------------------
  950. //
  951. // Member: CFat::Contig, public
  952. //
  953. // Synposis: Create contiguous sector table
  954. //
  955. // Effects: Return contiguity information about a chain.
  956. //
  957. // Arguments: [aseg] -- Segment table to return data in
  958. // [sect] -- Starting sector for table to begin
  959. // [ulength] -- Runlength in sectors of table to produce
  960. // [pcSeg] -- Returns count of segments in table
  961. //
  962. // Returns: Appropriate status code.
  963. //
  964. // Algorithm: Perform calls to CFat::GetNext(). Any call that is
  965. // 1 higher than the previous represents contiguous blocks.
  966. // Construct the Segment table on that basis.
  967. //
  968. // History: 16-Aug-91 PhilipLa Created.
  969. // 20-May-92 AlexT Moved to CFat
  970. //
  971. // Notes:
  972. //
  973. //---------------------------------------------------------------------------
  974. SCODE CFat::Contig(
  975. SSegment STACKBASED *aseg,
  976. BOOL fWrite,
  977. SECT sectStart,
  978. ULONG ulLengthStart,
  979. ULONG *pcSeg)
  980. {
  981. msfDebugOut((DEB_ITRACE,"In CFat::Contig(%lu,%lu)\n",sectStart,ulLengthStart));
  982. SCODE sc = S_OK;
  983. ULONG ulLength = ulLengthStart;
  984. SECT sect = sectStart;
  985. SECT stemp = sect;
  986. ULONG ulCount = 1;
  987. USHORT iseg = 0;
  988. FSINDEX ipfs = (FSINDEX) -1;
  989. FSINDEX ipfsOld = ipfs;
  990. FSOFFSET isect;
  991. CFatSect *pfs = NULL;
  992. msfAssert(sect != ENDOFCHAIN &&
  993. aMsg("Called Contig with ENDOFCHAIN start"));
  994. msfAssert((ulLength > 0) && aMsg("Bad length passed to Contig()"));
  995. aseg[iseg].sectStart = sect;
  996. aseg[iseg].cSect = 1;
  997. aseg[iseg].ulOffset = 0;
  998. ulLength--;
  999. while (TRUE)
  1000. {
  1001. msfAssert(sect != ENDOFCHAIN &&
  1002. aMsg("Contig found premature ENDOFCHAIN"));
  1003. SectToPair(sect, &ipfs, &isect);
  1004. if (ipfs != ipfsOld)
  1005. {
  1006. if (ipfsOld != (FSINDEX) -1)
  1007. {
  1008. _fv.ReleaseTable(ipfsOld);
  1009. }
  1010. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  1011. ipfsOld = ipfs;
  1012. }
  1013. if (pfs != NULL)
  1014. sect = pfs->GetSect(isect);
  1015. if (sect == ENDOFCHAIN)
  1016. {
  1017. if ((ulLength < 1) || !fWrite)
  1018. break;
  1019. //Allocate new sectors.
  1020. #if 0
  1021. SECT sectNew;
  1022. msfChk(GetFree(ulLength, &sectNew, GF_WRITE));
  1023. msfChk(SetNext(stemp, sectNew));
  1024. sect = sectNew;
  1025. #else
  1026. //GetFreeContig will allocate new sectors and fill up
  1027. // our contig table. After this call, the chain will
  1028. // be the proper length and the contig table will either
  1029. // contain the entire chain, or will be full. Either
  1030. // way we can exit immediately.
  1031. if (ipfs != (FSINDEX) - 1)
  1032. {
  1033. _fv.ReleaseTable(ipfs);
  1034. }
  1035. ULONG isegRet = 0;
  1036. aseg[iseg].cSect = ulCount;
  1037. msfChk(GetFreeContig(ulLength, aseg, iseg, &isegRet));
  1038. if (isegRet == CSEG)
  1039. {
  1040. aseg[isegRet].ulOffset = 0;
  1041. aseg[isegRet].cSect = 0;
  1042. aseg[isegRet].sectStart = FREESECT;
  1043. }
  1044. else
  1045. {
  1046. aseg[isegRet + 1].sectStart = ENDOFCHAIN;
  1047. }
  1048. *pcSeg = isegRet + 1;
  1049. #if DBG == 1
  1050. SSegment segtab[CSEG + 1];
  1051. ULONG cSeg;
  1052. Contig(segtab, FALSE, sectStart, ulLengthStart, &cSeg);
  1053. msfAssert(cSeg == *pcSeg);
  1054. for (USHORT i = 0; i < cSeg; i++)
  1055. {
  1056. msfAssert(segtab[i].sectStart == aseg[i].sectStart);
  1057. msfAssert(segtab[i].ulOffset == aseg[i].ulOffset);
  1058. msfAssert(segtab[i].cSect == aseg[i].cSect);
  1059. }
  1060. #endif
  1061. return S_OK;
  1062. #endif
  1063. }
  1064. if (sect != (stemp + 1))
  1065. {
  1066. if (ulLength < 1)
  1067. break;
  1068. aseg[iseg].cSect = ulCount;
  1069. iseg++;
  1070. aseg[iseg].ulOffset = aseg[iseg - 1].ulOffset + ulCount;
  1071. aseg[iseg].sectStart = sect;
  1072. ulCount = 1;
  1073. stemp = sect;
  1074. }
  1075. else
  1076. {
  1077. ulCount++;
  1078. stemp = sect;
  1079. }
  1080. if (ulLength > 0)
  1081. ulLength--;
  1082. if (iseg >= CSEG)
  1083. break;
  1084. }
  1085. if (ipfs != (FSINDEX) -1)
  1086. {
  1087. _fv.ReleaseTable(ipfs);
  1088. }
  1089. if (iseg < CSEG)
  1090. {
  1091. aseg[iseg].cSect = ulCount;
  1092. aseg[iseg + 1].sectStart = ENDOFCHAIN;
  1093. }
  1094. else
  1095. {
  1096. aseg[iseg].ulOffset = 0;
  1097. aseg[iseg].cSect = 0;
  1098. aseg[iseg].sectStart = FREESECT;
  1099. }
  1100. *pcSeg = iseg + 1;
  1101. msfDebugOut((DEB_ITRACE,"Exiting Contig()\n"));
  1102. Err:
  1103. return sc;
  1104. }
  1105. //+---------------------------------------------------------------------------
  1106. //
  1107. // Member: CFat::ReserveSects, public
  1108. //
  1109. // Synopsis: Make sure the fat has at least a given number of free
  1110. // sectors in it.
  1111. //
  1112. // Arguments: [cSect] -- Number of sectors to reserve.
  1113. //
  1114. // Returns: Appropriate status code
  1115. //
  1116. // History: 18-Sep-95 PhilipLa Created
  1117. //
  1118. //----------------------------------------------------------------------------
  1119. SCODE CFat::ReserveSects(ULONG cSect)
  1120. {
  1121. SCODE sc = S_OK;
  1122. msfDebugOut((DEB_ITRACE, "In CFat::ReserveSects:%p()\n", this));
  1123. //Make sure there are enough free sectors to hold the whole chain
  1124. // we're trying to allocate.
  1125. if (_ulFreeSects == MAX_ULONG)
  1126. {
  1127. msfChk(CountFree(&_ulFreeSects));
  1128. }
  1129. #if DBG == 1
  1130. else
  1131. {
  1132. CheckFreeCount();
  1133. }
  1134. #endif
  1135. while (cSect > _ulFreeSects)
  1136. {
  1137. #if DBG == 1 && !defined(USE_NOSCRATCH)
  1138. ULONG ulFree = _ulFreeSects;
  1139. #endif
  1140. msfChk(Resize(_cfsTable +
  1141. ((cSect - _ulFreeSects + _fv.GetSectTable() - 1) >>
  1142. _uFatShift)));
  1143. #if DBG == 1 && !defined(USE_NOSCRATCH)
  1144. msfAssert(_ulFreeSects > ulFree &&
  1145. aMsg("Number of free sectors didn't increase after Resize."));
  1146. #endif
  1147. }
  1148. msfDebugOut((DEB_ITRACE, "Out CFat::ReserveSects\n"));
  1149. Err:
  1150. return sc;
  1151. }
  1152. //+-------------------------------------------------------------------------
  1153. //
  1154. // Member: CFat::GetLength, public
  1155. //
  1156. // Synposis: Return the length of a fat chain.
  1157. //
  1158. // Arguments: [sect] -- Sector to begin count at.
  1159. //
  1160. // Returns: Length of the chain, in sectors
  1161. //
  1162. // Algorithm: Traverse the chain until ENDOFCHAIN is reached.
  1163. //
  1164. // History: 18-Jul-91 PhilipLa Created.
  1165. //
  1166. // Notes:
  1167. //
  1168. //---------------------------------------------------------------------------
  1169. SCODE CFat::GetLength(SECT sect, ULONG * pulRet)
  1170. {
  1171. msfDebugOut((DEB_FAT,"In CFat::GetLength(%lu)\n",sect));
  1172. SCODE sc = S_OK;
  1173. ULONG csect = 0;
  1174. const ULONG csectMax = PairToSect(_cfsTable+1,0);
  1175. while (sect != ENDOFCHAIN)
  1176. {
  1177. msfChk(GetNext(sect, &sect));
  1178. csect++;
  1179. if (csect > csectMax) // infinite loop in the chain
  1180. msfErr (Err, STG_E_DOCFILECORRUPT);
  1181. }
  1182. msfDebugOut((DEB_FAT,"FAT: GetLength returned %u\n",csect));
  1183. *pulRet = csect;
  1184. Err:
  1185. return sc;
  1186. }
  1187. //+-------------------------------------------------------------------------
  1188. //
  1189. // Member: CFat::Init, public
  1190. //
  1191. // Synposis: Sets up a FAT, reading data from an existing stream
  1192. //
  1193. // Effects: Changes all _apfsTable entries, _cfsTable, and all
  1194. // flags fields
  1195. //
  1196. // Arguments: None.
  1197. //
  1198. // Returns: S_OK if call completed OK.
  1199. //
  1200. // Algorithm: Read size from first FAT in stream.
  1201. // Resize array to necessary size.
  1202. // Read in FAT sectors sequentially.
  1203. //
  1204. // History: 18-Jul-91 PhilipLa Created.
  1205. //
  1206. // Notes:
  1207. //
  1208. //---------------------------------------------------------------------------
  1209. SCODE CFat::Init(CMStream *pmsParent,
  1210. FSINDEX cFatSect,
  1211. BOOL fConvert)
  1212. {
  1213. SCODE sc;
  1214. msfDebugOut((DEB_FAT,"CFat::setup thinks the FAT is size %lu\n",cFatSect));
  1215. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  1216. _uFatShift = pmsParent->GetSectorShift() - 2;
  1217. _uFatMask = (pmsParent->GetSectorSize() >> 2) - 1;
  1218. _fv.InitCommon(1 << _uFatShift, 1 << _uFatShift);
  1219. msfChk(_fv.Init(pmsParent, cFatSect));
  1220. _cfsTable = cFatSect;
  1221. USHORT cbSectorSize;
  1222. cbSectorSize = pmsParent->GetSectorSize();
  1223. InitRangeLocksSector();
  1224. _ulFreeSects = MAX_ULONG;
  1225. Err:
  1226. return sc;
  1227. }
  1228. //+-------------------------------------------------------------------------
  1229. //
  1230. // Method: CFat::InitConvert, public
  1231. //
  1232. // Synopsis: Init function used for conversion
  1233. //
  1234. // Arguments: [sectData] -- number of sectors used by file
  1235. //
  1236. // Returns: S_OK if call completed OK.
  1237. //
  1238. // Algorithm: *Finish This*
  1239. //
  1240. // History: 28-May-92 PhilipLa Created.
  1241. //
  1242. // Notes:
  1243. //
  1244. //--------------------------------------------------------------------------
  1245. SCODE CFat::InitConvert(CMStream *pmsParent,
  1246. SECT sectData)
  1247. {
  1248. SCODE sc;
  1249. msfDebugOut((DEB_FAT,"Doing conversion\n"));
  1250. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  1251. msfAssert((sectData != 0) &&
  1252. aMsg("Attempt to convert zero length file."));
  1253. SECT sectMax = 0;
  1254. FSINDEX csectFat = 0;
  1255. FSINDEX csectLast;
  1256. _uFatShift = pmsParent->GetSectorShift() - 2;
  1257. _uFatMask = (pmsParent->GetSectorSize() >> 2) - 1;
  1258. _fv.InitCommon(1 << _uFatShift, 1 << _uFatShift);
  1259. InitRangeLocksSector ();
  1260. if (_sid == SIDFAT)
  1261. {
  1262. SECT sectTotal;
  1263. //Since the fat needs to represent itself, we can't determine
  1264. // the actual number of sectors needed in one pass. We
  1265. // therefore loop, factoring in the number of fat sectors
  1266. // at each iteration, until we reach a stable state.
  1267. //
  1268. //As an example, consider the case where each fat sector represents
  1269. // 128 sectors and the file being converted is 128 sectors long.
  1270. // There will be no DIFat - therefore, we have 128 sectors needed
  1271. // on the first pass, which will require 1 fat sector to
  1272. // represent them. On the second pass, we discover that we
  1273. // actually need 2 fat sectors, since we now have 129 total
  1274. // sectors to allocate space for. The third pass will result
  1275. // in a stable state.
  1276. do
  1277. {
  1278. csectLast = csectFat;
  1279. sectTotal = sectData + pmsParent->GetHeader()->GetDifLength() +
  1280. csectFat + 1;
  1281. csectFat = (sectTotal + _fv.GetSectTable() - 1) >> _uFatShift;
  1282. }
  1283. while (csectLast != csectFat);
  1284. sectMax = sectData + pmsParent->GetHeader()->GetDifLength();
  1285. }
  1286. else
  1287. {
  1288. //The minifat doesn't need to represent itself, so we can
  1289. // compute the number of sectors needed in one pass.
  1290. sectMax = sectData;
  1291. csectFat = (sectMax + _fv.GetSectTable() -1) >> _uFatShift;
  1292. }
  1293. msfChk(_fv.Init(pmsParent, csectFat));
  1294. FSINDEX i;
  1295. if (_sid == SIDMINIFAT)
  1296. {
  1297. SECT sectFirst;
  1298. msfChk(pmsParent->GetFat()->Allocate(csectFat, &sectFirst));
  1299. pmsParent->GetHeader()->SetMiniFatStart(sectFirst);
  1300. pmsParent->GetHeader()->SetMiniFatLength(csectFat);
  1301. }
  1302. for (i = 0; i < csectFat; i++)
  1303. {
  1304. CFatSect *pfs;
  1305. msfChk(_fv.GetTable(i, FB_NEW, &pfs));
  1306. if (_sid == SIDFAT)
  1307. {
  1308. _fv.SetSect(i, sectMax + i);
  1309. pmsParent->GetDIFat()->SetFatSect(i, sectMax + i);
  1310. }
  1311. else
  1312. {
  1313. msfAssert(_pfatNoScratch == NULL);
  1314. SECT sect;
  1315. msfChk(pmsParent->GetESect(_sid, i, &sect));
  1316. _fv.SetSect(i, sect);
  1317. }
  1318. _fv.ReleaseTable(i);
  1319. }
  1320. _cfsTable = csectFat;
  1321. if (_sid != SIDMINIFAT)
  1322. {
  1323. pmsParent->GetHeader()->SetFatLength(_cfsTable);
  1324. SECT sect;
  1325. if (sectData > 1)
  1326. {
  1327. for (sect = 0; sect < sectData - 2; sect++)
  1328. {
  1329. msfChk(SetNext(sect, sect + 1));
  1330. }
  1331. msfChk(SetNext(sectData - 2, ENDOFCHAIN));
  1332. msfChk(SetNext(sectData - 1, 0));
  1333. }
  1334. else
  1335. {
  1336. //In the event that the file to be converted is less
  1337. // than one sector long, we don't need to create a
  1338. // real chain, just a single terminated sector.
  1339. msfChk(SetNext(0, ENDOFCHAIN));
  1340. }
  1341. for (sect = sectData; sect < sectMax; sect++)
  1342. {
  1343. msfChk(SetNext(sect, DIFSECT));
  1344. }
  1345. for (USHORT i2 = 0; i2 < csectFat; i2++)
  1346. {
  1347. msfChk(SetNext(sectMax + i2, FATSECT));
  1348. }
  1349. //Set up directory chain.
  1350. msfChk(SetNext(sectMax + i, ENDOFCHAIN));
  1351. pmsParent->GetHeader()->SetDirStart(sectMax + i);
  1352. _ulFreeSects = (_cfsTable << _uFatShift) - (sectMax + csectFat + 1);
  1353. }
  1354. else
  1355. {
  1356. for (SECT sect = 0; sect < sectData -1; sect++)
  1357. {
  1358. msfChk(SetNext(sect, sect + 1));
  1359. }
  1360. msfChk(SetNext(sectData - 1, ENDOFCHAIN));
  1361. _ulFreeSects = (_cfsTable << _uFatShift) - sectData;
  1362. }
  1363. if (!pmsParent->IsScratch())
  1364. {
  1365. msfChk(pmsParent->SetSize());
  1366. }
  1367. Err:
  1368. return sc;
  1369. }
  1370. //+-------------------------------------------------------------------------
  1371. //
  1372. // Member: CFat::InitNew, public
  1373. //
  1374. // Synposis: Sets up a FAT for a newly created multi-strean
  1375. //
  1376. // Effects: Changes all _apfsTable entries, _cfsTable, and all
  1377. // flags fields
  1378. //
  1379. // Arguments: [pmsparent] -- pointer to parent Mstream
  1380. //
  1381. // Returns: S_OK if call completed OK.
  1382. //
  1383. // Algorithm: Set parent pointer.
  1384. // Allocate 1 sector for FAT and 1 for Directory.
  1385. //
  1386. // History: 18-Jul-91 PhilipLa Created.
  1387. // 17-Aug-91 PhilipLa Added dirty bits optimization (Dump)
  1388. //
  1389. // Notes:
  1390. //
  1391. //---------------------------------------------------------------------------
  1392. SCODE CFat::InitNew(CMStream *pmsParent)
  1393. {
  1394. msfDebugOut((DEB_FAT,"In CFat::InitNew()\n"));
  1395. SCODE sc;
  1396. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  1397. _uFatShift = pmsParent->GetSectorShift() - 2;
  1398. _uFatMask = (pmsParent->GetSectorSize() >> 2) - 1;
  1399. _fv.InitCommon(1 << _uFatShift, 1 << _uFatShift);
  1400. FSINDEX count;
  1401. if (SIDMINIFAT == _sid)
  1402. count = pmsParent->GetHeader()->GetMiniFatLength();
  1403. else
  1404. count = pmsParent->GetHeader()->GetFatLength();
  1405. msfDebugOut((DEB_FAT,"Setting up Fat of size %lu\n",count));
  1406. msfChk(_fv.Init(pmsParent, count));
  1407. _cfsTable = count;
  1408. InitRangeLocksSector();
  1409. if (SIDFAT == _sid)
  1410. {
  1411. FSINDEX ipfs;
  1412. FSOFFSET isect;
  1413. CFatSect *pfs;
  1414. SectToPair(pmsParent->GetHeader()->GetFatStart(), &ipfs, &isect);
  1415. msfChk(_fv.GetTable(ipfs, FB_NEW, &pfs));
  1416. _fv.SetSect(ipfs, pmsParent->GetHeader()->GetFatStart());
  1417. _fv.ReleaseTable(ipfs);
  1418. msfChk(SetNext(pmsParent->GetHeader()->GetFatStart(), FATSECT));
  1419. msfDebugOut((DEB_ITRACE,"Set sector %lu (FAT) to ENDOFCHAIN\n",pmsParent->GetHeader()->GetFatStart()));
  1420. msfChk(SetNext(pmsParent->GetHeader()->GetDirStart(), ENDOFCHAIN));
  1421. msfDebugOut((DEB_ITRACE,"Set sector %lu (DIR) to ENDOFCHAIN\n",pmsParent->GetHeader()->GetDirStart()));
  1422. _ulFreeSects = (count << _uFatShift) - 2;
  1423. }
  1424. else
  1425. {
  1426. _ulFreeSects = 0;
  1427. }
  1428. if (!pmsParent->IsScratch())
  1429. {
  1430. msfChk(pmsParent->SetSize());
  1431. }
  1432. msfDebugOut((DEB_FAT,"Exiting CFat::setupnew()\n"));
  1433. Err:
  1434. return sc;
  1435. }
  1436. //+-------------------------------------------------------------------------
  1437. //
  1438. // Member: CFat::Resize, private
  1439. //
  1440. // Synposis: Resize FAT, both in memory and in the file
  1441. //
  1442. // Effects: Modifies _cfsTable, _apfsTable, and all flags fields
  1443. //
  1444. // Arguments: [ulSize] -- New size (in # of tables) for FAT
  1445. //
  1446. // Returns: S_OK if call completed OK.
  1447. //
  1448. // Algorithm: Allocate new array of new size.
  1449. // Copy over all old pointers.
  1450. // Allocate new tables for any necessary.
  1451. //
  1452. // History: 18-Jul-91 PhilipLa Created.
  1453. // 18-Aug-91 PhilipLa Added dirty bits optimization
  1454. //
  1455. // Notes: This routine currently cannot reduce the size of a fat.
  1456. //
  1457. //---------------------------------------------------------------------------
  1458. SCODE CFat::Resize(ULONG ulSize)
  1459. {
  1460. msfDebugOut((DEB_FAT,"In CFat::Resize(%lu)\n",ulSize));
  1461. SCODE sc = S_OK;
  1462. if (ulSize == _cfsTable)
  1463. {
  1464. return S_OK;
  1465. }
  1466. ULONG csect = _cfsTable;
  1467. msfAssert(ulSize > _cfsTable &&
  1468. aMsg("Attempted to shrink Fat"));
  1469. // 512byte sector docfiles are restricted to 2G for now
  1470. if (_pmsParent->GetSectorShift() == SECTORSHIFT512 &&
  1471. ulSize > _ipfsRangeLocks)
  1472. return STG_E_DOCFILETOOLARGE;
  1473. ULONG ipfs;
  1474. SECT sectNew = 0;
  1475. CFat *pfat = _pmsParent->GetFat();
  1476. if ((!_pmsParent->IsScratch()) && (_sid == SIDFAT))
  1477. {
  1478. //Make sure we have enough space for all of the sectors
  1479. // to be allocated.
  1480. ULONG csectFat = ulSize - _cfsTable;
  1481. ULONG csectPerDif = (1 << _uFatShift) - 1;
  1482. ULONG csectDif = (csectFat + csectPerDif - 1) / csectPerDif;
  1483. //Assuming all the free sectors are at the end of the file,
  1484. // we need a file csectNew sectors long to hold them.
  1485. ULONG csectOld, csectNew;
  1486. msfChk(FindMaxSect(&csectOld));
  1487. // Every new sector added can conceivably cause a remap of
  1488. // another sector while in COW mode.
  1489. csectNew = csectOld +
  1490. ((csectFat + csectDif) * ((_sectLastUsed > 0) ? 2 : 1));
  1491. ULARGE_INTEGER cbSize;
  1492. #ifdef LARGE_DOCFILE
  1493. cbSize.QuadPart = ConvertSectOffset(
  1494. csectNew,
  1495. 0,
  1496. _pmsParent->GetSectorShift());
  1497. #else
  1498. ULISet32(cbSize, ConvertSectOffset(
  1499. csectNew,
  1500. 0,
  1501. _pmsParent->GetSectorShift()));
  1502. #endif
  1503. #ifdef LARGE_DOCFILE
  1504. if (cbSize.QuadPart > _pmsParent->GetParentSize())
  1505. #else
  1506. if (ULIGetLow(cbSize) > _pmsParent->GetParentSize())
  1507. #endif
  1508. {
  1509. msfHChk(_pmsParent->GetILB()->SetSize(cbSize));
  1510. }
  1511. //If we are the fat, we have enough space in the file for
  1512. // ourselves at this point.
  1513. }
  1514. else if (_sid != SIDFAT)
  1515. {
  1516. if (_cfsTable == 0)
  1517. {
  1518. msfChk(pfat->Allocate(ulSize, &sectNew));
  1519. _pmsParent->GetHeader()->SetMiniFatStart(sectNew);
  1520. }
  1521. else
  1522. {
  1523. sectNew = _pmsParent->GetHeader()->GetMiniFatStart();
  1524. SECT sectLast;
  1525. msfChk(pfat->GetESect(sectNew, ulSize - 1, &sectLast));
  1526. }
  1527. if (!_pmsParent->IsScratch())
  1528. {
  1529. msfChk(_pmsParent->SetSize());
  1530. }
  1531. msfChk(pfat->GetSect(sectNew, csect, &sectNew));
  1532. //If we are the Minifat, we have enough space in the underlying
  1533. // file for ourselves at this point.
  1534. }
  1535. _fv.Resize(ulSize);
  1536. for (ipfs = csect; ipfs < ulSize; ipfs++)
  1537. {
  1538. CFatSect *pfs;
  1539. msfChk(_fv.GetTable(ipfs, FB_NEW, &pfs));
  1540. _cfsTable = ipfs + 1;
  1541. if (_sid == SIDFAT)
  1542. {
  1543. if (ipfs == _ipfsRangeLocks)
  1544. {
  1545. CVectBits *pfb;
  1546. pfs->SetSect(_isectRangeLocks, ENDOFCHAIN);
  1547. pfb = _fv.GetBits(_ipfsRangeLocks);
  1548. if (pfb != NULL && pfb->full == FALSE &&
  1549. _isectRangeLocks == pfb->firstfree)
  1550. {
  1551. pfb->firstfree = _isectRangeLocks + 1;
  1552. }
  1553. _ulFreeSects--;
  1554. }
  1555. if (_sectNoSnapshotFree != ENDOFCHAIN)
  1556. {
  1557. SECT sectStart, sectEnd;
  1558. _pmsParent->GetHeader()->SetFatLength(_cfsTable);
  1559. msfChk(GetFree(1, &sectNew, GF_READONLY));
  1560. _pmsParent->GetDIFat()->CacheUnmarkedSect(sectNew,
  1561. FATSECT,
  1562. ENDOFCHAIN);
  1563. msfChk(_pmsParent->GetDIFat()->SetFatSect(ipfs, sectNew));
  1564. msfAssert((_ulFreeSects != MAX_ULONG) &&
  1565. aMsg("Free count not set in no-snapshot"));
  1566. //We don't need to look at anything less than
  1567. //_sectNoSnapshotFree, since those are all by definition
  1568. //not free.
  1569. sectStart = max(PairToSect(ipfs, 0), _sectNoSnapshotFree);
  1570. sectEnd = PairToSect(ipfs, 0) + _fv.GetSectTable();
  1571. for (SECT sectChk = sectStart;
  1572. sectChk < sectEnd;
  1573. sectChk++)
  1574. {
  1575. if (IsFree(sectChk) == S_OK)
  1576. {
  1577. _ulFreeSects++;
  1578. }
  1579. }
  1580. CheckFreeCount();
  1581. }
  1582. else
  1583. {
  1584. if (_pfatNoScratch != NULL)
  1585. {
  1586. SECT sectStart, sectEnd;
  1587. msfChk(GetFree(1, &sectNew, GF_READONLY));
  1588. _pmsParent->GetDIFat()->CacheUnmarkedSect(sectNew,
  1589. FATSECT,
  1590. ENDOFCHAIN);
  1591. if (_ulFreeSects != MAX_ULONG)
  1592. {
  1593. sectStart = PairToSect(ipfs, 0);
  1594. sectEnd = sectStart + _fv.GetSectTable();
  1595. for (SECT sectChk = sectStart;
  1596. sectChk < sectEnd;
  1597. sectChk++)
  1598. {
  1599. if (IsFree(sectChk) == S_OK)
  1600. {
  1601. _ulFreeSects++;
  1602. }
  1603. }
  1604. CheckFreeCount();
  1605. }
  1606. }
  1607. else
  1608. {
  1609. _ulFreeSects += (1 << _uFatShift);
  1610. msfChk(pfat->GetFree(1, &sectNew, GF_WRITE));
  1611. msfChk(pfat->SetNext(sectNew, FATSECT));
  1612. }
  1613. msfChk(_pmsParent->GetDIFat()->SetFatSect(ipfs, sectNew));
  1614. }
  1615. }
  1616. msfAssert(sectNew != ENDOFCHAIN &&
  1617. aMsg("Bad sector returned for fatsect."));
  1618. _fv.SetSect(ipfs, sectNew);
  1619. _fv.ReleaseTable(ipfs);
  1620. if (_sid == SIDMINIFAT)
  1621. {
  1622. _ulFreeSects += (1 << _uFatShift);
  1623. msfChk(pfat->GetNext(sectNew, &sectNew));
  1624. }
  1625. }
  1626. CheckFreeCount();
  1627. msfDebugOut((DEB_FAT,"CFat::Resize() - all new objects allocated\n"));
  1628. if (SIDMINIFAT == _sid)
  1629. {
  1630. _pmsParent->GetHeader()->SetMiniFatLength(_cfsTable);
  1631. }
  1632. else
  1633. _pmsParent->GetHeader()->SetFatLength(_cfsTable);
  1634. //This setsize should only shrink the file.
  1635. #if DBG == 1
  1636. STATSTG stat;
  1637. msfHChk(_pmsParent->GetILB()->Stat(&stat, STATFLAG_NONAME));
  1638. #endif
  1639. if (!_pmsParent->IsScratch())
  1640. {
  1641. msfChk(_pmsParent->SetSize());
  1642. }
  1643. if ((_pfatNoScratch != NULL) && (_ulFreeSects == MAX_ULONG))
  1644. {
  1645. msfChk(CountFree(&_ulFreeSects));
  1646. }
  1647. #if DBG == 1
  1648. STATSTG statNew;
  1649. msfHChk(_pmsParent->GetILB()->Stat(&statNew, STATFLAG_NONAME));
  1650. #ifdef LARGE_DOCFILE
  1651. if (ulSize < _ipfsRangeLocks && !(_pmsParent->IsInCOW()))
  1652. msfAssert(statNew.cbSize.QuadPart <= stat.cbSize.QuadPart);
  1653. #else
  1654. if (!(_pmsParent->IsInCOW())
  1655. msfAssert(ULIGetLow(statNew.cbSize) <= ULIGetLow(stat.cbSize));
  1656. #endif
  1657. #endif
  1658. msfDebugOut((DEB_FAT,"Out CFat::Resize(%lu)\n",ulSize));
  1659. Err:
  1660. msfAssert((_ulFreeSects != MAX_ULONG) &&
  1661. aMsg("Free sect count not set after Resize()."));
  1662. return sc;
  1663. }
  1664. //+-------------------------------------------------------------------------
  1665. //
  1666. // Member: CFat::Extend, private
  1667. //
  1668. // Synposis: Increase the size of an existing chain
  1669. //
  1670. // Effects: Modifies ulSize sectors within the fat. Causes one or
  1671. // more sector writes.
  1672. //
  1673. // Arguments: [sect] -- Sector ID of last sector in chain to be extended
  1674. // [ulSize] -- Number of sectors to add to chain
  1675. //
  1676. // Requires: sect must be at the end of a chain.
  1677. //
  1678. // Returns: S_OK if call completed OK.
  1679. //
  1680. // Algorithm: Use calls to GetFree to allocate chain.
  1681. //
  1682. // History: 18-Jul-91 PhilipLa Created.
  1683. // 17-Aug-91 PhilipLa Added dirty bits opt (Dump)
  1684. //
  1685. // Notes:
  1686. //
  1687. //---------------------------------------------------------------------------
  1688. SCODE CFat::Extend(SECT sect, ULONG ulSize)
  1689. {
  1690. SCODE sc;
  1691. msfDebugOut((DEB_FAT,"In CFat::Extend(%lu,%lu)\n",sect,ulSize));
  1692. SECT sectTemp;
  1693. msfChk(GetFree(ulSize, &sectTemp, GF_WRITE));
  1694. //If this SetSize fails, clean up the new space and don't do anything
  1695. // to the original chain.
  1696. if (!_pmsParent->IsScratch())
  1697. {
  1698. msfChkTo(EH_OOD, _pmsParent->SetSize());
  1699. }
  1700. //If this SetNext fail calls, we're in trouble. Return the error but
  1701. // don't attempt to cleanup.
  1702. msfChk(SetNext(sect, sectTemp));
  1703. msfDebugOut((DEB_FAT,"Out CFat::Extend()\n"));
  1704. Err:
  1705. return sc;
  1706. EH_OOD:
  1707. SetChainLength(sectTemp, 0);
  1708. return sc;
  1709. }
  1710. //+-------------------------------------------------------------------------
  1711. //
  1712. // Member: CFat::GetNext, public
  1713. //
  1714. // Synposis: Returns the next sector in a chain, given a sector
  1715. //
  1716. // Arguments: [sect] -- Sector ID of any sector in a chain.
  1717. //
  1718. // Returns: Sector ID of next sector in chain, ENDOFCHAIN if at end
  1719. //
  1720. // History: 18-Jul-91 PhilipLa Created.
  1721. //
  1722. // Notes:
  1723. //
  1724. //---------------------------------------------------------------------------
  1725. SCODE CFat::GetNext(const SECT sect, SECT * psRet)
  1726. {
  1727. SCODE sc;
  1728. FSINDEX ipfs;
  1729. FSOFFSET isect;
  1730. msfAssert(sect <= MAXREGSECT &&
  1731. aMsg("Called GetNext() on invalid sector"));
  1732. SectToPair(sect, &ipfs, &isect);
  1733. CFatSect *pfs;
  1734. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  1735. *psRet = pfs->GetSect(isect);
  1736. _fv.ReleaseTable(ipfs);
  1737. if (sect == *psRet)
  1738. {
  1739. msfAssert(sect != *psRet &&
  1740. aMsg("Detected loop in fat chain."));
  1741. return STG_E_ABNORMALAPIEXIT;
  1742. }
  1743. return S_OK;
  1744. Err:
  1745. return sc;
  1746. }
  1747. //+-------------------------------------------------------------------------
  1748. //
  1749. // Member: CFat::SetNext, private
  1750. //
  1751. // Synposis: Set the next sector in a chain
  1752. //
  1753. // Effects: Modifies a single entry within the fat.
  1754. //
  1755. // Arguments: [sectFirst] -- Sector ID of first sector
  1756. // [sectNext] -- Sector ID of next sector
  1757. //
  1758. // Returns: void
  1759. //
  1760. // History: 18-Jul-91 PhilipLa Created.
  1761. // 17-Aug-91 PhilipLa Added dirty bits optimization
  1762. //
  1763. // Notes:
  1764. //
  1765. //---------------------------------------------------------------------------
  1766. SCODE CFat::SetNext(SECT sectFirst, SECT sectNext)
  1767. {
  1768. FSINDEX ipfs;
  1769. FSOFFSET isect;
  1770. SCODE sc;
  1771. msfAssert((!_pmsParent->IsShadow()) &&
  1772. aMsg("Modifying shadow fat."));
  1773. // creating infinite loops is a no-no
  1774. msfAssert(sectFirst != sectNext &&
  1775. aMsg("Attempted to create loop in Fat chain"));
  1776. msfAssert(sectFirst <= MAXREGSECT &&
  1777. aMsg("Called SetNext on invalid sector"));
  1778. SectToPair(sectFirst, &ipfs, &isect);
  1779. CFatSect *pfs;
  1780. SECT sectCurrent;
  1781. if (ipfs >= _cfsTable)
  1782. {
  1783. msfChk(Resize(ipfs + 1));
  1784. }
  1785. msfAssert(ipfs <= _cfsTable);
  1786. msfChk(_fv.GetTable(ipfs, FB_DIRTY, &pfs));
  1787. sectCurrent = pfs->GetSect(isect);
  1788. pfs->SetSect(isect,sectNext);
  1789. _fv.ReleaseTable(ipfs);
  1790. if (sectNext == FREESECT)
  1791. {
  1792. CVectBits *pfb;
  1793. pfb = _fv.GetBits(ipfs);
  1794. if ((pfb != NULL) &&
  1795. ((pfb->full == TRUE) || (isect < pfb->firstfree)))
  1796. {
  1797. pfb->full = FALSE;
  1798. pfb->firstfree = isect;
  1799. }
  1800. if (sectFirst == _sectMax - 1)
  1801. {
  1802. _sectMax = ENDOFCHAIN;
  1803. }
  1804. if (sectFirst < _sectFirstFree)
  1805. {
  1806. _sectFirstFree = sectFirst;
  1807. }
  1808. if (_ulFreeSects != MAX_ULONG)
  1809. {
  1810. SECT sectOld = FREESECT;
  1811. msfChk(IsFree(sectFirst));
  1812. if (sc != S_FALSE)
  1813. {
  1814. _ulFreeSects++;
  1815. }
  1816. sc = S_OK; // Don't return S_FALSE.
  1817. }
  1818. }
  1819. else if (_pfatNoScratch != NULL)
  1820. {
  1821. //We need to update the noscratch fat as well.
  1822. msfChk(_pfatNoScratch->SetNext(sectFirst, sectNext));
  1823. }
  1824. else if (sectFirst >= _sectMax)
  1825. {
  1826. _sectMax = sectFirst + 1;
  1827. #if DBG == 1
  1828. SECT sectLast;
  1829. msfChk(FindLast(&sectLast));
  1830. msfAssert(((_sectMax == sectLast) || (_sectMax == _sectLastUsed)) &&
  1831. aMsg("_sectMax doesn't match actual last sector"));
  1832. #endif
  1833. }
  1834. //If we're the no-scratch fat, then we may be marking a free sector
  1835. //as allocated due to the real fat allocating it. In this case, we
  1836. //need to update our free sector count.
  1837. if ((_sid == SIDMINIFAT) && (_pmsParent->IsScratch()) &&
  1838. (sectCurrent == FREESECT) && (sectNext != FREESECT) &&
  1839. (_ulFreeSects != MAX_ULONG))
  1840. {
  1841. _ulFreeSects--;
  1842. }
  1843. Err:
  1844. return sc;
  1845. }
  1846. //+-------------------------------------------------------------------------
  1847. //
  1848. // Member: CFat::CountFree, private
  1849. //
  1850. // Synposis: Count and return the number of free sectors in the Fat
  1851. //
  1852. // Arguments: void.
  1853. //
  1854. // Returns: void.
  1855. //
  1856. // Algorithm: Do a linear search of the Fat, counting free sectors.
  1857. // If a FatSect has its full bit set, it is not necessary
  1858. // to search that FatSect.
  1859. //
  1860. // History: 11-Sep-91 PhilipLa Created.
  1861. //
  1862. // Notes: This includes all the FREESECT's in the tail of the last FAT
  1863. // block (past the last allocated sector) as free. So it is possible
  1864. // That CountFree() could be greater than FindLast()!
  1865. //---------------------------------------------------------------------------
  1866. SCODE CFat::CountFree(ULONG * pulRet)
  1867. {
  1868. msfDebugOut((DEB_FAT,"In CFat::CountFree()\n"));
  1869. SCODE sc = S_OK;
  1870. FSINDEX ipfs;
  1871. ULONG csectFree=0;
  1872. FSOFFSET isectStart;
  1873. FSINDEX ipfsStart;
  1874. SectToPair(_sectFirstFree, &ipfsStart, &isectStart);
  1875. for (ipfs = ipfsStart; ipfs < _cfsTable; ipfs++)
  1876. {
  1877. CVectBits *pfb = _fv.GetBits(ipfs);
  1878. if ((pfb == NULL) || (!pfb->full))
  1879. {
  1880. msfDebugOut((DEB_FAT,"Checking table %lu\n",ipfs));
  1881. CFatSect *pfs;
  1882. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  1883. if (pfb != NULL)
  1884. {
  1885. isectStart = pfb->firstfree;
  1886. }
  1887. FSOFFSET isect;
  1888. for (isect = isectStart; isect < _fv.GetSectTable(); isect++)
  1889. {
  1890. SECT sectCurrent = pfs->GetSect(isect);
  1891. SECT sectNew = PairToSect(ipfs, isect);
  1892. if (sectCurrent == FREESECT)
  1893. {
  1894. msfChkTo(Err_Rel, IsFree(sectNew));
  1895. if (sc == S_FALSE)
  1896. {
  1897. sectCurrent = ENDOFCHAIN;
  1898. }
  1899. }
  1900. if (sectCurrent == FREESECT)
  1901. {
  1902. csectFree++;
  1903. }
  1904. }
  1905. _fv.ReleaseTable(ipfs);
  1906. }
  1907. isectStart = 0;
  1908. }
  1909. msfDebugOut((DEB_FAT,"Countfree returned %lu\n",csectFree));
  1910. *pulRet = csectFree;
  1911. Err:
  1912. return sc;
  1913. Err_Rel:
  1914. _fv.ReleaseTable(ipfs);
  1915. return sc;
  1916. }
  1917. //+-------------------------------------------------------------------------
  1918. //
  1919. // Member: CFat::CountSectType, private
  1920. //
  1921. // Synposis: Count and return the number of sectors of a given
  1922. // type in the Fat
  1923. //
  1924. // Arguments: [out] count The returned count of sectors.
  1925. // [in] sectStart The first sector of the range to examine.
  1926. // [in] sectEnd The last sector of the range to examine.
  1927. // [in] sectType The type of sector looked for.
  1928. //
  1929. // Returns: SCODE.
  1930. //
  1931. // Algorithm: Do a linear search of the Fat, counting sectors of the given
  1932. // type in the given range.
  1933. //
  1934. // History: 18-Feb-97 BChapman Created.
  1935. //
  1936. // Notes:
  1937. //
  1938. //---------------------------------------------------------------------------
  1939. SCODE CFat::CountSectType(
  1940. ULONG * pulRet,
  1941. SECT sectStart,
  1942. SECT sectEnd,
  1943. SECT sectType)
  1944. {
  1945. msfDebugOut((DEB_FAT,"In CFat::CountSect(0x%x, 0x%x, 0x%x)\n",
  1946. sectStart, sectEnd, sectType));
  1947. SCODE sc = S_OK;
  1948. FSINDEX ipfs;
  1949. ULONG csectType=0;
  1950. FSOFFSET isectStart; // starting index into the current FAT
  1951. FSOFFSET isectEnd; // ending index into the current FAT
  1952. FSOFFSET isectFirstStart; // starting index into the first FAT
  1953. FSOFFSET isectLastEnd; // ending index into the last FAT
  1954. FSINDEX ipfsStart; // Starting FAT block number
  1955. FSINDEX ipfsEnd; // Ending FAT block number
  1956. SectToPair(sectStart, &ipfsStart, &isectFirstStart);
  1957. SectToPair(sectEnd, &ipfsEnd, &isectLastEnd);
  1958. for (ipfs = ipfsStart; ipfs <= ipfsEnd; ipfs++)
  1959. {
  1960. //
  1961. // If we are counting FREESECTS and this FAT blocks is
  1962. // known to be full then just skip it.
  1963. //
  1964. if(FREESECT == sectType)
  1965. {
  1966. CVectBits *pfb = _fv.GetBits(ipfs);
  1967. if ((pfb != NULL) && pfb->full)
  1968. continue;
  1969. }
  1970. msfDebugOut((DEB_FAT,"Checking table %lu\n",ipfs));
  1971. CFatSect *pfs;
  1972. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  1973. //
  1974. // If this is the first FAT block in the given range use the given
  1975. // starting offset-index. Otherwise start at the beginning.
  1976. //
  1977. if(ipfs == ipfsStart)
  1978. isectStart = isectFirstStart;
  1979. else
  1980. isectStart = 0;
  1981. //
  1982. // If this is the last FAT block in the given range use the given
  1983. // ending fooset-index, otherwise scan to the end of the block.
  1984. //
  1985. if(ipfs == ipfsEnd)
  1986. isectEnd = isectLastEnd;
  1987. else
  1988. isectEnd = _fv.GetSectTable();
  1989. FSOFFSET isect;
  1990. for (isect = isectStart; isect < isectEnd; isect++)
  1991. {
  1992. SECT sectCurrent = pfs->GetSect(isect);
  1993. SECT sectNew = PairToSect(ipfs, isect);
  1994. if (sectCurrent == sectType)
  1995. {
  1996. msfChkTo(Err_Rel, IsSectType(sectNew, sectType));
  1997. if (sc != S_FALSE)
  1998. {
  1999. csectType++;
  2000. }
  2001. }
  2002. }
  2003. _fv.ReleaseTable(ipfs);
  2004. isectStart = 0;
  2005. }
  2006. msfDebugOut((DEB_FAT,"CountSectType returned %lu\n",csectType));
  2007. *pulRet = csectType;
  2008. Err:
  2009. return sc;
  2010. Err_Rel:
  2011. _fv.ReleaseTable(ipfs);
  2012. return sc;
  2013. }
  2014. //+-------------------------------------------------------------------------
  2015. //
  2016. // Member: CFat::GetSect, public
  2017. //
  2018. // Synposis: Return the nth sector in a chain
  2019. //
  2020. // Arguments: [sect] -- Sector ID of beginning of chain
  2021. // [uNum] -- indicator of which sector is to be returned
  2022. // [psectReturn] -- Pointer to storage for return value
  2023. //
  2024. // Returns: S_OK.
  2025. //
  2026. // Algorithm: Linearly traverse chain until numth sector
  2027. //
  2028. // History: 18-Jul-91 PhilipLa Created.
  2029. //
  2030. // Notes:
  2031. //
  2032. //---------------------------------------------------------------------------
  2033. SCODE CFat::GetSect(SECT sect, ULONG ulNum, SECT * psectReturn)
  2034. {
  2035. msfDebugOut((DEB_FAT,"In CFat::GetSect(%lu,%lu)\n",sect,ulNum));
  2036. SCODE sc = S_OK;
  2037. if (ulNum == 0)
  2038. {
  2039. msfDebugOut((DEB_FAT,"Out CFat::GetSect()=>%lu\n",sect));
  2040. }
  2041. else if ((SIDFAT == _sid) &&
  2042. (_pmsParent->GetHeader()->GetFatStart() == sect))
  2043. {
  2044. msfChk(_pmsParent->GetDIFat()->GetFatSect(ulNum, &sect));
  2045. }
  2046. else for (ULONG i = 0; i < ulNum; i++)
  2047. {
  2048. msfChk(GetNext(sect, &sect));
  2049. if (sect > MAXREGSECT)
  2050. {
  2051. //The stream isn't long enough, so stop.
  2052. msfAssert(sect == ENDOFCHAIN &&
  2053. aMsg("Found invalid sector in fat chain."));
  2054. break;
  2055. }
  2056. }
  2057. *psectReturn = sect;
  2058. msfDebugOut((DEB_FAT,"Out CFat::GetSect()=>%lu\n",sect));
  2059. Err:
  2060. return sc;
  2061. }
  2062. //+-------------------------------------------------------------------------
  2063. //
  2064. // Member: CFat::GetESect
  2065. //
  2066. // Synposis: Return the nth sector in a chain, extending the chain
  2067. // if necessary.
  2068. //
  2069. // Effects: Modifies fat (via Extend) if necessary
  2070. //
  2071. // Arguments: [sect] -- Sector ID of beginning of chain
  2072. // [ulNum] -- Indicates which sector is to be returned
  2073. // [psectReturn] -- Pointer to storage for return value
  2074. //
  2075. // Returns: S_OK if call completed OK.
  2076. //
  2077. // Algorithm: Linearly search chain until numth sector is found. If
  2078. // the chain terminates early, extend it as necessary.
  2079. //
  2080. // History: 18-Jul-91 PhilipLa Created.
  2081. //
  2082. // Notes:
  2083. //
  2084. //---------------------------------------------------------------------------
  2085. SCODE CFat::GetESect(SECT sect, ULONG ulNum, SECT *psectReturn)
  2086. {
  2087. msfDebugOut((DEB_FAT,"In CFat::GetESect(%lu,%lu)\n",sect,ulNum));
  2088. SCODE sc = S_OK;
  2089. ULONG i = 0;
  2090. while (i < ulNum)
  2091. {
  2092. SECT temp;
  2093. msfChk(GetNext(sect, &temp));
  2094. msfAssert(temp != FREESECT &&
  2095. aMsg("FREESECT found in chain."));
  2096. if (temp == ENDOFCHAIN)
  2097. {
  2098. //The stream isn't long enough, so extend it somehow.
  2099. ULONG need = ulNum - i;
  2100. msfAssert((SIDMINIFAT == _sid ||
  2101. sect != _pmsParent->GetHeader()->GetFatStart()) &&
  2102. aMsg("Called GetESect on Fat chain"));
  2103. msfChk(Extend(sect,need));
  2104. }
  2105. else
  2106. {
  2107. sect = temp;
  2108. i++;
  2109. }
  2110. }
  2111. msfDebugOut((DEB_FAT,"Exiting GetESect with result %lu\n",sect));
  2112. *psectReturn = sect;
  2113. Err:
  2114. return sc;
  2115. }
  2116. #if DBG == 1
  2117. //+-------------------------------------------------------------------------
  2118. //
  2119. // Member: CFat::checksanity, private
  2120. //
  2121. // Synposis: Print out a FAT chain. Used for debugging only.
  2122. //
  2123. // Arguments: [sectStart] -- sector to begin run at.
  2124. //
  2125. // Returns: void
  2126. //
  2127. // History: 18-Jul-91 PhilipLa Created.
  2128. //
  2129. // Notes:
  2130. //
  2131. //---------------------------------------------------------------------------
  2132. SCODE CFat::checksanity(SECT sectStart)
  2133. {
  2134. msfDebugOut((DEB_FAT,"Sanity Check (%i)\n\t",sectStart));
  2135. SCODE sc = S_OK;
  2136. while (sectStart != ENDOFCHAIN)
  2137. {
  2138. msfDebugOut((DEB_FAT | DEB_NOCOMPNAME,"%lu, ",sectStart));
  2139. msfChk(GetNext(sectStart, &sectStart));
  2140. }
  2141. msfDebugOut((DEB_FAT | DEB_NOCOMPNAME,"ENDOFCHAIN\n"));
  2142. Err:
  2143. return sc;
  2144. }
  2145. #endif
  2146. //+-------------------------------------------------------------------------
  2147. //
  2148. // Member: CFat::SetChainLength, private
  2149. //
  2150. // Synposis: Set the length of a fat chain. This is used to reduce
  2151. // the length of the chain only. To extend a chain, use
  2152. // Extend or GetESect
  2153. //
  2154. // Effects: Modifies the fat
  2155. //
  2156. // Arguments: [sectStart] -- Sector to begin at (head of chain)
  2157. // [uLength] -- New length for chain
  2158. //
  2159. // Returns: void.
  2160. //
  2161. // Algorithm: Traverse chain until uLength is reached or the chain
  2162. // terminates. If it terminates prematurely, return with
  2163. // no other action. Otherwise, deallocate all remaining
  2164. // sectors in the chain.
  2165. //
  2166. // History: 14-Aug-91 PhilipLa Created.
  2167. //
  2168. // Notes:
  2169. //
  2170. //---------------------------------------------------------------------------
  2171. SCODE CFat::SetChainLength(SECT sectStart, ULONG ulLength)
  2172. {
  2173. msfDebugOut((DEB_FAT,"In CFat::SetChainLength(%lu,%lu)\n",sectStart,ulLength));
  2174. SCODE sc;
  2175. if (sectStart == ENDOFCHAIN) return S_OK;
  2176. for (ULONG ui = 1; ui < ulLength; ui++)
  2177. {
  2178. msfChk(GetNext(sectStart, &sectStart));
  2179. if (sectStart == ENDOFCHAIN) return S_OK;
  2180. }
  2181. msfAssert(sectStart != ENDOFCHAIN &&
  2182. aMsg("Called SetChainLength is ENDOFCHAIN start"));
  2183. SECT sectEnd;
  2184. sectEnd = sectStart;
  2185. msfChk(GetNext(sectStart, &sectStart));
  2186. if (ulLength != 0)
  2187. {
  2188. msfChk(SetNext(sectEnd, ENDOFCHAIN));
  2189. }
  2190. else
  2191. {
  2192. msfChk(SetNext(sectEnd, FREESECT));
  2193. }
  2194. while (sectStart != ENDOFCHAIN)
  2195. {
  2196. SECT sectTemp;
  2197. msfChk(GetNext(sectStart, &sectTemp));
  2198. msfChk(SetNext(sectStart, FREESECT));
  2199. sectStart = sectTemp;
  2200. }
  2201. msfDebugOut((DEB_FAT,"Out CFat::SetChainLength()\n"));
  2202. Err:
  2203. return sc;
  2204. }
  2205. //+-------------------------------------------------------------------------
  2206. //
  2207. // Method: CFat::DirtyAll, public
  2208. //
  2209. // Synopsis: Dirty every sector in the FAT. This had the effect in
  2210. // consolidation of copying the whole FAT down lower in the
  2211. // file.
  2212. //
  2213. // Returns: SCODE success or failure code.
  2214. //
  2215. // Algorithm: Load each FAT sector into the cache "for-writing".
  2216. //
  2217. // History: 24-Feb-1997 BChapman Created.
  2218. //
  2219. // Notes: For use
  2220. //
  2221. //--------------------------------------------------------------------------
  2222. SCODE CFat::DirtyAll()
  2223. {
  2224. SCODE sc = S_OK;
  2225. CFatSect *pfs;
  2226. FSINDEX i;
  2227. for(i=0; i<_cfsTable; i++)
  2228. {
  2229. msfChk(_fv.GetTable(i, FB_DIRTY, &pfs));
  2230. _fv.ReleaseTable(i);
  2231. }
  2232. Err:
  2233. return sc;
  2234. }
  2235. //+-------------------------------------------------------------------------
  2236. //
  2237. // Method: CFat::FindLast, private
  2238. //
  2239. // Synopsis: Find last used sector in a fat
  2240. //
  2241. // Returns: Location of last used sector
  2242. //
  2243. // Algorithm: Perform a backward linear search until a non-free
  2244. // sector is found.
  2245. //
  2246. // History: 18-Dec-91 PhilipLa Created.
  2247. //
  2248. // Notes: Used for shadow fats only.
  2249. //
  2250. //--------------------------------------------------------------------------
  2251. SCODE CFat::FindLast(SECT * psectRet)
  2252. {
  2253. SCODE sc = S_OK;
  2254. FSINDEX ipfs = _cfsTable;
  2255. SECT sect = 0;
  2256. while (ipfs > 0)
  2257. {
  2258. ipfs--;
  2259. FSOFFSET isect = _fv.GetSectTable();
  2260. CFatSect *pfs;
  2261. msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
  2262. while (isect > 0)
  2263. {
  2264. isect--;
  2265. SECT sectCurrent = pfs->GetSect(isect);
  2266. SECT sectNew = PairToSect(ipfs, isect);
  2267. if (sectCurrent == FREESECT)
  2268. {
  2269. msfChkTo(Err_Rel, IsFree(sectNew));
  2270. if (sc == S_FALSE)
  2271. sectCurrent = ENDOFCHAIN;
  2272. }
  2273. if (ipfs == _ipfsRangeLocks && isect == _isectRangeLocks)
  2274. sectCurrent = FREESECT;
  2275. if (sectCurrent != FREESECT)
  2276. {
  2277. msfDebugOut((DEB_FAT,"FindLast returns %lu\n",PairToSect(ipfs,isect)));
  2278. sect = sectNew + 1;
  2279. break;
  2280. }
  2281. }
  2282. _fv.ReleaseTable(ipfs);
  2283. if (sect != 0)
  2284. break;
  2285. }
  2286. //We need additional checks here since in some cases there aren't
  2287. //enough pages in the fat to hold _sectNoSnapshot (or _sectNoSnapshotFree).
  2288. //Returning too small a value could result in SetSizing the file to too
  2289. //small a size, which is data loss.
  2290. if (sect < _sectNoSnapshot)
  2291. {
  2292. sect = _sectNoSnapshot;
  2293. }
  2294. if ((_sectNoSnapshotFree != ENDOFCHAIN) && (sect < _sectNoSnapshotFree))
  2295. {
  2296. sect = _sectNoSnapshotFree;
  2297. }
  2298. *psectRet = sect;
  2299. Err:
  2300. return sc;
  2301. Err_Rel:
  2302. _fv.ReleaseTable(ipfs);
  2303. return sc;
  2304. }
  2305. //+-------------------------------------------------------------------------
  2306. //
  2307. // Method: CFat::Remap, public
  2308. //
  2309. // Synopsis: Remap a portion of a chain for copy-on-write
  2310. //
  2311. // Effects:
  2312. //
  2313. // Arguments: [sectStart] -- Sector marking the first sector in the chain
  2314. // [oStart] -- Offset in sectors at which to begin the remap
  2315. // [ulRunLength] -- Number of sectors to remap
  2316. // [psectOldStart] -- Returns old location of first remapped
  2317. // sector.
  2318. // [psectNewStart] -- Returns new location of first sector
  2319. // [psectOldEnd] -- Returns old location of last sector
  2320. // [psectNewEnd] -- Returns new location of last sector
  2321. //
  2322. // Returns: Appropriate status code.
  2323. // S_FALSE if everything succeeded but no sectors were
  2324. // remapped.
  2325. //
  2326. // History: 18-Feb-92 PhilipLa Created.
  2327. //
  2328. //--------------------------------------------------------------------------
  2329. SCODE CFat::Remap(
  2330. SECT sectStart,
  2331. ULONG oStart,
  2332. ULONG ulRunLength,
  2333. SECT *psectOldStart,
  2334. SECT *psectNewStart,
  2335. SECT *psectOldEnd,
  2336. SECT *psectNewEnd)
  2337. {
  2338. msfDebugOut((DEB_FAT,"In CFat::Remap(%lu, %lu, %lu)\n",sectStart,oStart,ulRunLength));
  2339. msfAssert(SIDMINIFAT != _sid &&
  2340. aMsg("Called Remap on Minifat"));
  2341. msfAssert(ulRunLength != 0 &&
  2342. aMsg("Called Remap with 0 runlength"));
  2343. msfAssert(!_pmsParent->IsScratch() &&
  2344. aMsg("Called Remap on scratch."));
  2345. BOOL fRemapped = FALSE;
  2346. SCODE sc = S_OK;
  2347. SECT sectPrev = ENDOFCHAIN;
  2348. SECT sect;
  2349. ULONG uCount = 0;
  2350. *psectNewStart = ENDOFCHAIN;
  2351. *psectNewEnd = ENDOFCHAIN;
  2352. #if DBG == 1
  2353. *psectOldStart = ENDOFCHAIN;
  2354. *psectOldEnd = ENDOFCHAIN;
  2355. #endif
  2356. if (oStart == 0)
  2357. {
  2358. sectPrev = ENDOFCHAIN;
  2359. sect = sectStart;
  2360. }
  2361. else
  2362. {
  2363. msfChk(GetESect(sectStart, oStart - 1, &sectPrev));
  2364. msfChk(GetNext(sectPrev, &sect));
  2365. }
  2366. *psectOldStart = sect;
  2367. while ((uCount < ulRunLength) && (sect != ENDOFCHAIN))
  2368. {
  2369. if (uCount == ulRunLength - 1)
  2370. {
  2371. *psectOldEnd = sect;
  2372. }
  2373. msfChk(QueryRemapped(sect));
  2374. if (sc == S_FALSE)
  2375. {
  2376. SECT sectNew;
  2377. msfChk(GetFree(1, &sectNew, GF_WRITE));
  2378. msfDebugOut((DEB_ITRACE,"Remapping sector %lu to %lu\n",sect,sectNew));
  2379. if (sectPrev != ENDOFCHAIN)
  2380. {
  2381. msfChk(SetNext(sectPrev, sectNew));
  2382. if (_pfatNoScratch != NULL)
  2383. {
  2384. msfChk(_pfatNoScratch->SetNext(sectPrev, sectNew));
  2385. }
  2386. }
  2387. msfAssert((sect != ENDOFCHAIN) &&
  2388. aMsg("Remap precondition failed."));
  2389. SECT sectTemp;
  2390. msfChk(GetNext(sect, &sectTemp));
  2391. msfChk(SetNext(sectNew, sectTemp));
  2392. if (_pfatNoScratch != NULL)
  2393. {
  2394. msfChk(_pfatNoScratch->SetNext(sectNew, sectTemp));
  2395. }
  2396. msfChk(SetNext(sect, FREESECT));
  2397. fRemapped = TRUE;
  2398. if (uCount == 0)
  2399. {
  2400. *psectNewStart = sectNew;
  2401. }
  2402. if (uCount == ulRunLength - 1)
  2403. {
  2404. *psectNewEnd = sectNew;
  2405. }
  2406. sect = sectNew;
  2407. }
  2408. sectPrev = sect;
  2409. msfChk(GetNext(sect, &sect));
  2410. uCount++;
  2411. }
  2412. if ((*psectNewStart != ENDOFCHAIN) && (oStart == 0))
  2413. {
  2414. if (sectStart == _pmsParent->GetHeader()->GetDirStart())
  2415. _pmsParent->GetHeader()->SetDirStart(*psectNewStart);
  2416. if (sectStart == _pmsParent->GetHeader()->GetMiniFatStart())
  2417. _pmsParent->GetHeader()->SetMiniFatStart(*psectNewStart);
  2418. }
  2419. msfDebugOut((DEB_FAT,"Out CFat::Remap()=>%lu\n",*psectNewStart));
  2420. Err:
  2421. if ((sc == S_OK) && !fRemapped)
  2422. sc = S_FALSE;
  2423. return sc;
  2424. }
  2425. //+-------------------------------------------------------------------------
  2426. //
  2427. // Method: CFat::FindMaxSect, private
  2428. //
  2429. // Synopsis: Return last used sector in current Fat.
  2430. //
  2431. // Arguments: None.
  2432. //
  2433. // Returns: Last used sector in current Fat
  2434. //
  2435. // History: 15-Dec-91 PhilipLa Created.
  2436. //
  2437. //--------------------------------------------------------------------------
  2438. SCODE CFat::FindMaxSect(SECT *psectRet)
  2439. {
  2440. SCODE sc = S_OK;
  2441. if (_pfatNoScratch != NULL)
  2442. {
  2443. return _pfatNoScratch->FindMaxSect(psectRet);
  2444. }
  2445. if (_sectMax == ENDOFCHAIN)
  2446. {
  2447. msfChk(FindLast(psectRet));
  2448. }
  2449. else
  2450. {
  2451. #if DBG == 1
  2452. SECT sectLast;
  2453. msfChk(FindLast(&sectLast));
  2454. msfAssert(((_sectMax == sectLast) || (_sectMax == _sectLastUsed)) &&
  2455. aMsg("_sectMax doesn't match actual last sector"));
  2456. #endif
  2457. *psectRet = _sectMax;
  2458. }
  2459. if (*psectRet < _sectLastUsed)
  2460. {
  2461. *psectRet = _sectLastUsed;
  2462. }
  2463. Err:
  2464. return sc;
  2465. }
  2466. //+---------------------------------------------------------------------------
  2467. //
  2468. // Member: CFat::InitScratch, public
  2469. //
  2470. // Synopsis: Initialize the fat based on another fat. This is used
  2471. // for NOSCRATCH mode. The fats may have different sector
  2472. // sizes.
  2473. //
  2474. // Arguments: [pfat] -- Pointer to fat to copy.
  2475. // [fNew] -- TRUE if this is being called on an empty fat.
  2476. //
  2477. // Returns: Appropriate status code
  2478. //
  2479. // History: 20-Mar-95 PhilipLa Created
  2480. //
  2481. //----------------------------------------------------------------------------
  2482. SCODE CFat::InitScratch(CFat *pfat, BOOL fNew)
  2483. {
  2484. SCODE sc = S_OK;
  2485. msfAssert((_sid == SIDMINIFAT) && (_pmsParent->IsScratch()) &&
  2486. aMsg("Called InitScratch on the wrong thing."));
  2487. USHORT cbSectorOriginal = pfat->_pmsParent->GetSectorSize();
  2488. USHORT cSectPerRealSect = _pmsParent->GetSectorSize() /
  2489. cbSectorOriginal;
  2490. //This routine copies the fat from the multistream passed in into
  2491. // the _minifat_ of the current multistream.
  2492. ULONG cfatOriginal = pfat->_cfsTable;
  2493. //Our minifat must be large enough to hold all of the necessary
  2494. //sectors. Set the size appropriately.
  2495. ULONG cMiniFatSize = (cfatOriginal + cSectPerRealSect - 1) /
  2496. cSectPerRealSect;
  2497. msfAssert(((!fNew) || (_cfsTable == 0)) &&
  2498. aMsg("fNew TRUE when fat non-empty."));
  2499. msfAssert(((fNew) || (_pfatReal == pfat)) &&
  2500. aMsg("Fat pointer changed between calls to InitScratch"));
  2501. _pfatReal = P_TO_BP(CBasedFatPtr, pfat);
  2502. if (cMiniFatSize > _cfsTable)
  2503. {
  2504. msfChk(Resize(cMiniFatSize));
  2505. }
  2506. ULONG ifs;
  2507. for (ifs = 0; ifs < cfatOriginal; ifs++)
  2508. {
  2509. CFatSect *pfs;
  2510. CFatSect *pfsCurrent;
  2511. //Get the sector from the original fat
  2512. msfChk(pfat->_fv.GetTable(ifs, FB_NONE, &pfs));
  2513. msfAssert(pfs != NULL);
  2514. //Write the sector into the appropriate place in this fat.
  2515. ULONG ifsCurrent;
  2516. ifsCurrent = ifs / cSectPerRealSect;
  2517. OFFSET off;
  2518. off = (USHORT)((ifs % cSectPerRealSect) * cbSectorOriginal);
  2519. msfChk(_fv.GetTable(ifsCurrent, FB_DIRTY, &pfsCurrent));
  2520. if (fNew)
  2521. {
  2522. memcpy((BYTE *)pfsCurrent + off, pfs, cbSectorOriginal);
  2523. }
  2524. else
  2525. {
  2526. //Merge the table into the current one.
  2527. for (USHORT i = 0; i < cbSectorOriginal / sizeof(SECT); i++)
  2528. {
  2529. SECT sectCurrent;
  2530. OFFSET offCurrent;
  2531. offCurrent = i + (off / sizeof(SECT));
  2532. sectCurrent = pfsCurrent->GetSect(offCurrent);
  2533. if (sectCurrent != STREAMSECT)
  2534. {
  2535. pfsCurrent->SetSect(offCurrent, pfs->GetSect(i));
  2536. }
  2537. }
  2538. }
  2539. _fv.ReleaseTable(ifsCurrent);
  2540. pfat->_fv.ReleaseTable(ifs);
  2541. }
  2542. msfAssert((pfat->_cUnmarkedSects == 0) &&
  2543. aMsg("Fat being copied has changes in DIF"));
  2544. _fv.ResetBits();
  2545. _ulFreeSects = MAX_ULONG;
  2546. _sectFirstFree = 0;
  2547. _sectLastUsed = 0;
  2548. _sectMax = ENDOFCHAIN;
  2549. Err:
  2550. return sc;
  2551. }
  2552. //+---------------------------------------------------------------------------
  2553. //
  2554. // Member: CFat::ResizeNoSnapshot, public
  2555. //
  2556. // Synopsis: Resize the fat to handle a no-snapshot commit. In
  2557. // no-snapshot mode it is possible that another commit has
  2558. // grown the file to the point where it cannot be contained in
  2559. // the existing fat in this open, so we need to grow it before
  2560. // we can continue with anything else.
  2561. //
  2562. // Arguments: None.
  2563. //
  2564. // Returns: Appropriate SCODE.
  2565. //
  2566. // History: 19-Jun-96 PhilipLa Created
  2567. //
  2568. //----------------------------------------------------------------------------
  2569. SCODE CFat::ResizeNoSnapshot(void)
  2570. {
  2571. SCODE sc = S_OK;
  2572. FSINDEX ipfs;
  2573. FSOFFSET isect;
  2574. //If we need to grow the fat to handle the previous commits (which is
  2575. // possible if other opens are doing a lot of writing), we do it here,
  2576. // since we know for certain that the first available sector is at
  2577. // _sectNoSnapshot.
  2578. SectToPair(_sectNoSnapshot, &ipfs, &isect);
  2579. if (ipfs >= _cfsTable)
  2580. {
  2581. //We know we have no free sectors, so we can set this here and
  2582. // Resize will end up with the correct value.
  2583. _ulFreeSects = 0;
  2584. //This Resize will also cause a resize in the DIFat if necessary.
  2585. sc = Resize(ipfs + 1);
  2586. CheckFreeCount();
  2587. }
  2588. return sc;
  2589. }
  2590. #if DBG == 1
  2591. void CFat::CheckFreeCount(void)
  2592. {
  2593. SCODE sc; // check is disabled if fat grows above >1G
  2594. if ((_ulFreeSects != MAX_ULONG) && (_cfsTable < _ipfsRangeLocks/2))
  2595. {
  2596. ULONG ulFree;
  2597. msfChk(CountFree(&ulFree));
  2598. if (ulFree != _ulFreeSects)
  2599. {
  2600. msfDebugOut((DEB_ERROR,
  2601. "Free count mismatch. Cached: %lu, Real: %lu."
  2602. " Difference: %li\n",
  2603. _ulFreeSects,
  2604. ulFree,
  2605. ulFree - _ulFreeSects));
  2606. }
  2607. msfAssert((ulFree == _ulFreeSects) &&
  2608. aMsg("Free count doesn't match cached value."));
  2609. }
  2610. Err:
  2611. return;
  2612. }
  2613. #endif