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.

1572 lines
39 KiB

  1. //+============================================================================
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1998.
  5. //
  6. // File: hntfsstg.cxx
  7. //
  8. // This file provides the NFF (NTFS Flat File) IStream implementation.
  9. //
  10. // History:
  11. // 5/6/98 MikeHill
  12. // - Use CoTaskMem rather than new/delete.
  13. //
  14. //+============================================================================
  15. #include <pch.cxx>
  16. #include <tstr.h>
  17. #include "cli.hxx"
  18. #include "expparam.hxx"
  19. #ifdef _MAC_NODOC
  20. ASSERTDATA // File-specific data for FnAssert
  21. #endif
  22. DECLARE_INFOLEVEL(nff)
  23. #ifndef DEB_INFO
  24. #define DEB_INFO DEB_USER1
  25. #endif
  26. //+----------------------------------------------------------------------------
  27. //
  28. // Method: CNtfsStream::AddRef (IUnknown)
  29. //
  30. //+----------------------------------------------------------------------------
  31. ULONG
  32. CNtfsStream::AddRef()
  33. {
  34. LONG cRefs;
  35. cRefs = InterlockedIncrement( &_cRefs );
  36. nffDebug((DEB_REFCOUNT, "CNtfsStream::AddRef(this=%x) == %d\n",
  37. this, cRefs));
  38. return cRefs;
  39. }
  40. //+----------------------------------------------------------------------------
  41. //
  42. // Method: CNtfsStream::Release (IUnknown)
  43. //
  44. //+----------------------------------------------------------------------------
  45. ULONG
  46. CNtfsStream::Release()
  47. {
  48. ULONG ulRet = InterlockedDecrement( &_cRefs );
  49. if( 0 == ulRet )
  50. {
  51. RemoveSelfFromList();
  52. delete this;
  53. }
  54. nffDebug((DEB_REFCOUNT, "CNtfsStream::Release(this=%x) == %d\n",
  55. this, ulRet));
  56. return( ulRet );
  57. }
  58. //+----------------------------------------------------------------------------
  59. //
  60. // Method: CNtfsStream::AddRef (IUnknown)
  61. //
  62. //+----------------------------------------------------------------------------
  63. HRESULT
  64. CNtfsStream::QueryInterface(
  65. REFIID riid,
  66. void** ppv )
  67. {
  68. HRESULT sc=S_OK;
  69. #if DBG == 1
  70. WCHAR strIID[64];
  71. StringFromGUID2(riid, strIID, 64);
  72. nffDebug(( DEB_TRACE | DEB_REFCOUNT,
  73. "CNtfsStream::QueryInterface( %ws )\n", strIID ));
  74. #endif
  75. NFF_VALIDATE( QueryInterface( riid, ppv ) );
  76. nffChk( CheckReverted() );
  77. if( IsEqualIID( riid, IID_IUnknown )
  78. ||
  79. IsEqualIID( riid, IID_IStream )
  80. ||
  81. IsEqualIID( riid, IID_ISequentialStream ) )
  82. {
  83. *ppv = static_cast<IStream*>(this);
  84. AddRef();
  85. return( S_OK );
  86. }
  87. else if( IsEqualIID( riid, IID_IMappedStream ))
  88. {
  89. *ppv = static_cast<IMappedStream*>(&_nffMappedStream);
  90. AddRef();
  91. return( S_OK );
  92. }
  93. else if( IsEqualIID( riid, IID_ILockBytes ))
  94. {
  95. *ppv = static_cast<ILockBytes*>(this);
  96. AddRef();
  97. return( S_OK );
  98. }
  99. #if DBG == 1
  100. else if( IsEqualIID( riid, IID_IStorageTest ))
  101. {
  102. *ppv = static_cast<IStorageTest*>(this);
  103. AddRef();
  104. return( S_OK );
  105. }
  106. #endif // #if DBG
  107. else
  108. {
  109. nffDebug(( DEB_TRACE | DEB_REFCOUNT,
  110. "CNtfsStream::QueryInterface() Failed E_NOINTERFACE\n" ));
  111. return( E_NOINTERFACE );
  112. }
  113. EH_Err:
  114. return sc;
  115. }
  116. //+----------------------------------------------------------------------------
  117. //
  118. // Method: CNtfsStream::Seek (IStream)
  119. //
  120. //+----------------------------------------------------------------------------
  121. HRESULT
  122. CNtfsStream::Seek(
  123. LARGE_INTEGER dlibMove,
  124. DWORD dwOrigin,
  125. ULARGE_INTEGER *puliNewPos)
  126. {
  127. HRESULT sc = S_OK;
  128. LARGE_INTEGER liFileSize;
  129. LARGE_INTEGER liNewPos;
  130. nffDebug(( DEB_TRACE, "CNtfsStream::Seek( %x:%08x, %d, %p );\n",
  131. dlibMove.HighPart, dlibMove.LowPart,
  132. dwOrigin, puliNewPos ));
  133. NFF_VALIDATE( Seek( dlibMove, dwOrigin, puliNewPos ) );
  134. Lock( INFINITE );
  135. nffChk( CheckReverted() );
  136. switch( dwOrigin )
  137. {
  138. case STREAM_SEEK_SET:
  139. liNewPos.QuadPart = dlibMove.QuadPart;
  140. break;
  141. case STREAM_SEEK_CUR:
  142. liNewPos.QuadPart = _liCurrentSeekPosition.QuadPart + dlibMove.QuadPart;
  143. break;
  144. case STREAM_SEEK_END:
  145. liFileSize.LowPart = GetFileSize( _hFile,
  146. (ULONG*)(&liFileSize.HighPart) );
  147. if( 0xFFFFFFFF == liFileSize.LowPart && NO_ERROR != GetLastError() )
  148. {
  149. nffChk( HRESULT_FROM_WIN32( GetLastError() ) );
  150. }
  151. liNewPos.QuadPart = liFileSize.QuadPart + dlibMove.QuadPart;
  152. break;
  153. default:
  154. nffChk(STG_E_INVALIDPARAMETER);
  155. break;
  156. }
  157. // Compatibility with Docfile. Seeking < 0 fails.
  158. if( liNewPos.QuadPart < 0 )
  159. nffErr( EH_Err, STG_E_INVALIDFUNCTION );
  160. _liCurrentSeekPosition = liNewPos;
  161. // If desired, give the caller the now-current seek position.
  162. if( NULL != puliNewPos )
  163. *puliNewPos = _liCurrentSeekPosition;
  164. EH_Err:
  165. Unlock();
  166. return( sc );
  167. }
  168. //+----------------------------------------------------------------------------
  169. //
  170. // Method: CNtfsStream::SetSize (IStream)
  171. //
  172. //+----------------------------------------------------------------------------
  173. HRESULT
  174. CNtfsStream::SetSize(
  175. ULARGE_INTEGER uliNewSize)
  176. {
  177. HRESULT sc = S_OK;
  178. CLargeInteger liEOF;
  179. if ( uliNewSize.HighPart != 0 )
  180. nffErr(EH_Err, STG_E_INVALIDFUNCTION);
  181. nffDebug(( DEB_ITRACE | DEB_INFO | DEB_WRITE,
  182. "CNtfsStream::SetSize(%x:%x) hdl=%x, stream='%ws'\n",
  183. uliNewSize.QuadPart,
  184. _hFile,
  185. _pwcsName ));
  186. NFF_VALIDATE( SetSize( uliNewSize ) );
  187. Lock( INFINITE );
  188. nffChk( CheckReverted() );
  189. // If this stream is mapped, set the size accordingly
  190. if( _nffMappedStream.IsMapped() )
  191. {
  192. _nffMappedStream.SetSize( uliNewSize.LowPart, TRUE, NULL, &sc );
  193. }
  194. else
  195. {
  196. sc = SetFileSize( CULargeInteger(uliNewSize) );
  197. }
  198. if( !FAILED(sc) )
  199. sc = S_OK;
  200. EH_Err:
  201. Unlock();
  202. return( sc);
  203. }
  204. //+----------------------------------------------------------------------------
  205. //
  206. // Method: CNtfsStream::CopyTo (IStream)
  207. //
  208. // There's no way of knowing what the IStream is to which we're copying, so
  209. // we have to assume that we might be copying to ourself. And given that
  210. // assumption, we have to deal with the case that this is an overlapping
  211. // copy (e.g., "copy 10 bytes from offset 0 to offset 5").
  212. //
  213. //+----------------------------------------------------------------------------
  214. HRESULT
  215. CNtfsStream::CopyTo(
  216. IStream *pstm,
  217. ULARGE_INTEGER cb,
  218. ULARGE_INTEGER *pcbRead,
  219. ULARGE_INTEGER *pcbWritten)
  220. {
  221. nffXTrace( "CNtfsStream::CopyTo" );
  222. HRESULT sc = S_OK;
  223. PVOID pv = NULL;
  224. ULONG cbRead = 0, cbWritten = 0;
  225. CULargeInteger cbReadTotal = 0, cbWrittenTotal = 0;
  226. CLargeInteger liZero = 0;
  227. CULargeInteger uliOriginalSourcePosition, uliOriginalDestPosition;
  228. CULargeInteger cbSourceSize, cbDestSize;
  229. ULONG cbPerCopy = 0;
  230. STATSTG statstg;
  231. CULargeInteger cbRequested = cb;
  232. BOOL fCopyForward;
  233. NFF_VALIDATE( CopyTo( pstm, cb, pcbRead, pcbWritten ) );
  234. Lock( INFINITE );
  235. nffChk( CheckReverted() );
  236. if( NULL == pstm)
  237. nffErr( EH_Err, STG_E_INVALIDPARAMETER );
  238. // Determine how much we'll copy at a time.
  239. // As of this writing, STREAMBUFFERSIZE is 8192 bytes
  240. if( cbRequested > STREAMBUFFERSIZE )
  241. cbPerCopy = STREAMBUFFERSIZE;
  242. else
  243. cbPerCopy = cbRequested.LowPart;
  244. // ------------------------------------------------------------------
  245. // Get the current stream sizes/positions, and adjust the destination
  246. // size if necessary
  247. // ------------------------------------------------------------------
  248. nffChk( this->Seek( liZero, STREAM_SEEK_CUR, &uliOriginalSourcePosition ) );
  249. nffChk( pstm->Seek( liZero, STREAM_SEEK_CUR, &uliOriginalDestPosition ) );
  250. nffChk( this->Stat( &statstg, STATFLAG_NONAME ) );
  251. cbSourceSize = statstg.cbSize;
  252. nffChk( pstm->Stat( &statstg, STATFLAG_NONAME ) );
  253. cbDestSize = statstg.cbSize;
  254. // Ensure the sizes are valid (we can't handle anything with the high bit
  255. // set, because Seek takes a signed offset).
  256. if( static_cast<CLargeInteger>(cbSourceSize) < 0
  257. ||
  258. static_cast<CLargeInteger>(cbDestSize) < 0 )
  259. {
  260. nffErr( EH_Err, STG_E_INVALIDHEADER );
  261. }
  262. // Don't copy more than the source stream has available
  263. if( cbRequested > cbSourceSize - uliOriginalSourcePosition )
  264. cbRequested = cbSourceSize - uliOriginalSourcePosition;
  265. // If necessary, grow the destination stream.
  266. if( cbSourceSize - uliOriginalSourcePosition > cbDestSize - uliOriginalDestPosition )
  267. {
  268. cbDestSize = cbSourceSize - uliOriginalSourcePosition + uliOriginalDestPosition;
  269. nffChk( pstm->SetSize( cbDestSize ) );
  270. }
  271. // ----------------------
  272. // Allocate a copy buffer
  273. // ----------------------
  274. nffMem( pv = CoTaskMemAlloc( cbPerCopy ) );
  275. // -----------------------------------------------------------------------------
  276. // Determine if we're copying forwards (high seek position to low) or backwards.
  277. // -----------------------------------------------------------------------------
  278. fCopyForward = TRUE;
  279. if( uliOriginalSourcePosition < uliOriginalDestPosition )
  280. {
  281. // E.g., say we're copying 15 bytes from offset 0 to offset 5,
  282. // and we're only able to copy 10 bytes at a time.
  283. // If we copy bytes 0-9 to offset 5, we'll end up overwriting
  284. // bytes 10-14, and be unable to complete the copy.
  285. // So instead, we'll copy bytes 5-14 to offset 10, and finish
  286. // up by copying bytes 0-4 to offset 5.
  287. fCopyForward = FALSE;
  288. // To do this kind of backwards copy, we need to start by seeking
  289. // towards the end of the stream.
  290. CULargeInteger uliNewSourcePosition, uliNewDestPosition;
  291. uliNewSourcePosition = cbSourceSize - cbPerCopy;
  292. nffChk( this->Seek( uliNewSourcePosition, STREAM_SEEK_SET, NULL ) );
  293. uliNewDestPosition = cbDestSize - cbPerCopy;
  294. nffChk( pstm->Seek( uliNewDestPosition, STREAM_SEEK_SET, NULL ) );
  295. }
  296. // --------------
  297. // Copy in chunks
  298. // --------------
  299. cbPerCopy = cbRequested > cbPerCopy ? cbPerCopy : cbRequested.LowPart;
  300. while( cbRequested > 0 )
  301. {
  302. // Read from the source
  303. nffChk( this->Read( pv, cbPerCopy, &cbRead ) );
  304. if( cbRead != cbPerCopy )
  305. nffErr(EH_Err, STG_E_READFAULT);
  306. cbReadTotal += cbRead;
  307. // Write to the dest
  308. nffChk( pstm->Write( pv, cbPerCopy, &cbWritten ) );
  309. if( cbWritten != cbPerCopy )
  310. nffErr( EH_Err, STG_E_WRITEFAULT );
  311. cbWrittenTotal += cbWritten;
  312. // Adjust the amount remaining to be copied
  313. cbRequested -= cbPerCopy;
  314. // Determine how much to copy in the next iteration (this will
  315. // always be cbPerCopy until the last iteration). If copying
  316. // backwards, we need to manually adjust the seek pointer.
  317. cbPerCopy = (cbRequested > cbPerCopy) ? cbPerCopy : cbRequested.LowPart;
  318. if( !fCopyForward )
  319. {
  320. nffChk( this->Seek( -static_cast<CLargeInteger>(cbPerCopy),
  321. STREAM_SEEK_CUR, NULL ) );
  322. nffChk( pstm->Seek( -static_cast<CLargeInteger>(cbPerCopy),
  323. STREAM_SEEK_CUR, NULL ) );
  324. }
  325. }
  326. // If we were backward-copying, adjust the seek pointers
  327. // as if we had forward-copied
  328. if( !fCopyForward )
  329. {
  330. uliOriginalSourcePosition += cbReadTotal;
  331. nffChk( this->Seek( uliOriginalSourcePosition, STREAM_SEEK_SET, NULL ) );
  332. uliOriginalDestPosition += cbWrittenTotal;
  333. nffChk( pstm->Seek( uliOriginalDestPosition, STREAM_SEEK_SET, NULL ) );
  334. }
  335. // ----
  336. // Exit
  337. // ----
  338. if( NULL != pcbRead )
  339. *pcbRead = cbReadTotal;
  340. if( NULL != pcbWritten )
  341. *pcbWritten = cbWrittenTotal;
  342. EH_Err:
  343. if( NULL != pv )
  344. CoTaskMemFree(pv);
  345. Unlock();
  346. return(sc);
  347. }
  348. //+----------------------------------------------------------------------------
  349. //
  350. // Method: CNtfsStream::Commit (IStream)
  351. //
  352. //+----------------------------------------------------------------------------
  353. HRESULT
  354. CNtfsStream::Commit( DWORD grfCommitFlags )
  355. {
  356. nffXTrace( "CNtfsStream::Commit" );
  357. HRESULT sc = S_OK;
  358. NFF_VALIDATE( Commit( grfCommitFlags ) );
  359. if(~(STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE|STGC_DEFAULT) & grfCommitFlags)
  360. nffErr( EH_Err, STG_E_INVALIDFLAG );
  361. Lock( INFINITE );
  362. nffChkTo ( EH_Unlock, CheckReverted() );
  363. if( !(STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE & grfCommitFlags) )
  364. {
  365. if( !FlushFileBuffers( _hFile ))
  366. sc = LAST_SCODE;
  367. }
  368. EH_Unlock:
  369. Unlock();
  370. EH_Err:
  371. return sc;
  372. }
  373. //+----------------------------------------------------------------------------
  374. //
  375. // Method: CNtfsStream::Revert (IStream)
  376. //
  377. //+----------------------------------------------------------------------------
  378. HRESULT
  379. CNtfsStream::Revert(void)
  380. {
  381. nffXTrace( "CNtfsStream::Revert" );
  382. // We only support direct-mode.
  383. return CheckReverted();
  384. }
  385. //+----------------------------------------------------------------------------
  386. //
  387. // Method: CNtfsStream::LockRegion (IStream)
  388. //
  389. //+----------------------------------------------------------------------------
  390. HRESULT
  391. CNtfsStream::LockRegion(
  392. ULARGE_INTEGER libOffset,
  393. ULARGE_INTEGER cb,
  394. DWORD dwLockType)
  395. {
  396. nffXTrace( "CNtfsStream::LockRegion" );
  397. HRESULT sc = S_OK;
  398. NFF_VALIDATE( LockRegion( libOffset, cb, dwLockType ) );
  399. Lock( INFINITE );
  400. nffChk( CheckReverted() );
  401. if (dwLockType != LOCK_EXCLUSIVE && dwLockType != LOCK_ONLYONCE)
  402. nffErr( EH_Err, STG_E_INVALIDFUNCTION );
  403. if( !LockFile( _hFile, libOffset.LowPart, libOffset.HighPart,
  404. cb.LowPart, cb.HighPart))
  405. {
  406. nffErr( EH_Err, LAST_SCODE );
  407. }
  408. EH_Err:
  409. Unlock();
  410. return( sc );
  411. }
  412. //+----------------------------------------------------------------------------
  413. //
  414. // Method: CNtfsStream::UnlockRegion (ILockBytes)
  415. //
  416. //+----------------------------------------------------------------------------
  417. HRESULT
  418. CNtfsStream::UnlockRegion(
  419. ULARGE_INTEGER libOffset,
  420. ULARGE_INTEGER cb,
  421. DWORD dwLockType)
  422. {
  423. nffXTrace( "CNtfsStream::UnlockRegion" );
  424. HRESULT sc = S_OK;
  425. NFF_VALIDATE( UnlockRegion( libOffset, cb, dwLockType ) );
  426. Lock( INFINITE );
  427. nffChk( CheckReverted() );
  428. if (dwLockType != LOCK_EXCLUSIVE && dwLockType != LOCK_ONLYONCE)
  429. {
  430. nffErr( EH_Err, STG_E_INVALIDFUNCTION );
  431. }
  432. if( !UnlockFile(_hFile, libOffset.LowPart, libOffset.HighPart,
  433. cb.LowPart, cb.HighPart))
  434. {
  435. nffErr( EH_Err, LAST_SCODE );
  436. }
  437. EH_Err:
  438. Unlock();
  439. return( sc );
  440. }
  441. //+----------------------------------------------------------------------------
  442. //
  443. // Method: CNtfsStream::Stat (IStream)
  444. //
  445. //+----------------------------------------------------------------------------
  446. HRESULT
  447. CNtfsStream::Stat(
  448. STATSTG *pstatstg,
  449. DWORD grfStatFlag)
  450. {
  451. nffXTrace( "CNtfsStream::Stat" );
  452. STATSTG statstg;
  453. HRESULT sc = S_OK;
  454. NTSTATUS status = STATUS_SUCCESS;
  455. FILE_ACCESS_INFORMATION file_access_information;
  456. IO_STATUS_BLOCK IoStatusBlock;
  457. BY_HANDLE_FILE_INFORMATION ByHandleFileInformation;
  458. NFF_VALIDATE( Stat( pstatstg, grfStatFlag ) );
  459. Lock( INFINITE );
  460. nffChkTo ( EH_Lock, CheckReverted() );
  461. ZeroMemory((void*)&statstg, sizeof(STATSTG));
  462. // Get the name, if desired
  463. if( (STATFLAG_NONAME & grfStatFlag) )
  464. statstg.pwcsName = NULL;
  465. else
  466. {
  467. nffAssert( NULL != _pwcsName );
  468. nffMem( statstg.pwcsName = reinterpret_cast<WCHAR*>
  469. ( CoTaskMemAlloc( sizeof(WCHAR)*(wcslen(_pwcsName) + 1) )));
  470. wcscpy( statstg.pwcsName, _pwcsName );
  471. }
  472. // Get the type
  473. statstg.type = STGTY_STREAM;
  474. statstg.grfLocksSupported = LOCK_EXCLUSIVE | LOCK_ONLYONCE;
  475. // Get the size & times.
  476. if( !GetFileInformationByHandle( _hFile, &ByHandleFileInformation ))
  477. nffErr( EH_Err, LAST_SCODE );
  478. statstg.cbSize.LowPart = ByHandleFileInformation.nFileSizeLow;
  479. statstg.cbSize.HighPart = ByHandleFileInformation.nFileSizeHigh;
  480. // We get a time back in ByHandleFileInformation, but it's the file's times,
  481. // not the streams times. So really the stream times are not supported, and
  482. // we'll just set them to zero.
  483. statstg.mtime = statstg.atime = statstg.ctime = CFILETIME(0);
  484. // Get the STGM modes
  485. statstg.grfMode = _grfMode & ~STGM_CREATE;
  486. *pstatstg = statstg;
  487. EH_Err:
  488. if( FAILED(sc) && NULL != statstg.pwcsName )
  489. CoTaskMemFree( statstg.pwcsName );
  490. EH_Lock:
  491. Unlock();
  492. return( sc );
  493. }
  494. //+----------------------------------------------------------------------------
  495. //
  496. // Method: CNtfsStream::Clone (IStream)
  497. //
  498. //+----------------------------------------------------------------------------
  499. HRESULT
  500. CNtfsStream::Clone(
  501. IStream** ppstm)
  502. {
  503. nffXTrace( "CNtfsStream::Clone" );
  504. return( E_NOTIMPL );
  505. }
  506. //+----------------------------------------------------------------------------
  507. //
  508. // Method: CNtfsStream::Read (IStream)
  509. //
  510. //+----------------------------------------------------------------------------
  511. HRESULT
  512. CNtfsStream::Read(
  513. void* pv,
  514. ULONG cb,
  515. ULONG* pcbRead)
  516. {
  517. nffXTrace( "CNtfsStream::Read" );
  518. HRESULT sc = S_OK;
  519. ULONG cbRead = 0;
  520. nffDebug(( DEB_ITRACE, "Read( pv=0x%x, cb=0x%x );\n", pv, cb ));
  521. NFF_VALIDATE( Read( pv, cb, pcbRead ) );
  522. Lock( INFINITE );
  523. nffChk( CheckReverted() );
  524. nffChk( ReadAt( _liCurrentSeekPosition, pv, cb, &cbRead ) );
  525. _liCurrentSeekPosition += cbRead;
  526. nffDebug(( DEB_ITRACE, "Read() read %x bytes.\n", cbRead ));
  527. if( NULL != pcbRead )
  528. *pcbRead = cbRead;
  529. EH_Err:
  530. Unlock();
  531. return( sc );
  532. }
  533. //+----------------------------------------------------------------------------
  534. //
  535. // Method: CNtfsStream::ReadAt (ILockBytes)
  536. //
  537. //+----------------------------------------------------------------------------
  538. HRESULT
  539. CNtfsStream::ReadAt(
  540. ULARGE_INTEGER ulOffset,
  541. void* pv,
  542. ULONG cb,
  543. ULONG* pcbRead)
  544. {
  545. nffXTrace( "CNtfsStream::ReadAt" );
  546. HRESULT sc = S_OK;
  547. nffDebug(( DEB_ITRACE, "ReadAt( off=%x:%x, pv=0x%x, cb=0x%x );\n",
  548. ulOffset, pv, cb ));
  549. NFF_VALIDATE( ReadAt( ulOffset, pv, cb, pcbRead ) );
  550. if( static_cast<LONG>(ulOffset.HighPart) < 0 )
  551. return TYPE_E_SIZETOOBIG;
  552. Lock( INFINITE );
  553. nffChk( CheckReverted() );
  554. // Is this stream mapped?
  555. if( _nffMappedStream.IsMapped() )
  556. {
  557. // This stream is mapped. We'll read directly from the mapping buffer.
  558. _nffMappedStream.Read( pv, _liCurrentSeekPosition.LowPart, &cb );
  559. if( NULL != pcbRead )
  560. *pcbRead = cb;
  561. }
  562. else
  563. {
  564. // No, just read from the file.
  565. nffChk( SyncReadAtFile( ulOffset, pv, cb, pcbRead ) );
  566. }
  567. nffDebug(( DEB_ITRACE, "ReadAt() read %x bytes.\n", *pcbRead ));
  568. EH_Err:
  569. Unlock();
  570. return( sc );
  571. }
  572. //+----------------------------------------------------------------------------
  573. //
  574. // Method: CNtfsStream::Write (IStream)
  575. //
  576. //+----------------------------------------------------------------------------
  577. HRESULT
  578. CNtfsStream::Write(
  579. const void* pv,
  580. ULONG cb,
  581. ULONG* pcbWritten)
  582. {
  583. nffXTrace( "CNtfsStream::Write" );
  584. HRESULT sc = S_OK;
  585. ULONG cbWritten = 0;
  586. nffDebug(( DEB_ITRACE, "Write( pv=0x%x, cb=0x%x );\n", pv, cb ));
  587. NFF_VALIDATE( Write( pv, cb, pcbWritten ) );
  588. Lock( INFINITE );
  589. nffChk( CheckReverted() );
  590. nffChk(WriteAt( _liCurrentSeekPosition, pv, cb, &cbWritten ));
  591. _liCurrentSeekPosition += cbWritten;
  592. nffDebug(( DEB_ITRACE, "Write() wrote %x bytes.\n", cbWritten ));
  593. if( NULL != pcbWritten )
  594. *pcbWritten = cbWritten;
  595. EH_Err:
  596. Unlock();
  597. return( sc );
  598. }
  599. //+----------------------------------------------------------------------------
  600. //
  601. // Method: CNtfsStream::WriteAt (ILockBytes)
  602. //
  603. //+----------------------------------------------------------------------------
  604. HRESULT
  605. CNtfsStream::WriteAt(
  606. ULARGE_INTEGER ulOffset,
  607. const void* pv,
  608. ULONG cb,
  609. ULONG* pcbWritten)
  610. {
  611. nffXTrace( "CNtfsStream::WriteAt" );
  612. HRESULT sc = S_OK;
  613. nffDebug(( DEB_ITRACE, "WriteAt( off=%x:%x, pv=0x%x, cb=0x%x );\n",
  614. ulOffset, pv, cb ));
  615. NFF_VALIDATE( WriteAt( ulOffset, pv, cb, pcbWritten ) );
  616. if( ((LONG)(ulOffset.HighPart)) < 0 )
  617. return( TYPE_E_SIZETOOBIG );
  618. Lock( INFINITE );
  619. nffChk( CheckReverted() );
  620. // Is this stream mapped?
  621. if( _nffMappedStream.IsMapped() )
  622. {
  623. // This stream is mapped, we'll take the Write to the mapping.
  624. ULONG iPosition = _nffMappedStream.SizeOfMapping() - _liCurrentSeekPosition.LowPart;
  625. if( cb > iPosition )
  626. {
  627. _nffMappedStream.SetSize( iPosition + cb, TRUE, NULL, &sc );
  628. nffChk(sc);
  629. }
  630. _nffMappedStream.Write( pv, _liCurrentSeekPosition.LowPart, &cb );
  631. if( NULL != pcbWritten )
  632. *pcbWritten = cb;
  633. }
  634. else
  635. {
  636. // No, just write to the file.
  637. nffChk( SyncWriteAtFile( ulOffset, pv, cb, pcbWritten ) );
  638. }
  639. nffDebug(( DEB_ITRACE, "WriteAt() wrote %x bytes.\n", *pcbWritten ));
  640. EH_Err:
  641. Unlock();
  642. return( sc );
  643. }
  644. //+----------------------------------------------------------------------------
  645. //
  646. // Method: CNtfsStream::Flush (IStream)
  647. //
  648. //+----------------------------------------------------------------------------
  649. HRESULT
  650. CNtfsStream::Flush()
  651. {
  652. HRESULT sc = S_OK;
  653. Lock( INFINITE );
  654. nffChk( CheckReverted() );
  655. _nffMappedStream.Flush(&sc);
  656. EH_Err:
  657. Unlock();
  658. return(sc);
  659. }
  660. //+-------------------------------------------------------------------
  661. //
  662. // Member: CNtfsStream Constructor
  663. //
  664. //--------------------------------------------------------------------
  665. CNtfsStream::CNtfsStream( CNtfsStorage *pnffstg,
  666. IBlockingLock *pBlockingLock )
  667. #pragma warning(disable: 4355)
  668. : _nffMappedStream( this ),
  669. #pragma warning(default: 4355)
  670. _pnffstg( pnffstg )
  671. {
  672. nffXTrace( "CNtfsStream::CNtfsStream" );
  673. nffDebug(( DEB_REFCOUNT, "new CNtfsStream Constructed with cRefs=1\n" ));
  674. _sig = NTFSSTREAM_SIG;
  675. _cRefs = 1;
  676. _grfMode = 0;
  677. _hFile = INVALID_HANDLE_VALUE;
  678. _liCurrentSeekPosition = 0;
  679. _pnffstmNext = NULL;
  680. _pnffstmPrev = NULL;
  681. _pwcsName = NULL;
  682. nffAssert( NULL != pBlockingLock );
  683. _pBlockingLock = pBlockingLock;
  684. _pBlockingLock->AddRef();
  685. _ovlp.Internal = _ovlp.InternalHigh = 0;
  686. _ovlp.Offset = _ovlp.OffsetHigh = 0;
  687. _ovlp.hEvent = NULL;
  688. }
  689. //+-------------------------------------------------------------------
  690. //
  691. // Member: CNtfsStream Destructor
  692. //
  693. //--------------------------------------------------------------------
  694. CNtfsStream::~CNtfsStream()
  695. {
  696. nffXTrace( "CNtfsStream::~CNtfsStream" );
  697. nffDebug(( DEB_INFO, "CNtfsStream: Close 0x%x.\n", _hFile ));
  698. // Shut down the mapped stream
  699. _nffMappedStream.ShutDown();
  700. // Close the file
  701. if( INVALID_HANDLE_VALUE != _hFile )
  702. NtClose( _hFile );
  703. if( NULL != _ovlp.hEvent )
  704. CloseHandle( _ovlp.hEvent );
  705. if( NULL != _pwcsName )
  706. CoTaskMemFree( _pwcsName );
  707. // Release the object that provides access to the tree lock.
  708. nffAssert( NULL != _pBlockingLock );
  709. _pBlockingLock->Release();
  710. _sig = NTFSSTREAM_SIGDEL;
  711. }
  712. //+-------------------------------------------------------------------
  713. //
  714. // Member: CNtfsStream::Init
  715. //
  716. //--------------------------------------------------------------------
  717. HRESULT
  718. CNtfsStream::Init(
  719. HANDLE hFile, // File handle of this NTFS Stream.
  720. DWORD grfMode, // Open Modes
  721. const OLECHAR * pwcsName, // Name of the Stream
  722. CNtfsStream *pnffstm) // Previously Open NTFS Stream (list)
  723. {
  724. HRESULT sc=S_OK;
  725. HANDLE ev;
  726. nffITrace( "CNtfsStream::Init" );
  727. // We now own this file handle, and are responsible for closing it.
  728. _hFile = hFile;
  729. // Save the STGM_ flags so we can return them in a Stat call.
  730. _grfMode = grfMode;
  731. // Save the stream name
  732. if( NULL != _pwcsName )
  733. {
  734. CoTaskMemFree( _pwcsName );
  735. _pwcsName = NULL;
  736. }
  737. if( NULL != pwcsName )
  738. {
  739. nffMem( _pwcsName = reinterpret_cast<WCHAR*>
  740. ( CoTaskMemAlloc( sizeof(WCHAR)*(wcslen(pwcsName) + 1) )));
  741. wcscpy( _pwcsName, pwcsName );
  742. }
  743. // All the streams live on a list held by the root Storage.
  744. if(NULL != pnffstm)
  745. InsertSelfIntoList(pnffstm);
  746. if( NULL == _ovlp.hEvent )
  747. {
  748. ev = CreateEvent(NULL, // Security Attributes.
  749. TRUE, // Manual Reset, Flag.
  750. FALSE, // Initial State = Signaled, Flag.
  751. NULL); // Object Name.
  752. if( NULL == ev)
  753. nffChk( LAST_SCODE );
  754. _ovlp.hEvent = ev;
  755. }
  756. nffChk( _nffMappedStream.Init( _hFile ));
  757. EH_Err:
  758. return sc;
  759. }
  760. //+----------------------------------------------------------------------------
  761. //
  762. // CNtfsStream Non-Interface::ShutDown
  763. //
  764. // Flush data, Close File handle and mark the object as reverted.
  765. // This is called when the Storage is released and when the Oplock Breaks.
  766. //
  767. //+----------------------------------------------------------------------------
  768. HRESULT
  769. CNtfsStream::ShutDown()
  770. {
  771. nffITrace( "CNtfsStream::ShutDown" );
  772. HRESULT sc=S_OK;
  773. if( INVALID_HANDLE_VALUE == _hFile )
  774. return S_OK;
  775. nffDebug(( DEB_INFO, "CNtfsStream::ShutDown(%x)\n", _hFile ));
  776. //
  777. // Shut down the mapped stream
  778. //
  779. _nffMappedStream.ShutDown();
  780. //
  781. // Close the file/stream handle and mark the IStream object as
  782. // Reverted by giving the file handle an invalid value.
  783. //
  784. CloseHandle(_hFile);
  785. _hFile = INVALID_HANDLE_VALUE;
  786. // We don't need the parent CNtfsStorage any longer, and more importantly it could
  787. // be going away.
  788. _pnffstg = NULL;
  789. //
  790. // Remove IStream object from the Storage's list
  791. //
  792. RemoveSelfFromList();
  793. return S_OK;
  794. }
  795. //+----------------------------------------------------------------------------
  796. //
  797. // CNtfsStream Non-Interface::Rename
  798. //
  799. //+----------------------------------------------------------------------------
  800. HRESULT
  801. CNtfsStream::Rename(
  802. const WCHAR *pwcsName,
  803. BOOL fOverWrite )
  804. {
  805. IO_STATUS_BLOCK io_status_block;
  806. PFILE_RENAME_INFORMATION pFileRenInfo=NULL; // _alloca()'ed
  807. NTSTATUS status;
  808. CNtfsStreamName nsnName = pwcsName; // Convert to ":name:$DATA"
  809. LONG cbBufSize=0;
  810. HRESULT sc=S_OK;
  811. nffDebug(( DEB_INFO | DEB_WRITE, "CNtfsStream::Rename(%ws -> %ws)\n",
  812. _pwcsName, pwcsName ));
  813. Lock( INFINITE );
  814. nffChk( CheckReverted() );
  815. // Size and allocate a FILE_RENAME_INFOMATION buffer. The size argument
  816. // to NtSetInformationFile must be correct, so subtract 1 WCHAR for the
  817. // FileName[1] in the struct we are not using.
  818. //
  819. cbBufSize = sizeof(FILE_RENAME_INFORMATION) - sizeof(WCHAR);
  820. cbBufSize += nsnName.Count() * sizeof(WCHAR);
  821. pFileRenInfo = (PFILE_RENAME_INFORMATION) _alloca( cbBufSize );
  822. // Load the FILE_RENAME_INFORMATION structure
  823. pFileRenInfo->ReplaceIfExists = (BOOLEAN) fOverWrite;
  824. pFileRenInfo->RootDirectory = NULL;
  825. pFileRenInfo->FileNameLength = nsnName.Count() * sizeof(WCHAR);
  826. wcscpy( pFileRenInfo->FileName, (const WCHAR*)nsnName );
  827. // Rename the stream
  828. status = NtSetInformationFile( _hFile,
  829. &io_status_block,
  830. pFileRenInfo,
  831. cbBufSize,
  832. FileRenameInformation );
  833. if( !NT_SUCCESS(status) )
  834. {
  835. nffChk( sc = NtStatusToScode(status) );
  836. }
  837. // Discard the old name and Save the new name
  838. CoTaskMemFree( _pwcsName );
  839. // reuse cbBufSize
  840. cbBufSize = sizeof(WCHAR) * (wcslen(pwcsName)+1);
  841. nffMem( _pwcsName = (WCHAR*) CoTaskMemAlloc( cbBufSize ));
  842. wcscpy( _pwcsName, pwcsName );
  843. sc = S_OK;
  844. EH_Err:
  845. Unlock();
  846. return( sc );
  847. }
  848. //+----------------------------------------------------------------------------
  849. //
  850. // CNtfsStream Non-Interface::Delete
  851. //
  852. //+----------------------------------------------------------------------------
  853. HRESULT
  854. CNtfsStream::Delete()
  855. {
  856. HRESULT sc=S_OK;
  857. nffDebug(( DEB_INFO | DEB_WRITE, "Delete(stm=%ws)\n", _pwcsName ));
  858. nffChk( CheckReverted() );
  859. if( IsWriteable() )
  860. nffChk( DeleteStream( &_hFile ));
  861. EH_Err:
  862. return( sc );
  863. }
  864. //+----------------------------------------------------------------------------
  865. //
  866. // CNtfsStream Non-Interface::DeleteStream
  867. //
  868. // This method is static so that it can be called globally.
  869. //
  870. //+----------------------------------------------------------------------------
  871. HRESULT // static
  872. CNtfsStream::DeleteStream( HANDLE *phStream )
  873. {
  874. HRESULT sc=S_OK;
  875. NTSTATUS status = STATUS_SUCCESS;
  876. FILE_DISPOSITION_INFORMATION Disposition;
  877. IO_STATUS_BLOCK IoStatusBlock;
  878. // Execute the following statement:
  879. // Disposition.DeleteFile = TRUE;
  880. // We can't actually write the code that way, because "DeleteFile" is #defined to
  881. // "DeleteFileW".
  882. nffDebug(( DEB_INFO | DEB_WRITE, "DeleteStream(hdl=%x)\n", *phStream ));
  883. *reinterpret_cast<BOOLEAN*>(&Disposition) = TRUE;
  884. DfpAssert( sizeof(Disposition) == sizeof(BOOLEAN) );
  885. // Mark the file for delete on close
  886. // Note that if this is the Contents stream we can delete it successfully,
  887. // but NTFS actually just truncates it to zero length.
  888. status = NtSetInformationFile(
  889. *phStream,
  890. &IoStatusBlock,
  891. &Disposition,
  892. sizeof(Disposition),
  893. FileDispositionInformation
  894. );
  895. if( !NT_SUCCESS(status) )
  896. {
  897. nffErr( EH_Err, NtStatusToScode(status) );
  898. }
  899. NtClose( *phStream );
  900. *phStream = INVALID_HANDLE_VALUE;
  901. EH_Err:
  902. return( sc );
  903. }
  904. //+----------------------------------------------------------------------------
  905. //
  906. // CNtfsStream::SetFileSize (private, non-interface method)
  907. //
  908. // Set the size of the _hFile. This is used by the IStream & IMappedStream
  909. // SetSize methods
  910. //
  911. //+----------------------------------------------------------------------------
  912. HRESULT // private
  913. CNtfsStream::SetFileSize( const CULargeInteger &uliNewSize )
  914. {
  915. nffITrace( "CNtfsStream::SetFileSize" );
  916. HRESULT sc = S_OK;
  917. CLargeInteger liEOF;
  918. // We have to convert uliNewSize into a LARGE_INTEGER, so ensure that it can
  919. // be cast without loss of data.
  920. liEOF = static_cast<CLargeInteger>(uliNewSize);
  921. if( liEOF < 0 )
  922. nffErr( EH_Err, STG_E_INVALIDPARAMETER );
  923. // Move to what will be the new end-of-file position.
  924. liEOF.LowPart = SetFilePointer( _hFile, liEOF.LowPart,
  925. &liEOF.HighPart, FILE_BEGIN );
  926. if( 0xFFFFFFFF == liEOF.LowPart && NO_ERROR != GetLastError() )
  927. nffErr( EH_Err, LAST_SCODE );
  928. // Set this as the new eof
  929. if( !SetEndOfFile( _hFile ))
  930. nffErr( EH_Err, LAST_SCODE );
  931. EH_Err:
  932. return( sc );
  933. }
  934. //+-------------------------------------------------------------------
  935. //
  936. // Member: CNtfsStream::InsertSelfIntoList/RemoveSelfFromList
  937. //
  938. //--------------------------------------------------------------------
  939. // We are passed a "current" element of a doubly linked list.
  940. // Insert "this" right after the given List element.
  941. //
  942. VOID
  943. CNtfsStream::InsertSelfIntoList(CNtfsStream *pnffstmCurrent)
  944. {
  945. nffDebug(( DEB_ITRACE, "CNtfsStream::InsertSelfIntoList this=%x\n", this ));
  946. // If we're already in the list, or there is no list, then we're done.
  947. if( NULL != _pnffstmNext || NULL == pnffstmCurrent )
  948. return;
  949. // "this" point back to the current element
  950. // and points forward to current's next element
  951. _pnffstmPrev = pnffstmCurrent;
  952. _pnffstmNext = pnffstmCurrent->_pnffstmNext;
  953. // the current element now points forward to "this"
  954. // and if the next is not NULL it points back at this.
  955. pnffstmCurrent->_pnffstmNext = this;
  956. if(NULL != _pnffstmNext)
  957. _pnffstmNext->_pnffstmPrev = this;
  958. }
  959. VOID
  960. CNtfsStream::RemoveSelfFromList()
  961. {
  962. nffDebug(( DEB_ITRACE, "CNtfsStream::RemoveSelfFromList this=%x\n", this ));
  963. // My next element's previous pointer is given my previous pointer.
  964. if(NULL != _pnffstmNext)
  965. _pnffstmNext->_pnffstmPrev = _pnffstmPrev;
  966. // My previous element's next pointer is given my next pointer.
  967. if(NULL != _pnffstmPrev)
  968. _pnffstmPrev->_pnffstmNext = _pnffstmNext;
  969. _pnffstmNext = NULL;
  970. _pnffstmPrev = NULL;
  971. }
  972. //+-------------------------------------------------------------------
  973. //
  974. // CNtfsStream Non-Interface::SyncReadAtFile
  975. //
  976. // Synopsis: Provide synchronous IO for a file handle open in
  977. // asynchronous mode.
  978. //
  979. //--------------------------------------------------------------------
  980. HRESULT
  981. CNtfsStream::SyncReadAtFile(
  982. ULARGE_INTEGER ulOffset,
  983. PVOID pv,
  984. ULONG cb,
  985. PULONG pcbRead)
  986. {
  987. HRESULT sc=S_OK;
  988. LONG err=ERROR_SUCCESS;
  989. //
  990. // We use the single OVERLAPPED structure in the object.
  991. // This saves us from creating an Event everytime. We
  992. // require the TreeMutex will keep us single threaded.
  993. //
  994. _ovlp.Offset = ulOffset.LowPart;
  995. _ovlp.OffsetHigh = ulOffset.HighPart;
  996. nffDebug(( DEB_ITRACE | DEB_INFO | DEB_READ,
  997. "SyncReadAtFile(_hFile=0x%x off=%x:%x, pv=0x%x, cb=0x%x )"
  998. " stream='%ws'\n",
  999. _hFile, ulOffset.HighPart, ulOffset.LowPart,
  1000. pv, cb, _pwcsName ));
  1001. if( !ReadFile( _hFile, pv, cb, pcbRead, &_ovlp ) )
  1002. {
  1003. err = GetLastError();
  1004. if( ERROR_IO_PENDING == err )
  1005. {
  1006. // Only wait if ReadFile errored and returned ERROR_IO_PENDING.
  1007. // In that case clear "err" and continue.
  1008. //
  1009. err = ERROR_SUCCESS;
  1010. if( !GetOverlappedResult( _hFile, &_ovlp, pcbRead, TRUE) )
  1011. {
  1012. err = GetLastError();
  1013. }
  1014. }
  1015. }
  1016. if(ERROR_SUCCESS != err && ERROR_HANDLE_EOF != err)
  1017. nffChk( HRESULT_FROM_WIN32( err ) );
  1018. nffDebug(( DEB_INFO, "SyncReadAtFile() read 0x%x bytes.\n", *pcbRead ));
  1019. EH_Err:
  1020. return sc;
  1021. }
  1022. //+-------------------------------------------------------------------
  1023. //
  1024. // CNtfsStream Non-Interface::SyncWriteAtFile
  1025. //
  1026. // Synopsis: Provide synchronous IO for a file handle open in
  1027. // asynchronous mode.
  1028. //
  1029. //--------------------------------------------------------------------
  1030. HRESULT
  1031. CNtfsStream::SyncWriteAtFile(
  1032. ULARGE_INTEGER ulOffset,
  1033. const void *pv,
  1034. ULONG cb,
  1035. PULONG pcbWritten)
  1036. {
  1037. HRESULT sc=S_OK;
  1038. //
  1039. // We use the single OVERLAPPED structure in the object.
  1040. // We require the TreeMutex will keep us single threaded.
  1041. //
  1042. _ovlp.Offset = ulOffset.LowPart;
  1043. _ovlp.OffsetHigh = ulOffset.HighPart;
  1044. nffDebug(( DEB_ITRACE | DEB_INFO | DEB_WRITE,
  1045. "SyncWriteAtFile(_hFile=0x%x, off=%x:%x, pv=0x%x, cb=0x%x );"
  1046. " stream='%ws'\n",
  1047. _hFile, ulOffset.HighPart, ulOffset.LowPart,
  1048. pv, cb, _pwcsName ));
  1049. //
  1050. // We expect either OK or FALSE/ERROR_IO_PENDING.
  1051. //
  1052. if( !WriteFile( _hFile, pv, cb, pcbWritten, &_ovlp ) )
  1053. {
  1054. if( ERROR_IO_PENDING != GetLastError() )
  1055. nffChk( HRESULT_FROM_WIN32( GetLastError() ) );
  1056. }
  1057. if( !GetOverlappedResult( _hFile, &_ovlp, pcbWritten, TRUE) )
  1058. nffChk( HRESULT_FROM_WIN32( GetLastError() ) );
  1059. nffDebug(( DEB_ITRACE | DEB_INFO,
  1060. "SyncWriteAtFile() wrote 0x%x bytes.\n", *pcbWritten ));
  1061. EH_Err:
  1062. return sc;
  1063. }
  1064. //+----------------------------------------------------------------------------
  1065. //
  1066. // CNtfsStream Non-Interface::MarkStreamAux
  1067. //
  1068. //+----------------------------------------------------------------------------
  1069. HRESULT
  1070. CNtfsStream::MarkStreamAux( const MARK_HANDLE_INFO& mhi )
  1071. {
  1072. nffDebug(( DEB_INFO | DEB_STATCTRL | DEB_ITRACE,
  1073. "MarkStreamAux() hdl=%x, stream='%ws'\n", _hFile, _pwcsName ));
  1074. return MarkFileHandleAux( _hFile, mhi );
  1075. }
  1076. //+----------------------------------------------------------------------------
  1077. //
  1078. // CNtfsStream Static Non-Interface::MarkFileHandleAux
  1079. //
  1080. //+----------------------------------------------------------------------------
  1081. HRESULT
  1082. CNtfsStream::MarkFileHandleAux(
  1083. HANDLE hFile,
  1084. const MARK_HANDLE_INFO& mhi )
  1085. {
  1086. nffITrace( "CNtfsStream::MarkStreamAux" );
  1087. HRESULT sc=S_OK;
  1088. ULONG cbReturned;
  1089. if( INVALID_HANDLE_VALUE == hFile )
  1090. {
  1091. nffDebug(( DEB_IWARN, "CNtfsStream::MarkStreamAux on hFile == -1\n" ));
  1092. return S_OK;
  1093. }
  1094. nffAssert( USN_SOURCE_AUXILIARY_DATA == mhi.UsnSourceInfo);
  1095. nffDebug(( DEB_STATCTRL | DEB_ITRACE,
  1096. "MarkFileHandleAux hdl=%x\n", hFile ));
  1097. nffBool( DeviceIoControl( hFile,
  1098. FSCTL_MARK_HANDLE,
  1099. (void*)&mhi, sizeof(mhi),
  1100. NULL, 0,
  1101. &cbReturned,
  1102. NULL ) );
  1103. EH_Err:
  1104. return sc;
  1105. }
  1106. //+----------------------------------------------------------------------------
  1107. //
  1108. // CNtfsStream Non-Interface::SetStreamTime
  1109. //
  1110. //+----------------------------------------------------------------------------
  1111. HRESULT
  1112. CNtfsStream::SetStreamTime( const FILETIME* pctime,
  1113. const FILETIME* patime,
  1114. const FILETIME* pmtime)
  1115. {
  1116. nffDebug((DEB_INFO | DEB_STATCTRL | DEB_ITRACE,
  1117. "SetStreamTime() hdl=%x, stream='%ws'\n",
  1118. _hFile, _pwcsName ));
  1119. return SetFileHandleTime( _hFile, pctime, patime, pmtime );
  1120. }
  1121. //+----------------------------------------------------------------------------
  1122. //
  1123. // CNtfsStream Static Non-Interface::SetFileHandleTime
  1124. //
  1125. //+----------------------------------------------------------------------------
  1126. HRESULT
  1127. CNtfsStream::SetFileHandleTime( HANDLE hFile,
  1128. const FILETIME* pctime,
  1129. const FILETIME* patime,
  1130. const FILETIME* pmtime)
  1131. {
  1132. HRESULT sc=S_OK;
  1133. if( INVALID_HANDLE_VALUE == hFile )
  1134. {
  1135. nffDebug(( DEB_IWARN, "CNtfsStream::SetFileHandleTime on hFile == -1\n" ));
  1136. return S_OK;
  1137. }
  1138. nffDebug(( DEB_STATCTRL | DEB_ITRACE,
  1139. "SetFileHandleTime(%p %p %p) hdl=%x\n",
  1140. pctime, patime, pmtime, hFile ));
  1141. nffBool( ::SetFileTime( hFile, pctime, patime, pmtime ) );
  1142. EH_Err:
  1143. return sc;
  1144. }
  1145. #if DBG
  1146. HRESULT STDMETHODCALLTYPE
  1147. CNtfsStream::UseNTFS4Streams( BOOL fUseNTFS4Streams )
  1148. {
  1149. return( _nffMappedStream.UseNTFS4Streams( fUseNTFS4Streams ));
  1150. }
  1151. #endif // #if DBG
  1152. #if DBG
  1153. HRESULT STDMETHODCALLTYPE
  1154. CNtfsStream::GetFormatVersion(WORD *pw)
  1155. {
  1156. return( E_NOTIMPL );
  1157. }
  1158. #endif // #if DBG
  1159. #if DBG
  1160. HRESULT STDMETHODCALLTYPE
  1161. CNtfsStream::SimulateLowMemory( BOOL fSimulate )
  1162. {
  1163. return( _nffMappedStream.SimulateLowMemory( fSimulate ));
  1164. }
  1165. #endif // #if DBG
  1166. #if DBG
  1167. HRESULT STDMETHODCALLTYPE
  1168. CNtfsStream::GetLockCount()
  1169. {
  1170. return( NULL == _pnffstg ? 0 : _pnffstg->GetLockCount() );
  1171. }
  1172. #endif // #if DBG
  1173. #if DBG
  1174. HRESULT STDMETHODCALLTYPE
  1175. CNtfsStream::IsDirty()
  1176. {
  1177. return( E_NOTIMPL );
  1178. }
  1179. #endif // #if DBG