Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1050 lines
27 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 128
  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. if (_uSectorShift > SECTORSHIFT512)
  346. fsiLen = _hdr.GetDirLength ();
  347. else
  348. msfChk(_fat.GetLength(_hdr.GetDirStart(), &fsiLen));
  349. msfChk(_dir.Init(this, fsiLen));
  350. msfChk(_fatMini.Init(this, _hdr.GetMiniFatLength(), 0));
  351. ULONGLONG ulSize;
  352. msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
  353. msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
  354. _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
  355. msfDebugOut((DEB_TRACE,"Out CMStream::Init()\n"));
  356. Err:
  357. return sc;
  358. }
  359. //+-------------------------------------------------------------------------
  360. //
  361. // Member: CMStream::InitNew, public
  362. //
  363. // Synposis: Set up a brand new mstream instance
  364. //
  365. // Effects: Modifies FAT and Directory
  366. //
  367. // Arguments: [fDelay] -- If TRUE, then the parent LStream
  368. // will be truncated at the time of first
  369. // entrance to COW, and no writes to the
  370. // LStream will happen before then.
  371. //
  372. // Returns: S_OK if call completed OK.
  373. //
  374. //---------------------------------------------------------------------------
  375. SCODE CMStream::InitNew(VOID)
  376. {
  377. SCODE sc;
  378. msfDebugOut((DEB_ITRACE,"In CMStream::InitNew()\n"));
  379. msfChk(InitCommon());
  380. ULARGE_INTEGER ulTmp;
  381. ulTmp.QuadPart = 0;
  382. (*_pplstParent)->SetSize(ulTmp);
  383. msfChk(_fatDif.InitNew(this));
  384. msfChk(_fat.InitNew(this));
  385. msfChk(_dir.InitNew(this));
  386. msfChk(_fatMini.InitNew(this));
  387. ULONGLONG ulSize;
  388. msfChk(_dir.GetSize(SIDMINISTREAM, &ulSize));
  389. msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
  390. _pdsministream->InitSystem(this, SIDMINISTREAM, ulSize);
  391. msfChk(Flush(0));
  392. msfDebugOut((DEB_TRACE,"Out CMStream::InitNew()\n"));
  393. return S_OK;
  394. Err:
  395. Empty();
  396. return sc;
  397. }
  398. //+---------------------------------------------------------------------------
  399. //
  400. // Member: CMStream::ConvertILB, private
  401. //
  402. // Synopsis: Copy the first sector of the underlying ILockBytes
  403. // out to the end.
  404. //
  405. // Arguments: [sectMax] -- Total number of sectors in the ILockBytes
  406. //
  407. // Returns: Appropriate status code
  408. //
  409. //----------------------------------------------------------------------------
  410. SCODE CMStream::ConvertILB(SECT sectMax)
  411. {
  412. SCODE sc;
  413. BYTE *pb;
  414. USHORT cbNull;
  415. GetSafeBuffer(GetSectorSize(), GetSectorSize(), &pb, &cbNull);
  416. ULONG ulTemp;
  417. ULARGE_INTEGER ulTmp;
  418. ULISet32(ulTmp, 0);
  419. msfHChk((*_pplstParent)->ReadAt(ulTmp, pb, GetSectorSize(), &ulTemp));
  420. ULARGE_INTEGER ulNewPos;
  421. ulNewPos.QuadPart = (ULONGLONG)(sectMax) << GetSectorShift();
  422. msfHChk((*_pplstParent)->WriteAt(
  423. ulNewPos,
  424. pb,
  425. GetSectorSize(),
  426. &ulTemp));
  427. Err:
  428. FreeBuffer(pb);
  429. return sc;
  430. }
  431. //+-------------------------------------------------------------------------
  432. //
  433. // Method: CMStream::InitConvert, public
  434. //
  435. // Synopsis: Init function used in conversion of files to multi
  436. // streams.
  437. //
  438. // Arguments: [fDelayConvert] -- If true, the actual file is not
  439. // touched until a BeginCopyOnWrite()
  440. //
  441. // Returns: S_OK if everything completed OK.
  442. //
  443. // Algorithm: *Finish This*
  444. //
  445. // Notes: We are allowed to fail here in low memory
  446. //
  447. //--------------------------------------------------------------------------
  448. SCODE CMStream::InitConvert(VOID)
  449. {
  450. SCODE sc;
  451. SECT sectMax;
  452. msfChk(InitCommon());
  453. STATSTG stat;
  454. (*_pplstParent)->Stat(&stat, STATFLAG_NONAME);
  455. sectMax = (SECT)((stat.cbSize.QuadPart + GetSectorSize() - 1) >>
  456. GetSectorShift());
  457. SECT sectMaxMini = 0;
  458. BOOL fIsMini;
  459. fIsMini = FALSE;
  460. //If the CONTENTS stream will be in the Minifat, compute
  461. // the number of Minifat sectors needed.
  462. if (stat.cbSize.QuadPart < MINISTREAMSIZE)
  463. {
  464. sectMaxMini = (SECT)((stat.cbSize.QuadPart +
  465. MINISECTORSIZE - 1) >> MINISECTORSHIFT);
  466. fIsMini = TRUE;
  467. }
  468. msfChk(_fatDif.InitConvert(this, sectMax));
  469. msfChk(_fat.InitConvert(this, sectMax));
  470. msfChk(_dir.InitNew(this));
  471. msfChk(fIsMini ? _fatMini.InitConvert(this, sectMaxMini)
  472. : _fatMini.InitNew(this));
  473. SID sid;
  474. msfChk(CreateEntry(SIDROOT, &dfnContents, STGTY_STREAM, &sid));
  475. msfChk(_dir.SetSize(sid, stat.cbSize.QuadPart));
  476. if (!fIsMini)
  477. msfChk(_dir.SetStart(sid, sectMax - 1));
  478. else
  479. {
  480. msfChk(_dir.SetStart(sid, 0));
  481. msfChk(_dir.SetStart(SIDMINISTREAM, sectMax - 1));
  482. msfChk(_dir.SetSize(SIDMINISTREAM, stat.cbSize.QuadPart));
  483. }
  484. ULONGLONG ulMiniSize;
  485. msfChk(_dir.GetSize(SIDMINISTREAM, &ulMiniSize));
  486. msfMem(_pdsministream = new CDirectStream(MINISTREAM_LUID));
  487. _pdsministream->InitSystem(this, SIDMINISTREAM, ulMiniSize);
  488. msfChk(ConvertILB(sectMax));
  489. msfChk(Flush(0));
  490. return S_OK;
  491. Err:
  492. Empty();
  493. return sc;
  494. }
  495. //+-------------------------------------------------------------------------
  496. //
  497. // Method: CMStream::GetName, public
  498. //
  499. // Synopsis: Given a handle, return the current name of that entry
  500. //
  501. // Arguments: [sid] -- SID to find name for.
  502. //
  503. // Returns: Pointer to name.
  504. //
  505. //--------------------------------------------------------------------------
  506. SCODE CMStream::GetName(SID const sid, CDfName *pdfn)
  507. {
  508. return _dir.GetName(sid, pdfn);
  509. }
  510. //+-------------------------------------------------------------------------
  511. //
  512. // Method: CMStream::FlushHeader, public
  513. //
  514. // Synopsis: Flush the header to the LStream.
  515. //
  516. // Arguments: [uForce] -- Flag to determine if header should be
  517. // flushed while in copy on write mode.
  518. //
  519. // Returns: S_OK if call completed OK.
  520. // S_OK if the MStream is in copy on write mode or
  521. // is Unconverted and the header was not flushed.
  522. //
  523. // Algorithm: Write the complete header out to the 0th position of
  524. // the LStream.
  525. //
  526. // Notes:
  527. //
  528. //--------------------------------------------------------------------------
  529. SCODE CMStream::FlushHeader(USHORT uForce)
  530. {
  531. ULONG ulTemp;
  532. SCODE sc;
  533. UNREFERENCED_PARM(uForce);
  534. msfDebugOut((DEB_ITRACE,"In CMStream::FlushHeader()\n"));
  535. ULARGE_INTEGER ulOffset;
  536. ULISet32(ulOffset, 0);
  537. _hdr.ByteSwap(); // swap to disk format if neccessary
  538. sc = DfGetScode((*_pplstParent)->
  539. WriteAt(ulOffset, (BYTE *)(&_hdr),
  540. sizeof(CMSFHeader), &ulTemp));
  541. _hdr.ByteSwap(); // swap to memort/machine format if neccessary
  542. msfDebugOut((DEB_ITRACE,"Out CMStream::FlushHeader()\n"));
  543. return sc;
  544. }
  545. //+-------------------------------------------------------------------------
  546. //
  547. // Member: CMStream::MWrite, public
  548. //
  549. // Synposis: Do multiple sector writes
  550. //
  551. // Effects: Causes multiple stream writes. Modifies fat and directory
  552. //
  553. // Arguments: [ph] -- Handle of stream doing write
  554. // [start] -- Starting sector to write
  555. // [oStart] -- offset into sector to begin write at
  556. // [end] -- Last sector to write
  557. // [oEnd] -- offset into last sector to write to
  558. // [buffer] -- Pointer to buffer into which data will be written
  559. // [ulRetVal] -- location to return number of bytes written
  560. //
  561. // Returns: Error code of any failed call to parent write
  562. // S_OK if call completed OK.
  563. //
  564. // Modifies: ulRetVal returns the number of bytes written
  565. //
  566. // Algorithm: Using a segment table, perform writes on parent stream
  567. // until call is completed.
  568. //
  569. // Notes:
  570. //
  571. //---------------------------------------------------------------------------
  572. SCODE CMStream::MWrite(
  573. SID sid,
  574. BOOL fIsMini,
  575. ULONGLONG ulOffset,
  576. VOID const HUGEP *pvBuffer,
  577. ULONG ulCount,
  578. CStreamCache *pstmc,
  579. ULONG *pulRetval)
  580. {
  581. SCODE sc;
  582. BYTE const HUGEP *pbBuffer = (BYTE const HUGEP *) pvBuffer;
  583. USHORT cbSector = GetSectorSize();
  584. CFat *pfat = &_fat;
  585. USHORT uShift = GetSectorShift();
  586. ULONG ulLastBytes = 0;
  587. ULARGE_INTEGER ulOff;
  588. ulOff.QuadPart = 0;
  589. ULONGLONG ulOldSize = 0;
  590. // Check if it's a small stream and whether this is a real
  591. // multistream.
  592. if ((fIsMini) &&
  593. (SIDMINISTREAM != sid))
  594. {
  595. msfAssert(sid <= MAXREGSID &&
  596. aMsg("Invalid SID in MWrite"));
  597. // This stream is stored in the ministream
  598. cbSector = MINISECTORSIZE;
  599. uShift = MINISECTORSHIFT;
  600. pfat = GetMiniFat();
  601. }
  602. USHORT uMask = (USHORT) (cbSector - 1);
  603. SECT start = (SECT)(ulOffset >> uShift);
  604. OFFSET oStart = (OFFSET)(ulOffset & uMask);
  605. SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift);
  606. OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
  607. msfDebugOut((DEB_ITRACE,"In CMStream::MWrite(%lu,%u,%lu,%u)\n",
  608. start,oStart,end,oEnd));
  609. ULONG bytecount;
  610. ULONG total = 0;
  611. msfChk(_dir.GetSize(sid, &ulOldSize));
  612. msfAssert(end != 0xffffffffL);
  613. if (end < start)
  614. {
  615. *pulRetval = total + ulLastBytes;
  616. goto Err;
  617. }
  618. ULONG ulRunLength;
  619. ulRunLength = end - start + 1;
  620. SECT sectSidStart;
  621. USHORT offset;
  622. offset = oStart;
  623. while (TRUE)
  624. {
  625. SSegment segtab[CSEG + 1];
  626. SECT sect;
  627. if (start > pstmc->GetOffset())
  628. {
  629. msfChk(pfat->GetESect(
  630. pstmc->GetSect(),
  631. start - pstmc->GetOffset(),
  632. &sect));
  633. }
  634. else if (start == pstmc->GetOffset())
  635. {
  636. sect = pstmc->GetSect();
  637. }
  638. else
  639. {
  640. msfChk(_dir.GetStart(sid, &sectSidStart));
  641. msfChk(pfat->GetESect(sectSidStart, start, &sect));
  642. }
  643. msfChk(pfat->Contig(
  644. (SSegment STACKBASED *) segtab,
  645. sect,
  646. ulRunLength));
  647. USHORT oend = (USHORT) (cbSector - 1);
  648. ULONG i = 0;
  649. SECT sectStart = ENDOFCHAIN;
  650. for (USHORT iseg = 0; iseg < CSEG;)
  651. {
  652. sectStart = segtab[iseg].sectStart;
  653. i = segtab[iseg].cSect;
  654. if (i > ulRunLength)
  655. i = ulRunLength;
  656. ulRunLength -= i;
  657. start += i;
  658. iseg++;
  659. if (segtab[iseg].sectStart == ENDOFCHAIN)
  660. {
  661. msfAssert(ulRunLength==0);
  662. oend = oEnd;
  663. }
  664. ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
  665. msfDebugOut((
  666. DEB_ITRACE,
  667. "Calling lstream WriteAt(%lu,%p,%lu)\n",
  668. ConvertSectOffset(sectStart,offset,uShift),
  669. pbBuffer,
  670. ulSize));
  671. if (GetMiniFat() == pfat)
  672. {
  673. sc = _pdsministream->CDirectStream::WriteAt(
  674. (sectStart << uShift) + offset,
  675. pbBuffer, ulSize,
  676. (ULONG STACKBASED *)&bytecount);
  677. }
  678. else
  679. {
  680. ulOff.QuadPart = ConvertSectOffset(sectStart, offset,
  681. uShift);
  682. sc = DfGetScode((*_pplstParent)->WriteAt(ulOff, pbBuffer,
  683. ulSize, &bytecount));
  684. }
  685. total += bytecount;
  686. //Check if this write is the last one in the stream,
  687. // and that the stream ends as a partial sector.
  688. //If so, fill out the remainder of the sector with
  689. // something.
  690. if ((0 == ulRunLength) && (total + ulOffset > ulOldSize) &&
  691. (((total + ulOffset) & (GetSectorSize() - 1)) != 0))
  692. {
  693. //This is the last sector and the stream has grown.
  694. ULONG csectOld = (SECT)((ulOldSize + GetSectorSize() - 1) >>
  695. GetSectorShift());
  696. ULONG csectNew = (SECT)((total + ulOffset + GetSectorSize() - 1) >>
  697. GetSectorShift());
  698. if (csectNew > csectOld)
  699. {
  700. msfAssert(!fIsMini &&
  701. aMsg("Small stream grew in MWrite"));
  702. SECT sectLast = sectStart + i - 1;
  703. msfVerify(SUCCEEDED(SecureSect(
  704. sectLast,
  705. total + ulOffset,
  706. FALSE)));
  707. }
  708. }
  709. if (0 == ulRunLength || FAILED(sc))
  710. {
  711. break;
  712. }
  713. pbBuffer = pbBuffer + bytecount;
  714. offset = 0;
  715. }
  716. pstmc->SetCache(start -1, sectStart + i - 1);
  717. if (0 == ulRunLength || FAILED(sc))
  718. {
  719. *pulRetval = total + ulLastBytes;
  720. msfDebugOut((
  721. DEB_TRACE,
  722. "Out CMStream::MWrite()=>%lu, retval = %lu\n",
  723. sc,
  724. total));
  725. break;
  726. }
  727. }
  728. Err:
  729. // We need this flush of the directory structures because we may have
  730. // remapped the first sector in a chain.
  731. return sc;
  732. }
  733. //+---------------------------------------------------------------------------
  734. //
  735. // Member: CMStream::Flush, public
  736. //
  737. // Synopsis: Flush control structures.
  738. //
  739. // Arguments: None.
  740. //
  741. // Returns: Appropriate status code
  742. //
  743. //----------------------------------------------------------------------------
  744. SCODE CMStream::Flush(BOOL fFlushCache)
  745. {
  746. SCODE sc = S_OK;
  747. msfChk(_dir.Flush());
  748. msfChk(_fatMini.Flush());
  749. msfChk(_fat.Flush());
  750. msfChk(_fatDif.Flush());
  751. msfChk(FlushHeader(HDR_NOFORCE));
  752. msfChk(ILBFlush(*_pplstParent, fFlushCache));
  753. Err:
  754. return sc;
  755. }
  756. //+-------------------------------------------------------------------------
  757. //
  758. // Function: ILBFlush
  759. //
  760. // Synopsis: Flush as thoroughly as possible
  761. //
  762. // Effects: Flushes ILockBytes
  763. //
  764. // Arguments: [pilb] - ILockBytes to flush
  765. // [fFlushCache] - Flush thoroughly iff TRUE
  766. //
  767. // Returns: SCODE
  768. //
  769. // Algorithm:
  770. //
  771. //--------------------------------------------------------------------------
  772. SCODE ILBFlush(ILockBytes *pilb, BOOL fFlushCache)
  773. {
  774. SCODE sc;
  775. UNREFERENCED_PARM(fFlushCache); // no cache used here
  776. msfDebugOut((DEB_ITRACE, "In ILBFlushCache(%p)\n", pilb));
  777. sc = DfGetScode(pilb->Flush());
  778. msfDebugOut((DEB_ITRACE, "Out ILBFlushCache()\n"));
  779. return(sc);
  780. }
  781. //+---------------------------------------------------------------------------
  782. //
  783. // Member: CMStream::SecureSect, public
  784. //
  785. // Synopsis: Zero out the unused portion of a sector
  786. //
  787. // Arguments: [sect] -- Sector to zero out
  788. // [ulSize] -- Size of stream
  789. // [fIsMini] -- TRUE if stream is in ministream
  790. //
  791. // Returns: Appropriate status code
  792. //
  793. // Modifies:
  794. //
  795. // Notes:
  796. //
  797. //----------------------------------------------------------------------------
  798. SCODE CMStream::SecureSect(
  799. const SECT sect,
  800. const ULONGLONG ulSize,
  801. const BOOL fIsMini)
  802. {
  803. SCODE sc = S_OK;
  804. BYTE *pb = NULL;
  805. ULONG cbSect = fIsMini ? MINISECTORSIZE : GetSectorSize();
  806. msfAssert(ulSize != 0);
  807. OFFSET ulOffset = (OFFSET)((ulSize - 1) % cbSect) + 1;
  808. ULONG cb = cbSect - ulOffset;
  809. msfAssert(cb != 0);
  810. // We can use any initialized block of memory here. The header
  811. // is available and is the correct size, so we use that.
  812. pb = (BYTE *)&_hdr;
  813. ULONG cbWritten;
  814. if (!fIsMini)
  815. {
  816. ULARGE_INTEGER ulOff;
  817. ulOff.QuadPart = ConvertSectOffset( sect, ulOffset,
  818. GetSectorShift());
  819. msfChk(DfGetScode((*_pplstParent)->
  820. WriteAt( ulOff, pb, cb, &cbWritten)));
  821. }
  822. else
  823. {
  824. msfChk(_pdsministream->WriteAt(
  825. (sect << MINISECTORSHIFT) + ulOffset,
  826. pb, cb, (ULONG STACKBASED *)&cbWritten));
  827. }
  828. if (cbWritten != cb)
  829. {
  830. sc = STG_E_WRITEFAULT;
  831. }
  832. Err:
  833. return sc;
  834. }