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.

2011 lines
57 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. if (SUCCEEDED(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. if (SUCCEEDED(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 = 0;
  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 = 0;
  458. STATSTG statBase = {0}, statOrig = {0};
  459. BOOL fFlush = FLUSH_CACHE(dwFlags);
  460. olDebugOut((DEB_ITRACE, "In CPubDocFile::Commit:%p(%lX)\n",
  461. this, dwFlags));
  462. olChk(CheckReverted());
  463. if (!P_WRITE(_df))
  464. olErr(EH_Err, STG_E_ACCESSDENIED);
  465. if (IsDirty())
  466. {
  467. olChk(DfGetTOD(&tm));
  468. olChk(_pdf->SetTime(WT_MODIFICATION, tm));
  469. }
  470. if (P_NOSNAPSHOT(_df) && (dwFlags & STGC_OVERWRITE))
  471. {
  472. olErr(EH_Err, STG_E_INVALIDFLAG);
  473. }
  474. #ifdef ACCESSTIME
  475. olChk(DfGetTOD(&tm));
  476. olChk(_pdf->SetTime(WT_ACCESS, tm));
  477. #endif
  478. #ifdef NEWPROPS
  479. olChk(FlushBufferedData(0));
  480. #endif
  481. if (!P_TRANSACTED(_df))
  482. {
  483. if (IsDirty())
  484. {
  485. if (!IsRoot())
  486. _pdfParent->SetDirty();
  487. SetClean();
  488. }
  489. if (_cTransactedDepth == 0)
  490. {
  491. if(STGC_CONSOLIDATE & dwFlags)
  492. sc = Consolidate(dwFlags);
  493. olChk(_pmsBase->Flush(fFlush));
  494. }
  495. return S_OK;
  496. }
  497. olAssert(GetTransactedDepth() > 0 &&
  498. aMsg("Transaction depth/flags conflict"));
  499. if (GetTransactedDepth() == 1)
  500. {
  501. // A transacted depth of 1 means this is the lowest transacted
  502. // level and committed changes will go into the real file,
  503. // so do all the special contents protection and locking
  504. if (_pdfb->GetOrigLockFlags() & LOCK_ONLYONCE)
  505. olChk(WaitForAccess(_pdfb->GetOriginal(), DF_WRITE,
  506. &ulLock));
  507. olChkTo(EH_GetAccess, _pmsBase->BeginCopyOnWrite(dwFlags));
  508. if (dwFlags & STGC_OVERWRITE)
  509. {
  510. olChkTo(EH_COW, PrepareForOverwrite());
  511. }
  512. if (P_INDEPENDENT(_df) || P_NOSNAPSHOT(_df))
  513. {
  514. if (_sigMSF == DF_INVALIDSIGNATURE)
  515. {
  516. if ((dwFlags & STGC_ONLYIFCURRENT) &&
  517. DllIsMultiStream(_pdfb->GetOriginal()) == S_OK)
  518. olErr(EH_COW, STG_E_NOTCURRENT);
  519. }
  520. else
  521. {
  522. olChkTo(EH_COW, DllGetCommitSig(_pdfb->GetOriginal(),
  523. &sigMSF));
  524. if (dwFlags & STGC_ONLYIFCURRENT)
  525. if (sigMSF != _sigMSF)
  526. olErr(EH_COW, STG_E_NOTCURRENT);
  527. }
  528. }
  529. }
  530. for (ptsm = _tss.GetHead(); ptsm; ptsm = ptsm->GetNext())
  531. if ((ptsm->GetFlags() & XSM_DELETED) == 0)
  532. olChkTo(EH_NoCommit, ptsm->BeginCommit(dwFlags));
  533. // 10/02/92 - To handle low disk space situations well, we
  534. // preallocate the space we'll need to copy (when independent).
  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. *ppdfDocFile = NULL;
  913. goto EH_Destroy;
  914. EH_pdf:
  915. pdf->Release();
  916. if (P_TRANSACTED(df))
  917. CWrappedDocFile::Unreserve(1, BP_TO_P(CDFBasis *, _pdfb));
  918. EH_Destroy:
  919. olVerSucc(_pdf->DestroyEntry(pdfnName, TRUE));
  920. return sc;
  921. EH_Reserve:
  922. CWrappedDocFile::Unreserve(cNewTDepth, BP_TO_P(CDFBasis *, _pdfb));
  923. EH_DirectReserve:
  924. CDocFile::Unreserve(1, BP_TO_P(CDFBasis *, _pdfb));
  925. EH_Err:
  926. return sc;
  927. }
  928. //+--------------------------------------------------------------
  929. //
  930. // Member: CPubDocFile::GetDocFile, public
  931. //
  932. // Synopsis: Gets an existing embedded DocFile
  933. //
  934. // Arguments: [pdfnName] - Name
  935. // [df] - Permissions
  936. // [ppdfDocFile] - DocFile return
  937. //
  938. // Returns: Appropriate status code
  939. //
  940. // Modifies: [ppdfDocFile]
  941. //
  942. // History: 20-Jan-92 DrewB Created
  943. //
  944. //---------------------------------------------------------------
  945. SCODE CPubDocFile::GetDocFile(CDfName const *pdfnName,
  946. DFLAGS const df,
  947. CPubDocFile **ppdfDocFile)
  948. {
  949. PDocFile *pdf;
  950. SCODE sc;
  951. CWrappedDocFile *pdfWrapped;
  952. SEntryBuffer eb;
  953. UINT cNewTDepth;
  954. olDebugOut((DEB_ITRACE, "In CPubDocFile::GetDocFile:%p("
  955. "%ws, %X, %p)\n",
  956. this, pdfnName, df, ppdfDocFile));
  957. olChk(CheckReverted());
  958. if (!P_READ(_df))
  959. olErr(EH_Err, STG_E_ACCESSDENIED);
  960. // Check to see if an instance with DENY_* exists
  961. olChk(_cilChildren.IsDenied(pdfnName, df, _df));
  962. olChk(_pdf->GetDocFile(pdfnName, df, &pdf));
  963. eb.luid = pdf->GetLuid();
  964. olAssert(eb.luid != DF_NOLUID && aMsg("DocFile id is DF_NOLUID!"));
  965. cNewTDepth = _cTransactedDepth+(P_TRANSACTED(df) ? 1 : 0);
  966. olMemTo(EH_pdf,
  967. *ppdfDocFile = new (_pmsBase->GetMalloc())
  968. CPubDocFile(this, pdf, df, eb.luid,
  969. BP_TO_P(CDFBasis *, _pdfb),
  970. pdfnName, cNewTDepth,
  971. BP_TO_P(CMStream *, _pmsBase)));
  972. if (P_TRANSACTED(df))
  973. {
  974. olMemTo(EH_ppdf, pdfWrapped = new(_pmsBase->GetMalloc())
  975. CWrappedDocFile(pdfnName, eb.luid, df,
  976. BP_TO_P(CDFBasis *, _pdfb), *ppdfDocFile));
  977. olChkTo(EH_pdfWrapped,
  978. pdfWrapped->Init(pdf));
  979. (*ppdfDocFile)->AddXSMember(NULL, pdfWrapped, eb.luid);
  980. (*ppdfDocFile)->SetDF(pdfWrapped);
  981. }
  982. olDebugOut((DEB_ITRACE, "Out CPubDocFile::GetDocFile\n"));
  983. return S_OK;
  984. EH_pdfWrapped:
  985. delete pdfWrapped;
  986. EH_ppdf:
  987. (*ppdfDocFile)->vRelease();
  988. return sc;
  989. EH_pdf:
  990. pdf->Release();
  991. EH_Err:
  992. return sc;
  993. }
  994. //+--------------------------------------------------------------
  995. //
  996. // Member: CPubDocFile::CreateStream, public
  997. //
  998. // Synopsis: Creates a stream
  999. //
  1000. // Arguments: [pdfnName] - Name
  1001. // [df] - Permissions
  1002. // [ppdstStream] - Stream return
  1003. //
  1004. // Returns: Appropriate status code
  1005. //
  1006. // Modifies: [ppdstStream]
  1007. //
  1008. // History: 20-Jan-92 DrewB Created
  1009. //
  1010. //---------------------------------------------------------------
  1011. SCODE CPubDocFile::CreateStream(CDfName const *pdfnName,
  1012. DFLAGS const df,
  1013. CPubStream **ppdstStream)
  1014. {
  1015. PSStream *psst;
  1016. SCODE sc;
  1017. SEntryBuffer eb;
  1018. olDebugOut((DEB_ITRACE, "In CPubDocFile::CreateStream:%p("
  1019. "%ws, %X, %p)\n", this, pdfnName, df, ppdstStream));
  1020. olChk(CheckReverted());
  1021. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1022. olErr(EH_Err, STG_E_ACCESSDENIED);
  1023. olChk(_cilChildren.IsDenied(pdfnName, df, _df));
  1024. olChk(CDirectStream::Reserve(1, BP_TO_P(CDFBasis *, _pdfb)));
  1025. olChkTo(EH_DirectReserve,
  1026. CTransactedStream::Reserve(_cTransactedDepth,
  1027. BP_TO_P(CDFBasis *, _pdfb)));
  1028. olChkTo(EH_Reserve,
  1029. _pdf->CreateStream(pdfnName, df, DF_NOLUID, &psst));
  1030. // As soon as we have a base we dirty ourself (in case
  1031. // we get an error later) so that we'll flush properly.
  1032. SetDirty();
  1033. eb.luid = psst->GetLuid();
  1034. olAssert(eb.luid != DF_NOLUID && aMsg("Stream id is DF_NOLUID!"));
  1035. olMemTo(EH_Create, *ppdstStream = new (_pmsBase->GetMalloc())
  1036. CPubStream(this, df, pdfnName));
  1037. (*ppdstStream)->Init(psst, eb.luid);
  1038. olDebugOut((DEB_ITRACE, "Out CPubDocFile::CreateStream\n"));
  1039. return S_OK;
  1040. EH_Create:
  1041. psst->Release();
  1042. olVerSucc(_pdf->DestroyEntry(pdfnName, TRUE));
  1043. return sc;
  1044. EH_Reserve:
  1045. CTransactedStream::Unreserve(_cTransactedDepth,
  1046. BP_TO_P(CDFBasis *, _pdfb));
  1047. EH_DirectReserve:
  1048. CDirectStream::Unreserve(1, BP_TO_P(CDFBasis *, _pdfb));
  1049. EH_Err:
  1050. return sc;
  1051. }
  1052. //+--------------------------------------------------------------
  1053. //
  1054. // Member: CPubDocFile::GetStream, public
  1055. //
  1056. // Synopsis: Gets an existing stream
  1057. //
  1058. // Arguments: [pdfnName] - Name
  1059. // [df] - Permissions
  1060. // [ppdstStream] - Stream return
  1061. //
  1062. // Returns: Appropriate status code
  1063. //
  1064. // Modifies: [ppdstStream]
  1065. //
  1066. // History: 20-Jan-92 DrewB Created
  1067. //
  1068. //---------------------------------------------------------------
  1069. SCODE CPubDocFile::GetStream(CDfName const *pdfnName,
  1070. DFLAGS const df,
  1071. CPubStream **ppdstStream)
  1072. {
  1073. PSStream *psst;
  1074. SCODE sc;
  1075. SEntryBuffer eb;
  1076. olDebugOut((DEB_ITRACE, "In CPubDocFile::GetStream(%ws, %X, %p)\n",
  1077. pdfnName, df, ppdstStream));
  1078. olChk(CheckReverted());
  1079. if (!P_READ(_df))
  1080. olErr(EH_Err, STG_E_ACCESSDENIED);
  1081. // Check permissions
  1082. olChk(_cilChildren.IsDenied(pdfnName, df, _df));
  1083. olChk(_pdf->GetStream(pdfnName, df, &psst));
  1084. eb.luid = psst->GetLuid();
  1085. olAssert(eb.luid != DF_NOLUID && aMsg("Stream id is DF_NOLUID!"));
  1086. olMemTo(EH_Get, *ppdstStream = new (_pmsBase->GetMalloc())
  1087. CPubStream(this, df, pdfnName));
  1088. (*ppdstStream)->Init(psst, eb.luid);
  1089. olDebugOut((DEB_ITRACE, "Out CPubDocFile::GetStream\n"));
  1090. return S_OK;
  1091. EH_Get:
  1092. psst->Release();
  1093. EH_Err:
  1094. return sc;
  1095. }
  1096. //+--------------------------------------------------------------
  1097. //
  1098. // Member: CPubDocFile::Stat, public
  1099. //
  1100. // Synopsis: Fills in a stat buffer
  1101. //
  1102. // Arguments: [pstatstg] - Buffer
  1103. // [grfStatFlag] - Stat flags
  1104. //
  1105. // Returns: Appropriate status code
  1106. //
  1107. // Modifies: [pstatstg]
  1108. //
  1109. // History: 24-Mar-92 DrewB Created
  1110. //
  1111. //---------------------------------------------------------------
  1112. SCODE CPubDocFile::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
  1113. {
  1114. SCODE sc;
  1115. if (_sig == CROOTPUBDOCFILE_SIG)
  1116. return ((CRootPubDocFile *)this)->Stat (pstatstg, grfStatFlag);
  1117. olDebugOut((DEB_ITRACE, "In CPubDocFile::Stat(%p, %lu)\n",
  1118. pstatstg, grfStatFlag));
  1119. olAssert(SUCCEEDED(VerifyStatFlag(grfStatFlag)));
  1120. olChk(CheckReverted());
  1121. pstatstg->pwcsName = NULL;
  1122. olChk(_pdf->GetTime(WT_CREATION, &pstatstg->ctime));
  1123. olChk(_pdf->GetTime(WT_MODIFICATION, &pstatstg->mtime));
  1124. pstatstg->atime.dwLowDateTime = pstatstg->atime.dwHighDateTime = 0;
  1125. olChk(_pdf->GetClass(&pstatstg->clsid));
  1126. olChk(_pdf->GetStateBits(&pstatstg->grfStateBits));
  1127. olAssert(!IsRoot());
  1128. if ((grfStatFlag & STATFLAG_NONAME) == 0)
  1129. {
  1130. olMem(pstatstg->pwcsName =
  1131. (WCHAR *)TaskMemAlloc(_dfn.GetLength()));
  1132. memcpy(pstatstg->pwcsName, _dfn.GetBuffer(), _dfn.GetLength());
  1133. }
  1134. pstatstg->grfMode = DFlagsToMode(_df);
  1135. olDebugOut((DEB_ITRACE, "Out CPubDocFile::Stat\n"));
  1136. // Fall through
  1137. EH_Err:
  1138. return sc;
  1139. }
  1140. //+--------------------------------------------------------------
  1141. //
  1142. // Member: CPubDocFile::RevertFromAbove, public
  1143. //
  1144. // Synopsis: Parent has asked for reversion
  1145. //
  1146. // History: 29-Jan-92 DrewB Created
  1147. //
  1148. //---------------------------------------------------------------
  1149. void CPubDocFile::RevertFromAbove(void)
  1150. {
  1151. olDebugOut((DEB_ITRACE, "In CPubDocFile::RevertFromAbove:%p()\n", this));
  1152. _df |= DF_REVERTED;
  1153. _cilChildren.DeleteByName(NULL);
  1154. ChangeXs(DF_NOLUID, XSO_RELEASE);
  1155. _pdf->Release();
  1156. _pdf = NULL;
  1157. olDebugOut((DEB_ITRACE, "Out CPubDocFile::RevertFromAbove\n"));
  1158. }
  1159. //+--------------------------------------------------------------
  1160. //
  1161. // Member: CPubDocFile::FlushBufferedData, public
  1162. //
  1163. // Synopsis: Flush buffered data in any child streams.
  1164. //
  1165. // History: 5-May-1995 BillMo Created
  1166. //
  1167. //---------------------------------------------------------------
  1168. #ifdef NEWPROPS
  1169. SCODE CPubDocFile::FlushBufferedData(int recursionlevel)
  1170. {
  1171. SCODE sc;
  1172. olDebugOut((DEB_ITRACE, "In CPubDocFile::FlushBufferedData:%p()\n", this));
  1173. if ((recursionlevel == 0 && (_df & DF_TRANSACTED)) ||
  1174. (_df & DF_TRANSACTED) == 0)
  1175. {
  1176. sc = _cilChildren.FlushBufferedData(recursionlevel);
  1177. }
  1178. else
  1179. {
  1180. sc = S_OK;
  1181. }
  1182. olDebugOut((DEB_ITRACE, "Out CPubDocFile::FlushBufferedData\n"));
  1183. return sc;
  1184. }
  1185. #endif
  1186. //+--------------------------------------------------------------
  1187. //
  1188. // Member: CPubDocFile::ChangeXs, public
  1189. //
  1190. // Synopsis: Performs an operation on the XS
  1191. //
  1192. // Arguments: [luidTree] - LUID of tree or DF_NOLUID
  1193. // [dwOp] - Operation
  1194. //
  1195. // History: 30-Jan-92 DrewB Created
  1196. //
  1197. //---------------------------------------------------------------
  1198. void CPubDocFile::ChangeXs(DFLUID const luidTree,
  1199. DWORD const dwOp)
  1200. {
  1201. olAssert((dwOp == XSO_RELEASE) || (dwOp == XSO_REVERT));
  1202. PTSetMember *ptsmNext, *ptsmCur, *ptsmPrev;
  1203. for (ptsmNext = _tss.GetHead(); ptsmNext; )
  1204. {
  1205. ptsmCur = ptsmNext;
  1206. ptsmNext = ptsmCur->GetNext();
  1207. olAssert ((ptsmCur->GetName() != ptsmCur->GetTree()));
  1208. if (luidTree == DF_NOLUID || ptsmCur->GetName() == luidTree)
  1209. {
  1210. switch(dwOp)
  1211. {
  1212. case XSO_RELEASE:
  1213. ptsmPrev = ptsmCur->GetPrev();
  1214. _tss.RemoveMember(ptsmCur);
  1215. ptsmCur->Release();
  1216. if (ptsmPrev == NULL)
  1217. ptsmNext = _tss.GetHead();
  1218. else
  1219. ptsmNext = ptsmPrev->GetNext();
  1220. break;
  1221. case XSO_REVERT:
  1222. ptsmCur->Revert();
  1223. // Revert might have changed the next pointer
  1224. ptsmNext = ptsmCur->GetNext();
  1225. break;
  1226. }
  1227. }
  1228. else if (luidTree != DF_NOLUID && luidTree == ptsmCur->GetTree())
  1229. {
  1230. // This weirdness is necessary because ptsm will be
  1231. // deleted by the call to ChangeXs. Since ptsm->GetNext()
  1232. // could also be deleted, we would have no way to continue.
  1233. // ptsm->GetPrev() will never be deleted by the call to
  1234. // ChangeXs, since all children of a node appear _after_
  1235. // that node in the list. Therefore, ptsm->GetPrev()->GetNext()
  1236. // is the best place to resume the loop.
  1237. ptsmPrev = ptsmCur->GetPrev();
  1238. ChangeXs(ptsmCur->GetName(), dwOp);
  1239. if (ptsmPrev == NULL)
  1240. ptsmNext = _tss.GetHead();
  1241. else
  1242. ptsmNext = ptsmPrev->GetNext();
  1243. }
  1244. }
  1245. }
  1246. //+--------------------------------------------------------------
  1247. //
  1248. // Member: CPubDocFile::AddXSMember, public
  1249. //
  1250. // Synopsis: Adds an object to the XS
  1251. //
  1252. // Arguments: [ptsmRequestor] - Object requesting add or NULL if
  1253. // first addition
  1254. // [ptsmAdd] - Object to add
  1255. // [luid] - LUID of object
  1256. //
  1257. // History: 29-Jan-92 DrewB Created
  1258. //
  1259. //---------------------------------------------------------------
  1260. void CPubDocFile::AddXSMember(PTSetMember *ptsmRequestor,
  1261. PTSetMember *ptsmAdd,
  1262. DFLUID luid)
  1263. {
  1264. DFLUID luidTree;
  1265. ULONG ulLevel;
  1266. olDebugOut((DEB_ITRACE, "In CPubDocFile::AddXSMember:%p("
  1267. "%p, %p, %ld)\n", this, ptsmRequestor, ptsmAdd, luid));
  1268. if (ptsmRequestor == NULL)
  1269. {
  1270. // If we're starting the XS, this is a new TL and we have
  1271. // no tree
  1272. luidTree = DF_NOLUID;
  1273. ulLevel = 0;
  1274. }
  1275. else
  1276. {
  1277. // We're creating a subobject so it goes in the parent's tree
  1278. luidTree = ptsmRequestor->GetName();
  1279. ulLevel = ptsmRequestor->GetLevel()+1;
  1280. }
  1281. ptsmAdd->SetXsInfo(luidTree, luid, ulLevel);
  1282. InsertXSMember(ptsmAdd);
  1283. olDebugOut((DEB_ITRACE, "Out CPubDocFile::AddXSMember\n"));
  1284. }
  1285. #if DBG == 1
  1286. //+--------------------------------------------------------------
  1287. //
  1288. // Member: CPubDocFile::VerifyXSMemberBases,public
  1289. //
  1290. // Synopsis: Verify that all XS members have valid bases
  1291. //
  1292. // History: 15-Sep-92 AlexT Created
  1293. //
  1294. //---------------------------------------------------------------
  1295. void CPubDocFile::VerifyXSMemberBases()
  1296. {
  1297. PTSetMember *ptsm;
  1298. olDebugOut((DEB_ITRACE, "In CPubDocFile::VerifyXSMemberBases\n"));
  1299. for (ptsm = _tss.GetHead(); ptsm; ptsm = ptsm->GetNext())
  1300. {
  1301. DWORD otype = REAL_STGTY(ptsm->ObjectType());
  1302. olAssert(otype == STGTY_STORAGE || otype == STGTY_STREAM);
  1303. if (otype == STGTY_STORAGE)
  1304. {
  1305. CWrappedDocFile *pdf = (CWrappedDocFile *) ptsm;
  1306. olAssert(pdf->GetBase() != NULL);
  1307. }
  1308. else
  1309. {
  1310. CTransactedStream *pstm = (CTransactedStream *) ptsm;
  1311. olAssert(pstm->GetBase() != NULL);
  1312. }
  1313. }
  1314. olDebugOut((DEB_ITRACE, "Out CPubDocFile::VerifyXSMemberBases\n"));
  1315. }
  1316. #endif
  1317. //+---------------------------------------------------------------------------
  1318. //
  1319. // Member: CPubDocFile::SetElementTimes, public
  1320. //
  1321. // Synopsis: Sets the times for an element
  1322. //
  1323. // Arguments: [pdfnName] - Name
  1324. // [pctime] - Create time
  1325. // [patime] - Access time
  1326. // [pmtime] - Modify time
  1327. //
  1328. // Returns: Appropriate status code
  1329. //
  1330. // History: 10-Nov-92 DrewB Created
  1331. // 06-Sep-95 MikeHill Added call to CMStream::MaintainFLBModifyTimestamp().
  1332. // 26-Apr-99 RogerCh Removed call to CMStram::MaintainFLBModifyTimestamp().
  1333. //
  1334. //----------------------------------------------------------------------------
  1335. SCODE CPubDocFile::SetElementTimes(CDfName const *pdfnName,
  1336. FILETIME const *pctime,
  1337. FILETIME const *patime,
  1338. FILETIME const *pmtime)
  1339. {
  1340. SCODE sc;
  1341. PDocFile *pdf;
  1342. PTSetMember *ptsm = NULL;
  1343. olDebugOut((DEB_ITRACE, "In CPubDocFile::SetElementTimes:%p("
  1344. "%ws, %p, %p, %p)\n", this, pdfnName, pctime,
  1345. patime, pmtime));
  1346. olChk(CheckReverted());
  1347. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1348. {
  1349. olErr(EH_Err, STG_E_ACCESSDENIED);
  1350. }
  1351. if (pdfnName != NULL)
  1352. {
  1353. if (_cilChildren.FindByName(pdfnName) != NULL)
  1354. olErr(EH_Err, STG_E_ACCESSDENIED);
  1355. }
  1356. if (pdfnName == NULL)
  1357. {
  1358. //Set pdf to the transacted self object.
  1359. pdf = BP_TO_P(PDocFile *, _pdf);
  1360. }
  1361. else if ((ptsm = FindXSMember(pdfnName, _luid)) != NULL)
  1362. {
  1363. if (ptsm->ObjectType() != STGTY_STORAGE)
  1364. olErr(EH_Err, STG_E_ACCESSDENIED);
  1365. pdf = (CWrappedDocFile *)ptsm;
  1366. }
  1367. else olChk(_pdf->GetDocFile(pdfnName, DF_WRITE, &pdf));
  1368. if (pctime)
  1369. {
  1370. olChkTo(EH_pdf, pdf->SetTime(WT_CREATION, *pctime));
  1371. }
  1372. if (pmtime)
  1373. {
  1374. olChkTo(EH_pdf, pdf->SetTime(WT_MODIFICATION, *pmtime));
  1375. }
  1376. if (patime)
  1377. {
  1378. olChkTo(EH_pdf, pdf->SetTime(WT_ACCESS, *patime));
  1379. }
  1380. if (pdfnName != NULL)
  1381. SetDirty();
  1382. olDebugOut((DEB_ITRACE, "Out CPubDocFile::SetElementTimes\n"));
  1383. // Fall through
  1384. EH_pdf:
  1385. if ((ptsm == NULL) && (pdfnName != NULL))
  1386. pdf->Release();
  1387. EH_Err:
  1388. return sc;
  1389. }
  1390. //+---------------------------------------------------------------------------
  1391. //
  1392. // Member: CPubDocFile::SetClass, public
  1393. //
  1394. // Synopsis: Sets the class ID
  1395. //
  1396. // Arguments: [clsid] - Class ID
  1397. //
  1398. // Returns: Appropriate status code
  1399. //
  1400. // History: 11-Nov-92 DrewB Created
  1401. //
  1402. //----------------------------------------------------------------------------
  1403. SCODE CPubDocFile::SetClass(REFCLSID clsid)
  1404. {
  1405. SCODE sc;
  1406. olDebugOut((DEB_ITRACE, "In CPubDocFile::SetClass:%p(?)\n", this));
  1407. olChk(CheckReverted());
  1408. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1409. olErr(EH_Err, STG_E_ACCESSDENIED);
  1410. sc = _pdf->SetClass(clsid);
  1411. SetDirty();
  1412. olDebugOut((DEB_ITRACE, "Out CPubDocFile::SetClass\n"));
  1413. // Fall through
  1414. EH_Err:
  1415. return sc;
  1416. }
  1417. //+---------------------------------------------------------------------------
  1418. //
  1419. // Member: CPubDocFile::SetStateBits, public
  1420. //
  1421. // Synopsis: Sets the state bits
  1422. //
  1423. // Arguments: [grfStateBits] - State bits
  1424. // [grfMask] - Mask
  1425. //
  1426. // Returns: Appropriate status code
  1427. //
  1428. // History: 11-Nov-92 DrewB Created
  1429. //
  1430. //----------------------------------------------------------------------------
  1431. SCODE CPubDocFile::SetStateBits(DWORD grfStateBits, DWORD grfMask)
  1432. {
  1433. SCODE sc;
  1434. olDebugOut((DEB_ITRACE, "In CPubDocFile::SetStateBits:%p(%lu, %lu)\n",
  1435. this, grfStateBits, grfMask));
  1436. olChk(CheckReverted());
  1437. if (!P_TRANSACTED(_df) && !P_WRITE(_df))
  1438. olErr(EH_Err, STG_E_ACCESSDENIED);
  1439. sc = _pdf->SetStateBits(grfStateBits, grfMask);
  1440. SetDirty();
  1441. olDebugOut((DEB_ITRACE, "Out CPubDocFile::SetStateBits\n"));
  1442. // Fall through
  1443. EH_Err:
  1444. return sc;
  1445. }
  1446. //+---------------------------------------------------------------------------
  1447. //
  1448. // Member: CPubDocFile::Validate, public static
  1449. //
  1450. // Synopsis: Validates a possibly invalid public docfile pointer
  1451. //
  1452. // Arguments: [pdf] - Memory to check
  1453. //
  1454. // Returns: Appropriate status code
  1455. //
  1456. // History: 26-Mar-93 DrewB Created
  1457. //
  1458. //----------------------------------------------------------------------------
  1459. SCODE CPubDocFile::Validate(CPubDocFile *pdf)
  1460. {
  1461. if (FAILED(ValidateBuffer(pdf, sizeof(CPubDocFile))) ||
  1462. (pdf->_sig != CPUBDOCFILE_SIG && pdf->_sig != CROOTPUBDOCFILE_SIG))
  1463. {
  1464. return STG_E_INVALIDHANDLE;
  1465. }
  1466. return S_OK;
  1467. }
  1468. #ifdef COORD
  1469. //+---------------------------------------------------------------------------
  1470. //
  1471. // Member: CPubDocFile::CommitPhase1, public
  1472. //
  1473. // Synopsis: Do phase 1 of the commit sequence
  1474. //
  1475. // Arguments: [dwFlags] -- Commit flags
  1476. //
  1477. // Returns: Appropriate status code
  1478. //
  1479. // History: 07-Aug-95 PhilipLa Created
  1480. //
  1481. //----------------------------------------------------------------------------
  1482. SCODE CPubDocFile::CommitPhase1(DWORD const dwFlags,
  1483. ULONG *pulLock,
  1484. DFSIGNATURE *psigMSF,
  1485. ULONG *pcbSizeBase,
  1486. ULONG *pcbSizeOrig)
  1487. {
  1488. SCODE sc;
  1489. TIME_T tm;
  1490. PTSetMember *ptsm;
  1491. ULONG ulLock = 0;
  1492. DFSIGNATURE sigMSF;
  1493. BOOL fFlush = FLUSH_CACHE(dwFlags);
  1494. olChk(CheckReverted());
  1495. if (!P_WRITE(_df))
  1496. olErr(EH_Err, STG_E_ACCESSDENIED);
  1497. if (IsDirty())
  1498. {
  1499. olChk(DfGetTOD(&tm));
  1500. olChk(_pdf->SetTime(WT_MODIFICATION, tm));
  1501. }
  1502. #ifdef ACCESSTIME
  1503. olChk(DfGetTOD(&tm));
  1504. olChk(_pdf->SetTime(WT_ACCESS, tm));
  1505. #endif
  1506. if (!P_TRANSACTED(_df))
  1507. {
  1508. if (IsDirty())
  1509. {
  1510. if (!IsRoot())
  1511. _pdfParent->SetDirty();
  1512. SetClean();
  1513. }
  1514. if (_cTransactedDepth == 0)
  1515. {
  1516. // Direct all the way
  1517. olChk(_pmsBase->Flush(fFlush));
  1518. }
  1519. return S_OK;
  1520. }
  1521. olAssert(GetTransactedDepth() > 0 &&
  1522. aMsg("Transaction depth/flags conflict"));
  1523. if (GetTransactedDepth() == 1)
  1524. {
  1525. // A transacted depth of 1 means this is the lowest transacted
  1526. // level and committed changes will go into the real file,
  1527. // so do all the special contents protection and locking
  1528. olChk(_pmsBase->BeginCopyOnWrite(dwFlags));
  1529. if (dwFlags & STGC_OVERWRITE)
  1530. {
  1531. olChk(PrepareForOverwrite());
  1532. }
  1533. if (_pdfb->GetOrigLockFlags() & LOCK_ONLYONCE)
  1534. olChkTo(EH_COW, WaitForAccess(_pdfb->GetOriginal(), DF_WRITE,
  1535. &ulLock));
  1536. if (P_INDEPENDENT(_df) | P_NOSNAPSHOT(_df))
  1537. {
  1538. if (_sigMSF == DF_INVALIDSIGNATURE)
  1539. {
  1540. if ((dwFlags & STGC_ONLYIFCURRENT) &&
  1541. DllIsMultiStream(_pdfb->GetOriginal()) == S_OK)
  1542. olErr(EH_GetAccess, STG_E_NOTCURRENT);
  1543. }
  1544. else
  1545. {
  1546. olChkTo(EH_GetAccess, DllGetCommitSig(_pdfb->GetOriginal(),
  1547. &sigMSF));
  1548. if (dwFlags & STGC_ONLYIFCURRENT)
  1549. if (sigMSF != _sigMSF)
  1550. olErr(EH_GetAccess, STG_E_NOTCURRENT);
  1551. }
  1552. }
  1553. }
  1554. for (ptsm = _tss.GetHead(); ptsm; ptsm = ptsm->GetNext())
  1555. if ((ptsm->GetFlags() & XSM_DELETED) == 0)
  1556. olChkTo(EH_NoCommit, ptsm->BeginCommit(dwFlags));
  1557. // 10/02/92 - To handle low disk space situations well, we
  1558. // preallocate the space we'll need to copy (when independent).
  1559. if (P_INDEPENDENT(_df))
  1560. {
  1561. STATSTG statBase, statOrig;
  1562. // With DELAYFLUSH we can't be sure of the size
  1563. // of the file until EndCopyOnWrite, but we do
  1564. // know that the file won't grow so this is safe
  1565. olHChkTo(EH_NoCommit, _pdfb->GetBase()->Stat(&statBase,
  1566. STATFLAG_NONAME));
  1567. olAssert(ULIGetHigh(statBase.cbSize) == 0);
  1568. olHChkTo(EH_NoCommit, _pdfb->GetOriginal()->Stat(&statOrig,
  1569. STATFLAG_NONAME));
  1570. olAssert(ULIGetHigh(statOrig.cbSize) == 0);
  1571. if (ULIGetLow(statBase.cbSize) > ULIGetLow(statOrig.cbSize))
  1572. {
  1573. olHChkTo(EH_NoCommit,
  1574. _pdfb->GetOriginal()->SetSize(statBase.cbSize));
  1575. }
  1576. *pcbSizeBase = ULIGetLow(statBase.cbSize);
  1577. *pcbSizeOrig = ULIGetLow(statOrig.cbSize);
  1578. }
  1579. *pulLock = ulLock;
  1580. *psigMSF = sigMSF;
  1581. return S_OK;
  1582. EH_NoCommit:
  1583. // Move to end of list
  1584. for (ptsm = _tss.GetHead();
  1585. ptsm && ptsm->GetNext();
  1586. ptsm = ptsm->GetNext())
  1587. NULL;
  1588. // Abort commits in reverse
  1589. for (; ptsm; ptsm = ptsm->GetPrev())
  1590. ptsm->EndCommit(DF_ABORT);
  1591. EH_GetAccess:
  1592. if (ulLock != 0)
  1593. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  1594. EH_COW:
  1595. if (GetTransactedDepth() == 1)
  1596. {
  1597. olVerSucc(_pmsBase->EndCopyOnWrite(dwFlags, DF_ABORT));
  1598. }
  1599. EH_Err:
  1600. return sc;
  1601. }
  1602. //+---------------------------------------------------------------------------
  1603. //
  1604. // Member: CPubDocFile::CommitPhase2, public
  1605. //
  1606. // Synopsis: Do phase 2 of commit
  1607. //
  1608. // Arguments: [dwFlags] -- Commit flags
  1609. //
  1610. // Returns: This can only fail if EndCopyOnWrite fails, which should
  1611. // never happen (but can due to a hard disk error). We
  1612. // include cleanup code just in case.
  1613. //
  1614. // History: 07-Aug-95 PhilipLa Created
  1615. //
  1616. //----------------------------------------------------------------------------
  1617. SCODE CPubDocFile::CommitPhase2(DWORD const dwFlags,
  1618. BOOL fCommit,
  1619. ULONG ulLock,
  1620. DFSIGNATURE sigMSF,
  1621. ULONG cbSizeBase,
  1622. ULONG cbSizeOrig)
  1623. {
  1624. SCODE sc;
  1625. PTSetMember *ptsm;
  1626. //The commit was aborted for some reason external to this particular
  1627. // docfile. We can handle this by calling directly to our cleanup
  1628. // code, which will abort and return success.
  1629. if (!fCommit)
  1630. {
  1631. sc = S_OK;
  1632. goto EH_Err;
  1633. }
  1634. if (GetTransactedDepth() == 1)
  1635. {
  1636. olChk(_pmsBase->EndCopyOnWrite(dwFlags, DF_COMMIT));
  1637. }
  1638. // Move to end of list
  1639. for (ptsm = _tss.GetHead();
  1640. ptsm && ptsm->GetNext();
  1641. ptsm = ptsm->GetNext())
  1642. NULL;
  1643. // End commits in reverse
  1644. for (; ptsm; ptsm = ptsm->GetPrev())
  1645. ptsm->EndCommit(DF_COMMIT);
  1646. if (P_INDEPENDENT(_df))
  1647. {
  1648. // Not robust, but we made sure we had enough
  1649. // disk space by presetting the larger size
  1650. // There is no practical way of making this robust
  1651. // and we have never guaranteed behavior in the face
  1652. // of disk errors, so this is good enough
  1653. olVerSucc(CopyLStreamToLStream(_pdfb->GetBase(),
  1654. _pdfb->GetOriginal()));
  1655. olVerSucc(_pdfb->GetOriginal()->Flush());
  1656. }
  1657. if (P_INDEPENDENT(_df) || P_NOSNAPSHOT(_df))
  1658. {
  1659. if (_sigMSF == DF_INVALIDSIGNATURE)
  1660. {
  1661. olVerSucc(DllGetCommitSig(_pdfb->GetOriginal(), &_sigMSF));
  1662. }
  1663. else
  1664. {
  1665. _sigMSF = sigMSF+1;
  1666. olVerSucc(DllSetCommitSig(_pdfb->GetOriginal(), _sigMSF));
  1667. }
  1668. }
  1669. if (ulLock != 0)
  1670. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  1671. // Dirty all parents up to the next transacted storage
  1672. if (IsDirty())
  1673. {
  1674. if (!IsRoot())
  1675. _pdfParent->SetDirty();
  1676. SetClean();
  1677. }
  1678. #if DBG == 1
  1679. VerifyXSMemberBases();
  1680. #endif
  1681. _wFlags = (_wFlags & ~PF_PREPARED);
  1682. return S_OK;
  1683. EH_Err:
  1684. if (P_INDEPENDENT(_df) && (cbSizeBase > cbSizeOrig))
  1685. {
  1686. ULARGE_INTEGER uliSize;
  1687. ULISet32(uliSize, cbSizeOrig);
  1688. _pdfb->GetOriginal()->SetSize(uliSize);
  1689. }
  1690. // Move to end of list
  1691. for (ptsm = _tss.GetHead();
  1692. ptsm && ptsm->GetNext();
  1693. ptsm = ptsm->GetNext())
  1694. NULL;
  1695. // Abort commits in reverse
  1696. for (; ptsm; ptsm = ptsm->GetPrev())
  1697. ptsm->EndCommit(DF_ABORT);
  1698. if (ulLock != 0)
  1699. ReleaseAccess(_pdfb->GetOriginal(), DF_WRITE, ulLock);
  1700. if (GetTransactedDepth() == 1)
  1701. {
  1702. olVerSucc(_pmsBase->EndCopyOnWrite(dwFlags, DF_ABORT));
  1703. }
  1704. return sc;
  1705. }
  1706. #endif