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.

1282 lines
37 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: sstream.cxx
  7. //
  8. // Contents: Stream operations for Mstream project
  9. //
  10. // Classes: None. (defined in sstream.hxx)
  11. //
  12. // History: 18-Jul-91 PhilipLa Created.
  13. // 24-Apr-92 AlexT Small object support
  14. //
  15. //--------------------------------------------------------------------
  16. #include "msfhead.cxx"
  17. #pragma hdrstop
  18. #include <dirfunc.hxx>
  19. #include <sstream.hxx>
  20. #include <dl.hxx>
  21. #include <tstream.hxx>
  22. #include <time.h>
  23. #include <mread.hxx>
  24. #define DEB_STREAM (DEB_ITRACE | 0x00020000)
  25. //+--------------------------------------------------------------
  26. //
  27. // Member: CDirectStream::CDirectStream, public
  28. //
  29. // Synopsis: Empty object constructor
  30. //
  31. // Arguments: [dl] - LUID
  32. //
  33. // History: 25-Aug-92 DrewB Created
  34. //
  35. //---------------------------------------------------------------
  36. CDirectStream::CDirectStream(DFLUID dl)
  37. : PSStream(dl)
  38. {
  39. _pdlHolder = NULL;
  40. _cReferences = 0;
  41. #ifdef SECURE_STREAMS
  42. _ulSize = 0;
  43. _ulHighWater = 0;
  44. #endif
  45. _sig = CDIRECTSTREAM_SIG;
  46. }
  47. //+-------------------------------------------------------------------------
  48. //
  49. // Method: CDirectStream::~CDirectStream, public
  50. //
  51. // Synopsis: CDirectStream destructor
  52. //
  53. // History: 18-Jul-91 PhilipLa Created.
  54. //
  55. // Notes:
  56. //
  57. //--------------------------------------------------------------------------
  58. CDirectStream::~CDirectStream()
  59. {
  60. msfAssert(_cReferences == 0);
  61. _sig = CDIRECTSTREAM_SIGDEL;
  62. #ifdef SECURE_STREAMS
  63. if (_ulSize > _ulHighWater)
  64. {
  65. ClearSects(_ulHighWater, _ulSize);
  66. }
  67. #endif
  68. }
  69. //+--------------------------------------------------------------
  70. //
  71. // Member: CDirectStream::InitSystem, public
  72. //
  73. // Synopsis: Initializes special system streams like the ministream
  74. //
  75. // Arguments: [pms] - Multistream
  76. // [sid] - SID
  77. // [cbSize] - size
  78. //
  79. // History: 25-Aug-92 DrewB Created
  80. //
  81. //---------------------------------------------------------------
  82. void CDirectStream::InitSystem(CMStream *pms,
  83. SID sid,
  84. #ifdef LARGE_STREAMS
  85. ULONGLONG cbSize)
  86. #else
  87. ULONG cbSize)
  88. #endif
  89. {
  90. _stmh.Init(pms, sid);
  91. _ulSize = _ulOldSize = cbSize;
  92. _stmc.Init(pms, sid, this);
  93. #ifdef SECURE_STREAMS
  94. #ifndef SECURE_BUFFER
  95. //If SECURE_BUFFER is defined, we've already zeroed this in the
  96. // multistream.
  97. memset(s_bufSecure, SECURECHAR, MINISTREAMSIZE);
  98. #endif
  99. _ulHighWater = cbSize;
  100. #endif
  101. AddRef();
  102. }
  103. //+-------------------------------------------------------------------------
  104. //
  105. // Method: CDirectStream::Init, public
  106. //
  107. // Synopsis: CDirectStream constructor
  108. //
  109. // Arguments: [pstgh] - Parent
  110. // [pdfn] - Name of entry
  111. // [fCreate] - Create or get
  112. //
  113. // Returns: Appropriate status code
  114. //
  115. // History: 18-Jul-91 PhilipLa Created.
  116. // 02-Jan-92 PhilipLa Converted to use handle.
  117. // 25-Aug-92 DrewB Converted to use StgHandle
  118. //
  119. //--------------------------------------------------------------------------
  120. SCODE CDirectStream::Init(
  121. CStgHandle *pstgh,
  122. CDfName const *pdfn,
  123. BOOL const fCreate)
  124. {
  125. SCODE sc;
  126. if (fCreate)
  127. sc = pstgh->CreateEntry(pdfn, STGTY_STREAM, &_stmh);
  128. else
  129. sc = pstgh->GetEntry(pdfn, STGTY_STREAM, &_stmh);
  130. if (SUCCEEDED(sc))
  131. {
  132. sc = _stmh.GetSize(&_ulSize);
  133. _ulOldSize = _ulSize;
  134. #ifdef SECURE_STREAMS
  135. _ulHighWater = (fCreate) ? 0 : _ulSize;
  136. #endif
  137. #if DBG == 1
  138. if (SUCCEEDED(sc))
  139. {
  140. //Make sure that the stream is sane.
  141. SCODE sc2;
  142. CFat *pfat;
  143. ULONG cbSector;
  144. ULONG cSect;
  145. ULONG cSectReal;
  146. SECT sectStart;
  147. if (_ulSize < MINISTREAMSIZE)
  148. {
  149. cbSector = MINISECTORSIZE;
  150. pfat = _stmh.GetMS()->GetMiniFat();
  151. }
  152. else
  153. {
  154. cbSector = _stmh.GetMS()->GetSectorSize();
  155. pfat = _stmh.GetMS()->GetFat();
  156. }
  157. cSect = (ULONG)((_ulSize + cbSector - 1) / cbSector);
  158. sc2 = _stmh.GetMS()->GetDir()->GetStart(
  159. _stmh.GetSid(),
  160. &sectStart);
  161. if (SUCCEEDED(sc2))
  162. {
  163. sc2 = pfat->GetLength(sectStart, &cSectReal);
  164. if (SUCCEEDED(sc2))
  165. {
  166. msfAssert((cSect == cSectReal) &&
  167. aMsg("Chain length incorrect at init."));
  168. }
  169. }
  170. }
  171. #endif
  172. if (SUCCEEDED(sc))
  173. AddRef();
  174. _stmc.Init(_stmh.GetMS(), _stmh.GetSid(), this);
  175. }
  176. return sc;
  177. }
  178. //+-------------------------------------------------------------------------
  179. //
  180. // Member: CDirectStream::ReadAt, public
  181. //
  182. // Synposis: Reads binary data from a linear single stream
  183. //
  184. // Arguments: [ulOffset] -- Position to be read from
  185. //
  186. // [pBuffer] -- Pointer to the area into which the data
  187. // will be read.
  188. // [ulCount] -- Indicates the number of bytes to be read
  189. // [pulRetval] -- Area into which return value will be stored
  190. //
  191. // Returns: Error Code of parent MStream call
  192. //
  193. // Algorithm: Calculate start and end sectors and offsets, then
  194. // pass call up to parent MStream.
  195. //
  196. // History: 18-Jul-91 PhilipLa Created.
  197. // 16-Aug-91 PhilipLa Converted to use multi-sect read
  198. // 23-Aug-91 PhilipLa Brought into compliance with protocol
  199. // 11-Sep-91 PhilipLa Moved most functionality up
  200. // to MStream level.
  201. // 24-Apr-92 AlexT Move everything to MStream::MRead
  202. // 09-Jun-92 PhilipLa Added fUnconverted support
  203. //
  204. // Notes: [pBuffer] may be unsafe memory
  205. //
  206. //---------------------------------------------------------------------------
  207. SCODE CDirectStream::ReadAt(
  208. #ifdef LARGE_STREAMS
  209. ULONGLONG ulOffset,
  210. #else
  211. ULONG ulOffset,
  212. #endif
  213. VOID HUGEP *pBuffer,
  214. ULONG ulCount,
  215. ULONG STACKBASED *pulRetval)
  216. {
  217. msfDebugOut((DEB_ITRACE,"In CDirectStream::ReadAt(%lu,%p,%lu)\n",
  218. ulOffset,pBuffer,ulCount));
  219. SCODE sc = S_OK;
  220. CMStream *pms = _stmh.GetMS();
  221. *pulRetval = 0;
  222. if (NULL == pms)
  223. return STG_E_UNKNOWN;
  224. // Check for offset beyond stream size and zero count
  225. if ((ulOffset >= _ulSize) || (0 == ulCount))
  226. {
  227. return S_OK;
  228. }
  229. if (ulOffset + ulCount > _ulSize)
  230. {
  231. msfDebugOut((DEB_ITRACE,"Truncating Read: ulOffset = %lu, ulCount = %lu, _ulSize = %lu\n",
  232. ulOffset,ulCount,_ulSize));
  233. ulCount = (ULONG)(_ulSize - ulOffset);
  234. }
  235. #ifdef DELAYCONVERT
  236. if (pms->IsUnconverted())
  237. {
  238. ULARGE_INTEGER ulTmp;
  239. ULISet32(ulTmp, ulOffset);
  240. return DfGetScode(pms->GetILB()->ReadAt(ulTmp, pBuffer, ulCount,
  241. pulRetval));
  242. }
  243. #else
  244. msfAssert(!pms->IsUnconverted());
  245. #endif
  246. // Stream is stored in ministream if size < MINISTREAMSIZE
  247. // and this is not a scratch stream.
  248. #ifdef SECURE_STREAMS
  249. if (ulOffset + ulCount > _ulHighWater)
  250. {
  251. if (ulOffset > _ulHighWater)
  252. {
  253. //Zero the whole buffer and return.
  254. memset(pBuffer, SECURECHAR, ulCount);
  255. *pulRetval = ulCount;
  256. return S_OK;
  257. }
  258. //Need to read into part of the buffer, then zero fill the
  259. // rest.
  260. if (FAILED(sc = ReadAt(ulOffset,
  261. pBuffer,
  262. _ulHighWater - ulOffset,
  263. pulRetval)) ||
  264. (*pulRetval != _ulHighWater - ulOffset))
  265. {
  266. return sc;
  267. }
  268. memset((BYTE *)pBuffer + *pulRetval,
  269. SECURECHAR,
  270. ulCount - (_ulHighWater - ulOffset));
  271. *pulRetval = ulCount;
  272. return S_OK;
  273. }
  274. #endif
  275. SID sid = _stmh.GetSid();
  276. CFat *pfat = pms->GetFat();
  277. USHORT cbSector = pms->GetSectorSize();
  278. USHORT uShift = pms->GetSectorShift();
  279. USHORT uMask = pms->GetSectorMask();
  280. if ((_ulSize < MINISTREAMSIZE) &&
  281. (!pms->IsScratch()) &&
  282. (sid != SIDMINISTREAM))
  283. {
  284. msfAssert(sid <= MAXREGSID);
  285. // This stream is stored in the ministream
  286. cbSector = MINISECTORSIZE;
  287. uShift = MINISECTORSHIFT;
  288. uMask = cbSector - 1;
  289. pfat = pms->GetMiniFat();
  290. }
  291. SECT start = (SECT)(ulOffset >> uShift);
  292. OFFSET oStart = (OFFSET)(ulOffset & uMask);
  293. SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift);
  294. OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
  295. ULONG total = 0;
  296. ULONG cSect = end - start + 1;
  297. USHORT offset;
  298. offset = oStart;
  299. while (TRUE)
  300. {
  301. ULONG cSeg;
  302. SSegment segtab[CSEG + 1];
  303. msfChk(_stmc.Contig(start,
  304. FALSE,
  305. (SSegment STACKBASED *) segtab,
  306. cSect,
  307. &cSeg));
  308. msfAssert(cSeg <= CSEG);
  309. USHORT oend = cbSector - 1;
  310. for (USHORT iseg = 0; iseg < cSeg;)
  311. {
  312. msfDebugOut((DEB_ITRACE,"Segment: (%lu,%lu)\n",segtab[iseg].sectStart,segtab[iseg].cSect));
  313. SECT sectStart = segtab[iseg].sectStart;
  314. ULONG i = segtab[iseg].cSect;
  315. if (i > cSect)
  316. i = cSect;
  317. cSect -= i;
  318. start += i;
  319. iseg++;
  320. if (cSect == 0)
  321. oend = oEnd;
  322. ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
  323. ULONG bytecount;
  324. if (pms->GetMiniFat() == pfat)
  325. {
  326. sc = pms->GetMiniStream()->CDirectStream::ReadAt(
  327. (sectStart << uShift) + offset,
  328. pBuffer, ulSize,
  329. (ULONG STACKBASED *)&bytecount);
  330. }
  331. else
  332. {
  333. ULARGE_INTEGER ulOffset2;
  334. #ifdef LARGE_DOCFILE
  335. ulOffset2.QuadPart = ConvertSectOffset(sectStart,offset,uShift);
  336. #else
  337. ULISet32(ulOffset2, ConvertSectOffset(sectStart,offset,uShift));
  338. #endif
  339. sc = DfGetScode(pms->GetILB()->ReadAt(ulOffset2,
  340. (BYTE *)pBuffer, ulSize,
  341. &bytecount));
  342. }
  343. total += bytecount;
  344. if ((0 == cSect) || (FAILED(sc)))
  345. {
  346. *pulRetval = total;
  347. msfDebugOut((DEB_ITRACE,
  348. "Leaving CDirectStream::ReadAt()=>%lu, ret is %lu\n",
  349. sc,*pulRetval));
  350. return sc;
  351. }
  352. pBuffer = (BYTE HUGEP *)pBuffer + bytecount;
  353. offset = 0;
  354. }
  355. }
  356. msfDebugOut((DEB_ERROR,"In CDirectStream::ReadAt - reached end of function\n"));
  357. Err:
  358. return sc;
  359. }
  360. //+-------------------------------------------------------------------------
  361. //
  362. // Member: CDirectStream::Write, public
  363. //
  364. // Synposis: Writes binary data from a linear single stream
  365. //
  366. // Effects: Modifies _ulSeekPos. May cause modification in parent
  367. // MStream.
  368. //
  369. // Arguments: [pBuffer] -- Pointer to the area from which the data
  370. // will be written.
  371. // [ulCount] -- Indicates the number of bytes to be written
  372. // [pulRetval] -- Pointer to area in which number of bytes
  373. // will be returned
  374. //
  375. // Returns: Error code of MStream call.
  376. //
  377. // Algorithm: Calculate sector and offset for beginning and end of
  378. // write, then pass call up to MStream.
  379. //
  380. //
  381. // History: 18-Jul-91 PhilipLa Created.
  382. // 16-Aug-91 PhilipLa Converted to use multi-sect write
  383. // 23-Aug-91 PhilipLa Brought into compliance with protocol
  384. // 11-Sep-91 PhilipLa Moved most functionality up
  385. // to MStream level.
  386. //
  387. // Notes: [pBuffer] may be unsafe memory
  388. //
  389. //---------------------------------------------------------------------------
  390. SCODE CDirectStream::WriteAt(
  391. #ifdef LARGE_STREAMS
  392. ULONGLONG ulOffset,
  393. #else
  394. ULONG ulOffset,
  395. #endif
  396. VOID const HUGEP *pBuffer,
  397. ULONG ulCount,
  398. ULONG STACKBASED *pulRetval)
  399. {
  400. msfDebugOut((DEB_ITRACE,"In CDirectStream::WriteAt(%lu,%p,%lu)\n",ulOffset,pBuffer,ulCount));
  401. *pulRetval = 0;
  402. if (0 == ulCount)
  403. return S_OK;
  404. SCODE sc;
  405. CMStream *pms;
  406. pms = _stmh.GetMS();
  407. if (NULL == pms)
  408. return STG_E_UNKNOWN;
  409. if (ulOffset + ulCount > _ulSize)
  410. {
  411. if (_ulSize > MINISTREAMSIZE)
  412. {
  413. }
  414. else
  415. {
  416. msfChk(SetSize(ulOffset + ulCount));
  417. }
  418. }
  419. // This should be an inline call to MWrite
  420. #ifdef SECURE_STREAMS
  421. if (ulOffset > _ulHighWater)
  422. {
  423. ClearSects(_ulHighWater, ulOffset);
  424. }
  425. #endif
  426. msfChk(pms->MWrite(
  427. _stmh.GetSid(),
  428. (_ulSize < MINISTREAMSIZE),
  429. ulOffset,
  430. pBuffer,
  431. ulCount,
  432. &_stmc,
  433. pulRetval));
  434. msfDebugOut((DEB_ITRACE,"Leaving CDirectStream::WriteAt()==>%lu, ret is %lu\n",sc,*pulRetval));
  435. Err:
  436. #ifdef SECURE_STREAMS
  437. if ((*pulRetval > 0 ) &&
  438. (ulOffset + *pulRetval > _ulHighWater))
  439. {
  440. _ulHighWater = ulOffset + *pulRetval;
  441. }
  442. #endif
  443. if (*pulRetval > 0 &&
  444. ulOffset + *pulRetval > _ulSize)
  445. {
  446. SCODE scSet;
  447. _ulSize = ulOffset + *pulRetval;
  448. scSet = pms->GetDir()->SetSize(_stmh.GetSid(), _ulSize);
  449. if (SUCCEEDED(sc) && FAILED(scSet))
  450. {
  451. sc = scSet;
  452. }
  453. }
  454. #ifdef SECURE_STREAMS
  455. msfAssert(_ulHighWater <= _ulSize);
  456. #endif
  457. return sc;
  458. }
  459. //+-------------------------------------------------------------------------
  460. //
  461. // Member: CDirectStream::SetSize, public
  462. //
  463. // Synposis: Set the size of a linear stream
  464. //
  465. // Effects: Modifies _ulSize. May cause change in parent MStream.
  466. //
  467. // Arguments: [ulNewSize] -- New size for stream
  468. //
  469. // Returns: Error code returned by MStream call.
  470. //
  471. // Algorithm: Pass call up to parent.
  472. //
  473. // History: 29-Jul-91 PhilipLa Created.
  474. // 14-May-92 AlexT Add small object support
  475. //
  476. // Notes: When changing the size of a stream, we need to be concerned
  477. // with the cases where each stream is either zero length,
  478. // stored in the ministream, or stored in a regular stream. The following
  479. // grid shows the actions that we must perform in each case:
  480. //
  481. // New Sector Count (Cn)
  482. //
  483. // 0 S L
  484. // O ------------------------------------------------
  485. // l | same size | allocate Cn | allocate Cn
  486. // d 0 | (fast out) | small sectors | large sectors
  487. // ------------------------------------------------
  488. // S | small | Co > Cn: | cbCopy = cbOld
  489. // e S | setchain(Cn) | small | large allocate Cn
  490. // c | | setchain(Cn)| copy bytes
  491. // t | | Cn > Co: | small setchain(0)
  492. // o | | extend small | copy data
  493. // r ------------------------------------------------
  494. // L | large | cbCopy = cbNew| Co > Cn:
  495. // C | setchain(Cn) | small | large setchain(Cn)
  496. // o | | allocate Cn | Cn > Co:
  497. // u | | copy bytes | extend large
  498. // n | | large |
  499. // t | | setchain(0) |
  500. // | | copy data |
  501. // (Co) ------------------------------------------------
  502. //
  503. // where S indicates small sectors, L indicates large sectors, and Cx
  504. // represents count of sectors. For example, the middle box represents
  505. // doing a setsize on a stream which is currently stored in a small
  506. // stream in Co small sectors and which will end up in a large stream
  507. // with Cn sectors.
  508. //
  509. //---------------------------------------------------------------------------
  510. #ifdef LARGE_STREAMS
  511. SCODE CDirectStream::SetSize(ULONGLONG cbNewSize)
  512. #else
  513. SCODE CDirectStream::SetSize(ULONG cbNewSize)
  514. #endif
  515. {
  516. msfDebugOut((DEB_ITRACE,"In CDirectStream::SetSize(%lu)\n",cbNewSize));
  517. SCODE sc = S_OK;
  518. BYTE *pBuf = NULL;
  519. SID sid = _stmh.GetSid();
  520. CMStream *pms = _stmh.GetMS();
  521. msfAssert(sid <= MAXREGSID);
  522. if (NULL == pms)
  523. return STG_E_UNKNOWN;
  524. CDirectory *pdir = pms->GetDir();
  525. if (_ulSize == cbNewSize)
  526. {
  527. return S_OK;
  528. }
  529. #ifdef SECURE_STREAMS
  530. msfAssert(_ulHighWater <= _ulSize);
  531. #endif
  532. USHORT cbpsOld = pms->GetSectorSize();
  533. // Count of Bytes Per Sector
  534. USHORT cbpsNew = cbpsOld;
  535. CFat *pfatOld = pms->GetFat();
  536. CFat *pfatNew = pfatOld;
  537. if ((!pms->IsScratch()) && (SIDMINISTREAM != sid))
  538. {
  539. // This is not a scratch DocFile, nor is this stream the ministream;
  540. // check if this stream is and/or will be stored in the ministream.
  541. if (cbNewSize < MINISTREAMSIZE)
  542. {
  543. cbpsNew = MINISECTORSIZE;
  544. pfatNew = pms->GetMiniFat();
  545. }
  546. if (_ulSize < MINISTREAMSIZE)
  547. {
  548. cbpsOld = MINISECTORSIZE;
  549. pfatOld = pms->GetMiniFat();
  550. }
  551. }
  552. ULONG csectOld = (ULONG)((_ulSize + cbpsOld - 1) / cbpsOld);
  553. ULONG csectNew = (ULONG)((cbNewSize + cbpsNew - 1) / cbpsNew);
  554. msfAssert(sid <= MAXREGSID);
  555. SECT sectstart, sectOldStart;
  556. msfChk(pdir->GetStart(sid, &sectstart));
  557. //Save start sector so we can free it later.
  558. sectOldStart = sectstart;
  559. msfDebugOut((DEB_ITRACE,"pdbOld size is %lu\n\tSid is %lu\n\tStart is %lu\n",
  560. _ulSize,sid,sectstart));
  561. msfDebugOut((DEB_ITRACE,"CMStream::SetSize() needs %lu %u byte sectors\n",
  562. csectNew, cbpsNew));
  563. msfDebugOut((DEB_ITRACE,"SetSize() currently has %lu %u byte sectors\n",
  564. csectOld, cbpsOld));
  565. ULONG cbCopy;
  566. cbCopy = 0;
  567. if (cbpsOld != cbpsNew)
  568. {
  569. // Sector sizes are different, so we'll copy the data
  570. msfAssert((cbNewSize > _ulSize ? _ulSize : cbNewSize) < 0x10000);
  571. cbCopy = (ULONG)(cbNewSize > _ulSize ? _ulSize : cbNewSize);
  572. }
  573. if (cbCopy > 0)
  574. {
  575. msfDebugOut((DEB_ITRACE,"Copying between fat and minifat\n"));
  576. GetSafeBuffer(cbCopy, cbCopy, &pBuf, &cbCopy);
  577. msfAssert((pBuf != NULL) && aMsg("Couldn't get scratch buffer"));
  578. ULONG ulRetVal;
  579. sc = ReadAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal);
  580. #ifdef SECURE_STREAMS
  581. //Part of the buffer may have gunk in it, so clear it out.
  582. if (_ulHighWater < cbCopy)
  583. {
  584. memset(pBuf + _ulHighWater, SECURECHAR, cbCopy - _ulHighWater);
  585. }
  586. #endif
  587. if ((FAILED(sc)) ||
  588. ((ulRetVal != cbCopy) ? (sc = STG_E_UNKNOWN) : 0))
  589. {
  590. msfErr(Err, sc);
  591. }
  592. #ifdef SECURE_STREAMS
  593. ClearSects(_ulHighWater, _ulSize);
  594. _ulHighWater = cbNewSize;
  595. #endif
  596. //The cache is no longer valid, so empty it.
  597. _stmc.Empty();
  598. msfChk(_stmc.Allocate(pfatNew, csectNew, &sectstart));
  599. }
  600. else
  601. {
  602. SECT dummy;
  603. if ((csectOld > csectNew))
  604. {
  605. #ifdef SECURE_STREAMS
  606. ClearSects(_ulHighWater, _ulSize);
  607. _ulHighWater = cbNewSize;
  608. #endif
  609. if (0 == csectNew)
  610. {
  611. //Note: We need to set the start sect in the directory
  612. // first in case the SetChainLength call fails part way
  613. // through, which would leave this directory entry pointing
  614. // to a FREESECT.
  615. SECT sectOldStart2 = sectstart;
  616. msfChk(pdir->SetStart(sid, ENDOFCHAIN));
  617. sectstart = ENDOFCHAIN;
  618. msfChk(pfatOld->SetChainLength(sectOldStart2, 0));
  619. }
  620. else
  621. {
  622. msfChk(pfatOld->SetChainLength(sectstart, csectNew));
  623. }
  624. //If this turns out to be a common case, we can
  625. // sometimes keep the cache valid here.
  626. _stmc.Empty();
  627. }
  628. else if (0 == csectOld)
  629. {
  630. msfChk(_stmc.Allocate(pfatNew, csectNew, &sectstart));
  631. }
  632. else if (csectNew > csectOld)
  633. {
  634. ULONG start = csectNew - 1;
  635. msfChk(_stmc.GetESect(start, &dummy));
  636. }
  637. }
  638. // Resize the ministream, if necessary
  639. if (((MINISECTORSIZE == cbpsOld) && (csectOld > 0)) ||
  640. ((MINISECTORSIZE == cbpsNew) && (csectNew > 0)))
  641. {
  642. msfChk(pms->SetMiniSize());
  643. }
  644. msfChk(pms->SetSize());
  645. //If we fail on either of these operations and cbCopy != 0,
  646. // we will have data loss. Ick.
  647. // Optimization - we only set the start sector if it has changed.
  648. if (sectstart != sectOldStart)
  649. {
  650. msfChk(pdir->SetStart(sid, sectstart));
  651. }
  652. //If we fail here, we're in big trouble.
  653. msfChk(pdir->SetSize(sid, cbNewSize));
  654. _ulSize = cbNewSize;
  655. #ifdef SECURE_STREAMS
  656. if (_ulHighWater > _ulSize)
  657. {
  658. _ulHighWater = _ulSize;
  659. }
  660. #endif
  661. if (cbCopy > 0)
  662. {
  663. // now copy the data
  664. ULONG ulRetVal;
  665. msfAssert(cbCopy <= _ulSize);
  666. msfChk(WriteAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal));
  667. if (ulRetVal != cbCopy)
  668. {
  669. msfErr(Err, STG_E_UNKNOWN);
  670. }
  671. msfChk(pfatOld->SetChainLength(sectOldStart, 0));
  672. msfChk(pms->SetMiniSize());
  673. msfChk(pms->SetSize());
  674. }
  675. #ifdef SECURE
  676. if (((csectNew > csectOld) || (cbCopy > 0)) &&
  677. ((cbNewSize & (cbpsNew - 1)) != 0))
  678. {
  679. SECT sectLast;
  680. msfChk(_stmc.GetSect(csectNew - 1, &sectLast));
  681. msfVerify(SUCCEEDED(pms->SecureSect(
  682. sectLast,
  683. cbNewSize,
  684. (cbNewSize < MINISTREAMSIZE) && (sid != SIDMINISTREAM))));
  685. }
  686. #endif //SECURE
  687. #ifdef SECURE_STREAMS
  688. msfAssert(_ulHighWater <= _ulSize);
  689. #endif
  690. Err:
  691. #ifdef SECURE_STREAMS
  692. if (_ulHighWater > _ulSize)
  693. {
  694. _ulHighWater = _ulSize;
  695. }
  696. #endif
  697. // Optimization - avoid calling FreeBuffer (which will end up calling
  698. // out to CompObj.DLL) when pBuf is NULL (common case).
  699. if (pBuf != NULL)
  700. FreeBuffer(pBuf);
  701. if (FAILED(sc))
  702. _stmc.Empty();
  703. return sc;
  704. }
  705. //+-------------------------------------------------------------------------
  706. //
  707. // Method: CDirectStream::BeginCommitFromChild, public
  708. //
  709. // Synopsis: Begin a commit from a child stream
  710. //
  711. // Arguments: [ulSize] -- Size of child stream
  712. // [pDelta] -- Pointer to delta list
  713. // [pstChild] - Child
  714. //
  715. // Returns: S_OK if call completed successfully.
  716. //
  717. // Algorithm: *Finish This*
  718. //
  719. // History: 22-Jan-92 PhilipLa Created.
  720. //
  721. // Notes:
  722. //
  723. //--------------------------------------------------------------------------
  724. SCODE CDirectStream::BeginCommitFromChild(
  725. #ifdef LARGE_STREAMS
  726. ULONGLONG ulSize,
  727. #else
  728. ULONG ulSize,
  729. #endif
  730. CDeltaList *pDelta,
  731. CTransactedStream *pstChild)
  732. {
  733. msfDebugOut((DEB_ITRACE,"In CDirectStream::BeginCommitFromChild:%p("
  734. "%lu, %p, %p)\n", this, ulSize, pDelta, pstChild));
  735. // msfDebugOut((DEB_ITRACE,"MultiStrean is %p\nStream name is: %ws\n",_stmh.GetMS(),((_stmh.GetMS()))->GetName(_stmh.GetSid())));
  736. SCODE sc = S_OK;
  737. ULONG temp;
  738. BYTE *pb = NULL;
  739. _pdlHolder = P_TO_BP(CBasedDeltaListPtr, pDelta);
  740. // Copy-on-write will back out these changes if we fail
  741. #ifdef USE_NOSCRATCH
  742. //For no-scratch mode, we commit very differently than we do regularly,
  743. // unless this commit is somehow involving the minifat.
  744. if ((pDelta->IsNoScratch()) &&
  745. (ulSize >= MINISTREAMSIZE) &&
  746. ((_ulSize >= MINISTREAMSIZE) || (_ulSize == 0)) &&
  747. (!pDelta->IsEmpty()))
  748. {
  749. USHORT cbSector = pDelta->GetDataSectorSize();
  750. SECT sectEnd = (SECT)((ulSize + cbSector - 1) / cbSector);
  751. SECT sectLast = ENDOFCHAIN;
  752. //We update our size and directory first so the stream cache
  753. // code knows which fat to get to.
  754. _ulOldSize = _ulSize;
  755. _ulSize = ulSize;
  756. msfChk(_stmh.GetMS()->GetDir()->SetSize(_stmh.GetSid(), ulSize));
  757. if (_ulOldSize > _ulSize)
  758. {
  759. //We need to truncate the chain.
  760. SECT sectStart;
  761. _stmh.GetMS()->GetDir()->GetStart(_stmh.GetSid(), &sectStart);
  762. _stmh.GetMS()->GetFat()->SetChainLength(sectStart, sectEnd);
  763. _stmc.Empty();
  764. }
  765. for (ULONG i = 0; i < sectEnd; i++)
  766. {
  767. SECT sectDirty;
  768. SECT sectOld;
  769. SECT sectNext;
  770. //For each sector, chain the old sector with the
  771. //existing new one.
  772. msfChk(pDelta->GetMap(i, DL_READ, &sectDirty));
  773. if (sectDirty != ENDOFCHAIN)
  774. {
  775. if (i > 0)
  776. {
  777. CFat *pfat = _stmh.GetMS()->GetFat();
  778. msfChk(_stmc.GetSect(i - 1, &sectLast));
  779. msfAssert(sectLast != ENDOFCHAIN);
  780. msfChk(pfat->GetNext(sectLast, &sectOld));
  781. msfChk(pfat->SetNext(sectLast, sectDirty));
  782. if (sectOld != ENDOFCHAIN)
  783. {
  784. msfChk(pfat->GetNext(sectOld, &sectNext));
  785. msfChk(pfat->SetNext(sectOld, FREESECT));
  786. }
  787. else
  788. {
  789. sectNext = ENDOFCHAIN;
  790. }
  791. msfChk(pfat->SetNext(sectDirty, sectNext));
  792. msfChk(_stmc.EmptyRegion(i, i));
  793. }
  794. else
  795. {
  796. CFat *pfat = _stmh.GetMS()->GetFat();
  797. CDirectory *pdir = _stmh.GetMS()->GetDir();
  798. sectNext = ENDOFCHAIN;
  799. msfChk(pdir->GetStart(_stmh.GetSid(), &sectLast));
  800. if (sectLast != ENDOFCHAIN)
  801. {
  802. msfChk(pfat->GetNext(sectLast, &sectNext));
  803. msfChk(pfat->SetNext(sectLast, FREESECT));
  804. }
  805. msfChk(pfat->SetNext(sectDirty, sectNext));
  806. msfChk(pdir->SetStart(_stmh.GetSid(), sectDirty));
  807. msfChk(_stmc.EmptyRegion(i, i));
  808. }
  809. }
  810. }
  811. #ifdef SECURE_STREAMS
  812. _ulHighWater = _ulSize;
  813. #endif
  814. #if DBG == 1
  815. //Make sure that the stream is sane.
  816. #ifdef LARGE_STREAMS
  817. ULONGLONG ulDirSize;
  818. #else
  819. ULONG ulDirSize;
  820. #endif
  821. ULONG cSect;
  822. ULONG cSectReal;
  823. SECT sectStart;
  824. _stmh.GetMS()->GetDir()->GetSize(_stmh.GetSid(), &ulDirSize);
  825. cSect = (ULONG)((ulDirSize + cbSector - 1) / cbSector);
  826. _stmh.GetMS()->GetDir()->GetStart(_stmh.GetSid(), &sectStart);
  827. _stmh.GetMS()->GetFat()->GetLength(sectStart, &cSectReal);
  828. msfAssert((cSect == cSectReal) &&
  829. aMsg("Chain length incorrect after commit."));
  830. #endif
  831. }
  832. else
  833. {
  834. #endif //USE_NOSCRATCH
  835. // Note: It's critical that we do this SetSize first (since we
  836. // use our scratch buffer below and SetSize can potentially also
  837. // use the scratch buffer.
  838. msfChk(SetSize(ulSize));
  839. _ulOldSize = _ulSize;
  840. msfAssert(pDelta != NULL);
  841. if (!pDelta->IsEmpty())
  842. {
  843. USHORT cbSector = pDelta->GetDataSectorSize();
  844. USHORT uSectorShift = pDelta->GetDataSectorShift();
  845. ULONG cbActualSize = 0;
  846. ULONG cbMaxSects = 15;
  847. GetSafeBuffer(cbSector, cbSector * cbMaxSects, &pb, &cbActualSize);
  848. BYTE *pbcurrent = pb;
  849. msfAssert((pb != NULL) && aMsg("Couldn't get scratch buffer"));
  850. cbMaxSects = cbActualSize / cbSector;
  851. OFFSET oEnd;
  852. oEnd = (OFFSET)((_ulSize - 1) % cbSector) + 1;
  853. SECT sectEnd;
  854. sectEnd = (SECT)((_ulSize + cbSector - 1) / cbSector);
  855. ULONG ulOffset;
  856. ILockBytes *pilbDirty;
  857. SECT sectBeginRead = ENDOFCHAIN; //the first sector to read
  858. SECT sectBeginWrite = ENDOFCHAIN; //the offset of the first place to write
  859. SECT sectDirty = ENDOFCHAIN; //the sector at this offset
  860. USHORT uReadCount = 0;
  861. ULARGE_INTEGER ulTmp;
  862. pilbDirty = pDelta->GetDataILB();
  863. for (ulOffset = 0; ulOffset < sectEnd; ulOffset++)
  864. {
  865. if (sectDirty == ENDOFCHAIN)
  866. {
  867. sectBeginWrite = ulOffset;
  868. }
  869. msfChk(pDelta->GetMap(ulOffset, DL_READ, &sectDirty));
  870. // Read will happen when we have determined there is something to read
  871. // and either
  872. // we have reached an ENDOFCHAIN
  873. // we have reached a non-adjacent sector
  874. // or we have reached the maximun amount that can be read
  875. if ( (uReadCount) &&
  876. ( (sectDirty == ENDOFCHAIN) ||
  877. (sectDirty != sectBeginRead + uReadCount) ||
  878. (ulOffset - sectBeginWrite == cbMaxSects) ))
  879. {
  880. msfDebugOut((DEB_ITRACE,"Reading %u sectors from sect %lu\n",
  881. uReadCount,
  882. sectBeginRead));
  883. #ifdef LARGE_DOCFILE
  884. ulTmp.QuadPart = ConvertSectOffset(sectBeginRead, 0,
  885. uSectorShift);
  886. #else
  887. ULISet32(ulTmp, ConvertSectOffset(sectBeginRead, 0,
  888. uSectorShift));
  889. #endif
  890. msfHChk(pilbDirty->ReadAt(
  891. ulTmp,
  892. pbcurrent,
  893. cbSector * uReadCount,
  894. (ULONG STACKBASED *)&temp));
  895. pbcurrent += cbSector * uReadCount;
  896. sectBeginRead = sectDirty;
  897. //reset the ReadCount now that we are done reading
  898. if (sectDirty == ENDOFCHAIN)
  899. uReadCount = 0;
  900. else
  901. uReadCount = 1;
  902. }
  903. // increment the read count
  904. else if (sectDirty != ENDOFCHAIN)
  905. {
  906. if (sectBeginRead == ENDOFCHAIN)
  907. {
  908. sectBeginRead = sectDirty;
  909. uReadCount=1;
  910. }
  911. else if (sectDirty == sectBeginRead + uReadCount)
  912. {
  913. uReadCount++;
  914. }
  915. }
  916. // Write occurs when we have something to write
  917. // and we have reached an ENDOFCHAIN
  918. // or the write buffer is full
  919. if (((sectDirty == ENDOFCHAIN) &&
  920. (sectBeginWrite != ulOffset) ) ||
  921. (ulOffset - sectBeginWrite == cbMaxSects) )
  922. {
  923. msfDebugOut((DEB_ITRACE,"Writing %u sectors from sect %lu\n",
  924. ulOffset - sectBeginWrite,
  925. sectBeginWrite));
  926. msfChk(WriteAt(sectBeginWrite * cbSector,
  927. pb,
  928. cbSector * (ulOffset - sectBeginWrite),
  929. (ULONG STACKBASED *)&temp));
  930. pbcurrent = pb;
  931. sectBeginWrite = ulOffset;
  932. }
  933. }
  934. // After loop, do last read and write
  935. if (uReadCount)
  936. {
  937. #ifdef LARGE_DOCFILE
  938. ulTmp.QuadPart = ConvertSectOffset(sectBeginRead, 0, uSectorShift);
  939. #else
  940. ULISet32(ulTmp, ConvertSectOffset(sectBeginRead, 0,
  941. uSectorShift));
  942. #endif
  943. msfDebugOut((DEB_ITRACE,"END::Reading %u sectors from sect %lu\n",
  944. uReadCount,
  945. sectBeginRead));
  946. msfHChk(pilbDirty->ReadAt(
  947. ulTmp,
  948. pbcurrent,
  949. cbSector * uReadCount,
  950. (ULONG STACKBASED *)&temp));
  951. msfDebugOut((DEB_ITRACE,"END::Writing %u sectors from sect %lu\n",
  952. ulOffset - sectBeginWrite,
  953. sectBeginWrite));
  954. msfChk(WriteAt(sectBeginWrite * cbSector,
  955. pb,
  956. // all sectors except the last one
  957. (cbSector * ((ulOffset-1) - sectBeginWrite)
  958. // last sector fragment
  959. + oEnd ),
  960. (ULONG STACKBASED *)&temp));
  961. }
  962. }
  963. #ifdef USE_NOSCRATCH
  964. }
  965. #endif
  966. msfDebugOut((DEB_ITRACE,"Out CDirectStream::BeginCommitFromChild()\n"));
  967. Err:
  968. #ifdef SECURE_STREAMS
  969. msfAssert(_ulHighWater <= _ulSize);
  970. #endif
  971. FreeBuffer(pb);
  972. return sc;
  973. }
  974. //+-------------------------------------------------------------------------
  975. //
  976. // Method: CDirectStream::EndCommitFromChild
  977. //
  978. // Synopsis: End a commit sequence from a child stream
  979. //
  980. // Arguments: [df] -- Indicates whether to commit or abort
  981. // [pstChild] - Child
  982. //
  983. // Returns: S_OK if call completed successfully.
  984. //
  985. // Algorithm: *Finish This*
  986. //
  987. // History: 22-Jan-92 PhilipLa Created.
  988. //
  989. // Notes:
  990. //
  991. //--------------------------------------------------------------------------
  992. void CDirectStream::EndCommitFromChild(DFLAGS df,
  993. CTransactedStream *pstChild)
  994. {
  995. msfDebugOut((DEB_ITRACE,"In CDirectStream::EndCommitFromChild:%p("
  996. "%lu, %p)\n", this, df, pstChild));
  997. if (!P_COMMIT(df))
  998. {
  999. _ulSize = _ulOldSize;
  1000. #ifdef SECURE_STREAMS
  1001. _ulHighWater = _ulSize;
  1002. #endif
  1003. //Stream cache is no longer valid, so nuke it.
  1004. _stmc.Empty();
  1005. }
  1006. _pdlHolder = NULL;
  1007. msfDebugOut((DEB_ITRACE,"Out CDirectStream::EndCommitFromChild()\n"));
  1008. }
  1009. //+---------------------------------------------------------------------------
  1010. //
  1011. // Member: CDirectStream::GetSize, public
  1012. //
  1013. // Synopsis: Gets the size of the stream
  1014. //
  1015. // Arguments: [pulSize] - Size return
  1016. //
  1017. // Modifies: [pulSize]
  1018. //
  1019. // History: 08-May-92 DrewB Created
  1020. //
  1021. //----------------------------------------------------------------------------
  1022. #ifdef LARGE_STREAMS
  1023. void CDirectStream::GetSize(ULONGLONG *pulSize)
  1024. #else
  1025. void CDirectStream::GetSize(ULONG *pulSize)
  1026. #endif
  1027. {
  1028. *pulSize = _ulSize;
  1029. }
  1030. //+---------------------------------------------------------------------------
  1031. //
  1032. // Member: CDirectStream::GetDeltaList, public
  1033. //
  1034. // Synopsis: Returns NULL, since a direct stream can never have
  1035. // a delta list.
  1036. //
  1037. // Arguments: None.
  1038. //
  1039. // Returns: NULL
  1040. //
  1041. // History: 30-Jul-93 PhilipLa Created
  1042. //
  1043. //----------------------------------------------------------------------------
  1044. CDeltaList * CDirectStream::GetDeltaList(void)
  1045. {
  1046. return NULL;
  1047. }
  1048. #ifdef SECURE_STREAMS
  1049. //+---------------------------------------------------------------------------
  1050. //
  1051. // Member: CDirectStream::ClearSects, private
  1052. //
  1053. // Synopsis:
  1054. //
  1055. // Arguments:
  1056. //
  1057. // Returns: void
  1058. //
  1059. // History: 10-Oct-95 PhilipLa Created
  1060. //
  1061. //----------------------------------------------------------------------------
  1062. void CDirectStream::ClearSects(ULONG ulStartOffset, ULONG ulEndOffset)
  1063. {
  1064. ULONG cbBytesToWrite = ulEndOffset - ulStartOffset;
  1065. ULONG ulOffset = ulStartOffset;
  1066. msfAssert(ulEndOffset >= ulStartOffset);
  1067. //Start offset must be less than high water mark, or the WriteAt
  1068. // will recurse.
  1069. msfAssert(ulStartOffset <= _ulHighWater);
  1070. while (cbBytesToWrite > 0)
  1071. {
  1072. ULONG cbWritten;
  1073. if (FAILED(WriteAt(ulOffset,
  1074. s_bufSecure,
  1075. min(MINISTREAMSIZE, cbBytesToWrite),
  1076. &cbWritten)))
  1077. {
  1078. break;
  1079. }
  1080. ulOffset += cbWritten;
  1081. cbBytesToWrite -= cbWritten;
  1082. }
  1083. return;
  1084. }
  1085. #endif