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.

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