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.

3274 lines
88 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) IStorage implementation.
  9. //
  10. // History:
  11. // 5/6/98 MikeHill
  12. // - Use CoTaskMem rather than new/delete.
  13. // - Split the Init method into two methods, one which is
  14. // file name based and the other which is handle based.
  15. // 5/18/98 MikeHill
  16. // - Use the cleaned up CPropertySetStorage & CPropertyBagEx
  17. // constructors.
  18. //
  19. //+============================================================================
  20. #include <pch.cxx>
  21. #include "expparam.hxx"
  22. #define UNSUPPORTED_STGM_BITS ( STGM_CONVERT | \
  23. STGM_TRANSACTED | \
  24. STGM_PRIORITY | \
  25. STGM_SIMPLE | \
  26. STGM_DELETEONRELEASE )
  27. WCHAR GetDriveLetter (WCHAR const *pwcsName);
  28. BOOL IsDataStream( const PFILE_STREAM_INFORMATION pFileStreamInformation );
  29. //-----------------------------------------------------------
  30. //
  31. // NFFOpen();
  32. //
  33. // Routine for the rest of Storage to use to open NFF files
  34. // without knowing a lot of details.
  35. //
  36. //-----------------------------------------------------------
  37. HRESULT
  38. NFFOpen(const WCHAR *pwcsName,
  39. DWORD grfMode,
  40. DWORD dwFlags,
  41. BOOL fCreateAPI,
  42. REFIID riid,
  43. void **ppv)
  44. {
  45. CNtfsStorage* pnffstg=NULL;
  46. IUnknown *punk=NULL;
  47. HRESULT sc=S_OK;
  48. nffDebug(( DEB_TRACE | DEB_INFO | DEB_OPENS,
  49. "NFFOpen(\"%ws\", %x, %x, &iid=%x, %x)\n",
  50. pwcsName, grfMode, fCreateAPI, &riid, ppv));
  51. // Parameter validation
  52. if( 0 != ( grfMode & UNSUPPORTED_STGM_BITS ) )
  53. nffErr( EH_Err, STG_E_INVALIDFLAG );
  54. // We don't support Write only storage (yet)
  55. if( STGM_WRITE == (grfMode & STGM_RDWR_MASK) )
  56. nffErr( EH_Err, STG_E_INVALIDFLAG );
  57. // Instantiate and initialize a CNtfsStorage for this file.
  58. nffMem( pnffstg = new CNtfsStorage( grfMode ));
  59. nffChk( pnffstg->InitFromName( pwcsName, fCreateAPI, dwFlags ) );
  60. nffChk( pnffstg->QueryInterface( riid, (void**)&punk ) );
  61. *ppv = punk;
  62. punk = NULL;
  63. EH_Err:
  64. RELEASE_INTERFACE( pnffstg );
  65. RELEASE_INTERFACE( punk );
  66. // Compatibilty with Docfile: Multiple opens with incompatible
  67. // STGM_ modes returns LOCK vio not SHARE vio. We use file SHARE'ing
  68. // Docfile used file LOCK'ing.
  69. if(STG_E_SHAREVIOLATION == sc)
  70. sc = STG_E_LOCKVIOLATION;
  71. nffDebug(( DEB_TRACE, "NFFOpen() sc=%x\n", sc ));
  72. return(sc);
  73. }
  74. //+----------------------------------------------------------------------------
  75. //
  76. // Function: NFFOpenOnHandle
  77. //
  78. // Create or open an NFF IStorage (or QI-able interface) on a given
  79. // handle.
  80. //
  81. //+----------------------------------------------------------------------------
  82. HRESULT
  83. NFFOpenOnHandle( BOOL fCreateAPI,
  84. DWORD grfMode,
  85. DWORD stgfmt,
  86. HANDLE* phStream,
  87. REFIID riid,
  88. void ** ppv)
  89. {
  90. HRESULT sc=S_OK;
  91. CNtfsStorage *pnffstg=NULL;
  92. IUnknown *punk=NULL;
  93. nffDebug(( DEB_TRACE | DEB_INFO | DEB_OPENS,
  94. "NFFOpenOnHandle(%x, %x, %x, %x, &iid=%x, %x)\n",
  95. fCreateAPI, grfMode, stgfmt, *phStream, &riid, ppv));
  96. // Parameter validation
  97. if( 0 != ( grfMode & UNSUPPORTED_STGM_BITS ) )
  98. nffErr( EH_Err, STG_E_INVALIDFLAG );
  99. // We don't currently support create here.
  100. if( fCreateAPI )
  101. nffErr( EH_Err, STG_E_INVALIDPARAMETER );
  102. // Instantiate and initialize a CNtfsStorage on this handle
  103. nffMem( pnffstg = new CNtfsStorage( grfMode ));
  104. nffChk( pnffstg->InitFromMainStreamHandle( phStream,
  105. NULL,
  106. fCreateAPI,
  107. NFFOPEN_NORMAL,
  108. stgfmt ) );
  109. nffAssert( INVALID_HANDLE_VALUE == *phStream );
  110. nffChk( pnffstg->QueryInterface( riid, (void**)&punk ) );
  111. *ppv = punk;
  112. punk = NULL;
  113. EH_Err:
  114. RELEASE_INTERFACE(pnffstg);
  115. RELEASE_INTERFACE(punk);
  116. return( sc );
  117. } // OpenNFFOnHandle
  118. //+----------------------------------------------------------------------------
  119. //
  120. // CNtfsStorage IUnknown::QueryInterface
  121. //
  122. //+----------------------------------------------------------------------------
  123. HRESULT
  124. CNtfsStorage::QueryInterface(
  125. REFIID riid,
  126. void ** ppvObject
  127. )
  128. {
  129. nffXTrace( "CNtfsStorage::QueryInterface" );
  130. HRESULT sc = S_OK;
  131. // Parameter validation
  132. NFF_VALIDATE( QueryInterface( riid, ppvObject ) );
  133. // Check for the known interfaces
  134. if( IID_IStorage == riid )
  135. {
  136. nffDebug(( DEB_ERROR, "STGFMT_FILE IID_IStorage is not supported\n" ));
  137. return E_NOINTERFACE;
  138. }
  139. else if( IID_IPropertySetStorage == riid || IID_IUnknown == riid )
  140. {
  141. *ppvObject = static_cast<IPropertySetStorage*>(this);
  142. AddRef();
  143. }
  144. else if( IID_IBlockingLock == riid )
  145. {
  146. *ppvObject = static_cast<IBlockingLock*>(this);
  147. AddRef();
  148. }
  149. else if( IID_ITimeAndNoticeControl == riid )
  150. {
  151. *ppvObject = static_cast<ITimeAndNoticeControl*>(this);
  152. AddRef();
  153. }
  154. else if( IID_IPropertyBagEx == riid )
  155. {
  156. *ppvObject = static_cast<IPropertyBagEx*>(&_PropertyBagEx);
  157. AddRef();
  158. }
  159. else if( IID_IPropertyBag == riid )
  160. {
  161. *ppvObject = static_cast<IPropertyBag*>(&_PropertyBagEx);
  162. AddRef();
  163. }
  164. #if DBG
  165. else if( IID_IStorageTest == riid )
  166. {
  167. *ppvObject = static_cast<IStorageTest*>(this);
  168. AddRef();
  169. }
  170. #endif // #if DBG
  171. else
  172. return E_NOINTERFACE ;
  173. return sc;
  174. }
  175. //+----------------------------------------------------------------------------
  176. //
  177. // CNtfsStorage IUnknown::AddRef
  178. //
  179. //+----------------------------------------------------------------------------
  180. ULONG STDMETHODCALLTYPE
  181. CNtfsStorage::AddRef(void)
  182. {
  183. LONG lRet;
  184. lRet = InterlockedIncrement( &_cReferences );
  185. nffDebug(( DEB_REFCOUNT, "CNtfsStorage::AddRef(this==%x) == %d\n",
  186. this, lRet));
  187. return( lRet );
  188. }
  189. //+----------------------------------------------------------------------------
  190. //
  191. // CNtfsStorage IUnknown::Release
  192. //
  193. //+----------------------------------------------------------------------------
  194. ULONG STDMETHODCALLTYPE
  195. CNtfsStorage::Release(void)
  196. {
  197. LONG lRet;
  198. lRet = InterlockedDecrement( &_cReferences );
  199. if( 0 == lRet )
  200. {
  201. delete this;
  202. }
  203. nffDebug((DEB_REFCOUNT, "CNtfsStorage::Release(this=%x) == %d\n",
  204. this, lRet));
  205. return( lRet );
  206. }
  207. #ifdef OLE2ANSI
  208. #error CNtfsStorage requires OLECHAR to be UNICODE
  209. #endif
  210. //+----------------------------------------------------------------------------
  211. //
  212. // CNtfsStorage IStorage::CreateStream
  213. //
  214. //+----------------------------------------------------------------------------
  215. HRESULT
  216. CNtfsStorage::CreateStream(
  217. const OLECHAR* pwcsName,
  218. DWORD grfMode,
  219. DWORD res1,
  220. DWORD res2,
  221. IStream** ppstm)
  222. {
  223. HRESULT sc=S_OK;
  224. CNtfsStream *pstm = NULL;
  225. CNtfsStream *pstmPrevious = NULL;
  226. //
  227. // Prop code passed streams names with DOCF_ UPDR_ prefix and are too long.
  228. // MikeHill and BChapman agree that the docfile in a stream code should
  229. // be moved into this object's (currenly unimplemented) CreateStorage.
  230. // So for the moment since this IStorage is not exposed, we will remove
  231. // the parameter validation.
  232. //
  233. // NFF_VALIDATE( CreateStream( pwcsName, grfMode, res1, res2, ppstm ) );
  234. Lock( INFINITE );
  235. // Ensure we're not in the reverted state
  236. nffChk( CheckReverted() );
  237. nffDebug(( DEB_INFO | DEB_OPENS | DEB_TRACE,
  238. "CreateStream(\"%ws\", %x)\n", pwcsName, grfMode));
  239. // We don't support convert
  240. if( STGM_CONVERT & grfMode )
  241. nffErr( EH_Err, STG_E_INVALIDFLAG );
  242. // Is this tream already opened?
  243. if( FindAlreadyOpenStream( pwcsName, &pstmPrevious ) )
  244. {
  245. // If the stream is already open then return Access Denied because
  246. // streams are always opened Exclusive. But if we are CREATE'ing
  247. // then revert the old one and make a new one.
  248. if( 0 == (STGM_CREATE & grfMode) )
  249. {
  250. nffErr( EH_Err, STG_E_ACCESSDENIED );
  251. }
  252. else
  253. {
  254. pstmPrevious->ShutDown();
  255. pstmPrevious->Release(); // FindAOS() Addref'ed, so release here
  256. pstmPrevious = NULL;
  257. }
  258. }
  259. // The stream isn't already open, or we blew it away.
  260. // Instantiate a new one.
  261. nffChk( NewCNtfsStream( pwcsName, grfMode, TRUE, &pstm ));
  262. // ------------------
  263. // Set Out Parameters
  264. // ------------------
  265. *ppstm = static_cast<IStream*>(pstm);
  266. pstm = NULL;
  267. EH_Err:
  268. if( NULL != pstm )
  269. pstm->Release();
  270. if( NULL != pstmPrevious )
  271. pstmPrevious->Release();
  272. Unlock();
  273. nffDebug(( DEB_TRACE, "CreateStream() sc=%x\n", sc ));
  274. return( sc );
  275. }
  276. //+----------------------------------------------------------------------------
  277. //
  278. // CNtfsStorage IStorage::OpenStream
  279. //
  280. //+----------------------------------------------------------------------------
  281. HRESULT
  282. CNtfsStorage::OpenStream(
  283. const OLECHAR* pwcsName,
  284. void* res1,
  285. DWORD grfMode,
  286. DWORD res2,
  287. IStream** ppstm)
  288. {
  289. HRESULT sc=S_OK;
  290. CNtfsStream *pstm = NULL;
  291. //
  292. // Prop code passed streams names with DOCF_ UPDR_ prefix and are too long.
  293. // MikeHill and BChapman agree that the docfile in a stream code should
  294. // be moved into this object's (currenly unimplemented) OpenStorage.
  295. // So for the moment since this IStorage is not exposed, we will remove
  296. // the parameter validation.
  297. //
  298. // NFF_VALIDATE( OpenStream( pwcsName, res1, grfMode, res2, ppstm ) );
  299. Lock( INFINITE );
  300. nffChk( CheckReverted() );
  301. nffDebug(( DEB_INFO | DEB_OPENS | DEB_TRACE,
  302. "OpenStream(\"%ws\", grf=0x%x);\n", pwcsName, grfMode ));
  303. // Is this stream already open? If so => error.
  304. if( FindAlreadyOpenStream( pwcsName, &pstm ) )
  305. nffErr( EH_Err, STG_E_ACCESSDENIED );
  306. // Otherwise, open the stream.
  307. nffChk( NewCNtfsStream( pwcsName, grfMode, FALSE, &pstm ));
  308. *ppstm = static_cast<IStream*>(pstm);
  309. pstm = NULL;
  310. EH_Err:
  311. if( NULL != pstm )
  312. pstm->Release();
  313. Unlock();
  314. nffDebug(( DEB_TRACE, "OpenStream() sc=%x\n", sc ));
  315. return( sc );
  316. }
  317. //+----------------------------------------------------------------------------
  318. //
  319. // CNtfsStorage IStorage::CreateStorage
  320. //
  321. //+----------------------------------------------------------------------------
  322. HRESULT
  323. CNtfsStorage::CreateStorage(
  324. const OLECHAR* pwcsName,
  325. DWORD grfMode,
  326. DWORD reserved1,
  327. DWORD reserved2,
  328. IStorage** ppstg)
  329. {
  330. nffXTrace( "CNtfsStorage::CreateStorage" );
  331. // Not supported
  332. return( E_NOTIMPL );
  333. } // CNtfsStorage::CreateStorage
  334. //+----------------------------------------------------------------------------
  335. //
  336. // CNtfsStorage IStorage::OpenStorage
  337. //
  338. //+----------------------------------------------------------------------------
  339. HRESULT CNtfsStorage::OpenStorage(
  340. const OLECHAR* pwcsName,
  341. IStorage* pstgPriority,
  342. DWORD grfMode,
  343. SNB snbExclude,
  344. DWORD reserved,
  345. IStorage** ppstg)
  346. {
  347. nffXTrace( "CNtfsStorage::OpenStorage" );
  348. // Not supported
  349. return( E_NOTIMPL );
  350. } // CNtfsStorage::OpenStorage
  351. //+----------------------------------------------------------------------------
  352. //
  353. // CNtfsStorage IStorage::CopyTo
  354. //
  355. //+----------------------------------------------------------------------------
  356. HRESULT
  357. CNtfsStorage::CopyTo(
  358. DWORD ciidExclude,
  359. const IID* rgiidExclude,
  360. SNB snbExclude,
  361. IStorage* pstgDest)
  362. {
  363. nffXTrace( "CNtfsStorage::CopyTo" );
  364. return E_NOTIMPL;
  365. }
  366. //+----------------------------------------------------------------------------
  367. //
  368. // CNtfsStorage IStorage::MoveElementTo
  369. //
  370. //+----------------------------------------------------------------------------
  371. HRESULT
  372. CNtfsStorage::MoveElementTo(
  373. const OLECHAR* pwcsName,
  374. IStorage* pstgDest,
  375. const OLECHAR* pwcsNewName,
  376. DWORD grfFlags)
  377. {
  378. nffXTrace( "CNtfsStorage::MoveElementTo" );
  379. HRESULT sc=S_OK;
  380. NFF_VALIDATE( MoveElementTo( pwcsName, pstgDest, pwcsNewName, grfFlags ) );
  381. Lock( INFINITE );
  382. nffChk( CheckReverted() );
  383. // MoveElementTo not supported. Use CopyTo and DestroyElement
  384. EH_Err:
  385. Unlock();
  386. return( E_NOTIMPL );
  387. }
  388. //+----------------------------------------------------------------------------
  389. //
  390. // CNtfsStorage IStorage::Commit
  391. //
  392. //+----------------------------------------------------------------------------
  393. HRESULT
  394. CNtfsStorage::Commit( DWORD grfCommitFlags )
  395. {
  396. nffXTrace( "CNtfsStorage::Commit" );
  397. CNtfsStream *pstm = NULL;
  398. HRESULT sc=S_OK;
  399. NFF_VALIDATE( Commit( grfCommitFlags ) );
  400. Lock( INFINITE );
  401. nffChk( CheckReverted() );
  402. // Commit the property bag (stored as a special stream).
  403. nffChk( _PropertyBagEx.Commit( grfCommitFlags ));
  404. // Loop through the open streams and commit (flush) them.
  405. if( NULL != _pstmOpenList ) // Skip the head sentinal;
  406. pstm = _pstmOpenList->_pnffstmNext;
  407. while(NULL != pstm)
  408. {
  409. sc = pstm->Commit ( grfCommitFlags );
  410. if( S_OK != sc )
  411. break;
  412. pstm = pstm->_pnffstmNext;
  413. }
  414. EH_Err:
  415. Unlock();
  416. return( sc );
  417. }
  418. //+----------------------------------------------------------------------------
  419. //
  420. // CNtfsStorage IStorage::Revert
  421. //
  422. //+----------------------------------------------------------------------------
  423. HRESULT
  424. CNtfsStorage::Revert( void )
  425. {
  426. nffXTrace( "CNtfsStorage::Revert" );
  427. // We don't support transactioning, so we must be in direct mode.
  428. // In direct mode, return S_OK on Revert.
  429. return( S_OK );
  430. }
  431. //+----------------------------------------------------------------------------
  432. //
  433. // CNtfsStorage IStorage::EnumElements
  434. //
  435. //+----------------------------------------------------------------------------
  436. HRESULT
  437. CNtfsStorage::EnumElements(
  438. DWORD res1,
  439. void* res2,
  440. DWORD res3,
  441. IEnumSTATSTG** ppenum )
  442. {
  443. nffXTrace( "CNtfsStorage::EnumElements" );
  444. CNtfsEnumSTATSTG *pNtfsEnumSTATSTG = NULL;
  445. HRESULT sc=S_OK;
  446. NFF_VALIDATE( EnumElements( res1, res2, res3, ppenum ) );
  447. Lock( INFINITE );
  448. nffChk( CheckReverted() );
  449. // Create the enumerator
  450. pNtfsEnumSTATSTG = new CNtfsEnumSTATSTG(
  451. static_cast<IBlockingLock*>(_pTreeMutex) );
  452. if( NULL == pNtfsEnumSTATSTG )
  453. {
  454. sc = E_OUTOFMEMORY;
  455. goto EH_Err;
  456. }
  457. // Initialize the enumerator
  458. nffChk( pNtfsEnumSTATSTG->Init( _hFileMainStream ));
  459. // ----
  460. // Exit
  461. // ----
  462. *ppenum = static_cast<IEnumSTATSTG*>(pNtfsEnumSTATSTG);
  463. pNtfsEnumSTATSTG = NULL;
  464. sc = S_OK;
  465. EH_Err:
  466. if( NULL != pNtfsEnumSTATSTG )
  467. delete pNtfsEnumSTATSTG;
  468. Unlock();
  469. return( sc );
  470. } // CNtfsStorage::EnumElements
  471. //+----------------------------------------------------------------------------
  472. //
  473. // CNtfsStorage IStorage::DestroyElement
  474. //
  475. //+----------------------------------------------------------------------------
  476. HRESULT
  477. CNtfsStorage::DestroyElement( const OLECHAR* pwcsName )
  478. {
  479. nffXTrace( "CNtfsStorage::DestroyElement" );
  480. HRESULT sc=S_OK;
  481. NFF_VALIDATE( DestroyElement( pwcsName ) );
  482. Lock( INFINITE );
  483. nffChk( CheckReverted() );
  484. // We don't allow Destroying the CONTENT Stream.
  485. if( IsContentStream( pwcsName ) )
  486. nffErr( EH_Err, STG_E_INVALIDFUNCTION );
  487. nffDebug((DEB_INFO, "CNtfsStorage::DestroyElement(\"%ws\", %x)\n",
  488. pwcsName));
  489. // Try to delete the stream
  490. sc = DestroyStreamElement( pwcsName );
  491. if( STG_E_PATHNOTFOUND == sc || STG_E_FILENOTFOUND == sc )
  492. {
  493. // It didn't exist - delete it as a storage (a storage is
  494. // really a docfile, and the stream name has a "Docf_" prefix).
  495. // ?? Why is this storage logic here? The storage logic is supposed
  496. // to be part of CNtfsStorageForPropSet, and not known here?
  497. sc = DestroyStreamElement( CDocfileStreamName(pwcsName) );
  498. }
  499. nffChk(sc);
  500. // If the stream is already open, revert it.
  501. CNtfsStream *pstm;
  502. if( FindAlreadyOpenStream( pwcsName, &pstm ) ) // revert open stream
  503. {
  504. pstm->ShutDown();
  505. pstm->Release();
  506. }
  507. EH_Err:
  508. Unlock();
  509. return( sc );
  510. }
  511. //+----------------------------------------------------------------------------
  512. //
  513. // CNtfsStorage IStorage::RenameElement
  514. //
  515. //+----------------------------------------------------------------------------
  516. HRESULT
  517. CNtfsStorage::RenameElement(
  518. const OLECHAR* pwcsOldName,
  519. const OLECHAR* pwcsNewName)
  520. {
  521. HRESULT sc=S_OK;
  522. CNtfsStream *pstm = NULL;
  523. nffXTrace( "CNtfsStorage::RenameElement" );
  524. //NFF_VALIDATE( RenameElement( pwcsOldName, pwcsNewName ) );
  525. Lock( INFINITE );
  526. nffChk( CheckReverted() );
  527. // We don't allow Renaming the CONTENT Stream.
  528. if( IsContentStream( pwcsOldName ) )
  529. nffErr( EH_Err, STG_E_INVALIDFUNCTION );
  530. // Get a CNtfsStream for this stream (you have to open it,
  531. // with exclusive access, in order to rename it).
  532. nffChk( NewCNtfsStream( pwcsOldName,
  533. STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  534. FALSE,
  535. &pstm ) );
  536. // Rename it
  537. nffChk( pstm->Rename( pwcsNewName, FALSE ));
  538. nffVerify( 0 == pstm->Release() );
  539. pstm = NULL;
  540. EH_Err:
  541. if( NULL != pstm )
  542. nffVerify( 0 == pstm->Release() );
  543. Unlock();
  544. return( sc );
  545. }
  546. //+----------------------------------------------------------------------------
  547. //
  548. // CNtfsStorage IStorage::SetElementTimes
  549. //
  550. //+----------------------------------------------------------------------------
  551. HRESULT
  552. CNtfsStorage::SetElementTimes(
  553. const OLECHAR* pwcsName,
  554. const FILETIME* pctime,
  555. const FILETIME* patime,
  556. const FILETIME* pmtime)
  557. {
  558. nffXTrace( "CNtfsStorage::SetElementTimes" );
  559. HRESULT sc=S_OK;
  560. NFF_VALIDATE( SetElementTimes( pwcsName, pctime, patime, pmtime ) );
  561. if(NULL != pwcsName)
  562. return S_OK;
  563. Lock ( INFINITE );
  564. nffChk( CheckReverted() );
  565. nffDebug((DEB_INFO, "CNtfsStorage::SetElementTimes(\"%ws\")\n",
  566. pwcsName));
  567. // If user mode code sets the last modified times on a handle,
  568. // then WriteFile()s no longer changes the last modified time
  569. sc = SetAllStreamsTimes(pctime, patime, pmtime);
  570. EH_Err:
  571. Unlock();
  572. return( sc );
  573. }
  574. //+----------------------------------------------------------------------------
  575. //
  576. // CNtfsStorage IStorage::SetClass
  577. //
  578. //+----------------------------------------------------------------------------
  579. HRESULT
  580. CNtfsStorage::SetClass(
  581. REFCLSID clsid)
  582. {
  583. nffXTrace( "CNtfsStorage::SetClass" );
  584. CLSID clsidOld = _clsidStgClass;
  585. HRESULT sc = S_OK;
  586. NFF_VALIDATE( SetClass( clsid ) );
  587. Lock( INFINITE );
  588. nffChk( CheckReverted() );
  589. _clsidStgClass = clsid;
  590. nffChk( WriteControlStream() );
  591. EH_Err:
  592. if (FAILED(sc))
  593. _clsidStgClass = clsidOld;
  594. Unlock();
  595. return( sc );
  596. }
  597. //+----------------------------------------------------------------------------
  598. //
  599. // CNtfsStorage IStorage::SetStateBits
  600. //
  601. //+----------------------------------------------------------------------------
  602. HRESULT
  603. CNtfsStorage::SetStateBits(
  604. DWORD grfStateBits,
  605. DWORD grfMask)
  606. {
  607. // Reserved for future use
  608. return E_NOTIMPL;
  609. }
  610. //+----------------------------------------------------------------------------
  611. //
  612. // CNtfsStorage IStorage::Stat
  613. //
  614. //+----------------------------------------------------------------------------
  615. HRESULT
  616. CNtfsStorage::Stat(
  617. STATSTG *pstatstg,
  618. DWORD grfStatFlag)
  619. {
  620. nffXTrace( "CNtfsStorage::Stat" );
  621. HRESULT sc = S_OK;
  622. BY_HANDLE_FILE_INFORMATION ByHandleFileInformation;
  623. WCHAR* pwszPath=NULL;
  624. STATSTG statstg;
  625. NFF_VALIDATE( Stat( pstatstg, grfStatFlag ) );
  626. statstg.pwcsName = NULL;
  627. Lock( INFINITE );
  628. nffChk( CheckReverted() );
  629. nffDebug((DEB_INFO, "CNtfsStorage::Stat()\n"));
  630. // Does the caller want a name?
  631. if( (STATFLAG_NONAME & grfStatFlag) )
  632. pwszPath = NULL;
  633. else
  634. nffChk( GetFilePath( &pwszPath ) );
  635. // Get the type
  636. statstg.type = STGTY_STORAGE;
  637. // Get the size & times.
  638. if( !GetFileInformationByHandle( _hFileMainStream,
  639. &ByHandleFileInformation ))
  640. {
  641. nffErr( EH_Err, LAST_SCODE );
  642. }
  643. statstg.cbSize.LowPart = ByHandleFileInformation.nFileSizeLow;
  644. statstg.cbSize.HighPart = ByHandleFileInformation.nFileSizeHigh;
  645. statstg.mtime = ByHandleFileInformation.ftLastWriteTime;
  646. statstg.atime = ByHandleFileInformation.ftLastAccessTime;
  647. statstg.ctime = ByHandleFileInformation.ftCreationTime;
  648. statstg.grfLocksSupported = 0; // no locks supported
  649. // Get the STGM modes
  650. statstg.grfMode = _grfMode & ~STGM_CREATE;
  651. // Get the clsid & state bits
  652. statstg.grfStateBits = _dwStgStateBits;
  653. statstg.clsid = _clsidStgClass;
  654. sc = S_OK;
  655. statstg.pwcsName = pwszPath;
  656. pwszPath = NULL;
  657. *pstatstg = statstg;
  658. EH_Err:
  659. if(NULL != pwszPath)
  660. CoTaskMemFree( pwszPath);
  661. Unlock();
  662. return( sc );
  663. }
  664. //+----------------------------------------------------------------------------
  665. //
  666. // CNtfsStorage IBlockingLock::Lock
  667. //
  668. //+----------------------------------------------------------------------------
  669. inline HRESULT
  670. CNtfsStorage::Lock( DWORD dwTimeout )
  671. {
  672. // Don't trace at this level. The noice is too great!
  673. // nffCDbgTrace dbg(DEB_ITRACE, "CNtfsStorage::Lock");
  674. nffAssert( INFINITE == dwTimeout );
  675. if( INFINITE != dwTimeout )
  676. return( E_NOTIMPL );
  677. // If there was an error during Initialize(), we may not have created the tree
  678. // mutex.
  679. if( NULL == _pTreeMutex )
  680. return( E_NOTIMPL );
  681. else
  682. return _pTreeMutex->Lock( dwTimeout );
  683. }
  684. //+----------------------------------------------------------------------------
  685. //
  686. // CNtfsStorage IBlockingLock::Unlock
  687. //
  688. //+----------------------------------------------------------------------------
  689. inline HRESULT
  690. CNtfsStorage::Unlock()
  691. {
  692. // Don't trace at this level. The noice is too great!
  693. // nffCDbgTrace dbg(DEB_ITRACE, "CNtfsStorage::Unlock");
  694. // If there was an error during Initialize(), we may not have created the tree
  695. // mutex.
  696. if( NULL == _pTreeMutex )
  697. return( E_NOTIMPL );
  698. else
  699. return _pTreeMutex->Unlock();
  700. }
  701. //+----------------------------------------------------------------------------
  702. //
  703. // CNtfsStorage ITimeAndNoticeControl::SuppressChanges
  704. //
  705. // This method puts the storage in a state such that the modify timestamp
  706. // is not updated, and
  707. //+----------------------------------------------------------------------------
  708. HRESULT
  709. CNtfsStorage::SuppressChanges(
  710. DWORD res1,
  711. DWORD res2)
  712. {
  713. return E_NOTIMPL;
  714. }
  715. //+----------------------------------------------------------------------------
  716. // End of Interface Methods
  717. // -------------
  718. // Start of C++ Methods.
  719. //+----------------------------------------------------------------------------
  720. //+----------------------------------------------------------------------------
  721. //
  722. // CNtfsStorage Constructor
  723. //
  724. //+----------------------------------------------------------------------------
  725. inline
  726. CNtfsStorage::CNtfsStorage( DWORD grfMode )
  727. : _sig(NTFSSTORAGE_SIG),
  728. CPropertySetStorage( MAPPED_STREAM_QI ),
  729. _PropertyBagEx( grfMode )
  730. {
  731. nffITrace("CNtfsStorage::CNtfsStorage");
  732. _grfMode = grfMode;
  733. _pstmOpenList = NULL;
  734. _hFileMainStream = INVALID_HANDLE_VALUE;
  735. _hFileControlStream = INVALID_HANDLE_VALUE;
  736. _wcDriveLetter = 0;
  737. _dwState = 0;
  738. _hsmStatus = 0;
  739. _dwStgStateBits = 0;
  740. _clsidStgClass = CLSID_NULL;
  741. _pTreeMutex = NULL;
  742. _filetime.dwHighDateTime = 0;
  743. _filetime.dwLowDateTime = 0;
  744. // Finish initialization the property set objects.
  745. _NtfsStorageForPropSetStg.Init( this ); // Not add-refed
  746. CPropertySetStorage::Init( static_cast<IStorage*>(&_NtfsStorageForPropSetStg),
  747. static_cast<IBlockingLock*>(this),
  748. FALSE ); // fControlLifetimes (=> don't addref)
  749. // These are also not add-refed
  750. _PropertyBagEx.Init( static_cast<IPropertySetStorage*>(this),
  751. static_cast<IBlockingLock*>(this) );
  752. };
  753. //+----------------------------------------------------------------------------
  754. //
  755. // CNtfsStorage Non-Interface::IsNffAppropriate
  756. //
  757. // Synopsis: Looks for Control stream and Docfile Header given a filename
  758. //
  759. // Arguments: [pwszName] - Filename.
  760. //
  761. // History: 22-July-98 BChapman Created
  762. // 10-Nov-98 BChapman Added global routine so it can be
  763. // called by code that doesn't include
  764. // CNtfsStorage/CNtfsStream definitions.
  765. //+----------------------------------------------------------------------------
  766. HRESULT IsNffAppropriate( const LPCWSTR pwcsName )
  767. {
  768. return CNtfsStorage::IsNffAppropriate( pwcsName );
  769. }
  770. HRESULT // static
  771. CNtfsStorage::IsNffAppropriate( const LPCWSTR pwcsName )
  772. {
  773. UNICODE_STRING usNtfsName;
  774. LPWSTR pFreeBuffer=NULL;
  775. HANDLE hFile=INVALID_HANDLE_VALUE;
  776. HRESULT sc=S_OK;
  777. if (NULL == pwcsName)
  778. nffErr (EH_Err, STG_E_INVALIDNAME);
  779. if (!RtlDosPathNameToNtPathName_U(pwcsName, &usNtfsName, NULL, NULL))
  780. nffErr(EH_Err, STG_E_INVALIDNAME);
  781. // This buffer will need free'ing later
  782. pFreeBuffer = usNtfsName.Buffer;
  783. // When Checking file state always open the main stream ReadOnly share
  784. // everything. We allow opening Directories.
  785. //
  786. nffChk( OpenNtFileHandle( usNtfsName,
  787. NULL, // No Parent File Handle
  788. STGM_READ | STGM_SHARE_DENY_NONE,
  789. NFFOPEN_NORMAL,
  790. FALSE, // Not a Create API
  791. &hFile ) );
  792. nffChk( IsNffAppropriate( hFile, pwcsName ) );
  793. EH_Err:
  794. if (NULL != pFreeBuffer)
  795. RtlFreeHeap(RtlProcessHeap(), 0, pFreeBuffer);
  796. if( INVALID_HANDLE_VALUE != hFile )
  797. NtClose( hFile );
  798. return( sc );
  799. }
  800. //+----------------------------------------------------------------------------
  801. //
  802. // CNtfsStorage Non-Interface::IsNffAppropriate
  803. //
  804. // Synopsis: Looks for Control stream and Docfile Header given a HFILE
  805. //
  806. // Arguments: [hFile] - readable File Handle to the main stream.
  807. //
  808. // History: 22-July-98 BChapman Created
  809. //+----------------------------------------------------------------------------
  810. HRESULT
  811. CNtfsStorage::IsNffAppropriate( HANDLE hFile,
  812. const WCHAR* wcszPath )
  813. {
  814. PFILE_STREAM_INFORMATION pfsiBuf = NULL;
  815. ULONG cbBuf;
  816. OVERLAPPED olpTemp;
  817. HANDLE ev=NULL;
  818. HRESULT sc=S_OK;
  819. olpTemp.hEvent = NULL;
  820. // Check that we are on NTFS by doing a stream enum.
  821. // This is also useful later when looking for a control stream.
  822. // PERF we should cache the fsi (reload every create or delete)
  823. //
  824. sc = EnumNtStreams( hFile, &pfsiBuf, &cbBuf, TRUE );
  825. if( FAILED(sc) )
  826. {
  827. nffDebug((DEB_IWARN, "EnumNtStreams Failed. Not NTFS.\n" ));
  828. nffErr( EH_Err, STG_E_INVALIDFUNCTION );
  829. }
  830. // If the control stream exists then the file is NFF.
  831. if( IsControlStreamExtant( pfsiBuf ) )
  832. {
  833. // This is a kludge test for nt4-pre-sp4 system over the RDR.
  834. // We don't support NFF on those systems (because they didn't
  835. // allow the '\005' property set name prefix charachter).
  836. nffChk( TestNt4StreamNameBug( pfsiBuf, wcszPath ) );
  837. goto EH_Err; // return S_OK;
  838. }
  839. // Don't read HSM migrated Files.
  840. // If the test fails in any way, assume it is not an HSM file.
  841. //
  842. if( S_OK == IsOfflineFile( hFile ) )
  843. nffErr( EH_Err, STG_E_INCOMPLETE );
  844. // Check that the file is not a Storage File. Docfile and NSS don't
  845. // want this implementation making NTFS streams on their files.
  846. //
  847. // To do this we need to read the main stream.
  848. ZeroMemory( &olpTemp, sizeof(OVERLAPPED) );
  849. // Create the Event for the Overlapped structure.
  850. //
  851. ev = CreateEvent( NULL, // Security Attributes.
  852. TRUE, // Manual Reset Flag.
  853. FALSE, // Inital State = Signaled, Flag.
  854. NULL ); // Name
  855. if( NULL == ev)
  856. nffErr( EH_Err, LAST_SCODE );
  857. olpTemp.hEvent = ev;
  858. // See if this is an NSS
  859. nffChk( StgIsStorageFileHandle( hFile, &olpTemp ) );
  860. if( S_OK == sc )
  861. nffErr (EH_Err, STG_E_INVALIDFUNCTION);
  862. nffAssert(S_FALSE == sc);
  863. // Ensure this isn't NT4-pre-SP4, where we don't
  864. // support NFF (that was before '\005' became a legal
  865. // character in stream names).
  866. nffChk( TestNt4StreamNameBug( pfsiBuf, wcszPath ) );
  867. sc = S_OK;
  868. EH_Err:
  869. if( NULL != pfsiBuf )
  870. delete [] (BYTE *)pfsiBuf;
  871. if( NULL != olpTemp.hEvent )
  872. CloseHandle( olpTemp.hEvent );
  873. return sc;
  874. }
  875. //+----------------------------------------------------------------------------
  876. //
  877. // CNtfsStorage Non-Interface::TestNt4StreamNameBug
  878. //
  879. // Synopsis: Check if a stream with a \005 in the name can be opened.
  880. // This routine added an extra NTCreateFile to the NFF Open
  881. // path. And limits the length of the filename component to
  882. // MAX_PATH - StrLen(PropSetName(). This routine should be
  883. // eliminated as soon as NT4 Sp3 is history.
  884. // The bug this looking for was fixed in nt4 sp4 and Nt5.
  885. //
  886. // Returns: S_OK if the system is working correctly
  887. // STG_E_INVALIDFUNCTION if a \005 stream cannot be opened
  888. //
  889. // Arguments: [pfsiBuf] - Buffer of Enumerated Stream Names.
  890. // [wcszPath] - Full Pathname of file.
  891. //
  892. // History: 12-Oct-98 BChapman Created
  893. //+----------------------------------------------------------------------------
  894. FMTID FMTID_NT4Check = { /* ffc11011-5e3b-11d2-8a3e-00c04f8eedad */
  895. 0xffc11011,
  896. 0x5e3b,
  897. 0x11d2,
  898. {0x8a, 0x3e, 0x00, 0xc0, 0x4f, 0x8e, 0xed, 0xad}
  899. };
  900. HRESULT
  901. CNtfsStorage::TestNt4StreamNameBug(
  902. PFILE_STREAM_INFORMATION pfsiBuf,
  903. const WCHAR* pwcszPath )
  904. {
  905. const WCHAR* pwcszNtStreamName=NULL;
  906. WCHAR* pwszPathBuf=NULL;
  907. int ccBufSize=0;
  908. HANDLE hFile;
  909. UNICODE_STRING usNtfsName;
  910. OBJECT_ATTRIBUTES object_attributes;
  911. IO_STATUS_BLOCK iostatusblock;
  912. ACCESS_MASK accessmask=0;
  913. ULONG ulAttrs=0;
  914. ULONG ulSharing=0;
  915. ULONG ulCreateDisp=0;
  916. ULONG ulCreateOpt = 0;
  917. NTSTATUS status;
  918. HRESULT sc=S_OK;
  919. // If there is no pathname (and in some calling paths there isn't)
  920. // then we can't do the test.
  921. //
  922. if( NULL == pwcszPath )
  923. goto EH_Err; // S_OK
  924. // last ditch optimization to prevent having to do
  925. // the NT4 pre-sp4 stream name bug tests.
  926. //
  927. if( AreAnyNtPropertyStreamsExtant( pfsiBuf ) )
  928. goto EH_Err; // S_OK
  929. //
  930. // OK here is the deal....
  931. // Try to open READONLY a stream that doesn't exist with a \005 in
  932. // the name. If the system supports such stream names then it will
  933. // return filenotfound, on NT4 before sp4 it will return INVALIDNAME.
  934. //
  935. {
  936. CPropSetName psn( FMTID_NT4Check );
  937. CNtfsStreamName nsn( psn.GetPropSetName() );
  938. pwcszNtStreamName = nsn;
  939. //
  940. // Use the NT API so we don't have to worry about the length
  941. // of the name. We have to convert the name while it is less
  942. // than MAX_PATH.
  943. //
  944. if (!RtlDosPathNameToNtPathName_U(pwcszPath, &usNtfsName, NULL, NULL))
  945. nffErr(EH_Err, STG_E_INVALIDNAME);
  946. //
  947. // Build a buffer with the Path + Stream name. Free the
  948. // allocated UNICODE_STRING name and point at the buffer.
  949. //
  950. ccBufSize = usNtfsName.Length/sizeof(WCHAR)+ (ULONG)wcslen(pwcszNtStreamName) + 1;
  951. __try
  952. {
  953. pwszPathBuf = (WCHAR*) alloca( ccBufSize*sizeof(WCHAR) );
  954. }
  955. __except(EXCEPTION_EXECUTE_HANDLER)
  956. {
  957. RtlFreeHeap(RtlProcessHeap(), 0, usNtfsName.Buffer);
  958. nffErr(EH_Err, STG_E_INSUFFICIENTMEMORY);
  959. }
  960. StringCchCopy( pwszPathBuf, ccBufSize, usNtfsName.Buffer );
  961. StringCchCat( pwszPathBuf, ccBufSize, pwcszNtStreamName );
  962. RtlFreeHeap(RtlProcessHeap(), 0, usNtfsName.Buffer);
  963. usNtfsName.Buffer = pwszPathBuf;
  964. usNtfsName.Length = (USHORT) wcslen(pwszPathBuf)*sizeof(WCHAR);
  965. usNtfsName.MaximumLength = (USHORT)(ccBufSize*sizeof(WCHAR));
  966. InitializeObjectAttributes(&object_attributes,
  967. &usNtfsName,
  968. OBJ_CASE_INSENSITIVE,
  969. NULL,
  970. NULL);
  971. nffChk( ModeToNtFlags( STGM_READ|STGM_SHARE_DENY_NONE, 0, FALSE,
  972. &accessmask, &ulAttrs, &ulSharing,
  973. &ulCreateDisp, &ulCreateOpt ) );
  974. status = NtCreateFile( &hFile, accessmask,
  975. &object_attributes, &iostatusblock,
  976. NULL,
  977. ulAttrs, ulSharing,
  978. ulCreateDisp, ulCreateOpt,
  979. NULL, 0);
  980. nffAssert( NULL == hFile && "NFF Property TestNt4StreamNameBug" );
  981. if( NULL != hFile )
  982. CloseHandle( hFile );
  983. // The system doesn't support \005.
  984. //
  985. if( STATUS_OBJECT_NAME_INVALID == status )
  986. {
  987. nffDebug(( DEB_OPENS, "Nt4File: file=(%x) \"%ws\"\n",
  988. pwszPathBuf, pwszPathBuf ));
  989. nffErr( EH_Err, STG_E_INVALIDFUNCTION );
  990. }
  991. // NOT_FOUND is the expected status for good systems.
  992. //
  993. if( STATUS_OBJECT_NAME_NOT_FOUND != status )
  994. {
  995. nffDebug(( DEB_IWARN, "NT4Chk Create Stream status 0x%x\n", status ));
  996. nffErr(EH_Err, STG_E_INVALIDFUNCTION);
  997. }
  998. }
  999. EH_Err:
  1000. return sc;
  1001. }
  1002. //+----------------------------------------------------------------------------
  1003. //
  1004. // CNtfsStorage Non-Interface::IsOfflineFile
  1005. //
  1006. // Synopsis: Check for FILE_ATTRIBUTE_OFFLINE in the file attributes.
  1007. //
  1008. // Returns: S_OK if the file attributes have the bit set.
  1009. // S_FALSE if the file attributes do not have the bit set.
  1010. // E_* if an error occured while accessing the attributes.
  1011. //
  1012. // Arguments: [hFile] - Attribute Readable file handle
  1013. //
  1014. // History: 27-July-98 BChapman Created
  1015. //+----------------------------------------------------------------------------
  1016. HRESULT
  1017. CNtfsStorage::IsOfflineFile( HANDLE hFile )
  1018. {
  1019. HRESULT sc=S_OK;
  1020. NTSTATUS status;
  1021. IO_STATUS_BLOCK iostatblk;
  1022. FILE_BASIC_INFORMATION fbi;
  1023. status = NtQueryInformationFile( hFile,
  1024. &iostatblk,
  1025. (PVOID) &fbi,
  1026. sizeof(FILE_BASIC_INFORMATION),
  1027. FileBasicInformation );
  1028. if( !NT_SUCCESS(status) )
  1029. {
  1030. nffDebug(( DEB_IERROR,
  1031. "Query FileAttributeTagInformation file=%x, failed stat=%x\n",
  1032. hFile, status ));
  1033. nffErr( EH_Err, NtStatusToScode( status ) );
  1034. }
  1035. // If it does not have a reparse tag, it is not HighLatency
  1036. //
  1037. if( 0==( FILE_ATTRIBUTE_OFFLINE & fbi.FileAttributes) )
  1038. {
  1039. sc = S_FALSE;
  1040. goto EH_Err;
  1041. }
  1042. EH_Err:
  1043. return sc;
  1044. }
  1045. //+----------------------------------------------------------------------------
  1046. //
  1047. // CNtfsStorage Non-Interface::InitFromName
  1048. //
  1049. //+----------------------------------------------------------------------------
  1050. HRESULT
  1051. CNtfsStorage::InitFromName(
  1052. const WCHAR *pwcsName,
  1053. BOOL fCreateAPI,
  1054. DWORD dwOpenFlags )
  1055. {
  1056. nffITrace( "CNtfsStorage::Init (name)" );
  1057. HANDLE hFile = INVALID_HANDLE_VALUE;
  1058. UNICODE_STRING usNtfsName;
  1059. WCHAR* pFreeBuffer=NULL;
  1060. DWORD dwTid;
  1061. HRESULT sc=S_OK;
  1062. DWORD fCreateOrNot=0;
  1063. if (!RtlDosPathNameToNtPathName_U(pwcsName, &usNtfsName, NULL, NULL))
  1064. nffErr(EH_Err, STG_E_INVALIDNAME);
  1065. // This buffer will need free'ing later
  1066. pFreeBuffer = usNtfsName.Buffer;
  1067. // Regardless of _grfMode, always open the unnamed stream read-only share
  1068. // everything. We allow opening Directories. We use this handle to
  1069. // dup-open all the other streams.
  1070. //
  1071. if( fCreateAPI && (STGM_CREATE & _grfMode) )
  1072. fCreateOrNot = STGM_CREATE;
  1073. nffChk( OpenNtFileHandle( usNtfsName,
  1074. NULL, // No Parent File Handle
  1075. STGM_READ | STGM_SHARE_DENY_NONE | fCreateOrNot,
  1076. dwOpenFlags,
  1077. fCreateAPI,
  1078. &hFile ) );
  1079. // Cache the drive letter so that in Stat we can compose a
  1080. // complete path name
  1081. _wcDriveLetter = GetDriveLetter( pwcsName );
  1082. nffChk( InitFromMainStreamHandle( &hFile,
  1083. pwcsName,
  1084. fCreateAPI,
  1085. dwOpenFlags,
  1086. STGFMT_ANY ) );
  1087. // hFile now belongs to the object.
  1088. nffAssert( INVALID_HANDLE_VALUE == hFile );
  1089. EH_Err:
  1090. if (NULL != pFreeBuffer)
  1091. RtlFreeHeap(RtlProcessHeap(), 0, pFreeBuffer);
  1092. if( INVALID_HANDLE_VALUE != hFile )
  1093. NtClose( hFile );
  1094. return( sc );
  1095. }
  1096. //+----------------------------------------------------------------------------
  1097. //
  1098. // CNtfsStorage Non-Interface::InitFromMainStreamHandle
  1099. //
  1100. // Synopsis: Opens NFF file from a handle.
  1101. //
  1102. // Arguments: [hFileMainStream] - ReadOnly DenyNone file handle.
  1103. // [fCreateAPI] - Called from a Create API (vs. Open)
  1104. // [fmtKnown] - STGFMT_FILE if IsNffAppropriate has
  1105. // already been called. STGFMT_ANY otherwise
  1106. //
  1107. // History: 05-Jun-98 BChapman Created
  1108. //+----------------------------------------------------------------------------
  1109. HRESULT
  1110. CNtfsStorage::InitFromMainStreamHandle(
  1111. HANDLE* phFileMainStream,
  1112. const WCHAR* wcszPath,
  1113. BOOL fCreateAPI,
  1114. DWORD dwOpenFlags,
  1115. DWORD fmtKnown )
  1116. {
  1117. nffITrace( "CNtfsStorage::InitFromMainStreamHandle(HANDLE)" );
  1118. HRESULT sc = S_OK;
  1119. CNtfsStream* pstmHeadSentinal= NULL;
  1120. CNFFTreeMutex* pTreeMutex = NULL;
  1121. // Check that this file should be opened by NFF.
  1122. // Skip the check if the caller has already figured it out.
  1123. //
  1124. if( STGFMT_FILE != fmtKnown )
  1125. {
  1126. nffChk( IsNffAppropriate( *phFileMainStream, wcszPath ) );
  1127. fmtKnown = STGFMT_FILE;
  1128. }
  1129. //
  1130. // Load the Main Stream Handle here so member functions (below)
  1131. // can use it.
  1132. //
  1133. _hFileMainStream = *phFileMainStream;
  1134. *phFileMainStream = INVALID_HANDLE_VALUE;
  1135. // If requested, suppress changes, starting with the main stream handle
  1136. // we just accepted. All subsequent stream opens/creates (including the
  1137. // Control stream) will be marked similarly.
  1138. //
  1139. if( NFFOPEN_SUPPRESS_CHANGES & dwOpenFlags )
  1140. nffChk( SuppressChanges(1, 0) );
  1141. // Open the ControlPropertySet and place the SHARE MODE locks there
  1142. //
  1143. nffChk( OpenControlStream( fCreateAPI ) );
  1144. // Create a Mutex to Serialize access to the NFF File
  1145. //
  1146. nffMem( pTreeMutex = new CNFFTreeMutex() );
  1147. nffChk( pTreeMutex->Init() );
  1148. // Create an Head Sentinal for the Open Stream List
  1149. //
  1150. nffMem( pstmHeadSentinal = new CNtfsStream( this, pTreeMutex ) );
  1151. // Success!
  1152. _dwState |= NFF_INIT_COMPLETED;
  1153. _pTreeMutex = pTreeMutex;
  1154. pTreeMutex = NULL;
  1155. _pstmOpenList = pstmHeadSentinal;
  1156. pstmHeadSentinal = NULL;
  1157. EH_Err:
  1158. if( NULL != pTreeMutex )
  1159. pTreeMutex->Release();
  1160. if( NULL != pstmHeadSentinal )
  1161. pstmHeadSentinal->Release();
  1162. return( sc );
  1163. }
  1164. //+----------------------------------------------------------------------------
  1165. //
  1166. // CNtfsStorage Destructor
  1167. //
  1168. //+----------------------------------------------------------------------------
  1169. inline
  1170. CNtfsStorage::~CNtfsStorage()
  1171. {
  1172. nffITrace("CNtfsStorage::~CNtfsStorage");
  1173. DWORD rc, hrThread=S_OK;
  1174. HANDLE thread;
  1175. nffDebug(( DEB_REFCOUNT, "~CNtfsStorage\n" ));
  1176. ShutDownStorage();
  1177. if( NULL != _pTreeMutex )
  1178. _pTreeMutex->Release();
  1179. nffAssert( NULL == _pstmOpenList );
  1180. _sig = NTFSSTORAGE_SIGDEL;
  1181. }
  1182. //+----------------------------------------------------------------------------
  1183. //
  1184. // CNtfsStorage Non-Interface::ShutDownStorage
  1185. //
  1186. // Flush data, Close File handle and mark the objects as reverted.
  1187. // This is called when the Oplock Breaks and when the Storage is released.
  1188. // In neither case does the caller hold the tree mutex. So we take it here.
  1189. //
  1190. //+----------------------------------------------------------------------------
  1191. HRESULT
  1192. CNtfsStorage::ShutDownStorage()
  1193. {
  1194. nffITrace( "CNtfsStorage::ShutDownStorage" );
  1195. HRESULT sc, scAccum=S_OK;
  1196. CNtfsStream *pstm = NULL;
  1197. CNtfsStream *pstmNext = NULL;
  1198. ULONG cbBuf;
  1199. Lock( INFINITE );
  1200. if(NFF_FILE_CLOSED & _dwState)
  1201. goto EH_Err;
  1202. _dwState |= NFF_FILE_CLOSED;
  1203. nffDebug(( DEB_INFO, "CNtfsStorage::Shutdown called\n" ));
  1204. // Shut down the property bag (it is initialized in the
  1205. // constructor, so we need to shut it down whether or not
  1206. // we ever completed initialization).
  1207. if( FAILED(sc = _PropertyBagEx.ShutDown() ))
  1208. scAccum = sc;
  1209. // Clean up the tree mutex and open stream list, neither of which
  1210. // will exist unless we're fully initialized.
  1211. if(NFF_INIT_COMPLETED & _dwState)
  1212. {
  1213. nffAssert( NULL != _pstmOpenList );
  1214. // Skip the head sentinal;
  1215. pstm = _pstmOpenList->_pnffstmNext;
  1216. //
  1217. // Shutdown all the streams. If there is a problem, make note of it
  1218. // but continue until all the streams are shutdown.
  1219. //
  1220. while(NULL != pstm)
  1221. {
  1222. // ShutDown will cut itself from the list, so pick up the
  1223. // Next pointer before calling it.
  1224. // Let the streams go loose (don't delete or Release them)
  1225. // the app still holds the reference (the list never had a reference)
  1226. //
  1227. pstmNext = pstm->_pnffstmNext;
  1228. if( FAILED( sc = pstm->ShutDown() ) )
  1229. scAccum = sc;
  1230. pstm = pstmNext;
  1231. }
  1232. // Delete the head sentinal because it is not a stream and the
  1233. // app doesn't have a pointer to it.
  1234. //
  1235. nffAssert( NULL == _pstmOpenList->_pnffstmNext );
  1236. _pstmOpenList->Release();
  1237. _pstmOpenList = NULL;
  1238. }
  1239. // Close down all the handles
  1240. nffDebug(( DEB_OPENS, "Closing Storage w/ _hFileMainStream=%x\n",
  1241. _hFileMainStream ));
  1242. if( INVALID_HANDLE_VALUE != _hFileControlStream )
  1243. {
  1244. CloseHandle( _hFileControlStream );
  1245. _hFileControlStream = INVALID_HANDLE_VALUE;
  1246. }
  1247. if( INVALID_HANDLE_VALUE != _hFileMainStream )
  1248. {
  1249. CloseHandle( _hFileMainStream );
  1250. _hFileMainStream = INVALID_HANDLE_VALUE;
  1251. }
  1252. _dwState |= NFF_REVERTED;
  1253. EH_Err:
  1254. Unlock();
  1255. return scAccum;
  1256. }
  1257. //+----------------------------------------------------------------------------
  1258. //
  1259. // CNtfsStorage Non-Interface::GetStreamHandle
  1260. //
  1261. // This method gets the HANDLE for the named stream.
  1262. // It understands grfModes and RelativeOpens of a main stream handle.
  1263. //
  1264. //+----------------------------------------------------------------------------
  1265. HRESULT
  1266. CNtfsStorage::GetStreamHandle(
  1267. HANDLE *phStream,
  1268. const WCHAR * pwcsName,
  1269. DWORD grfMode,
  1270. BOOL fCreateAPI)
  1271. {
  1272. HANDLE hFileStream = INVALID_HANDLE_VALUE;
  1273. HRESULT sc=S_OK;
  1274. DWORD dwNffOpenFlags=0;
  1275. CNtfsStreamName nsn( pwcsName );
  1276. nffDebug(( DEB_ITRACE | DEB_INFO,
  1277. "GetStreamHandle(\"%ws\", grf=0x%x, %s)\n",
  1278. pwcsName, grfMode, fCreateAPI?"Create":"Open" ));
  1279. Lock( INFINITE );
  1280. if( IsContentStream( pwcsName ) )
  1281. {
  1282. // The content (main) stream always exists
  1283. //
  1284. if( fCreateAPI && !( STGM_CREATE & grfMode ) )
  1285. nffErr( EH_Err, STG_E_FILEALREADYEXISTS );
  1286. // only allow DenyNone mode.
  1287. //
  1288. grfMode &= ~STGM_SHARE_MASK;
  1289. grfMode |= STGM_SHARE_DENY_NONE; // Its is already open for read.
  1290. dwNffOpenFlags |= NFFOPEN_CONTENTSTREAM;
  1291. }
  1292. else // not the content stream
  1293. {
  1294. // Use the given access mode but
  1295. // Use the container's Share mode.
  1296. //
  1297. grfMode &= ~STGM_SHARE_MASK;
  1298. grfMode |= _grfMode & STGM_SHARE_MASK;
  1299. }
  1300. //dwNffOpenFlags |= NFFOPEN_ASYNC;
  1301. sc = OpenNtStream( nsn, // ":name:$DATA"
  1302. grfMode,
  1303. dwNffOpenFlags,
  1304. fCreateAPI,
  1305. &hFileStream );
  1306. #if DBG==1
  1307. if( STG_E_FILENOTFOUND == sc )
  1308. {
  1309. nffDebug(( DEB_IWARN, "GetStreamHandle: stream '%ws' not found\n",
  1310. (const WCHAR*)nsn ));
  1311. goto EH_Err;
  1312. }
  1313. #endif DBG
  1314. nffChk( sc );
  1315. *phStream = hFileStream;
  1316. hFileStream = INVALID_HANDLE_VALUE;
  1317. EH_Err:
  1318. #if DBG==1
  1319. if( S_OK != sc )
  1320. {
  1321. nffDebug(( DEB_OPENS|DEB_INFO,
  1322. "Open on stream '%ws' Failed\n",
  1323. pwcsName ));
  1324. }
  1325. #endif
  1326. if( INVALID_HANDLE_VALUE != hFileStream )
  1327. NtClose( hFileStream );
  1328. Unlock();
  1329. return( sc );
  1330. }
  1331. //+----------------------------------------------------------------------------
  1332. //
  1333. // CNtfsStorage Non-Interface::FindAlreadyOpenStream
  1334. //
  1335. // This routine finds the previously open stream by the given name.
  1336. //
  1337. //+----------------------------------------------------------------------------
  1338. BOOL
  1339. CNtfsStorage::FindAlreadyOpenStream(
  1340. const WCHAR* pwcsName,
  1341. CNtfsStream** ppstm)
  1342. {
  1343. // Skip the head sentinal.
  1344. CNtfsStream *pstm = _pstmOpenList->_pnffstmNext;
  1345. while(NULL != pstm)
  1346. {
  1347. //if( 0 == _wcsicmp(pwcsName, pstm->GetName() ) )
  1348. if( 0 == dfwcsnicmp( pwcsName, pstm->GetName(), -1 ))
  1349. {
  1350. *ppstm = pstm;
  1351. pstm->AddRef();
  1352. return TRUE;
  1353. }
  1354. pstm = pstm->_pnffstmNext;
  1355. }
  1356. return FALSE;
  1357. }
  1358. //+----------------------------------------------------------------------------
  1359. //
  1360. // CNtfsStorage Non-Interface::NewCNtfsStream
  1361. //
  1362. // This method lumps together the three phases of creating a new stream
  1363. // object (Constructor, Filesystem Open, and Object Initialization). And
  1364. // it handles the special case of opening the "already open" CONTENTS stream.
  1365. // This begs the question, why is there three phases.
  1366. // 1) We can't put to much in the constructor because of the inability to
  1367. // return errors.
  1368. // 2) GetStreamHandle and InitCNtfsStream are broken apart because of the
  1369. // the special needs in the Storage::Init routine. It opens the
  1370. // CONTENT stream directly and calls InitCNtfsStream to finish.
  1371. //
  1372. //+----------------------------------------------------------------------------
  1373. HRESULT
  1374. CNtfsStorage::NewCNtfsStream( const WCHAR *pwcsName,
  1375. DWORD grfMode,
  1376. BOOL fCreateAPI,
  1377. CNtfsStream **ppstm )
  1378. {
  1379. HRESULT sc=S_OK;
  1380. HANDLE hStream = INVALID_HANDLE_VALUE;
  1381. CNtfsStream *pstm = NULL;
  1382. Lock( INFINITE );
  1383. nffMem( pstm = new CNtfsStream( this, (IBlockingLock*) _pTreeMutex ) );
  1384. nffChk( GetStreamHandle( &hStream, pwcsName, grfMode, fCreateAPI ) );
  1385. sc = InitCNtfsStream( pstm, hStream, grfMode, pwcsName );
  1386. hStream = INVALID_HANDLE_VALUE; // hStream now belongs the the object.
  1387. nffChk(sc);
  1388. // If we're creating, truncate the stream just in case we opened one
  1389. // that already existed.
  1390. if( fCreateAPI )
  1391. nffChk( pstm->SetSize( CULargeInteger(0) ));
  1392. // Load Out parameters and clear working state
  1393. *ppstm = pstm;
  1394. pstm = NULL;
  1395. EH_Err:
  1396. nffDebug(( DEB_ITRACE | DEB_INFO,
  1397. "NewCNtfsStream() sc=%x. hFile=0x%x\n",
  1398. sc,
  1399. FAILED(sc)?INVALID_HANDLE_VALUE:(*ppstm)->GetFileHandle() ));
  1400. if( INVALID_HANDLE_VALUE != hStream )
  1401. NtClose( hStream );
  1402. if( NULL != pstm )
  1403. pstm->Release();
  1404. Unlock();
  1405. return( sc );
  1406. }
  1407. //+----------------------------------------------------------------------------
  1408. //
  1409. // CNtfsStorage Non-Interface ::DestroyStreamElement
  1410. //
  1411. //+----------------------------------------------------------------------------
  1412. HRESULT
  1413. CNtfsStorage::DestroyStreamElement( const OLECHAR *pwcsName )
  1414. {
  1415. nffXTrace( "CNtfsStorage::DestroyStreamElement" );
  1416. HANDLE hFileStream = INVALID_HANDLE_VALUE;
  1417. HRESULT sc=S_OK;
  1418. Lock( INFINITE );
  1419. nffChk( CheckReverted() );
  1420. nffDebug(( DEB_INFO | DEB_WRITE,
  1421. "CNtfsStorage::DestroyStreamElement('%ws')\n",
  1422. pwcsName));
  1423. // Open the handle with DELETE permissions. Write includes Delete.
  1424. //
  1425. nffChk( OpenNtStream( CNtfsStreamName(pwcsName), // ":name:$Data"
  1426. STGM_WRITE | STGM_SHARE_DENY_NONE, // grfMode
  1427. NFFOPEN_SYNC,
  1428. FALSE, // not CreateAPI
  1429. &hFileStream ) );
  1430. nffChk( CNtfsStream::DeleteStream( &hFileStream ));
  1431. EH_Err:
  1432. if( INVALID_HANDLE_VALUE != hFileStream )
  1433. {
  1434. NtClose( hFileStream );
  1435. }
  1436. Unlock();
  1437. return( sc );
  1438. } // CNtfsStorage::DestroyStreamElement
  1439. //+----------------------------------------------------------------------------
  1440. //
  1441. // CNtfsStorage Non-Interface ::GetFilePath
  1442. // Helper routine for Stat.
  1443. //
  1444. //+----------------------------------------------------------------------------
  1445. HRESULT
  1446. CNtfsStorage::GetFilePath( WCHAR** ppwszPath )
  1447. {
  1448. IO_STATUS_BLOCK IoStatusBlock;
  1449. ULONG cbFileNameInfo = 2*(MAX_PATH+1)+sizeof(FILE_NAME_INFORMATION);
  1450. PFILE_NAME_INFORMATION pFileNameInfo=NULL;
  1451. WCHAR* pwsz=NULL;
  1452. HRESULT sc = E_FAIL;
  1453. NTSTATUS status;
  1454. // Query the handle for the "volume-relative" path. This isn't
  1455. // actually volume-relative (e.g. on a UNC path), it's actually
  1456. // the complete path without the leading "D:" or leading "\".
  1457. pFileNameInfo = (PFILE_NAME_INFORMATION)CoTaskMemAlloc( cbFileNameInfo );
  1458. nffMem( pFileNameInfo );
  1459. // Get the file name
  1460. status = NtQueryInformationFile( _hFileMainStream,
  1461. &IoStatusBlock,
  1462. pFileNameInfo,
  1463. cbFileNameInfo,
  1464. FileNameInformation );
  1465. if( !NT_SUCCESS(status) )
  1466. {
  1467. if( STATUS_BUFFER_OVERFLOW == status )
  1468. nffErr( EH_Err, CO_E_PATHTOOLONG);
  1469. nffErr( EH_Err, NtStatusToScode( status ) );
  1470. }
  1471. if( 0 == pFileNameInfo->FileNameLength )
  1472. nffErr( EH_Err, STG_E_INVALIDHEADER );
  1473. // Allocate and copy this filename for the return.
  1474. //
  1475. int cbFileName;
  1476. int cchPrefix;
  1477. cbFileName = pFileNameInfo->FileNameLength + (sizeof(WCHAR) * 3);
  1478. nffMem( pwsz = (WCHAR*) CoTaskMemAlloc( cbFileName ) );
  1479. // Start with the Drive Letter or "\" for UNC paths
  1480. if (IsCharAlphaW(_wcDriveLetter))
  1481. {
  1482. pwsz[0] = _wcDriveLetter;
  1483. pwsz[1] = L':';
  1484. pwsz[2] = L'\0';
  1485. cchPrefix = 2;
  1486. }
  1487. else
  1488. {
  1489. nffAssert( L'\\' == _wcDriveLetter );
  1490. pwsz[0] = L'\\';
  1491. pwsz[1] = L'\0';
  1492. cchPrefix = 1;
  1493. }
  1494. // Copy in the File Path we got from NT. We have a length and it is
  1495. // not necessarily NULL terminated.
  1496. //
  1497. CopyMemory(&pwsz[cchPrefix],
  1498. &pFileNameInfo->FileName,
  1499. pFileNameInfo->FileNameLength );
  1500. // NULL terminiate the string. Assuming we got the length allocation
  1501. // right, then the NULL just goes at the end.
  1502. //
  1503. pwsz[ cchPrefix + pFileNameInfo->FileNameLength/sizeof(WCHAR) ] = L'\0';
  1504. // Copy the Out Params And Clear the Temporaries.
  1505. *ppwszPath = pwsz;
  1506. pwsz = NULL;
  1507. EH_Err:
  1508. if( NULL != pFileNameInfo )
  1509. CoTaskMemFree( pFileNameInfo );
  1510. if( NULL != pwsz )
  1511. CoTaskMemFree( pwsz );
  1512. return sc;
  1513. }
  1514. BOOL
  1515. CNtfsStorage::IsControlStreamExtant( PFILE_STREAM_INFORMATION pfsiBuf )
  1516. {
  1517. return IsNtStreamExtant( pfsiBuf, CNtfsStreamName( GetControlStreamName() ));
  1518. }
  1519. BOOL
  1520. CNtfsStorage::AreAnyNtPropertyStreamsExtant( PFILE_STREAM_INFORMATION pfsiBuf )
  1521. {
  1522. return FindStreamPrefixInFSI( pfsiBuf, L":\005" );
  1523. }
  1524. //+----------------------------------------------------------------------------
  1525. //
  1526. // CNtfsStorage Non-Interface::OpenControlStream
  1527. //
  1528. // This stream is not a property set at the moment. Because we put one of
  1529. // these on every file and it normally doesn't actually contain _any_ data we
  1530. // feel that the overhead of 88 bytes for an empty PPSet was too great.
  1531. //
  1532. // An important role of the control property set is to the be first stream
  1533. // (after the main stream) to be opened. The share mode of the container is
  1534. // is expressed by the share mode of the control property set stream.
  1535. //
  1536. //+----------------------------------------------------------------------------
  1537. HRESULT
  1538. CNtfsStorage::OpenControlStream( BOOL fCreateAPI )
  1539. {
  1540. nffITrace( "CNtfsStorage::OpenControlPropertySet" );
  1541. HRESULT sc = S_OK;
  1542. HANDLE hFile=INVALID_HANDLE_VALUE;
  1543. NFFCONTROLBITS nffControlBits;
  1544. DWORD cbDidRead=0;
  1545. DWORD grfModeOpen=0;
  1546. CNtfsStreamName ntfsnameControlStream( GetControlStreamName() );
  1547. // We shouldn't be called more than once.
  1548. // But we can handle it correctly here.
  1549. //
  1550. if( INVALID_HANDLE_VALUE != _hFileControlStream )
  1551. goto EH_Err;
  1552. // Add STGM_CREATE flag in the open path (this is an internal only mode
  1553. // that uses NT's OPEN_IF).
  1554. // Don't add it in the Create path because that would mean OverWrite.
  1555. // Don't add it in the ReadOnly case because it would create a stream.
  1556. //
  1557. grfModeOpen = _grfMode;
  1558. if( !fCreateAPI && GrfModeIsWriteable( _grfMode ) )
  1559. grfModeOpen |= STGM_CREATE;
  1560. sc = OpenNtStream( ntfsnameControlStream,
  1561. grfModeOpen,
  1562. NFFOPEN_SYNC,
  1563. fCreateAPI,
  1564. &hFile );
  1565. //
  1566. // If we are a ReadOnly Open, then it is OK to not have a
  1567. // control stream.
  1568. //
  1569. if( STG_E_FILENOTFOUND == sc )
  1570. {
  1571. if( !fCreateAPI && !GrfModeIsWriteable( _grfMode ) )
  1572. {
  1573. sc = S_OK;
  1574. goto EH_Err;
  1575. }
  1576. }
  1577. nffChk(sc);
  1578. // Set buffer to Zero so short reads are OK.
  1579. ZeroMemory(&nffControlBits, sizeof(NFFCONTROLBITS) );
  1580. if( !ReadFile( hFile, &nffControlBits,
  1581. sizeof(nffControlBits), &cbDidRead, NULL) )
  1582. {
  1583. nffErr(EH_Err, LAST_SCODE);
  1584. }
  1585. // Currently we only support version 0 control streams.
  1586. // Note: a zero length stream is a version zero stream.
  1587. //
  1588. if( 0 != nffControlBits.sig)
  1589. nffErr(EH_Err, STG_E_INVALIDHEADER);
  1590. _dwStgStateBits = nffControlBits.bits;
  1591. _clsidStgClass = nffControlBits.clsid;
  1592. _hsmStatus = nffControlBits.hsmStatus;
  1593. _hFileControlStream = hFile;
  1594. hFile = INVALID_HANDLE_VALUE;
  1595. EH_Err:
  1596. if(INVALID_HANDLE_VALUE != hFile)
  1597. NtClose(hFile);
  1598. return( sc );
  1599. } // CNtfsStorage::OpenControlPropertySet
  1600. //+----------------------------------------------------------------------------
  1601. //
  1602. // CNtfsStorage Non-Interface::WriteControlStream
  1603. //
  1604. //+----------------------------------------------------------------------------
  1605. HRESULT
  1606. CNtfsStorage::WriteControlStream()
  1607. {
  1608. NFFCONTROLBITS nffcb;
  1609. LONG cbToWrite=0;
  1610. ULONG cbDidWrite=0;
  1611. HRESULT sc=S_OK;
  1612. nffAssert( INVALID_HANDLE_VALUE != _hFileControlStream );
  1613. nffcb.sig = 0;
  1614. nffcb.hsmStatus = _hsmStatus;
  1615. nffcb.bits = _dwStgStateBits;
  1616. nffcb.clsid = _clsidStgClass;
  1617. // Try to save some space in the file by not writing the CLSID
  1618. // if it is all zeros.
  1619. //
  1620. if( IsEqualGUID(_clsidStgClass, CLSID_NULL) )
  1621. {
  1622. cbToWrite = FIELD_OFFSET(NFFCONTROLBITS, clsid);
  1623. // Assert that clsid is the last thing in the struct.
  1624. nffAssert( sizeof(NFFCONTROLBITS) == cbToWrite+sizeof(CLSID) );
  1625. }
  1626. else
  1627. cbToWrite = sizeof(NFFCONTROLBITS);
  1628. if( -1 == SetFilePointer( _hFileControlStream, 0, NULL, FILE_BEGIN ) )
  1629. nffErr( EH_Err, LAST_SCODE );
  1630. if( !WriteFile( _hFileControlStream,
  1631. &nffcb,
  1632. cbToWrite,
  1633. &cbDidWrite,
  1634. NULL) )
  1635. {
  1636. nffErr(EH_Err, LAST_SCODE);
  1637. }
  1638. EH_Err:
  1639. return sc;
  1640. }
  1641. //+----------------------------------------------------------------------------
  1642. //
  1643. // CNtfsStorage Non-Interface::StreamExists
  1644. // The right way to do this is with enumeration.
  1645. //
  1646. //+----------------------------------------------------------------------------
  1647. HRESULT
  1648. CNtfsStorage::StreamExists( const WCHAR *pwcsName )
  1649. {
  1650. nffITrace( "CNtfsStorage::StreamExists" );
  1651. HANDLE hFileStream = NULL;
  1652. HRESULT sc = S_OK;
  1653. if( IsContentStream( pwcsName ) )
  1654. {
  1655. // The Contents stream always exists
  1656. sc = S_OK;
  1657. }
  1658. else
  1659. {
  1660. sc = OpenNtStream( CNtfsStreamName(pwcsName),
  1661. STGM_READ_ATTRIBUTE | STGM_SHARE_DENY_NONE,
  1662. NFFOPEN_NORMAL,
  1663. FALSE, // Not a create API.
  1664. &hFileStream);
  1665. if( S_OK == sc )
  1666. {
  1667. NtClose( hFileStream );
  1668. }
  1669. else
  1670. sc = S_FALSE;
  1671. }
  1672. return sc;
  1673. }
  1674. //+----------------------------------------------------------------------------
  1675. //
  1676. // CNtfsStorage Non-Interface::SetAllStreamsTimes
  1677. //
  1678. //+----------------------------------------------------------------------------
  1679. HRESULT
  1680. CNtfsStorage::SetAllStreamsTimes(
  1681. const FILETIME *pctime,
  1682. const FILETIME *patime,
  1683. const FILETIME *pmtime)
  1684. {
  1685. HRESULT sc=S_OK;
  1686. HRESULT scAccum=S_OK;
  1687. CNtfsStream *pstm = NULL;
  1688. nffDebug(( DEB_INFO | DEB_STATCTRL | DEB_ITRACE,
  1689. "CNtfsStorage::SetAllStreamsTimes()\n" ));
  1690. // Set the time on the main control stream.
  1691. if( INVALID_HANDLE_VALUE != _hFileControlStream )
  1692. {
  1693. sc = CNtfsStream::SetFileHandleTime( _hFileControlStream,
  1694. pctime, patime, pmtime );
  1695. if( S_OK != sc )
  1696. scAccum = sc;
  1697. }
  1698. // We don't set time stamps on _hFileMainStream and _hFileOplock
  1699. // Because they are readonly. (and _hFileOplock is not always open)
  1700. // Now set the time on any CNtfsStream objects we have open.
  1701. if( NULL != _pstmOpenList ) // Skip the head sentinal;
  1702. pstm = _pstmOpenList->_pnffstmNext;
  1703. while(NULL != pstm)
  1704. {
  1705. sc = pstm->SetStreamTime( pctime, patime, pmtime );
  1706. if( S_OK != sc )
  1707. scAccum = sc;
  1708. pstm = pstm->_pnffstmNext;
  1709. }
  1710. return scAccum;
  1711. }
  1712. //+----------------------------------------------------------------------------
  1713. //
  1714. // CNtfsStorage Non-Interface::InitCNtfsStream
  1715. //
  1716. // Create and Init an CNtfsStream Object.
  1717. //
  1718. //+----------------------------------------------------------------------------
  1719. HRESULT
  1720. CNtfsStorage::InitCNtfsStream(
  1721. CNtfsStream *pstm,
  1722. HANDLE hStream,
  1723. DWORD grfMode,
  1724. const WCHAR * pwcsName )
  1725. {
  1726. nffITrace("CNtfsStorage::InitCNtfsStream");
  1727. HRESULT sc=S_OK;
  1728. // Attach the File Stream to the Stream Object
  1729. nffChk( pstm->Init( hStream, grfMode, pwcsName, _pstmOpenList ) );
  1730. sc = S_OK;
  1731. EH_Err:
  1732. return sc;
  1733. }
  1734. //+----------------------------------------------------------------------------
  1735. //
  1736. // CNtfsStorage Non-Interface::ModeToNtFlags
  1737. //
  1738. //+----------------------------------------------------------------------------
  1739. HRESULT
  1740. CNtfsStorage::ModeToNtFlags(DWORD grfMode,
  1741. DWORD dwFlags,
  1742. BOOL fCreateAPI,
  1743. ACCESS_MASK *pam,
  1744. ULONG *pulAttributes,
  1745. ULONG *pulSharing,
  1746. ULONG *pulCreateDisposition,
  1747. ULONG *pulCreateOptions)
  1748. {
  1749. SCODE sc=S_OK;
  1750. nffDebug((DEB_ITRACE, "In ModeToNtFlags("
  1751. "%lX, %d %d, %p, %p, %p, %p, %p)\n",
  1752. grfMode, dwFlags, fCreateAPI, pam,
  1753. pulAttributes, pulSharing,
  1754. pulCreateDisposition, pulCreateOptions));
  1755. *pam = 0;
  1756. *pulAttributes = 0;
  1757. *pulSharing = 0;
  1758. *pulCreateDisposition = 0;
  1759. *pulCreateOptions = 0;
  1760. switch(grfMode & (STGM_READ | STGM_WRITE | STGM_READWRITE | STGM_READ_ATTRIBUTE))
  1761. {
  1762. case STGM_READ:
  1763. *pam = FILE_GENERIC_READ;
  1764. break;
  1765. case STGM_WRITE:
  1766. *pam = FILE_GENERIC_WRITE;
  1767. if( 0 == (NFFOPEN_CONTENTSTREAM & dwFlags) )
  1768. *pam |= DELETE;
  1769. break;
  1770. case STGM_READWRITE:
  1771. *pam = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
  1772. if( 0 == (NFFOPEN_CONTENTSTREAM & dwFlags) )
  1773. *pam |= DELETE;
  1774. break;
  1775. case STGM_READ_ATTRIBUTE:
  1776. *pam = FILE_READ_ATTRIBUTES;
  1777. break;
  1778. default:
  1779. nffErr(EH_Err, STG_E_INVALIDFLAG);
  1780. break;
  1781. }
  1782. *pam |= SYNCHRONIZE;
  1783. switch(grfMode & (STGM_SHARE_DENY_NONE | STGM_SHARE_DENY_READ |
  1784. STGM_SHARE_DENY_WRITE | STGM_SHARE_EXCLUSIVE))
  1785. {
  1786. case STGM_SHARE_DENY_READ:
  1787. *pulSharing = FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  1788. break;
  1789. case STGM_SHARE_DENY_WRITE:
  1790. *pulSharing = FILE_SHARE_READ;
  1791. break;
  1792. case STGM_SHARE_EXCLUSIVE:
  1793. *pulSharing = 0;
  1794. break;
  1795. case STGM_SHARE_DENY_NONE:
  1796. case 0:
  1797. *pulSharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  1798. break;
  1799. default:
  1800. nffErr(EH_Err, STG_E_INVALIDFLAG);
  1801. break;
  1802. }
  1803. switch(grfMode & (STGM_CREATE | STGM_FAILIFTHERE | STGM_CONVERT))
  1804. {
  1805. case STGM_CREATE:
  1806. if (fCreateAPI)
  1807. *pulCreateDisposition = FILE_OVERWRITE_IF;
  1808. else
  1809. *pulCreateDisposition = FILE_OPEN_IF; // Illegal but used internaly
  1810. break;
  1811. case STGM_FAILIFTHERE: // this is a 0 flag
  1812. if (fCreateAPI)
  1813. *pulCreateDisposition = FILE_CREATE;
  1814. else
  1815. *pulCreateDisposition = FILE_OPEN;
  1816. break;
  1817. case STGM_CONVERT:
  1818. nffDebug(( DEB_ERROR, "STGM_CONVERT illegal flag to NFF" ));
  1819. nffErr(EH_Err, STG_E_INVALIDFLAG);
  1820. break;
  1821. default:
  1822. nffErr(EH_Err, STG_E_INVALIDFLAG);
  1823. break;
  1824. }
  1825. //if( NFFOPEN_SYNC & dwFlags )
  1826. *pulCreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
  1827. *pulAttributes = FILE_ATTRIBUTE_NORMAL;
  1828. sc = S_OK;
  1829. nffDebug((DEB_ITRACE, "Out ModeToNtFlags\n"));
  1830. EH_Err:
  1831. return sc;
  1832. }
  1833. //+----------------------------------------------------------------------------
  1834. //
  1835. // CNtfsStorage Non-Interface::OpenNtStream
  1836. // Used by NFF to open a named stream, relative to an exiting main
  1837. // stream handle.
  1838. //
  1839. //+----------------------------------------------------------------------------
  1840. HRESULT
  1841. CNtfsStorage::OpenNtStream( const CNtfsStreamName& nsnName,
  1842. DWORD grfMode,
  1843. DWORD dwFlags,
  1844. BOOL fCreateAPI,
  1845. HANDLE* phFile )
  1846. {
  1847. UNICODE_STRING usNtfsStreamName;
  1848. RtlInitUnicodeString(&usNtfsStreamName, (const WCHAR*)nsnName);
  1849. return OpenNtFileHandle( usNtfsStreamName,
  1850. _hFileMainStream,
  1851. grfMode,
  1852. dwFlags,
  1853. fCreateAPI,
  1854. phFile);
  1855. }
  1856. //+----------------------------------------------------------------------------
  1857. //
  1858. // CNtfsStorage Non-Interface::OpenNtFileHandle
  1859. // Common sub-code for OpenNtFile and OpenNtStream
  1860. //
  1861. //+----------------------------------------------------------------------------
  1862. HRESULT
  1863. CNtfsStorage::OpenNtFileHandle( const UNICODE_STRING& usNtfsStreamName,
  1864. HANDLE hParent,
  1865. DWORD grfMode,
  1866. DWORD dwFlags,
  1867. BOOL fCreateAPI,
  1868. HANDLE *phFile)
  1869. {
  1870. OBJECT_ATTRIBUTES object_attributes;
  1871. IO_STATUS_BLOCK iostatusblock;
  1872. HANDLE hStream;
  1873. ACCESS_MASK accessmask=0;
  1874. ULONG ulAttrs=0;
  1875. ULONG ulSharing=0;
  1876. ULONG ulCreateDisp=0;
  1877. ULONG ulCreateOpt = 0;
  1878. SCODE sc = S_OK;
  1879. NTSTATUS status = STATUS_SUCCESS;
  1880. nffDebug(( DEB_ITRACE | DEB_OPENS,
  1881. "OpenNtStream(%ws, %p, %lX, %d, %p)\n",
  1882. usNtfsStreamName.Buffer,
  1883. hParent, grfMode,
  1884. fCreateAPI, phFile ));
  1885. InitializeObjectAttributes(&object_attributes,
  1886. (PUNICODE_STRING) &usNtfsStreamName, // cast away const
  1887. OBJ_CASE_INSENSITIVE,
  1888. hParent,
  1889. NULL);
  1890. nffChk( ModeToNtFlags( grfMode, dwFlags, fCreateAPI,
  1891. &accessmask, &ulAttrs, &ulSharing,
  1892. &ulCreateDisp, &ulCreateOpt ) );
  1893. status = NtCreateFile( &hStream, accessmask,
  1894. &object_attributes, &iostatusblock,
  1895. NULL,
  1896. ulAttrs, ulSharing,
  1897. ulCreateDisp, ulCreateOpt,
  1898. NULL, 0);
  1899. if (NT_SUCCESS(status))
  1900. {
  1901. *phFile = hStream;
  1902. sc = S_OK;
  1903. }
  1904. else
  1905. sc = NtStatusToScode(status);
  1906. EH_Err:
  1907. nffDebug(( DEB_ITRACE | DEB_OPENS,
  1908. "OpenNtFileHandle returns hFile=%x sc=%x status=%x\n",
  1909. *phFile, sc, status));
  1910. return sc;
  1911. }
  1912. //////////////////////////////////////////////////////////////////////////
  1913. //
  1914. // CNFFTreeMutex
  1915. //
  1916. //////////////////////////////////////////////////////////////////////////
  1917. //+----------------------------------------------------------------------------
  1918. //
  1919. // CNFFTreeMutex IUnknown::QueryInterface
  1920. //
  1921. //+----------------------------------------------------------------------------
  1922. HRESULT
  1923. CNFFTreeMutex::QueryInterface(
  1924. REFIID riid,
  1925. void ** ppvObject
  1926. )
  1927. {
  1928. //nffITrace( "CNFFTreeMutex::QueryInterface");
  1929. HRESULT sc = S_OK;
  1930. // ----------
  1931. // Validation
  1932. // ----------
  1933. VDATEREADPTRIN( &riid, IID );
  1934. VDATEPTROUT( ppvObject, void* );
  1935. *ppvObject = NULL;
  1936. // -----
  1937. // Query
  1938. // -----
  1939. if( IID_IUnknown == riid || IID_IBlockingLock == riid )
  1940. {
  1941. *ppvObject = static_cast<IBlockingLock*>(this);
  1942. AddRef();
  1943. }
  1944. else
  1945. sc = E_NOINTERFACE;
  1946. return( sc );
  1947. }
  1948. //+----------------------------------------------------------------------------
  1949. //
  1950. // CNFFTreeMutex IUnknown::AddRef
  1951. //
  1952. //+----------------------------------------------------------------------------
  1953. ULONG STDMETHODCALLTYPE
  1954. CNFFTreeMutex::AddRef(void)
  1955. {
  1956. LONG lRet;
  1957. lRet = InterlockedIncrement( &_cRefs );
  1958. nffDebug(( DEB_REFCOUNT, "CNFFTreeMutex::AddRef(this==%x) == %d\n",
  1959. this, lRet));
  1960. return( lRet );
  1961. }
  1962. //+----------------------------------------------------------------------------
  1963. //
  1964. // CNFFTreeMutex IUnknown::Release
  1965. //
  1966. //+----------------------------------------------------------------------------
  1967. ULONG STDMETHODCALLTYPE
  1968. CNFFTreeMutex::Release(void)
  1969. {
  1970. LONG lRet;
  1971. lRet = InterlockedDecrement( &_cRefs );
  1972. if( 0 == lRet )
  1973. delete this;
  1974. nffDebug((DEB_REFCOUNT, "CNFFTreeMutex::Release(this=%x) == %d\n",
  1975. this, lRet));
  1976. return( lRet );
  1977. }
  1978. //+----------------------------------------------------------------------------
  1979. //
  1980. // CNFFTreeMutex IBlockingLock::Lock
  1981. //
  1982. //+----------------------------------------------------------------------------
  1983. inline HRESULT
  1984. CNFFTreeMutex::Lock( DWORD dwTimeout )
  1985. {
  1986. // Don't trace at this level. The noice is too great!
  1987. // nffCDbgTrace dbg(DEB_ITRACE, "CNFFTreeMutex::Lock");
  1988. nffAssert (_fInitialized == TRUE);
  1989. nffAssert( INFINITE == dwTimeout );
  1990. if( INFINITE != dwTimeout )
  1991. return( E_NOTIMPL );
  1992. EnterCriticalSection( &_cs );
  1993. nffDebug(( DEB_ITRACE, "Tree Locked. cnt=%d\n", _cs.RecursionCount ));
  1994. return( S_OK );
  1995. }
  1996. //+----------------------------------------------------------------------------
  1997. //
  1998. // CNFFTreeMutex IBlockingLock::Unlock
  1999. //
  2000. //+----------------------------------------------------------------------------
  2001. inline HRESULT
  2002. CNFFTreeMutex::Unlock()
  2003. {
  2004. // Don't trace at this level. The noice is too great!
  2005. //nffCDbgTrace dbg(DEB_ITRACE, "CNFFTreeMutex::Unlock");
  2006. nffAssert (_fInitialized == TRUE);
  2007. LeaveCriticalSection( &_cs );
  2008. nffDebug(( DEB_ITRACE, "Tree Unlocked. cnt=%d\n", _cs.RecursionCount ));
  2009. return( S_OK );
  2010. }
  2011. #if DBG
  2012. LONG
  2013. CNFFTreeMutex::GetLockCount()
  2014. {
  2015. return( _cs.LockCount + 1 );
  2016. }
  2017. #endif // #if DBG
  2018. //////////////////////////////////////////////////////////////////////////
  2019. //
  2020. // CNtfsEnumSTATSTG
  2021. //
  2022. //////////////////////////////////////////////////////////////////////////
  2023. //+----------------------------------------------------------------------------
  2024. //
  2025. // Method: CNtfsEnumSTATSTG::QueryInterface (IUnknown)
  2026. //
  2027. //+----------------------------------------------------------------------------
  2028. HRESULT
  2029. CNtfsEnumSTATSTG::QueryInterface(
  2030. REFIID riid,
  2031. void ** ppvObject
  2032. )
  2033. {
  2034. nffXTrace( "CNtfsEnumSTATSTG::QueryInterface" );
  2035. HRESULT sc = S_OK;
  2036. // ----------
  2037. // Validation
  2038. // ----------
  2039. VDATEREADPTRIN( &riid, IID );
  2040. VDATEPTROUT( ppvObject, void* );
  2041. // -----
  2042. // Query
  2043. // -----
  2044. if( IID_IUnknown == riid || IID_IEnumSTATSTG == riid )
  2045. {
  2046. *ppvObject = static_cast<IEnumSTATSTG*>(this);
  2047. AddRef();
  2048. }
  2049. else
  2050. {
  2051. *ppvObject = NULL;
  2052. sc = E_NOINTERFACE;
  2053. }
  2054. return( sc );
  2055. }
  2056. //+----------------------------------------------------------------------------
  2057. //
  2058. // Method: CNtfsEnumSTATSTG::AddRef (IUnknown)
  2059. //
  2060. //+----------------------------------------------------------------------------
  2061. ULONG
  2062. CNtfsEnumSTATSTG::AddRef(void)
  2063. {
  2064. LONG lRet;
  2065. lRet = InterlockedIncrement( &_cRefs );
  2066. nffDebug(( DEB_REFCOUNT, "CNtfsEnumSTATSTG::AddRef(this==%x) == %d\n",
  2067. this, lRet));
  2068. return( lRet );
  2069. }
  2070. //+----------------------------------------------------------------------------
  2071. //
  2072. // Method: CNtfsEnumSTATSTG::Release (IUnknown)
  2073. //
  2074. //+----------------------------------------------------------------------------
  2075. ULONG
  2076. CNtfsEnumSTATSTG::Release(void)
  2077. {
  2078. LONG lRet;
  2079. lRet = InterlockedDecrement( &_cRefs );
  2080. nffAssert( 0 <= lRet );
  2081. if( 0 == lRet )
  2082. delete this;
  2083. nffDebug((DEB_REFCOUNT, "CNtfsEnumSTATSTG::Release(this=%x) == %d\n",
  2084. this, lRet));
  2085. return( lRet );
  2086. }
  2087. //+----------------------------------------------------------------------------
  2088. //
  2089. // Method: CNtfsEnumSTATSTG::Next (IEnumSTATSTG)
  2090. //
  2091. //+----------------------------------------------------------------------------
  2092. HRESULT STDMETHODCALLTYPE
  2093. CNtfsEnumSTATSTG::Next(ULONG celt, STATSTG *prgstatstg, ULONG *pcFetched)
  2094. {
  2095. nffXTrace( "CNtfsEnumSTATSTG::Next" );
  2096. HRESULT sc = S_OK;
  2097. NFF_VALIDATE( Next(celt, prgstatstg, pcFetched ) );
  2098. if( NULL != pcFetched )
  2099. *pcFetched = 0;
  2100. // Compatibility requires we return S_OK when 0 elements are requested.
  2101. if( 0 == celt )
  2102. return S_OK;
  2103. _pBlockingLock->Lock( INFINITE );
  2104. sc = _pstatstgarray->NextAt( _istatNextToRead, prgstatstg, &celt );
  2105. if( FAILED(sc) ) goto Exit;
  2106. _istatNextToRead += celt;
  2107. if( NULL != pcFetched )
  2108. *pcFetched = celt;
  2109. Exit:
  2110. _pBlockingLock->Unlock();
  2111. return( sc );
  2112. }
  2113. //+----------------------------------------------------------------------------
  2114. //
  2115. // Method: CNtfsEnumSTATSTG::Skip (IEnumSTATSTG)
  2116. //
  2117. //+----------------------------------------------------------------------------
  2118. HRESULT STDMETHODCALLTYPE
  2119. CNtfsEnumSTATSTG::Skip(ULONG celt)
  2120. {
  2121. nffXTrace( "CNtfsEnumSTATSTG::Skip" );
  2122. HRESULT sc = S_OK;
  2123. NFF_VALIDATE( Skip( celt ) );
  2124. _pBlockingLock->Lock( INFINITE );
  2125. // Advance the index, but not past the end of the array
  2126. if( _istatNextToRead + celt > _pstatstgarray->GetCount() )
  2127. {
  2128. _istatNextToRead = _pstatstgarray->GetCount();
  2129. sc = S_FALSE;
  2130. }
  2131. else
  2132. _istatNextToRead += celt;
  2133. _pBlockingLock->Unlock();
  2134. return( sc );
  2135. }
  2136. //+----------------------------------------------------------------------------
  2137. //
  2138. // Method: CNtfsEnumSTATSTG::Reset (IEnumSTATSTG)
  2139. //
  2140. //+----------------------------------------------------------------------------
  2141. HRESULT STDMETHODCALLTYPE
  2142. CNtfsEnumSTATSTG::Reset()
  2143. {
  2144. nffXTrace( "CNtfsEnumSTATSTG::Reset" );
  2145. _pBlockingLock->Lock( INFINITE );
  2146. _istatNextToRead = 0;
  2147. _pBlockingLock->Unlock();
  2148. return( S_OK );
  2149. }
  2150. //+----------------------------------------------------------------------------
  2151. //
  2152. // Method: CNtfsEnumSTATSTG::Clone (IEnumSTATSTG)
  2153. //
  2154. //+----------------------------------------------------------------------------
  2155. HRESULT STDMETHODCALLTYPE
  2156. CNtfsEnumSTATSTG::Clone(IEnumSTATSTG **ppenum)
  2157. {
  2158. nffXTrace( "CNtfsEnumSTATSTG::Clone" );
  2159. HRESULT sc = S_OK;
  2160. NFF_VALIDATE( Clone( ppenum ) );
  2161. _pBlockingLock->Lock( INFINITE );
  2162. CNtfsEnumSTATSTG *pNtfsEnumSTATSTG = new CNtfsEnumSTATSTG(*this);
  2163. if( NULL == pNtfsEnumSTATSTG )
  2164. {
  2165. sc = E_OUTOFMEMORY;
  2166. goto Exit;
  2167. }
  2168. *ppenum = static_cast<IEnumSTATSTG*>(pNtfsEnumSTATSTG);
  2169. pNtfsEnumSTATSTG = NULL;
  2170. Exit:
  2171. _pBlockingLock->Unlock();
  2172. if( NULL != pNtfsEnumSTATSTG )
  2173. delete pNtfsEnumSTATSTG;
  2174. return( sc );
  2175. }
  2176. //+----------------------------------------------------------------------------
  2177. //
  2178. // Method: CNtfsEnumSTATSTG::ReadFileStreamInfo (private)
  2179. //
  2180. // This method reads the FileStreamInformation from the ContentStream. It
  2181. // puts this buffer into a member pointer, for use in Next, etc.
  2182. //
  2183. //+----------------------------------------------------------------------------
  2184. HRESULT
  2185. CNtfsSTATSTGArray::ReadFileStreamInfo( HANDLE hFile )
  2186. {
  2187. nffITrace( "CNtfsStorage::ReadFileStreamInfo" );
  2188. PFILE_STREAM_INFORMATION pStreamInfo=NULL;
  2189. PFILE_STREAM_INFORMATION pFSI=NULL;
  2190. ULONG cbBuffer=0;
  2191. ULONG cStreams=0;
  2192. HRESULT sc=S_OK;
  2193. sc = EnumNtStreams( hFile, &pStreamInfo, &cbBuffer, TRUE );
  2194. if( FAILED(sc) )
  2195. return sc;
  2196. for(pFSI=pStreamInfo ; NULL != pFSI; pFSI=NextFSI( pFSI ) )
  2197. cStreams++;
  2198. _pFileStreamInformation = pStreamInfo;
  2199. _cFileStreamInformation = cStreams;
  2200. return S_OK;
  2201. }
  2202. //+----------------------------------------------------------------------------
  2203. //
  2204. // Method: CNtfsSTATSTGArray::Init (Internal method)
  2205. //
  2206. //+----------------------------------------------------------------------------
  2207. HRESULT
  2208. CNtfsSTATSTGArray::Init( HANDLE hFile )
  2209. {
  2210. nffITrace( "CNtfsSTATSTGArray::Init" );
  2211. HRESULT hr = S_OK;
  2212. DfpAssert( NULL != _pBlockingLock );
  2213. _pBlockingLock->Lock( INFINITE );
  2214. if( NULL != _pFileStreamInformation )
  2215. {
  2216. CoTaskMemFree( _pFileStreamInformation );
  2217. _pFileStreamInformation = NULL;
  2218. _cFileStreamInformation = 0;
  2219. }
  2220. // Snapshot the stream information in _pFileStreamInformation
  2221. hr = ReadFileStreamInfo( hFile );
  2222. if( FAILED(hr) ) goto Exit;
  2223. Exit:
  2224. _pBlockingLock->Unlock();
  2225. return( hr );
  2226. }
  2227. //+----------------------------------------------------------------------------
  2228. //
  2229. // Method: CNtfsSTATSTGArray::NextAt
  2230. //
  2231. //+----------------------------------------------------------------------------
  2232. HRESULT
  2233. CNtfsSTATSTGArray::NextAt( ULONG iNext, STATSTG *prgstatstg, ULONG *pcFetched )
  2234. {
  2235. nffITrace( "CNtfsSTATSTGArray::NextAt" );
  2236. HRESULT sc=S_OK;
  2237. ULONG cFetched=0;
  2238. ULONG cVisibleDataStreams=0;
  2239. PFILE_STREAM_INFORMATION pFSI=NULL;
  2240. const WCHAR* pwName=NULL;
  2241. ULONG cbAlloc=0, cchLength=0;
  2242. _pBlockingLock->Lock( INFINITE );
  2243. // If there is nothing to do skip out early.
  2244. if( iNext >= _cFileStreamInformation )
  2245. {
  2246. sc = S_FALSE;
  2247. *pcFetched = 0;
  2248. goto EH_Err;
  2249. }
  2250. // Loop through the cached stream info in _pFileStreamInformation
  2251. for( pFSI=_pFileStreamInformation; NULL != pFSI; pFSI = NextFSI(pFSI) )
  2252. {
  2253. if( cFetched >= *pcFetched )
  2254. break; // We are done.
  2255. // We only handle data streams
  2256. //
  2257. if( !IsDataStream( pFSI ) )
  2258. continue;
  2259. // We hide some of the streams (like the Control Stream)
  2260. //
  2261. if( IsHiddenStream( pFSI ) )
  2262. {
  2263. continue;
  2264. }
  2265. // We are counting up to the requested streams.
  2266. //
  2267. if( iNext > cVisibleDataStreams++)
  2268. continue;
  2269. // Now lets unmangle the name no memory is allocated yet we just
  2270. // move the pointer past the first ':' and return a shortened length.
  2271. // Must be a $DATA Stream. Also invent "CONTENTS" if necessary.
  2272. // pwName is not null terminated.
  2273. //
  2274. GetNtfsUnmangledNameInfo(pFSI, &pwName, &cchLength);
  2275. // Yes, this is a data stream that we need to return.
  2276. // Allocate a buffer for the stream name in the statstg. If this is
  2277. // the unnamed stream, then we'll return it to the caller with the
  2278. // name "Contents".
  2279. cbAlloc = (cchLength + 1) * sizeof(WCHAR);
  2280. // Allocate memory, copy and null terminate the string from the FSI.
  2281. //
  2282. nffMem( prgstatstg[cFetched].pwcsName = (WCHAR*) CoTaskMemAlloc( cbAlloc ) );
  2283. memcpy( prgstatstg[cFetched].pwcsName, pwName, cchLength*sizeof(WCHAR) );
  2284. prgstatstg[cFetched].pwcsName[ cchLength ] = L'\0';
  2285. // But Wait !!!
  2286. // If this stream is really a non-simple property set, it's actually
  2287. // a docfile, so let's return it as a STGTY_STORAGE, without the
  2288. // name munging.
  2289. if( IsDocfileStream( prgstatstg[cFetched].pwcsName ))
  2290. {
  2291. StringCbCopy( prgstatstg[cFetched].pwcsName,
  2292. cbAlloc,
  2293. UnmangleDocfileStreamName( prgstatstg[cFetched].pwcsName ));
  2294. prgstatstg[cFetched].type = STGTY_STORAGE;
  2295. }
  2296. else
  2297. prgstatstg[cFetched].type = STGTY_STREAM;
  2298. // Fill in the rest of the stream information.
  2299. prgstatstg[cFetched].cbSize.QuadPart = static_cast<ULONGLONG>(pFSI->StreamSize.QuadPart);
  2300. // streams don't support timestamps yet
  2301. prgstatstg[cFetched].mtime = prgstatstg[cFetched].ctime = prgstatstg[cFetched].atime = CFILETIME(0);
  2302. prgstatstg[cFetched].grfMode = 0;
  2303. prgstatstg[cFetched].grfLocksSupported = 0; // no locks supported
  2304. prgstatstg[cFetched].grfStateBits = 0;
  2305. prgstatstg[cFetched].clsid = CLSID_NULL;
  2306. prgstatstg[cFetched].reserved = 0;
  2307. // Advance the index of the next index the caller wants retrieved
  2308. iNext++;
  2309. // Advance the count of entries read
  2310. cFetched++;
  2311. }
  2312. // ----
  2313. // Exit
  2314. // ----
  2315. if( cFetched == *pcFetched )
  2316. sc = S_OK;
  2317. else
  2318. sc = S_FALSE;
  2319. *pcFetched = cFetched;
  2320. EH_Err:
  2321. _pBlockingLock->Unlock();
  2322. return( sc );
  2323. }
  2324. //+----------------------------------------------------------------------------
  2325. //
  2326. // Routine GetDriveLetter
  2327. // Return the drive letter from a path, or '\' for UNC paths.
  2328. //
  2329. //+----------------------------------------------------------------------------
  2330. WCHAR GetDriveLetter (WCHAR const *pwcsName)
  2331. {
  2332. nffITrace( "GetDriveLetter" );
  2333. if( pwcsName == NULL )
  2334. return( L'\0' );
  2335. if( pwcsName[0] != L'\0' )
  2336. {
  2337. if( 0 == dfwcsnicmp( pwcsName, L"\\\\?\\", 4 )
  2338. &&
  2339. pwcsName[4] != L'\0' )
  2340. {
  2341. if( pwcsName[5] == L':' )
  2342. return( pwcsName[4] );
  2343. else if( 0 == dfwcsnicmp( pwcsName, L"\\\\?\\UNC\\", -1 ))
  2344. return( L'\\' );
  2345. }
  2346. if( pwcsName[1] == L':'
  2347. ||
  2348. pwcsName[0] == L'\\' && pwcsName[1] == L'\\' )
  2349. {
  2350. return( pwcsName[0] );
  2351. }
  2352. }
  2353. // No drive letter in pathname, get current drive instead
  2354. WCHAR wcsPath[MAX_PATH];
  2355. NTSTATUS nts = RtlGetCurrentDirectory_U (MAX_PATH*sizeof(WCHAR),wcsPath);
  2356. if (NT_SUCCESS(nts))
  2357. return( wcsPath[0] );
  2358. return( L'\0' );
  2359. };
  2360. #if DBG
  2361. HRESULT STDMETHODCALLTYPE
  2362. CNtfsStorage::UseNTFS4Streams( BOOL fUseNTFS4Streams )
  2363. {
  2364. return( E_NOTIMPL );
  2365. }
  2366. #endif // #if DBG
  2367. #if DBG
  2368. HRESULT STDMETHODCALLTYPE
  2369. CNtfsStorage::GetFormatVersion(WORD *pw)
  2370. {
  2371. return( E_NOTIMPL );
  2372. }
  2373. #endif // #if DBG
  2374. #if DBG
  2375. HRESULT STDMETHODCALLTYPE
  2376. CNtfsStorage::SimulateLowMemory( BOOL fSimulate )
  2377. {
  2378. return( E_NOTIMPL );
  2379. }
  2380. #endif // #if DBG
  2381. #if DBG
  2382. HRESULT STDMETHODCALLTYPE
  2383. CNtfsStorage::GetLockCount()
  2384. {
  2385. return( _pTreeMutex->GetLockCount() );
  2386. }
  2387. #endif // #if DBG
  2388. #if DBG
  2389. HRESULT STDMETHODCALLTYPE
  2390. CNtfsStorage::IsDirty()
  2391. {
  2392. return( E_NOTIMPL );
  2393. }
  2394. #endif // #if DBG
  2395. //+---------------------------------------------------------------------------
  2396. //
  2397. // Function: EnumNtStreams
  2398. //
  2399. // Synopsis: Enumerate NT stream information
  2400. //
  2401. // Arguments: [h] -- Handle to rename
  2402. // [ppfsi] -- buffer to hold stream information
  2403. // [pulBufferSize] -- size of output buffer
  2404. // [fGrow] -- FALSE for fixed size buffer
  2405. //
  2406. // Returns: Appropriate status code
  2407. //
  2408. // Notes :
  2409. //
  2410. // History: 1-Apr-98 HenryLee Created
  2411. //
  2412. //----------------------------------------------------------------------------
  2413. HRESULT EnumNtStreams (HANDLE h,
  2414. FILE_STREAM_INFORMATION ** ppfsi,
  2415. ULONG *pulBufferSize,
  2416. BOOL fGrow)
  2417. {
  2418. HRESULT sc = S_OK;
  2419. NTSTATUS nts;
  2420. IO_STATUS_BLOCK iosb;
  2421. nffAssert (pulBufferSize != NULL);
  2422. ULONG ulStreamInfoSize = 2048;
  2423. FILE_STREAM_INFORMATION *pfsi;
  2424. *ppfsi = NULL;
  2425. *pulBufferSize = 0;
  2426. do
  2427. {
  2428. nffMem (pfsi = (FILE_STREAM_INFORMATION*) new BYTE[ulStreamInfoSize]);
  2429. nts = NtQueryInformationFile(h,
  2430. &iosb,
  2431. (VOID*) pfsi,
  2432. ulStreamInfoSize - sizeof (L'\0'),
  2433. FileStreamInformation
  2434. );
  2435. if ( !NT_SUCCESS(nts) )
  2436. {
  2437. // We failed the call. Free up the previous buffer and set up
  2438. // for another pass with a buffer twice as large
  2439. delete [] (BYTE *)pfsi;
  2440. pfsi = NULL;
  2441. ulStreamInfoSize *= 2;
  2442. }
  2443. if (fGrow == FALSE)
  2444. break;
  2445. } while (nts == STATUS_BUFFER_OVERFLOW || nts == STATUS_BUFFER_TOO_SMALL);
  2446. if (NT_SUCCESS(nts))
  2447. {
  2448. if (iosb.Information == 0) // no data returned
  2449. {
  2450. delete [] (BYTE *) pfsi;
  2451. *ppfsi = NULL;
  2452. *pulBufferSize = 0;
  2453. }
  2454. else
  2455. {
  2456. *ppfsi = pfsi;
  2457. *pulBufferSize = iosb.Status;
  2458. }
  2459. }
  2460. else
  2461. {
  2462. sc = NtStatusToScode(nts);
  2463. }
  2464. EH_Err:
  2465. return sc;
  2466. }
  2467. //+---------------------------------------------------------------------------
  2468. //
  2469. // Function: FindStreamInFSI
  2470. //
  2471. // Synopsis: Find a Stream name in a provided Enumeration Buffer
  2472. //
  2473. // Arguments: [ppfsi] -- buffer that holds the stream enumeration.
  2474. // [pwszNtStreamName] -- Name to look for, in :*:$DATA form.
  2475. //
  2476. // Returns: Pointer to the found element, or NULL otherwise
  2477. //
  2478. //----------------------------------------------------------------------------
  2479. const FILE_STREAM_INFORMATION *
  2480. FindStreamInFSI( IN const FILE_STREAM_INFORMATION *pfsi,
  2481. IN const WCHAR *pwszNtStreamName // In :*:$data format
  2482. )
  2483. {
  2484. ULONG cchLength = (ULONG)wcslen(pwszNtStreamName);
  2485. for( ; NULL != pfsi; pfsi= NextFSI(pfsi) )
  2486. {
  2487. if( cchLength*sizeof(WCHAR) != pfsi->StreamNameLength )
  2488. continue;
  2489. if( 0 == dfwcsnicmp( pwszNtStreamName, pfsi->StreamName, cchLength ))
  2490. break;
  2491. }
  2492. return( pfsi );
  2493. }
  2494. //+---------------------------------------------------------------------------
  2495. //
  2496. // Function: IsStreamPrefixInFSI
  2497. //
  2498. // Synopsis: Find a Stream with the given prefix in a provided
  2499. // Enumeration Buffer
  2500. //
  2501. // Arguments: [ppfsi] -- buffer that holds the stream enumeration.
  2502. // [pwszPrefix] -- Prefix to find.
  2503. //
  2504. // Returns: TRUE if it finds it, FALSE otherwise.
  2505. //
  2506. //----------------------------------------------------------------------------
  2507. BOOL
  2508. FindStreamPrefixInFSI( IN const FILE_STREAM_INFORMATION *pfsi,
  2509. IN const WCHAR *pwszPrefix
  2510. )
  2511. {
  2512. ULONG cchLength = (ULONG)wcslen(pwszPrefix);
  2513. for( ; NULL != pfsi; pfsi= NextFSI(pfsi) )
  2514. {
  2515. if( cchLength*sizeof(WCHAR) > pfsi->StreamNameLength )
  2516. continue;
  2517. if( 0 == dfwcsnicmp( pwszPrefix, pfsi->StreamName, cchLength ))
  2518. return TRUE;
  2519. }
  2520. return FALSE;
  2521. }