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.

1234 lines
33 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: dl.cxx
  7. //
  8. // Contents: Delta list code for streams
  9. //
  10. // Classes: Defined in dl.hxx
  11. //
  12. // History: 28-Jul-92 PhilipLa Created.
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "msfhead.cxx"
  16. #pragma hdrstop
  17. #include <mread.hxx>
  18. #include <dl.hxx>
  19. #include <tstream.hxx>
  20. #ifndef _MAC
  21. inline
  22. #endif
  23. void *SDeltaBlock::operator new(size_t size, IMalloc * const pMalloc)
  24. {
  25. return pMalloc->Alloc(size);
  26. }
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Method: SDeltaBlock::SDeltaBlock, public
  30. //
  31. // Synopsis: SDeltaBlock constructor
  32. //
  33. // History: 10-Jul-92 PhilipLa Created.
  34. //
  35. //--------------------------------------------------------------------------
  36. #ifndef _MAC
  37. inline
  38. #endif
  39. SDeltaBlock::SDeltaBlock()
  40. {
  41. for (USHORT i = 0; i < CSECTPERBLOCK; i++)
  42. {
  43. _sect[i] = ENDOFCHAIN;
  44. }
  45. for (i = 0; i < CSECTPERBLOCK / CBITPERUSHORT; i++)
  46. {
  47. _fOwn[i] = 0;
  48. }
  49. }
  50. //+-------------------------------------------------------------------------
  51. //
  52. // Method: CDeltaList::CDeltaList, public
  53. //
  54. // Synopsis: CDeltaList constructor
  55. //
  56. // History: 21-Jan-92 PhilipLa Created.
  57. //
  58. // Notes:
  59. //
  60. //--------------------------------------------------------------------------
  61. CDeltaList::CDeltaList(CMStream *pms, CMStream *pmsScratch)
  62. {
  63. _pms = P_TO_BP(CBasedMStreamPtr, pms);
  64. _pmsScratch = P_TO_BP(CBasedMStreamPtr, pmsScratch);
  65. _apdb = NULL;
  66. _sectStart = ENDOFCHAIN;
  67. _ulSize = 0;
  68. _ptsParent = NULL;
  69. }
  70. inline CBasedDeltaBlockPtr * CDeltaList::GetNewDeltaArray(ULONG ulSize)
  71. {
  72. msfAssert(ulSize > 0);
  73. if (ulSize > (_HEAP_MAXREQ / sizeof(SDeltaBlock *)))
  74. {
  75. return NULL;
  76. }
  77. return (CBasedDeltaBlockPtr *) _pmsScratch->GetMalloc()->
  78. Alloc(sizeof(SDeltaBlock *) * ulSize);
  79. }
  80. //+-------------------------------------------------------------------------
  81. //
  82. // Method: CDeltaList::Init, public
  83. //
  84. // Synopsis: Init function for CDeltaList
  85. //
  86. // Arguments: [ulSize] -- Size of delta list to be initialized
  87. // [ptsParent] -- Pointer to transacted stream that contains
  88. // this delta list.
  89. //
  90. // Returns: S_OK if call completed successfully.
  91. //
  92. // Algorithm: *Finish This*
  93. //
  94. // History: 21-Jan-92 PhilipLa Created.
  95. //
  96. //--------------------------------------------------------------------------
  97. #ifdef LARGE_STREAMS
  98. SCODE CDeltaList::Init(ULONGLONG ulSize, CTransactedStream *ptsParent)
  99. #else
  100. SCODE CDeltaList::Init(ULONG ulSize, CTransactedStream *ptsParent)
  101. #endif
  102. {
  103. SCODE sc = S_OK;
  104. ULONG ulNewSize;
  105. CBasedDeltaBlockPtr *apdbTemp = NULL;
  106. msfAssert(IsEmpty() &&
  107. aMsg("Init called on non-empty delta list."));
  108. ULONG cbSector = GetDataSectorSize();
  109. ULONG csect = (ULONG)((ulSize + cbSector - 1) / cbSector);
  110. ulNewSize = (csect + CSECTPERBLOCK - 1) / CSECTPERBLOCK;
  111. _ulSize = ulNewSize;
  112. _ptsParent = P_TO_BP(CBasedTransactedStreamPtr, ptsParent);
  113. CDeltaList *pdlParent = NULL;
  114. if (_ptsParent->GetBase() != NULL)
  115. {
  116. pdlParent = _ptsParent->GetBase()->GetDeltaList();
  117. }
  118. msfAssert(_ulSize > 0);
  119. msfAssert(IsEmpty());
  120. // if the parent is InStream, we stay in low-memory mode
  121. if ((pdlParent == NULL) || (pdlParent->IsInMemory()))
  122. {
  123. //Try to copy it down. If it doesn't work, put it in a stream
  124. //instead.
  125. msfMem(apdbTemp = GetNewDeltaArray(_ulSize));
  126. MAXINDEXTYPE i;
  127. for (i = 0; i < _ulSize; i++)
  128. {
  129. apdbTemp[i] = NULL;
  130. }
  131. if (pdlParent != NULL)
  132. {
  133. for (i = 0; i < _ulSize; i++)
  134. {
  135. if ((i < pdlParent->_ulSize) && (pdlParent->_apdb[i] != NULL))
  136. {
  137. SDeltaBlock *pdbTemp;
  138. msfMemTo(Err_Alloc, pdbTemp =
  139. new(_pmsScratch->GetMalloc()) SDeltaBlock);
  140. apdbTemp[i] = P_TO_BP(CBasedDeltaBlockPtr, pdbTemp);
  141. for (USHORT j = 0; j < CSECTPERBLOCK; j++)
  142. {
  143. pdbTemp->_sect[j] = pdlParent->_apdb[i]->_sect[j];
  144. }
  145. }
  146. }
  147. }
  148. _apdb = P_TO_BP(CBasedDeltaBlockPtrPtr, apdbTemp);
  149. return S_OK;
  150. Err_Alloc:
  151. for (i = 0; i < _ulSize; i++)
  152. {
  153. _pmsScratch->GetMalloc()->Free(BP_TO_P(SDeltaBlock *, apdbTemp[i]));
  154. apdbTemp[i] = NULL;
  155. }
  156. }
  157. Err:
  158. _apdb = NULL;
  159. //We'll end up here if we get an error allocating memory for
  160. // the InMemory case above or if the parent is InStream. We
  161. // must allocate a new stream and copy down the parent.
  162. if (pdlParent == NULL)
  163. {
  164. for (ULONG i = 0; i < _ulSize; i++)
  165. {
  166. msfChkTo(Err_Init, InitStreamBlock(i));
  167. }
  168. }
  169. else
  170. {
  171. //Copy the parent into a stream representation.
  172. for (ULONG i = 0;
  173. i < min(_ulSize, pdlParent->_ulSize) * CSECTPERBLOCK;
  174. i++)
  175. {
  176. SECT sectOld;
  177. msfChkTo(Err_Init, pdlParent->GetMap(i, DL_READ, &sectOld));
  178. msfChkTo(Err_Init, WriteMap(&_sectStart, i, sectOld));
  179. }
  180. for (i = pdlParent->_ulSize; i < _ulSize; i++)
  181. {
  182. msfChkTo(Err_Init, InitStreamBlock(i));
  183. }
  184. }
  185. Err_Init:
  186. return sc;
  187. }
  188. //+-------------------------------------------------------------------------
  189. //
  190. // Method: CDeltaList::InitResize, public
  191. //
  192. // Synopsis: Resize initializer for deltalists
  193. //
  194. // Arguments: [ulSize] -- Size of new deltalist
  195. // [pdlOld] -- Pointer to deltalist to be resized
  196. //
  197. // Returns: S_OK if call completed OK.
  198. //
  199. // Algorithm: *Finish This*
  200. //
  201. // History: 21-Jan-92 PhilipLa Created.
  202. //
  203. //--------------------------------------------------------------------------
  204. #ifdef LARGE_STREAMS
  205. SCODE CDeltaList::InitResize(ULONGLONG ulSize)
  206. #else
  207. SCODE CDeltaList::InitResize(ULONG ulSize)
  208. #endif
  209. {
  210. msfDebugOut((DEB_ITRACE,"In CDeltaList copy constructor\n"));
  211. SCODE sc = S_OK;
  212. CBasedDeltaBlockPtr *temp = NULL;
  213. CBasedDeltaBlockPtr *apdbTemp = NULL;
  214. ULONG cbSector = GetDataSectorSize();
  215. ULONG csect = (ULONG)((ulSize + cbSector - 1) / cbSector);
  216. ULONG ulNewSize = (csect + CSECTPERBLOCK - 1) / CSECTPERBLOCK;
  217. msfAssert(ulNewSize > 0);
  218. if (ulNewSize == _ulSize)
  219. {
  220. return S_OK;
  221. }
  222. if (IsInStream())
  223. {
  224. //We have already copied the delta list contents out to the
  225. // stream, and will not attempt to read them back in.
  226. //
  227. //All we need to do is adjust the size and return.
  228. if (ulNewSize > _ulSize)
  229. {
  230. for (ULONG i = _ulSize; i < ulNewSize; i++)
  231. {
  232. msfChk(InitStreamBlock(i));
  233. }
  234. }
  235. _ulSize = ulNewSize;
  236. return S_OK;
  237. }
  238. if (ulNewSize > (_HEAP_MAXREQ / sizeof(SDeltaBlock *)))
  239. {
  240. //This is not an error. Write the current delta information
  241. // to the stream and use that.
  242. msfChk(DumpList());
  243. if (ulNewSize > _ulSize)
  244. {
  245. for (ULONG i = _ulSize; i < ulNewSize; i++)
  246. {
  247. msfChk(InitStreamBlock(i));
  248. }
  249. }
  250. _ulSize = ulNewSize;
  251. return S_OK;
  252. }
  253. msfMemTo(ErrMem, temp = GetNewDeltaArray(ulNewSize));
  254. //apdbTemp is an unbased version of _apdb, for efficiency.
  255. apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb);
  256. ULONG i;
  257. if (apdbTemp != NULL)
  258. {
  259. for (i = 0; i < min(_ulSize, ulNewSize); i++)
  260. {
  261. temp[i] = apdbTemp[i];
  262. apdbTemp[i] = NULL;
  263. }
  264. }
  265. for (i = _ulSize; i < ulNewSize; i++)
  266. {
  267. temp[i] = NULL;
  268. }
  269. for (i = ulNewSize; i < _ulSize; i++)
  270. {
  271. ReleaseBlock(i);
  272. }
  273. _ulSize = ulNewSize;
  274. _pmsScratch->GetMalloc()->Free(apdbTemp);
  275. _apdb = P_TO_BP(CBasedDeltaBlockPtrPtr, temp);
  276. return S_OK;
  277. ErrMem:
  278. //The only error that can get us here is an error allocating temp.
  279. //If this happens, dump the current vector to a stream and use
  280. // the stream for all future delta list operations.
  281. msfChk(DumpList());
  282. if (ulNewSize > _ulSize)
  283. {
  284. for (i = _ulSize; i < ulNewSize; i++)
  285. {
  286. msfChk(InitStreamBlock(i));
  287. }
  288. }
  289. _ulSize = ulNewSize;
  290. return S_OK;
  291. Err:
  292. //We only get here if we error out on the DumpList() or
  293. //InitStreamBlock calls (i.e. Disk Error)
  294. return sc;
  295. }
  296. //+---------------------------------------------------------------------------
  297. //
  298. // Member: CDeltaList::InitStreamBlock, private
  299. //
  300. // Synopsis: Initialize a new block in a stream
  301. //
  302. // Arguments: [ulBlock] -- Block to initialize
  303. //
  304. // Returns: Appropriate status code
  305. //
  306. // History: 20-Nov-92 PhilipLa Created
  307. //
  308. // Notes:
  309. //
  310. //----------------------------------------------------------------------------
  311. SCODE CDeltaList::InitStreamBlock(ULONG ulBlock)
  312. {
  313. SCODE sc = S_OK;
  314. ULONG cSectOld = ulBlock * CSECTPERBLOCK;
  315. ULONG cSectNew = (ulBlock + 1) * CSECTPERBLOCK;
  316. //NOTE: This can potentially be optimized to avoid the loop.
  317. for (ULONG i = cSectOld; i < cSectNew; i++)
  318. {
  319. msfChk(WriteMap(&_sectStart, i, ENDOFCHAIN));
  320. }
  321. Err:
  322. return sc;
  323. }
  324. //+-------------------------------------------------------------------------
  325. //
  326. // Method: CDeltaList::ReleaseBlock, private
  327. //
  328. // Synopsis: Release an SDeltaBlock, freeing its storage in the
  329. // scratch MS.
  330. //
  331. // Arguments: [oBlock] -- Offset of block to release.
  332. //
  333. // Returns: void.
  334. //
  335. // History: 10-Jul-92 PhilipLa Created.
  336. //
  337. //--------------------------------------------------------------------------
  338. void CDeltaList::ReleaseBlock(ULONG oBlock)
  339. {
  340. CFat *pfat = GetDataFat();
  341. msfAssert(IsInMemory());
  342. SDeltaBlock *temp = BP_TO_P(SDeltaBlock *, _apdb[(MAXINDEXTYPE)oBlock]);
  343. if (temp != NULL)
  344. {
  345. for (USHORT i = 0; i < CSECTPERBLOCK; i++)
  346. {
  347. if ((temp->_sect[i] != ENDOFCHAIN) && temp->IsOwned(i))
  348. {
  349. SECT sectCurrent = FREESECT;
  350. pfat->GetNext(temp->_sect[i], &sectCurrent);
  351. if (sectCurrent == STREAMSECT)
  352. pfat->SetNext(temp->_sect[i], FREESECT);
  353. }
  354. }
  355. _pmsScratch->GetMalloc()->Free(temp);
  356. _apdb[(MAXINDEXTYPE)oBlock] = NULL;
  357. }
  358. }
  359. //+-------------------------------------------------------------------------
  360. //
  361. // Method: CDeltaList::~CDeltaList, public
  362. //
  363. // Synopsis: CDeltaList destructor
  364. //
  365. // History: 21-Jan-92 PhilipLa Created.
  366. //
  367. //--------------------------------------------------------------------------
  368. CDeltaList::~CDeltaList()
  369. {
  370. Empty();
  371. }
  372. //+-------------------------------------------------------------------------
  373. //
  374. // Method: CDeltaList::GetMap, public
  375. //
  376. // Synopsis: Get mapping information for a sector
  377. //
  378. // Arguments: [sectOld] -- Sector to get mapping information for
  379. // [dwFlags] -- DL_GET or DL_CREATE
  380. // [psectRet] -- Location for return value
  381. // [pfIsOwner] -- Returns TRUE if the returned sector
  382. // is owned by this delta list, FALSE if it
  383. // if owned by an ancestor.
  384. //
  385. // Returns: S_OK if call completed OK.
  386. //
  387. // Algorithm: If DL_READ is specified, return the current existing
  388. // mapping for the sector. It is not required that
  389. // the delta list own the sector. Return ENDOFCHAIN
  390. // if no mapping exists.
  391. // If DL_GET is specified, return the current existing
  392. // mapping for the sector if it is owned by this delta
  393. // list. If none exists, return ENDOFCHAIN.
  394. // If DL_CREATE, check the existing mapping. If none
  395. // exists, or one exists but is not owned, get a free
  396. // sector from the fat and set the mapping. Return
  397. // the new mapping (or the existing one if it had
  398. // previously been mapped).
  399. //
  400. // History: 21-Jan-92 PhilipLa Created.
  401. // 10-Jul-92 PhilipLa Changed for copy reductions.
  402. //
  403. //--------------------------------------------------------------------------
  404. SCODE CDeltaList::GetMap(SECT sectOld, const DWORD dwFlags, SECT *psectRet)
  405. {
  406. msfDebugOut((DEB_ITRACE,"In CDeltaList::GetMap()\n"));
  407. SCODE sc = S_OK;
  408. msfAssert(!IsEmpty());
  409. msfAssert((dwFlags == DL_GET) || (dwFlags == DL_CREATE) ||
  410. (dwFlags == DL_READ));
  411. MAXINDEXTYPE odb = (MAXINDEXTYPE)(sectOld / CSECTPERBLOCK);
  412. USHORT os = (USHORT)(sectOld % CSECTPERBLOCK);
  413. msfAssert(odb < _ulSize);
  414. if (IsInStream())
  415. {
  416. BOOL fOwn = TRUE;
  417. msfChk(ReadMap(&_sectStart, sectOld, psectRet));
  418. if (dwFlags == DL_READ)
  419. {
  420. return S_OK;
  421. }
  422. CDeltaList *pdlParent = NULL;
  423. if (_ptsParent->GetBase() != NULL)
  424. pdlParent = _ptsParent->GetBase()->GetDeltaList();
  425. if (pdlParent != NULL)
  426. {
  427. msfChk(pdlParent->IsOwned(sectOld, *psectRet, &fOwn));
  428. }
  429. if (fOwn == FALSE)
  430. *psectRet = ENDOFCHAIN;
  431. if ((dwFlags == DL_CREATE) && (*psectRet == ENDOFCHAIN))
  432. {
  433. msfChk(GetDataFat()->GetFree(1, psectRet, GF_WRITE));
  434. msfChk(GetDataFat()->SetNext(*psectRet, STREAMSECT));
  435. if(!IsNoScratch())
  436. msfChk(_pmsScratch->SetSize());
  437. else
  438. msfChk(_pms->SetSize());
  439. msfChk(WriteMap(&_sectStart, sectOld, *psectRet));
  440. }
  441. return S_OK;
  442. }
  443. msfAssert(odb < _ulSize);
  444. // If _apdb[odb] == NULL, there is no existing mapping so we
  445. // don't need to check ownership.
  446. if (_apdb[odb] == NULL)
  447. {
  448. if (dwFlags & DL_CREATE)
  449. {
  450. SDeltaBlock * pdbTemp = new(_pmsScratch->GetMalloc()) SDeltaBlock;
  451. _apdb[odb] = P_TO_BP(CBasedDeltaBlockPtr, pdbTemp);
  452. if (_apdb[odb] == NULL)
  453. {
  454. msfChk(DumpList());
  455. msfAssert(IsInStream());
  456. return GetMap(sectOld, dwFlags, psectRet);
  457. }
  458. }
  459. else
  460. {
  461. *psectRet = ENDOFCHAIN;
  462. return S_OK;
  463. }
  464. }
  465. SECT sectTemp;
  466. sectTemp = _apdb[odb]->_sect[os];
  467. if (dwFlags != DL_READ)
  468. {
  469. BOOL fOwn = _apdb[odb]->IsOwned(os);
  470. if (fOwn == FALSE)
  471. sectTemp = ENDOFCHAIN;
  472. if ((dwFlags == DL_CREATE) && (sectTemp == ENDOFCHAIN))
  473. {
  474. //
  475. // Don't grow the file (w/ SetSize) here. As an optimzation
  476. // it is the responsibility of the caller to grow the file after
  477. // possibly multiple calls to GetMap(DL_CREATE).
  478. //
  479. msfChk(GetDataFat()->GetFree(1, &sectTemp, GF_WRITE));
  480. msfChk(GetDataFat()->SetNext(sectTemp, STREAMSECT));
  481. _apdb[odb]->_sect[os] = sectTemp;
  482. _apdb[odb]->MakeOwn(os);
  483. }
  484. }
  485. *psectRet = sectTemp;
  486. msfDebugOut((DEB_ITRACE,"Out CDeltaList::GetMap()\n"));
  487. Err:
  488. return sc;
  489. }
  490. //+-------------------------------------------------------------------------
  491. //
  492. // Method: CDeltaList::ReleaseInvalidSects, public
  493. //
  494. // Synopsis: Release sectors allocated in the FAT that are not in the
  495. // MStream.
  496. //
  497. // Arguments: [sectMaxValid] -- Release all SECTS greater than this one.
  498. //
  499. // Returns: S_OK if call completed OK.
  500. //
  501. // Algorithm:
  502. //
  503. // History: 26-Mar-97 BChapman Created.
  504. //
  505. //--------------------------------------------------------------------------
  506. SCODE CDeltaList::ReleaseInvalidSects(SECT sectMaxValid)
  507. {
  508. msfDebugOut((DEB_ITRACE,"In CDeltaList::ReleaseInvalidSects(%x)\n",
  509. sectMaxValid));
  510. msfAssert(!IsEmpty());
  511. CBasedDeltaBlockPtr *apdbTemp; // Real Ptr to array of Based Pointers
  512. SDeltaBlock *pdbTemp;
  513. CFat *pfat = GetDataFat();
  514. if (IsInStream())
  515. {
  516. // We don't need to do this if we are InStream.
  517. return S_OK;
  518. }
  519. apdbTemp = _apdb; // Convert the array BasedPtr to a Ptr.
  520. //
  521. // Walk the entire Delta List looking for SECTS in the FAT that are
  522. // greater than sectMaxValid, and free them.
  523. // If all the entries in any block are freed, then free the block.
  524. //
  525. for (MAXINDEXTYPE i = 0; i < _ulSize; i++)
  526. {
  527. pdbTemp = _apdb[i]; // Convert BasedPtr to Ptr
  528. if (pdbTemp != NULL)
  529. {
  530. BOOL fFreeAll = TRUE;
  531. for (USHORT k=0; k < CSECTPERBLOCK; k++)
  532. {
  533. SECT sectType=FREESECT;
  534. SECT sectEntryK = pdbTemp->_sect[k];
  535. if(sectEntryK != ENDOFCHAIN)
  536. {
  537. if(pdbTemp->IsOwned(k) && (sectEntryK > sectMaxValid))
  538. {
  539. //
  540. // This routins is already in the error path. So we
  541. // don't check for errors. Just keep pluggin away.
  542. // BTW. There shouldn't be any errors because we just
  543. // allocated all this stuff and we are only tring to
  544. // give it back.
  545. //
  546. pfat->GetNext(sectEntryK, &sectType);
  547. if (sectType == STREAMSECT)
  548. {
  549. pfat->SetNext(sectEntryK, FREESECT);
  550. pdbTemp->DisOwn(k);
  551. pdbTemp->_sect[k] = ENDOFCHAIN;
  552. }
  553. }
  554. else
  555. {
  556. // don't free this DeltaBlock if any non-ENDOFCHAIN
  557. // entries are not owned or are valid (<= MaxValid)
  558. fFreeAll = FALSE;
  559. }
  560. }
  561. }
  562. if(fFreeAll)
  563. {
  564. _pmsScratch->GetMalloc()->Free(pdbTemp);
  565. _apdb[i] = NULL;
  566. }
  567. }
  568. }
  569. msfDebugOut((DEB_ITRACE,"Out CDeltaList::ReleaseInvalidSects()\n"));
  570. return S_OK;
  571. }
  572. //+---------------------------------------------------------------------------
  573. //
  574. // Member: CDeltaList::BeginCommit, public
  575. //
  576. // Synopsis: Begin the commit of a delta list
  577. //
  578. // Arguments: [ptsParent] -- Pointer to containing Tstream.
  579. //
  580. // Returns: Appropriate status code
  581. //
  582. // History: 19-Nov-92 PhilipLa Created
  583. //
  584. //----------------------------------------------------------------------------
  585. void CDeltaList::BeginCommit(CTransactedStream *ptsParent)
  586. {
  587. _ptsParent = P_TO_BP(CBasedTransactedStreamPtr, ptsParent);
  588. }
  589. //+-------------------------------------------------------------------------
  590. //
  591. // Method: CDeltaList::EndCommit, public
  592. //
  593. // Synopsis: Take the new delta list passed up and release the old.
  594. // Free any sectors used and owned in the old list but not
  595. // in the new.
  596. //
  597. // Arguments: [pdlNew] -- Pointer to new delta list to take
  598. //
  599. // Returns: void.
  600. //
  601. // History: 10-Jul-92 PhilipLa Created.
  602. //
  603. //--------------------------------------------------------------------------
  604. void CDeltaList::EndCommit(CDeltaList *pdlNew, DFLAGS df)
  605. {
  606. msfAssert(pdlNew != NULL);
  607. if (pdlNew->IsEmpty()) return;
  608. ULONG ulMaxSize = min(_ulSize, pdlNew->_ulSize);
  609. if (P_COMMIT(df))
  610. {
  611. #if DBG == 1
  612. msfDebugOut((DEB_ITRACE, "Beginning commit process:\n"));
  613. PrintList();
  614. msfDebugOut((DEB_ITRACE, "New list is:\n"));
  615. pdlNew->PrintList();
  616. #endif
  617. ULONG iMax = ulMaxSize * CSECTPERBLOCK;
  618. for (ULONG i = 0; i < iMax; i++)
  619. {
  620. SECT sectOld = ENDOFCHAIN, sectNew = ENDOFCHAIN;
  621. GetMap(i, DL_GET, &sectOld);
  622. pdlNew->GetMap(i, DL_GET, &sectNew);
  623. if ((sectOld != sectNew) && (sectOld != ENDOFCHAIN) &&
  624. (sectNew != ENDOFCHAIN))
  625. {
  626. CFat *pfat = GetDataFat();
  627. SECT sectChk;
  628. pfat->GetNext(sectOld, &sectChk);
  629. if (sectChk == STREAMSECT)
  630. pfat->SetNext(sectOld, FREESECT);
  631. }
  632. }
  633. //At this point, all the sectors in the current delta list
  634. // that are not used in the new delta list have been freed.
  635. // We still need to clean up the actual representation of
  636. // the delta list, and merge the ownership bitvectors if
  637. // we are InMemory.
  638. if (IsInMemory())
  639. {
  640. for (i = pdlNew->_ulSize; i < _ulSize; i++)
  641. {
  642. ReleaseBlock(i);
  643. }
  644. CBasedDeltaBlockPtr * apdbTemp;
  645. apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb);
  646. for (MAXINDEXTYPE i = 0; i < ulMaxSize; i++)
  647. {
  648. if ((apdbTemp[i] != NULL) && (pdlNew->IsInMemory()))
  649. {
  650. msfAssert(pdlNew->_apdb[i] != NULL);
  651. for (USHORT j = 0; j < CSECTPERBLOCK / CBITPERUSHORT; j++)
  652. {
  653. pdlNew->_apdb[i]->_fOwn[j] |= apdbTemp[i]->_fOwn[j];
  654. }
  655. }
  656. _pmsScratch->GetMalloc()->Free(BP_TO_P(SDeltaBlock *, apdbTemp[i]));
  657. }
  658. _pmsScratch->GetMalloc()->Free(apdbTemp);
  659. }
  660. else if (IsInStream())
  661. {
  662. for (i = pdlNew->_ulSize * CSECTPERBLOCK;
  663. i < _ulSize * CSECTPERBLOCK;
  664. i++)
  665. {
  666. SECT sectOld = ENDOFCHAIN;
  667. GetMap(i, DL_GET, &sectOld);
  668. if (sectOld != ENDOFCHAIN)
  669. {
  670. CFat *pfat = GetDataFat();
  671. #if DBG == 1
  672. SECT sectChk;
  673. pfat->GetNext(sectOld, &sectChk);
  674. msfAssert((sectChk == STREAMSECT) &&
  675. aMsg("Freeing non-dirty stream sector"));
  676. #endif
  677. pfat->SetNext(sectOld, FREESECT);
  678. }
  679. }
  680. GetControlFat()->SetChainLength(_sectStart, 0);
  681. }
  682. _apdb = pdlNew->_apdb;
  683. _ulSize = pdlNew->_ulSize;
  684. _sectStart = pdlNew->_sectStart;
  685. pdlNew->_apdb = NULL;
  686. pdlNew->_ulSize = 0;
  687. pdlNew->_sectStart = ENDOFCHAIN;
  688. pdlNew->_ptsParent = NULL;
  689. #if DBG == 1
  690. msfDebugOut((DEB_ITRACE, "Completed commit process:\n"));
  691. PrintList();
  692. #endif
  693. }
  694. return;
  695. }
  696. //+---------------------------------------------------------------------------
  697. //
  698. // Member: CDeltaList::Empty, public
  699. //
  700. // Synopsis: Empty the delta list
  701. //
  702. // Arguments: None.
  703. //
  704. // History: 18-Nov-92 PhilipLa Created
  705. //
  706. //----------------------------------------------------------------------------
  707. void CDeltaList::Empty(void)
  708. {
  709. if (IsInMemory())
  710. {
  711. msfAssert(_sectStart == ENDOFCHAIN);
  712. CBasedDeltaBlockPtr * apdbTemp;
  713. apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb);
  714. for (ULONG i = 0; i < _ulSize; i++)
  715. {
  716. if (apdbTemp[i] != NULL)
  717. {
  718. ReleaseBlock(i);
  719. }
  720. }
  721. _pmsScratch->GetMalloc()->Free(apdbTemp);
  722. _apdb = NULL;
  723. }
  724. else if (IsInStream())
  725. {
  726. msfAssert(_apdb == NULL);
  727. if (_sectStart != ENDOFCHAIN)
  728. {
  729. FreeStream(_sectStart, _ulSize);
  730. }
  731. _sectStart = ENDOFCHAIN;
  732. }
  733. _ptsParent = NULL;
  734. _ulSize = 0;
  735. }
  736. //+---------------------------------------------------------------------------
  737. //
  738. // Member: CDeltaList::DumpList, public
  739. //
  740. // Synopsis: Dump a delta list out to a stream, then release its
  741. // in memory representation.
  742. //
  743. // Arguments: None.
  744. //
  745. // Returns: Appropriate status code
  746. //
  747. // History: 20-Nov-92 PhilipLa Created
  748. //
  749. //----------------------------------------------------------------------------
  750. SCODE CDeltaList::DumpList(void)
  751. {
  752. SCODE sc = S_OK;
  753. ULONG cSect = _ulSize * CSECTPERBLOCK;
  754. msfAssert(IsInMemory());
  755. for (ULONG i = 0; i < cSect; i++)
  756. {
  757. SECT sectNew;
  758. msfChk(GetMap(i, DL_GET, &sectNew));
  759. msfChk(WriteMap(&_sectStart, i, sectNew));
  760. }
  761. CBasedDeltaBlockPtr * apdbTemp;
  762. apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb);
  763. if (apdbTemp != NULL)
  764. {
  765. for (i = 0; i < _ulSize; i++)
  766. {
  767. SDeltaBlock *temp = BP_TO_P(SDeltaBlock *, apdbTemp[i]);
  768. if (temp != NULL)
  769. {
  770. _pmsScratch->GetMalloc()->Free(temp);
  771. }
  772. }
  773. _pmsScratch->GetMalloc()->Free(apdbTemp);
  774. _apdb = NULL;
  775. }
  776. msfAssert(IsInStream());
  777. Err:
  778. return sc;
  779. }
  780. //+---------------------------------------------------------------------------
  781. //
  782. // Member: CDeltaList::FindOffset, private
  783. //
  784. // Synopsis: Compute the correct offset from which to read a mapping
  785. //
  786. // Arguments: [psectStart] -- Pointer to start sector
  787. // [sect] -- Sector to find mapping for
  788. // [pulRet] -- Pointer to return location
  789. // [fWrite] -- TRUE if the sector will be written to
  790. //
  791. // Returns: Appropriate status code
  792. //
  793. // History: 20-Nov-92 PhilipLa Created
  794. //
  795. //----------------------------------------------------------------------------
  796. SCODE CDeltaList::FindOffset(
  797. SECT *psectStart,
  798. SECT sect,
  799. ULARGE_INTEGER *pulRet,
  800. BOOL fWrite)
  801. {
  802. SCODE sc;
  803. ULONG ulOffset = sect * sizeof(SECT);
  804. ULONG cbSector = GetControlSectorSize();
  805. msfAssert(cbSector == SCRATCHSECTORSIZE);
  806. SECT sectChain = ulOffset / cbSector;
  807. SECT sectReal;
  808. CFat *pfat = GetControlFat();
  809. if (fWrite)
  810. {
  811. if (*psectStart == ENDOFCHAIN)
  812. {
  813. msfChk(pfat->Allocate(1, psectStart));
  814. }
  815. msfChk(pfat->GetESect(*psectStart, sectChain, &sectReal));
  816. }
  817. else
  818. {
  819. msfChk(pfat->GetSect(*psectStart, sectChain, &sectReal));
  820. }
  821. msfAssert(sectReal != ENDOFCHAIN);
  822. ULARGE_INTEGER ul;
  823. #ifdef LARGE_DOCFILE
  824. ul.QuadPart = ConvertSectOffset(sectReal,
  825. (OFFSET)(ulOffset % cbSector),
  826. _pmsScratch->GetSectorShift());
  827. #else
  828. ULISet32(ul, ConvertSectOffset(sectReal,
  829. (OFFSET)(ulOffset % cbSector),
  830. _pmsScratch->GetSectorShift()));
  831. #endif
  832. *pulRet = ul;
  833. Err:
  834. return sc;
  835. }
  836. //+---------------------------------------------------------------------------
  837. //
  838. // Member: CDeltaList::ReadMap, private
  839. //
  840. // Synopsis: Read a mapping from a stream representation.
  841. //
  842. // Arguments: [sect] -- Sector to read mapping for
  843. // [psectRet] -- Location to return mapping in.
  844. //
  845. // Returns: Appropriate status code
  846. //
  847. // History: 20-Nov-92 PhilipLa Created
  848. //
  849. //----------------------------------------------------------------------------
  850. SCODE CDeltaList::ReadMap(SECT *psectStart, SECT sect, SECT *psectRet)
  851. {
  852. SCODE sc;
  853. if (_sectStart == ENDOFCHAIN)
  854. {
  855. //We haven't written anything yet, so the sector must be
  856. // unmapped.
  857. *psectRet = ENDOFCHAIN;
  858. return S_OK;
  859. }
  860. ULARGE_INTEGER ul;
  861. ULONG ulRetval;
  862. msfChk(FindOffset(psectStart, sect, &ul, FALSE));
  863. msfHChk(GetControlILB()->ReadAt(ul, psectRet, sizeof(SECT),
  864. &ulRetval));
  865. if (ulRetval != sizeof(SECT))
  866. {
  867. //The ILB isn't long enough to contain that mapping,
  868. *psectRet = ENDOFCHAIN;
  869. }
  870. Err:
  871. return sc;
  872. }
  873. //+---------------------------------------------------------------------------
  874. //
  875. // Member: CDeltaList::WriteMap, private
  876. //
  877. // Synopsis: Write a mapping to a stream representation
  878. //
  879. // Arguments: [sect] -- Sect to write mapping for
  880. // [sectMap] -- Mapping of sect
  881. //
  882. // Returns: Appropriate status code
  883. //
  884. // History: 20-Nov-92 PhilipLa Created
  885. //
  886. //----------------------------------------------------------------------------
  887. SCODE CDeltaList::WriteMap(SECT *psectStart, SECT sect, SECT sectMap)
  888. {
  889. SCODE sc;
  890. ULARGE_INTEGER ul;
  891. ULONG ulRetval;
  892. SECT sectOld = *psectStart;
  893. msfAssert(_pmsScratch->IsScratch());
  894. msfChk(FindOffset(psectStart, sect, &ul, TRUE));
  895. msfHChk(GetControlILB()->WriteAt(ul, &sectMap, sizeof(SECT),
  896. &ulRetval));
  897. if (ulRetval != sizeof(SECT))
  898. {
  899. msfErr(Err, STG_E_WRITEFAULT);
  900. }
  901. return S_OK;
  902. Err:
  903. //If we failed, we may have allocated sectors for storage that
  904. // cannot be written to - we should ignore these sectors. This
  905. // can leave some wasted space in the fat, but we don't really
  906. // care since this is the scratch.
  907. *psectStart = sectOld;
  908. return sc;
  909. }
  910. //+---------------------------------------------------------------------------
  911. //
  912. // Member: CDeltaList::FreeStream, private
  913. //
  914. // Synopsis: Free the scratch sectors associated with a stream
  915. // representation of a delta list.
  916. //
  917. // Arguments: [sectStart] -- Start sector of representation to
  918. // free.
  919. //
  920. // Returns: void.
  921. //
  922. // History: 23-Nov-92 PhilipLa Created
  923. //
  924. //----------------------------------------------------------------------------
  925. void CDeltaList::FreeStream(SECT sectStart, ULONG ulSize)
  926. {
  927. ULONG cSect = ulSize * CSECTPERBLOCK;
  928. SECT sectOld = ENDOFCHAIN;
  929. BOOL fOwn = TRUE;
  930. CDeltaList *pdlParent = NULL;
  931. if (_ptsParent->GetBase() != NULL)
  932. pdlParent = _ptsParent->GetBase()->GetDeltaList();
  933. for (ULONG i = 0; i < cSect; i++)
  934. {
  935. ReadMap(&sectStart, i, &sectOld);
  936. if (pdlParent != NULL)
  937. {
  938. pdlParent->IsOwned(i, sectOld, &fOwn);
  939. }
  940. if ((sectOld != ENDOFCHAIN) && fOwn)
  941. {
  942. CFat *pfat = GetDataFat();
  943. SECT sectChk = FREESECT;
  944. pfat->GetNext(sectOld, &sectChk);
  945. if (sectChk == STREAMSECT)
  946. pfat->SetNext(sectOld, FREESECT);
  947. }
  948. }
  949. GetControlFat()->SetChainLength(sectStart, 0);
  950. return;
  951. }
  952. //+---------------------------------------------------------------------------
  953. //
  954. // Member: CDeltaList::IsOwned, public
  955. //
  956. // Synopsis: Return TRUE if the caller owns the sector given,
  957. // FALSE otherwise.
  958. //
  959. // Arguments: [sect] -- Sector for mapping given
  960. // [sectMap] -- Sector mapping
  961. // [fOwn] -- Return value
  962. //
  963. // Returns: Appropriate status code
  964. //
  965. // History: 30-Jul-93 PhilipLa Created
  966. //
  967. //----------------------------------------------------------------------------
  968. SCODE CDeltaList::IsOwned(SECT sect, SECT sectMap, BOOL *fOwn)
  969. {
  970. SCODE sc = S_OK;
  971. //To determine ownership of a sector:
  972. // 1) If the sector mapping does not exist at the current level,
  973. // then the caller must own it.
  974. // 2) If the sector mapping does exist at the current level, then
  975. // the caller cannot own it.
  976. SECT sectOld;
  977. if (sect < _ulSize * CSECTPERBLOCK)
  978. {
  979. if (IsInMemory())
  980. {
  981. MAXINDEXTYPE odb = (MAXINDEXTYPE)(sect / CSECTPERBLOCK);
  982. USHORT os = (USHORT)(sect % CSECTPERBLOCK);
  983. sectOld = _apdb[odb]->_sect[os];
  984. }
  985. else
  986. {
  987. msfChk(GetMap(sect, DL_READ, &sectOld));
  988. }
  989. *fOwn = (sectOld != sectMap);
  990. }
  991. else
  992. {
  993. *fOwn = TRUE;
  994. }
  995. Err:
  996. return sc;
  997. }
  998. #if DBG == 1
  999. void CDeltaList::PrintList(void)
  1000. {
  1001. if (!IsEmpty())
  1002. {
  1003. for (ULONG i = 0; i < _ulSize * CSECTPERBLOCK; i++)
  1004. {
  1005. SECT sect;
  1006. GetMap(i, DL_READ, &sect);
  1007. msfDebugOut((DEB_NOCOMPNAME|DEB_ITRACE, "%lx ",sect));
  1008. }
  1009. msfDebugOut((DEB_NOCOMPNAME|DEB_ITRACE,"\n"));
  1010. }
  1011. else
  1012. {
  1013. msfDebugOut((DEB_NOCOMPNAME|DEB_ITRACE,"List is empty\n"));
  1014. }
  1015. }
  1016. #endif