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.

2021 lines
55 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: publicdf.cxx
  7. //
  8. // Contents: Public DocFile implementation
  9. //
  10. // History: 20-Jan-92 DrewB Created
  11. //
  12. //---------------------------------------------------------------
  13. #include <dfhead.cxx>
  14. #pragma hdrstop
  15. #include <time.h>
  16. #include <pbstream.hxx>
  17. #include <tstream.hxx>
  18. #include <sstream.hxx>
  19. #include <lock.hxx>
  20. #include <rpubdf.hxx>
  21. //+--------------------------------------------------------------
  22. //
  23. // Member: PRevertable::RevertFromAbove, public
  24. //
  25. // Synopsis: calls to derived object
  26. //
  27. // History: 20-Jan-98 HenryLee Created
  28. //
  29. //---------------------------------------------------------------
  30. void PRevertable::RevertFromAbove(void)
  31. {
  32. if (_sig == CPUBDOCFILE_SIG || _sig == CROOTPUBDOCFILE_SIG)
  33. ((CPubDocFile *)this)->RevertFromAbove();
  34. else if (_sig == CPUBSTREAM_SIG)
  35. ((CPubStream *)this)->RevertFromAbove();
  36. else olAssert (!"Invalid signature on PRevertable");
  37. }
  38. //+--------------------------------------------------------------
  39. //
  40. // Member: PRevertable::FlushBufferedData, public
  41. //
  42. // Synopsis: calls to derived object
  43. //
  44. // History: 20-Jan-98 HenryLee Created
  45. //
  46. //---------------------------------------------------------------
  47. SCODE PRevertable::FlushBufferedData(int recursionlevel)
  48. {
  49. if (_sig == CPUBDOCFILE_SIG || _sig == CROOTPUBDOCFILE_SIG)
  50. return ((CPubDocFile *)this)->FlushBufferedData(recursionlevel);
  51. else if (_sig == CPUBSTREAM_SIG)
  52. return ((CPubStream *)this)->FlushBufferedData(recursionlevel);
  53. else olAssert (!"Invalid signature on PRevertable");
  54. return STG_E_INVALIDFUNCTION;
  55. }
  56. //+--------------------------------------------------------------
  57. //
  58. // Member: PRevertable::EmptyCache, public
  59. //
  60. // Synopsis: calls to derived object
  61. //
  62. // History: 20-Jan-98 HenryLee Created
  63. //
  64. //---------------------------------------------------------------
  65. void PRevertable::EmptyCache()
  66. {
  67. if (_sig == CPUBDOCFILE_SIG || _sig == CROOTPUBDOCFILE_SIG)
  68. ((CPubDocFile *)this)->EmptyCache();
  69. else if (_sig == CPUBSTREAM_SIG)
  70. ((CPubStream *)this)->EmptyCache();
  71. else olAssert (!"Invalid signature on PRevertable");
  72. }
  73. //+--------------------------------------------------------------
  74. //
  75. // Member: CPubDocFile::CPubDocFile, public
  76. //
  77. // Synopsis: Constructor
  78. //
  79. // Arguments: [pdfParent] - Parent PubDocFile
  80. // [pdf] - DocFile basis
  81. // [df] - Permissions
  82. // [luid] - LUID
  83. // [pdfb] - Basis
  84. // [pdfn] - name
  85. // [cTransactedDepth] - Number of transacted parents
  86. // [pmsBase] - Base multistream
  87. //
  88. // History: 20-Jan-92 DrewB Created
  89. //
  90. //---------------------------------------------------------------
  91. CPubDocFile::CPubDocFile(CPubDocFile *pdfParent,
  92. PDocFile *pdf,
  93. DFLAGS const df,
  94. DFLUID luid,
  95. CDFBasis *pdfb,
  96. CDfName const *pdfn,
  97. UINT cTransactedDepth,
  98. CMStream *pmsBase)
  99. {
  100. olDebugOut((DEB_ITRACE, "In CPubDocFile::CPubDocFile("
  101. "%p, %p, %X, %lu, %p, %p, %lu, %p)\n",
  102. pdfParent, pdf, df, luid, pdfb, pdfn, cTransactedDepth,
  103. pmsBase));
  104. _pdfParent = P_TO_BP(CBasedPubDocFilePtr, pdfParent);
  105. _pdf = P_TO_BP(CBasedDocFilePtr, pdf);
  106. _df = df;
  107. _luid = luid;
  108. _pdfb = P_TO_BP(CBasedDFBasisPtr, pdfb);
  109. _cTransactedDepth = cTransactedDepth;
  110. _wFlags = 0;
  111. _pmsBase = P_TO_BP(CBasedMStreamPtr, pmsBase);
  112. _cReferences = 1;
  113. if (pdfn)
  114. {
  115. _dfn.Set(pdfn->GetLength(), pdfn->GetBuffer());
  116. }
  117. else
  118. {
  119. _dfn.Set((WORD)0, (BYTE *)NULL);
  120. }
  121. if (!IsRoot())
  122. _pdfParent->AddChild(this);
  123. _sig = CPUBDOCFILE_SIG;
  124. olDebugOut((DEB_ITRACE, "Out CPubDocFile::CPubDocFile\n"));
  125. }
  126. //+--------------------------------------------------------------
  127. //
  128. // Member: CPubDocFile::~CPubDocFile, public
  129. //
  130. // Synopsis: Destructor
  131. //
  132. // History: 23-Jan-92 DrewB Created
  133. //
  134. //---------------------------------------------------------------
  135. void CPubDocFile::vdtor(void)
  136. {
  137. olAssert(_cReferences == 0);
  138. if (_sig == CROOTPUBDOCFILE_SIG)
  139. {
  140. ((CRootPubDocFile *)this)->vdtor();
  141. return;
  142. }
  143. _sig = CPUBDOCFILE_SIGDEL;
  144. if (SUCCEEDED(CheckReverted()))
  145. {
  146. ChangeXs(DF_NOLUID, XSO_RELEASE);
  147. olAssert(!IsRoot());
  148. _pdfParent->ReleaseChild(this);
  149. _cilChildren.DeleteByName(NULL);
  150. if (_pdf)
  151. _pdf->Release();
  152. }
  153. delete this;
  154. }
  155. //+--------------------------------------------------------------
  156. //
  157. // Member: CPubDocFile::Release, public
  158. //
  159. // Synopsis: Releases resources for a CPubDocFile
  160. //
  161. // Returns: Appropriate status code
  162. //
  163. // History: 20-Jan-92 DrewB Created
  164. //
  165. //---------------------------------------------------------------
  166. void CPubDocFile::vRelease(void)
  167. {
  168. olDebugOut((DEB_ITRACE, "In CPubDocFile::Release()\n"));
  169. olAssert(_cReferences > 0);
  170. if (_pdf && !P_TRANSACTED(_df) && SUCCEEDED(CheckReverted()))
  171. {
  172. TIME_T tm;
  173. #ifdef ACCESSTIME
  174. olVerSucc(DfGetTOD(&tm));
  175. olVerSucc(_pdf->SetTime(WT_ACCESS, tm));
  176. #endif
  177. #ifdef NEWPROPS
  178. olVerSucc(FlushBufferedData(0));
  179. #endif
  180. if (IsDirty())
  181. {
  182. olVerSucc(DfGetTOD(&tm));
  183. olVerSucc(_pdf->SetTime(WT_MODIFICATION, tm));
  184. if (!IsRoot())
  185. _pdfParent->SetDirty();
  186. else
  187. {
  188. msfAssert(P_WRITE(_df) &&
  189. aMsg("Dirty & Direct but no write access"));
  190. }
  191. SetClean();
  192. }
  193. if (IsRoot() && P_WRITE(_df))
  194. {
  195. SCODE sc;
  196. sc = _pmsBase->Flush(0);
  197. #if DBG == 1
  198. if (FAILED(sc))
  199. {
  200. olDebugOut((DEB_ERROR,
  201. "ILockBytes::Flush() failed in release path "
  202. "with error %lx\n", sc));
  203. }
  204. #endif
  205. }
  206. }
  207. vDecRef();
  208. olDebugOut((DEB_ITRACE, "Out CPubDocFile::Release()\n"));
  209. }
  210. //+--------------------------------------------------------------
  211. //
  212. // Method: CPubDocFile::CopyLStreamToLStream, private
  213. //
  214. // Synopsis: Copies the contents of a stream to another stream
  215. //
  216. // Arguments: [plstFrom] - Stream to copy from
  217. // [plstTo] - Stream to copy to
  218. //
  219. // Returns: Appropriate status code
  220. //
  221. // History: 13-Sep-91 DrewB Created
  222. //
  223. //---------------------------------------------------------------
  224. SCODE CPubDocFile::CopyLStreamToLStream(ILockBytes *plstFrom,
  225. ILockBytes *plstTo)
  226. {
  227. BYTE *pbBuffer;
  228. ULONG cbBuffer = 0;
  229. SCODE sc;
  230. ULONG cbRead, cbWritten;
  231. ULARGE_INTEGER cbPos;
  232. STATSTG stat;
  233. ULONG cbBufferSave;
  234. GetSafeBuffer(CB_SMALLBUFFER, CB_LARGEBUFFER, &pbBuffer, &cbBuffer);
  235. olAssert((pbBuffer != NULL) && aMsg("Couldn't get scratch buffer"));
  236. // Set destination size for contiguity
  237. olHChk(plstFrom->Stat(&stat, STATFLAG_NONAME));
  238. olHChk(plstTo->SetSize(stat.cbSize));
  239. // Copy between streams
  240. ULISet32 (cbPos, 0);
  241. for (;;)
  242. {
  243. BOOL fRangeLocks = IsInRangeLocks (cbPos.QuadPart, cbBuffer);
  244. if (fRangeLocks)
  245. {
  246. ULONG ulRangeLocksBegin = OLOCKREGIONEND_SECTORALIGNED;
  247. // For unbuffered I/O, make sure we skip a whole page
  248. cbBufferSave = cbBuffer;
  249. ulRangeLocksBegin -= (_pdfb->GetOpenFlags() & DF_LARGE) ?
  250. CB_PAGEBUFFER : HEADERSIZE;
  251. cbBuffer = ulRangeLocksBegin - cbPos.LowPart;
  252. }
  253. cbWritten = 0;
  254. if (cbBuffer > 0)
  255. {
  256. olHChk(plstFrom->ReadAt(cbPos, pbBuffer, cbBuffer, &cbRead));
  257. if (cbRead == 0) // EOF
  258. break;
  259. olHChk(plstTo->WriteAt(cbPos, pbBuffer, cbRead, &cbWritten));
  260. if (cbRead != cbWritten)
  261. olErr(EH_Err, STG_E_WRITEFAULT);
  262. }
  263. if (fRangeLocks)
  264. {
  265. cbBuffer = cbBufferSave;
  266. cbWritten = cbBuffer;
  267. }
  268. cbPos.QuadPart += cbWritten;
  269. }
  270. // Fall through
  271. EH_Err:
  272. FreeBuffer(pbBuffer);
  273. return sc;
  274. }
  275. //+-------------------------------------------------------------------------
  276. //
  277. // Method: CPubDocFile::PrepareForOverwrite, private
  278. //
  279. // Synopsis: Make sure that there is enough space to do a commit
  280. // when the overwrite flag has been specified.
  281. //
  282. // Arguments: None.
  283. //
  284. // Returns: S_OK if call completed OK.
  285. //
  286. // History: 08-Jul-92 PhilipLa Created.
  287. //
  288. //--------------------------------------------------------------------------
  289. SCODE CPubDocFile::PrepareForOverwrite(void)
  290. {
  291. SCODE sc;
  292. #ifdef LARGE_DOCFILE
  293. ULONGLONG ulSize;
  294. #else
  295. ULONG ulSize;
  296. #endif
  297. ULARGE_INTEGER ulNewSize;
  298. olChk(GetCommitSize(&ulSize));
  299. ulNewSize.QuadPart = ulSize;
  300. if (P_INDEPENDENT(_df))
  301. {
  302. STATSTG statOrig;
  303. olHChk(_pdfb->GetOriginal()->Stat(&statOrig, STATFLAG_NONAME));
  304. olAssert(ULIGetHigh(statOrig.cbSize) == 0);
  305. if (ulNewSize.QuadPart > statOrig.cbSize.QuadPart)
  306. {
  307. olHChk(_pdfb->GetOriginal()->SetSize(ulNewSize));
  308. }
  309. }
  310. sc = DfGetScode(_pmsBase->GetILB()->SetSize(ulNewSize));
  311. // Fall through
  312. EH_Err:
  313. olDebugOut((DEB_ITRACE,"Out CPubDocFile::PrepareForOverwrite() =>"
  314. "%lu\n", sc));
  315. return sc;
  316. }
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Member: CPubDocFile::GetCommitSize, public
  320. //
  321. // Synopsis: Get the total size needed to commit the current docfile
  322. // with overwrite permissions.
  323. //
  324. // Arguments: [pulSize] -- Return location for size
  325. //
  326. // Returns: Appropriate status code
  327. //
  328. // Algorithm: For each Transaction Set Member call GetCommitInfo()
  329. // 1) If Tset member is a Docfile, then GetCommitInfo
  330. // returns number of deleted entries and number of
  331. // newly created entries.
  332. // 2) If Tset member is a stream, GetCommitInfo returns
  333. // current size and size of base.
  334. // Determine the number of DirSectors needed to handle
  335. // newly created entries.
  336. // Determine number of data sectors needed to hold new
  337. // stream info.
  338. // Determine number of fat sectors needed to hold new
  339. // data and dir sectors.
  340. // Determine number of DI Fat sectors needed to hold new
  341. // fat sectors.
  342. // Add size of new sectors to the current size of the
  343. // base and return that value.
  344. //
  345. // History: 15-Jun-93 PhilipLa Created
  346. //
  347. //----------------------------------------------------------------------------
  348. #ifdef LARGE_DOCFILE
  349. SCODE CPubDocFile::GetCommitSize(ULONGLONG *pulSize)
  350. #else
  351. SCODE CPubDocFile::GetCommitSize(ULONG *pulSize)
  352. #endif
  353. {
  354. SCODE sc;
  355. PTSetMember *ptsm;
  356. ULONG cDirEntries = 0;
  357. ULONG cNewSectors = 0;
  358. ULONG cMiniSectors = 0;
  359. ULONG cMiniFatSectors;
  360. ULONG cFatSectors = 0;
  361. ULONG cFatLast;
  362. ULONG cDIFatSectors = 0;
  363. olDebugOut((DEB_ITRACE,"In CPubDocFile::PrepareForOverwrite()\n"));
  364. //Bytes per sector
  365. ULONG cbSect = _pmsBase->GetSectorSize();
  366. if (!(_wFlags & PF_PREPARED))
  367. {
  368. //DirEntries per sector
  369. ULONG cdsSect = cbSect / sizeof(CDirEntry);
  370. //Fat entries per sector
  371. ULONG cfsSect = cbSect / sizeof(SECT);
  372. //Minisectors per sector
  373. ULONG cmsSect = cbSect / MINISECTORSIZE;
  374. #ifdef LARGE_STREAMS
  375. ULONGLONG ulRet1 = 0, ulRet2 = 0;
  376. #else
  377. ULONG ulRet1, ulRet2;
  378. #endif
  379. for (ptsm = _tss.GetHead(); ptsm; ptsm = ptsm->GetNext())
  380. {
  381. ptsm->GetCommitInfo(&ulRet1, &ulRet2);
  382. switch(REAL_STGTY(ptsm->ObjectType()))
  383. {
  384. case STGTY_STORAGE:
  385. if (ulRet2 < ulRet1)
  386. {
  387. cDirEntries += (ULONG)(ulRet1 - ulRet2);
  388. }
  389. break;
  390. case STGTY_STREAM:
  391. //If new size is larger than old...
  392. if (ulRet2 > ulRet1)
  393. {
  394. if (ulRet2 < MINISTREAMSIZE)
  395. {
  396. cMiniSectors += (ULONG)(((ulRet2 + MINISECTORSIZE - 1)
  397. / MINISECTORSIZE) -
  398. ((ulRet1 + MINISECTORSIZE - 1)
  399. / MINISECTORSIZE));
  400. }
  401. else
  402. {
  403. ULONG csectOld = (ULONG)((ulRet1 + cbSect - 1)/cbSect);
  404. ULONG csectNew = (ULONG)((ulRet2 + cbSect - 1)/cbSect);
  405. cNewSectors += (csectNew - csectOld);
  406. }
  407. }
  408. break;
  409. default:
  410. olAssert(!aMsg("Unknown pstm object type"));
  411. break;
  412. }
  413. }
  414. cNewSectors += (cDirEntries + cdsSect - 1) / cdsSect;
  415. cMiniFatSectors = ((cMiniSectors + cfsSect - 1) / cfsSect);
  416. cNewSectors += cMiniFatSectors + ((cMiniSectors + cmsSect -1) / cmsSect);
  417. do
  418. {
  419. cFatLast = cFatSectors;
  420. cFatSectors = (cNewSectors + cDIFatSectors + cFatSectors + cbSect - 1)
  421. / cbSect;
  422. cDIFatSectors = (cFatSectors + cfsSect - 1) / cfsSect;
  423. }
  424. while (cFatLast != cFatSectors);
  425. cNewSectors += cFatSectors + cDIFatSectors;
  426. }
  427. STATSTG stat;
  428. olHChk(_pmsBase->GetILB()->Stat(&stat, STATFLAG_NONAME));
  429. #ifdef LARGE_DOCFILE
  430. *pulSize = stat.cbSize.QuadPart + cNewSectors * cbSect;
  431. #else
  432. *pulSize = stat.cbSize.LowPart + cNewSectors * cbSect;
  433. #endif
  434. EH_Err:
  435. return sc;
  436. }
  437. //+--------------------------------------------------------------
  438. //
  439. // Member: CPubDocFile::Commit, public
  440. //
  441. // Synopsis: Commits transacted changes
  442. //
  443. // Arguments: [dwFlags] - DFC_*
  444. //
  445. // Returns: Appropriate status code
  446. //
  447. // History: 20-Jan-92 DrewB Created
  448. //
  449. //---------------------------------------------------------------
  450. SCODE CPubDocFile::Commit(DWORD const dwFlags)
  451. {
  452. SCODE sc=S_OK;
  453. #ifndef COORD
  454. TIME_T tm;
  455. PTSetMember *ptsm;
  456. ULONG ulLock = 0;
  457. DFSIGNATURE sigMSF;
  458. BOOL fFlush = FLUSH_CACHE(dwFlags);
  459. olDebugOut((DEB_ITRACE, "In CPubDocFile::Commit:%p(%lX)\n",
  460. this, dwFlags));
  461. olChk(CheckReverted());
  462. if (!P_WRITE(_df))
  463. olErr(EH_Err, STG_E_ACCESSDENIED);
  464. if (IsDirty())
  465. {
  466. olChk(DfGetTOD(&tm));
  467. olChk(_pdf->SetTime(WT_MODIFICATION, tm));
  468. }
  469. if (P_NOSNAPSHOT(_df) && (dwFlags & STGC_OVERWRITE))
  470. {
  471. olErr(EH_Err, STG_E_INVALIDFLAG);
  472. }
  473. #ifdef ACCESSTIME
  474. olChk(DfGetTOD(&tm));
  475. olChk(_pdf->SetTime(WT_ACCESS, tm));
  476. #endif
  477. #ifdef NEWPROPS
  478. olChk(FlushBufferedData(0));
  479. #endif
  480. if (!P_TRANSACTED(_df))
  481. {
  482. if (IsDirty())
  483. {
  484. if (!IsRoot())
  485. _pdfParent->SetDirty();
  486. SetClean();
  487. }
  488. if (_cTransactedDepth == 0)
  489. {
  490. if(STGC_CONSOLIDATE & dwFlags)
  491. sc = Consolidate(dwFlags);
  492. olChk(_pmsBase->Flush(fFlush));
  493. }
  494. return S_OK;
  495. }
  496. olAssert(GetTransactedDepth() > 0 &&
  497. aMsg("Transaction depth/flags conflict"));
  498. if (GetTransactedDepth() == 1)
  499. {
  500. // A transacted depth of 1 means this is the lowest transacted
  501. // level and committed changes will go into the real file,
  502. // so do all the special contents protection and locking
  503. if (_pdfb->GetOrigLockFlags() & LOCK_ONLYONCE)
  504. olChk(WaitForAccess(_pdfb->GetOriginal(), DF_WRITE,
  505. &ulLock));
  506. olChkTo(EH_GetAccess, _pmsBase->BeginCopyOnWrite(dwFlags));
  507. if (dwFlags & STGC_OVERWRITE)
  508. {
  509. olChkTo(EH_COW, PrepareForOverwrite());
  510. }
  511. if (P_INDEPENDENT(_df) || P_NOSNAPSHOT(_df))
  512. {
  513. if (_sigMSF == DF_INVALIDSIGNATURE)
  514. {
  515. if ((dwFlags & STGC_ONLYIFCURRENT) &&
  516. DllIsMultiStream(_pdfb->GetOriginal()) == S_OK)
  517. olErr(EH_COW, STG_E_NOTCURRENT);
  518. }
  519. else
  520. {
  521. olChkTo(EH_COW, DllGetCommitSig(_pdfb->GetOriginal(),
  522. &sigMSF));
  523. if (dwFlags & STGC_ONLYIFCURRENT)
  524. if (sigMSF != _sigMSF)
  525. olErr(EH_COW, STG_E_NOTCURRENT);
  526. }
  527. }
  528. }
  529. for (ptsm = _tss.GetHead(); ptsm; ptsm = ptsm->GetNext())
  530. if ((ptsm->GetFlags() & XSM_DELETED) == 0)
  531. olChkTo(EH_NoCommit, ptsm->BeginCommit(dwFlags));
  532. // 10/02/92 - To handle low disk space situations well, we
  533. // preallocate the space we'll need to copy (when independent).
  534. STATSTG statBase, statOrig;
  535. if (P_INDEPENDENT(_df))
  536. {
  537. // With DELAYFLUSH we can't be sure of the size
  538. // of the file until EndCopyOnWrite, but we do
  539. // know that the file won't grow so this is safe
  540. olHChkTo(EH_NoCommit, _pdfb->GetBase()->Stat(&statBase,
  541. STATFLAG_NONAME));
  542. olAssert(ULIGetHigh(statBase.cbSize) == 0);
  543. olHChkTo(EH_NoCommit, _pdfb->GetOriginal()->Stat(&statOrig,
  544. STATFLAG_NONAME));
  545. olAssert(ULIGetHigh(statOrig.cbSize) == 0);
  546. if (ULIGetLow(statBase.cbSize) > ULIGetLow(statOrig.cbSize))
  547. {
  548. olHChkTo(EH_NoCommit,
  549. _pdfb->GetOriginal()->SetSize(statBase.cbSize));
  550. }
  551. }
  552. //End of phase 1 of commit.
  553. if (GetTransactedDepth() == 1)
  554. {
  555. olChkTo(EH_ResetSize,
  556. _pmsBase->EndCopyOnWrite(dwFlags, DF_COMMIT));
  557. }
  558. // Move to end of list
  559. for (ptsm = _tss.GetHead();
  560. ptsm && ptsm->GetNext();
  561. ptsm = ptsm->GetNext())
  562. NULL;
  563. // End commits in reverse
  564. for (; ptsm; ptsm = ptsm->GetPrev())
  565. ptsm->EndCommit(DF_COMMIT);
  566. //
  567. // Do consolidation here, before we might
  568. // copy the snapshot back to the original file.
  569. //
  570. if(STGC_CONSOLIDATE & dwFlags)
  571. {
  572. sc = Consolidate(dwFlags);
  573. }
  574. //
  575. // If this is a root storage in transacted w/ snapshot mode.
  576. // Copy the snapshot back to the original file. Only the root
  577. // transacted storage can be intependent so transacted substorages
  578. // of direct mode opens do not qualify.
  579. //
  580. if (P_INDEPENDENT(_df))
  581. {
  582. SCODE scTemp;
  583. // Not robust against power failure!
  584. // We made sure we had enough disk space by presetting the larger
  585. // size. But should the write fail part way through for other
  586. // reasons then we have lost the original file!
  587. // To do this robustly we could "commit" the whole base file to the
  588. // end of the original file. Then consolidate the result.
  589. // But... we don't. Perhaps we could revisit this later.
  590. olVerSucc(scTemp = CopyLStreamToLStream(_pdfb->GetBase(),
  591. _pdfb->GetOriginal()));
  592. olVerSucc(_pdfb->GetOriginal()->Flush());
  593. }
  594. if (P_INDEPENDENT(_df) || P_NOSNAPSHOT(_df))
  595. {
  596. if (_sigMSF == DF_INVALIDSIGNATURE)
  597. {
  598. olVerSucc(DllGetCommitSig(_pdfb->GetOriginal(), &_sigMSF));
  599. }
  600. else
  601. {
  602. _sigMSF = sigMSF+1;
  603. olVerSucc(DllSetCommitSig(_pdfb->GetOriginal(), _sigMSF));
  604. }
  605. }
  606. if (ulLock != 0)
  607. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  608. // Dirty all parents up to the next transacted storage
  609. if (IsDirty())
  610. {
  611. if (!IsRoot())
  612. _pdfParent->SetDirty();
  613. SetClean();
  614. }
  615. olDebugOut((DEB_ITRACE, "Out CTransactionLevel::Commit\n"));
  616. #if DBG == 1
  617. VerifyXSMemberBases();
  618. #endif
  619. _wFlags = (_wFlags & ~PF_PREPARED);
  620. if (_sig == CROOTPUBDOCFILE_SIG)
  621. {
  622. ((CRootPubDocFile *)this)->CommitTimestamps(dwFlags);
  623. }
  624. return sc;
  625. EH_ResetSize:
  626. if (P_INDEPENDENT(_df) &&
  627. (ULIGetLow(statBase.cbSize) > ULIGetLow(statOrig.cbSize)))
  628. {
  629. _pdfb->GetOriginal()->SetSize(statOrig.cbSize);
  630. }
  631. EH_NoCommit:
  632. // Move to end of list
  633. for (ptsm = _tss.GetHead();
  634. ptsm && ptsm->GetNext();
  635. ptsm = ptsm->GetNext())
  636. NULL;
  637. // Abort commits in reverse
  638. for (; ptsm; ptsm = ptsm->GetPrev())
  639. ptsm->EndCommit(DF_ABORT);
  640. EH_COW:
  641. if (GetTransactedDepth() == 1)
  642. {
  643. olVerSucc(_pmsBase->EndCopyOnWrite(dwFlags, DF_ABORT));
  644. }
  645. EH_GetAccess:
  646. if (ulLock != 0)
  647. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  648. EH_Err:
  649. return sc;
  650. #else //COORD
  651. ULONG ulLock = 0;
  652. DFSIGNATURE sigMSF;
  653. ULONG cbSizeBase;
  654. ULONG cbSizeOrig;
  655. olDebugOut((DEB_ITRACE, "In CPubDocFile::Commit:%p(%lX)\n",
  656. this, dwFlags));
  657. sc = CommitPhase1(dwFlags, &ulLock, &sigMSF, &cbSizeBase, &cbSizeOrig);
  658. //Only do phase 2 if we're transacted and phase 1 succeeded.
  659. if (P_TRANSACTED(_df) && SUCCEEDED(sc))
  660. {
  661. sc = CommitPhase2(dwFlags,
  662. TRUE,
  663. ulLock,
  664. sigMSF,
  665. cbSizeBase,
  666. cbSizeOrig);
  667. }
  668. olDebugOut((DEB_ITRACE, "Out CPubDocFile::Commit -> %lX\n", sc));
  669. return sc;
  670. #endif //!COORD
  671. }
  672. //+--------------------------------------------------------------
  673. //
  674. // Member: CPubDocFile::Consolidate, private
  675. //
  676. // Synopsis: Consolidates a Docfile by moving sectors down
  677. // and filling in free space holes in the file.
  678. //
  679. // Arguments:
  680. //
  681. // Returns: Appropriate status code
  682. //
  683. // History: 10-Feb-1997 BChapman Created
  684. //
  685. //---------------------------------------------------------------
  686. SCODE CPubDocFile::Consolidate(DWORD dwFlags)
  687. {
  688. SCODE sc;
  689. //
  690. // Consolidation only makes sense when we are writting to the
  691. // real file, so we only consolidate on top level commits.
  692. //
  693. if(GetTransactedDepth() > 1)
  694. {
  695. return STG_S_CANNOTCONSOLIDATE;
  696. }
  697. //
  698. // Consolidating NoScratch is not supported.
  699. //
  700. if(P_NOSCRATCH(_df))
  701. {
  702. return STG_S_CANNOTCONSOLIDATE;
  703. }
  704. //
  705. // We can only Considate if there is one "seperate" open of the
  706. // file. Marshaled opens are OK.
  707. //
  708. if(P_NOSNAPSHOT(_df))
  709. {
  710. sc = IsSingleWriter();
  711. if (sc != S_OK)
  712. {
  713. return STG_S_MULTIPLEOPENS;
  714. }
  715. }
  716. //
  717. // Make A backup copy of the FAT, header, etc...
  718. // Get ready to try to make some revertable changes to the file.
  719. //
  720. olChk(_pmsBase->BeginCopyOnWrite(dwFlags));
  721. //
  722. // Pack the file down.
  723. //
  724. olChkTo(EH_Abort, _pmsBase->Consolidate());
  725. EmptyCache();
  726. //
  727. // Finally commit the consolidation.
  728. //
  729. olChkTo(EH_Abort, _pmsBase->EndCopyOnWrite(dwFlags, DF_COMMIT));
  730. return S_OK;
  731. EH_Abort:
  732. EmptyCache();
  733. olVerSucc(_pmsBase->EndCopyOnWrite(dwFlags, DF_ABORT));
  734. EH_Err:
  735. return STG_S_CONSOLIDATIONFAILED;
  736. }
  737. //+--------------------------------------------------------------
  738. //
  739. // Member: CPubDocFile::IsSingleWriter, private
  740. //
  741. // Synopsis: Compare the number of locks on the file with the number
  742. // of Contexts that have this file open.
  743. //
  744. // Arguments:
  745. //
  746. // Returns:
  747. //
  748. // History: 10-Feb-1997 BChapman Created
  749. //
  750. //---------------------------------------------------------------
  751. SCODE CPubDocFile::IsSingleWriter(void)
  752. {
  753. ILockBytes *ilb;
  754. SCODE sc;
  755. ULONG i, cWriteLocks=0;
  756. ULARGE_INTEGER uliOffset, ulicbLength;
  757. ilb = _pdfb->GetBase();
  758. ulicbLength.QuadPart = 1;
  759. for (i = 0; i < COPENLOCKS; i++)
  760. {
  761. uliOffset.QuadPart = (OOPENWRITELOCK+i);
  762. if(FAILED(ilb->LockRegion(uliOffset, ulicbLength, LOCK_ONLYONCE)))
  763. {
  764. ++cWriteLocks;
  765. }
  766. else
  767. {
  768. ilb->UnlockRegion(uliOffset, ulicbLength, LOCK_ONLYONCE);
  769. }
  770. }
  771. if(_pdfb->CountContexts() == cWriteLocks)
  772. return S_OK;
  773. return S_FALSE;
  774. }
  775. //+--------------------------------------------------------------
  776. //
  777. // Member: CPubDocFile::DestroyEntry, public
  778. //
  779. // Synopsis: Permanently deletes an element of a DocFile
  780. //
  781. // Arguments: [pdfnName] - Name of element
  782. // [fClean] - Whether this was invoked as cleanup or not
  783. //
  784. // Returns: Appropriate status code
  785. //
  786. // History: 20-Jan-92 DrewB Created
  787. //
  788. //---------------------------------------------------------------
  789. SCODE CPubDocFile::DestroyEntry(CDfName const *pdfnName,
  790. BOOL fClean)
  791. {
  792. SCODE sc;
  793. olDebugOut((DEB_ITRACE, "In CPubDocFile::DestroyEntry:%p(%ws, %d)\n",
  794. this, pdfnName, fClean));
  795. olChk(CheckReverted());
  796. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  797. olErr(EH_Err, STG_E_ACCESSDENIED);
  798. olChk(_pdf->DestroyEntry(pdfnName, fClean));
  799. _cilChildren.DeleteByName(pdfnName);
  800. SetDirty();
  801. olDebugOut((DEB_ITRACE, "Out CPubDocFile::DestroyEntry\n"));
  802. // Fall through
  803. EH_Err:
  804. return sc;
  805. }
  806. //+--------------------------------------------------------------
  807. //
  808. // Member: CPubDocFile::RenameEntry, public
  809. //
  810. // Synopsis: Renames an element of a DocFile
  811. //
  812. // Arguments: [pdfnName] - Current name
  813. // [pdfnNewName] - New name
  814. //
  815. // Returns: Appropriate status code
  816. //
  817. // History: 20-Jan-92 DrewB Created
  818. // 28-Oct-92 AlexT Add names to XSM's
  819. // 09-Aug-93 AlexT Disallow renames of open children
  820. //
  821. //---------------------------------------------------------------
  822. SCODE CPubDocFile::RenameEntry(CDfName const *pdfnName,
  823. CDfName const *pdfnNewName)
  824. {
  825. SCODE sc;
  826. olDebugOut((DEB_ITRACE, "In CPubDocFile::RenameEntry(%ws, %ws)\n",
  827. pdfnName, pdfnNewName));
  828. olChk(CheckReverted());
  829. if (FAILED(_cilChildren.IsDenied(pdfnName, DF_WRITE | DF_DENYALL, _df)))
  830. {
  831. // Translate all denial errors to STG_E_ACCESSDENIED
  832. sc = STG_E_ACCESSDENIED;
  833. }
  834. else
  835. {
  836. sc = _pdf->RenameEntry(pdfnName, pdfnNewName);
  837. if (SUCCEEDED(sc))
  838. {
  839. SetDirty();
  840. }
  841. }
  842. olDebugOut((DEB_ITRACE, "Out CPubDocFile::RenameEntry\n"));
  843. // Fall through
  844. EH_Err:
  845. return sc;
  846. }
  847. //+--------------------------------------------------------------
  848. //
  849. // Member: CPubDocFile::CreateDocFile, public
  850. //
  851. // Synopsis: Creates an embedded DocFile
  852. //
  853. // Arguments: [pdfnName] - Name
  854. // [df] - Permissions
  855. // [ppdfDocFile] - New DocFile return
  856. //
  857. // Returns: Appropriate status code
  858. //
  859. // Modifies: [ppdfDocFile]
  860. //
  861. // History: 20-Jan-92 DrewB Created
  862. //
  863. //---------------------------------------------------------------
  864. SCODE CPubDocFile::CreateDocFile(CDfName const *pdfnName,
  865. DFLAGS const df,
  866. CPubDocFile **ppdfDocFile)
  867. {
  868. PDocFile *pdf;
  869. SCODE sc;
  870. CWrappedDocFile *pdfWrapped = NULL;
  871. SEntryBuffer eb;
  872. UINT cNewTDepth;
  873. olDebugOut((DEB_ITRACE, "In CPubDocFile::CreateDocFile:%p("
  874. "%ws, %X, %p)\n", this, pdfnName, df, ppdfDocFile));
  875. olChk(CheckReverted());
  876. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  877. olErr(EH_Err, STG_E_ACCESSDENIED);
  878. olChk(_cilChildren.IsDenied(pdfnName, df, _df));
  879. olChk(CDocFile::Reserve(1, BP_TO_P(CDFBasis *, _pdfb)));
  880. cNewTDepth = _cTransactedDepth+(P_TRANSACTED(df) ? 1 : 0);
  881. olChkTo(EH_DirectReserve,
  882. CWrappedDocFile::Reserve(cNewTDepth, BP_TO_P(CDFBasis *, _pdfb)));
  883. olChkTo(EH_Reserve, _pdf->CreateDocFile(pdfnName, df, DF_NOLUID,
  884. &pdf));
  885. // As soon as we have a base we dirty ourself (in case
  886. // we get an error later) so that we'll flush properly.
  887. SetDirty();
  888. eb.luid = pdf->GetLuid();
  889. olAssert(eb.luid != DF_NOLUID && aMsg("DocFile id is DF_NOLUID!"));
  890. olMemTo(EH_pdf,
  891. *ppdfDocFile = new (_pmsBase->GetMalloc())
  892. CPubDocFile(this, pdf, df, eb.luid,
  893. BP_TO_P(CDFBasis *, _pdfb),
  894. pdfnName, cNewTDepth,
  895. BP_TO_P(CMStream *, _pmsBase)));
  896. if (P_TRANSACTED(df))
  897. {
  898. pdfWrapped = new(BP_TO_P(CDFBasis *, _pdfb))
  899. CWrappedDocFile(pdfnName, eb.luid, df,
  900. BP_TO_P(CDFBasis *, _pdfb), *ppdfDocFile);
  901. olAssert(pdfWrapped != NULL && aMsg("Reserved DocFile not found"));
  902. olChkTo(EH_pdfWrapped,
  903. pdfWrapped->Init(pdf));
  904. (*ppdfDocFile)->AddXSMember(NULL, pdfWrapped, eb.luid);
  905. (*ppdfDocFile)->SetDF(pdfWrapped);
  906. }
  907. olDebugOut((DEB_ITRACE, "Out CPubDocFile::CreateDocFile\n"));
  908. return S_OK;
  909. EH_pdfWrapped:
  910. delete pdfWrapped;
  911. (*ppdfDocFile)->vRelease();
  912. goto EH_Destroy;
  913. EH_pdf:
  914. pdf->Release();
  915. if (P_TRANSACTED(df))
  916. CWrappedDocFile::Unreserve(1, BP_TO_P(CDFBasis *, _pdfb));
  917. EH_Destroy:
  918. olVerSucc(_pdf->DestroyEntry(pdfnName, TRUE));
  919. return sc;
  920. EH_Reserve:
  921. CWrappedDocFile::Unreserve(cNewTDepth, BP_TO_P(CDFBasis *, _pdfb));
  922. EH_DirectReserve:
  923. CDocFile::Unreserve(1, BP_TO_P(CDFBasis *, _pdfb));
  924. EH_Err:
  925. return sc;
  926. }
  927. //+--------------------------------------------------------------
  928. //
  929. // Member: CPubDocFile::GetDocFile, public
  930. //
  931. // Synopsis: Gets an existing embedded DocFile
  932. //
  933. // Arguments: [pdfnName] - Name
  934. // [df] - Permissions
  935. // [ppdfDocFile] - DocFile return
  936. //
  937. // Returns: Appropriate status code
  938. //
  939. // Modifies: [ppdfDocFile]
  940. //
  941. // History: 20-Jan-92 DrewB Created
  942. //
  943. //---------------------------------------------------------------
  944. SCODE CPubDocFile::GetDocFile(CDfName const *pdfnName,
  945. DFLAGS const df,
  946. CPubDocFile **ppdfDocFile)
  947. {
  948. PDocFile *pdf;
  949. SCODE sc;
  950. CWrappedDocFile *pdfWrapped;
  951. SEntryBuffer eb;
  952. UINT cNewTDepth;
  953. olDebugOut((DEB_ITRACE, "In CPubDocFile::GetDocFile:%p("
  954. "%ws, %X, %p)\n",
  955. this, pdfnName, df, ppdfDocFile));
  956. olChk(CheckReverted());
  957. if (!P_READ(_df))
  958. olErr(EH_Err, STG_E_ACCESSDENIED);
  959. // Check to see if an instance with DENY_* exists
  960. olChk(_cilChildren.IsDenied(pdfnName, df, _df));
  961. olChk(_pdf->GetDocFile(pdfnName, df, &pdf));
  962. eb.luid = pdf->GetLuid();
  963. olAssert(eb.luid != DF_NOLUID && aMsg("DocFile id is DF_NOLUID!"));
  964. cNewTDepth = _cTransactedDepth+(P_TRANSACTED(df) ? 1 : 0);
  965. olMemTo(EH_pdf,
  966. *ppdfDocFile = new (_pmsBase->GetMalloc())
  967. CPubDocFile(this, pdf, df, eb.luid,
  968. BP_TO_P(CDFBasis *, _pdfb),
  969. pdfnName, cNewTDepth,
  970. BP_TO_P(CMStream *, _pmsBase)));
  971. if (P_TRANSACTED(df))
  972. {
  973. olMemTo(EH_ppdf, pdfWrapped = new(_pmsBase->GetMalloc())
  974. CWrappedDocFile(pdfnName, eb.luid, df,
  975. BP_TO_P(CDFBasis *, _pdfb), *ppdfDocFile));
  976. olChkTo(EH_pdfWrapped,
  977. pdfWrapped->Init(pdf));
  978. (*ppdfDocFile)->AddXSMember(NULL, pdfWrapped, eb.luid);
  979. (*ppdfDocFile)->SetDF(pdfWrapped);
  980. }
  981. olDebugOut((DEB_ITRACE, "Out CPubDocFile::GetDocFile\n"));
  982. return S_OK;
  983. EH_pdfWrapped:
  984. delete pdfWrapped;
  985. EH_ppdf:
  986. (*ppdfDocFile)->vRelease();
  987. return sc;
  988. EH_pdf:
  989. pdf->Release();
  990. EH_Err:
  991. return sc;
  992. }
  993. //+--------------------------------------------------------------
  994. //
  995. // Member: CPubDocFile::CreateStream, public
  996. //
  997. // Synopsis: Creates a stream
  998. //
  999. // Arguments: [pdfnName] - Name
  1000. // [df] - Permissions
  1001. // [ppdstStream] - Stream return
  1002. //
  1003. // Returns: Appropriate status code
  1004. //
  1005. // Modifies: [ppdstStream]
  1006. //
  1007. // History: 20-Jan-92 DrewB Created
  1008. //
  1009. //---------------------------------------------------------------
  1010. SCODE CPubDocFile::CreateStream(CDfName const *pdfnName,
  1011. DFLAGS const df,
  1012. CPubStream **ppdstStream)
  1013. {
  1014. PSStream *psst;
  1015. SCODE sc;
  1016. SEntryBuffer eb;
  1017. olDebugOut((DEB_ITRACE, "In CPubDocFile::CreateStream:%p("
  1018. "%ws, %X, %p)\n", this, pdfnName, df, ppdstStream));
  1019. olChk(CheckReverted());
  1020. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1021. olErr(EH_Err, STG_E_ACCESSDENIED);
  1022. olChk(_cilChildren.IsDenied(pdfnName, df, _df));
  1023. olChk(CDirectStream::Reserve(1, BP_TO_P(CDFBasis *, _pdfb)));
  1024. olChkTo(EH_DirectReserve,
  1025. CTransactedStream::Reserve(_cTransactedDepth,
  1026. BP_TO_P(CDFBasis *, _pdfb)));
  1027. olChkTo(EH_Reserve,
  1028. _pdf->CreateStream(pdfnName, df, DF_NOLUID, &psst));
  1029. // As soon as we have a base we dirty ourself (in case
  1030. // we get an error later) so that we'll flush properly.
  1031. SetDirty();
  1032. eb.luid = psst->GetLuid();
  1033. olAssert(eb.luid != DF_NOLUID && aMsg("Stream id is DF_NOLUID!"));
  1034. olMemTo(EH_Create, *ppdstStream = new (_pmsBase->GetMalloc())
  1035. CPubStream(this, df, pdfnName));
  1036. (*ppdstStream)->Init(psst, eb.luid);
  1037. olDebugOut((DEB_ITRACE, "Out CPubDocFile::CreateStream\n"));
  1038. return S_OK;
  1039. EH_Create:
  1040. psst->Release();
  1041. olVerSucc(_pdf->DestroyEntry(pdfnName, TRUE));
  1042. return sc;
  1043. EH_Reserve:
  1044. CTransactedStream::Unreserve(_cTransactedDepth,
  1045. BP_TO_P(CDFBasis *, _pdfb));
  1046. EH_DirectReserve:
  1047. CDirectStream::Unreserve(1, BP_TO_P(CDFBasis *, _pdfb));
  1048. EH_Err:
  1049. return sc;
  1050. }
  1051. //+--------------------------------------------------------------
  1052. //
  1053. // Member: CPubDocFile::GetStream, public
  1054. //
  1055. // Synopsis: Gets an existing stream
  1056. //
  1057. // Arguments: [pdfnName] - Name
  1058. // [df] - Permissions
  1059. // [ppdstStream] - Stream return
  1060. //
  1061. // Returns: Appropriate status code
  1062. //
  1063. // Modifies: [ppdstStream]
  1064. //
  1065. // History: 20-Jan-92 DrewB Created
  1066. //
  1067. //---------------------------------------------------------------
  1068. SCODE CPubDocFile::GetStream(CDfName const *pdfnName,
  1069. DFLAGS const df,
  1070. CPubStream **ppdstStream)
  1071. {
  1072. PSStream *psst;
  1073. SCODE sc;
  1074. SEntryBuffer eb;
  1075. olDebugOut((DEB_ITRACE, "In CPubDocFile::GetStream(%ws, %X, %p)\n",
  1076. pdfnName, df, ppdstStream));
  1077. olChk(CheckReverted());
  1078. if (!P_READ(_df))
  1079. olErr(EH_Err, STG_E_ACCESSDENIED);
  1080. // Check permissions
  1081. olChk(_cilChildren.IsDenied(pdfnName, df, _df));
  1082. olChk(_pdf->GetStream(pdfnName, df, &psst));
  1083. eb.luid = psst->GetLuid();
  1084. olAssert(eb.luid != DF_NOLUID && aMsg("Stream id is DF_NOLUID!"));
  1085. olMemTo(EH_Get, *ppdstStream = new (_pmsBase->GetMalloc())
  1086. CPubStream(this, df, pdfnName));
  1087. (*ppdstStream)->Init(psst, eb.luid);
  1088. olDebugOut((DEB_ITRACE, "Out CPubDocFile::GetStream\n"));
  1089. return S_OK;
  1090. EH_Get:
  1091. psst->Release();
  1092. EH_Err:
  1093. return sc;
  1094. }
  1095. //+--------------------------------------------------------------
  1096. //
  1097. // Member: CPubDocFile::Stat, public
  1098. //
  1099. // Synopsis: Fills in a stat buffer
  1100. //
  1101. // Arguments: [pstatstg] - Buffer
  1102. // [grfStatFlag] - Stat flags
  1103. //
  1104. // Returns: Appropriate status code
  1105. //
  1106. // Modifies: [pstatstg]
  1107. //
  1108. // History: 24-Mar-92 DrewB Created
  1109. //
  1110. //---------------------------------------------------------------
  1111. SCODE CPubDocFile::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
  1112. {
  1113. SCODE sc;
  1114. if (_sig == CROOTPUBDOCFILE_SIG)
  1115. return ((CRootPubDocFile *)this)->Stat (pstatstg, grfStatFlag);
  1116. olDebugOut((DEB_ITRACE, "In CPubDocFile::Stat(%p, %lu)\n",
  1117. pstatstg, grfStatFlag));
  1118. olAssert(SUCCEEDED(VerifyStatFlag(grfStatFlag)));
  1119. olChk(CheckReverted());
  1120. pstatstg->pwcsName = NULL;
  1121. if ((grfStatFlag & STATFLAG_NONAME) == 0)
  1122. {
  1123. #ifdef COORD
  1124. if (P_COORD(_df))
  1125. {
  1126. olHChk(_pdfb->GetOriginal()->Stat((STATSTG *)pstatstg,
  1127. grfStatFlag));
  1128. }
  1129. else
  1130. #endif
  1131. {
  1132. olMem(pstatstg->pwcsName =
  1133. (WCHAR *)TaskMemAlloc(_dfn.GetLength()));
  1134. memcpy(pstatstg->pwcsName, _dfn.GetBuffer(), _dfn.GetLength());
  1135. }
  1136. }
  1137. olChk(_pdf->GetTime(WT_CREATION, &pstatstg->ctime));
  1138. olChk(_pdf->GetTime(WT_MODIFICATION, &pstatstg->mtime));
  1139. pstatstg->atime.dwLowDateTime = pstatstg->atime.dwHighDateTime = 0;
  1140. olChk(_pdf->GetClass(&pstatstg->clsid));
  1141. olChk(_pdf->GetStateBits(&pstatstg->grfStateBits));
  1142. olAssert(!IsRoot());
  1143. pstatstg->grfMode = DFlagsToMode(_df);
  1144. olDebugOut((DEB_ITRACE, "Out CPubDocFile::Stat\n"));
  1145. // Fall through
  1146. EH_Err:
  1147. return sc;
  1148. }
  1149. //+--------------------------------------------------------------
  1150. //
  1151. // Member: CPubDocFile::RevertFromAbove, public
  1152. //
  1153. // Synopsis: Parent has asked for reversion
  1154. //
  1155. // History: 29-Jan-92 DrewB Created
  1156. //
  1157. //---------------------------------------------------------------
  1158. void CPubDocFile::RevertFromAbove(void)
  1159. {
  1160. olDebugOut((DEB_ITRACE, "In CPubDocFile::RevertFromAbove:%p()\n", this));
  1161. _df |= DF_REVERTED;
  1162. _cilChildren.DeleteByName(NULL);
  1163. ChangeXs(DF_NOLUID, XSO_RELEASE);
  1164. _pdf->Release();
  1165. _pdf = NULL;
  1166. olDebugOut((DEB_ITRACE, "Out CPubDocFile::RevertFromAbove\n"));
  1167. }
  1168. //+--------------------------------------------------------------
  1169. //
  1170. // Member: CPubDocFile::FlushBufferedData, public
  1171. //
  1172. // Synopsis: Flush buffered data in any child streams.
  1173. //
  1174. // History: 5-May-1995 BillMo Created
  1175. //
  1176. //---------------------------------------------------------------
  1177. #ifdef NEWPROPS
  1178. SCODE CPubDocFile::FlushBufferedData(int recursionlevel)
  1179. {
  1180. SCODE sc;
  1181. olDebugOut((DEB_ITRACE, "In CPubDocFile::FlushBufferedData:%p()\n", this));
  1182. if ((recursionlevel == 0 && (_df & DF_TRANSACTED)) ||
  1183. (_df & DF_TRANSACTED) == 0)
  1184. {
  1185. sc = _cilChildren.FlushBufferedData(recursionlevel);
  1186. }
  1187. else
  1188. {
  1189. sc = S_OK;
  1190. }
  1191. olDebugOut((DEB_ITRACE, "Out CPubDocFile::FlushBufferedData\n"));
  1192. return sc;
  1193. }
  1194. #endif
  1195. //+--------------------------------------------------------------
  1196. //
  1197. // Member: CPubDocFile::ChangeXs, public
  1198. //
  1199. // Synopsis: Performs an operation on the XS
  1200. //
  1201. // Arguments: [luidTree] - LUID of tree or DF_NOLUID
  1202. // [dwOp] - Operation
  1203. //
  1204. // History: 30-Jan-92 DrewB Created
  1205. //
  1206. //---------------------------------------------------------------
  1207. void CPubDocFile::ChangeXs(DFLUID const luidTree,
  1208. DWORD const dwOp)
  1209. {
  1210. olAssert((dwOp == XSO_RELEASE) || (dwOp == XSO_REVERT));
  1211. PTSetMember *ptsmNext, *ptsmCur, *ptsmPrev;
  1212. for (ptsmNext = _tss.GetHead(); ptsmNext; )
  1213. {
  1214. ptsmCur = ptsmNext;
  1215. ptsmNext = ptsmCur->GetNext();
  1216. olAssert ((ptsmCur->GetName() != ptsmCur->GetTree()));
  1217. if (luidTree == DF_NOLUID || ptsmCur->GetName() == luidTree)
  1218. {
  1219. switch(dwOp)
  1220. {
  1221. case XSO_RELEASE:
  1222. ptsmPrev = ptsmCur->GetPrev();
  1223. _tss.RemoveMember(ptsmCur);
  1224. ptsmCur->Release();
  1225. if (ptsmPrev == NULL)
  1226. ptsmNext = _tss.GetHead();
  1227. else
  1228. ptsmNext = ptsmPrev->GetNext();
  1229. break;
  1230. case XSO_REVERT:
  1231. ptsmCur->Revert();
  1232. // Revert might have changed the next pointer
  1233. ptsmNext = ptsmCur->GetNext();
  1234. break;
  1235. }
  1236. }
  1237. else if (luidTree != DF_NOLUID && luidTree == ptsmCur->GetTree())
  1238. {
  1239. // This weirdness is necessary because ptsm will be
  1240. // deleted by the call to ChangeXs. Since ptsm->GetNext()
  1241. // could also be deleted, we would have no way to continue.
  1242. // ptsm->GetPrev() will never be deleted by the call to
  1243. // ChangeXs, since all children of a node appear _after_
  1244. // that node in the list. Therefore, ptsm->GetPrev()->GetNext()
  1245. // is the best place to resume the loop.
  1246. ptsmPrev = ptsmCur->GetPrev();
  1247. ChangeXs(ptsmCur->GetName(), dwOp);
  1248. if (ptsmPrev == NULL)
  1249. ptsmNext = _tss.GetHead();
  1250. else
  1251. ptsmNext = ptsmPrev->GetNext();
  1252. }
  1253. }
  1254. }
  1255. //+--------------------------------------------------------------
  1256. //
  1257. // Member: CPubDocFile::AddXSMember, public
  1258. //
  1259. // Synopsis: Adds an object to the XS
  1260. //
  1261. // Arguments: [ptsmRequestor] - Object requesting add or NULL if
  1262. // first addition
  1263. // [ptsmAdd] - Object to add
  1264. // [luid] - LUID of object
  1265. //
  1266. // History: 29-Jan-92 DrewB Created
  1267. //
  1268. //---------------------------------------------------------------
  1269. void CPubDocFile::AddXSMember(PTSetMember *ptsmRequestor,
  1270. PTSetMember *ptsmAdd,
  1271. DFLUID luid)
  1272. {
  1273. DFLUID luidTree;
  1274. ULONG ulLevel;
  1275. olDebugOut((DEB_ITRACE, "In CPubDocFile::AddXSMember:%p("
  1276. "%p, %p, %ld)\n", this, ptsmRequestor, ptsmAdd, luid));
  1277. if (ptsmRequestor == NULL)
  1278. {
  1279. // If we're starting the XS, this is a new TL and we have
  1280. // no tree
  1281. luidTree = DF_NOLUID;
  1282. ulLevel = 0;
  1283. }
  1284. else
  1285. {
  1286. // We're creating a subobject so it goes in the parent's tree
  1287. luidTree = ptsmRequestor->GetName();
  1288. ulLevel = ptsmRequestor->GetLevel()+1;
  1289. }
  1290. ptsmAdd->SetXsInfo(luidTree, luid, ulLevel);
  1291. InsertXSMember(ptsmAdd);
  1292. olDebugOut((DEB_ITRACE, "Out CPubDocFile::AddXSMember\n"));
  1293. }
  1294. #if DBG == 1
  1295. //+--------------------------------------------------------------
  1296. //
  1297. // Member: CPubDocFile::VerifyXSMemberBases,public
  1298. //
  1299. // Synopsis: Verify that all XS members have valid bases
  1300. //
  1301. // History: 15-Sep-92 AlexT Created
  1302. //
  1303. //---------------------------------------------------------------
  1304. void CPubDocFile::VerifyXSMemberBases()
  1305. {
  1306. PTSetMember *ptsm;
  1307. olDebugOut((DEB_ITRACE, "In CPubDocFile::VerifyXSMemberBases\n"));
  1308. for (ptsm = _tss.GetHead(); ptsm; ptsm = ptsm->GetNext())
  1309. {
  1310. DWORD otype = REAL_STGTY(ptsm->ObjectType());
  1311. olAssert(otype == STGTY_STORAGE || otype == STGTY_STREAM);
  1312. if (otype == STGTY_STORAGE)
  1313. {
  1314. CWrappedDocFile *pdf = (CWrappedDocFile *) ptsm;
  1315. olAssert(pdf->GetBase() != NULL);
  1316. }
  1317. else
  1318. {
  1319. CTransactedStream *pstm = (CTransactedStream *) ptsm;
  1320. olAssert(pstm->GetBase() != NULL);
  1321. }
  1322. }
  1323. olDebugOut((DEB_ITRACE, "Out CPubDocFile::VerifyXSMemberBases\n"));
  1324. }
  1325. #endif
  1326. //+---------------------------------------------------------------------------
  1327. //
  1328. // Member: CPubDocFile::SetElementTimes, public
  1329. //
  1330. // Synopsis: Sets the times for an element
  1331. //
  1332. // Arguments: [pdfnName] - Name
  1333. // [pctime] - Create time
  1334. // [patime] - Access time
  1335. // [pmtime] - Modify time
  1336. //
  1337. // Returns: Appropriate status code
  1338. //
  1339. // History: 10-Nov-92 DrewB Created
  1340. // 06-Sep-95 MikeHill Added call to CMStream::MaintainFLBModifyTimestamp().
  1341. // 26-Apr-99 RogerCh Removed call to CMStram::MaintainFLBModifyTimestamp().
  1342. //
  1343. //----------------------------------------------------------------------------
  1344. SCODE CPubDocFile::SetElementTimes(CDfName const *pdfnName,
  1345. FILETIME const *pctime,
  1346. FILETIME const *patime,
  1347. FILETIME const *pmtime)
  1348. {
  1349. SCODE sc;
  1350. PDocFile *pdf;
  1351. PTSetMember *ptsm = NULL;
  1352. olDebugOut((DEB_ITRACE, "In CPubDocFile::SetElementTimes:%p("
  1353. "%ws, %p, %p, %p)\n", this, pdfnName, pctime,
  1354. patime, pmtime));
  1355. olChk(CheckReverted());
  1356. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1357. {
  1358. olErr(EH_Err, STG_E_ACCESSDENIED);
  1359. }
  1360. if (pdfnName != NULL)
  1361. {
  1362. if (_cilChildren.FindByName(pdfnName) != NULL)
  1363. olErr(EH_Err, STG_E_ACCESSDENIED);
  1364. }
  1365. if (pdfnName == NULL)
  1366. {
  1367. //Set pdf to the transacted self object.
  1368. pdf = BP_TO_P(PDocFile *, _pdf);
  1369. }
  1370. else if ((ptsm = FindXSMember(pdfnName, _luid)) != NULL)
  1371. {
  1372. if (ptsm->ObjectType() != STGTY_STORAGE)
  1373. olErr(EH_Err, STG_E_ACCESSDENIED);
  1374. pdf = (CWrappedDocFile *)ptsm;
  1375. }
  1376. else olChk(_pdf->GetDocFile(pdfnName, DF_WRITE, &pdf));
  1377. if (pctime)
  1378. {
  1379. olChkTo(EH_pdf, pdf->SetTime(WT_CREATION, *pctime));
  1380. }
  1381. if (pmtime)
  1382. {
  1383. olChkTo(EH_pdf, pdf->SetTime(WT_MODIFICATION, *pmtime));
  1384. }
  1385. if (patime)
  1386. {
  1387. olChkTo(EH_pdf, pdf->SetTime(WT_ACCESS, *patime));
  1388. }
  1389. if (pdfnName != NULL)
  1390. SetDirty();
  1391. olDebugOut((DEB_ITRACE, "Out CPubDocFile::SetElementTimes\n"));
  1392. // Fall through
  1393. EH_pdf:
  1394. if ((ptsm == NULL) && (pdfnName != NULL))
  1395. pdf->Release();
  1396. EH_Err:
  1397. return sc;
  1398. }
  1399. //+---------------------------------------------------------------------------
  1400. //
  1401. // Member: CPubDocFile::SetClass, public
  1402. //
  1403. // Synopsis: Sets the class ID
  1404. //
  1405. // Arguments: [clsid] - Class ID
  1406. //
  1407. // Returns: Appropriate status code
  1408. //
  1409. // History: 11-Nov-92 DrewB Created
  1410. //
  1411. //----------------------------------------------------------------------------
  1412. SCODE CPubDocFile::SetClass(REFCLSID clsid)
  1413. {
  1414. SCODE sc;
  1415. olDebugOut((DEB_ITRACE, "In CPubDocFile::SetClass:%p(?)\n", this));
  1416. olChk(CheckReverted());
  1417. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1418. olErr(EH_Err, STG_E_ACCESSDENIED);
  1419. sc = _pdf->SetClass(clsid);
  1420. SetDirty();
  1421. olDebugOut((DEB_ITRACE, "Out CPubDocFile::SetClass\n"));
  1422. // Fall through
  1423. EH_Err:
  1424. return sc;
  1425. }
  1426. //+---------------------------------------------------------------------------
  1427. //
  1428. // Member: CPubDocFile::SetStateBits, public
  1429. //
  1430. // Synopsis: Sets the state bits
  1431. //
  1432. // Arguments: [grfStateBits] - State bits
  1433. // [grfMask] - Mask
  1434. //
  1435. // Returns: Appropriate status code
  1436. //
  1437. // History: 11-Nov-92 DrewB Created
  1438. //
  1439. //----------------------------------------------------------------------------
  1440. SCODE CPubDocFile::SetStateBits(DWORD grfStateBits, DWORD grfMask)
  1441. {
  1442. SCODE sc;
  1443. olDebugOut((DEB_ITRACE, "In CPubDocFile::SetStateBits:%p(%lu, %lu)\n",
  1444. this, grfStateBits, grfMask));
  1445. olChk(CheckReverted());
  1446. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1447. olErr(EH_Err, STG_E_ACCESSDENIED);
  1448. sc = _pdf->SetStateBits(grfStateBits, grfMask);
  1449. SetDirty();
  1450. olDebugOut((DEB_ITRACE, "Out CPubDocFile::SetStateBits\n"));
  1451. // Fall through
  1452. EH_Err:
  1453. return sc;
  1454. }
  1455. //+---------------------------------------------------------------------------
  1456. //
  1457. // Member: CPubDocFile::Validate, public static
  1458. //
  1459. // Synopsis: Validates a possibly invalid public docfile pointer
  1460. //
  1461. // Arguments: [pdf] - Memory to check
  1462. //
  1463. // Returns: Appropriate status code
  1464. //
  1465. // History: 26-Mar-93 DrewB Created
  1466. //
  1467. //----------------------------------------------------------------------------
  1468. SCODE CPubDocFile::Validate(CPubDocFile *pdf)
  1469. {
  1470. if (FAILED(ValidateBuffer(pdf, sizeof(CPubDocFile))) ||
  1471. (pdf->_sig != CPUBDOCFILE_SIG && pdf->_sig != CROOTPUBDOCFILE_SIG))
  1472. {
  1473. return STG_E_INVALIDHANDLE;
  1474. }
  1475. return S_OK;
  1476. }
  1477. #ifdef COORD
  1478. //+---------------------------------------------------------------------------
  1479. //
  1480. // Member: CPubDocFile::CommitPhase1, public
  1481. //
  1482. // Synopsis: Do phase 1 of the commit sequence
  1483. //
  1484. // Arguments: [dwFlags] -- Commit flags
  1485. //
  1486. // Returns: Appropriate status code
  1487. //
  1488. // History: 07-Aug-95 PhilipLa Created
  1489. //
  1490. //----------------------------------------------------------------------------
  1491. SCODE CPubDocFile::CommitPhase1(DWORD const dwFlags,
  1492. ULONG *pulLock,
  1493. DFSIGNATURE *psigMSF,
  1494. ULONG *pcbSizeBase,
  1495. ULONG *pcbSizeOrig)
  1496. {
  1497. SCODE sc;
  1498. TIME_T tm;
  1499. PTSetMember *ptsm;
  1500. ULONG ulLock = 0;
  1501. DFSIGNATURE sigMSF;
  1502. BOOL fFlush = FLUSH_CACHE(dwFlags);
  1503. olChk(CheckReverted());
  1504. if (!P_WRITE(_df))
  1505. olErr(EH_Err, STG_E_ACCESSDENIED);
  1506. if (IsDirty())
  1507. {
  1508. olChk(DfGetTOD(&tm));
  1509. olChk(_pdf->SetTime(WT_MODIFICATION, tm));
  1510. }
  1511. #ifdef ACCESSTIME
  1512. olChk(DfGetTOD(&tm));
  1513. olChk(_pdf->SetTime(WT_ACCESS, tm));
  1514. #endif
  1515. if (!P_TRANSACTED(_df))
  1516. {
  1517. if (IsDirty())
  1518. {
  1519. if (!IsRoot())
  1520. _pdfParent->SetDirty();
  1521. SetClean();
  1522. }
  1523. if (_cTransactedDepth == 0)
  1524. {
  1525. // Direct all the way
  1526. olChk(_pmsBase->Flush(fFlush));
  1527. }
  1528. return S_OK;
  1529. }
  1530. olAssert(GetTransactedDepth() > 0 &&
  1531. aMsg("Transaction depth/flags conflict"));
  1532. if (GetTransactedDepth() == 1)
  1533. {
  1534. // A transacted depth of 1 means this is the lowest transacted
  1535. // level and committed changes will go into the real file,
  1536. // so do all the special contents protection and locking
  1537. olChk(_pmsBase->BeginCopyOnWrite(dwFlags));
  1538. if (dwFlags & STGC_OVERWRITE)
  1539. {
  1540. olChk(PrepareForOverwrite());
  1541. }
  1542. if (_pdfb->GetOrigLockFlags() & LOCK_ONLYONCE)
  1543. olChkTo(EH_COW, WaitForAccess(_pdfb->GetOriginal(), DF_WRITE,
  1544. &ulLock));
  1545. if (P_INDEPENDENT(_df) | P_NOSNAPSHOT(_df))
  1546. {
  1547. if (_sigMSF == DF_INVALIDSIGNATURE)
  1548. {
  1549. if ((dwFlags & STGC_ONLYIFCURRENT) &&
  1550. DllIsMultiStream(_pdfb->GetOriginal()) == S_OK)
  1551. olErr(EH_GetAccess, STG_E_NOTCURRENT);
  1552. }
  1553. else
  1554. {
  1555. olChkTo(EH_GetAccess, DllGetCommitSig(_pdfb->GetOriginal(),
  1556. &sigMSF));
  1557. if (dwFlags & STGC_ONLYIFCURRENT)
  1558. if (sigMSF != _sigMSF)
  1559. olErr(EH_GetAccess, STG_E_NOTCURRENT);
  1560. }
  1561. }
  1562. }
  1563. for (ptsm = _tss.GetHead(); ptsm; ptsm = ptsm->GetNext())
  1564. if ((ptsm->GetFlags() & XSM_DELETED) == 0)
  1565. olChkTo(EH_NoCommit, ptsm->BeginCommit(dwFlags));
  1566. // 10/02/92 - To handle low disk space situations well, we
  1567. // preallocate the space we'll need to copy (when independent).
  1568. if (P_INDEPENDENT(_df))
  1569. {
  1570. STATSTG statBase, statOrig;
  1571. // With DELAYFLUSH we can't be sure of the size
  1572. // of the file until EndCopyOnWrite, but we do
  1573. // know that the file won't grow so this is safe
  1574. olHChkTo(EH_NoCommit, _pdfb->GetBase()->Stat(&statBase,
  1575. STATFLAG_NONAME));
  1576. olAssert(ULIGetHigh(statBase.cbSize) == 0);
  1577. olHChkTo(EH_NoCommit, _pdfb->GetOriginal()->Stat(&statOrig,
  1578. STATFLAG_NONAME));
  1579. olAssert(ULIGetHigh(statOrig.cbSize) == 0);
  1580. if (ULIGetLow(statBase.cbSize) > ULIGetLow(statOrig.cbSize))
  1581. {
  1582. olHChkTo(EH_NoCommit,
  1583. _pdfb->GetOriginal()->SetSize(statBase.cbSize));
  1584. }
  1585. *pcbSizeBase = ULIGetLow(statBase.cbSize);
  1586. *pcbSizeOrig = ULIGetLow(statOrig.cbSize);
  1587. }
  1588. *pulLock = ulLock;
  1589. *psigMSF = sigMSF;
  1590. return S_OK;
  1591. EH_NoCommit:
  1592. // Move to end of list
  1593. for (ptsm = _tss.GetHead();
  1594. ptsm && ptsm->GetNext();
  1595. ptsm = ptsm->GetNext())
  1596. NULL;
  1597. // Abort commits in reverse
  1598. for (; ptsm; ptsm = ptsm->GetPrev())
  1599. ptsm->EndCommit(DF_ABORT);
  1600. EH_GetAccess:
  1601. if (ulLock != 0)
  1602. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  1603. EH_COW:
  1604. if (GetTransactedDepth() == 1)
  1605. {
  1606. olVerSucc(_pmsBase->EndCopyOnWrite(dwFlags, DF_ABORT));
  1607. }
  1608. EH_Err:
  1609. return sc;
  1610. }
  1611. //+---------------------------------------------------------------------------
  1612. //
  1613. // Member: CPubDocFile::CommitPhase2, public
  1614. //
  1615. // Synopsis: Do phase 2 of commit
  1616. //
  1617. // Arguments: [dwFlags] -- Commit flags
  1618. //
  1619. // Returns: This can only fail if EndCopyOnWrite fails, which should
  1620. // never happen (but can due to a hard disk error). We
  1621. // include cleanup code just in case.
  1622. //
  1623. // History: 07-Aug-95 PhilipLa Created
  1624. //
  1625. //----------------------------------------------------------------------------
  1626. SCODE CPubDocFile::CommitPhase2(DWORD const dwFlags,
  1627. BOOL fCommit,
  1628. ULONG ulLock,
  1629. DFSIGNATURE sigMSF,
  1630. ULONG cbSizeBase,
  1631. ULONG cbSizeOrig)
  1632. {
  1633. SCODE sc;
  1634. PTSetMember *ptsm;
  1635. //The commit was aborted for some reason external to this particular
  1636. // docfile. We can handle this by calling directly to our cleanup
  1637. // code, which will abort and return success.
  1638. if (!fCommit)
  1639. {
  1640. sc = S_OK;
  1641. goto EH_Err;
  1642. }
  1643. if (GetTransactedDepth() == 1)
  1644. {
  1645. olChk(_pmsBase->EndCopyOnWrite(dwFlags, DF_COMMIT));
  1646. }
  1647. // Move to end of list
  1648. for (ptsm = _tss.GetHead();
  1649. ptsm && ptsm->GetNext();
  1650. ptsm = ptsm->GetNext())
  1651. NULL;
  1652. // End commits in reverse
  1653. for (; ptsm; ptsm = ptsm->GetPrev())
  1654. ptsm->EndCommit(DF_COMMIT);
  1655. if (P_INDEPENDENT(_df))
  1656. {
  1657. // Not robust, but we made sure we had enough
  1658. // disk space by presetting the larger size
  1659. // There is no practical way of making this robust
  1660. // and we have never guaranteed behavior in the face
  1661. // of disk errors, so this is good enough
  1662. olVerSucc(CopyLStreamToLStream(_pdfb->GetBase(),
  1663. _pdfb->GetOriginal()));
  1664. olVerSucc(_pdfb->GetOriginal()->Flush());
  1665. }
  1666. if (P_INDEPENDENT(_df) || P_NOSNAPSHOT(_df))
  1667. {
  1668. if (_sigMSF == DF_INVALIDSIGNATURE)
  1669. {
  1670. olVerSucc(DllGetCommitSig(_pdfb->GetOriginal(), &_sigMSF));
  1671. }
  1672. else
  1673. {
  1674. _sigMSF = sigMSF+1;
  1675. olVerSucc(DllSetCommitSig(_pdfb->GetOriginal(), _sigMSF));
  1676. }
  1677. }
  1678. if (ulLock != 0)
  1679. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  1680. // Dirty all parents up to the next transacted storage
  1681. if (IsDirty())
  1682. {
  1683. if (!IsRoot())
  1684. _pdfParent->SetDirty();
  1685. SetClean();
  1686. }
  1687. #if DBG == 1
  1688. VerifyXSMemberBases();
  1689. #endif
  1690. _wFlags = (_wFlags & ~PF_PREPARED);
  1691. return S_OK;
  1692. EH_Err:
  1693. if (P_INDEPENDENT(_df) && (cbSizeBase > cbSizeOrig))
  1694. {
  1695. ULARGE_INTEGER uliSize;
  1696. ULISet32(uliSize, cbSizeOrig);
  1697. _pdfb->GetOriginal()->SetSize(uliSize);
  1698. }
  1699. // Move to end of list
  1700. for (ptsm = _tss.GetHead();
  1701. ptsm && ptsm->GetNext();
  1702. ptsm = ptsm->GetNext())
  1703. NULL;
  1704. // Abort commits in reverse
  1705. for (; ptsm; ptsm = ptsm->GetPrev())
  1706. ptsm->EndCommit(DF_ABORT);
  1707. if (ulLock != 0)
  1708. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  1709. if (GetTransactedDepth() == 1)
  1710. {
  1711. olVerSucc(_pmsBase->EndCopyOnWrite(dwFlags, DF_ABORT));
  1712. }
  1713. return sc;
  1714. }
  1715. #endif