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.

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