|
|
//+============================================================================
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 1998.
//
// File: hforpset.cxx
//
// This file provides the definition of the CNtfsStorageForPropSetStg
// class. This class presents an IStorage implementation to the
// CPropertySetStorage implementation of IPropertySetStorage.
// Mostly, this class forwards to CNtfsStorage.
//
// The reason this class exists is because CNtfsStorage (which just
// wraps NTFS) doesn't support storages. This class supports
// storages by creating a docfile in an underlying NTFS stream.
//
// History:
//
// 3/10/98 MikeHill - Factored out common code in the create/open paths.
// 5/18/98 MikeHill
// - Parameter validation in CNtfsStorageForPropSetStg::
// Create/OpenStorage.
// 6/11/98 MikeHill
// - Dbg output, parameter validation.
// - In CreateOrOpenStorage(create), clean up partially
// created stream on error.
//
//+============================================================================
#include <pch.cxx>
#include <expparam.hxx> // CExpParameterValidate
#include <docfilep.hxx>
//+----------------------------------------------------------------------------
//
// Method: CNtfsStorageForPropSetStg::QueryInterface (IUnknown)
//
// This method only allows QI between IStorage & IUnknown. This is the only
// kind of QI that CPropertySetStorage makes.
//
//+----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::QueryInterface( REFIID riid, void** ppvObject ) { HRESULT hr = S_OK;
if( IID_IUnknown == riid || IID_IStorage == riid ) { *ppvObject = static_cast<IStorage*>(this); AddRef(); hr = S_OK; } else hr = E_NOINTERFACE;
return( hr );
} // CNtfsStorageForPropSetStg::QueryInterface
//+----------------------------------------------------------------------------
//
// Method: CNtfsStorage::CNtfsStorageForPropSetStg delegation methods
//
// These methods all delegate directly to CNtfsStorage's IStorage methods.
//
//+----------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CNtfsStorageForPropSetStg::AddRef() { return( _pNtfsStorage->AddRef() ); }
ULONG STDMETHODCALLTYPE CNtfsStorageForPropSetStg::Release() { return( _pNtfsStorage->Release() ); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::Commit( /* [in] */ DWORD grfCommitFlags) { return( _pNtfsStorage->Commit( grfCommitFlags )); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::Revert( void) { return( _pNtfsStorage->Revert() ); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::SetElementTimes( /* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName, /* [unique][in] */ const FILETIME __RPC_FAR *pctime, /* [unique][in] */ const FILETIME __RPC_FAR *patime, /* [unique][in] */ const FILETIME __RPC_FAR *pmtime) { return( _pNtfsStorage->SetElementTimes( pwcsName, pctime, patime, pmtime )); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::SetClass( /* [in] */ REFCLSID clsid) { return( _pNtfsStorage->SetClass( clsid )); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::SetStateBits( /* [in] */ DWORD grfStateBits, /* [in] */ DWORD grfMask) { return( _pNtfsStorage->SetStateBits( grfStateBits, grfMask )); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::Stat( /* [out] */ STATSTG __RPC_FAR *pstatstg, /* [in] */ DWORD grfStatFlag) { return( _pNtfsStorage->Stat( pstatstg, grfStatFlag )); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::EnumElements( /* [in] */ DWORD reserved1, /* [size_is][unique][in] */ void __RPC_FAR *reserved2, /* [in] */ DWORD reserved3, /* [out] */ IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum) { return( _pNtfsStorage->EnumElements( reserved1, reserved2, reserved3, ppenum )); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::DestroyElement( /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName) { return( _pNtfsStorage->DestroyElement( pwcsName )); }
//+----------------------------------------------------------------------------
//
// Method: CNtfsStorageForPropSetStg noimpl methods
//
// These methods are unused by CPropertySetStorage and left unimplemented.
//
//+----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::CopyTo( /* [in] */ DWORD ciidExclude, /* [size_is][unique][in] */ const IID __RPC_FAR *rgiidExclude, /* [unique][in] */ SNB snbExclude, /* [unique][in] */ IStorage __RPC_FAR *pstgDest) { return( E_NOTIMPL ); // No need to implement
}
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::MoveElementTo( /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName, /* [unique][in] */ IStorage __RPC_FAR *pstgDest, /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName, /* [in] */ DWORD grfFlags) { return( E_NOTIMPL ); // Not necessary to implement
}
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::RenameElement( /* [string][in] */ const OLECHAR __RPC_FAR *pwcsOldName, /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName) { return( E_NOTIMPL ); // Not necessary to implement
}
//+----------------------------------------------------------------------------
//
// Method: CNtfsStorageForPropSetStg::CreateStorage (IStorage)
//
// CNtfsStorage doesn't support CreateStorage. For CPropertySetStorage,
// we support it with the special CNtfsStorageForPropStg, which is created
// here.
//
//+----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::CreateStorage( /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName, /* [in] */ DWORD grfMode, /* [in] */ DWORD reserved1, /* [in] */ DWORD reserved2, /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg) {
HRESULT hr = S_OK; IStorage * pstg = NULL; CNtfsStream *pNtfsStream = NULL;
propXTrace( "CNtfsStorageForPropSetStg::CreateStorage" );
_pNtfsStorage->Lock( INFINITE );
// Parameter validation
hr = CExpParameterValidate::CreateStorage( pwcsName, grfMode, reserved1, reserved2, ppstg ); if( FAILED(hr) ) goto Exit;
// We require STGM_SHARE_EXCLUSIVE
hr = EnforceSingle(grfMode); if( FAILED(hr) ) goto Exit;
propTraceParameters(( "%ws, 0x%08x, 0x%x, 0x%x, %p", pwcsName, grfMode, reserved1, reserved2, ppstg ));
// In the underlying CNtfsStorage, we give streams and storages different
// names (storages have a "Docf_" prefix). So we require special
// handling for STGM_CREATE/STGM_FAILIFTHERE - we have to check
// to see if a *stream* (which doesn't have the "Docf_" prefix)
// already exists by that name.
if( STGM_CREATE & grfMode ) { // Delete any existing stream
hr = _pNtfsStorage->DestroyStreamElement( pwcsName ); if( FAILED(hr) && STG_E_FILENOTFOUND != hr ) { propDbg(( DEB_ERROR, "Couldn't destroy %s", pwcsName )); goto Exit; } hr = S_OK; } else { // STGM_FAILIFTHERE
// See if a stream by this name already exists.
hr = _pNtfsStorage->StreamExists( pwcsName ); if( FAILED(hr) ) goto Exit;
if( S_OK == hr ) { hr = STG_E_FILEALREADYEXISTS; goto Exit; } }
// Create the storage
hr = CreateOrOpenStorage( pwcsName, NULL, grfMode, NULL, TRUE /* fCreate */, &pstg ); if( FAILED(hr) ) goto Exit;
*ppstg = pstg; pstg = NULL;
Exit:
if( pstg ) pstg->Release();
_pNtfsStorage->Unlock();
if( STG_E_FILEALREADYEXISTS == hr ) propSuppressExitErrors(); return( hr );
} // CNtfsStorageForPropSetStg::CreateStorage
//+----------------------------------------------------------------------------
//
// Method: CNtfsStorageForPropSetStg::OpenStorage (IStorage)
//
// CNtfsStorage doesn't support OpenStorage. For CPropertySetStorage,
// we support it with the special CNtfsStorageForPropStg, which is created
// here.
//
//+----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::OpenStorage( /* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName, /* [unique][in] */ IStorage __RPC_FAR *pstgPriority, /* [in] */ DWORD grfMode, /* [unique][in] */ SNB snbExclude, /* [in] */ DWORD reserved, /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg) { HRESULT hr = S_OK;
propXTrace( "CNtfsStorageForPropSetStg::OpenStorage" );
// Validate parameters
hr = CExpParameterValidate::OpenStorage( pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg ); if( FAILED(hr) ) goto Exit;
// We only support STGM_SHARE_EXCLUSIVE
hr = EnforceSingle(grfMode); if( FAILED(hr) ) goto Exit;
propTraceParameters(( "%ws, %p, 0x%08x, %p, 0x%x, %p", pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg ));
// Try to open the storage
hr = CreateOrOpenStorage( pwcsName, pstgPriority, grfMode, snbExclude, FALSE /*!fCreate*/, ppstg ); if( FAILED(hr) ) goto Exit;
hr = S_OK;
Exit:
if( STG_E_FILENOTFOUND == hr ) propSuppressExitErrors();
return( hr );
} // CNtfsStorageForPropSetStg::OpenStorage
//+----------------------------------------------------------------------------
//
// CNtfsStorageForPropSetStg::CreateOrOpenStorage
//
// Internal routine to create or open a "storage" (a docfile in an NTFS
// stream).
//
//+----------------------------------------------------------------------------
HRESULT CNtfsStorageForPropSetStg::CreateOrOpenStorage( const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, BOOL fCreate, IStorage **ppstg ) { HRESULT hr = S_OK; CNtfsStream * pNtfsStream = NULL; IStorage * pstg = NULL; BOOL fCreated = FALSE;
propITrace( "CNtfsStorageForPropSetStg::CreateOrOpenStorage" ); propTraceParameters(( "%ws, %p, 0x%08x, %p, %d, %p", pwcsName, pstgPriority, grfMode, snbExclude, fCreate, ppstg ));
_pNtfsStorage->Lock( INFINITE );
// Compose the stream name (prepend "Docf_" to pwcsName)
CDocfileStreamName docfsn(pwcsName); const WCHAR* pwcszStreamName = docfsn;
// Open the NTFS stream
if( fCreate ) { hr = _pNtfsStorage->CreateStream( docfsn, grfMode, 0, 0, (IStream**)&pNtfsStream ); } else { hr = _pNtfsStorage->OpenStream( docfsn, NULL, grfMode, 0, (IStream**)&pNtfsStream ); }
if( FAILED(hr) ) goto Exit;
fCreated = TRUE;
// Get the ILockBytes for the NTFS stream, and put a
// docfile on top of it.
hr = CreateOrOpenStorageOnILockBytes( static_cast<ILockBytes*>(pNtfsStream), NULL, grfMode, NULL, fCreate, &pstg ); if( FAILED(hr) ) goto Exit;
pNtfsStream->Release(); pNtfsStream = NULL;
*ppstg = pstg; pstg = NULL;
Exit:
if( NULL != pNtfsStream ) pNtfsStream->Release();
if( pstg ) pstg->Release();
// If we fail in the create path, we shouldn't leave behind a corrupt
// docfile. I.e., if NewCNtfsStream succeded but create-on-ilockbyte failed,
// we have an empty stream which cannot be opened.
if( FAILED(hr) && fCreate && fCreated ) _pNtfsStorage->DestroyElement( CDocfileStreamName(pwcsName) );
_pNtfsStorage->Unlock();
if( STG_E_FILENOTFOUND == hr ) propSuppressExitErrors();
return( hr ); }
//+----------------------------------------------------------------------------
//
// Method: CreateOrOpenStorageOnILockBytes
//
// Given an ILockBytes, create or open a docfile. The input grfMode is that
// of the property set, though the docfile may be opened in a different
// mode as appropriate.
//
//+----------------------------------------------------------------------------
HRESULT // static
CNtfsStorageForPropSetStg::CreateOrOpenStorageOnILockBytes( ILockBytes *plkb, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, BOOL fCreate, IStorage **ppstg ) { HRESULT hr = S_OK;
propITraceStatic( "CNtfsStorageForPropSetStg::CreateOrOpenStorageOnILockBytes" ); propTraceParameters(( "%p, %p, 0x%08x, %p, %d, %p", plkb, pstgPriority, grfMode, snbExclude, fCreate, ppstg ));
// Create or open the docfile. We use transacted mode because we guarantee that
// NTFS property sets are always atomically updated.
if( fCreate ) { // We have to force the STGM_CREATE bit to avoid an error. This is OK
// (though the caller might not have set it) because we already handled
// stgm_create/stgm_failifthere in the CreateStorage caller.
hr = StgCreateDocfileOnILockBytes( plkb, grfMode | STGM_CREATE | STGM_TRANSACTED, 0, ppstg ); } else { // We only set stgm_transacted if necessary, and we only open deny_write in the
// read-only open case. This is so that we can allow multiple read-only/deny-write
// root opens.
hr = StgOpenStorageOnILockBytes( plkb, pstgPriority, grfMode & ~STGM_SHARE_MASK | (GrfModeIsWriteable(grfMode) ? STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED : STGM_SHARE_DENY_WRITE), snbExclude, 0, ppstg );
// STG_E_INVALIDHEADER in some paths of the above call gets converted into
// STG_E_FILEALREADYEXISTS, which doesn't make a whole lot of sense
// from our point of view (we already knew it existed, we wanted to open it). So,
// translate it back.
if( STG_E_FILEALREADYEXISTS == hr ) hr = STG_E_INVALIDHEADER; } if( FAILED(hr) ) goto Exit;
Exit:
return( hr ); }
//+----------------------------------------------------------------------------
//
// Method: CNtfsStorageForPropSetStg::CreateStream (IStorage)
// CNtfsStorageForPropSetStg::OpenStream (IStorage)
//
// These methods call to the CreateOrOpenStream method to do most of the
// work. CreateStream also needs to do extra work to handle the case where
// a stream/storage is being created, but a storage/stream by that name
// already exists.
//
//+----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::CreateStream( /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName, /* [in] */ DWORD grfMode, /* [in] */ DWORD reserved1, /* [in] */ DWORD reserved2, /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm) { HRESULT hr = S_OK; CDocfileStreamName dsName( pwcsName ); // (Name with pre-pended "Docf_")
propXTrace( "CNtfsStorageForPropSetStg::CreateStream" ); _pNtfsStorage->Lock( INFINITE );
// Parameter validation
hr = CExpParameterValidate::CreateStream( pwcsName, grfMode, reserved1, reserved2, ppstm ); if( FAILED(hr) ) goto Exit;
// We only support STGM_SHARE_EXCLUSIVE
hr = EnforceSingle(grfMode); if( FAILED(hr) ) goto Exit;
propTraceParameters(( "%ws, 0x%08x, %x, %x, %p", pwcsName, grfMode, reserved1, reserved2, ppstm ));
// In the underlying CNtfsStorage, we give streams and storages different
// names (storages have a "Docf_" prefix). So we require special
// handling for STGM_CREATE/STGM_FAILIFTHERE.
if( STGM_CREATE & grfMode ) { hr = _pNtfsStorage->DestroyStreamElement( dsName ); if( FAILED(hr) && STG_E_FILENOTFOUND != hr ) { propDbg(( DEB_ERROR, "Couldn't destroy %ws", static_cast<const WCHAR*>(dsName) )); goto Exit; } hr = S_OK; } else { // STGM_FAILIFTHERE
hr = _pNtfsStorage->StreamExists( dsName ); if( FAILED(hr) ) goto Exit;
if( S_OK == hr ) { hr = STG_E_FILEALREADYEXISTS; goto Exit; } }
// Instantiate & initialize the *ppstm.
hr = _pNtfsStorage->CreateStream( pwcsName, grfMode, 0, 0, ppstm ); if( FAILED(hr) ) goto Exit;
Exit:
_pNtfsStorage->Unlock();
if( STG_E_FILEALREADYEXISTS == hr ) propSuppressExitErrors(); return( hr ); }
HRESULT STDMETHODCALLTYPE CNtfsStorageForPropSetStg::OpenStream( /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName, /* [unique][in] */ void __RPC_FAR *reserved1, /* [in] */ DWORD grfMode, /* [in] */ DWORD reserved2, /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm) { HRESULT hr;
// Parameter validation
hr = CExpParameterValidate::OpenStream( pwcsName, reserved1, grfMode, reserved2, ppstm ); if( FAILED(hr) ) goto Exit;
// We only support STGM_SHARE_EXCLUSIVE
hr = EnforceSingle(grfMode); if( FAILED(hr) ) goto Exit;
// Attempt to open the stream
hr = _pNtfsStorage->OpenStream( pwcsName, NULL, grfMode, 0, ppstm ); if( FAILED(hr) ) goto Exit;
hr = S_OK;
Exit: return hr;
}
|