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.

1055 lines
26 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. //--------------------------------------------------------------------
  13. #include "msfhead.cxx"
  14. #include "h/dirfunc.hxx"
  15. #include "h/sstream.hxx"
  16. #include "h/difat.hxx"
  17. #include "h/msfiter.hxx"
  18. #include <time.h>
  19. #include "mread.hxx"
  20. #include "h/docfilep.hxx"
  21. #if DEVL == 1
  22. DECLARE_INFOLEVEL(msf, DEB_ERROR)
  23. #endif
  24. #define MINPAGES 6
  25. #define MAXPAGES 12
  26. extern "C" WCHAR const wcsContents[] =
  27. {'C','O','N','T','E','N','T','S','\0'};
  28. extern "C" CDfName const dfnContents(wcsContents);
  29. SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache);
  30. //+---------------------------------------------------------------------------
  31. //
  32. // Function: GetBuffer, public
  33. //
  34. // Synopsis: Gets a chunk of memory to use as a buffer
  35. //
  36. // Arguments: [cbMin] - Minimum size for buffer
  37. // [cbMax] - Maximum size for buffer
  38. // [ppb] - Buffer pointer return
  39. // [pcbActual] - Actual buffer size return
  40. //
  41. // Returns: Appropriate status code
  42. //
  43. // Modifies: [ppb]
  44. // [pcbActual]
  45. //
  46. // Algorithm: Attempt to dynamically allocate [cbMax] bytes
  47. // If that fails, halve allocation size and retry
  48. // If allocation size falls below [cbMin], fail
  49. //
  50. // Notes: Buffer should be released with FreeBuffer
  51. //
  52. //----------------------------------------------------------------------------
  53. SCODE GetBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb, USHORT *pcbActual)
  54. {
  55. USHORT cbSize;
  56. BYTE *pb;
  57. msfDebugOut((DEB_ITRACE, "In GetBuffer(%hu, %hu, %p, %p)\n",
  58. cbMin, cbMax, ppb, pcbActual));
  59. msfAssert(cbMin > 0);
  60. msfAssert(cbMax >= cbMin);
  61. msfAssert(ppb != NULL);
  62. msfAssert(pcbActual != NULL);
  63. cbSize = cbMax;
  64. for (;;)
  65. {
  66. pb = new BYTE[cbSize];
  67. if (pb == NULL)
  68. {
  69. cbSize >>= 1;
  70. if (cbSize < cbMin)
  71. break;
  72. }
  73. else
  74. {
  75. *pcbActual = cbSize;
  76. break;
  77. }
  78. }
  79. *ppb = pb;
  80. msfDebugOut((DEB_ITRACE, "Out GetBuffer => %p, %hu\n", *ppb, *pcbActual));
  81. return pb == NULL ? STG_E_INSUFFICIENTMEMORY : S_OK;
  82. }
  83. // Define the safe buffer size
  84. #define SCRATCHBUFFERSIZE ((USHORT) 4096)
  85. static BYTE s_buf[SCRATCHBUFFERSIZE];
  86. static LONG s_bufRef = 0;
  87. //+---------------------------------------------------------------------------
  88. //
  89. // Function: GetSafeBuffer, public
  90. //
  91. // Synopsis: Gets a buffer by first trying GetBuffer and if that fails,
  92. // returning a pointer to statically allocated storage.
  93. // Guaranteed to return a pointer to some storage.
  94. //
  95. // Arguments: [cbMin] - Minimum buffer size
  96. // [cbMax] - Maximum buffer size
  97. // [ppb] - Buffer pointer return
  98. // [pcbActual] - Actual buffer size return
  99. //
  100. // Modifies: [ppb]
  101. // [pcbActual]
  102. //
  103. //----------------------------------------------------------------------------
  104. void GetSafeBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb, USHORT *pcbActual)
  105. {
  106. msfAssert(cbMin > 0);
  107. msfAssert(cbMin <= SCRATCHBUFFERSIZE &&
  108. aMsg("Minimum too large for GetSafeBuffer"));
  109. msfAssert(cbMax >= cbMin);
  110. msfAssert(ppb != NULL);
  111. msfAssert(s_bufRef == 0 &&
  112. aMsg("Tried to use scratch buffer twice"));
  113. if (cbMax <= SCRATCHBUFFERSIZE ||
  114. FAILED(GetBuffer(cbMin, cbMax, ppb, pcbActual)))
  115. {
  116. s_bufRef = 1;
  117. *ppb = s_buf;
  118. *pcbActual = min(cbMax, SCRATCHBUFFERSIZE);
  119. }
  120. msfAssert(*ppb != NULL);
  121. }
  122. //+---------------------------------------------------------------------------
  123. //
  124. // Function: FreeBuffer, public
  125. //
  126. // Synopsis: Releases a buffer allocated by GetBuffer or GetSafeBuffer
  127. //
  128. // Arguments: [pb] - Buffer
  129. //
  130. //----------------------------------------------------------------------------
  131. void FreeBuffer(BYTE *pb)
  132. {
  133. if (pb == s_buf)
  134. {
  135. msfAssert((s_bufRef == 1) && aMsg("Bad safe buffer ref count"));
  136. s_bufRef = 0;
  137. }
  138. else
  139. delete [] pb;
  140. }
  141. //+-------------------------------------------------------------------------
  142. //
  143. // Method: CMStream::CMStream, public
  144. //
  145. // Synopsis: CMStream constructor
  146. //
  147. // Arguments: [pplstParent] -- Pointer to ILockBytes pointer of parent
  148. // [plGen] -- Pointer to LUID Generator to use.
  149. // Note: May be NULL, in which case a new
  150. // [uSectorShift] -- Sector shift for this MStream
  151. //
  152. //--------------------------------------------------------------------------
  153. CMStream::CMStream(
  154. ILockBytes **pplstParent,
  155. USHORT uSectorShift)
  156. :_uSectorShift(uSectorShift),
  157. _uSectorSize( (USHORT) (1 << uSectorShift) ),
  158. _uSectorMask((USHORT) (_uSectorSize - 1)),
  159. _pplstParent(pplstParent),
  160. _hdr(uSectorShift),
  161. _fatDif( (USHORT) (1<<uSectorShift) ),
  162. _fat(SIDFAT, (USHORT) (1<<uSectorShift), uSectorShift),
  163. _dir((USHORT) (1 << uSectorShift)),
  164. _fatMini(SIDMINIFAT, (USHORT) (1 << uSectorShift), uSectorShift)
  165. {
  166. _pdsministream = NULL;
  167. _pmpt = NULL;
  168. }
  169. //+-------------------------------------------------------------------------
  170. //
  171. // Method: CMStream::InitCommon, private
  172. //
  173. // Synopsis: Common code for initialization routines.
  174. //
  175. // Arguments: None.
  176. //
  177. // Returns: S_OK if call completed OK.
  178. //
  179. // Algorithm:
  180. //
  181. //--------------------------------------------------------------------------
  182. SCODE CMStream::InitCommon(VOID)
  183. {
  184. msfDebugOut((DEB_ITRACE,"In CMStream InitCommon()\n"));
  185. SCODE sc = S_OK;
  186. msfAssert(_pmpt == NULL);
  187. msfMem(_pmpt = new CMSFPageTable(this, MINPAGES, MAXPAGES));
  188. msfChk(_pmpt->Init());
  189. msfDebugOut((DEB_ITRACE,"Leaving CMStream InitCommon()\n"));
  190. return sc;
  191. Err:
  192. delete _pmpt;
  193. _pmpt = NULL;
  194. return sc;
  195. }
  196. //+---------------------------------------------------------------------------
  197. //
  198. // Member: CMStream::GetESect, private
  199. //
  200. // Synopsis: For a given SID and sect, return the location of that
  201. // sector in the multistream.
  202. //
  203. // Arguments: [sid] -- SID of sector to locate
  204. // [sect] -- Offset into chain to locate
  205. // [psect] -- Pointer to return location.
  206. //
  207. // Returns: Appropriate status code
  208. //
  209. // Modifies:
  210. //
  211. // Notes:
  212. //
  213. //----------------------------------------------------------------------------
  214. SCODE CMStream::GetESect(SID sid, SECT sect, SECT *psect)
  215. {
  216. SCODE sc = S_OK;
  217. SECT start;
  218. if (sid == SIDFAT)
  219. {
  220. msfChk(_fatDif.GetFatSect(sect, &start));
  221. }
  222. else if (sid == SIDDIF)
  223. {
  224. msfChk(_fatDif.GetSect(sect, &start));
  225. }
  226. else
  227. {
  228. start = GetStart(sid);
  229. msfChk(_fat.GetESect(start, sect, &start));
  230. }
  231. *psect = start;
  232. Err:
  233. return sc;
  234. }
  235. //+---------------------------------------------------------------------------
  236. //
  237. // Member: CMStream::Empty, public
  238. //
  239. // Synopsis: Empty all of the control structures of this CMStream
  240. //
  241. // Arguments: None.
  242. //
  243. // Returns: void.
  244. //
  245. //----------------------------------------------------------------------------
  246. void CMStream::Empty(void)
  247. {
  248. _fat.Empty();
  249. _fatMini.Empty();
  250. _fatDif.Empty();
  251. _dir.Empty();
  252. }
  253. //+-------------------------------------------------------------------------
  254. //
  255. // Method: CMStream::~CMStream, public
  256. //
  257. // Synopsis: CMStream destructor
  258. //
  259. //--------------------------------------------------------------------------
  260. CMStream::~CMStream()
  261. {
  262. msfDebugOut((DEB_ITRACE,"In CMStream destructor\n"));
  263. if (_pdsministream != NULL)
  264. {
  265. _pdsministream->Release();
  266. }
  267. if (_pmpt != NULL)
  268. {
  269. _pmpt->Release();
  270. }
  271. msfDebugOut((DEB_ITRACE,"Leaving CMStream destructor\n"));
  272. }
  273. //+-------------------------------------------------------------------------
  274. //
  275. // Member: CMStream::GetIterator, public
  276. //
  277. // Synposis: Create a new iterator for a given handle.
  278. //
  279. // Effects: Creates a new CMSFIterator
  280. //
  281. // Arguments: [sidParent] -- SID of entry to iterate over
  282. // [ppitRetval] -- Location for return of iterator pointer
  283. //
  284. // Returns: S_OK
  285. //
  286. // Algorithm: Create new iterator with parent of 'this' and nsi as given
  287. // by handle.
  288. //
  289. // Notes:
  290. //
  291. //---------------------------------------------------------------------------
  292. SCODE CMStream::GetIterator(
  293. SID const sidParent,
  294. CMSFIterator **ppitRetval)
  295. {
  296. SCODE sc;
  297. msfDebugOut((DEB_TRACE,"In CMStream::GetIterator()\n"));
  298. SID sidChild;
  299. msfChk(_dir.GetChild(sidParent, &sidChild));
  300. msfDebugOut((DEB_ITRACE, "Getting an iterator for SID = %lu, "
  301. "sidChild is %lu\n", sidParent, sidChild));
  302. msfMem(*ppitRetval = new CMSFIterator(GetDir(), sidChild));
  303. msfDebugOut((DEB_TRACE,"Leaving CMStream::GetIterator()\n"));
  304. Err:
  305. return sc;
  306. }
  307. //+-------------------------------------------------------------------------
  308. //
  309. // Member: CMStream::Init, public
  310. //
  311. // Synposis: Set up an mstream instance from an existing stream
  312. //
  313. // Effects: Modifies Fat and Directory
  314. //
  315. // Arguments: void.
  316. //
  317. // Returns: S_OK if call completed OK.
  318. // Error of Fat or Dir setup otherwise.
  319. //
  320. // Notes:
  321. //
  322. //---------------------------------------------------------------------------
  323. SCODE CMStream::Init(VOID)
  324. {
  325. ULONG ulTemp;
  326. SCODE sc;
  327. ULARGE_INTEGER ulOffset;
  328. msfDebugOut((DEB_ITRACE,"In CMStream::Init()\n"));
  329. msfChk(InitCommon());
  330. ULISet32(ulOffset, 0);
  331. msfHChk((*_pplstParent)->ReadAt(ulOffset, (BYTE *)(&_hdr),
  332. sizeof(CMSFHeader), &ulTemp));
  333. _hdr.ByteSwap(); // swap to memory/machine format if neccessary
  334. _uSectorShift = _hdr.GetSectorShift();
  335. _uSectorSize = (USHORT) (1 << _uSectorShift);
  336. _uSectorMask = (USHORT) (_uSectorSize - 1);
  337. if (ulTemp != sizeof(CMSFHeader))
  338. {
  339. msfErr(Err,STG_E_INVALIDHEADER);
  340. }
  341. msfChk(_hdr.Validate());
  342. msfChk(_fatDif.Init(this, _hdr.GetDifLength()));
  343. msfChk(_fat.Init(this, _hdr.GetFatLength(), 0));
  344. FSINDEX fsiLen;
  345. msfChk(_fat.GetLength(_hdr.GetDirStart(), &fsiLen));
  346. msfChk(_dir.Init(this, fsiLen));
  347. msfChk(_fatMini.Init(this, _hdr.GetMiniFatLength(), 0));
  348. ULONG ulSize;
  349. msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
  350. msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
  351. _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
  352. msfDebugOut((DEB_TRACE,"Out CMStream::Init()\n"));
  353. Err:
  354. return sc;
  355. }
  356. //+-------------------------------------------------------------------------
  357. //
  358. // Member: CMStream::InitNew, public
  359. //
  360. // Synposis: Set up a brand new mstream instance
  361. //
  362. // Effects: Modifies FAT and Directory
  363. //
  364. // Arguments: [fDelay] -- If TRUE, then the parent LStream
  365. // will be truncated at the time of first
  366. // entrance to COW, and no writes to the
  367. // LStream will happen before then.
  368. //
  369. // Returns: S_OK if call completed OK.
  370. //
  371. //---------------------------------------------------------------------------
  372. SCODE CMStream::InitNew(VOID)
  373. {
  374. SCODE sc;
  375. msfDebugOut((DEB_ITRACE,"In CMStream::InitNew()\n"));
  376. msfChk(InitCommon());
  377. ULARGE_INTEGER ulTmp;
  378. ULISet32(ulTmp, 0);
  379. (*_pplstParent)->SetSize(ulTmp);
  380. msfChk(_fatDif.InitNew(this));
  381. msfChk(_fat.InitNew(this));
  382. msfChk(_dir.InitNew(this));
  383. msfChk(_fatMini.InitNew(this));
  384. ULONG ulSize;
  385. msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
  386. msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
  387. _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
  388. msfChk(Flush(0));
  389. msfDebugOut((DEB_TRACE,"Out CMStream::InitNew()\n"));
  390. return S_OK;
  391. Err:
  392. Empty();
  393. return sc;
  394. }
  395. //+---------------------------------------------------------------------------
  396. //
  397. // Member: CMStream::ConvertILB, private
  398. //
  399. // Synopsis: Copy the first sector of the underlying ILockBytes
  400. // out to the end.
  401. //
  402. // Arguments: [sectMax] -- Total number of sectors in the ILockBytes
  403. //
  404. // Returns: Appropriate status code
  405. //
  406. //----------------------------------------------------------------------------
  407. SCODE CMStream::ConvertILB(SECT sectMax)
  408. {
  409. SCODE sc;
  410. BYTE *pb;
  411. USHORT cbNull;
  412. GetSafeBuffer(GetSectorSize(), GetSectorSize(), &pb, &cbNull);
  413. ULONG ulTemp;
  414. ULARGE_INTEGER ulTmp;
  415. ULISet32(ulTmp, 0);
  416. msfHChk((*_pplstParent)->ReadAt(ulTmp, pb, GetSectorSize(), &ulTemp));
  417. ULARGE_INTEGER ulNewPos;
  418. ULISet32(ulNewPos, sectMax << GetSectorShift());
  419. msfDebugOut((DEB_ITRACE,"Copying first sector out to %lu\n",
  420. ULIGetLow(ulNewPos)));
  421. msfHChk((*_pplstParent)->WriteAt(
  422. ulNewPos,
  423. pb,
  424. GetSectorSize(),
  425. &ulTemp));
  426. Err:
  427. FreeBuffer(pb);
  428. return sc;
  429. }
  430. //+-------------------------------------------------------------------------
  431. //
  432. // Method: CMStream::InitConvert, public
  433. //
  434. // Synopsis: Init function used in conversion of files to multi
  435. // streams.
  436. //
  437. // Arguments: [fDelayConvert] -- If true, the actual file is not
  438. // touched until a BeginCopyOnWrite()
  439. //
  440. // Returns: S_OK if everything completed OK.
  441. //
  442. // Algorithm: *Finish This*
  443. //
  444. // Notes: We are allowed to fail here in low memory
  445. //
  446. //--------------------------------------------------------------------------
  447. SCODE CMStream::InitConvert(VOID)
  448. {
  449. SCODE sc;
  450. SECT sectMax;
  451. msfChk(InitCommon());
  452. STATSTG stat;
  453. (*_pplstParent)->Stat(&stat, STATFLAG_NONAME);
  454. msfAssert(ULIGetHigh(stat.cbSize) == 0);
  455. msfDebugOut((DEB_ITRACE,"Size is: %lu\n",ULIGetLow(stat.cbSize)));
  456. sectMax = (ULIGetLow(stat.cbSize) + GetSectorSize() - 1) >>
  457. GetSectorShift();
  458. SECT sectMaxMini;
  459. BOOL fIsMini;
  460. fIsMini = FALSE;
  461. //If the CONTENTS stream will be in the Minifat, compute
  462. // the number of Minifat sectors needed.
  463. if (ULIGetLow(stat.cbSize) < MINISTREAMSIZE)
  464. {
  465. sectMaxMini = (ULIGetLow(stat.cbSize) +
  466. MINISECTORSIZE - 1) >> MINISECTORSHIFT;
  467. fIsMini = TRUE;
  468. }
  469. msfChk(_fatDif.InitConvert(this, sectMax));
  470. msfChk(_fat.InitConvert(this, sectMax));
  471. msfChk(_dir.InitNew(this));
  472. msfChk(fIsMini ? _fatMini.InitConvert(this, sectMaxMini)
  473. : _fatMini.InitNew(this));
  474. SID sid;
  475. msfChk(CreateEntry(SIDROOT, &dfnContents, STGTY_STREAM, &sid));
  476. msfChk(_dir.SetSize(sid, ULIGetLow(stat.cbSize)));
  477. if (!fIsMini)
  478. msfChk(_dir.SetStart(sid, sectMax - 1));
  479. else
  480. {
  481. msfChk(_dir.SetStart(sid, 0));
  482. msfChk(_dir.SetStart(SIDMINISTREAM, sectMax - 1));
  483. msfChk(_dir.SetSize(SIDMINISTREAM, ULIGetLow(stat.cbSize)));
  484. }
  485. ULONG ulMiniSize;
  486. msfChk(_dir.GetSize(SIDMINISTREAM, &ulMiniSize));
  487. msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
  488. _pdsministream->InitSystem(this, SIDMINISTREAM, ulMiniSize);
  489. msfChk(ConvertILB(sectMax));
  490. msfChk(Flush(0));
  491. return S_OK;
  492. Err:
  493. Empty();
  494. return sc;
  495. }
  496. //+-------------------------------------------------------------------------
  497. //
  498. // Method: CMStream::GetName, public
  499. //
  500. // Synopsis: Given a handle, return the current name of that entry
  501. //
  502. // Arguments: [sid] -- SID to find name for.
  503. //
  504. // Returns: Pointer to name.
  505. //
  506. //--------------------------------------------------------------------------
  507. SCODE CMStream::GetName(SID const sid, CDfName *pdfn)
  508. {
  509. return _dir.GetName(sid, pdfn);
  510. }
  511. //+-------------------------------------------------------------------------
  512. //
  513. // Method: CMStream::FlushHeader, public
  514. //
  515. // Synopsis: Flush the header to the LStream.
  516. //
  517. // Arguments: [uForce] -- Flag to determine if header should be
  518. // flushed while in copy on write mode.
  519. //
  520. // Returns: S_OK if call completed OK.
  521. // S_OK if the MStream is in copy on write mode or
  522. // is Unconverted and the header was not flushed.
  523. //
  524. // Algorithm: Write the complete header out to the 0th position of
  525. // the LStream.
  526. //
  527. // Notes:
  528. //
  529. //--------------------------------------------------------------------------
  530. SCODE CMStream::FlushHeader(USHORT uForce)
  531. {
  532. ULONG ulTemp;
  533. SCODE sc;
  534. UNREFERENCED_PARM(uForce);
  535. msfDebugOut((DEB_ITRACE,"In CMStream::FlushHeader()\n"));
  536. ULARGE_INTEGER ulOffset;
  537. ULISet32(ulOffset, 0);
  538. _hdr.ByteSwap(); // swap to disk format if neccessary
  539. sc = DfGetScode((*_pplstParent)->
  540. WriteAt(ulOffset, (BYTE *)(&_hdr),
  541. sizeof(CMSFHeader), &ulTemp));
  542. _hdr.ByteSwap(); // swap to memort/machine format if neccessary
  543. msfDebugOut((DEB_ITRACE,"Out CMStream::FlushHeader()\n"));
  544. return sc;
  545. }
  546. //+-------------------------------------------------------------------------
  547. //
  548. // Member: CMStream::MWrite, public
  549. //
  550. // Synposis: Do multiple sector writes
  551. //
  552. // Effects: Causes multiple stream writes. Modifies fat and directory
  553. //
  554. // Arguments: [ph] -- Handle of stream doing write
  555. // [start] -- Starting sector to write
  556. // [oStart] -- offset into sector to begin write at
  557. // [end] -- Last sector to write
  558. // [oEnd] -- offset into last sector to write to
  559. // [buffer] -- Pointer to buffer into which data will be written
  560. // [ulRetVal] -- location to return number of bytes written
  561. //
  562. // Returns: Error code of any failed call to parent write
  563. // S_OK if call completed OK.
  564. //
  565. // Modifies: ulRetVal returns the number of bytes written
  566. //
  567. // Algorithm: Using a segment table, perform writes on parent stream
  568. // until call is completed.
  569. //
  570. // Notes:
  571. //
  572. //---------------------------------------------------------------------------
  573. SCODE CMStream::MWrite(
  574. SID sid,
  575. BOOL fIsMini,
  576. ULONG ulOffset,
  577. VOID const HUGEP *pvBuffer,
  578. ULONG ulCount,
  579. CStreamCache *pstmc,
  580. ULONG *pulRetval)
  581. {
  582. SCODE sc;
  583. BYTE const HUGEP *pbBuffer = (BYTE const HUGEP *) pvBuffer;
  584. USHORT cbSector = GetSectorSize();
  585. CFat *pfat = &_fat;
  586. USHORT uShift = GetSectorShift();
  587. ULONG ulLastBytes = 0;
  588. ULARGE_INTEGER ulOff;
  589. ULISetHigh(ulOff, 0);
  590. ULONG ulOldSize = 0;
  591. // Check if it's a small stream and whether this is a real
  592. // multistream.
  593. if ((fIsMini) &&
  594. (SIDMINISTREAM != sid))
  595. {
  596. msfAssert(sid <= MAXREGSID &&
  597. aMsg("Invalid SID in MWrite"));
  598. // This stream is stored in the ministream
  599. cbSector = MINISECTORSIZE;
  600. uShift = MINISECTORSHIFT;
  601. pfat = GetMiniFat();
  602. }
  603. USHORT uMask = (USHORT) (cbSector - 1);
  604. SECT start = (SECT)(ulOffset >> uShift);
  605. OFFSET oStart = (OFFSET)(ulOffset & uMask);
  606. SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift);
  607. OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
  608. msfDebugOut((DEB_ITRACE,"In CMStream::MWrite(%lu,%u,%lu,%u)\n",
  609. start,oStart,end,oEnd));
  610. ULONG bytecount;
  611. ULONG total = 0;
  612. msfChk(_dir.GetSize(sid, &ulOldSize));
  613. msfAssert(end != 0xffffffffL);
  614. if (end < start)
  615. {
  616. *pulRetval = total + ulLastBytes;
  617. goto Err;
  618. }
  619. ULONG ulRunLength;
  620. ulRunLength = end - start + 1;
  621. SECT sectSidStart;
  622. USHORT offset;
  623. offset = oStart;
  624. while (TRUE)
  625. {
  626. SSegment segtab[CSEG + 1];
  627. SECT sect;
  628. if (start > pstmc->GetOffset())
  629. {
  630. msfChk(pfat->GetESect(
  631. pstmc->GetSect(),
  632. start - pstmc->GetOffset(),
  633. &sect));
  634. }
  635. else if (start == pstmc->GetOffset())
  636. {
  637. sect = pstmc->GetSect();
  638. }
  639. else
  640. {
  641. msfChk(_dir.GetStart(sid, &sectSidStart));
  642. msfChk(pfat->GetESect(sectSidStart, start, &sect));
  643. }
  644. msfChk(pfat->Contig(
  645. (SSegment STACKBASED *) segtab,
  646. sect,
  647. ulRunLength));
  648. USHORT oend = (USHORT) (cbSector - 1);
  649. ULONG i;
  650. SECT sectStart;
  651. for (USHORT iseg = 0; iseg < CSEG;)
  652. {
  653. sectStart = segtab[iseg].sectStart;
  654. i = segtab[iseg].cSect;
  655. if (i > ulRunLength)
  656. i = ulRunLength;
  657. ulRunLength -= i;
  658. start += i;
  659. iseg++;
  660. if (segtab[iseg].sectStart == ENDOFCHAIN)
  661. {
  662. msfAssert(ulRunLength==0);
  663. oend = oEnd;
  664. }
  665. ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
  666. msfDebugOut((
  667. DEB_ITRACE,
  668. "Calling lstream WriteAt(%lu,%p,%lu)\n",
  669. ConvertSectOffset(sectStart,offset,uShift),
  670. pbBuffer,
  671. ulSize));
  672. if (GetMiniFat() == pfat)
  673. {
  674. sc = _pdsministream->CDirectStream::WriteAt(
  675. (sectStart << uShift) + offset,
  676. pbBuffer, ulSize,
  677. (ULONG STACKBASED *)&bytecount);
  678. }
  679. else
  680. {
  681. ULISetLow(ulOff, ConvertSectOffset(sectStart, offset,
  682. uShift));
  683. sc = DfGetScode((*_pplstParent)->WriteAt(ulOff, pbBuffer,
  684. ulSize, &bytecount));
  685. }
  686. total += bytecount;
  687. //Check if this write is the last one in the stream,
  688. // and that the stream ends as a partial sector.
  689. //If so, fill out the remainder of the sector with
  690. // something.
  691. if ((0 == ulRunLength) && (total + ulOffset > ulOldSize) &&
  692. (((total + ulOffset) & (GetSectorSize() - 1)) != 0))
  693. {
  694. //This is the last sector and the stream has grown.
  695. ULONG csectOld = (ulOldSize + GetSectorSize() - 1) >>
  696. GetSectorShift();
  697. ULONG csectNew = (total + ulOffset + GetSectorSize() - 1) >>
  698. GetSectorShift();
  699. if (csectNew > csectOld)
  700. {
  701. msfAssert(!fIsMini &&
  702. aMsg("Small stream grew in MWrite"));
  703. SECT sectLast = sectStart + i - 1;
  704. msfVerify(SUCCEEDED(SecureSect(
  705. sectLast,
  706. total + ulOffset,
  707. FALSE)));
  708. }
  709. }
  710. if (0 == ulRunLength || FAILED(sc))
  711. {
  712. break;
  713. }
  714. pbBuffer = pbBuffer + bytecount;
  715. offset = 0;
  716. }
  717. pstmc->SetCache(start -1, sectStart + i - 1);
  718. if (0 == ulRunLength || FAILED(sc))
  719. {
  720. *pulRetval = total + ulLastBytes;
  721. msfDebugOut((
  722. DEB_TRACE,
  723. "Out CMStream::MWrite()=>%lu, retval = %lu\n",
  724. sc,
  725. total));
  726. break;
  727. }
  728. }
  729. Err:
  730. // We need this flush of the directory structures because we may have
  731. // remapped the first sector in a chain.
  732. return sc;
  733. }
  734. //+---------------------------------------------------------------------------
  735. //
  736. // Member: CMStream::Flush, public
  737. //
  738. // Synopsis: Flush control structures.
  739. //
  740. // Arguments: None.
  741. //
  742. // Returns: Appropriate status code
  743. //
  744. //----------------------------------------------------------------------------
  745. SCODE CMStream::Flush(BOOL fFlushCache)
  746. {
  747. SCODE sc = S_OK;
  748. msfChk(_dir.Flush());
  749. msfChk(_fatMini.Flush());
  750. msfChk(_fat.Flush());
  751. msfChk(_fatDif.Flush());
  752. msfChk(FlushHeader(HDR_NOFORCE));
  753. msfChk(ILBFlush(*_pplstParent, fFlushCache));
  754. Err:
  755. return sc;
  756. }
  757. //+-------------------------------------------------------------------------
  758. //
  759. // Function: ILBFlush
  760. //
  761. // Synopsis: Flush as thoroughly as possible
  762. //
  763. // Effects: Flushes ILockBytes
  764. //
  765. // Arguments: [pilb] - ILockBytes to flush
  766. // [fFlushCache] - Flush thoroughly iff TRUE
  767. //
  768. // Returns: SCODE
  769. //
  770. // Algorithm:
  771. //
  772. //--------------------------------------------------------------------------
  773. SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache)
  774. {
  775. SCODE sc;
  776. UNREFERENCED_PARM(fFlushCache); // no cache used here
  777. msfDebugOut((DEB_ITRACE, "In ILBFlushCache(%p)\n", pilb));
  778. sc = DfGetScode(pilb->Flush());
  779. msfDebugOut((DEB_ITRACE, "Out ILBFlushCache()\n"));
  780. return(sc);
  781. }
  782. //+---------------------------------------------------------------------------
  783. //
  784. // Member: CMStream::SecureSect, public
  785. //
  786. // Synopsis: Zero out the unused portion of a sector
  787. //
  788. // Arguments: [sect] -- Sector to zero out
  789. // [ulSize] -- Size of stream
  790. // [fIsMini] -- TRUE if stream is in ministream
  791. //
  792. // Returns: Appropriate status code
  793. //
  794. // Modifies:
  795. //
  796. // Notes:
  797. //
  798. //----------------------------------------------------------------------------
  799. SCODE CMStream::SecureSect(
  800. const SECT sect,
  801. const ULONG ulSize,
  802. const BOOL fIsMini)
  803. {
  804. SCODE sc = S_OK;
  805. BYTE *pb = NULL;
  806. ULONG cbSect = fIsMini ? MINISECTORSIZE : GetSectorSize();
  807. msfAssert(ulSize != 0);
  808. ULONG ulOffset = ((ulSize - 1) % cbSect) + 1;
  809. ULONG cb = cbSect - ulOffset;
  810. msfAssert(cb != 0);
  811. // We can use any initialized block of memory here. The header
  812. // is available and is the correct size, so we use that.
  813. pb = (BYTE *)&_hdr;
  814. ULONG cbWritten;
  815. if (!fIsMini)
  816. {
  817. ULARGE_INTEGER ulOff;
  818. // justify the casting later
  819. msfAssert(ulOffset <= USHRT_MAX);
  820. ULISet32(ulOff,
  821. ConvertSectOffset( sect, (USHORT) ulOffset,
  822. GetSectorShift()));
  823. msfChk(DfGetScode((*_pplstParent)->
  824. WriteAt( ulOff, pb, cb, &cbWritten)));
  825. }
  826. else
  827. {
  828. msfChk(_pdsministream->WriteAt(
  829. (sect << MINISECTORSHIFT) + ulOffset,
  830. pb, cb, (ULONG STACKBASED *)&cbWritten));
  831. }
  832. if (cbWritten != cb)
  833. {
  834. sc = STG_E_WRITEFAULT;
  835. }
  836. Err:
  837. return sc;
  838. }