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.

1469 lines
40 KiB

  1. //+============================================================================
  2. //
  3. // File: nffmstm.cxx
  4. //
  5. // This file provides the NFF (NTFS Flat File) IMappedStream implementation.
  6. //
  7. // History:
  8. // 5/6/98 MikeHill
  9. // - Misc dbg cleanup.
  10. //
  11. //+============================================================================
  12. #include <pch.cxx>
  13. CNFFMappedStream::~CNFFMappedStream()
  14. {
  15. HRESULT hr = S_OK;
  16. // If the update stream has the latest data, rename it over the original
  17. // stream. Ordinarily this replace call will create a new update stream.
  18. // But since we're going away, tell it not to bother.
  19. // Errors are ignored here because there's no way to return them.
  20. // If the caller wishes to avoid this, they should call Flush first.
  21. if( NULL != _pstmUpdate )
  22. {
  23. ReplaceOriginalWithUpdate( DONT_CREATE_NEW_UPDATE_STREAM );
  24. DfpVerify( 0 == RELEASE_INTERFACE(_pstmUpdate) );
  25. }
  26. // Just to be safe, free the mapping buffer (it should have
  27. // already been freed).
  28. DfpAssert( NULL == _pbMappedStream );
  29. CoTaskMemFree( _pbMappedStream );
  30. // If we've got the global reserved buffer locked,
  31. // free it now.
  32. if (_fLowMem)
  33. g_ReservedMemory.UnlockMemory();
  34. }
  35. HRESULT
  36. CNFFMappedStream::QueryInterface( REFIID riid, void**ppvObject )
  37. {
  38. return( _pnffstm->QueryInterface( riid, ppvObject ));
  39. }
  40. ULONG
  41. CNFFMappedStream::AddRef()
  42. {
  43. return( _pnffstm->AddRef() );
  44. }
  45. ULONG
  46. CNFFMappedStream::Release()
  47. {
  48. return( _pnffstm->Release() );
  49. }
  50. //+----------------------------------------------------------------------------
  51. //
  52. // Method: CNFFMappedStream::Open (IMappedStream)
  53. //
  54. //+----------------------------------------------------------------------------
  55. VOID
  56. CNFFMappedStream::Open( IN VOID *powner, OUT LONG *phr )
  57. {
  58. nffITrace( "CNFFMappedStream::Open" );
  59. VOID *pv = NULL;
  60. HRESULT sc=S_OK;
  61. BOOL fUsingLatestStream = FALSE;
  62. DfpAssert(!_fLowMem);
  63. _pnffstm->Lock( INFINITE );
  64. nffChk( _pnffstm->CheckReverted() );
  65. // If the previous open crashed during a flush, roll forward to the
  66. // updated copy. If we're only open for read access, then this will
  67. // just set _fUpdateStreamHasLatest so that we'll know to process
  68. // reads from that stream.
  69. nffChk( RollForwardIfNecessary() );
  70. BeginUsingLatestStream();
  71. fUsingLatestStream = TRUE;
  72. // If given a pointer to the owner of this mapped stream,
  73. // save it. This could be NULL (i.e., when called from
  74. // ReOpen).
  75. if( NULL != powner )
  76. _pMappedStreamOwner = powner;
  77. // If we haven't already read the stream, read it now.
  78. if( NULL == _pbMappedStream )
  79. {
  80. BY_HANDLE_FILE_INFORMATION fileinfo;
  81. DfpAssert( INVALID_HANDLE_VALUE != _pnffstm->GetFileHandle() );
  82. DfpAssert( 0 == _cbMappedStream );
  83. DfpAssert( 0 == _cbMappedStreamActual);
  84. // Get and validate the size of the file
  85. if( !GetFileInformationByHandle( _pnffstm->GetFileHandle(), &fileinfo ))
  86. {
  87. nffErr( EH_Err, LAST_SCODE );
  88. }
  89. else if( 0 != fileinfo.nFileSizeHigh
  90. || CBMAXPROPSETSTREAM < fileinfo.nFileSizeLow )
  91. {
  92. nffErr( EH_Err, STG_E_INVALIDHEADER );
  93. }
  94. _cbMappedStream = _cbMappedStreamActual = fileinfo.nFileSizeLow;
  95. // Allocate a buffer to hold the Stream. If there isn't sufficient
  96. // memory in the system, lock and get the reserved buffer. In the
  97. // end, 'pv' points to the appropriate buffer.
  98. #if DBG
  99. pv = _fSimulateLowMem ? NULL : CoTaskMemAlloc( _cbMappedStreamActual );
  100. #else
  101. pv = CoTaskMemAlloc( _cbMappedStreamActual );
  102. #endif
  103. if( NULL == pv )
  104. {
  105. // could block until previous property call completes
  106. pv = g_ReservedMemory.LockMemory();
  107. if( NULL == pv )
  108. nffErr( EH_Err, E_OUTOFMEMORY );
  109. _fLowMem = TRUE;
  110. }
  111. _pbMappedStream = (BYTE*) pv;
  112. // Read in the file.
  113. if( 0 != _cbMappedStreamActual )
  114. {
  115. ULARGE_INTEGER ulOffset;
  116. ulOffset.QuadPart = 0;
  117. if( FAILED(_pnffstm->SyncReadAtFile( ulOffset, _pbMappedStream,
  118. _cbMappedStreamActual, &_cbMappedStream)))
  119. {
  120. nffErr( EH_Err, LAST_SCODE );
  121. }
  122. // Ensure that we got all the bytes we requested.
  123. if( _cbMappedStream != _cbMappedStreamActual )
  124. {
  125. propDbg((DEBTRACE_ERROR,
  126. "CMappedStreamOnHFile(%08X)::Open bytes-read (%lu) doesn't match bytes-requested (%lu)\n",
  127. this, _cbMappedStream, _cbMappedStreamActual ));
  128. nffErr( EH_Err, STG_E_INVALIDHEADER );
  129. }
  130. }
  131. #if BIGENDIAN==1
  132. // Notify our owner that we've read in new data.
  133. if( _pMappedStreamOwner != NULL && 0 != _cbMappedStream )
  134. {
  135. nffChk( PrOnMappedStreamEvent( _pMappedStreamOwner, _pbMappedStream, _cbMappedStream ) );
  136. }
  137. #endif
  138. } // if( NULL == _pbMappedStream )
  139. // ----
  140. // Exit
  141. // ----
  142. EH_Err:
  143. if( fUsingLatestStream )
  144. EndUsingLatestStream();
  145. // If there was an error, free any memory we have.
  146. if( FAILED(sc) )
  147. {
  148. propDbg((DEB_ERROR, "IMappedStream::CNtfsStream(%08X)::Open exception returns %08X\n", this, *phr));
  149. if (_fLowMem)
  150. g_ReservedMemory.UnlockMemory();
  151. else
  152. CoTaskMemFree(pv);
  153. _pbMappedStream = NULL;
  154. _cbMappedStream = _cbMappedStreamActual = 0;
  155. _fLowMem = FALSE;
  156. }
  157. _pnffstm->Unlock();
  158. *phr = sc;
  159. return;
  160. }
  161. //+-------------------------------------------------------------------
  162. //
  163. // Member: CNFFMappedStream::Flush (IMappedStream)
  164. //
  165. //--------------------------------------------------------------------
  166. VOID CNFFMappedStream::Flush(OUT LONG *phr)
  167. {
  168. nffITrace( "CNFFMappedStream::Flush" );
  169. HRESULT sc=S_OK;
  170. BOOL fUsingLatestStream = FALSE;
  171. _pnffstm->Lock( INFINITE );;
  172. BeginUsingLatestStream();
  173. fUsingLatestStream = TRUE;
  174. nffChk( _pnffstm->CheckReverted() );
  175. if( !IsWriteable() )
  176. nffErr( EH_Err, STG_E_ACCESSDENIED );
  177. // If the IMappedStream is being used, write it out to the
  178. // underlying file.
  179. if( NULL != _pbMappedStream )
  180. nffChk( WriteMappedStream() );
  181. // Commit the Stream.
  182. if( !FlushFileBuffers( _pnffstm->GetFileHandle() ))
  183. nffErr( EH_Err, LAST_SCODE );
  184. EndUsingLatestStream();
  185. fUsingLatestStream = FALSE;
  186. nffChk( ReplaceOriginalWithUpdate( CREATE_NEW_UPDATE_STREAM ));
  187. sc = S_OK;
  188. EH_Err:
  189. if( fUsingLatestStream )
  190. EndUsingLatestStream();
  191. _pnffstm->Unlock();
  192. *phr = sc;
  193. return;
  194. }
  195. //+-------------------------------------------------------------------
  196. //
  197. // Member: IMappedStream::Close
  198. //
  199. // Synopsis: Close the mapped stream by writing out
  200. // the mapping buffer and then freeing it.
  201. // Errors are ignored, so if the caller wants an
  202. // opportunity to recover from an error, they should
  203. // call Flush before calling Close.
  204. //
  205. // Arguments: [LONG*] phr
  206. // An HRESULT error code.
  207. //
  208. // Returns: None.
  209. //
  210. //--------------------------------------------------------------------
  211. VOID CNFFMappedStream::Close(OUT LONG *phr)
  212. {
  213. nffITrace( "CNFFMappedStream::Close" );
  214. HRESULT sc=S_OK;
  215. _pnffstm->Lock( INFINITE );
  216. // So watch out for multiple closes.
  217. sc = _pnffstm->CheckReverted();
  218. // If we are already closed then return immediatly (but don't error)
  219. if( STG_E_REVERTED == sc )
  220. {
  221. sc = S_OK;
  222. goto EH_Err;
  223. }
  224. // Report any real errors.
  225. if( FAILED( sc ) )
  226. nffErr( EH_Err, sc );
  227. // Write the changes. We don't need to Commit them,
  228. // they will be implicitely committed when the
  229. // Stream is Released.
  230. sc = WriteMappedStream();
  231. // Even if we fail the write, we must free the memory.
  232. // (PrClosePropertySet deletes everything whether or not
  233. // there was an error here, so we must free the memory.
  234. // There's no danger of this happenning due to out-of-
  235. // disk-space conditions, because the propset code
  236. // pre-allocates).
  237. CoTaskMemFree( _pbMappedStream );
  238. _pbMappedStream = NULL;
  239. // Re-zero the member data.
  240. InitMappedStreamMembers();
  241. sc = S_OK;
  242. EH_Err:
  243. _pnffstm->Unlock();
  244. *phr = sc;
  245. return;
  246. }
  247. //+-------------------------------------------------------------------
  248. //
  249. // Member: CNFFMappedStream::ReOpen (IMappedStream)
  250. //
  251. //--------------------------------------------------------------------
  252. VOID
  253. CNFFMappedStream::ReOpen(IN OUT VOID **ppv, OUT LONG *phr)
  254. {
  255. nffITrace( "CNFFMappedStream::ReOpen" );
  256. HRESULT sc=S_OK;
  257. *ppv = NULL;
  258. _pnffstm->Lock( INFINITE );;
  259. nffChk( _pnffstm->CheckReverted() );
  260. this->Open(NULL, &sc);
  261. nffChk(sc);
  262. *ppv = _pbMappedStream;
  263. EH_Err:
  264. _pnffstm->Unlock();
  265. *phr = sc;
  266. return;
  267. }
  268. //+-------------------------------------------------------------------
  269. //
  270. // Member: CNFFMappedStream::Quiesce (IMappedStream)
  271. //
  272. //--------------------------------------------------------------------
  273. VOID CNFFMappedStream::Quiesce(VOID)
  274. {
  275. nffITrace( "CNFFMappedStream::Quiesce" );
  276. // Not necessary for this implemented
  277. }
  278. //+-------------------------------------------------------------------
  279. //
  280. // Member: CNFFMappedStream::Map (IMappedStream)
  281. //
  282. //--------------------------------------------------------------------
  283. VOID
  284. CNFFMappedStream::Map(IN BOOLEAN fCreate, OUT VOID **ppv)
  285. {
  286. nffITrace( "CNFFMappedStream::Map" );
  287. HRESULT sc;
  288. _pnffstm->Lock( INFINITE );;
  289. nffChk( _pnffstm->CheckReverted() );
  290. DfpAssert(_pbMappedStream != NULL);
  291. *ppv = _pbMappedStream;
  292. EH_Err:
  293. _pnffstm->Unlock();
  294. }
  295. //+-------------------------------------------------------------------
  296. //
  297. // Member: CNFFMappedStream::Unmap (IMappedStream)
  298. //
  299. //--------------------------------------------------------------------
  300. VOID
  301. CNFFMappedStream::Unmap(BOOLEAN fFlush, VOID **ppv)
  302. {
  303. nffITrace( "CNFFMappedStream::Unmap" );
  304. *ppv = NULL;
  305. }
  306. //+-------------------------------------------------------------------
  307. //
  308. // Member: CNFFMappedStream::WriteMappedStream (internal support for IMappedStream)
  309. //
  310. // Returns: S_OK if successful, S_FALSE if there was nothing to write.
  311. //
  312. //--------------------------------------------------------------------
  313. #define STACK_BYTES 16
  314. HRESULT
  315. CNFFMappedStream::WriteMappedStream()
  316. {
  317. nffITrace( "CNFFMappedStream::WriteMappedStream" );
  318. HRESULT sc = S_OK;
  319. ULONG cbWritten;
  320. BOOL fOwnerSignaled = FALSE;
  321. BOOL fUsingUpdateStream = FALSE;
  322. // We can return right away if there's nothing to write.
  323. // (_pbMappedStream may be NULL in the error path of our
  324. // caller).
  325. if (!IsModified() || NULL == _pbMappedStream )
  326. {
  327. propDbg((DEB_TRACE, "IMappedStream::CNtfsStream(%08X)::Flush returns with not-dirty\n", this));
  328. return S_FALSE;
  329. }
  330. // Put the update stream's handle into _pnffstm, so that we write out to it.
  331. BeginUsingUpdateStream();
  332. fUsingUpdateStream = TRUE;
  333. DfpAssert( INVALID_HANDLE_VALUE != _pnffstm->GetFileHandle() );
  334. #if BIGENDIAN==1
  335. // Notify our owner that we're about to perform a Write.
  336. nffChk( PrOnMappedStreamEvent( _powner, _pbMappedStream, _cbMappedStream ) );
  337. fOwnerSignaled = TRUE;
  338. #endif
  339. // Write out the mapping buffer (to the update stream).
  340. ULARGE_INTEGER ulOffset;
  341. ulOffset.QuadPart = 0;
  342. nffChk( _pnffstm->SyncWriteAtFile( ulOffset, _pbMappedStream,
  343. _cbMappedStream, &cbWritten ));
  344. if( cbWritten != _cbMappedStream )
  345. {
  346. propDbg((DEB_ERROR,
  347. "CMappedStreamOnHFile(%08X)::Write bytes-written (%lu) doesn't match bytes-requested (%lu)\n",
  348. this, cbWritten, _cbMappedStream ));
  349. sc = STG_E_INVALIDHEADER;
  350. goto EH_Err;
  351. }
  352. // If the buffer is shrinking, this is a good time to shrink the file.
  353. if (_cbMappedStream < _cbMappedStreamActual)
  354. {
  355. nffChk( _pnffstm->SetSize( static_cast<CULargeInteger>(_cbMappedStream) ) );
  356. _cbMappedStreamActual = _cbMappedStream;
  357. }
  358. if( _fStreamRenameSupported )
  359. {
  360. // We wrote the data to the update stream. So flag that it now
  361. // has the latest data.
  362. _fUpdateStreamHasLatest = TRUE;
  363. DfpAssert( NULL != _pstmUpdate && INVALID_HANDLE_VALUE != _pstmUpdate->GetFileHandle() );
  364. }
  365. // ----
  366. // Exit
  367. // ----
  368. EH_Err:
  369. #if BIGENDIAN==1
  370. // Notify our owner that we're done with the Write. We do this
  371. // whether or not there was an error, because _pbMappedStream is
  372. // not modified, and therefore intact even in the error path.
  373. if( fOwnerSignaled )
  374. {
  375. DfpVerify( PrOnMappedStreamEvent( _powner,
  376. _pbMappedStream, _cbMappedStream ) );
  377. }
  378. #endif
  379. if( fUsingUpdateStream )
  380. EndUsingUpdateStream();
  381. if (sc == S_OK || sc == STG_E_REVERTED)
  382. {
  383. _fMappedStreamDirty = FALSE;
  384. }
  385. propDbg(( DbgFlag(sc,DEB_ITRACE), "CNtfsStream(%08X)::Write %s returns hr=%08X\n",
  386. this, sc != S_OK ? "exception" : "", sc));
  387. return sc;
  388. }
  389. //+-------------------------------------------------------------------
  390. //
  391. // Member: CNFFMappedStream::GetSize (IMappedStream)
  392. //
  393. //--------------------------------------------------------------------
  394. ULONG CNFFMappedStream::GetSize(OUT LONG *phr)
  395. {
  396. nffITrace( "CNFFMappedStream::GetSize" );
  397. HRESULT sc=S_OK;
  398. _pnffstm->Lock( INFINITE );;
  399. nffChk( _pnffstm->CheckReverted() );
  400. // If necessary, open the Stream.
  401. if( NULL == _pbMappedStream )
  402. {
  403. this->Open(NULL, &sc);
  404. }
  405. if( SUCCEEDED(sc) )
  406. {
  407. DfpAssert( NULL != _pbMappedStream );
  408. }
  409. // Return the size of the mapped stream. If there was an
  410. // Open error, it will be zero, and *phr will be set.
  411. EH_Err:
  412. _pnffstm->Unlock();
  413. *phr = sc;
  414. return _cbMappedStream;
  415. }
  416. //+-------------------------------------------------------------------
  417. //
  418. // Member: CNFFMappedStream::InitMappedStreamMembers
  419. //
  420. //--------------------------------------------------------------------
  421. void
  422. CNFFMappedStream::InitMappedStreamMembers()
  423. {
  424. nffITrace( "CNFFMappedStream::InitMappedStreamMembers" );
  425. _pbMappedStream = NULL;
  426. _cbMappedStream = 0;
  427. _cbMappedStreamActual = 0;
  428. _pMappedStreamOwner = NULL;
  429. _fLowMem = FALSE;
  430. _fMappedStreamDirty = FALSE;
  431. _fCheckedForRollForward = FALSE;
  432. _fStreamRenameSupported = FALSE;
  433. _cUpdateStreamInUse = _cLatestStreamInUse = 0;
  434. }
  435. //+-------------------------------------------------------------------
  436. //
  437. // Member: CNFFMappedStream::SetSize (IMappedStream)
  438. //
  439. //--------------------------------------------------------------------
  440. VOID
  441. CNFFMappedStream::SetSize(IN ULONG cb,
  442. IN BOOLEAN fPersistent,
  443. IN OUT VOID **ppv, OUT LONG *phr)
  444. {
  445. nffITrace( "CNFFMappedStream::SetSize" );
  446. BYTE *pv;
  447. HRESULT &sc = *phr;
  448. BOOL fUsingUpdateStream = FALSE, fUsingLatestStream = FALSE;
  449. DfpAssert(cb != 0);
  450. sc = S_OK;
  451. _pnffstm->Lock( INFINITE );;
  452. nffChk( _pnffstm->CheckReverted() );
  453. if( CBMAXPROPSETSTREAM < cb )
  454. nffErr( EH_Err, STG_E_MEDIUMFULL );
  455. if( fPersistent )
  456. {
  457. nffChk( CreateUpdateStreamIfNecessary() );
  458. BeginUsingUpdateStream();
  459. fUsingUpdateStream = TRUE;
  460. }
  461. else
  462. {
  463. BeginUsingLatestStream();
  464. fUsingLatestStream = TRUE;
  465. }
  466. // if we are growing the data, we should grow the file
  467. if( fPersistent && cb > _cbMappedStreamActual )
  468. {
  469. nffChk( _pnffstm->SetFileSize( CULargeInteger(cb) ) );
  470. _cbMappedStreamActual = cb;
  471. }
  472. // We only get here if we either (1) didn't want to grow the
  473. // underlying stream, or (2) we successfully grew the underlying stream.
  474. // Re-size the buffer to the size specified in cb.
  475. if( _fLowMem )
  476. {
  477. // If we want to grow the buffer In low-memory conditions,
  478. // no realloc is necessary, because
  479. // _pbMappedStream is already large enough for the largest
  480. // property set.
  481. if( NULL != ppv )
  482. *ppv = _pbMappedStream;
  483. }
  484. else if ( cb != _cbMappedStream )
  485. {
  486. // We must re-alloc the buffer.
  487. #if DBG
  488. pv = _fSimulateLowMem ? NULL : (PBYTE) CoTaskMemRealloc( _pbMappedStream, cb );
  489. #else
  490. pv = (PBYTE)CoTaskMemRealloc( _pbMappedStream, cb );
  491. #endif
  492. if ((pv == NULL) )
  493. {
  494. // allocation failed: we need to try using a backup mechanism for
  495. // more memory.
  496. // copy the data to the global reserved chunk... we will wait until
  497. // someone else has released it. it will be released on the way out
  498. // of the property code.
  499. pv = g_ReservedMemory.LockMemory();
  500. if( NULL == pv )
  501. nffErr( EH_Err, E_OUTOFMEMORY );
  502. _fLowMem = TRUE;
  503. if( NULL != _pbMappedStream )
  504. {
  505. memcpy( pv, _pbMappedStream, _cbMappedStream );
  506. }
  507. CoTaskMemFree( _pbMappedStream );
  508. }
  509. _pbMappedStream = pv;
  510. if( NULL != ppv )
  511. *ppv = pv;
  512. }
  513. _cbMappedStream = cb;
  514. // ----
  515. // Exit
  516. // ----
  517. EH_Err:
  518. if( fUsingUpdateStream )
  519. {
  520. DfpAssert( !fUsingLatestStream );
  521. EndUsingUpdateStream();
  522. }
  523. else if( fUsingLatestStream )
  524. {
  525. EndUsingLatestStream();
  526. }
  527. _pnffstm->Unlock();
  528. if( FAILED(*phr) )
  529. {
  530. propDbg((DbgFlag(*phr,DEB_ITRACE), "IMappedStream::CNtfsStream(%08X)::SetSize %s returns hr=%08X\n",
  531. this, *phr != S_OK ? "exception" : "", *phr));
  532. }
  533. }
  534. //+-------------------------------------------------------------------
  535. //
  536. // Member: CNFFMappedStream::Lock (IMappedStream)
  537. //
  538. //--------------------------------------------------------------------
  539. NTSTATUS
  540. CNFFMappedStream::Lock(IN BOOLEAN fExclusive)
  541. {
  542. // Don't trace at this level. The noice is too great!
  543. //nffXTrace( "CNFFMappedStream::Lock");
  544. UNREFERENCED_PARM(fExclusive);
  545. _pnffstm->Lock( INFINITE );
  546. return(STATUS_SUCCESS);
  547. }
  548. //+-------------------------------------------------------------------
  549. //
  550. // Member: CNFFMappedStream::Unlock (IMappedStream)
  551. //
  552. //--------------------------------------------------------------------
  553. // Should we unlock even if there's an error?
  554. NTSTATUS
  555. CNFFMappedStream::Unlock(VOID)
  556. {
  557. // Don't trace at this level. The noise is too great!
  558. //nffXTrace( "CNFFMappedStream::Unlock");
  559. // if at the end of the properties set/get call we have the low
  560. // memory region locked, we flush to disk.
  561. HRESULT sc = S_OK;
  562. if (_fLowMem)
  563. {
  564. Flush(&sc);
  565. g_ReservedMemory.UnlockMemory();
  566. _pbMappedStream = NULL;
  567. _cbMappedStream = _cbMappedStreamActual = 0;
  568. _fLowMem = FALSE;
  569. propDbg((DEB_PROP_INFO, "CMappedStreamOnHFile(%08X):Unlock low-mem returns NTSTATUS=%08X\n",
  570. this, sc));
  571. }
  572. _pnffstm->Unlock();
  573. return(sc);
  574. }
  575. //+-------------------------------------------------------------------
  576. //
  577. // Member: Unused methods by this IMappedStream implementation:
  578. // QuerySecurity, IsWritable, GetHandle, QueryTimeStamps,
  579. // and QueryModifyTime.
  580. //
  581. //--------------------------------------------------------------------
  582. BOOLEAN
  583. CNFFMappedStream::QuerySecurity(OUT ULONG *pul) const
  584. {
  585. nffITrace( "CNFFMappedStream::QuerySecurity" );
  586. return(FALSE);
  587. }
  588. BOOLEAN
  589. CNFFMappedStream::IsWriteable() const
  590. {
  591. nffITrace( "CNFFMappedStream::IsWriteable" );
  592. return( (BOOLEAN) _pnffstm->IsWriteable() );
  593. }
  594. HANDLE
  595. CNFFMappedStream::GetHandle(VOID) const
  596. {
  597. nffITrace( "CNFFMappedStream::GetHandle" );
  598. return(INVALID_HANDLE_VALUE);
  599. }
  600. VOID
  601. CNFFMappedStream::QueryTimeStamps(OUT STATPROPSETSTG *pspss, BOOLEAN fNonSimple) const
  602. {
  603. nffITrace( "CNFFMappedStream::QueryTimeStamps" );
  604. }
  605. BOOLEAN
  606. CNFFMappedStream::QueryModifyTime(OUT LONGLONG *pll) const
  607. {
  608. nffITrace( "CNFFMappedStream::QueryModifyTime" );
  609. return(FALSE);
  610. }
  611. //+-------------------------------------------------------------------
  612. //
  613. // Member: CNFFMappedStream::SetModified/IsModified (IMappedStream)
  614. //
  615. //--------------------------------------------------------------------
  616. VOID
  617. CNFFMappedStream::SetModified(OUT LONG *phr)
  618. {
  619. nffITrace( "CNFFMappedStream::SetModified" );
  620. HRESULT &sc = *phr;
  621. _pnffstm->Lock( INFINITE );;
  622. nffChk( _pnffstm->CheckReverted() );
  623. nffChk( CreateUpdateStreamIfNecessary() );
  624. _fMappedStreamDirty = TRUE;
  625. sc = S_OK;
  626. EH_Err:
  627. _pnffstm->Unlock();
  628. }
  629. BOOLEAN
  630. CNFFMappedStream::IsModified(VOID) const
  631. {
  632. nffITrace( "CNFFMappedStream::IsModified" );
  633. return _fMappedStreamDirty;
  634. }
  635. //+-------------------------------------------------------------------
  636. //
  637. // Member: ImappedStream::IsNtMappedStream/SetChangePending
  638. //
  639. // Synopsis: Debug routines.
  640. //
  641. //--------------------------------------------------------------------
  642. #if DBGPROP
  643. BOOLEAN
  644. CNFFMappedStream::IsNtMappedStream(VOID) const
  645. {
  646. nffITrace( "CNFFMappedStream::IsNtMappedStream" );
  647. return(TRUE);
  648. }
  649. #endif
  650. #if DBGPROP
  651. BOOLEAN
  652. CNFFMappedStream::SetChangePending(BOOLEAN f)
  653. {
  654. nffITrace( "CNFFMappedStream::SetChangePending" );
  655. return(f);
  656. }
  657. #endif
  658. //
  659. // CNFFMappedStream::BeginUsingLatestStream/EndUsingLatestStream
  660. //
  661. // These routines are similar to Begin/EndUsing*Update*Stream,
  662. // except that they honor the _fUpdateStreamHasLatest flag.
  663. // Thus, if the original stream has the latest data, then this
  664. // routine will do nothing.
  665. //
  666. void
  667. CNFFMappedStream::BeginUsingLatestStream()
  668. {
  669. if( _fUpdateStreamHasLatest )
  670. {
  671. if( 0 == _cLatestStreamInUse++ )
  672. BeginUsingUpdateStream();
  673. }
  674. }
  675. void
  676. CNFFMappedStream::EndUsingLatestStream()
  677. {
  678. if( 0 != _cLatestStreamInUse )
  679. {
  680. EndUsingUpdateStream();
  681. _cLatestStreamInUse--;
  682. }
  683. DfpAssert( static_cast<USHORT>(-1) != _cLatestStreamInUse );
  684. }
  685. //
  686. // CNFFMappedStream::BeginUsingUpdateStream
  687. //
  688. // This is called when the update stream is to be used. It
  689. // does nothing, though, if we don't have an update stream
  690. // (e.g. if the file system doesn't support stream renames).
  691. // We increment the _cUpdateStreamInUse count, so that we can determine in
  692. // EndUsingUpdateStream when to swap the handles back.
  693. void
  694. CNFFMappedStream::BeginUsingUpdateStream()
  695. {
  696. if( NULL != _pstmUpdate
  697. &&
  698. INVALID_HANDLE_VALUE != _pstmUpdate->GetFileHandle()
  699. &&
  700. 0 == _cUpdateStreamInUse++ )
  701. {
  702. HANDLE hTemp = _pnffstm->_hFile;
  703. _pnffstm->_hFile = _pstmUpdate->_hFile;
  704. _pstmUpdate->_hFile = hTemp;
  705. }
  706. }
  707. //
  708. // CNFFMappedStream::EndUsingUpdateStream
  709. //
  710. // Decrement the _cUpdateStreamInUse count. And, if that puts
  711. // the count down to zero, swap the handles back.
  712. //
  713. void
  714. CNFFMappedStream::EndUsingUpdateStream()
  715. {
  716. if( 0 != _cUpdateStreamInUse
  717. &&
  718. 0 == --_cUpdateStreamInUse )
  719. {
  720. DfpAssert( NULL != _pstmUpdate && INVALID_HANDLE_VALUE != _pstmUpdate->GetFileHandle() );
  721. HANDLE hTemp = _pnffstm->_hFile;
  722. _pnffstm->_hFile = _pstmUpdate->_hFile;
  723. _pstmUpdate->_hFile = hTemp;
  724. }
  725. DfpAssert( static_cast<USHORT>(-1) != _cUpdateStreamInUse );
  726. }
  727. inline HRESULT
  728. CNFFMappedStream::CreateUpdateStreamIfNecessary()
  729. {
  730. if( _fStreamRenameSupported
  731. &&
  732. ( NULL == _pstmUpdate
  733. ||
  734. INVALID_HANDLE_VALUE == _pstmUpdate->GetFileHandle()
  735. )
  736. )
  737. {
  738. return( OpenUpdateStream( TRUE ));
  739. }
  740. else
  741. return( S_OK );
  742. }
  743. //+----------------------------------------------------------------------------
  744. //
  745. // Method: CNFFMAppedStream::RollForwardIfNecessary (non-interface method)
  746. //
  747. // In the open path, we look to see if there's a leftover update stream for
  748. // a previous open of the stream, which must have crashed during a write.
  749. // If we're opening for write, we fix the problem. Otherwise, we
  750. // just remember that we'll have to read out of the update stream.
  751. //
  752. // See the CNtfsStreamForPropStg class declaration for a description of
  753. // this transactioning.
  754. //
  755. //+----------------------------------------------------------------------------
  756. HRESULT
  757. CNFFMappedStream::RollForwardIfNecessary()
  758. {
  759. HRESULT hr = S_OK;
  760. BY_HANDLE_FILE_INFORMATION ByHandleFileInformation;
  761. // If we've already checked for this, then we needn't check again.
  762. if( _fCheckedForRollForward )
  763. goto Exit;
  764. // We also needn't do anything if we're creating, since that overwrites
  765. // any existing data anyway.
  766. if( !(STGM_CREATE & _pnffstm->_grfMode) )
  767. {
  768. // Get the size of the current stream.
  769. if( !GetFileInformationByHandle( _pnffstm->_hFile, &ByHandleFileInformation ))
  770. {
  771. hr = HRESULT_FROM_WIN32( GetLastError() );
  772. goto Exit;
  773. }
  774. // If the size is zero, then there might be an update
  775. // stream with the real data.
  776. if( 0 == ByHandleFileInformation.nFileSizeLow
  777. &&
  778. 0 == ByHandleFileInformation.nFileSizeHigh )
  779. {
  780. // See if there's an update stream
  781. hr = OpenUpdateStream( FALSE );
  782. if( SUCCEEDED(hr) )
  783. {
  784. // We have a zero-length main stream and an update stream,
  785. // so there must have been a crash in ReplaceOriginalWithUpdate,
  786. // after the truncation but before the NtSetInformationFile
  787. // (FileRenameInformation).
  788. // If this is a writable stream, rename the update stream
  789. // over the zero-length one. Otherwise, we'll just read from
  790. // the update stream.
  791. _fUpdateStreamHasLatest = TRUE;
  792. if( IsWriteable() )
  793. {
  794. hr = ReplaceOriginalWithUpdate( DONT_CREATE_NEW_UPDATE_STREAM );
  795. if( FAILED(hr) ) goto Exit;
  796. }
  797. }
  798. else if( STG_E_FILENOTFOUND == hr )
  799. // Ignore the case where there's no update stream. This happens
  800. // when the stream is created without STGM_CREATE set.
  801. hr = S_OK;
  802. else
  803. goto Exit;
  804. }
  805. } // if( !(STGM_CREATE & _grfMode) )
  806. // We don't need to check for this again.
  807. _fCheckedForRollForward = TRUE;
  808. Exit:
  809. return( hr );
  810. } // CNtfsStreamForPropStg::RollForwardIfNecessary
  811. //+----------------------------------------------------------------------------
  812. //
  813. // Method: CNtfsStreamForPropStg::ReplaceOriginalWithUpdate (internal method)
  814. //
  815. // This method renames the update stream over the original stream, then
  816. // creates a new update stream (with no data but properly sized). If, however,
  817. // the update stream doesn't have the latest data anyway, then this routine
  818. // noops.
  819. //
  820. // See the CNtfsStreamForPropStg class declaration for a description of
  821. // this transactioning.
  822. //
  823. //+----------------------------------------------------------------------------
  824. HRESULT
  825. CNFFMappedStream::ReplaceOriginalWithUpdate( enumCREATE_NEW_UPDATE_STREAM CreateNewUpdateStream )
  826. {
  827. HRESULT hr = S_OK;
  828. NTSTATUS status;
  829. FILE_END_OF_FILE_INFORMATION file_end_of_file_information;
  830. IO_STATUS_BLOCK io_status_block;
  831. // If the original stream already has the latest data, then
  832. // there's nothing to do.
  833. if( !_fUpdateStreamHasLatest )
  834. goto Exit;
  835. DfpAssert( NULL != _pstmUpdate );
  836. DfpAssert( 0 == _cUpdateStreamInUse );
  837. // We must write the update data all the way to disk.
  838. hr = _pstmUpdate->Flush();
  839. if( FAILED(hr) ) goto Exit;
  840. // Truncate the original stream so that it can be overwritten.
  841. // After this atomic operation, the update stream is considered
  842. // *the* stream (which is why we had to flush it above).
  843. file_end_of_file_information.EndOfFile = CLargeInteger(0);
  844. status = NtSetInformationFile( _pnffstm->_hFile, &io_status_block,
  845. &file_end_of_file_information,
  846. sizeof(file_end_of_file_information),
  847. FileEndOfFileInformation );
  848. if( !NT_SUCCESS(status) )
  849. {
  850. hr = NtStatusToScode(status);
  851. goto Exit;
  852. }
  853. NtClose( _pnffstm->_hFile );
  854. _pnffstm->_hFile = INVALID_HANDLE_VALUE;
  855. // Rename the updated stream over the original (now empty) stream.
  856. // This is guaranteed by NTFS to be atomic.
  857. hr = _pstmUpdate->Rename( _pnffstm->_pwcsName, TRUE );
  858. if( FAILED(hr) )
  859. {
  860. // Go into the reverted state and return the error.
  861. // The state is still in the update stream, and we'll
  862. // use it on the next open.
  863. // Bug 566706: Actually, this doesn't make sense to
  864. // return an error to the caller; we've already truncated
  865. // the original stream, so this transaction is committed, and
  866. // we shouldn't make them think otherwise.
  867. NtClose( _pstmUpdate->_hFile );
  868. _pstmUpdate->_hFile = INVALID_HANDLE_VALUE;
  869. goto Exit;
  870. }
  871. // Make the updated stream the master
  872. _pnffstm->_hFile = _pstmUpdate->_hFile;
  873. _pstmUpdate->_hFile = INVALID_HANDLE_VALUE;
  874. _fUpdateStreamHasLatest = FALSE;
  875. // Optionally create a new update stream.
  876. if( CREATE_NEW_UPDATE_STREAM == CreateNewUpdateStream )
  877. {
  878. // return an error if we cannot create the update stream
  879. hr = OpenUpdateStream( TRUE );
  880. if( FAILED(hr) ) goto Exit;
  881. }
  882. else
  883. DfpAssert( DONT_CREATE_NEW_UPDATE_STREAM == CreateNewUpdateStream );
  884. Exit:
  885. return( hr );
  886. } // CNFFMappedStream::ReplaceOriginalWithUpdate()
  887. //+----------------------------------------------------------------------------
  888. //
  889. // Method: CNFFMappedStream::OpenUpdateStream
  890. //
  891. // This method opens the update stream, to which stream updates are written.
  892. // This is necessary to provide a minimal level of transactioning.
  893. //
  894. // See the CNtfsStreamForPropStg class declaration for a description of
  895. // this transactioning.
  896. //
  897. //+----------------------------------------------------------------------------
  898. HRESULT
  899. CNFFMappedStream::OpenUpdateStream( BOOL fCreate )
  900. {
  901. HRESULT hr = S_OK;
  902. HANDLE hStream = INVALID_HANDLE_VALUE;
  903. CNtfsUpdateStreamName UpdateStreamName = _pnffstm->_pwcsName;
  904. // Open the NTFS stream
  905. hr = _pnffstm->_pnffstg->GetStreamHandle( &hStream,
  906. UpdateStreamName,
  907. _pnffstm->_grfMode | (fCreate ? STGM_CREATE : 0),
  908. fCreate );
  909. if( FAILED(hr) ) goto Exit;
  910. // If necessary, instantiate a CNtfsUpdateStreamForPropStg
  911. if( NULL == _pstmUpdate )
  912. {
  913. _pstmUpdate = new CNtfsUpdateStreamForPropStg( _pnffstm->_pnffstg, _pnffstm->_pBlockingLock );
  914. if( NULL == _pstmUpdate )
  915. {
  916. hr = E_OUTOFMEMORY;
  917. goto Exit;
  918. }
  919. }
  920. // Put the NTFS stream handle into the CNtfsUpdateStreamForPropStg
  921. hr = _pnffstm->_pnffstg->InitCNtfsStream( _pstmUpdate, hStream,
  922. _pnffstm->_grfMode | (fCreate ? STGM_CREATE : 0),
  923. UpdateStreamName );
  924. hStream = INVALID_HANDLE_VALUE; // ownership of the handle has changed
  925. if( FAILED(hr) ) goto Exit;
  926. // If we're creating the update stream, size it to match the size
  927. // of the original stream.
  928. if( fCreate )
  929. {
  930. ULONG ulSize = GetSize(&hr);
  931. if( FAILED(hr) ) goto Exit;
  932. hr = _pstmUpdate->SetSize( CULargeInteger(ulSize) );
  933. if( FAILED(hr) ) goto Exit;
  934. }
  935. Exit:
  936. if( INVALID_HANDLE_VALUE != hStream )
  937. NtClose( hStream );
  938. if( FAILED(hr) )
  939. {
  940. // If we were attempting a create but failed, then ensure the
  941. // update stream is gone.
  942. if( NULL != _pstmUpdate && fCreate )
  943. _pstmUpdate->Delete();
  944. DfpVerify( 0 == RELEASE_INTERFACE(_pstmUpdate) );
  945. }
  946. return( hr );
  947. } // CNFFMappedStream::OpenUpdateStream()
  948. //+----------------------------------------------------------------------------
  949. //
  950. // Method: CNFFMappedStream::Init (called by from CNtfsStream::Init)
  951. //
  952. // This method initializes the CNtfsStream, and checks the file system to
  953. // determine if we can support the update stream (for robustness). The
  954. // necessary file system support is stream renaming, which we use to provide
  955. // a minimal level of transactioning.
  956. //
  957. // See the CNtfsStreamForPropStg class declaration for a description of
  958. // this transactioning.
  959. //
  960. //+----------------------------------------------------------------------------
  961. HRESULT
  962. CNFFMappedStream::Init( HANDLE hFile )
  963. {
  964. HRESULT hr = S_OK;
  965. NTSTATUS status = STATUS_SUCCESS;
  966. FILE_FS_ATTRIBUTE_INFORMATION file_fs_attribute_information;
  967. IO_STATUS_BLOCK io_status_block;
  968. // Check to see if we'll be able to support stream renaming.
  969. if( NULL != _pnffstm->_pnffstg )
  970. {
  971. // We can at least see an IStorage for the file, so stream renaming
  972. // could potentially work, but we also need to query the file system
  973. // attributes to see if it actually supports it.
  974. status = NtQueryVolumeInformationFile( hFile, &io_status_block,
  975. &file_fs_attribute_information,
  976. sizeof(file_fs_attribute_information),
  977. FileFsAttributeInformation );
  978. // We should always get a buffer-overflow error here, because we don't
  979. // provide enough buffer for the file system name, but that's OK because
  980. // we don't need it (status_buffer_overflow is just a warning, so the rest
  981. // of the data is good).
  982. if( !NT_SUCCESS(status) && STATUS_BUFFER_OVERFLOW != status)
  983. {
  984. hr = NtStatusToScode(status);
  985. goto Exit;
  986. }
  987. // There's no attribute bit which says "supports stream rename". The best
  988. // we can do is look for another NTFS5 feature and make an inferrence.
  989. if( FILE_SUPPORTS_OBJECT_IDS & file_fs_attribute_information.FileSystemAttributes )
  990. _fStreamRenameSupported = TRUE;
  991. }
  992. Exit:
  993. return( hr );
  994. } // CNFFMappedStream::Init()
  995. HRESULT
  996. CNFFMappedStream::ShutDown()
  997. { // mikehill step
  998. HRESULT hr = S_OK;
  999. _pnffstm->Lock( INFINITE );
  1000. // Close the mapped stream
  1001. Close( &hr );
  1002. if( FAILED(hr) && STG_E_REVERTED != hr )
  1003. propDbg(( DEB_ERROR, "CNFFMappedStream(0x%x)::ShutDown failed call to CNtfsStream::Close (%08x)\n",
  1004. this, hr ));
  1005. // Overwrite the original stream with the update (if necessary),
  1006. // but don't bother to create a new update stream afterwards.
  1007. if( NULL != _pstmUpdate )
  1008. {
  1009. hr = ReplaceOriginalWithUpdate( DONT_CREATE_NEW_UPDATE_STREAM );
  1010. if( FAILED(hr) )
  1011. propDbg(( DEB_ERROR, "CNFFMappedStream(0x%x)::ShutDown failed call to ReplaceOriginalWithUpdate (%08x)\n",
  1012. this, hr ));
  1013. }
  1014. // Release the update stream.
  1015. if( NULL != _pstmUpdate )
  1016. DfpVerify( 0 == RELEASE_INTERFACE(_pstmUpdate) );
  1017. propDbg(( DbgFlag(hr,DEB_ITRACE), "CNFFMappedStream(0x%x)::ShutDown() returns %08x\n", this, hr ));
  1018. _pnffstm->Unlock();
  1019. return( hr );
  1020. } // CNFFMappedStream::ShutDown
  1021. void
  1022. CNFFMappedStream::Read( void *pv, ULONG ulOffset, ULONG *pcbCopy )
  1023. {
  1024. if( ulOffset > _cbMappedStream )
  1025. *pcbCopy = 0;
  1026. else if( *pcbCopy > _cbMappedStream - ulOffset )
  1027. *pcbCopy = _cbMappedStream - ulOffset;
  1028. memcpy( pv, &_pbMappedStream[ ulOffset ], *pcbCopy );
  1029. *pcbCopy = 0;
  1030. return;
  1031. }
  1032. void
  1033. CNFFMappedStream::Write( const void *pv, ULONG ulOffset, ULONG *pcbCopy )
  1034. {
  1035. if( ulOffset > _cbMappedStream )
  1036. *pcbCopy = 0;
  1037. else if( *pcbCopy + ulOffset > _cbMappedStream )
  1038. *pcbCopy = _cbMappedStream - ulOffset;
  1039. memcpy( &_pbMappedStream[ulOffset], pv, *pcbCopy );
  1040. *pcbCopy = 0;
  1041. return;
  1042. }
  1043. //+----------------------------------------------------------------------------
  1044. //
  1045. // Method: IStorageTest::UseNTFS4Streams (DBG only)
  1046. //
  1047. // This method can be used to disable the stream-renaming necessary for
  1048. // robust property sets. This emulates an NTFS4 volume.
  1049. //
  1050. //+----------------------------------------------------------------------------
  1051. #if DBG
  1052. HRESULT STDMETHODCALLTYPE
  1053. CNFFMappedStream::UseNTFS4Streams( BOOL fUseNTFS4Streams )
  1054. {
  1055. HRESULT hr = S_OK;
  1056. if( _fUpdateStreamHasLatest )
  1057. {
  1058. hr = STG_E_INVALIDPARAMETER;
  1059. propDbg(( DEB_ERROR, "CNtfsStreamForPropStg(0x%x)::UseNTFS4Streams(%s)"
  1060. "was called while an update stream was already in use\n",
  1061. this, fUseNTFS4Streams ? "True" : "False" ));
  1062. }
  1063. else if( fUseNTFS4Streams )
  1064. {
  1065. DfpVerify( 0 == RELEASE_INTERFACE(_pstmUpdate) );
  1066. _fStreamRenameSupported = FALSE;
  1067. }
  1068. else
  1069. {
  1070. // Shutting NTFS4streams off isn't implemented
  1071. hr = E_NOTIMPL;
  1072. }
  1073. return( hr );
  1074. } // CNFFMAppedStream::UseNTFS4Streams
  1075. #endif // #if DBG
  1076. #if DBG
  1077. HRESULT
  1078. CNFFMappedStream::GetFormatVersion( WORD *pw )
  1079. {
  1080. return( E_NOTIMPL );
  1081. }
  1082. #endif // #if DBG
  1083. #if DBG
  1084. HRESULT
  1085. CNFFMappedStream::SimulateLowMemory( BOOL fSimulate )
  1086. {
  1087. _fSimulateLowMem = fSimulate;
  1088. return( S_OK );
  1089. }
  1090. #endif // #if DBG
  1091. #if DBG
  1092. LONG
  1093. CNFFMappedStream::GetLockCount()
  1094. {
  1095. return( _pnffstm->GetLockCount() );
  1096. }
  1097. #endif // #if DBG
  1098. #if DBG
  1099. HRESULT
  1100. CNFFMappedStream::IsDirty()
  1101. {
  1102. return( _fMappedStreamDirty ? S_OK : S_FALSE );
  1103. }
  1104. #endif // #if DBG
  1105. //+----------------------------------------------------------------------------
  1106. //
  1107. // Method: CNtfsUpdateStreamForPropStg::ShutDown (overrides CNtfsStream)
  1108. //
  1109. // Override so that we can remove this stream from the linked-list, but
  1110. // not do a flush. See the CNtfsStreamForPropStg class declaration for
  1111. // more information on this class.
  1112. //
  1113. //+----------------------------------------------------------------------------
  1114. HRESULT
  1115. CNtfsUpdateStreamForPropStg::ShutDown()
  1116. {
  1117. RemoveSelfFromList();
  1118. return( S_OK );
  1119. } // CNtfsUpdateStreamForPropStg::ShutDown