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

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