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.

2674 lines
69 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: mstream.cxx
  7. //
  8. // Contents: Mstream operations
  9. //
  10. // Classes: None. (defined in mstream.hxx)
  11. //
  12. // History: 18-Jul-91 Philipla Created.
  13. //
  14. //--------------------------------------------------------------------
  15. #include "msfhead.cxx"
  16. #pragma hdrstop
  17. #include <dirfunc.hxx>
  18. #include <sstream.hxx>
  19. #include <difat.hxx>
  20. #include <time.h>
  21. #include <mread.hxx>
  22. #include <docfilep.hxx>
  23. #include <df32.hxx>
  24. #include <smalloc.hxx>
  25. #include <filelkb.hxx>
  26. #if DBG == 1
  27. DECLARE_INFOLEVEL(msf)
  28. #endif
  29. #define MINPAGES 6
  30. #define MAXPAGES 128
  31. #define MINPAGESSCRATCH 2
  32. #define MAXPAGESSCRATCH 16
  33. //#define SECURETEST
  34. const WCHAR wcsContents[] = L"CONTENTS"; //Name of contents stream for
  35. // conversion
  36. const WCHAR wcsRootEntry[] = L"Root Entry"; //Name of root directory
  37. // entry
  38. SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache);
  39. //+---------------------------------------------------------------------------
  40. //
  41. // Function: GetBuffer, public
  42. //
  43. // Synopsis: Gets a chunk of memory to use as a buffer
  44. //
  45. // Arguments: [cbMin] - Minimum size for buffer
  46. // [cbMax] - Maximum size for buffer
  47. // [ppb] - Buffer pointer return
  48. // [pcbActual] - Actual buffer size return
  49. //
  50. // Returns: Appropriate status code
  51. //
  52. // Modifies: [ppb]
  53. // [pcbActual]
  54. //
  55. // Algorithm: Attempt to dynamically allocate [cbMax] bytes
  56. // If that fails, halve allocation size and retry
  57. // If allocation size falls below [cbMin], fail
  58. //
  59. // History: 04-Mar-93 DrewB Created
  60. //
  61. // Notes: Buffer should be released with FreeBuffer
  62. //
  63. //----------------------------------------------------------------------------
  64. SCODE GetBuffer(ULONG cbMin, ULONG cbMax, BYTE **ppb, ULONG *pcbActual)
  65. {
  66. ULONG cbSize;
  67. BYTE *pb;
  68. msfDebugOut((DEB_ITRACE, "In GetBuffer(%u, %u, %p, %p)\n",
  69. cbMin, cbMax, ppb, pcbActual));
  70. msfAssert(cbMin > 0);
  71. msfAssert(cbMax >= cbMin);
  72. msfAssert(ppb != NULL);
  73. msfAssert(pcbActual != NULL);
  74. cbSize = cbMax;
  75. for (;;)
  76. {
  77. pb = (BYTE *) DfMemAlloc(cbSize);
  78. if (pb == NULL)
  79. {
  80. cbSize >>= 1;
  81. if (cbSize < cbMin)
  82. break;
  83. }
  84. else
  85. {
  86. *pcbActual = cbSize;
  87. break;
  88. }
  89. }
  90. *ppb = pb;
  91. msfDebugOut((DEB_ITRACE, "Out GetBuffer => %p, %u\n", *ppb, *pcbActual));
  92. return pb == NULL ? STG_E_INSUFFICIENTMEMORY : S_OK;
  93. }
  94. // Define the safe buffer size
  95. //#define SCRATCHBUFFERSIZE SCRATCHSECTORSIZE
  96. BYTE s_bufSafe[SCRATCHBUFFERSIZE];
  97. LONG s_bufSafeRef = 0;
  98. // Critical Section will be initiqalized in the shared memory allocator
  99. // constructor and deleted in the SmAllocator destructor
  100. CRITICAL_SECTION g_csScratchBuffer;
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Function: GetSafeBuffer, public
  104. //
  105. // Synopsis: Gets a buffer by first trying GetBuffer and if that fails,
  106. // returning a pointer to statically allocated storage.
  107. // Guaranteed to return a pointer to some storage.
  108. //
  109. // Arguments: [cbMin] - Minimum buffer size
  110. // [cbMax] - Maximum buffer size
  111. // [ppb] - Buffer pointer return
  112. // [pcbActual] - Actual buffer size return
  113. //
  114. // Modifies: [ppb]
  115. // [pcbActual]
  116. //
  117. // History: 04-Mar-93 DrewB Created
  118. //
  119. //----------------------------------------------------------------------------
  120. void GetSafeBuffer(ULONG cbMin, ULONG cbMax, BYTE **ppb, ULONG *pcbActual)
  121. {
  122. msfAssert(cbMin > 0);
  123. msfAssert(cbMin <= SCRATCHBUFFERSIZE &&
  124. aMsg("Minimum too large for GetSafeBuffer"));
  125. msfAssert(cbMax >= cbMin);
  126. msfAssert(ppb != NULL);
  127. // We want to minimize contention for the
  128. // static buffer so we always try dynamic allocation, regardless
  129. // of the size
  130. if (
  131. FAILED(GetBuffer(cbMin, cbMax, ppb, pcbActual)))
  132. {
  133. EnterCriticalSection(&g_csScratchBuffer);
  134. msfAssert(s_bufSafeRef == 0 &&
  135. aMsg("Tried to use scratch buffer twice"));
  136. s_bufSafeRef = 1;
  137. *ppb = s_bufSafe;
  138. *pcbActual = min(cbMax, SCRATCHBUFFERSIZE);
  139. }
  140. msfAssert(*ppb != NULL);
  141. }
  142. //+---------------------------------------------------------------------------
  143. //
  144. // Function: FreeBuffer, public
  145. //
  146. // Synopsis: Releases a buffer allocated by GetBuffer or GetSafeBuffer
  147. //
  148. // Arguments: [pb] - Buffer
  149. //
  150. // History: 04-Mar-93 DrewB Created
  151. //
  152. //----------------------------------------------------------------------------
  153. void FreeBuffer(BYTE *pb)
  154. {
  155. if (pb == s_bufSafe)
  156. {
  157. msfAssert((s_bufSafeRef == 1) && aMsg("Bad safe buffer ref count"));
  158. s_bufSafeRef = 0;
  159. LeaveCriticalSection(&g_csScratchBuffer);
  160. }
  161. else
  162. DfMemFree(pb);
  163. }
  164. //+-------------------------------------------------------------------------
  165. //
  166. // Method: CMStream::CMStream, public
  167. //
  168. // Synopsis: CMStream constructor
  169. //
  170. // Arguments: [pplstParent] -- Pointer to ILockBytes pointer of parent
  171. // [plGen] -- Pointer to LUID Generator to use.
  172. // Note: May be NULL, in which case a new
  173. // [uSectorShift] -- Sector shift for this MStream
  174. //
  175. // History: 18-Jul-91 PhilipLa Created.
  176. // 05-Sep-95 MikeHill Initialize '_fMaintainFLBModifyTimestamp'.
  177. // 26-Apr-99 RogerCh Removed _fMaintainFLBModifyTimestamp
  178. //
  179. //--------------------------------------------------------------------------
  180. CMStream::CMStream(
  181. IMalloc *pMalloc,
  182. ILockBytes **pplstParent,
  183. BOOL fIsScratch,
  184. #if defined(USE_NOSCRATCH) || defined(USE_NOSNAPSHOT)
  185. DFLAGS df,
  186. #endif
  187. USHORT uSectorShift)
  188. :_uSectorShift(uSectorShift),
  189. _uSectorSize(1 << uSectorShift),
  190. _uSectorMask(_uSectorSize - 1),
  191. _pplstParent(P_TO_BP(CBasedILockBytesPtrPtr, pplstParent)),
  192. _fIsScratch(fIsScratch),
  193. _fIsNoScratch(P_NOSCRATCH(df)),
  194. _pmsScratch(NULL),
  195. _fIsNoSnapshot(P_NOSNAPSHOT(df)),
  196. _hdr(uSectorShift),
  197. _fat(SIDFAT),
  198. _fatMini(SIDMINIFAT),
  199. _pMalloc(pMalloc)
  200. {
  201. _pmsShadow = NULL;
  202. _pCopySectBuf = NULL;
  203. #if DBG == 1
  204. _uBufferRef = 0;
  205. #endif
  206. _fIsShadow = FALSE;
  207. _ulParentSize = 0;
  208. _pdsministream = NULL;
  209. _pmpt = NULL;
  210. _fBlockWrite = _fTruncate = _fBlockHeader = _fNewConvert = FALSE;
  211. }
  212. //+-------------------------------------------------------------------------
  213. //
  214. // Method: CMStream::CMStream, public
  215. //
  216. // Synopsis: CMStream copy constructor
  217. //
  218. // Arguments: [ms] -- MStream to copy
  219. //
  220. // History: 04-Nov-92 PhilipLa Created.
  221. //
  222. //--------------------------------------------------------------------------
  223. CMStream::CMStream(const CMStream *pms)
  224. :_uSectorShift(pms->_uSectorShift),
  225. _uSectorSize(pms->_uSectorSize),
  226. _uSectorMask(pms->_uSectorMask),
  227. _pplstParent(pms->_pplstParent),
  228. _fIsScratch(pms->_fIsScratch),
  229. _hdr(*(CMSFHeader *)&pms->_hdr),
  230. _dir(*(CDirectory *)pms->GetDir()),
  231. _fat(pms->GetFat()),
  232. _fatMini(pms->GetMiniFat()),
  233. _fatDif(pms->GetDIFat()),
  234. _pdsministream(pms->_pdsministream),
  235. _pmpt(pms->_pmpt),
  236. _fBlockWrite(pms->_fBlockWrite),
  237. _fTruncate(pms->_fTruncate),
  238. _fBlockHeader(pms->_fBlockHeader),
  239. _fNewConvert(pms->_fNewConvert),
  240. _pmsShadow(NULL),
  241. _fIsShadow(TRUE),
  242. _pMalloc(pms->_pMalloc)
  243. {
  244. _pCopySectBuf = pms->_pCopySectBuf;
  245. #if DBG == 1
  246. _uBufferRef = pms->_uBufferRef;
  247. #endif
  248. _dir.SetParent(this);
  249. _fat.SetParent(this);
  250. _fatMini.SetParent(this);
  251. _fatDif.SetParent(this);
  252. _ulParentSize = 0;
  253. _pmpt->AddRef();
  254. }
  255. //+-------------------------------------------------------------------------
  256. //
  257. // Method: CMStream::InitCommon, private
  258. //
  259. // Synopsis: Common code for initialization routines.
  260. //
  261. // Arguments: None.
  262. //
  263. // Returns: S_OK if call completed OK.
  264. //
  265. // Algorithm: *Finish This*
  266. //
  267. // History: 20-May-92 PhilipLa Created.
  268. //
  269. //--------------------------------------------------------------------------
  270. SCODE CMStream::InitCommon(VOID)
  271. {
  272. msfDebugOut((DEB_ITRACE,"In CMStream InitCommon()\n"));
  273. SCODE sc = S_OK;
  274. #ifdef SECURE_BUFFER
  275. memset(s_bufSecure, SECURECHAR, MINISTREAMSIZE);
  276. #endif
  277. CMSFPageTable *pmpt;
  278. msfMem(pmpt = new (GetMalloc()) CMSFPageTable(
  279. this,
  280. (_fIsScratch) ? MINPAGESSCRATCH: MINPAGES,
  281. (_fIsScratch) ? MAXPAGESSCRATCH: MAXPAGES));
  282. _pmpt = P_TO_BP(CBasedMSFPageTablePtr, pmpt);
  283. msfChk(pmpt->Init());
  284. if (!_fIsScratch)
  285. {
  286. CMStream *pms;
  287. msfMem(pms = (CMStream *) new (GetMalloc()) CMStream(this));
  288. _pmsShadow = P_TO_BP(CBasedMStreamPtr, pms);
  289. }
  290. _stmcDir.Init(this, SIDDIR, NULL);
  291. _stmcMiniFat.Init(this, SIDMINIFAT, NULL);
  292. msfDebugOut((DEB_ITRACE,"Leaving CMStream InitCommon()\n"));
  293. Err:
  294. return sc;
  295. }
  296. //+---------------------------------------------------------------------------
  297. //
  298. // Member: CMStream::InitCopy, public
  299. //
  300. // Synopsis: Copy the structures from one multistream to yourself
  301. //
  302. // Arguments: [pms] -- Pointer to multistream to copy.
  303. //
  304. // History: 04-Dec-92 PhilipLa Created
  305. //
  306. // Notes:
  307. //
  308. //----------------------------------------------------------------------------
  309. void CMStream::InitCopy(CMStream *pms)
  310. {
  311. _stmcDir.Init(this, SIDDIR, NULL);
  312. _stmcMiniFat.Init(this, SIDMINIFAT, NULL);
  313. _fat.InitCopy(pms->GetFat());
  314. _fatMini.InitCopy(pms->GetMiniFat());
  315. _fatDif.InitCopy(pms->GetDIFat());
  316. _dir.InitCopy(pms->GetDir());
  317. _dir.SetParent(this);
  318. _fat.SetParent(this);
  319. _fatMini.SetParent(this);
  320. _fatDif.SetParent(this);
  321. memcpy(&_hdr, pms->GetHeader(), sizeof(CMSFHeader));
  322. }
  323. //+---------------------------------------------------------------------------
  324. //
  325. // Member: CMStream::Empty, public
  326. //
  327. // Synopsis: Empty all of the control structures of this CMStream
  328. //
  329. // Arguments: None.
  330. //
  331. // Returns: void.
  332. //
  333. // History: 04-Dec-92 PhilipLa Created
  334. //
  335. //----------------------------------------------------------------------------
  336. void CMStream::Empty(void)
  337. {
  338. _fat.Empty();
  339. _fatMini.Empty();
  340. _fatDif.Empty();
  341. _dir.Empty();
  342. }
  343. //+-------------------------------------------------------------------------
  344. //
  345. // Method: CMStream::~CMStream, public
  346. //
  347. // Synopsis: CMStream destructor
  348. //
  349. // History: 18-Jul-91 PhilipLa Created.
  350. // 20-Jul-95 SusiA Modified to eliminate mutex in allocator
  351. // Caller must already have the mutex.
  352. //
  353. //--------------------------------------------------------------------------
  354. CMStream::~CMStream()
  355. {
  356. msfDebugOut((DEB_ITRACE,"In CMStream destructor\n"));
  357. if (_pmsShadow != NULL)
  358. {
  359. _pmsShadow->~CMStream();
  360. _pmsShadow->deleteNoMutex (BP_TO_P(CMStream *, _pmsShadow));
  361. }
  362. #if DBG == 1
  363. msfAssert((_uBufferRef == 0) &&
  364. aMsg("CopySect buffer left with positive refcount."));
  365. #endif
  366. g_smAllocator.FreeNoMutex(BP_TO_P(BYTE *, _pCopySectBuf));
  367. if ((!_fIsShadow) && (_pdsministream != NULL))
  368. {
  369. _pdsministream->Release();
  370. }
  371. if (_pmpt != NULL)
  372. {
  373. _pmpt->Release();
  374. }
  375. msfDebugOut((DEB_ITRACE,"Leaving CMStream destructor\n"));
  376. }
  377. //+-------------------------------------------------------------------------
  378. //
  379. // Member: CMStream::Init, public
  380. //
  381. // Synposis: Set up an mstream instance from an existing stream
  382. //
  383. // Effects: Modifies Fat and Directory
  384. //
  385. // Arguments: void.
  386. //
  387. // Returns: S_OK if call completed OK.
  388. // Error of Fat or Dir setup otherwise.
  389. //
  390. // History: 18-Jul-91 PhilipLa Created.
  391. //
  392. // Notes:
  393. //
  394. //---------------------------------------------------------------------------
  395. SCODE CMStream::Init(VOID)
  396. {
  397. ULONG ulTemp;
  398. SCODE sc;
  399. ULARGE_INTEGER ulOffset;
  400. msfDebugOut((DEB_ITRACE,"In CMStream::Init()\n"));
  401. msfAssert(!_fIsScratch &&
  402. aMsg("Called Init() on scratch multistream."));
  403. ULONG ulSectorSize = HEADERSIZE;
  404. IFileLockBytes *pfl;
  405. if (SUCCEEDED((*_pplstParent)->QueryInterface(IID_IFileLockBytes,
  406. (void**) &pfl)))
  407. {
  408. ulSectorSize = pfl->GetSectorSize();
  409. pfl->Release();
  410. }
  411. ULISet32(ulOffset, 0);
  412. if (ulSectorSize == sizeof(CMSFHeaderData))
  413. {
  414. sc = (*_pplstParent)->ReadAt(ulOffset, (BYTE *)_hdr.GetData(),
  415. sizeof(CMSFHeaderData), &ulTemp);
  416. }
  417. else
  418. {
  419. void *pvBuf = TaskMemAlloc(ulSectorSize);
  420. sc = (*_pplstParent)->ReadAt(ulOffset, pvBuf, ulSectorSize, &ulTemp);
  421. if (SUCCEEDED(sc))
  422. memcpy (_hdr.GetData(), pvBuf, sizeof(CMSFHeaderData));
  423. TaskMemFree (pvBuf);
  424. }
  425. if (sc == E_PENDING)
  426. {
  427. sc = STG_E_PENDINGCONTROL;
  428. }
  429. msfChk(sc);
  430. //We need to mark the header as not dirty, since the constructor
  431. // defaults it to the dirty state. This needs to happen before
  432. // any possible failures, otherwise we can end up writing a
  433. // brand new header over an existing file.
  434. _hdr.ResetDirty();
  435. _uSectorShift = _hdr.GetSectorShift();
  436. _uSectorSize = 1 << _uSectorShift;
  437. _uSectorMask = _uSectorSize - 1;
  438. if (ulTemp != ulSectorSize)
  439. {
  440. msfErr(Err,STG_E_INVALIDHEADER);
  441. }
  442. msfChk(_hdr.Validate());
  443. msfChk(InitCommon());
  444. msfChk(_fatDif.Init(this, _hdr.GetDifLength()));
  445. msfChk(_fat.Init(this, _hdr.GetFatLength(), 0));
  446. FSINDEX fsiLen;
  447. if (_uSectorShift > SECTORSHIFT512)
  448. fsiLen = _hdr.GetDirLength ();
  449. else
  450. msfChk(_fat.GetLength(_hdr.GetDirStart(), &fsiLen));
  451. msfChk(_dir.Init(this, fsiLen));
  452. msfChk(_fatMini.Init(this, _hdr.GetMiniFatLength(), 0));
  453. BYTE *pbBuf;
  454. msfMem(pbBuf = (BYTE *) GetMalloc()->Alloc(GetSectorSize()));
  455. _pCopySectBuf = P_TO_BP(CBasedBytePtr, pbBuf);
  456. #ifdef LARGE_STREAMS
  457. ULONGLONG ulSize;
  458. #else
  459. ULONG ulSize;
  460. #endif
  461. msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
  462. CDirectStream *pdsTemp;
  463. msfMem(pdsTemp = new(GetMalloc()) CDirectStream(MINISTREAM_LUID));
  464. _pdsministream = P_TO_BP(CBasedDirectStreamPtr, pdsTemp);
  465. _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
  466. msfDebugOut((DEB_ITRACE,"Out CMStream::Init()\n"));
  467. Err:
  468. return sc;
  469. }
  470. //+-------------------------------------------------------------------------
  471. //
  472. // Member: CMStream::InitNew, public
  473. //
  474. // Synposis: Set up a brand new mstream instance
  475. //
  476. // Effects: Modifies FAT and Directory
  477. //
  478. // Arguments: [fDelay] -- If TRUE, then the parent LStream
  479. // will be truncated at the time of first
  480. // entrance to COW, and no writes to the
  481. // LStream will happen before then.
  482. //
  483. // Returns: S_OK if call completed OK.
  484. //
  485. // History: 18-Jul-91 PhilipLa Created.
  486. // 12-Jun-92 PhilipLa Added fDelay.
  487. //
  488. //---------------------------------------------------------------------------
  489. SCODE CMStream::InitNew(BOOL fDelay, ULARGE_INTEGER uliSize)
  490. {
  491. SCODE sc;
  492. msfDebugOut((DEB_ITRACE,"In CMStream::InitNew()\n"));
  493. #ifdef LARGE_DOCFILE
  494. ULONGLONG ulParentSize = 0;
  495. #else
  496. ULONG ulParentSize = 0;
  497. #endif
  498. msfChk(InitCommon());
  499. if (!_fIsScratch)
  500. {
  501. #ifdef LARGE_DOCFILE
  502. ulParentSize = uliSize.QuadPart;
  503. #else
  504. msfAssert (ULIGetHigh(uliSize) == 0);
  505. ulParentSize = ULIGetLow(uliSize);
  506. #endif
  507. if (!fDelay && ulParentSize > 0)
  508. {
  509. ULARGE_INTEGER ulTmp;
  510. ULISet32(ulTmp, 0);
  511. (*_pplstParent)->SetSize(ulTmp);
  512. }
  513. }
  514. _fBlockWrite = (ulParentSize == 0) ? FALSE : fDelay;
  515. msfChk(_fatDif.InitNew(this));
  516. msfChk(_fat.InitNew(this));
  517. if (!_fIsScratch || _fIsNoScratch)
  518. {
  519. msfChk(_fatMini.InitNew(this));
  520. }
  521. if (!_fIsScratch)
  522. {
  523. msfChk(_dir.InitNew(this));
  524. BYTE *pbBuf;
  525. msfMem(pbBuf = (BYTE *) GetMalloc()->Alloc(GetSectorSize()));
  526. _pCopySectBuf = P_TO_BP(CBasedBytePtr, pbBuf);
  527. #ifdef LARGE_STREAMS
  528. ULONGLONG ulSize;
  529. #else
  530. ULONG ulSize;
  531. #endif
  532. msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
  533. CDirectStream *pdsTemp;
  534. msfMem(pdsTemp = new(GetMalloc()) CDirectStream(MINISTREAM_LUID));
  535. _pdsministream = P_TO_BP(CBasedDirectStreamPtr, pdsTemp);
  536. _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
  537. }
  538. //If we have a zero length original file, this will create an
  539. // empty Docfile on the disk. If the original file was
  540. // not zero length, then the Flush operations will be skipped
  541. // by _fBlockWrite and the file will be unmodified.
  542. if (!_fBlockWrite)
  543. {
  544. msfChk(Flush(0));
  545. }
  546. _fTruncate = (ulParentSize != 0);
  547. _fBlockWrite = fDelay;
  548. msfDebugOut((DEB_ITRACE,"Out CMStream::InitNew()\n"));
  549. return S_OK;
  550. Err:
  551. Empty();
  552. return sc;
  553. }
  554. //+---------------------------------------------------------------------------
  555. //
  556. // Member: CMStream::ConvertILB, private
  557. //
  558. // Synopsis: Copy the first sector of the underlying ILockBytes
  559. // out to the end.
  560. //
  561. // Arguments: [sectMax] -- Total number of sectors in the ILockBytes
  562. //
  563. // Returns: Appropriate status code
  564. //
  565. // History: 03-Feb-93 PhilipLa Created
  566. //
  567. //----------------------------------------------------------------------------
  568. SCODE CMStream::ConvertILB(SECT sectMax)
  569. {
  570. SCODE sc;
  571. BYTE *pb;
  572. ULONG cbNull;
  573. GetSafeBuffer(GetSectorSize(), GetSectorSize(), &pb, &cbNull);
  574. ULONG ulTemp;
  575. ULARGE_INTEGER ulTmp;
  576. ULISet32(ulTmp, 0);
  577. msfHChk((*_pplstParent)->ReadAt(ulTmp, pb, GetSectorSize(), &ulTemp));
  578. ULARGE_INTEGER ulNewPos;
  579. #ifdef LARGE_DOCFILE
  580. ulNewPos.QuadPart = sectMax << GetSectorShift();
  581. #else
  582. ULISet32(ulNewPos, sectMax << GetSectorShift());
  583. #endif
  584. msfDebugOut((DEB_ITRACE,"Copying first sector out to %lu\n",
  585. ULIGetLow(ulNewPos)));
  586. msfHChk((*_pplstParent)->WriteAt(
  587. ulNewPos,
  588. pb,
  589. GetSectorSize(),
  590. &ulTemp));
  591. Err:
  592. FreeBuffer(pb);
  593. return sc;
  594. }
  595. //+-------------------------------------------------------------------------
  596. //
  597. // Method: CMStream::InitConvert, public
  598. //
  599. // Synopsis: Init function used in conversion of files to multi
  600. // streams.
  601. //
  602. // Arguments: [fDelayConvert] -- If true, the actual file is not
  603. // touched until a BeginCopyOnWrite()
  604. //
  605. // Returns: S_OK if everything completed OK.
  606. //
  607. // Algorithm: *Finish This*
  608. //
  609. // History: 28-May-92 Philipla Created.
  610. //
  611. // Notes: We are allowed to fail here in low memory
  612. //
  613. //--------------------------------------------------------------------------
  614. SCODE CMStream::InitConvert(BOOL fDelayConvert)
  615. {
  616. SCODE sc;
  617. SECT sectMax;
  618. CDfName const dfnContents(wcsContents);
  619. msfAssert(!_fIsScratch &&
  620. aMsg("Called InitConvert on scratch multistream"));
  621. _fBlockWrite = fDelayConvert;
  622. msfAssert(!_fBlockWrite &&
  623. aMsg("Delayed conversion not supported in this release."));
  624. msfChk(InitCommon());
  625. STATSTG stat;
  626. (*_pplstParent)->Stat(&stat, STATFLAG_NONAME);
  627. #ifndef LARGE_DOCFILE
  628. msfAssert (ULIGetHigh(stat.cbSize) == 0);
  629. #endif
  630. msfDebugOut((DEB_ITRACE,"Size is: %lu\n",ULIGetLow(stat.cbSize)));
  631. #ifdef LARGE_DOCFILE
  632. sectMax = (SECT) ((stat.cbSize.QuadPart + GetSectorSize() - 1) >>
  633. GetSectorShift());
  634. #else
  635. sectMax = (ULIGetLow(stat.cbSize) + GetSectorSize() - 1) >>
  636. GetSectorShift();
  637. #endif
  638. SECT sectMaxMini;
  639. BOOL fIsMini;
  640. fIsMini = FALSE;
  641. //If the CONTENTS stream will be in the Minifat, compute
  642. // the number of Minifat sectors needed.
  643. #ifdef LARGE_DOCFILE
  644. if (stat.cbSize.QuadPart < MINISTREAMSIZE)
  645. #else
  646. if (ULIGetLow(stat.cbSize) < MINISTREAMSIZE)
  647. #endif
  648. {
  649. sectMaxMini = (ULIGetLow(stat.cbSize) + MINISECTORSIZE - 1) >>
  650. MINISECTORSHIFT;
  651. fIsMini = TRUE;
  652. }
  653. BYTE *pbBuf;
  654. msfMem(pbBuf = (BYTE *) GetMalloc()->Alloc(GetSectorSize()));
  655. _pCopySectBuf = P_TO_BP(CBasedBytePtr, pbBuf);
  656. msfChk(_fatDif.InitConvert(this, sectMax));
  657. msfChk(_fat.InitConvert(this, sectMax));
  658. msfChk(_dir.InitNew(this));
  659. msfChk(fIsMini ? _fatMini.InitConvert(this, sectMaxMini)
  660. : _fatMini.InitNew(this));
  661. SID sid;
  662. msfChk(CreateEntry(SIDROOT, &dfnContents, STGTY_STREAM, &sid));
  663. #ifdef LARGE_STREAMS
  664. msfChk(_dir.SetSize(sid, stat.cbSize.QuadPart));
  665. #else
  666. msfChk(_dir.SetSize(sid, ULIGetLow(stat.cbSize)));
  667. #endif
  668. if (!fIsMini)
  669. msfChk(_dir.SetStart(sid, sectMax - 1));
  670. else
  671. {
  672. msfChk(_dir.SetStart(sid, 0));
  673. msfChk(_dir.SetStart(SIDMINISTREAM, sectMax - 1));
  674. #ifdef LARGE_STREAMS
  675. msfChk(_dir.SetSize(SIDMINISTREAM, stat.cbSize.QuadPart));
  676. #else
  677. msfChk(_dir.SetSize(SIDMINISTREAM, ULIGetLow(stat.cbSize)));
  678. #endif
  679. }
  680. #ifdef LARGE_STREAMS
  681. ULONGLONG ulMiniSize;
  682. #else
  683. ULONG ulMiniSize;
  684. #endif
  685. msfChk(_dir.GetSize(SIDMINISTREAM, &ulMiniSize));
  686. CDirectStream *pdsTemp;
  687. msfMem(pdsTemp = new(GetMalloc()) CDirectStream(MINISTREAM_LUID));
  688. _pdsministream = P_TO_BP(CBasedDirectStreamPtr, pdsTemp);
  689. _pdsministream->InitSystem(this, SIDMINISTREAM, ulMiniSize);
  690. if (!_fBlockWrite)
  691. {
  692. msfChk(ConvertILB(sectMax));
  693. msfChk(Flush(0));
  694. }
  695. return S_OK;
  696. Err:
  697. Empty();
  698. return sc;
  699. }
  700. //+-------------------------------------------------------------------------
  701. //
  702. // Method: CMStream::FlushHeader, public
  703. //
  704. // Synopsis: Flush the header to the LStream.
  705. //
  706. // Arguments: [uForce] -- Flag to determine if header should be
  707. // flushed while in copy on write mode.
  708. //
  709. // Returns: S_OK if call completed OK.
  710. // S_OK if the MStream is in copy on write mode or
  711. // is Unconverted and the header was not flushed.
  712. //
  713. // Algorithm: Write the complete header out to the 0th position of
  714. // the LStream.
  715. //
  716. // History: 11-Dec-91 PhilipLa Created.
  717. // 18-Feb-92 PhilipLa Added copy on write support.
  718. //
  719. // Notes:
  720. //
  721. //--------------------------------------------------------------------------
  722. SCODE CMStream::FlushHeader(USHORT uForce)
  723. {
  724. ULONG ulTemp;
  725. SCODE sc;
  726. msfDebugOut((DEB_ITRACE,"In CMStream::FlushHeader()\n"));
  727. if (_fIsScratch || _fBlockWrite ||
  728. ((_fBlockHeader) && (!(uForce & HDR_FORCE))))
  729. {
  730. return S_OK;
  731. }
  732. //If the header isn't dirty, we don't flush it unless forced to.
  733. if (!(uForce & HDR_FORCE) && !(_hdr.IsDirty()))
  734. {
  735. return S_OK;
  736. }
  737. ULARGE_INTEGER ulOffset;
  738. ULISet32(ulOffset, 0);
  739. USHORT usSectorSize = GetSectorSize();
  740. if (usSectorSize == HEADERSIZE || _fIsScratch)
  741. {
  742. sc = (*_pplstParent)->WriteAt(ulOffset, (BYTE *)_hdr.GetData(),
  743. sizeof(CMSFHeaderData), &ulTemp);
  744. }
  745. else
  746. {
  747. msfAssert (_pCopySectBuf != NULL);
  748. memset (_pCopySectBuf, 0, usSectorSize);
  749. memcpy (_pCopySectBuf, _hdr.GetData(), sizeof(CMSFHeaderData));
  750. sc = (*_pplstParent)->WriteAt(ulOffset, _pCopySectBuf,
  751. usSectorSize, &ulTemp);
  752. }
  753. if (sc == E_PENDING)
  754. {
  755. sc = STG_E_PENDINGCONTROL;
  756. }
  757. msfDebugOut((DEB_ITRACE,"Out CMStream::FlushHeader()\n"));
  758. if (SUCCEEDED(sc))
  759. {
  760. _hdr.ResetDirty();
  761. }
  762. return sc;
  763. }
  764. //+-------------------------------------------------------------------------
  765. //
  766. // Method: CMStream::BeginCopyOnWrite, public
  767. //
  768. // Synopsis: Switch the multistream into copy on write mode
  769. //
  770. // Effects: Creates new in-core copies of the Fat, Directory, and
  771. // header.
  772. //
  773. // Arguments: None.
  774. //
  775. // Requires: The multistream cannot already be in copy on write
  776. // mode.
  777. //
  778. // Returns: S_OK if the call completed OK.
  779. // STG_E_ACCESSDENIED if multistream was already in COW mode
  780. //
  781. // Algorithm: Retrieve and store size of parent LStream.
  782. // If _fUnconverted & _fTruncate, call SetSize(0)
  783. // on the parent LStream.
  784. // If _fUnconverted, then flush all control structures.
  785. // Copy all control structures, and switch in the shadow
  786. // copies for current use.
  787. // Return S_OK.
  788. //
  789. // History: 18-Feb-92 PhilipLa Created.
  790. // 09-Jun-92 PhilipLa Added support for fUnconverted
  791. //
  792. // Notes:
  793. //
  794. //--------------------------------------------------------------------------
  795. SCODE CMStream::BeginCopyOnWrite(DWORD const dwFlags)
  796. {
  797. msfDebugOut((DEB_ITRACE,"In CMStream::BeginCopyOnWrite()\n"));
  798. SCODE sc;
  799. msfAssert(!_fBlockHeader &&
  800. aMsg("Tried to reenter Copy-on-Write mode."));
  801. msfAssert(!_fIsScratch &&
  802. aMsg("Tried to enter Copy-on-Write mode in scratch."));
  803. msfAssert(!_fIsNoScratch &&
  804. aMsg("Copy-on-Write started for NoScratch."));
  805. //_fBlockWrite is true if we have a delayed conversion or
  806. // truncation.
  807. if (_fBlockWrite)
  808. {
  809. //In the overwrite case, we don't want to release any
  810. // disk space, so we skip this step.
  811. if ((_fTruncate) && !(dwFlags & STGC_OVERWRITE) &&
  812. (_pmsScratch == NULL))
  813. {
  814. ULARGE_INTEGER ulTmp;
  815. ULISet32(ulTmp, 0);
  816. msfHChk((*_pplstParent)->SetSize(ulTmp));
  817. }
  818. if (!(dwFlags & STGC_OVERWRITE))
  819. {
  820. _fBlockHeader = TRUE;
  821. }
  822. _fBlockWrite = FALSE;
  823. msfChk(Flush(0));
  824. _fBlockHeader = FALSE;
  825. _fTruncate = FALSE;
  826. }
  827. STATSTG stat;
  828. msfHChk((*_pplstParent)->Stat(&stat, STATFLAG_NONAME));
  829. #ifdef LARGE_DOCFILE
  830. _ulParentSize = stat.cbSize.QuadPart;
  831. msfDebugOut((DEB_ITRACE,"Parent size at begin is %Lu\n",_ulParentSize));
  832. #else
  833. msfAssert(ULIGetHigh(stat.cbSize) == 0);
  834. _ulParentSize = ULIGetLow(stat.cbSize);
  835. msfDebugOut((DEB_ITRACE,"Parent size at begin is %lu\n",_ulParentSize));
  836. #endif
  837. if (_fIsNoSnapshot)
  838. {
  839. SECT sectNoSnapshot;
  840. #ifdef LARGE_DOCFILE
  841. sectNoSnapshot = (SECT) ((_ulParentSize - GetSectorSize() +
  842. #else
  843. sectNoSnapshot = (SECT) ((_ulParentSize - HEADERSIZE +
  844. #endif
  845. GetSectorSize() - 1) / GetSectorSize());
  846. _fat.SetNoSnapshot(sectNoSnapshot);
  847. }
  848. //We flush out all of our current dirty pages - after this point,
  849. // we know that any dirty pages should be remapped before being
  850. // written out, assuming we aren't in overwrite mode.
  851. msfChk(Flush(0));
  852. if (!(dwFlags & STGC_OVERWRITE))
  853. {
  854. SECT sectTemp;
  855. if (_pmsScratch == NULL)
  856. {
  857. msfChk(_fat.FindMaxSect(&sectTemp));
  858. }
  859. else
  860. {
  861. msfChk(_fat.FindLast(&sectTemp));
  862. }
  863. _pmsShadow->InitCopy(this);
  864. _pmsShadow->_pdsministream = NULL;
  865. _fat.SetCopyOnWrite(_pmsShadow->GetFat(), sectTemp);
  866. _fBlockHeader = TRUE;
  867. msfChk(_fatDif.RemapSelf());
  868. if (_fIsNoSnapshot)
  869. msfChk(_fat.ResizeNoSnapshot());
  870. msfChk(_fatDif.Fixup(BP_TO_P(CMStream *, _pmsShadow)));
  871. if (_fIsNoSnapshot)
  872. _fat.ResetNoSnapshotFree();
  873. #if DBG == 1
  874. _fat.CheckFreeCount();
  875. #endif
  876. }
  877. else
  878. {
  879. _fat.SetCopyOnWrite(NULL, 0);
  880. }
  881. msfDebugOut((DEB_ITRACE,"Out CMStream::BeginCopyOnWrite()\n"));
  882. return S_OK;
  883. Err:
  884. _fBlockHeader = FALSE;
  885. _pmsShadow->Empty();
  886. _fat.ResetCopyOnWrite();
  887. if (_fIsNoSnapshot)
  888. _fat.ResetNoSnapshotFree();
  889. return sc;
  890. }
  891. //+-------------------------------------------------------------------------
  892. //
  893. // Method: CMStream::EndCopyOnWrite, public
  894. //
  895. // Synopsis: End copy on write mode, either by committing the current
  896. // changes (in which case a merge is performed), or by
  897. // aborting the changes, in which case the persistent form
  898. // of the multistream should be identical to its form
  899. // before copy on write mode was entered.
  900. //
  901. // Effects: *Finish This*
  902. //
  903. // Arguments: [df] -- Flags to determine commit or abort status.
  904. //
  905. // Requires: The multistream must be in copy on write mode.
  906. //
  907. // Returns: S_OK if call completed OK.
  908. // STG_E_ACCESSDENIED if MStream was not in COW mode.
  909. //
  910. // Algorithm: If aborting, delete all shadow structures,
  911. // call SetSize() on parent LStream to restore
  912. // original size, and switch active controls back
  913. // to originals.
  914. // If committing, delete all old structures, switch
  915. // shadows into original position.
  916. //
  917. // History: 18-Feb-92 PhilipLa Created.
  918. // 09-Jun-92 Philipla Added support for fUnconverted
  919. //
  920. // Notes:
  921. //
  922. //--------------------------------------------------------------------------
  923. SCODE CMStream::EndCopyOnWrite(
  924. DWORD const dwCommitFlags,
  925. DFLAGS const df)
  926. {
  927. SCODE sc = S_OK;
  928. msfDebugOut((DEB_ITRACE,"In CMStream::EndCopyOnWrite(%lu)\n",df));
  929. BOOL fFlush = FLUSH_CACHE(dwCommitFlags);
  930. if (dwCommitFlags & STGC_OVERWRITE)
  931. {
  932. if (_pmsScratch != NULL)
  933. {
  934. msfChk(_fatDif.Fixup(NULL));
  935. _fat.ResetCopyOnWrite();
  936. }
  937. msfChk(Flush(fFlush));
  938. }
  939. else
  940. {
  941. msfAssert(_fBlockHeader &&
  942. aMsg("Tried to exit copy-on-write mode without entering."));
  943. ULARGE_INTEGER ulParentSize = {0,0};
  944. if (P_ABORT(df))
  945. {
  946. msfDebugOut((DEB_ITRACE,"Aborting Copy On Write mode\n"));
  947. Empty();
  948. InitCopy(BP_TO_P(CMStream *, _pmsShadow));
  949. #ifdef LARGE_DOCFILE
  950. ulParentSize.QuadPart = _ulParentSize;
  951. #else
  952. ULISetLow(ulParentSize, _ulParentSize);
  953. #endif
  954. }
  955. else
  956. {
  957. SECT sectMax;
  958. msfChk(_fatDif.Fixup(BP_TO_P(CMStream *, _pmsShadow)));
  959. msfChk(Flush(fFlush));
  960. _fat.ResetCopyOnWrite();
  961. msfChk(_fat.GetMaxSect(&sectMax));
  962. #ifdef LARGE_DOCFILE
  963. ulParentSize.QuadPart = ConvertSectOffset(sectMax, 0,
  964. GetSectorShift());
  965. #else
  966. ULISetLow(ulParentSize, ConvertSectOffset(sectMax, 0,
  967. GetSectorShift()));
  968. #endif
  969. msfChk(FlushHeader(HDR_FORCE));
  970. msfVerify(SUCCEEDED(ILBFlush(*_pplstParent, fFlush)) &&
  971. aMsg("CMStream::EndCopyOnWrite ILBFLush failed. "
  972. "Non-fatal, hit Ok."));
  973. }
  974. //
  975. // Shrink the file if the size got smaller.
  976. // Don't shrink if we are in NoSnapshot mode, unless the NoSnapshot
  977. // limit has been set to 0 by Consolidate.
  978. //We don't ever expect this SetSize to fail, since it
  979. // should never attempt to enlarge the file.
  980. if (!_fIsNoSnapshot || 0 == _fat.GetNoSnapshot())
  981. {
  982. #ifdef LARGE_DOCFILE
  983. if (ulParentSize.QuadPart < _ulParentSize)
  984. #else
  985. if (ULIGetLow(ulParentSize) < _ulParentSize)
  986. #endif
  987. {
  988. olHVerSucc((*_pplstParent)->SetSize(ulParentSize));
  989. }
  990. }
  991. _pmsShadow->Empty();
  992. _fBlockHeader = FALSE;
  993. _fNewConvert = FALSE;
  994. }
  995. if (_pmsScratch != NULL)
  996. {
  997. //Let the no-scratch fat pick up whatever changed we've made.
  998. _pmsScratch->InitScratch(this, FALSE);
  999. }
  1000. if (!_fIsNoSnapshot)
  1001. {
  1002. //In no-snapshot mode, we can't let the file shrink, since
  1003. //we might blow away someone else's state.
  1004. _ulParentSize = 0;
  1005. }
  1006. {
  1007. SCODE sc2 = SetSize();
  1008. msfVerify((SUCCEEDED(sc2) || (sc2 == E_PENDING)) &&
  1009. aMsg("SetSize after copy-on-write failed."));
  1010. }
  1011. if (_fIsNoSnapshot)
  1012. {
  1013. _ulParentSize = 0;
  1014. _fat.SetNoSnapshot(0);
  1015. }
  1016. #if DBG == 1
  1017. STATSTG stat;
  1018. msfHChk((*_pplstParent)->Stat(&stat, STATFLAG_NONAME));
  1019. #ifndef LARGE_DOCFILE
  1020. msfAssert(ULIGetHigh(stat.cbSize) == 0);
  1021. #endif
  1022. msfDebugOut((DEB_ITRACE, "Parent size at end is %lu\n",
  1023. ULIGetLow(stat.cbSize)));
  1024. #endif
  1025. msfDebugOut((DEB_ITRACE,"Out CMStream::EndCopyOnWrite()\n"));
  1026. Err:
  1027. return sc;
  1028. }
  1029. //+---------------------------------------------------------------------------
  1030. //
  1031. // Member: CMStream::Consolidate, public
  1032. //
  1033. // Synopsis: Fill in the holes of a file by moving blocks toward the front.
  1034. //
  1035. // Arguments:
  1036. //
  1037. // Returns: Appropriate status code
  1038. //
  1039. // Algorithm: 1) Find a limit that all blocks should be moved below.
  1040. // The limit includes all the data, a new FAT, DIFAT and
  1041. // DirStream, and doesn't disturb the old fat/dif/dir blocks.
  1042. // 2) Move new fat/dif/dir sectors down. We do this with the
  1043. // cache's copy-on-write DIRTY behaviour.
  1044. // 3) Stream by stream move all the high sectors down.
  1045. //
  1046. // History: 11-Feb-1997 BChapman Created
  1047. //
  1048. // Notes: 1) This is called in the contex of Begin/End Copy-on-Write.
  1049. // 2) We assume throughout that the underlying free sector allocator
  1050. // returns the first free sector of the file.
  1051. // 3) The old fat/dif/dir may leave small holes in the finished file.
  1052. //----------------------------------------------------------------------------
  1053. SCODE CMStream::Consolidate(void)
  1054. {
  1055. //
  1056. // We don't support NOSCRATCH and this should have already
  1057. // been checked in the caller.
  1058. //
  1059. msfAssert(_pmsScratch == NULL);
  1060. SCODE sc=S_OK;
  1061. ULONG cAllocatedSects;
  1062. ULONG cDirEntries;
  1063. CDirEntry *pde=NULL;
  1064. SID sid;
  1065. ULONG sectLast = 0; // Last allocated Sector #.
  1066. ULONG csectFree = 0; // #sects that are free.
  1067. SECT sectLimit; // #sects we will try to shrink the file into.
  1068. ULONG csectLowDIF; // #DIF sects below sectLimit.
  1069. ULONG csectLowFAT; // #FAT sects below sectLimit.
  1070. ULONG csectLowControl; // #motion sensitive sects below sectLimit.
  1071. SECT *psectControl; // list of Dir and Mini Fat sectors
  1072. ULONG csectControl; // # of sects in psectControl
  1073. ULONG i;
  1074. SECT sectType;
  1075. //
  1076. // It is quite impossible to consolidate a file when the Snapshot
  1077. // limits are in effect. This routine is only called when we have
  1078. // confirmed there are no other "seperate" writers. So it should be
  1079. // safe to turn off the snapshot limits.
  1080. //
  1081. if(_fIsNoSnapshot)
  1082. {
  1083. _fat.SetNoSnapshot(0);
  1084. _fat.ResetNoSnapshotFree();
  1085. }
  1086. //
  1087. // Compute the Number of allocated sectors in the file.
  1088. // Ignore the header.
  1089. //
  1090. msfChk(_fat.FindLast(&sectLast));
  1091. sectLast--;
  1092. msfChk(_fat.CountSectType(&csectFree, 0, sectLast, FREESECT));
  1093. //
  1094. // Compute the expected size of the consolidated file. We will
  1095. // use this limit to determine when a sector is too high and needs
  1096. // to be copied down.
  1097. //
  1098. sectLimit = sectLast - csectFree;
  1099. //
  1100. // We will move the stream data sectors by copying them to free
  1101. // sectors and releasing the old sector.
  1102. // But, there are a class of sectors (control structures: FAT, DIF,
  1103. // miniFat, Directory Stream) that the old sector cannot be freed until
  1104. // end-copy-on-write.
  1105. // It is possible that the old (original) versions of these sectors
  1106. // could exist below sectLimit and with therefore be taking up "dead"
  1107. // space in the resulting file. So we need to adjust sectLimit.
  1108. //
  1109. // We are in Copy-On-Write mode so any FAT, DIF, Directory Stream, or
  1110. // MiniFat sector that is modified (by moving other sectors) will be
  1111. // copied to a free sector by the cache manager.
  1112. // It is difficult to know ahead of time which Low FAT sectors won't
  1113. // be touched, and therefore can avoid being copied, so we just assume
  1114. // we need to make a complete copy of the FAT, DIF, Directory Stream,
  1115. // and MiniFAT.
  1116. //
  1117. // Count the number of FAT (and DIFat) blocks up to sectLimit.
  1118. //
  1119. msfChk(_fat.CountSectType(&csectLowFAT, 0, sectLimit, FATSECT));
  1120. msfChk(_fat.CountSectType(&csectLowDIF, 0, sectLimit, DIFSECT));
  1121. //
  1122. // Build a list of sectors in the Directory Stream and MiniFat
  1123. //
  1124. msfChk(BuildConsolidationControlSectList(&psectControl, &csectControl));
  1125. //
  1126. // Sum all the copy-on-write control sectors below sectLimit.
  1127. //
  1128. csectLowControl = csectLowFAT + csectLowDIF;
  1129. for(i=0; i<csectControl; i++)
  1130. {
  1131. if(psectControl[i] < sectLimit)
  1132. ++csectLowControl;
  1133. }
  1134. //
  1135. // Now we adjust sectLimit. (see large comment above)
  1136. // We want to increase it by csectLowControl # of sectors.
  1137. // But, advancing over new control sectors doesn't help make space
  1138. // so skip over those.
  1139. // Note: In a well packed file we can hit EOF while doing this.
  1140. //
  1141. for( ; csectLowControl > 0; ++sectLimit)
  1142. {
  1143. if(sectLimit >= sectLast)
  1144. {
  1145. LocalFree(psectControl);
  1146. return S_OK;
  1147. }
  1148. msfChkTo(Err_FreeList, _fat.GetNext(sectLimit, &sectType));
  1149. if( FATSECT != sectType
  1150. && DIFSECT != sectType
  1151. && (! IsSectorInList(sectLimit, psectControl, csectControl)) )
  1152. {
  1153. --csectLowControl;
  1154. }
  1155. }
  1156. //
  1157. // We are done with the control sector list.
  1158. //
  1159. LocalFree(psectControl);
  1160. psectControl = NULL;
  1161. //
  1162. // At Last! We begin to move some data.
  1163. // Iterate through the directory.
  1164. // Remapping the sectors of each Stream to below sectLimit.
  1165. //
  1166. cDirEntries = _dir.GetNumDirEntries();
  1167. for(sid=0; sid<cDirEntries; sid++)
  1168. {
  1169. //
  1170. // Always get the directory entry "for-writing".
  1171. // This has the effect of remapping each sector of the directory
  1172. // stream down into the front of the file.
  1173. //
  1174. msfChk(_dir.GetDirEntry(sid, FB_DIRTY, &pde));
  1175. switch(pde->GetFlags())
  1176. {
  1177. case STGTY_LOCKBYTES:
  1178. case STGTY_PROPERTY:
  1179. case STGTY_STORAGE:
  1180. case STGTY_INVALID:
  1181. default:
  1182. break;
  1183. //
  1184. // Remap The Mini-stream
  1185. //
  1186. case STGTY_ROOT:
  1187. msfChkTo(Err_Release, ConsolidateStream(pde, sectLimit));
  1188. GetMiniStream()->EmptyCache();
  1189. break;
  1190. //
  1191. // Remap the regular streams.
  1192. // Don't remap streams in the mini-streams
  1193. //
  1194. case STGTY_STREAM:
  1195. #ifdef LARGE_STREAMS
  1196. if(pde->GetSize(_dir.IsLargeSector()) < MINISTREAMSIZE)
  1197. #else
  1198. if(pde->GetSize() < MINISTREAMSIZE)
  1199. #endif
  1200. break;
  1201. msfChkTo(Err_Release, ConsolidateStream(pde, sectLimit));
  1202. break;
  1203. }
  1204. _dir.ReleaseEntry(sid);
  1205. }
  1206. //
  1207. // If there are any remaining un-remapped FAT blocks, remap them now.
  1208. // (begin-copy-on-write already remapped the DIF).
  1209. //
  1210. msfChk(_fat.DirtyAll());
  1211. msfChk(_fatMini.DirtyAll());
  1212. return sc;
  1213. Err_FreeList:
  1214. LocalFree(psectControl);
  1215. return sc;
  1216. Err_Release:
  1217. _dir.ReleaseEntry(sid);
  1218. Err:
  1219. return sc;
  1220. }
  1221. //+---------------------------------------------------------------------------
  1222. //
  1223. // Member: CMStream::BuildConsolidationControlSectList, private
  1224. //
  1225. // Synopsis: Makes a list of all the sectors that are copy-on-write
  1226. // for the purpose of computing how much space we need to
  1227. // make to Consolidate a file.
  1228. //
  1229. // Arguments: [ppsectList] -- [out] pointer to a list of sectors.
  1230. // [pcsect] -- [out] count of sectors on the list.
  1231. //
  1232. // Returns: Appropriate status code
  1233. //
  1234. // Modifies:
  1235. //
  1236. // History: 25-feb-1997 BChapman Created
  1237. //
  1238. //----------------------------------------------------------------------------
  1239. SCODE CMStream::BuildConsolidationControlSectList(
  1240. SECT **ppsectList,
  1241. ULONG *pcsect)
  1242. {
  1243. SECT sect;
  1244. SECT *psectList;
  1245. ULONG i, csect;
  1246. SCODE sc;
  1247. csect = _dir.GetNumDirSects() + _hdr.GetMiniFatLength();
  1248. msfMem(psectList = (SECT*) LocalAlloc(LPTR, sizeof(SECT) * csect));
  1249. i = 0;
  1250. //
  1251. // Walk the Directory Stream FAT chain and record all
  1252. // the sector numbers.
  1253. //
  1254. sect = _hdr.GetDirStart();
  1255. while(sect != ENDOFCHAIN)
  1256. {
  1257. msfAssert(i < csect);
  1258. psectList[i++] = sect;
  1259. msfChkTo(Err_Free, _fat.GetNext(sect, &sect));
  1260. }
  1261. msfAssert(i == _dir.GetNumDirSects());
  1262. //
  1263. // Walk the MiniFat FAT chain and record all
  1264. // the sector numbers.
  1265. //
  1266. sect = _hdr.GetMiniFatStart();
  1267. while(sect != ENDOFCHAIN)
  1268. {
  1269. msfAssert(i < csect);
  1270. psectList[i++] = sect;
  1271. msfChkTo(Err_Free, _fat.GetNext(sect, &sect));
  1272. }
  1273. msfAssert((i == csect) && aMsg("Directory Stream + MiniFat too short\n"));
  1274. *ppsectList = psectList;
  1275. *pcsect = csect;
  1276. return S_OK;
  1277. Err_Free:
  1278. LocalFree(psectList);
  1279. return sc;
  1280. Err:
  1281. return sc;
  1282. }
  1283. //+---------------------------------------------------------------------------
  1284. //
  1285. // Member: CMStream::IsSectorOnList, private
  1286. //
  1287. // Synopsis: Searches a list of sector values for a given value.
  1288. //
  1289. // Arguments: [sect] -- [in] value to search for.
  1290. // [psectList] -- [in] list of sectors.
  1291. // [csect] -- [in] count of sectors on the list.
  1292. //
  1293. // Returns: TRUE if the sector is on the list, otherwise FALSE.
  1294. //
  1295. // Modifies:
  1296. //
  1297. // History: 25-feb-1997 BChapman Created
  1298. //
  1299. // Notes:
  1300. //
  1301. //----------------------------------------------------------------------------
  1302. BOOL CMStream::IsSectorInList(
  1303. SECT sect,
  1304. SECT *psectList,
  1305. ULONG csectList)
  1306. {
  1307. ULONG i;
  1308. for(i=0; i < csectList; i++)
  1309. {
  1310. if(sect == psectList[i])
  1311. return TRUE;
  1312. }
  1313. return FALSE;
  1314. }
  1315. //+---------------------------------------------------------------------------
  1316. //
  1317. // Member: CMStream::ConsolidateStream, private
  1318. //
  1319. // Synopsis: Scan the stream FAT chain and remap sectors that are
  1320. // above the given limit.
  1321. //
  1322. // Arguments: [pde] -- Directory entry of the stream (DIRTY)
  1323. // [sectLimit] -- sector limit that all sectors should be below
  1324. //
  1325. // Returns: Appropriate status code
  1326. //
  1327. // Modifies:
  1328. //
  1329. // History: 18-feb-1997 BChapman Created
  1330. //
  1331. // Notes:
  1332. //
  1333. //----------------------------------------------------------------------------
  1334. SCODE CMStream::ConsolidateStream(
  1335. CDirEntry *pde, // Current CDirEntry Object (read-only)
  1336. SECT sectLimit) // Move all sectors below this sector#
  1337. {
  1338. SECT sectPrev, sectCurrent, sectNew;
  1339. ULONG cbLength;
  1340. SCODE sc=S_OK;
  1341. //
  1342. // This code should not be used in NOSCRATCH mode.
  1343. //
  1344. msfAssert(_pmsScratch == NULL);
  1345. //
  1346. // Check the first sector of the stream as a special case.
  1347. //
  1348. sectCurrent = pde->GetStart();
  1349. if(ENDOFCHAIN != sectCurrent && sectCurrent > sectLimit)
  1350. {
  1351. msfChk(_fat.GetFree(1, &sectNew, GF_WRITE));
  1352. // This is only here because I don't understand GetFree().
  1353. msfAssert(ENDOFCHAIN != sectNew);
  1354. msfChk(MoveSect(ENDOFCHAIN, sectCurrent, sectNew));
  1355. sectCurrent = sectNew;
  1356. pde->SetStart(sectCurrent);
  1357. }
  1358. //
  1359. // Do the rest of the stream FAT chain.
  1360. //
  1361. sectPrev = sectCurrent;
  1362. while(ENDOFCHAIN != sectPrev)
  1363. {
  1364. msfChk(_fat.GetNext(sectPrev, &sectCurrent));
  1365. if(ENDOFCHAIN != sectCurrent && sectCurrent > sectLimit)
  1366. {
  1367. msfChk(_fat.GetFree(1, &sectNew, GF_WRITE));
  1368. // This is only here because I don't understand GetFree().
  1369. msfAssert(ENDOFCHAIN != sectNew);
  1370. msfChk(MoveSect(sectPrev, sectCurrent, sectNew));
  1371. sectCurrent = sectNew;
  1372. }
  1373. sectPrev = sectCurrent;
  1374. }
  1375. Err:
  1376. return sc;
  1377. }
  1378. //+---------------------------------------------------------------------------
  1379. //
  1380. // Member: CMStream::MoveSect, private
  1381. //
  1382. // Synopsis: Move Data Sector for Consolidation Support.
  1383. //
  1384. // Arguments: [sectPrev] -- Previous sector, so the link can be updated.
  1385. // [sectOld] -- Location to copy from
  1386. // [sectNew] -- Location to copy to
  1387. //
  1388. // Returns: Appropriate status code
  1389. //
  1390. // Modifies:
  1391. //
  1392. // History: 20-Feb-1997 BChapman Created
  1393. //
  1394. // Notes:
  1395. //
  1396. //----------------------------------------------------------------------------
  1397. SCODE CMStream::MoveSect(
  1398. SECT sectPrev,
  1399. SECT sectOld,
  1400. SECT sectNew)
  1401. {
  1402. ULONG cb;
  1403. SCODE sc=S_OK;
  1404. ULARGE_INTEGER ulOff;
  1405. BYTE *pbScratch = BP_TO_P(BYTE HUGEP *, _pCopySectBuf);
  1406. //
  1407. // This code does not expect NOSCRATCH mode.
  1408. //
  1409. msfAssert(_pmsScratch == NULL);
  1410. //
  1411. // Copy the data from the old sector to the new sector.
  1412. //
  1413. ulOff.QuadPart = ConvertSectOffset(sectOld, 0, GetSectorShift());
  1414. msfChk((*_pplstParent)->ReadAt(ulOff,
  1415. pbScratch,
  1416. GetSectorSize(),
  1417. &cb));
  1418. ulOff.QuadPart = ConvertSectOffset(sectNew, 0, GetSectorShift());
  1419. msfChk((*_pplstParent)->WriteAt(ulOff,
  1420. pbScratch,
  1421. GetSectorSize(),
  1422. &cb));
  1423. //
  1424. // Update the previous sector's link (if this isn't the first sector)
  1425. //
  1426. if(ENDOFCHAIN != sectPrev)
  1427. {
  1428. msfChk(_fat.SetNext(sectPrev, sectNew));
  1429. }
  1430. //
  1431. // Update the link to the next sector.
  1432. //
  1433. SECT sectTemp;
  1434. msfChk(_fat.GetNext(sectOld, &sectTemp));
  1435. msfChk(_fat.SetNext(sectNew, sectTemp));
  1436. //
  1437. // Free the old sector.
  1438. //
  1439. msfChk(_fat.SetNext(sectOld, FREESECT));
  1440. Err:
  1441. return sc;
  1442. }
  1443. //+---------------------------------------------------------------------------
  1444. //
  1445. // Member: CMStream::CopySect, private
  1446. //
  1447. // Synopsis: Do a partial sector delta for copy-on-write support
  1448. //
  1449. // Arguments: [sectOld] -- Location to copy from
  1450. // [sectNew] -- Location to copy to
  1451. // [oStart] -- Offset into sector to begin delta
  1452. // [oEnd] -- Offset into sector to end delta
  1453. // [pb] -- Buffer to delta from
  1454. // [pulRetval] -- Return location for number of bytes written
  1455. //
  1456. // Returns: Appropriate status code
  1457. //
  1458. // Modifies:
  1459. //
  1460. // History: 22-Jan-93 PhilipLa Created
  1461. //
  1462. // Notes: [pb] may be unsafe memory
  1463. //
  1464. //----------------------------------------------------------------------------
  1465. //This pragma is to avoid a C7 bug when building RETAIL
  1466. #if _MSC_VER == 700 && DBG == 0
  1467. #pragma function(memcpy)
  1468. #endif
  1469. SCODE CMStream::CopySect(
  1470. SECT sectOld,
  1471. SECT sectNew,
  1472. OFFSET oStart, // First byte of the sector to copy.
  1473. OFFSET oEnd, // Last byte of the sector to copy.
  1474. BYTE const HUGEP *pb,
  1475. ULONG *pulRetval)
  1476. {
  1477. SCODE sc;
  1478. ULONG cb;
  1479. ULARGE_INTEGER ulOff;
  1480. ULISetHigh(ulOff, 0);
  1481. BYTE HUGEP *pbScratch = BP_TO_P(BYTE HUGEP *, _pCopySectBuf);
  1482. #if DBG == 1
  1483. msfAssert((_uBufferRef == 0) &&
  1484. aMsg("Attempted to use CopySect buffer while refcount != 0"));
  1485. AtomicInc(&_uBufferRef);
  1486. #endif
  1487. msfAssert((pbScratch != NULL) && aMsg("No CopySect buffer found."));
  1488. #ifdef LARGE_DOCFILE
  1489. ulOff.QuadPart = ConvertSectOffset(sectOld, 0, GetSectorShift());
  1490. #else
  1491. ULISetLow(ulOff, ConvertSectOffset(sectOld, 0, GetSectorShift()));
  1492. #endif
  1493. msfHChk((*_pplstParent)->ReadAt(
  1494. ulOff,
  1495. pbScratch,
  1496. GetSectorSize(),
  1497. &cb));
  1498. //Now do delta in memory.
  1499. BYTE HUGEP *pstart;
  1500. pstart = pbScratch + oStart;
  1501. USHORT memLength;
  1502. memLength = oEnd - oStart + 1;
  1503. TRY
  1504. {
  1505. memcpy(pstart, pb, memLength);
  1506. }
  1507. CATCH(CException, e)
  1508. {
  1509. UNREFERENCED_PARM(e);
  1510. msfErr(Err, STG_E_INVALIDPOINTER);
  1511. }
  1512. END_CATCH
  1513. #ifdef LARGE_DOCFILE
  1514. ulOff.QuadPart = ConvertSectOffset(sectNew, 0, GetSectorShift());
  1515. #else
  1516. ULISetLow(ulOff, ConvertSectOffset(sectNew, 0, GetSectorShift()));
  1517. #endif
  1518. msfHChk((*_pplstParent)->WriteAt(
  1519. ulOff,
  1520. pbScratch,
  1521. GetSectorSize(),
  1522. &cb));
  1523. *pulRetval = memLength;
  1524. Err:
  1525. #if DBG == 1
  1526. AtomicDec(&_uBufferRef);
  1527. #endif
  1528. return sc;
  1529. }
  1530. //This returns the compiler to the default behavior
  1531. #if _MSC_VER == 700 && DBG == 0
  1532. #pragma intrinsic(memcpy)
  1533. #endif
  1534. //+-------------------------------------------------------------------------
  1535. //
  1536. // Member: CMStream::MWrite, public
  1537. //
  1538. // Synposis: Do multiple sector writes
  1539. //
  1540. // Effects: Causes multiple stream writes. Modifies fat and directory
  1541. //
  1542. // Arguments: [ph] -- Handle of stream doing write
  1543. // [start] -- Starting sector to write
  1544. // [oStart] -- offset into sector to begin write at
  1545. // [end] -- Last sector to write
  1546. // [oEnd] -- offset into last sector to write to
  1547. // [buffer] -- Pointer to buffer into which data will be written
  1548. // [ulRetVal] -- location to return number of bytes written
  1549. //
  1550. // Returns: Error code of any failed call to parent write
  1551. // S_OK if call completed OK.
  1552. //
  1553. // Modifies: ulRetVal returns the number of bytes written
  1554. //
  1555. // Algorithm: Using a segment table, perform writes on parent stream
  1556. // until call is completed.
  1557. //
  1558. // History: 16-Aug-91 PhilipLa Created.
  1559. // 10-Sep-91 PhilipLa Converted to use sector table
  1560. // 11-Sep-91 PhilipLa Modified interface, modified to
  1561. // allow partial sector writes.
  1562. // 07-Jan-92 PhilipLa Converted to use handle.
  1563. // 18-Feb-92 PhilipLa Added copy on write support.
  1564. //
  1565. // Notes: [pvBuffer] may be unsafe memory
  1566. //
  1567. //---------------------------------------------------------------------------
  1568. SCODE CMStream::MWrite(
  1569. SID sid,
  1570. BOOL fIsMini,
  1571. #ifdef LARGE_STREAMS
  1572. ULONGLONG ulOffset,
  1573. #else
  1574. ULONG ulOffset,
  1575. #endif
  1576. VOID const HUGEP *pvBuffer,
  1577. ULONG ulCount,
  1578. CStreamCache *pstmc,
  1579. ULONG *pulRetval)
  1580. {
  1581. SCODE sc;
  1582. BYTE const HUGEP *pbBuffer = (BYTE const HUGEP *) pvBuffer;
  1583. USHORT cbSector = GetSectorSize();
  1584. CFat *pfat = &_fat;
  1585. USHORT uShift = GetSectorShift();
  1586. ULONG ulLastBytes = 0;
  1587. ULARGE_INTEGER ulOff;
  1588. ULISetHigh(ulOff, 0);
  1589. #ifdef LARGE_STREAMS
  1590. ULONGLONG ulOldSize = 0;
  1591. #else
  1592. ULONG ulOldSize = 0;
  1593. #endif
  1594. // Check if it's a small stream and whether this is a real or
  1595. // scratch multistream.
  1596. if ((fIsMini) &&
  1597. (!_fIsScratch) &&
  1598. (SIDMINISTREAM != sid))
  1599. {
  1600. msfAssert(sid <= MAXREGSID &&
  1601. aMsg("Invalid SID in MWrite"));
  1602. // This stream is stored in the ministream
  1603. cbSector = MINISECTORSIZE;
  1604. uShift = MINISECTORSHIFT;
  1605. pfat = GetMiniFat();
  1606. }
  1607. USHORT uMask = cbSector - 1;
  1608. SECT start = (SECT)(ulOffset >> uShift);
  1609. OFFSET oStart = (OFFSET)(ulOffset & uMask);
  1610. SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift);
  1611. OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
  1612. msfDebugOut((DEB_ITRACE,"In CMStream::MWrite(%lu,%u,%lu,%u)\n",
  1613. start,oStart,end,oEnd));
  1614. ULONG bytecount;
  1615. ULONG total = 0;
  1616. msfChk(_dir.GetSize(sid, &ulOldSize));
  1617. //BEGIN COPYONWRITE
  1618. // Note that we don't do this for ministreams (the second pass through
  1619. // this code will take care of it).
  1620. msfAssert(!_fBlockWrite &&
  1621. aMsg("Called MWrite on Unconverted multistream"));
  1622. if ((_fBlockHeader) && (GetMiniFat() != pfat))
  1623. {
  1624. msfDebugOut((DEB_ITRACE,"**MWrite preparing for copy-on-write\n"));
  1625. SECT sectOldStart, sectNewStart, sectOldEnd, sectNewEnd;
  1626. SECT sectNew;
  1627. if (start != 0)
  1628. {
  1629. msfChk(pstmc->GetESect(start - 1, &sectNew));
  1630. }
  1631. else
  1632. {
  1633. msfChk(_dir.GetStart(sid, &sectNew));
  1634. }
  1635. msfChk(_fat.Remap(
  1636. sectNew,
  1637. (start == 0) ? 0 : 1,
  1638. (end - start + 1),
  1639. &sectOldStart,
  1640. &sectNewStart,
  1641. &sectOldEnd,
  1642. &sectNewEnd));
  1643. msfAssert(((end != start) || (sectNewStart == sectNewEnd)) &&
  1644. aMsg("Remap postcondition failed."));
  1645. if (sc != S_FALSE)
  1646. {
  1647. msfChk(pstmc->EmptyRegion(start, end));
  1648. }
  1649. if ((start == 0) && (sectNewStart != ENDOFCHAIN))
  1650. {
  1651. msfDebugOut((DEB_ITRACE,
  1652. "*** Remapped first sector. Changing directory.\n"));
  1653. msfChk(_dir.SetStart(sid, sectNewStart));
  1654. }
  1655. #ifdef LARGE_STREAMS
  1656. ULONGLONG ulSize = ulOldSize;
  1657. #else
  1658. ULONG ulSize = ulOldSize;
  1659. #endif
  1660. if (((oStart != 0) ||
  1661. ((end == start) && (ulOffset + ulCount != ulSize)
  1662. && ((USHORT)oEnd != (cbSector - 1)))) &&
  1663. (sectNewStart != ENDOFCHAIN))
  1664. {
  1665. //Partial first sector.
  1666. ULONG ulRetval;
  1667. msfChk(CopySect(
  1668. sectOldStart,
  1669. sectNewStart,
  1670. oStart,
  1671. (end == start) ? oEnd : (cbSector - 1),
  1672. pbBuffer,
  1673. &ulRetval));
  1674. pbBuffer = pbBuffer + ulRetval;
  1675. total = total + ulRetval;
  1676. start++;
  1677. oStart = 0;
  1678. }
  1679. if (((end >= start) && ((USHORT)oEnd != cbSector - 1) &&
  1680. (ulCount + ulOffset != ulSize)) &&
  1681. (sectNewEnd != ENDOFCHAIN))
  1682. {
  1683. //Partial last sector.
  1684. msfAssert(((end != start) || (oStart == 0)) &&
  1685. aMsg("CopySect precondition failed."));
  1686. msfChk(CopySect(
  1687. sectOldEnd,
  1688. sectNewEnd,
  1689. 0,
  1690. oEnd,
  1691. pbBuffer + ((end - start) << uShift) - oStart,
  1692. &ulLastBytes));
  1693. end--;
  1694. oEnd = cbSector - 1;
  1695. //We don't need to update pbBuffer, since the change
  1696. // is at the end.
  1697. }
  1698. }
  1699. // At this point, the entire block has been moved into the copy-on-write
  1700. // area of the multistream, and all partial writes have been done.
  1701. //END COPYONWRITE
  1702. msfAssert(end != 0xffffffffL);
  1703. if (end < start)
  1704. {
  1705. *pulRetval = total + ulLastBytes;
  1706. goto Err;
  1707. }
  1708. ULONG ulRunLength;
  1709. ulRunLength = end - start + 1;
  1710. USHORT offset;
  1711. offset = oStart;
  1712. while (TRUE)
  1713. {
  1714. SSegment segtab[CSEG + 1];
  1715. ULONG cSeg;
  1716. msfChk(pstmc->Contig(
  1717. start,
  1718. TRUE,
  1719. (SSegment STACKBASED *) segtab,
  1720. ulRunLength,
  1721. &cSeg));
  1722. msfAssert(cSeg <= CSEG);
  1723. USHORT oend = cbSector - 1;
  1724. ULONG i;
  1725. SECT sectStart;
  1726. for (USHORT iseg = 0; iseg < cSeg;)
  1727. {
  1728. sectStart = segtab[iseg].sectStart;
  1729. i = segtab[iseg].cSect;
  1730. if (i > ulRunLength)
  1731. i = ulRunLength;
  1732. ulRunLength -= i;
  1733. start += i;
  1734. iseg++;
  1735. if (ulRunLength == 0)
  1736. oend = oEnd;
  1737. ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
  1738. msfDebugOut((
  1739. DEB_ITRACE,
  1740. "Calling lstream WriteAt(%lu,%p,%lu)\n",
  1741. ConvertSectOffset(sectStart,offset,uShift),
  1742. pbBuffer,
  1743. ulSize));
  1744. if (GetMiniFat() == pfat)
  1745. {
  1746. sc = _pdsministream->CDirectStream::WriteAt(
  1747. (sectStart << uShift) + offset,
  1748. pbBuffer, ulSize,
  1749. (ULONG STACKBASED *)&bytecount);
  1750. }
  1751. else
  1752. {
  1753. #ifdef LARGE_DOCFILE
  1754. ulOff.QuadPart = ConvertSectOffset(sectStart, offset, uShift);
  1755. #else
  1756. ULISetLow(ulOff, ConvertSectOffset(sectStart, offset,
  1757. uShift));
  1758. #endif
  1759. sc = DfGetScode((*_pplstParent)->WriteAt(ulOff, pbBuffer,
  1760. ulSize, &bytecount));
  1761. }
  1762. total += bytecount;
  1763. //Check if this write is the last one in the stream,
  1764. // and that the stream ends as a partial sector.
  1765. //If so, fill out the remainder of the sector with
  1766. // something.
  1767. if ((0 == ulRunLength) && (total + ulOffset > ulOldSize) &&
  1768. (((total + ulOffset) & (GetSectorSize() - 1)) != 0))
  1769. {
  1770. //This is the last sector and the stream has grown.
  1771. ULONG csectOld = (ULONG)((ulOldSize + GetSectorSize() - 1) >>
  1772. GetSectorShift());
  1773. ULONG csectNew = (ULONG)((total + ulOffset + GetSectorSize() - 1) >>
  1774. GetSectorShift());
  1775. if (csectNew > csectOld)
  1776. {
  1777. msfAssert(!fIsMini &&
  1778. aMsg("Small stream grew in MWrite"));
  1779. SECT sectLast = sectStart + i - 1;
  1780. msfVerify(SUCCEEDED(SecureSect(
  1781. sectLast,
  1782. total + ulOffset,
  1783. FALSE)));
  1784. }
  1785. }
  1786. if (0 == ulRunLength || FAILED(sc))
  1787. {
  1788. break;
  1789. }
  1790. pbBuffer = pbBuffer + bytecount;
  1791. offset = 0;
  1792. }
  1793. if (0 == ulRunLength || FAILED(sc))
  1794. {
  1795. *pulRetval = total + ulLastBytes;
  1796. msfDebugOut((
  1797. DEB_ITRACE,
  1798. "Out CMStream::MWrite()=>%lu, retval = %lu\n",
  1799. sc,
  1800. total));
  1801. break;
  1802. }
  1803. }
  1804. Err:
  1805. return sc;
  1806. }
  1807. //+---------------------------------------------------------------------------
  1808. //
  1809. // Member: CMStream::Flush, public
  1810. //
  1811. // Synopsis: Flush control structures.
  1812. //
  1813. // Arguments: None.
  1814. //
  1815. // Returns: Appropriate status code
  1816. //
  1817. // History: 16-Dec-92 PhilipLa Created
  1818. //
  1819. //----------------------------------------------------------------------------
  1820. SCODE CMStream::Flush(BOOL fFlushCache)
  1821. {
  1822. SCODE sc = S_OK;
  1823. msfAssert(!_fBlockWrite &&
  1824. aMsg("Flush called on unconverted base."));
  1825. if ((!_fIsScratch) && (*_pplstParent != NULL))
  1826. {
  1827. msfChk(_pmpt->Flush());
  1828. msfChk(FlushHeader(HDR_NOFORCE));
  1829. msfChk(ILBFlush(*_pplstParent, fFlushCache));
  1830. }
  1831. Err:
  1832. return sc;
  1833. }
  1834. //+-------------------------------------------------------------------------
  1835. //
  1836. // Function: ILBFlush
  1837. //
  1838. // Synopsis: Flush as thoroughly as possible
  1839. //
  1840. // Effects: Flushes ILockBytes
  1841. //
  1842. // Arguments: [pilb] - ILockBytes to flush
  1843. // [fFlushCache] - Flush thoroughly iff TRUE
  1844. //
  1845. // Returns: SCODE
  1846. //
  1847. // Algorithm:
  1848. //
  1849. // History: 12-Feb-93 AlexT Created
  1850. //
  1851. //--------------------------------------------------------------------------
  1852. SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache)
  1853. {
  1854. // Try to query interface to our own implementation
  1855. IFileLockBytes *pfl;
  1856. SCODE sc;
  1857. msfDebugOut((DEB_ITRACE, "In ILBFlushCache(%p)\n", pilb));
  1858. // Check for FileLockBytes
  1859. if (!fFlushCache ||
  1860. FAILED(DfGetScode(pilb->QueryInterface(IID_IFileLockBytes, (void **)&pfl))))
  1861. {
  1862. // Either we don't have to flush the cache or its not our ILockBytes
  1863. sc = DfGetScode(pilb->Flush());
  1864. }
  1865. else
  1866. {
  1867. // We have to flush the cache and its our ILockBytes
  1868. sc = DfGetScode(pfl->FlushCache());
  1869. pfl->Release();
  1870. }
  1871. msfDebugOut((DEB_ITRACE, "Out ILBFlushCache()\n"));
  1872. return(sc);
  1873. }
  1874. //+---------------------------------------------------------------------------
  1875. //
  1876. // Member: CMStream::SecureSect, public
  1877. //
  1878. // Synopsis: Zero out the unused portion of a sector
  1879. //
  1880. // Arguments: [sect] -- Sector to zero out
  1881. // [ulSize] -- Size of stream
  1882. // [fIsMini] -- TRUE if stream is in ministream
  1883. //
  1884. // Returns: Appropriate status code
  1885. //
  1886. // Modifies:
  1887. //
  1888. // History: 05-Apr-93 PhilipLa Created
  1889. //
  1890. // Notes:
  1891. //
  1892. //----------------------------------------------------------------------------
  1893. SCODE CMStream::SecureSect(
  1894. const SECT sect,
  1895. #ifdef LARGE_STREAMS
  1896. const ULONGLONG ulSize,
  1897. #else
  1898. const ULONG ulSize,
  1899. #endif
  1900. const BOOL fIsMini)
  1901. {
  1902. #ifdef SECURE_TAIL
  1903. SCODE sc = S_OK;
  1904. BYTE *pb = NULL;
  1905. if (!_fIsScratch)
  1906. {
  1907. ULONG cbSect = fIsMini ? MINISECTORSIZE : GetSectorSize();
  1908. msfAssert(ulSize != 0);
  1909. ULONG ulOffset = (ULONG)(((ulSize - 1) % cbSect) + 1);
  1910. ULONG cb = cbSect - ulOffset;
  1911. msfAssert(cb != 0);
  1912. //We can use any initialized block of memory here. The header
  1913. // is available and is the correct size, so we use that.
  1914. #ifdef SECURE_BUFFER
  1915. pb = s_bufSecure;
  1916. #else
  1917. pb = (BYTE *)_hdr.GetData();
  1918. #endif
  1919. #ifdef SECURETEST
  1920. pb = (BYTE *) DfMemAlloc(cb);
  1921. if (pb != NULL)
  1922. memset(pb, 'Y', cb);
  1923. #endif
  1924. ULONG cbWritten;
  1925. if (!fIsMini)
  1926. {
  1927. ULARGE_INTEGER ulOff;
  1928. #ifdef LARGE_DOCFILE
  1929. ulOff.QuadPart = ConvertSectOffset(
  1930. sect,
  1931. (OFFSET)ulOffset,
  1932. GetSectorShift());
  1933. #else
  1934. ULISet32 (ulOff, ConvertSectOffset(
  1935. sect,
  1936. (OFFSET)ulOffset,
  1937. GetSectorShift()));
  1938. #endif
  1939. msfChk(DfGetScode((*_pplstParent)->WriteAt(
  1940. ulOff,
  1941. pb,
  1942. cb,
  1943. &cbWritten)));
  1944. }
  1945. else
  1946. {
  1947. msfChk(_pdsministream->WriteAt(
  1948. (sect << MINISECTORSHIFT) + ulOffset,
  1949. pb,
  1950. cb,
  1951. (ULONG STACKBASED *)&cbWritten));
  1952. }
  1953. if (cbWritten != cb)
  1954. {
  1955. sc = STG_E_WRITEFAULT;
  1956. }
  1957. }
  1958. Err:
  1959. #ifdef SECURETEST
  1960. DfMemFree(pb);
  1961. #endif
  1962. return sc;
  1963. #else
  1964. //On NT, our sectors get zeroed out by the file system, so we don't
  1965. // need this whole rigamarole.
  1966. return S_OK;
  1967. #endif // WIN32 == 200
  1968. }
  1969. //+-------------------------------------------------------------------------
  1970. //
  1971. // Method: CMStream::SetFileLockBytesTime, public
  1972. //
  1973. // Synopsis: Set the IFileLockBytes time.
  1974. //
  1975. // Arguments: [tt] -- Timestamp requested (WT_CREATION, WT_MODIFICATION,
  1976. // WT_ACCESS)
  1977. // [nt] -- New timestamp
  1978. //
  1979. // Returns: S_OK if call completed OK.
  1980. //
  1981. // Algorithm: Query for IFileLockBytes and call its SetTime member.
  1982. //
  1983. // History: 01-Sep-95 MikeHill Created.
  1984. //
  1985. //--------------------------------------------------------------------------
  1986. SCODE CMStream::SetFileLockBytesTime(
  1987. WHICHTIME const tt,
  1988. TIME_T nt)
  1989. {
  1990. SCODE sc = S_OK;
  1991. ILockBytes *pilb = *_pplstParent;
  1992. IFileLockBytes *pfl;
  1993. if (pilb &&
  1994. (SUCCEEDED(pilb->QueryInterface(IID_IFileLockBytes, (void **)&pfl))))
  1995. {
  1996. sc = ((CFileStream *)pfl)->SetTime(tt, nt);
  1997. pfl->Release();
  1998. }
  1999. return sc;
  2000. }
  2001. //+-------------------------------------------------------------------------
  2002. //
  2003. // Method: CMStream::SetAllFileLockBytesTimes, public
  2004. //
  2005. // Synopsis: Set the IFileLockBytes time.
  2006. //
  2007. // Arguments:
  2008. // [atm] -- ACCESS time
  2009. // [mtm] -- MODIFICATION time
  2010. // [ctm] -- CREATION time
  2011. //
  2012. // Returns: S_OK if call completed OK.
  2013. //
  2014. // Algorithm: Query for IFileLockBytes and call its SetAllTimes member.
  2015. //
  2016. // History: 29-Nov-95 SusiA Created.
  2017. //
  2018. //--------------------------------------------------------------------------
  2019. SCODE CMStream::SetAllFileLockBytesTimes(
  2020. TIME_T atm,
  2021. TIME_T mtm,
  2022. TIME_T ctm)
  2023. {
  2024. SCODE sc = S_OK;
  2025. ILockBytes *pilb = *_pplstParent;
  2026. IFileLockBytes *pfl;
  2027. if (SUCCEEDED(pilb->QueryInterface( IID_IFileLockBytes, (void **)&pfl)))
  2028. {
  2029. sc = ((CFileStream *)pfl)->SetAllTimes(atm, mtm, ctm);
  2030. pfl->Release();
  2031. }
  2032. return sc;
  2033. }
  2034. //+-------------------------------------------------------------------------
  2035. //
  2036. // Method: CMStream::SetTime, public
  2037. //
  2038. // Synopsis: Set the time for a given handle
  2039. //
  2040. // Arguments: [sid] -- SID to retrieve time for
  2041. // [tt] -- Timestamp requested (WT_CREATION, WT_MODIFICATION,
  2042. // WT_ACCESS)
  2043. // [nt] -- New timestamp
  2044. //
  2045. // Returns: S_OK if call completed OK.
  2046. //
  2047. // Algorithm: Call through to directory
  2048. //
  2049. // History: 01-Apr-92 PhilipLa Created.
  2050. // 14-Sep-92 PhilipLa inlined.
  2051. // <Missing history>
  2052. // 26-APR-99 RogerCh Removed faulty optimization
  2053. //
  2054. //--------------------------------------------------------------------------
  2055. SCODE CMStream::SetTime(
  2056. SID const sid,
  2057. WHICHTIME const tt,
  2058. TIME_T nt)
  2059. {
  2060. if ( sid == SIDROOT )
  2061. {
  2062. SCODE sc;
  2063. if( FAILED( sc = SetFileLockBytesTime( tt, nt )))
  2064. {
  2065. return sc;
  2066. }
  2067. }// if( sid == SIDROOT)
  2068. return _dir.SetTime(sid, tt, nt);
  2069. }
  2070. //+-------------------------------------------------------------------------
  2071. //
  2072. // Method: CMStream::SetAllTimes, public
  2073. //
  2074. // Synopsis: Set all the times for a given handle
  2075. //
  2076. // Arguments: [sid] -- SID to retrieve time for
  2077. // [atm] -- ACCESS time
  2078. // [mtm] -- MODIFICATION time
  2079. // [ctm] -- CREATION time
  2080. //
  2081. // Returns: S_OK if call completed OK.
  2082. //
  2083. // Algorithm: Call through to directory
  2084. //
  2085. // History: 27-Nov-95 SusiA Created
  2086. //
  2087. //--------------------------------------------------------------------------
  2088. SCODE CMStream::SetAllTimes(
  2089. SID const sid,
  2090. TIME_T atm,
  2091. TIME_T mtm,
  2092. TIME_T ctm)
  2093. {
  2094. if ( sid == SIDROOT )
  2095. {
  2096. SCODE sc;
  2097. if( FAILED( sc = SetAllFileLockBytesTimes(atm, mtm, ctm )))
  2098. {
  2099. return sc;
  2100. }
  2101. }
  2102. return _dir.SetAllTimes(sid, atm, mtm, ctm);
  2103. }
  2104. //+-------------------------------------------------------------------------
  2105. //
  2106. // Method: CMStream::GetTime, public
  2107. //
  2108. // Synopsis: Get the time for a given handle
  2109. //
  2110. // Arguments: [sid] -- SID to retrieve time for
  2111. // [tt] -- Timestamp requested (WT_CREATION, WT_MODIFICATION,
  2112. // WT_ACCESS)
  2113. // [pnt] -- Pointer to return location
  2114. //
  2115. // Returns: S_OK if call completed OK.
  2116. //
  2117. // History: 01-Apr-92 PhilipLa Created.
  2118. // 14-Sep-92 PhilipLa inlined.
  2119. //
  2120. //--------------------------------------------------------------------------
  2121. SCODE CMStream::GetTime(SID const sid,
  2122. WHICHTIME const tt,
  2123. TIME_T *pnt)
  2124. {
  2125. SCODE sc = S_OK;
  2126. if (sid == SIDROOT)
  2127. {
  2128. //Get timestamp from ILockBytes
  2129. STATSTG stat;
  2130. msfChk((*_pplstParent)->Stat(&stat, STATFLAG_NONAME));
  2131. if (tt == WT_CREATION)
  2132. {
  2133. *pnt = stat.ctime;
  2134. }
  2135. else if (tt == WT_MODIFICATION)
  2136. {
  2137. *pnt = stat.mtime;
  2138. }
  2139. else
  2140. {
  2141. *pnt = stat.atime;
  2142. }
  2143. }
  2144. else
  2145. sc = _dir.GetTime(sid, tt, pnt);
  2146. Err:
  2147. return sc;
  2148. }
  2149. //+-------------------------------------------------------------------------
  2150. //
  2151. // Method: CMStream::GetAllTimes, public
  2152. //
  2153. // Synopsis: Get the times for a given handle
  2154. //
  2155. // Arguments: [sid] -- SID to retrieve time for
  2156. // [patm] -- Pointer to the ACCESS time
  2157. // [pmtm] -- Pointer to the MODIFICATION time
  2158. // [pctm] -- Pointer to the CREATION time
  2159. //
  2160. // Returns: S_OK if call completed OK.
  2161. //
  2162. // History: 26-May-95 SusiA Created
  2163. //
  2164. //--------------------------------------------------------------------------
  2165. SCODE CMStream::GetAllTimes(SID const sid,
  2166. TIME_T *patm,
  2167. TIME_T *pmtm,
  2168. TIME_T *pctm)
  2169. {
  2170. SCODE sc = S_OK;
  2171. if (sid == SIDROOT)
  2172. {
  2173. //Get timestamp from ILockBytes
  2174. STATSTG stat;
  2175. msfChk((*_pplstParent)->Stat(&stat, STATFLAG_NONAME));
  2176. *pctm = stat.ctime;
  2177. *pmtm = stat.mtime;
  2178. *patm = stat.atime;
  2179. }
  2180. else
  2181. sc = _dir.GetAllTimes(sid, patm, pmtm, pctm);
  2182. Err:
  2183. return sc;
  2184. }
  2185. //+---------------------------------------------------------------------------
  2186. //
  2187. // Member: CMStream::InitScratch, public
  2188. //
  2189. // Synopsis: Set up a multistream for NoScratch operation
  2190. //
  2191. // Arguments: [pms] -- Pointer to base multistream
  2192. // [fNew] -- True if this is the first time the function has
  2193. // been called (init path), FALSE if merging behavior
  2194. // is required (EndCopyOnWrite)
  2195. //
  2196. // Returns: Appropriate status code
  2197. //
  2198. // Modifies:
  2199. //
  2200. // History: 02-Mar-95 PhilipLa Created
  2201. //
  2202. // Notes:
  2203. //
  2204. //----------------------------------------------------------------------------
  2205. SCODE CMStream::InitScratch(CMStream *pms, BOOL fNew)
  2206. {
  2207. msfDebugOut((DEB_ITRACE, "In CMStream::InitScratch:%p()\n", this));
  2208. msfAssert(GetSectorSize() == SCRATCHSECTORSIZE);
  2209. msfAssert(_fIsNoScratch &&
  2210. aMsg("Called InitScratch on Multistream not in NoScratch mode"));
  2211. return _fatMini.InitScratch(pms->GetFat(), fNew);
  2212. }
  2213. #ifdef MULTIHEAP
  2214. //+--------------------------------------------------------------
  2215. //
  2216. // Member: CMStream::GetMalloc, public
  2217. //
  2218. // Synopsis: Returns the allocator associated with this multistream
  2219. //
  2220. // History: 05-May-93 AlexT Created
  2221. //
  2222. //---------------------------------------------------------------
  2223. IMalloc * CMStream::GetMalloc(VOID) const
  2224. {
  2225. return (IMalloc *) &g_smAllocator;
  2226. }
  2227. #endif