Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

605 lines
19 KiB

  1. //+============================================================================
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1998.
  5. //
  6. // File: hforpset.cxx
  7. //
  8. // This file provides the definition of the CNtfsStorageForPropSetStg
  9. // class. This class presents an IStorage implementation to the
  10. // CPropertySetStorage implementation of IPropertySetStorage.
  11. // Mostly, this class forwards to CNtfsStorage.
  12. //
  13. // The reason this class exists is because CNtfsStorage (which just
  14. // wraps NTFS) doesn't support storages. This class supports
  15. // storages by creating a docfile in an underlying NTFS stream.
  16. //
  17. // History:
  18. //
  19. // 3/10/98 MikeHill - Factored out common code in the create/open paths.
  20. // 5/18/98 MikeHill
  21. // - Parameter validation in CNtfsStorageForPropSetStg::
  22. // Create/OpenStorage.
  23. // 6/11/98 MikeHill
  24. // - Dbg output, parameter validation.
  25. // - In CreateOrOpenStorage(create), clean up partially
  26. // created stream on error.
  27. //
  28. //+============================================================================
  29. #include <pch.cxx>
  30. #include <expparam.hxx> // CExpParameterValidate
  31. #include <docfilep.hxx>
  32. //+----------------------------------------------------------------------------
  33. //
  34. // Method: CNtfsStorageForPropSetStg::QueryInterface (IUnknown)
  35. //
  36. // This method only allows QI between IStorage & IUnknown. This is the only
  37. // kind of QI that CPropertySetStorage makes.
  38. //
  39. //+----------------------------------------------------------------------------
  40. HRESULT STDMETHODCALLTYPE
  41. CNtfsStorageForPropSetStg::QueryInterface( REFIID riid, void** ppvObject )
  42. {
  43. HRESULT hr = S_OK;
  44. if( IID_IUnknown == riid || IID_IStorage == riid )
  45. {
  46. *ppvObject = static_cast<IStorage*>(this);
  47. AddRef();
  48. hr = S_OK;
  49. }
  50. else
  51. hr = E_NOINTERFACE;
  52. return( hr );
  53. } // CNtfsStorageForPropSetStg::QueryInterface
  54. //+----------------------------------------------------------------------------
  55. //
  56. // Method: CNtfsStorage::CNtfsStorageForPropSetStg delegation methods
  57. //
  58. // These methods all delegate directly to CNtfsStorage's IStorage methods.
  59. //
  60. //+----------------------------------------------------------------------------
  61. ULONG STDMETHODCALLTYPE
  62. CNtfsStorageForPropSetStg::AddRef()
  63. {
  64. return( _pNtfsStorage->AddRef() );
  65. }
  66. ULONG STDMETHODCALLTYPE
  67. CNtfsStorageForPropSetStg::Release()
  68. {
  69. return( _pNtfsStorage->Release() );
  70. }
  71. HRESULT STDMETHODCALLTYPE
  72. CNtfsStorageForPropSetStg::Commit(
  73. /* [in] */ DWORD grfCommitFlags)
  74. {
  75. return( _pNtfsStorage->Commit( grfCommitFlags ));
  76. }
  77. HRESULT STDMETHODCALLTYPE
  78. CNtfsStorageForPropSetStg::Revert( void)
  79. {
  80. return( _pNtfsStorage->Revert() );
  81. }
  82. HRESULT STDMETHODCALLTYPE
  83. CNtfsStorageForPropSetStg::SetElementTimes(
  84. /* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName,
  85. /* [unique][in] */ const FILETIME __RPC_FAR *pctime,
  86. /* [unique][in] */ const FILETIME __RPC_FAR *patime,
  87. /* [unique][in] */ const FILETIME __RPC_FAR *pmtime)
  88. {
  89. return( _pNtfsStorage->SetElementTimes( pwcsName, pctime, patime, pmtime ));
  90. }
  91. HRESULT STDMETHODCALLTYPE
  92. CNtfsStorageForPropSetStg::SetClass(
  93. /* [in] */ REFCLSID clsid)
  94. {
  95. return( _pNtfsStorage->SetClass( clsid ));
  96. }
  97. HRESULT STDMETHODCALLTYPE
  98. CNtfsStorageForPropSetStg::SetStateBits(
  99. /* [in] */ DWORD grfStateBits,
  100. /* [in] */ DWORD grfMask)
  101. {
  102. return( _pNtfsStorage->SetStateBits( grfStateBits, grfMask ));
  103. }
  104. HRESULT STDMETHODCALLTYPE
  105. CNtfsStorageForPropSetStg::Stat(
  106. /* [out] */ STATSTG __RPC_FAR *pstatstg,
  107. /* [in] */ DWORD grfStatFlag)
  108. {
  109. return( _pNtfsStorage->Stat( pstatstg, grfStatFlag ));
  110. }
  111. HRESULT STDMETHODCALLTYPE
  112. CNtfsStorageForPropSetStg::EnumElements(
  113. /* [in] */ DWORD reserved1,
  114. /* [size_is][unique][in] */ void __RPC_FAR *reserved2,
  115. /* [in] */ DWORD reserved3,
  116. /* [out] */ IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum)
  117. {
  118. return( _pNtfsStorage->EnumElements( reserved1, reserved2, reserved3, ppenum ));
  119. }
  120. HRESULT STDMETHODCALLTYPE
  121. CNtfsStorageForPropSetStg::DestroyElement(
  122. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName)
  123. {
  124. return( _pNtfsStorage->DestroyElement( pwcsName ));
  125. }
  126. //+----------------------------------------------------------------------------
  127. //
  128. // Method: CNtfsStorageForPropSetStg noimpl methods
  129. //
  130. // These methods are unused by CPropertySetStorage and left unimplemented.
  131. //
  132. //+----------------------------------------------------------------------------
  133. HRESULT STDMETHODCALLTYPE
  134. CNtfsStorageForPropSetStg::CopyTo(
  135. /* [in] */ DWORD ciidExclude,
  136. /* [size_is][unique][in] */ const IID __RPC_FAR *rgiidExclude,
  137. /* [unique][in] */ SNB snbExclude,
  138. /* [unique][in] */ IStorage __RPC_FAR *pstgDest)
  139. {
  140. return( E_NOTIMPL ); // No need to implement
  141. }
  142. HRESULT STDMETHODCALLTYPE
  143. CNtfsStorageForPropSetStg::MoveElementTo(
  144. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  145. /* [unique][in] */ IStorage __RPC_FAR *pstgDest,
  146. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName,
  147. /* [in] */ DWORD grfFlags)
  148. {
  149. return( E_NOTIMPL ); // Not necessary to implement
  150. }
  151. HRESULT STDMETHODCALLTYPE
  152. CNtfsStorageForPropSetStg::RenameElement(
  153. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsOldName,
  154. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName)
  155. {
  156. return( E_NOTIMPL ); // Not necessary to implement
  157. }
  158. //+----------------------------------------------------------------------------
  159. //
  160. // Method: CNtfsStorageForPropSetStg::CreateStorage (IStorage)
  161. //
  162. // CNtfsStorage doesn't support CreateStorage. For CPropertySetStorage,
  163. // we support it with the special CNtfsStorageForPropStg, which is created
  164. // here.
  165. //
  166. //+----------------------------------------------------------------------------
  167. HRESULT STDMETHODCALLTYPE
  168. CNtfsStorageForPropSetStg::CreateStorage(
  169. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  170. /* [in] */ DWORD grfMode,
  171. /* [in] */ DWORD reserved1,
  172. /* [in] */ DWORD reserved2,
  173. /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
  174. {
  175. HRESULT hr = S_OK;
  176. IStorage * pstg = NULL;
  177. CNtfsStream *pNtfsStream = NULL;
  178. propXTrace( "CNtfsStorageForPropSetStg::CreateStorage" );
  179. _pNtfsStorage->Lock( INFINITE );
  180. // Parameter validation
  181. hr = CExpParameterValidate::CreateStorage( pwcsName, grfMode, reserved1,
  182. reserved2, ppstg );
  183. if( FAILED(hr) ) goto Exit;
  184. // We require STGM_SHARE_EXCLUSIVE
  185. hr = EnforceSingle(grfMode);
  186. if( FAILED(hr) ) goto Exit;
  187. propTraceParameters(( "%ws, 0x%08x, 0x%x, 0x%x, %p",
  188. pwcsName, grfMode, reserved1, reserved2, ppstg ));
  189. // In the underlying CNtfsStorage, we give streams and storages different
  190. // names (storages have a "Docf_" prefix). So we require special
  191. // handling for STGM_CREATE/STGM_FAILIFTHERE - we have to check
  192. // to see if a *stream* (which doesn't have the "Docf_" prefix)
  193. // already exists by that name.
  194. if( STGM_CREATE & grfMode )
  195. {
  196. // Delete any existing stream
  197. hr = _pNtfsStorage->DestroyStreamElement( pwcsName );
  198. if( FAILED(hr) && STG_E_FILENOTFOUND != hr )
  199. {
  200. propDbg(( DEB_ERROR, "Couldn't destroy %s", pwcsName ));
  201. goto Exit;
  202. }
  203. hr = S_OK;
  204. }
  205. else
  206. {
  207. // STGM_FAILIFTHERE
  208. // See if a stream by this name already exists.
  209. hr = _pNtfsStorage->StreamExists( pwcsName );
  210. if( FAILED(hr) ) goto Exit;
  211. if( S_OK == hr )
  212. {
  213. hr = STG_E_FILEALREADYEXISTS;
  214. goto Exit;
  215. }
  216. }
  217. // Create the storage
  218. hr = CreateOrOpenStorage( pwcsName, NULL, grfMode, NULL, TRUE /* fCreate */, &pstg );
  219. if( FAILED(hr) ) goto Exit;
  220. *ppstg = pstg;
  221. pstg = NULL;
  222. Exit:
  223. if( pstg )
  224. pstg->Release();
  225. _pNtfsStorage->Unlock();
  226. if( STG_E_FILEALREADYEXISTS == hr )
  227. propSuppressExitErrors();
  228. return( hr );
  229. } // CNtfsStorageForPropSetStg::CreateStorage
  230. //+----------------------------------------------------------------------------
  231. //
  232. // Method: CNtfsStorageForPropSetStg::OpenStorage (IStorage)
  233. //
  234. // CNtfsStorage doesn't support OpenStorage. For CPropertySetStorage,
  235. // we support it with the special CNtfsStorageForPropStg, which is created
  236. // here.
  237. //
  238. //+----------------------------------------------------------------------------
  239. HRESULT STDMETHODCALLTYPE
  240. CNtfsStorageForPropSetStg::OpenStorage(
  241. /* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName,
  242. /* [unique][in] */ IStorage __RPC_FAR *pstgPriority,
  243. /* [in] */ DWORD grfMode,
  244. /* [unique][in] */ SNB snbExclude,
  245. /* [in] */ DWORD reserved,
  246. /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
  247. {
  248. HRESULT hr = S_OK;
  249. propXTrace( "CNtfsStorageForPropSetStg::OpenStorage" );
  250. // Validate parameters
  251. hr = CExpParameterValidate::OpenStorage( pwcsName, pstgPriority, grfMode,
  252. snbExclude, reserved, ppstg );
  253. if( FAILED(hr) ) goto Exit;
  254. // We only support STGM_SHARE_EXCLUSIVE
  255. hr = EnforceSingle(grfMode);
  256. if( FAILED(hr) ) goto Exit;
  257. propTraceParameters(( "%ws, %p, 0x%08x, %p, 0x%x, %p",
  258. pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg ));
  259. // Try to open the storage
  260. hr = CreateOrOpenStorage( pwcsName, pstgPriority, grfMode, snbExclude,
  261. FALSE /*!fCreate*/, ppstg );
  262. if( FAILED(hr) ) goto Exit;
  263. hr = S_OK;
  264. Exit:
  265. if( STG_E_FILENOTFOUND == hr )
  266. propSuppressExitErrors();
  267. return( hr );
  268. } // CNtfsStorageForPropSetStg::OpenStorage
  269. //+----------------------------------------------------------------------------
  270. //
  271. // CNtfsStorageForPropSetStg::CreateOrOpenStorage
  272. //
  273. // Internal routine to create or open a "storage" (a docfile in an NTFS
  274. // stream).
  275. //
  276. //+----------------------------------------------------------------------------
  277. HRESULT
  278. CNtfsStorageForPropSetStg::CreateOrOpenStorage( const OLECHAR *pwcsName,
  279. IStorage *pstgPriority,
  280. DWORD grfMode,
  281. SNB snbExclude,
  282. BOOL fCreate,
  283. IStorage **ppstg )
  284. {
  285. HRESULT hr = S_OK;
  286. CNtfsStream * pNtfsStream = NULL;
  287. IStorage * pstg = NULL;
  288. BOOL fCreated = FALSE;
  289. propITrace( "CNtfsStorageForPropSetStg::CreateOrOpenStorage" );
  290. propTraceParameters(( "%ws, %p, 0x%08x, %p, %d, %p",
  291. pwcsName, pstgPriority, grfMode, snbExclude, fCreate, ppstg ));
  292. _pNtfsStorage->Lock( INFINITE );
  293. // Compose the stream name (prepend "Docf_" to pwcsName)
  294. CDocfileStreamName docfsn(pwcsName);
  295. const WCHAR* pwcszStreamName = docfsn;
  296. // Open the NTFS stream
  297. if( fCreate )
  298. {
  299. hr = _pNtfsStorage->CreateStream( docfsn, grfMode, 0, 0,
  300. (IStream**)&pNtfsStream );
  301. }
  302. else
  303. {
  304. hr = _pNtfsStorage->OpenStream( docfsn, NULL, grfMode, 0,
  305. (IStream**)&pNtfsStream );
  306. }
  307. if( FAILED(hr) )
  308. goto Exit;
  309. fCreated = TRUE;
  310. // Get the ILockBytes for the NTFS stream, and put a
  311. // docfile on top of it.
  312. hr = CreateOrOpenStorageOnILockBytes( static_cast<ILockBytes*>(pNtfsStream),
  313. NULL, grfMode, NULL, fCreate, &pstg );
  314. if( FAILED(hr) ) goto Exit;
  315. pNtfsStream->Release();
  316. pNtfsStream = NULL;
  317. *ppstg = pstg;
  318. pstg = NULL;
  319. Exit:
  320. if( NULL != pNtfsStream )
  321. pNtfsStream->Release();
  322. if( pstg )
  323. pstg->Release();
  324. // If we fail in the create path, we shouldn't leave behind a corrupt
  325. // docfile. I.e., if NewCNtfsStream succeded but create-on-ilockbyte failed,
  326. // we have an empty stream which cannot be opened.
  327. if( FAILED(hr) && fCreate && fCreated )
  328. _pNtfsStorage->DestroyElement( CDocfileStreamName(pwcsName) );
  329. _pNtfsStorage->Unlock();
  330. if( STG_E_FILENOTFOUND == hr )
  331. propSuppressExitErrors();
  332. return( hr );
  333. }
  334. //+----------------------------------------------------------------------------
  335. //
  336. // Method: CreateOrOpenStorageOnILockBytes
  337. //
  338. // Given an ILockBytes, create or open a docfile. The input grfMode is that
  339. // of the property set, though the docfile may be opened in a different
  340. // mode as appropriate.
  341. //
  342. //+----------------------------------------------------------------------------
  343. HRESULT // static
  344. CNtfsStorageForPropSetStg::CreateOrOpenStorageOnILockBytes( ILockBytes *plkb,
  345. IStorage *pstgPriority,
  346. DWORD grfMode,
  347. SNB snbExclude,
  348. BOOL fCreate,
  349. IStorage **ppstg )
  350. {
  351. HRESULT hr = S_OK;
  352. propITraceStatic( "CNtfsStorageForPropSetStg::CreateOrOpenStorageOnILockBytes" );
  353. propTraceParameters(( "%p, %p, 0x%08x, %p, %d, %p",
  354. plkb, pstgPriority, grfMode, snbExclude, fCreate, ppstg ));
  355. // Create or open the docfile. We use transacted mode because we guarantee that
  356. // NTFS property sets are always atomically updated.
  357. if( fCreate )
  358. {
  359. // We have to force the STGM_CREATE bit to avoid an error. This is OK
  360. // (though the caller might not have set it) because we already handled
  361. // stgm_create/stgm_failifthere in the CreateStorage caller.
  362. hr = StgCreateDocfileOnILockBytes( plkb,
  363. grfMode | STGM_CREATE | STGM_TRANSACTED,
  364. 0, ppstg );
  365. }
  366. else
  367. {
  368. // We only set stgm_transacted if necessary, and we only open deny_write in the
  369. // read-only open case. This is so that we can allow multiple read-only/deny-write
  370. // root opens.
  371. hr = StgOpenStorageOnILockBytes( plkb, pstgPriority,
  372. grfMode & ~STGM_SHARE_MASK
  373. | (GrfModeIsWriteable(grfMode) ? STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED
  374. : STGM_SHARE_DENY_WRITE),
  375. snbExclude, 0, ppstg );
  376. // STG_E_INVALIDHEADER in some paths of the above call gets converted into
  377. // STG_E_FILEALREADYEXISTS, which doesn't make a whole lot of sense
  378. // from our point of view (we already knew it existed, we wanted to open it). So,
  379. // translate it back.
  380. if( STG_E_FILEALREADYEXISTS == hr )
  381. hr = STG_E_INVALIDHEADER;
  382. }
  383. if( FAILED(hr) ) goto Exit;
  384. Exit:
  385. return( hr );
  386. }
  387. //+----------------------------------------------------------------------------
  388. //
  389. // Method: CNtfsStorageForPropSetStg::CreateStream (IStorage)
  390. // CNtfsStorageForPropSetStg::OpenStream (IStorage)
  391. //
  392. // These methods call to the CreateOrOpenStream method to do most of the
  393. // work. CreateStream also needs to do extra work to handle the case where
  394. // a stream/storage is being created, but a storage/stream by that name
  395. // already exists.
  396. //
  397. //+----------------------------------------------------------------------------
  398. HRESULT STDMETHODCALLTYPE
  399. CNtfsStorageForPropSetStg::CreateStream(
  400. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  401. /* [in] */ DWORD grfMode,
  402. /* [in] */ DWORD reserved1,
  403. /* [in] */ DWORD reserved2,
  404. /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
  405. {
  406. HRESULT hr = S_OK;
  407. CDocfileStreamName dsName( pwcsName ); // (Name with pre-pended "Docf_")
  408. propXTrace( "CNtfsStorageForPropSetStg::CreateStream" );
  409. _pNtfsStorage->Lock( INFINITE );
  410. // Parameter validation
  411. hr = CExpParameterValidate::CreateStream( pwcsName, grfMode, reserved1,
  412. reserved2, ppstm );
  413. if( FAILED(hr) ) goto Exit;
  414. // We only support STGM_SHARE_EXCLUSIVE
  415. hr = EnforceSingle(grfMode);
  416. if( FAILED(hr) ) goto Exit;
  417. propTraceParameters(( "%ws, 0x%08x, %x, %x, %p",
  418. pwcsName, grfMode, reserved1, reserved2, ppstm ));
  419. // In the underlying CNtfsStorage, we give streams and storages different
  420. // names (storages have a "Docf_" prefix). So we require special
  421. // handling for STGM_CREATE/STGM_FAILIFTHERE.
  422. if( STGM_CREATE & grfMode )
  423. {
  424. hr = _pNtfsStorage->DestroyStreamElement( dsName );
  425. if( FAILED(hr) && STG_E_FILENOTFOUND != hr )
  426. {
  427. propDbg(( DEB_ERROR, "Couldn't destroy %ws",
  428. static_cast<const WCHAR*>(dsName) ));
  429. goto Exit;
  430. }
  431. hr = S_OK;
  432. }
  433. else
  434. {
  435. // STGM_FAILIFTHERE
  436. hr = _pNtfsStorage->StreamExists( dsName );
  437. if( FAILED(hr) ) goto Exit;
  438. if( S_OK == hr )
  439. {
  440. hr = STG_E_FILEALREADYEXISTS;
  441. goto Exit;
  442. }
  443. }
  444. // Instantiate & initialize the *ppstm.
  445. hr = _pNtfsStorage->CreateStream( pwcsName, grfMode, 0, 0, ppstm );
  446. if( FAILED(hr) ) goto Exit;
  447. Exit:
  448. _pNtfsStorage->Unlock();
  449. if( STG_E_FILEALREADYEXISTS == hr )
  450. propSuppressExitErrors();
  451. return( hr );
  452. }
  453. HRESULT STDMETHODCALLTYPE
  454. CNtfsStorageForPropSetStg::OpenStream(
  455. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  456. /* [unique][in] */ void __RPC_FAR *reserved1,
  457. /* [in] */ DWORD grfMode,
  458. /* [in] */ DWORD reserved2,
  459. /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
  460. {
  461. HRESULT hr;
  462. // Parameter validation
  463. hr = CExpParameterValidate::OpenStream( pwcsName, reserved1, grfMode,
  464. reserved2, ppstm );
  465. if( FAILED(hr) ) goto Exit;
  466. // We only support STGM_SHARE_EXCLUSIVE
  467. hr = EnforceSingle(grfMode);
  468. if( FAILED(hr) ) goto Exit;
  469. // Attempt to open the stream
  470. hr = _pNtfsStorage->OpenStream( pwcsName, NULL, grfMode, 0, ppstm );
  471. if( FAILED(hr) ) goto Exit;
  472. hr = S_OK;
  473. Exit:
  474. return hr;
  475. }