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.

641 lines
17 KiB

  1. // --------------------------------------------------------------------------------
  2. // Vstream.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Ronald E. Gray
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "vstream.h"
  8. #include "dllmain.h"
  9. #include "demand.h"
  10. // --------------------------------------------------------------------------------
  11. // Utilities
  12. // --------------------------------------------------------------------------------
  13. inline ULONG ICeil(ULONG x, ULONG interval)
  14. {
  15. return (x ? (((x-1)/interval) + 1) * interval : 0);
  16. }
  17. // --------------------------------------------------------------------------------
  18. // CVirtualStream::CVirtualStream
  19. // --------------------------------------------------------------------------------
  20. CVirtualStream::CVirtualStream(void)
  21. {
  22. m_cRef = 1;
  23. m_cbSize = 0;
  24. m_cbCommitted = 0;
  25. m_cbAlloc = 0;
  26. m_dwOffset = 0;
  27. m_pstm = NULL;
  28. m_pb = 0;
  29. m_fFileErr = FALSE;
  30. InitializeCriticalSection(&m_cs);
  31. }
  32. // --------------------------------------------------------------------------------
  33. // CVirtualStream::~CVirtualStream
  34. // --------------------------------------------------------------------------------
  35. CVirtualStream::~CVirtualStream(void)
  36. {
  37. if (m_pb)
  38. VirtualFree(m_pb, 0, MEM_RELEASE);
  39. if (m_pstm)
  40. m_pstm->Release();
  41. DeleteCriticalSection(&m_cs);
  42. }
  43. // --------------------------------------------------------------------------------
  44. // CVirtualStream::QueryInterface
  45. // --------------------------------------------------------------------------------
  46. STDMETHODIMP CVirtualStream::QueryInterface(REFIID riid, LPVOID *ppv)
  47. {
  48. // check params
  49. if (ppv == NULL)
  50. return TrapError(E_INVALIDARG);
  51. // Init
  52. *ppv = NULL;
  53. // Find IID
  54. if ( (IID_IUnknown == riid)
  55. || (IID_IStream == riid)
  56. || (IID_IVirtualStream == riid))
  57. *ppv = (IStream *)this;
  58. else
  59. {
  60. *ppv = NULL;
  61. return TrapError(E_NOINTERFACE);
  62. }
  63. // AddRef It
  64. AddRef();
  65. // Done
  66. return (ResultFromScode(S_OK));
  67. }
  68. // --------------------------------------------------------------------------------
  69. // CVirtualStream::AddRef
  70. // --------------------------------------------------------------------------------
  71. STDMETHODIMP_(ULONG) CVirtualStream::AddRef(void)
  72. {
  73. return InterlockedIncrement((LONG*)&m_cRef);
  74. }
  75. // --------------------------------------------------------------------------------
  76. // CVirtualStream::SyncFileStream
  77. // --------------------------------------------------------------------------------
  78. HRESULT CVirtualStream::SyncFileStream()
  79. {
  80. LARGE_INTEGER li;
  81. HRESULT hr;
  82. // figure out where to set the file stream be subtracting the memory portion
  83. // of the stream from the offset
  84. #ifdef MAC
  85. if (m_dwOffset < m_cbAlloc)
  86. LISet32(li, 0);
  87. else
  88. {
  89. LISet32(li, m_dwOffset);
  90. li.LowPart -= m_cbAlloc;
  91. }
  92. #else // !MAC
  93. if (m_dwOffset < m_cbAlloc)
  94. li.QuadPart = 0;
  95. else
  96. li.QuadPart = m_dwOffset - m_cbAlloc;
  97. #endif // MAC
  98. // seek in the stream
  99. hr = m_pstm->Seek(li, STREAM_SEEK_SET, NULL);
  100. // reset the file err member based on the current error
  101. m_fFileErr = !!hr;
  102. return hr;
  103. }
  104. // --------------------------------------------------------------------------------
  105. // CVirtualStream::Release
  106. // --------------------------------------------------------------------------------
  107. STDMETHODIMP_(ULONG) CVirtualStream::Release(void)
  108. {
  109. ULONG cRef = InterlockedDecrement((LONG*)&m_cRef);
  110. if (0 != cRef)
  111. {
  112. #ifdef DEBUG
  113. return cRef;
  114. #else
  115. return 0;
  116. #endif
  117. }
  118. delete this;
  119. return 0;
  120. }
  121. // --------------------------------------------------------------------------------
  122. // CVirtualStream::Read
  123. // --------------------------------------------------------------------------------
  124. #ifndef WIN16
  125. STDMETHODIMP CVirtualStream::Read(LPVOID pv, ULONG cb, ULONG *pcbRead)
  126. #else
  127. STDMETHODIMP CVirtualStream::Read(VOID HUGEP *pv, ULONG cb, ULONG *pcbRead)
  128. #endif // !WIN16
  129. {
  130. // Locals
  131. HRESULT hr = ResultFromScode(S_OK);
  132. ULONG cbGet = 0;
  133. // Check
  134. AssertWritePtr(pv, cb);
  135. // Thread Safety
  136. EnterCriticalSection(&m_cs);
  137. // if the steam pointer is possibly out of sync
  138. // resync
  139. if (m_fFileErr)
  140. {
  141. hr = SyncFileStream();
  142. if (hr) goto err;
  143. }
  144. // make sure there's something to read
  145. if (m_dwOffset < m_cbSize)
  146. {
  147. // figure out what we're getting out of memory
  148. if (m_dwOffset < m_cbCommitted)
  149. {
  150. if (m_cbSize > m_cbCommitted)
  151. cbGet = min(cb, m_cbCommitted - m_dwOffset);
  152. else
  153. cbGet = min(cb, m_cbSize - m_dwOffset);
  154. // copy the memory stuff
  155. CopyMemory((LPBYTE)pv, m_pb + m_dwOffset, cbGet);
  156. }
  157. // if we still have stuff to read
  158. // and we've used all of the memory
  159. // and we do have a stream, try to get the rest of the data out of the stream
  160. if ( (cbGet != cb)
  161. && (m_cbCommitted == m_cbAlloc)
  162. && m_pstm)
  163. {
  164. ULONG cbRead;
  165. #ifdef DEBUG
  166. LARGE_INTEGER li = {0, 0};
  167. ULARGE_INTEGER uli = {0, 0};
  168. if (!m_pstm->Seek(li, STREAM_SEEK_CUR, &uli))
  169. #ifdef MAC
  170. Assert(((m_dwOffset + cbGet) - m_cbAlloc) == uli.LowPart);
  171. #else // !MAC
  172. Assert(((m_dwOffset + cbGet) - m_cbAlloc) == uli.QuadPart);
  173. #endif // MAC
  174. #endif
  175. hr = m_pstm->Read(((LPBYTE)pv) + cbGet, cb - cbGet, &cbRead);
  176. if (hr)
  177. {
  178. m_fFileErr = TRUE;
  179. goto err;
  180. }
  181. cbGet += cbRead;
  182. }
  183. m_dwOffset += cbGet;
  184. }
  185. if (pcbRead)
  186. *pcbRead = cbGet;
  187. err:
  188. // Thread Safety
  189. LeaveCriticalSection(&m_cs);
  190. // Done
  191. return hr;
  192. }
  193. // --------------------------------------------------------------------------------
  194. // CVirtualStream::SetSize
  195. // --------------------------------------------------------------------------------
  196. HRESULT CVirtualStream::SetSize(ULARGE_INTEGER uli)
  197. {
  198. // Locals
  199. HRESULT hr = ResultFromScode(S_OK);
  200. ULONG cbDemand = uli.LowPart;
  201. ULONG cbCommit = ICeil(cbDemand, g_dwSysPageSize);
  202. if (uli.HighPart != 0)
  203. return(ResultFromScode(STG_E_MEDIUMFULL));
  204. // Thread Safety
  205. EnterCriticalSection(&m_cs);
  206. // if we haven't initialized memory, do it now
  207. if (!m_cbAlloc)
  208. {
  209. LPVOID pv;
  210. ULONG cb = 32 * g_dwSysPageSize; // use 32 pages
  211. while ((!(pv = VirtualAlloc(NULL, cb, MEM_RESERVE, PAGE_READWRITE)))
  212. && (cb > g_dwSysPageSize))
  213. {
  214. cb /= 2;
  215. }
  216. if (!pv)
  217. {
  218. hr = ResultFromScode(E_OUTOFMEMORY);
  219. goto err;
  220. }
  221. m_cbAlloc = cb;
  222. m_pb = (LPBYTE)pv;
  223. }
  224. if (cbCommit < m_cbCommitted)
  225. {
  226. // shrink the stream
  227. LPBYTE pb =m_pb;
  228. ULONG cb;
  229. // figure out the begining of the last page in the range not used
  230. pb += cbCommit;
  231. // figure out the size of the range being decommitted
  232. cb = m_cbCommitted - cbCommit;
  233. #ifndef MAC
  234. VirtualFree(pb, cb, MEM_DECOMMIT);
  235. #endif // !MAC
  236. // figure out what we have left committed
  237. m_cbCommitted = cbCommit;
  238. }
  239. else if (cbCommit > m_cbCommitted)
  240. {
  241. LPBYTE pb;
  242. // figure out how much memory to commit
  243. cbCommit = (cbDemand <= m_cbAlloc)
  244. ? ICeil(cbDemand, g_dwSysPageSize)
  245. : m_cbAlloc;
  246. if (cbCommit > m_cbCommitted)
  247. {
  248. #ifndef MAC
  249. if (!VirtualAlloc(m_pb, cbCommit, MEM_COMMIT, PAGE_READWRITE))
  250. {
  251. hr = ResultFromScode(E_OUTOFMEMORY);
  252. goto err;
  253. }
  254. #endif // !MAC
  255. }
  256. m_cbCommitted = cbCommit;
  257. // Wow, we've used all of memory, start up the disk
  258. if (cbDemand > m_cbAlloc)
  259. {
  260. ULARGE_INTEGER uliAlloc;
  261. // no stream? better create it now
  262. if (!m_pstm)
  263. {
  264. hr = CreateTempFileStream(&m_pstm);
  265. if (hr) goto err;
  266. }
  267. uliAlloc.LowPart = cbDemand - m_cbAlloc;
  268. uliAlloc.HighPart = 0;
  269. hr = m_pstm->SetSize(uliAlloc);
  270. if (hr) goto err;
  271. // if the current offset beyond the end of the memory allocation,
  272. // initialize the stream pointer correctly
  273. if (m_dwOffset > m_cbAlloc)
  274. {
  275. hr = SyncFileStream();
  276. if (hr) goto err;
  277. }
  278. }
  279. }
  280. m_cbSize = cbDemand;
  281. err:
  282. // Thread Safety
  283. LeaveCriticalSection(&m_cs);
  284. // Done
  285. return hr;
  286. }
  287. // --------------------------------------------------------------------------------
  288. // CVirtualStream::QueryStat
  289. // --------------------------------------------------------------------------------
  290. STDMETHODIMP CVirtualStream::Stat(STATSTG *pStat, DWORD grfStatFlag)
  291. {
  292. // Invalid Arg
  293. if (NULL == pStat)
  294. return TrapError(E_INVALIDARG);
  295. // Fill pStat
  296. pStat->type = STGTY_STREAM;
  297. pStat->cbSize.HighPart = 0;
  298. pStat->cbSize.LowPart = m_cbSize;
  299. // Done
  300. return S_OK;
  301. }
  302. // --------------------------------------------------------------------------------
  303. // CVirtualStream::QueryStat
  304. // --------------------------------------------------------------------------------
  305. void CVirtualStream::QueryStat(ULARGE_INTEGER *puliOffset, ULARGE_INTEGER *pulSize)
  306. {
  307. #ifdef MAC
  308. if (puliOffset)
  309. ULISet32(*puliOffset, m_dwOffset);
  310. if (pulSize)
  311. ULISet32(*pulSize, m_cbSize);
  312. #else // !MAC
  313. if (puliOffset)
  314. puliOffset->QuadPart = (LONGLONG)m_dwOffset;
  315. if (pulSize)
  316. pulSize->QuadPart = (LONGLONG)m_cbSize;
  317. #endif // MAC
  318. }
  319. // --------------------------------------------------------------------------------
  320. // CVirtualStream::Seek
  321. // --------------------------------------------------------------------------------
  322. STDMETHODIMP CVirtualStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  323. {
  324. // Locals
  325. HRESULT hr = ResultFromScode(S_OK);
  326. BOOL fForward;
  327. ULONG ulOffset;
  328. #ifdef MAC
  329. ULONG llCur;
  330. #else // !MAC
  331. LONGLONG llCur;
  332. #endif // MAC
  333. // Thread Safety
  334. EnterCriticalSection(&m_cs);
  335. // look for starting position
  336. if (dwOrigin == STREAM_SEEK_CUR)
  337. llCur = m_dwOffset;
  338. else if (dwOrigin == STREAM_SEEK_END)
  339. llCur = m_cbSize;
  340. else
  341. llCur = 0;
  342. #ifdef MAC
  343. Assert(0 == dlibMove.HighPart);
  344. llCur += dlibMove.LowPart;
  345. #else // !MAC
  346. llCur += dlibMove.QuadPart;
  347. #endif // MAC
  348. // limit to 4 Gig
  349. if (llCur > 0xFFFFFFFF)
  350. goto seekerr;
  351. // if we have a stream and
  352. // we are currently in the file stream or the new seek seeks into the
  353. // stream and the seek will not grow the stream, reseek in the stream
  354. if ( m_pstm
  355. && ( (m_dwOffset > m_cbAlloc)
  356. || (llCur > m_cbAlloc))
  357. && (llCur <= m_cbSize))
  358. {
  359. LARGE_INTEGER li;
  360. #ifdef MAC
  361. LISet32(li ,llCur < m_cbAlloc ? 0 : llCur - m_cbAlloc);
  362. #else // !MAC
  363. li.QuadPart = llCur < m_cbAlloc ? 0 : llCur - m_cbAlloc;
  364. #endif // MAC
  365. hr = m_pstm->Seek(li, STREAM_SEEK_SET, NULL);
  366. if (hr)
  367. {
  368. m_fFileErr = TRUE;
  369. goto err;
  370. }
  371. }
  372. m_dwOffset = (ULONG)llCur;
  373. if (plibNewPosition)
  374. #ifdef MAC
  375. LISet32(*plibNewPosition, llCur);
  376. #else // !MAC
  377. plibNewPosition->QuadPart = llCur;
  378. #endif // MAC
  379. err:
  380. // Thread Safety
  381. LeaveCriticalSection(&m_cs);
  382. return hr;
  383. seekerr:
  384. hr = ResultFromScode(STG_E_MEDIUMFULL);
  385. goto err;
  386. // Done
  387. }
  388. // --------------------------------------------------------------------------------
  389. // CVirtualStream::Write
  390. // --------------------------------------------------------------------------------
  391. #ifndef WIN16
  392. STDMETHODIMP CVirtualStream::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
  393. #else
  394. STDMETHODIMP CVirtualStream::Write(const void HUGEP *pv, ULONG cb, ULONG *pcbWritten)
  395. #endif // !WIN16
  396. {
  397. // Locals
  398. HRESULT hr = ResultFromScode(S_OK);
  399. ULONG cbNew;
  400. ULONG cbWrite = 0;
  401. // Thread Safety
  402. EnterCriticalSection(&m_cs);
  403. // figure out where we'll end up
  404. cbNew = cb + m_dwOffset;
  405. // make sure that we won't wrap
  406. if (cbNew < m_dwOffset)
  407. goto stmfull;
  408. // if that is past the end of the stream, make more stream
  409. if (cbNew > m_cbSize)
  410. {
  411. ULARGE_INTEGER uli = {cbNew, 0};
  412. hr = SetSize(uli);
  413. if (hr) goto err;
  414. }
  415. // figure out what we're putting into memory
  416. if (m_dwOffset < m_cbCommitted)
  417. {
  418. cbWrite = min(cb, m_cbCommitted - m_dwOffset);
  419. // copy the memory stuff
  420. CopyMemory(m_pb + m_dwOffset, (LPBYTE)pv, cbWrite);
  421. }
  422. // if we still have stuff to write, dump to the file
  423. if (cbWrite != cb)
  424. {
  425. ULONG cbWritten;
  426. Assert(m_pstm);
  427. #ifdef DEBUG
  428. LARGE_INTEGER li = {0, 0};
  429. ULARGE_INTEGER uli = {0, 0};
  430. if (!m_pstm->Seek(li, STREAM_SEEK_CUR, &uli))
  431. #ifdef MAC
  432. Assert(0 == uli.HighPart);
  433. Assert(((m_dwOffset + cbWrite) - m_cbAlloc) == uli.LowPart);
  434. #else // !MAC
  435. Assert(((m_dwOffset + cbWrite) - m_cbAlloc) == uli.QuadPart);
  436. #endif // MAC
  437. #endif
  438. hr = m_pstm->Write(((LPBYTE)pv) + cbWrite, cb - cbWrite, &cbWritten);
  439. if (hr)
  440. {
  441. m_fFileErr = TRUE;
  442. goto err;
  443. }
  444. cbWrite += cbWritten;
  445. }
  446. m_dwOffset += cbWrite;
  447. if (pcbWritten)
  448. *pcbWritten = cbWrite;
  449. err:
  450. // Thread Safety
  451. LeaveCriticalSection(&m_cs);
  452. // Done
  453. return hr;
  454. stmfull:
  455. hr = ResultFromScode(STG_E_MEDIUMFULL);
  456. goto err;
  457. }
  458. STDMETHODIMP CVirtualStream::CopyTo(LPSTREAM pstmDst,
  459. ULARGE_INTEGER uli,
  460. ULARGE_INTEGER* puliRead,
  461. ULARGE_INTEGER* puliWritten)
  462. {
  463. HRESULT hr = 0;
  464. UINT cbBuf;
  465. ULONG cbRemain;
  466. ULONG cbReadMem = 0;
  467. ULONG cbWriteMem = 0;
  468. #ifdef MAC
  469. ULARGE_INTEGER uliRead = {0, 0};
  470. ULARGE_INTEGER uliWritten = {0, 0};
  471. #else // !MAC
  472. ULARGE_INTEGER uliRead = {0};
  473. ULARGE_INTEGER uliWritten = {0};
  474. #endif // MAC
  475. // Initialize the outgoing params
  476. if (puliRead)
  477. {
  478. ULISet32((*puliRead), 0);
  479. }
  480. if (puliWritten)
  481. {
  482. ULISet32((*puliWritten), 0);
  483. }
  484. if (!m_cbSize)
  485. goto err;
  486. // if the request is greater than the max ULONG, bring the request down to
  487. // the max ULONG
  488. if (uli.HighPart)
  489. #ifdef MAC
  490. ULISet32(uli, ULONG_MAX);
  491. #else // !MAC
  492. uli.QuadPart = 0xFFFFFFFF;
  493. #endif // MAC
  494. if (m_dwOffset < m_cbCommitted)
  495. {
  496. if (m_cbSize < m_cbAlloc)
  497. cbReadMem = (ULONG)min(uli.LowPart, m_cbSize - m_dwOffset);
  498. else
  499. cbReadMem = (ULONG)min(uli.LowPart, m_cbAlloc - m_dwOffset);
  500. hr = pstmDst->Write(m_pb + m_dwOffset, cbReadMem, &cbWriteMem);
  501. if (!hr && (cbReadMem != cbWriteMem))
  502. hr = ResultFromScode(E_OUTOFMEMORY);
  503. if (hr) goto err;
  504. uli.LowPart -= cbReadMem;
  505. }
  506. // if we didn't get it all from memory and there is information in
  507. // the file stream, read from the file stream
  508. if ( uli.LowPart
  509. && (m_cbSize > m_cbAlloc)
  510. && m_pstm)
  511. {
  512. hr = m_pstm->CopyTo(pstmDst, uli, &uliRead, &uliWritten);
  513. if (hr)
  514. {
  515. m_fFileErr = TRUE;
  516. goto err;
  517. }
  518. }
  519. m_dwOffset += uliRead.LowPart + cbReadMem;
  520. // Total cbReadMem and ulRead because we have them both.
  521. #ifdef MAC
  522. if (puliRead)
  523. {
  524. ULISet32(*puliRead, uliRead.LowPart);
  525. Assert(INT_MAX - cbReadMem >= puliRead->LowPart);
  526. puliRead->LowPart += cbReadMem;
  527. }
  528. if (puliWritten)
  529. puliWritten->LowPart = uliWritten.LowPart + cbWriteMem;
  530. #else // !MAC
  531. if (puliRead)
  532. puliRead->QuadPart = cbReadMem + uliRead.LowPart;
  533. // Add in cbWriteMem because any written from the file stream was
  534. // already set
  535. if (puliWritten)
  536. puliWritten->QuadPart = uliWritten.LowPart + cbWriteMem;
  537. #endif // MAC
  538. err:
  539. return (hr);
  540. }