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.

710 lines
19 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. //--------------------------------------------------------------------
  13. #include "msfhead.cxx"
  14. #include "h/dirfunc.hxx"
  15. #include "h/sstream.hxx"
  16. #include <time.h>
  17. #include "mread.hxx"
  18. #define DEB_STREAM (DEB_ITRACE | 0x00020000)
  19. //+--------------------------------------------------------------
  20. //
  21. // Member: CDirectStream::CDirectStream, public
  22. //
  23. // Synopsis: Empty object constructor
  24. //
  25. // Arguments: [dl] - LUID
  26. //
  27. //---------------------------------------------------------------
  28. CDirectStream::CDirectStream(DFLUID dl)
  29. : PEntry(dl)
  30. {
  31. _cReferences = 0;
  32. }
  33. //+--------------------------------------------------------------
  34. //
  35. // Member: CDirectStream::InitSystem, public
  36. //
  37. // Synopsis: Initializes special system streams like the ministream
  38. //
  39. // Arguments: [pms] - Multistream
  40. // [sid] - SID
  41. // [cbSize] - size
  42. //
  43. //---------------------------------------------------------------
  44. void CDirectStream::InitSystem(CMStream *pms,
  45. SID sid,
  46. ULONG cbSize)
  47. {
  48. _stmh.Init(pms, sid);
  49. _ulSize = _ulOldSize = cbSize;
  50. AddRef();
  51. }
  52. //+-------------------------------------------------------------------------
  53. //
  54. // Method: CDirectStream::Init, public
  55. //
  56. // Synopsis: CDirectStream constructor
  57. //
  58. // Arguments: [pstgh] - Parent
  59. // [pdfn] - Name of entry
  60. // [fCreate] - Create or get
  61. //
  62. // Returns: Appropriate status code
  63. //
  64. //--------------------------------------------------------------------------
  65. SCODE CDirectStream::Init(
  66. CStgHandle *pstgh,
  67. CDfName const *pdfn,
  68. BOOL const fCreate)
  69. {
  70. SCODE sc;
  71. if (fCreate)
  72. sc = pstgh->CreateEntry(pdfn, STGTY_STREAM, &_stmh);
  73. else
  74. sc = pstgh->GetEntry(pdfn, STGTY_STREAM, &_stmh);
  75. if (SUCCEEDED(sc))
  76. {
  77. sc = _stmh.GetSize(&_ulSize);
  78. _ulOldSize = _ulSize;
  79. if (SUCCEEDED(sc))
  80. AddRef();
  81. }
  82. return sc;
  83. }
  84. //+-------------------------------------------------------------------------
  85. //
  86. // Method: CDirectStream::~CDirectStream, public
  87. //
  88. // Synopsis: CDirectStream destructor
  89. //
  90. // Notes:
  91. //
  92. //--------------------------------------------------------------------------
  93. CDirectStream::~CDirectStream()
  94. {
  95. msfAssert(_cReferences == 0);
  96. }
  97. //+-------------------------------------------------------------------------
  98. //
  99. // Member: CDirectStream::ReadAt, public
  100. //
  101. // Synposis: Reads binary data from a linear single stream
  102. //
  103. // Arguments: [ulOffset] -- Position to be read from
  104. //
  105. // [pBuffer] -- Pointer to the area into which the data
  106. // will be read.
  107. // [ulCount] -- Indicates the number of bytes to be read
  108. // [pulRetval] -- Area into which return value will be stored
  109. //
  110. // Returns: Error Code of parent MStream call
  111. //
  112. // Algorithm: Calculate start and end sectors and offsets, then
  113. // pass call up to parent MStream.
  114. //
  115. // Notes:
  116. //
  117. //---------------------------------------------------------------------------
  118. SCODE CDirectStream::ReadAt(
  119. ULONG ulOffset,
  120. VOID HUGEP *pBuffer,
  121. ULONG ulCount,
  122. ULONG STACKBASED *pulRetval)
  123. {
  124. msfDebugOut((DEB_TRACE,"In CDirectStream::ReadAt(%lu,%p,%lu)\n",
  125. ulOffset,pBuffer,ulCount));
  126. SCODE sc = S_OK;
  127. CMStream *pms = _stmh.GetMS();
  128. // Check for offset beyond stream size and zero count
  129. if ((ulOffset >= _ulSize) || (0 == ulCount))
  130. {
  131. *pulRetval = 0;
  132. return S_OK;
  133. }
  134. if (ulOffset + ulCount > _ulSize)
  135. {
  136. msfDebugOut((DEB_ITRACE,"Truncating Read: ulOffset = %lu, ulCount = %lu, _ulSize = %lu\n",
  137. ulOffset,ulCount,_ulSize));
  138. ulCount = _ulSize - ulOffset;
  139. }
  140. // Stream is stored in ministream if size < MINISTREAMSIZE
  141. // and this is not a scratch stream.
  142. SID sid = _stmh.GetSid();
  143. CFat *pfat = pms->GetFat();
  144. USHORT cbSector = pms->GetSectorSize();
  145. USHORT uShift = pms->GetSectorShift();
  146. USHORT uMask = pms->GetSectorMask();
  147. if ((_ulSize < MINISTREAMSIZE) &&
  148. (sid != SIDMINISTREAM))
  149. {
  150. msfAssert(sid <= MAXREGSID);
  151. // This stream is stored in the ministream
  152. cbSector = MINISECTORSIZE;
  153. uShift = MINISECTORSHIFT;
  154. uMask = (USHORT) (cbSector - 1);
  155. pfat = pms->GetMiniFat();
  156. }
  157. SECT start = (SECT)(ulOffset >> uShift);
  158. OFFSET oStart = (OFFSET)(ulOffset & uMask);
  159. SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift);
  160. OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
  161. ULONG total = 0;
  162. ULONG cSect = end - start + 1;
  163. SECT sectSidStart;
  164. USHORT offset;
  165. offset = oStart;
  166. while (TRUE)
  167. {
  168. SECT sect;
  169. if (start > _stmc.GetOffset())
  170. {
  171. msfChk(pfat->GetSect(
  172. _stmc.GetSect(),
  173. start - _stmc.GetOffset(),
  174. &sect));
  175. }
  176. else if (start == _stmc.GetOffset())
  177. {
  178. sect = _stmc.GetSect();
  179. }
  180. else
  181. {
  182. msfChk(pms->GetDir()->GetStart(sid, &sectSidStart));
  183. msfChk(pfat->GetSect(sectSidStart, start, &sect));
  184. }
  185. SSegment segtab[CSEG + 1];
  186. msfChk(pfat->Contig(
  187. (SSegment STACKBASED *) segtab,
  188. sect,
  189. cSect));
  190. USHORT oend = (USHORT) (cbSector - 1);
  191. for (USHORT iseg = 0; iseg < CSEG;)
  192. {
  193. msfDebugOut((DEB_ITRACE,"Segment: (%lu,%lu)\n",segtab[iseg].sectStart,segtab[iseg].cSect));
  194. SECT sectStart = segtab[iseg].sectStart;
  195. ULONG i = segtab[iseg].cSect;
  196. cSect -= i;
  197. start += i;
  198. iseg++;
  199. if (segtab[iseg].sectStart == ENDOFCHAIN)
  200. oend = oEnd;
  201. ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
  202. ULONG bytecount;
  203. SCODE sc;
  204. if (pms->GetMiniFat() == pfat)
  205. {
  206. sc = pms->GetMiniStream()->CDirectStream::ReadAt(
  207. (sectStart << uShift) + offset,
  208. pBuffer, ulSize,
  209. (ULONG STACKBASED *)&bytecount);
  210. }
  211. else
  212. {
  213. ULARGE_INTEGER ulOffset;
  214. ULISet32(ulOffset, ConvertSectOffset(sectStart,offset,uShift));
  215. sc = DfGetScode(pms->GetILB()->ReadAt(ulOffset,
  216. (BYTE *)pBuffer, ulSize,
  217. &bytecount));
  218. }
  219. total += bytecount;
  220. if ((0 == cSect) || (FAILED(sc)))
  221. {
  222. _stmc.SetCache(start - 1, sectStart + i - 1);
  223. *pulRetval = total;
  224. msfDebugOut((DEB_TRACE,
  225. "Leaving CDirectStream::ReadAt()=>%lu, ret is %lu\n",
  226. sc,*pulRetval));
  227. return sc;
  228. }
  229. pBuffer = (BYTE HUGEP *)pBuffer + bytecount;
  230. offset = 0;
  231. }
  232. }
  233. msfDebugOut((DEB_ERROR,"In CDirectStream::ReadAt - reached end of function\n"));
  234. Err:
  235. return sc;
  236. }
  237. //+-------------------------------------------------------------------------
  238. //
  239. // Member: CDirectStream::Write, public
  240. //
  241. // Synposis: Writes binary data from a linear single stream
  242. //
  243. // Effects: Modifies _ulSeekPos. May cause modification in parent
  244. // MStream.
  245. //
  246. // Arguments: [pBuffer] -- Pointer to the area from which the data
  247. // will be written.
  248. // [ulCount] -- Indicates the number of bytes to be written
  249. // [pulRetval] -- Pointer to area in which number of bytes
  250. // will be returned
  251. //
  252. // Returns: Error code of MStream call.
  253. //
  254. // Algorithm: Calculate sector and offset for beginning and end of
  255. // write, then pass call up to MStream.
  256. //
  257. //
  258. // Notes:
  259. //
  260. //---------------------------------------------------------------------------
  261. SCODE CDirectStream::WriteAt(
  262. ULONG ulOffset,
  263. VOID const HUGEP *pBuffer,
  264. ULONG ulCount,
  265. ULONG STACKBASED *pulRetval)
  266. {
  267. msfDebugOut((DEB_TRACE,"In CDirectStream::WriteAt(%lu,%p,%lu)\n",ulOffset,pBuffer,ulCount));
  268. *pulRetval = 0;
  269. if (0 == ulCount)
  270. return S_OK;
  271. SCODE sc;
  272. if (ulOffset + ulCount > _ulSize)
  273. {
  274. if (_ulSize > MINISTREAMSIZE)
  275. {
  276. }
  277. else
  278. {
  279. msfChk(SetSize(ulOffset + ulCount));
  280. }
  281. }
  282. CMStream *pms;
  283. pms = _stmh.GetMS();
  284. msfAssert(pms != NULL);
  285. // This should be an inline call to MWrite
  286. msfChk(pms->MWrite(
  287. _stmh.GetSid(),
  288. (_ulSize < MINISTREAMSIZE),
  289. ulOffset,
  290. pBuffer,
  291. ulCount,
  292. &_stmc,
  293. pulRetval));
  294. msfAssert(*pulRetval == ulCount);
  295. msfDebugOut((DEB_TRACE,"Leaving CDirectStream::WriteAt()==>%lu, ret is %lu\n",sc,*pulRetval));
  296. Err:
  297. if (ulOffset + *pulRetval > _ulSize)
  298. {
  299. SCODE scSet;
  300. _ulSize = ulOffset + *pulRetval;
  301. scSet = pms->GetDir()->SetSize(_stmh.GetSid(), _ulSize);
  302. if (SUCCEEDED(sc) && FAILED(scSet))
  303. {
  304. sc = scSet;
  305. }
  306. }
  307. return sc;
  308. }
  309. //+-------------------------------------------------------------------------
  310. //
  311. // Member: CDirectStream::SetSize, public
  312. //
  313. // Synposis: Set the size of a linear stream
  314. //
  315. // Effects: Modifies _ulSize. May cause change in parent MStream.
  316. //
  317. // Arguments: [ulNewSize] -- New size for stream
  318. //
  319. // Returns: Error code returned by MStream call.
  320. //
  321. // Algorithm: Pass call up to parent.
  322. //
  323. // Notes: When changing the size of a stream, we need to be concerned
  324. // with the cases where each stream is either zero length,
  325. // stored in the ministream, or stored in a regular stream. The following
  326. // grid shows the actions that we must perform in each case:
  327. //
  328. // New Sector Count (Cn)
  329. //
  330. // 0 S L
  331. // O ------------------------------------------------
  332. // l | same size | allocate Cn | allocate Cn
  333. // d 0 | (fast out) | small sectors | large sectors
  334. // ------------------------------------------------
  335. // S | small | Co > Cn: | cbCopy = cbOld
  336. // e S | setchain(Cn) | small | large allocate Cn
  337. // c | | setchain(Cn)| copy bytes
  338. // t | | Cn > Co: | small setchain(0)
  339. // o | | extend small | copy data
  340. // r ------------------------------------------------
  341. // L | large | cbCopy = cbNew| Co > Cn:
  342. // C | setchain(Cn) | small | large setchain(Cn)
  343. // o | | allocate Cn | Cn > Co:
  344. // u | | copy bytes | extend large
  345. // n | | large |
  346. // t | | setchain(0) |
  347. // | | copy data |
  348. // (Co) ------------------------------------------------
  349. //
  350. // where S indicates small sectors, L indicates large sectors, and Cx
  351. // represents count of sectors. For example, the middle box represents
  352. // doing a setsize on a stream which is currently stored in a small
  353. // stream in Co small sectors and which will end up in a large stream
  354. // with Cn sectors.
  355. //
  356. //---------------------------------------------------------------------------
  357. SCODE CDirectStream::SetSize(ULONG cbNewSize)
  358. {
  359. msfDebugOut((DEB_TRACE,"In CDirectStream::SetSize(%lu)\n",cbNewSize));
  360. SCODE sc = S_OK;
  361. BYTE *pBuf = NULL;
  362. SID sid = _stmh.GetSid();
  363. CMStream *pms = _stmh.GetMS();
  364. msfAssert(sid <= MAXREGSID);
  365. CDirectory *pdir = pms->GetDir();
  366. SECT sectOldStart;
  367. if (_ulSize == cbNewSize)
  368. {
  369. return S_OK;
  370. }
  371. USHORT cbpsOld = pms->GetSectorSize();
  372. // Count of Bytes Per Sector
  373. USHORT cbpsNew = cbpsOld;
  374. CFat *pfatOld = pms->GetFat();
  375. CFat *pfatNew = pfatOld;
  376. if (SIDMINISTREAM != sid)
  377. {
  378. if (cbNewSize < MINISTREAMSIZE)
  379. {
  380. cbpsNew = MINISECTORSIZE;
  381. pfatNew = pms->GetMiniFat();
  382. }
  383. if (_ulSize < MINISTREAMSIZE)
  384. {
  385. cbpsOld = MINISECTORSIZE;
  386. pfatOld = pms->GetMiniFat();
  387. }
  388. }
  389. ULONG csectOld = (ULONG)(_ulSize + cbpsOld - 1) / (ULONG) cbpsOld;
  390. ULONG csectNew = (ULONG)(cbNewSize + cbpsNew - 1) / (ULONG) cbpsNew;
  391. msfAssert(sid <= MAXREGSID);
  392. SECT sectstart;
  393. msfChk(pdir->GetStart(sid, &sectstart));
  394. msfDebugOut((DEB_ITRACE,"pdbOld size is %lu\n\tSid is %lu\n\tStart is %lu\n",
  395. _ulSize,sid,sectstart));
  396. msfDebugOut((DEB_ITRACE,"CMStream::SetSize() needs %lu %u byte sectors\n",
  397. csectNew, cbpsNew));
  398. msfDebugOut((DEB_ITRACE,"SetSize() currently has %lu %u byte sectors\n",
  399. csectOld, cbpsOld));
  400. USHORT cbCopy;
  401. cbCopy = 0;
  402. if (cbpsOld != cbpsNew)
  403. {
  404. // Sector sizes are different, so we'll copy the data
  405. msfAssert((cbNewSize > _ulSize ? _ulSize : cbNewSize) < 0x10000);
  406. cbCopy =(USHORT)(cbNewSize > _ulSize ? _ulSize : cbNewSize);
  407. }
  408. if (cbCopy > 0)
  409. {
  410. msfDebugOut((DEB_ITRACE,"Copying between fat and minifat\n"));
  411. GetSafeBuffer(cbCopy, cbCopy, &pBuf, &cbCopy);
  412. msfAssert((pBuf != NULL) && aMsg("Couldn't get scratch buffer"));
  413. ULONG ulRetVal;
  414. sc = ReadAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal);
  415. if ((FAILED(sc)) ||
  416. ((ulRetVal != cbCopy) ? (sc = STG_E_UNKNOWN) : 0))
  417. {
  418. msfErr(Err, sc);
  419. }
  420. //The cache is no longer valid, so empty it.
  421. _stmc.SetCache(MAX_ULONG, ENDOFCHAIN);
  422. //Save start sector so we can free it later.
  423. sectOldStart = sectstart;
  424. msfChk(pfatNew->Allocate(csectNew, &sectstart));
  425. }
  426. else
  427. {
  428. SECT dummy;
  429. if ((csectOld > csectNew))
  430. {
  431. msfChk(pfatOld->SetChainLength(sectstart, csectNew));
  432. if (0 == csectNew)
  433. {
  434. sectstart = ENDOFCHAIN;
  435. }
  436. //If this turns out to be a common case, we can
  437. // sometimes keep the cache valid here.
  438. _stmc.SetCache(MAX_ULONG, ENDOFCHAIN);
  439. }
  440. else if (0 == csectOld)
  441. {
  442. msfAssert(_stmc.GetOffset() == MAX_ULONG);
  443. msfChk(pfatNew->Allocate(csectNew, &sectstart));
  444. }
  445. else if (csectNew > csectOld)
  446. {
  447. ULONG start = csectNew - 1;
  448. if (start > _stmc.GetOffset())
  449. {
  450. msfChk(pfatNew->GetESect(
  451. _stmc.GetSect(),
  452. start - _stmc.GetOffset(),
  453. &dummy));
  454. }
  455. else if (start != _stmc.GetOffset())
  456. {
  457. msfChk(pfatNew->GetESect(sectstart, start, &dummy));
  458. }
  459. }
  460. }
  461. // Resize the ministream, if necessary
  462. if (((MINISECTORSIZE == cbpsOld) && (csectOld > 0)) ||
  463. ((MINISECTORSIZE == cbpsNew) && (csectNew > 0)))
  464. {
  465. msfChk(pms->SetMiniSize());
  466. }
  467. msfChk(pms->SetSize());
  468. //If we fail on either of these operations and cbCopy != 0,
  469. // we will have data loss. Ick.
  470. msfChk(pdir->SetStart(sid, sectstart));
  471. //If we fail here, were in trouble.
  472. msfChk(pdir->SetSize(sid, cbNewSize));
  473. _ulSize = cbNewSize;
  474. if (cbCopy > 0)
  475. {
  476. // now copy the data
  477. ULONG ulRetVal;
  478. msfAssert(cbCopy <= _ulSize);
  479. msfChk(WriteAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal));
  480. if (ulRetVal != cbCopy)
  481. {
  482. msfErr(Err, STG_E_UNKNOWN);
  483. }
  484. msfChk(pfatOld->SetChainLength(sectOldStart, 0));
  485. msfChk(pms->SetMiniSize());
  486. msfChk(pms->SetSize());
  487. }
  488. if (((csectNew > csectOld) || (cbCopy > 0)) &&
  489. ((cbNewSize & (cbpsNew - 1)) != 0))
  490. {
  491. SECT sectLast;
  492. if (csectNew - 1 > _stmc.GetOffset())
  493. {
  494. msfChk(pfatNew->GetSect(
  495. _stmc.GetSect(),
  496. (csectNew - 1) - _stmc.GetOffset(),
  497. &sectLast));
  498. }
  499. else
  500. {
  501. msfChk(pfatNew->GetSect(sectstart, csectNew - 1, &sectLast));
  502. }
  503. msfVerify(SUCCEEDED(pms->SecureSect(
  504. sectLast,
  505. cbNewSize,
  506. (cbNewSize < MINISTREAMSIZE) && (sid != SIDMINISTREAM))));
  507. }
  508. Err:
  509. FreeBuffer(pBuf);
  510. return sc;
  511. }
  512. //+---------------------------------------------------------------------------
  513. //
  514. // Member: CDirectStream::Release, public
  515. //
  516. // Synopsis: Decrements the ref count and frees if necessary
  517. //
  518. //----------------------------------------------------------------------------
  519. void CDirectStream::Release(VOID)
  520. {
  521. msfDebugOut((DEB_TRACE,"In CDirectStream::Release()\n"));
  522. msfAssert(_cReferences > 0);
  523. AtomicDec(&_cReferences);
  524. if (_cReferences == 0)
  525. delete this;
  526. msfDebugOut((DEB_TRACE,"Out CDirectStream::Release()\n"));
  527. }
  528. //+--------------------------------------------------------------
  529. //
  530. // Member: CDirectStream::AddRef, public
  531. //
  532. // Synopsis: Increments the ref count
  533. //
  534. //---------------------------------------------------------------
  535. void CDirectStream::AddRef(void)
  536. {
  537. msfDebugOut((DEB_ITRACE, "In CDirectStream::AddRef()\n"));
  538. AtomicInc(&_cReferences);
  539. msfDebugOut((DEB_ITRACE, "Out CDirectStream::AddRef, %lu\n",
  540. _cReferences));
  541. }
  542. //+---------------------------------------------------------------------------
  543. //
  544. // Member: CDirectStream::GetSize, public
  545. //
  546. // Synopsis: Gets the size of the stream
  547. //
  548. // Arguments: [pulSize] - Size return
  549. //
  550. // Modifies: [pulSize]
  551. //
  552. //----------------------------------------------------------------------------
  553. void CDirectStream::GetSize(ULONG *pulSize)
  554. {
  555. *pulSize = _ulSize;
  556. }
  557. //+--------------------------------------------------------------
  558. //
  559. // Member: CDirectStream::GetTime, public
  560. //
  561. // Synopsis: Gets a time
  562. //
  563. // Arguments: [wt] - Which time
  564. // [ptm] - Time return
  565. //
  566. // Returns: Appropriate status code
  567. //
  568. // Modifies: [ptm]
  569. //
  570. //---------------------------------------------------------------
  571. SCODE CDirectStream::GetTime(WHICHTIME wt, TIME_T *ptm)
  572. {
  573. return _stmh.GetTime(wt, ptm);
  574. }
  575. //+--------------------------------------------------------------
  576. //
  577. // Member: CDirectStream::SetTime, public
  578. //
  579. // Synopsis: Sets a time
  580. //
  581. // Arguments: [wt] - Which time
  582. // [tm] - New time
  583. //
  584. // Returns: Appropriate status code
  585. //
  586. //---------------------------------------------------------------
  587. SCODE CDirectStream::SetTime(WHICHTIME wt, TIME_T tm)
  588. {
  589. return _stmh.SetTime(wt, tm);
  590. }