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.

1283 lines
36 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. SCODE sc;
  325. if (pms->GetMiniFat() == pfat)
  326. {
  327. sc = pms->GetMiniStream()->CDirectStream::ReadAt(
  328. (sectStart << uShift) + offset,
  329. pBuffer, ulSize,
  330. (ULONG STACKBASED *)&bytecount);
  331. }
  332. else
  333. {
  334. ULARGE_INTEGER ulOffset;
  335. #ifdef LARGE_DOCFILE
  336. ulOffset.QuadPart = ConvertSectOffset(sectStart,offset,uShift);
  337. #else
  338. ULISet32(ulOffset, ConvertSectOffset(sectStart,offset,uShift));
  339. #endif
  340. sc = DfGetScode(pms->GetILB()->ReadAt(ulOffset,
  341. (BYTE *)pBuffer, ulSize,
  342. &bytecount));
  343. }
  344. total += bytecount;
  345. if ((0 == cSect) || (FAILED(sc)))
  346. {
  347. *pulRetval = total;
  348. msfDebugOut((DEB_ITRACE,
  349. "Leaving CDirectStream::ReadAt()=>%lu, ret is %lu\n",
  350. sc,*pulRetval));
  351. return sc;
  352. }
  353. pBuffer = (BYTE HUGEP *)pBuffer + bytecount;
  354. offset = 0;
  355. }
  356. }
  357. msfDebugOut((DEB_ERROR,"In CDirectStream::ReadAt - reached end of function\n"));
  358. Err:
  359. return sc;
  360. }
  361. //+-------------------------------------------------------------------------
  362. //
  363. // Member: CDirectStream::Write, public
  364. //
  365. // Synposis: Writes binary data from a linear single stream
  366. //
  367. // Effects: Modifies _ulSeekPos. May cause modification in parent
  368. // MStream.
  369. //
  370. // Arguments: [pBuffer] -- Pointer to the area from which the data
  371. // will be written.
  372. // [ulCount] -- Indicates the number of bytes to be written
  373. // [pulRetval] -- Pointer to area in which number of bytes
  374. // will be returned
  375. //
  376. // Returns: Error code of MStream call.
  377. //
  378. // Algorithm: Calculate sector and offset for beginning and end of
  379. // write, then pass call up to MStream.
  380. //
  381. //
  382. // History: 18-Jul-91 PhilipLa Created.
  383. // 16-Aug-91 PhilipLa Converted to use multi-sect write
  384. // 23-Aug-91 PhilipLa Brought into compliance with protocol
  385. // 11-Sep-91 PhilipLa Moved most functionality up
  386. // to MStream level.
  387. //
  388. // Notes: [pBuffer] may be unsafe memory
  389. //
  390. //---------------------------------------------------------------------------
  391. SCODE CDirectStream::WriteAt(
  392. #ifdef LARGE_STREAMS
  393. ULONGLONG ulOffset,
  394. #else
  395. ULONG ulOffset,
  396. #endif
  397. VOID const HUGEP *pBuffer,
  398. ULONG ulCount,
  399. ULONG STACKBASED *pulRetval)
  400. {
  401. msfDebugOut((DEB_ITRACE,"In CDirectStream::WriteAt(%lu,%p,%lu)\n",ulOffset,pBuffer,ulCount));
  402. *pulRetval = 0;
  403. if (0 == ulCount)
  404. return S_OK;
  405. SCODE sc;
  406. CMStream *pms;
  407. pms = _stmh.GetMS();
  408. if (NULL == pms)
  409. return STG_E_UNKNOWN;
  410. if (ulOffset + ulCount > _ulSize)
  411. {
  412. if (_ulSize > MINISTREAMSIZE)
  413. {
  414. }
  415. else
  416. {
  417. msfChk(SetSize(ulOffset + ulCount));
  418. }
  419. }
  420. // This should be an inline call to MWrite
  421. #ifdef SECURE_STREAMS
  422. if (ulOffset > _ulHighWater)
  423. {
  424. ClearSects(_ulHighWater, ulOffset);
  425. }
  426. #endif
  427. msfChk(pms->MWrite(
  428. _stmh.GetSid(),
  429. (_ulSize < MINISTREAMSIZE),
  430. ulOffset,
  431. pBuffer,
  432. ulCount,
  433. &_stmc,
  434. pulRetval));
  435. msfDebugOut((DEB_ITRACE,"Leaving CDirectStream::WriteAt()==>%lu, ret is %lu\n",sc,*pulRetval));
  436. Err:
  437. #ifdef SECURE_STREAMS
  438. if ((*pulRetval > 0 ) &&
  439. (ulOffset + *pulRetval > _ulHighWater))
  440. {
  441. _ulHighWater = ulOffset + *pulRetval;
  442. }
  443. #endif
  444. if (*pulRetval > 0 &&
  445. ulOffset + *pulRetval > _ulSize)
  446. {
  447. SCODE scSet;
  448. _ulSize = ulOffset + *pulRetval;
  449. scSet = pms->GetDir()->SetSize(_stmh.GetSid(), _ulSize);
  450. if (SUCCEEDED(sc) && FAILED(scSet))
  451. {
  452. sc = scSet;
  453. }
  454. }
  455. #ifdef SECURE_STREAMS
  456. msfAssert(_ulHighWater <= _ulSize);
  457. #endif
  458. return sc;
  459. }
  460. //+-------------------------------------------------------------------------
  461. //
  462. // Member: CDirectStream::SetSize, public
  463. //
  464. // Synposis: Set the size of a linear stream
  465. //
  466. // Effects: Modifies _ulSize. May cause change in parent MStream.
  467. //
  468. // Arguments: [ulNewSize] -- New size for stream
  469. //
  470. // Returns: Error code returned by MStream call.
  471. //
  472. // Algorithm: Pass call up to parent.
  473. //
  474. // History: 29-Jul-91 PhilipLa Created.
  475. // 14-May-92 AlexT Add small object support
  476. //
  477. // Notes: When changing the size of a stream, we need to be concerned
  478. // with the cases where each stream is either zero length,
  479. // stored in the ministream, or stored in a regular stream. The following
  480. // grid shows the actions that we must perform in each case:
  481. //
  482. // New Sector Count (Cn)
  483. //
  484. // 0 S L
  485. // O ------------------------------------------------
  486. // l | same size | allocate Cn | allocate Cn
  487. // d 0 | (fast out) | small sectors | large sectors
  488. // ------------------------------------------------
  489. // S | small | Co > Cn: | cbCopy = cbOld
  490. // e S | setchain(Cn) | small | large allocate Cn
  491. // c | | setchain(Cn)| copy bytes
  492. // t | | Cn > Co: | small setchain(0)
  493. // o | | extend small | copy data
  494. // r ------------------------------------------------
  495. // L | large | cbCopy = cbNew| Co > Cn:
  496. // C | setchain(Cn) | small | large setchain(Cn)
  497. // o | | allocate Cn | Cn > Co:
  498. // u | | copy bytes | extend large
  499. // n | | large |
  500. // t | | setchain(0) |
  501. // | | copy data |
  502. // (Co) ------------------------------------------------
  503. //
  504. // where S indicates small sectors, L indicates large sectors, and Cx
  505. // represents count of sectors. For example, the middle box represents
  506. // doing a setsize on a stream which is currently stored in a small
  507. // stream in Co small sectors and which will end up in a large stream
  508. // with Cn sectors.
  509. //
  510. //---------------------------------------------------------------------------
  511. #ifdef LARGE_STREAMS
  512. SCODE CDirectStream::SetSize(ULONGLONG cbNewSize)
  513. #else
  514. SCODE CDirectStream::SetSize(ULONG cbNewSize)
  515. #endif
  516. {
  517. msfDebugOut((DEB_ITRACE,"In CDirectStream::SetSize(%lu)\n",cbNewSize));
  518. SCODE sc = S_OK;
  519. BYTE *pBuf = NULL;
  520. SID sid = _stmh.GetSid();
  521. CMStream *pms = _stmh.GetMS();
  522. msfAssert(sid <= MAXREGSID);
  523. if (NULL == pms)
  524. return STG_E_UNKNOWN;
  525. CDirectory *pdir = pms->GetDir();
  526. if (_ulSize == cbNewSize)
  527. {
  528. return S_OK;
  529. }
  530. #ifdef SECURE_STREAMS
  531. msfAssert(_ulHighWater <= _ulSize);
  532. #endif
  533. USHORT cbpsOld = pms->GetSectorSize();
  534. // Count of Bytes Per Sector
  535. USHORT cbpsNew = cbpsOld;
  536. CFat *pfatOld = pms->GetFat();
  537. CFat *pfatNew = pfatOld;
  538. if ((!pms->IsScratch()) && (SIDMINISTREAM != sid))
  539. {
  540. // This is not a scratch DocFile, nor is this stream the ministream;
  541. // check if this stream is and/or will be stored in the ministream.
  542. if (cbNewSize < MINISTREAMSIZE)
  543. {
  544. cbpsNew = MINISECTORSIZE;
  545. pfatNew = pms->GetMiniFat();
  546. }
  547. if (_ulSize < MINISTREAMSIZE)
  548. {
  549. cbpsOld = MINISECTORSIZE;
  550. pfatOld = pms->GetMiniFat();
  551. }
  552. }
  553. ULONG csectOld = (ULONG)((_ulSize + cbpsOld - 1) / cbpsOld);
  554. ULONG csectNew = (ULONG)((cbNewSize + cbpsNew - 1) / cbpsNew);
  555. msfAssert(sid <= MAXREGSID);
  556. SECT sectstart, sectOldStart;
  557. msfChk(pdir->GetStart(sid, &sectstart));
  558. //Save start sector so we can free it later.
  559. sectOldStart = sectstart;
  560. msfDebugOut((DEB_ITRACE,"pdbOld size is %lu\n\tSid is %lu\n\tStart is %lu\n",
  561. _ulSize,sid,sectstart));
  562. msfDebugOut((DEB_ITRACE,"CMStream::SetSize() needs %lu %u byte sectors\n",
  563. csectNew, cbpsNew));
  564. msfDebugOut((DEB_ITRACE,"SetSize() currently has %lu %u byte sectors\n",
  565. csectOld, cbpsOld));
  566. ULONG cbCopy;
  567. cbCopy = 0;
  568. if (cbpsOld != cbpsNew)
  569. {
  570. // Sector sizes are different, so we'll copy the data
  571. msfAssert((cbNewSize > _ulSize ? _ulSize : cbNewSize) < 0x10000);
  572. cbCopy = (ULONG)(cbNewSize > _ulSize ? _ulSize : cbNewSize);
  573. }
  574. if (cbCopy > 0)
  575. {
  576. msfDebugOut((DEB_ITRACE,"Copying between fat and minifat\n"));
  577. GetSafeBuffer(cbCopy, cbCopy, &pBuf, &cbCopy);
  578. msfAssert((pBuf != NULL) && aMsg("Couldn't get scratch buffer"));
  579. ULONG ulRetVal;
  580. sc = ReadAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal);
  581. #ifdef SECURE_STREAMS
  582. //Part of the buffer may have gunk in it, so clear it out.
  583. if (_ulHighWater < cbCopy)
  584. {
  585. memset(pBuf + _ulHighWater, SECURECHAR, cbCopy - _ulHighWater);
  586. }
  587. #endif
  588. if ((FAILED(sc)) ||
  589. ((ulRetVal != cbCopy) ? (sc = STG_E_UNKNOWN) : 0))
  590. {
  591. msfErr(Err, sc);
  592. }
  593. #ifdef SECURE_STREAMS
  594. ClearSects(_ulHighWater, _ulSize);
  595. _ulHighWater = cbNewSize;
  596. #endif
  597. //The cache is no longer valid, so empty it.
  598. _stmc.Empty();
  599. msfChk(_stmc.Allocate(pfatNew, csectNew, &sectstart));
  600. }
  601. else
  602. {
  603. SECT dummy;
  604. if ((csectOld > csectNew))
  605. {
  606. #ifdef SECURE_STREAMS
  607. ClearSects(_ulHighWater, _ulSize);
  608. _ulHighWater = cbNewSize;
  609. #endif
  610. if (0 == csectNew)
  611. {
  612. //Note: We need to set the start sect in the directory
  613. // first in case the SetChainLength call fails part way
  614. // through, which would leave this directory entry pointing
  615. // to a FREESECT.
  616. SECT sectOldStart = sectstart;
  617. msfChk(pdir->SetStart(sid, ENDOFCHAIN));
  618. sectstart = ENDOFCHAIN;
  619. msfChk(pfatOld->SetChainLength(sectOldStart, 0));
  620. }
  621. else
  622. {
  623. msfChk(pfatOld->SetChainLength(sectstart, csectNew));
  624. }
  625. //If this turns out to be a common case, we can
  626. // sometimes keep the cache valid here.
  627. _stmc.Empty();
  628. }
  629. else if (0 == csectOld)
  630. {
  631. msfChk(_stmc.Allocate(pfatNew, csectNew, &sectstart));
  632. }
  633. else if (csectNew > csectOld)
  634. {
  635. ULONG start = csectNew - 1;
  636. msfChk(_stmc.GetESect(start, &dummy));
  637. }
  638. }
  639. // Resize the ministream, if necessary
  640. if (((MINISECTORSIZE == cbpsOld) && (csectOld > 0)) ||
  641. ((MINISECTORSIZE == cbpsNew) && (csectNew > 0)))
  642. {
  643. msfChk(pms->SetMiniSize());
  644. }
  645. msfChk(pms->SetSize());
  646. //If we fail on either of these operations and cbCopy != 0,
  647. // we will have data loss. Ick.
  648. // Optimization - we only set the start sector if it has changed.
  649. if (sectstart != sectOldStart)
  650. {
  651. msfChk(pdir->SetStart(sid, sectstart));
  652. }
  653. //If we fail here, we're in big trouble.
  654. msfChk(pdir->SetSize(sid, cbNewSize));
  655. _ulSize = cbNewSize;
  656. #ifdef SECURE_STREAMS
  657. if (_ulHighWater > _ulSize)
  658. {
  659. _ulHighWater = _ulSize;
  660. }
  661. #endif
  662. if (cbCopy > 0)
  663. {
  664. // now copy the data
  665. ULONG ulRetVal;
  666. msfAssert(cbCopy <= _ulSize);
  667. msfChk(WriteAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal));
  668. if (ulRetVal != cbCopy)
  669. {
  670. msfErr(Err, STG_E_UNKNOWN);
  671. }
  672. msfChk(pfatOld->SetChainLength(sectOldStart, 0));
  673. msfChk(pms->SetMiniSize());
  674. msfChk(pms->SetSize());
  675. }
  676. #ifdef SECURE
  677. if (((csectNew > csectOld) || (cbCopy > 0)) &&
  678. ((cbNewSize & (cbpsNew - 1)) != 0))
  679. {
  680. SECT sectLast;
  681. msfChk(_stmc.GetSect(csectNew - 1, &sectLast));
  682. msfVerify(SUCCEEDED(pms->SecureSect(
  683. sectLast,
  684. cbNewSize,
  685. (cbNewSize < MINISTREAMSIZE) && (sid != SIDMINISTREAM))));
  686. }
  687. #endif //SECURE
  688. #ifdef SECURE_STREAMS
  689. msfAssert(_ulHighWater <= _ulSize);
  690. #endif
  691. Err:
  692. #ifdef SECURE_STREAMS
  693. if (_ulHighWater > _ulSize)
  694. {
  695. _ulHighWater = _ulSize;
  696. }
  697. #endif
  698. // Optimization - avoid calling FreeBuffer (which will end up calling
  699. // out to CompObj.DLL) when pBuf is NULL (common case).
  700. if (pBuf != NULL)
  701. FreeBuffer(pBuf);
  702. if (FAILED(sc))
  703. _stmc.Empty();
  704. return sc;
  705. }
  706. //+-------------------------------------------------------------------------
  707. //
  708. // Method: CDirectStream::BeginCommitFromChild, public
  709. //
  710. // Synopsis: Begin a commit from a child stream
  711. //
  712. // Arguments: [ulSize] -- Size of child stream
  713. // [pDelta] -- Pointer to delta list
  714. // [pstChild] - Child
  715. //
  716. // Returns: S_OK if call completed successfully.
  717. //
  718. // Algorithm: *Finish This*
  719. //
  720. // History: 22-Jan-92 PhilipLa Created.
  721. //
  722. // Notes:
  723. //
  724. //--------------------------------------------------------------------------
  725. SCODE CDirectStream::BeginCommitFromChild(
  726. #ifdef LARGE_STREAMS
  727. ULONGLONG ulSize,
  728. #else
  729. ULONG ulSize,
  730. #endif
  731. CDeltaList *pDelta,
  732. CTransactedStream *pstChild)
  733. {
  734. msfDebugOut((DEB_ITRACE,"In CDirectStream::BeginCommitFromChild:%p("
  735. "%lu, %p, %p)\n", this, ulSize, pDelta, pstChild));
  736. // msfDebugOut((DEB_ITRACE,"MultiStrean is %p\nStream name is: %ws\n",_stmh.GetMS(),((_stmh.GetMS()))->GetName(_stmh.GetSid())));
  737. SCODE sc = S_OK;
  738. ULONG temp;
  739. BYTE *pb = NULL;
  740. _pdlHolder = P_TO_BP(CBasedDeltaListPtr, pDelta);
  741. // Copy-on-write will back out these changes if we fail
  742. #ifdef USE_NOSCRATCH
  743. //For no-scratch mode, we commit very differently than we do regularly,
  744. // unless this commit is somehow involving the minifat.
  745. if ((pDelta->IsNoScratch()) &&
  746. (ulSize >= MINISTREAMSIZE) &&
  747. ((_ulSize >= MINISTREAMSIZE) || (_ulSize == 0)) &&
  748. (!pDelta->IsEmpty()))
  749. {
  750. USHORT cbSector = pDelta->GetDataSectorSize();
  751. SECT sectEnd = (SECT)((ulSize + cbSector - 1) / cbSector);
  752. SECT sectLast = ENDOFCHAIN;
  753. //We update our size and directory first so the stream cache
  754. // code knows which fat to get to.
  755. _ulOldSize = _ulSize;
  756. _ulSize = ulSize;
  757. msfChk(_stmh.GetMS()->GetDir()->SetSize(_stmh.GetSid(), ulSize));
  758. if (_ulOldSize > _ulSize)
  759. {
  760. //We need to truncate the chain.
  761. SECT sectStart;
  762. _stmh.GetMS()->GetDir()->GetStart(_stmh.GetSid(), &sectStart);
  763. _stmh.GetMS()->GetFat()->SetChainLength(sectStart, sectEnd);
  764. _stmc.Empty();
  765. }
  766. for (ULONG i = 0; i < sectEnd; i++)
  767. {
  768. SECT sectDirty;
  769. SECT sectOld;
  770. SECT sectNext;
  771. //For each sector, chain the old sector with the
  772. //existing new one.
  773. msfChk(pDelta->GetMap(i, DL_READ, &sectDirty));
  774. if (sectDirty != ENDOFCHAIN)
  775. {
  776. if (i > 0)
  777. {
  778. CFat *pfat = _stmh.GetMS()->GetFat();
  779. msfChk(_stmc.GetSect(i - 1, &sectLast));
  780. msfAssert(sectLast != ENDOFCHAIN);
  781. msfChk(pfat->GetNext(sectLast, &sectOld));
  782. msfChk(pfat->SetNext(sectLast, sectDirty));
  783. if (sectOld != ENDOFCHAIN)
  784. {
  785. msfChk(pfat->GetNext(sectOld, &sectNext));
  786. msfChk(pfat->SetNext(sectOld, FREESECT));
  787. }
  788. else
  789. {
  790. sectNext = ENDOFCHAIN;
  791. }
  792. msfChk(pfat->SetNext(sectDirty, sectNext));
  793. msfChk(_stmc.EmptyRegion(i, i));
  794. }
  795. else
  796. {
  797. CFat *pfat = _stmh.GetMS()->GetFat();
  798. CDirectory *pdir = _stmh.GetMS()->GetDir();
  799. sectNext = ENDOFCHAIN;
  800. msfChk(pdir->GetStart(_stmh.GetSid(), &sectLast));
  801. if (sectLast != ENDOFCHAIN)
  802. {
  803. msfChk(pfat->GetNext(sectLast, &sectNext));
  804. msfChk(pfat->SetNext(sectLast, FREESECT));
  805. }
  806. msfChk(pfat->SetNext(sectDirty, sectNext));
  807. msfChk(pdir->SetStart(_stmh.GetSid(), sectDirty));
  808. msfChk(_stmc.EmptyRegion(i, i));
  809. }
  810. }
  811. }
  812. #ifdef SECURE_STREAMS
  813. _ulHighWater = _ulSize;
  814. #endif
  815. #if DBG == 1
  816. //Make sure that the stream is sane.
  817. #ifdef LARGE_STREAMS
  818. ULONGLONG ulDirSize;
  819. #else
  820. ULONG ulDirSize;
  821. #endif
  822. ULONG cSect;
  823. ULONG cSectReal;
  824. SECT sectStart;
  825. _stmh.GetMS()->GetDir()->GetSize(_stmh.GetSid(), &ulDirSize);
  826. cSect = (ULONG)((ulDirSize + cbSector - 1) / cbSector);
  827. _stmh.GetMS()->GetDir()->GetStart(_stmh.GetSid(), &sectStart);
  828. _stmh.GetMS()->GetFat()->GetLength(sectStart, &cSectReal);
  829. msfAssert((cSect == cSectReal) &&
  830. aMsg("Chain length incorrect after commit."));
  831. #endif
  832. }
  833. else
  834. {
  835. #endif //USE_NOSCRATCH
  836. // Note: It's critical that we do this SetSize first (since we
  837. // use our scratch buffer below and SetSize can potentially also
  838. // use the scratch buffer.
  839. msfChk(SetSize(ulSize));
  840. _ulOldSize = _ulSize;
  841. msfAssert(pDelta != NULL);
  842. if (!pDelta->IsEmpty())
  843. {
  844. USHORT cbSector = pDelta->GetDataSectorSize();
  845. USHORT uSectorShift = pDelta->GetDataSectorShift();
  846. ULONG cbActualSize = 0;
  847. ULONG cbMaxSects = 15;
  848. GetSafeBuffer(cbSector, cbSector * cbMaxSects, &pb, &cbActualSize);
  849. BYTE *pbcurrent = pb;
  850. msfAssert((pb != NULL) && aMsg("Couldn't get scratch buffer"));
  851. cbMaxSects = cbActualSize / cbSector;
  852. OFFSET oEnd;
  853. oEnd = (OFFSET)((_ulSize - 1) % cbSector) + 1;
  854. SECT sectEnd;
  855. sectEnd = (SECT)((_ulSize + cbSector - 1) / cbSector);
  856. ULONG ulOffset;
  857. ILockBytes *pilbDirty;
  858. SECT sectBeginRead = ENDOFCHAIN; //the first sector to read
  859. SECT sectBeginWrite = ENDOFCHAIN; //the offset of the first place to write
  860. SECT sectDirty = ENDOFCHAIN; //the sector at this offset
  861. USHORT uReadCount = 0;
  862. ULARGE_INTEGER ulTmp;
  863. pilbDirty = pDelta->GetDataILB();
  864. for (ulOffset = 0; ulOffset < sectEnd; ulOffset++)
  865. {
  866. if (sectDirty == ENDOFCHAIN)
  867. {
  868. sectBeginWrite = ulOffset;
  869. }
  870. msfChk(pDelta->GetMap(ulOffset, DL_READ, &sectDirty));
  871. // Read will happen when we have determined there is something to read
  872. // and either
  873. // we have reached an ENDOFCHAIN
  874. // we have reached a non-adjacent sector
  875. // or we have reached the maximun amount that can be read
  876. if ( (uReadCount) &&
  877. ( (sectDirty == ENDOFCHAIN) ||
  878. (sectDirty != sectBeginRead + uReadCount) ||
  879. (ulOffset - sectBeginWrite == cbMaxSects) ))
  880. {
  881. msfDebugOut((DEB_ITRACE,"Reading %u sectors from sect %lu\n",
  882. uReadCount,
  883. sectBeginRead));
  884. #ifdef LARGE_DOCFILE
  885. ulTmp.QuadPart = ConvertSectOffset(sectBeginRead, 0,
  886. uSectorShift);
  887. #else
  888. ULISet32(ulTmp, ConvertSectOffset(sectBeginRead, 0,
  889. uSectorShift));
  890. #endif
  891. msfHChk(pilbDirty->ReadAt(
  892. ulTmp,
  893. pbcurrent,
  894. cbSector * uReadCount,
  895. (ULONG STACKBASED *)&temp));
  896. pbcurrent += cbSector * uReadCount;
  897. sectBeginRead = sectDirty;
  898. //reset the ReadCount now that we are done reading
  899. if (sectDirty == ENDOFCHAIN)
  900. uReadCount = 0;
  901. else
  902. uReadCount = 1;
  903. }
  904. // increment the read count
  905. else if (sectDirty != ENDOFCHAIN)
  906. {
  907. if (sectBeginRead == ENDOFCHAIN)
  908. {
  909. sectBeginRead = sectDirty;
  910. uReadCount=1;
  911. }
  912. else if (sectDirty == sectBeginRead + uReadCount)
  913. {
  914. uReadCount++;
  915. }
  916. }
  917. // Write occurs when we have something to write
  918. // and we have reached an ENDOFCHAIN
  919. // or the write buffer is full
  920. if (((sectDirty == ENDOFCHAIN) &&
  921. (sectBeginWrite != ulOffset) ) ||
  922. (ulOffset - sectBeginWrite == cbMaxSects) )
  923. {
  924. msfDebugOut((DEB_ITRACE,"Writing %u sectors from sect %lu\n",
  925. ulOffset - sectBeginWrite,
  926. sectBeginWrite));
  927. msfChk(WriteAt(sectBeginWrite * cbSector,
  928. pb,
  929. cbSector * (ulOffset - sectBeginWrite),
  930. (ULONG STACKBASED *)&temp));
  931. pbcurrent = pb;
  932. sectBeginWrite = ulOffset;
  933. }
  934. }
  935. // After loop, do last read and write
  936. if (uReadCount)
  937. {
  938. #ifdef LARGE_DOCFILE
  939. ulTmp.QuadPart = ConvertSectOffset(sectBeginRead, 0, uSectorShift);
  940. #else
  941. ULISet32(ulTmp, ConvertSectOffset(sectBeginRead, 0,
  942. uSectorShift));
  943. #endif
  944. msfDebugOut((DEB_ITRACE,"END::Reading %u sectors from sect %lu\n",
  945. uReadCount,
  946. sectBeginRead));
  947. msfHChk(pilbDirty->ReadAt(
  948. ulTmp,
  949. pbcurrent,
  950. cbSector * uReadCount,
  951. (ULONG STACKBASED *)&temp));
  952. msfDebugOut((DEB_ITRACE,"END::Writing %u sectors from sect %lu\n",
  953. ulOffset - sectBeginWrite,
  954. sectBeginWrite));
  955. msfChk(WriteAt(sectBeginWrite * cbSector,
  956. pb,
  957. // all sectors except the last one
  958. (cbSector * ((ulOffset-1) - sectBeginWrite)
  959. // last sector fragment
  960. + oEnd ),
  961. (ULONG STACKBASED *)&temp));
  962. }
  963. }
  964. #ifdef USE_NOSCRATCH
  965. }
  966. #endif
  967. msfDebugOut((DEB_ITRACE,"Out CDirectStream::BeginCommitFromChild()\n"));
  968. Err:
  969. #ifdef SECURE_STREAMS
  970. msfAssert(_ulHighWater <= _ulSize);
  971. #endif
  972. FreeBuffer(pb);
  973. return sc;
  974. }
  975. //+-------------------------------------------------------------------------
  976. //
  977. // Method: CDirectStream::EndCommitFromChild
  978. //
  979. // Synopsis: End a commit sequence from a child stream
  980. //
  981. // Arguments: [df] -- Indicates whether to commit or abort
  982. // [pstChild] - Child
  983. //
  984. // Returns: S_OK if call completed successfully.
  985. //
  986. // Algorithm: *Finish This*
  987. //
  988. // History: 22-Jan-92 PhilipLa Created.
  989. //
  990. // Notes:
  991. //
  992. //--------------------------------------------------------------------------
  993. void CDirectStream::EndCommitFromChild(DFLAGS df,
  994. CTransactedStream *pstChild)
  995. {
  996. msfDebugOut((DEB_ITRACE,"In CDirectStream::EndCommitFromChild:%p("
  997. "%lu, %p)\n", this, df, pstChild));
  998. if (!P_COMMIT(df))
  999. {
  1000. _ulSize = _ulOldSize;
  1001. #ifdef SECURE_STREAMS
  1002. _ulHighWater = _ulSize;
  1003. #endif
  1004. //Stream cache is no longer valid, so nuke it.
  1005. _stmc.Empty();
  1006. }
  1007. _pdlHolder = NULL;
  1008. msfDebugOut((DEB_ITRACE,"Out CDirectStream::EndCommitFromChild()\n"));
  1009. }
  1010. //+---------------------------------------------------------------------------
  1011. //
  1012. // Member: CDirectStream::GetSize, public
  1013. //
  1014. // Synopsis: Gets the size of the stream
  1015. //
  1016. // Arguments: [pulSize] - Size return
  1017. //
  1018. // Modifies: [pulSize]
  1019. //
  1020. // History: 08-May-92 DrewB Created
  1021. //
  1022. //----------------------------------------------------------------------------
  1023. #ifdef LARGE_STREAMS
  1024. void CDirectStream::GetSize(ULONGLONG *pulSize)
  1025. #else
  1026. void CDirectStream::GetSize(ULONG *pulSize)
  1027. #endif
  1028. {
  1029. *pulSize = _ulSize;
  1030. }
  1031. //+---------------------------------------------------------------------------
  1032. //
  1033. // Member: CDirectStream::GetDeltaList, public
  1034. //
  1035. // Synopsis: Returns NULL, since a direct stream can never have
  1036. // a delta list.
  1037. //
  1038. // Arguments: None.
  1039. //
  1040. // Returns: NULL
  1041. //
  1042. // History: 30-Jul-93 PhilipLa Created
  1043. //
  1044. //----------------------------------------------------------------------------
  1045. CDeltaList * CDirectStream::GetDeltaList(void)
  1046. {
  1047. return NULL;
  1048. }
  1049. #ifdef SECURE_STREAMS
  1050. //+---------------------------------------------------------------------------
  1051. //
  1052. // Member: CDirectStream::ClearSects, private
  1053. //
  1054. // Synopsis:
  1055. //
  1056. // Arguments:
  1057. //
  1058. // Returns: void
  1059. //
  1060. // History: 10-Oct-95 PhilipLa Created
  1061. //
  1062. //----------------------------------------------------------------------------
  1063. void CDirectStream::ClearSects(ULONG ulStartOffset, ULONG ulEndOffset)
  1064. {
  1065. ULONG cbBytesToWrite = ulEndOffset - ulStartOffset;
  1066. ULONG ulOffset = ulStartOffset;
  1067. msfAssert(ulEndOffset >= ulStartOffset);
  1068. //Start offset must be less than high water mark, or the WriteAt
  1069. // will recurse.
  1070. msfAssert(ulStartOffset <= _ulHighWater);
  1071. while (cbBytesToWrite > 0)
  1072. {
  1073. ULONG cbWritten;
  1074. if (FAILED(WriteAt(ulOffset,
  1075. s_bufSecure,
  1076. min(MINISTREAMSIZE, cbBytesToWrite),
  1077. &cbWritten)))
  1078. {
  1079. break;
  1080. }
  1081. ulOffset += cbWritten;
  1082. cbBytesToWrite -= cbWritten;
  1083. }
  1084. return;
  1085. }
  1086. #endif