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

//+============================================================================
//
// 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;
}