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.
 
 
 
 
 
 

5717 lines
202 KiB

#include "precomp.hxx"
CIdToPointerMapper *g_PointerMapper = NULL;
CMDCOM::CMDCOM():
m_ImpIConnectionPointContainer(),
m_hresConstructorError(ERROR_SUCCESS)
{
UINT i;
m_dwRefCount = 0;
g_hReadSaveSemaphore = NULL;
g_PointerMapper = new CIdToPointerMapper (DEFAULT_START_NUMBER_OF_MAPS, DEFAULT_INCREASE_NUMBER_OF_MAPS);
MD_ASSERT(g_PointerMapper);
fFlusherInitialized = FALSE;
dwMBFlushCookie = 0;
msMBFlushTime = INETA_MB_FLUSH_DEFAULT;
INITIALIZE_CRITICAL_SECTION( &csFlushLock );
INITIALIZE_CRITICAL_SECTION( &g_csEditWhileRunning );
// Null all entries in the connection point array.
for (i=0; i<MAX_CONNECTION_POINTS; i++)
m_aConnectionPoints[i] = NULL;
HRESULT hr = NOERROR;
g_hReadSaveSemaphore = IIS_CREATE_SEMAPHORE(
"g_hReadSaveSemaphore",
&g_hReadSaveSemaphore,
1,
1
);
if( g_hReadSaveSemaphore == NULL ) {
hr = GetLastHResult();
IIS_PRINTF((buff,"CreateSemaphore Failed with %x\n",hr));
}
else {
COConnectionPoint* pCOConnPt;
m_ImpIConnectionPointContainer.Init(this);
// Rig this COPaper COM object to be connectable. Assign the connection
// point array. This object's connection points are determined at
// compile time--it currently has 2 connection points, one for ANSI,
// one for UNICODE. Create a connection
// point object for these and assign them into the array. This array could
// easily grow to support additional connection points in the future.
// First try creating a new connection point object. Pass 'this' as the
// pHostObj pointer used by the connection point to pass its AddRef and
// Release calls back to the host connectable object.
pCOConnPt = new COConnectionPoint((IUnknown*)this);
if (NULL != pCOConnPt)
{
// If creation succeeded then initialize it (including creating
// its initial dynamic connection array).
hr = pCOConnPt->Init(IID_IMDCOMSINK_A);
MD_ASSERT(SUCCEEDED(hr));
// If the init succeeded then use QueryInterface to obtain the
// IConnectionPoint interface on the new connection point object.
// The interface pointer is assigned directly into the
// connection point array. The QI also does the needed AddRef.
if (SUCCEEDED(hr))
{
hr = pCOConnPt->QueryInterface(
IID_IConnectionPoint,
(PPVOID)&m_aConnectionPoints[MD_CONNPOINT_WRITESINK_A]);
MD_ASSERT(SUCCEEDED(hr));
}
if( FAILED(hr) )
{
delete pCOConnPt;
}
}
pCOConnPt = new COConnectionPoint((IUnknown*)this);
if (NULL != pCOConnPt)
{
// If creation succeeded then initialize it (including creating
// its initial dynamic connection array).
hr = pCOConnPt->Init(IID_IMDCOMSINK_W);
MD_ASSERT(SUCCEEDED(hr));
// If the init succeeded then use QueryInterface to obtain the
// IConnectionPoint interface on the new connection point object.
// The interface pointer is assigned directly into the
// connection point array. The QI also does the needed AddRef.
if (SUCCEEDED(hr))
{
hr = pCOConnPt->QueryInterface(
IID_IConnectionPoint,
(PPVOID)&m_aConnectionPoints[MD_CONNPOINT_WRITESINK_W]);
MD_ASSERT(SUCCEEDED(hr));
}
if( FAILED(hr) )
{
delete pCOConnPt;
}
}
}
m_hresConstructorError = hr;
}
CMDCOM::~CMDCOM()
{
// SetEvent(hevtDone);
UINT i;
IConnectionPoint* pIConnectionPoint;
// Do final release of the connection point objects.
// If this isn't the final release, then the client has an outstanding
// unbalanced reference to a connection point and a memory leak may
// likely result because the host COPaper object is now going away yet
// a connection point for this host object will not end up deleting
// itself (and its connections array).
for (i=0; i<MAX_CONNECTION_POINTS; i++)
{
pIConnectionPoint = m_aConnectionPoints[i];
RELEASE_INTERFACE(pIConnectionPoint);
}
if (g_hReadSaveSemaphore != NULL) {
CloseHandle(g_hReadSaveSemaphore);
}
DeleteCriticalSection( &csFlushLock );
DeleteCriticalSection( &g_csEditWhileRunning );
MD_ASSERT(g_PointerMapper);
delete g_PointerMapper;
}
HRESULT
CMDCOM::QueryInterface(REFIID riid, void **ppObject) {
if (riid==IID_IUnknown || riid==IID_IMDCOM) {
*ppObject = (IMDCOM *) this;
AddRef();
}
else if ( IID_IMDCOM2 == riid )
{
*ppObject = (IMDCOM2 *) this;
AddRef();
}
else if ( IID_IMDCOM3 == riid )
{
*ppObject = (IMDCOM3 *) this;
AddRef();
}
else if (IID_IConnectionPointContainer == riid) {
*ppObject = &m_ImpIConnectionPointContainer;
AddRef();
}
else {
return E_NOINTERFACE;
}
return NO_ERROR;
}
ULONG
CMDCOM::AddRef()
{
DWORD dwRefCount;
InterlockedIncrement((long *)&g_dwRefCount);
dwRefCount = InterlockedIncrement((long *)&m_dwRefCount);
return dwRefCount;
}
ULONG
CMDCOM::Release()
{
DWORD dwRefCount;
InterlockedDecrement((long *)&g_dwRefCount);
dwRefCount = InterlockedDecrement((long *)&m_dwRefCount);
//
// This is now a member of class factory.
// It is not dynamically allocated, so don't delete it.
//
/*
if (dwRefCount == 0) {
delete this;
return 0;
}
*/
return dwRefCount;
}
HRESULT
CMDCOM::ComMDInitialize()
/*++
Routine Description:
Initializes the metadata database. This must be called before any other API.
Reads in the existing database, if found. If errors occur reading in the
existing database, warnings are returned and the metabase is initialized
with not data.
Arguments:
Return Value:
DWORD - Return Code
ERROR_SUCCESS
ERROR_ALREADY_INITIALIZED
ERROR_NOT_ENOUGH_MEMORY
ERROR_INVALID_DATA
MD_WARNING_PATH_NOT_FOUND
MD_WARNING_DUP_NAME
MD_WARNING_INVALID_DATA
Notes:
This could take a long time to process, as it may load in a large amount of data.
If a warning code is returned, the database has been successfully initialized, but
some data in the database was not loaded successfully.
--*/
{
InitializeFlusher ();
return InitWorker(FALSE, NULL, NULL, NULL);
}
HRESULT
CMDCOM::ComMDTerminate(IN BOOL)
/*++
Routine Description:
DeInitailizes the metadata database. This must be before the application terminates
or dunloads the dll.
Arguments:
SaveData - If TRUE, the metadata is saved before terminating.
If the save fails, the metadata is not terminated.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_NOT_ENOUGH_MEMORY
Errors from the file system.
Notes:
This could take a long time to process, as it may save a large amount of data.
--*/
{
HRESULT hr;
hr = TerminateWorker1(FALSE);
return hr;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSendShutdownNotifications(VOID)
/*++
Routine Description:
Sends the shutdown notifications.
Arguments:
None
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
SendShutdownNotifications();
return hr;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDShutdown( void)
{
HRESULT hresReturn;
IIS_CRYPTO_STORAGE CryptoStorage;
PIIS_CRYPTO_BLOB pSessionKeyBlob;
TerminateFlusher();
//
// Give applications some time to close their interfaces,
// but don't wait too long, user is waiting.
// Wait until references are closed, unless they take too long.
// IISADMIN and factory both have refences we do not wait for.
//
//
// Note, there are four references to the CMDCOM object that
// are allowed to be active after this point.
// 1) The reference taken in dllmain ( cleans up in dllmain ).
// 2) The reference owned by COADMIN itself
// ( this is called as part of it's shutdown )
// 3) The reference owned by the MDWriter for backup and restore
// ( it is released after TerminateComAdmindata is called )
// 4) The reference owned by the Metabase holder,
// which is used to validate that the metabase is up
// and working if iisadmin is started.
// ( it is also released after the TerminateComAdmindata is called )
//
for (int i = 0;
(InterlockedIncrement((long *)&m_dwRefCount) > 5) &&
(i < MD_SHUTDOWN_WAIT_SECONDS);
i++) {
InterlockedDecrement((long *)&m_dwRefCount);
Sleep(1000);
}
InterlockedDecrement((long *)&m_dwRefCount);
hresReturn = InitStorageAndSessionKey(
&CryptoStorage,
&pSessionKeyBlob
);
if( SUCCEEDED(hresReturn) ) {
//
// Need to hold a read lock here to make sure
// Terminate doesn't occur during SaveAllData.
//
// Cannot hold a write lock, as SaveAllData gets
// a read lock after getting ReadSaveSemaphore
//
g_LockMasterResource.ReadLock();
if (g_dwInitialized > 0) {
hresReturn = SaveAllData(TRUE, &CryptoStorage, pSessionKeyBlob);
}
else {
if (g_dwInitialized > 0) {
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
g_bSaveDisallowed = TRUE;
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
}
else {
g_bSaveDisallowed = TRUE;
}
}
g_LockMasterResource.ReadUnlock();
::IISCryptoFreeBlob(pSessionKeyBlob);
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDAddMetaObjectA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath)
{
return ComMDAddMetaObjectD(hMDHandle,
pszMDPath,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDAddMetaObjectW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath)
{
return ComMDAddMetaObjectD(hMDHandle,
(PBYTE) pszMDPath,
TRUE);
}
HRESULT
CMDCOM::ComMDAddMetaObjectD(IN METADATA_HANDLE hMDHandle,
IN PBYTE pszMDPath,
IN BOOL bUnicode)
/*++
Routine Description:
Creates a meta object and adds it to the list of child objects for the object specified by Path.
Arguments:
Handle - A handle returned by MDOpenMetaObject with write permission.
Path - Path of the object to be added, relative to the path of Handle.
Must not be NULL.
eg. "Root Object/Child/GrandChild"
Return Value:
DWORD - Return Code
ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_ACCESS_DENIED
ERROR_NOT_ENOUGH_MEMORY
ERROR_PATH_NOT_FOUND
ERROR_DUP_NAME
ERROR_INVALID_NAME
Notes:
METADATA_MASTER_ROOT_HANDLE is not valid for this operation.
--*/
{
HRESULT hresReturn;
CMDHandle *hHandleObject;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else {
WCHAR strPath[METADATA_MAX_NAME_LEN];
LPSTR pszTempPath = (LPSTR)pszMDPath;
//
// ExtractNameFromPath assumes no preceding delimeter
//
if (pszTempPath != NULL) {
SkipPathDelimeter(pszTempPath, bUnicode);
}
//
// Make sure at least one new object was specified
//
hresReturn = ExtractNameFromPath(pszTempPath,
(LPSTR)strPath,
bUnicode);
if (FAILED(hresReturn)) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
hHandleObject = GetHandleObject(hMDHandle);
if(hHandleObject != NULL)
{
hresReturn = AddObjectToDataBase(hMDHandle,
hHandleObject,
(LPSTR)pszMDPath,
bUnicode);
if (SUCCEEDED(hresReturn)) {
g_dwSystemChangeNumber++;
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
hHandleObject,
(LPSTR)pszMDPath,
bUnicode);
}
}
else
{
hresReturn = E_HANDLE;
}
g_LockMasterResource.WriteUnlock();
}
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteMetaObjectA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath)
{
return ComMDDeleteMetaObjectD(hMDHandle,
pszMDPath,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteMetaObjectW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath)
{
return ComMDDeleteMetaObjectD(hMDHandle,
(PBYTE)pszMDPath,
TRUE);
}
HRESULT
CMDCOM::ComMDDeleteMetaObjectD(IN METADATA_HANDLE hMDHandle,
IN PBYTE pszMDPath,
IN BOOL bUnicode)
/*++
Routine Description:
Deletes a meta object and all of its data. Recursively deletes all descendants.
Arguments:
Handle - A handle returned by MDOpenMetaObject with write permission.
Path - Path of object to be deleted, relative to the path of Handle.
Must not be NULL.
eg. "Root Object/Child/GrandChild"
Return Value:
DWORD - Return Code
ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
ERROR_ACCESS_DENIED
Notes:
METADATA_MASTER_ROOT_HANDLE is not valid for this operation.
--*/
{
HRESULT hresReturn;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((LPSTR)pszMDPath == NULL) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
CMDHandle *hMDHandleObject = GetHandleObject(hMDHandle);
if(hMDHandleObject != NULL)
{
hresReturn = RemoveObjectFromDataBase(hMDHandle,
hMDHandleObject,
(LPSTR)pszMDPath,
bUnicode);
}
else
{
hresReturn = E_HANDLE;
}
if (SUCCEEDED(hresReturn)) {
g_dwSystemChangeNumber++;
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
hMDHandleObject,
(LPSTR)pszMDPath,
bUnicode);
}
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteChildMetaObjectsA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath)
{
return ComMDDeleteChildMetaObjectsD(hMDHandle,
pszMDPath,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteChildMetaObjectsW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath)
{
return ComMDDeleteChildMetaObjectsD(hMDHandle,
(PBYTE)pszMDPath,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteChildMetaObjectsD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
IN BOOL bUnicode)
/*++
Routine Description:
Deletes all child meta objects of the specified object, with all of their
data. Recursively deletes all descendants of the child objects.
Arguments:
Handle - A handle returned by MDOpenMetaObject with write permission.
Path - Path of the parent of the objects to be deleted, relative to the path of Handle.
eg. "Root Object/Child"
Return Value:
DWORD - Return Code
ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_PATH_NOT_FOUND
ERROR_ACCESS_DENIED
Notes:
METADATA_MASTER_ROOT_HANDLE is not valid for this operation.
--*/
{
HRESULT hresReturn;
LPSTR pszPath = (LPSTR)pszMDPath;
CMDBaseObject *pboParent;
CMDBaseObject *pboChild;
CMDHandle *phoHandle;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else {
g_LockMasterResource.WriteLock();
hresReturn = GetObjectFromPath(pboParent, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
if (SUCCEEDED(hresReturn)) {
phoHandle = GetHandleObject(hMDHandle);
MD_ASSERT (phoHandle != NULL);
while ((pboChild = pboParent->EnumChildObject(0)) != NULL) {
MD_REQUIRE(pboParent->RemoveChildObject(pboChild) == ERROR_SUCCESS);
if (phoHandle->SetChangeData(pboChild, MD_CHANGE_TYPE_DELETE_OBJECT, 0) != ERROR_SUCCESS) {
delete(pboChild);
}
}
g_dwSystemChangeNumber++;
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
phoHandle,
(LPSTR)pszMDPath,
bUnicode);
}
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumMetaObjectsA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [size_is][out] */ unsigned char __RPC_FAR *pszMDName,
/* [in] */ DWORD dwMDEnumObjectIndex)
{
return ComMDEnumMetaObjectsD(hMDHandle,
pszMDPath,
pszMDName,
dwMDEnumObjectIndex,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumMetaObjectsW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [size_is][out] */ LPWSTR pszMDName,
/* [in] */ DWORD dwMDEnumObjectIndex)
{
return ComMDEnumMetaObjectsD(hMDHandle,
(PBYTE)pszMDPath,
(PBYTE)pszMDName,
dwMDEnumObjectIndex,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumMetaObjectsD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [size_is][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [size_is][out] */ unsigned char __RPC_FAR *pszMDName,
/* [in] */ DWORD dwMDEnumObjectIndex,
IN BOOL bUnicode)
/*++
Routine Description:
Enumerates all child metaobjects once per call. Child Objects are numbers from 0 to NumObjects - 1, where
NumObjects is the number of current child objects. If EnumObjectIndex is >= NumObjects, ERROR_NO_MORE_ITEMS
is returned.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with read permission.
Path - Path of parent object, relative to the path of Handle.
eg. "Root Object/Child/GrandChild"
Name - Buffer where the Name of the object is returned. Must be at least METADATA_MAX_NAME_LEN characters long.
EnumObjectIndex - Index of the value to be retrieved. The caller is expected to set this to 0 before the first call and increment
it by 1 on each successive call until ERROR_NO_MORE_ITEMS is returned.
Return Value:
DWORD - Return Code
ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_ACCESS_DENIED
ERROR_PATH_NOT_FOUND
ERROR_NO_MORE_ITEMS
Notes:
METADATA_MASTER_ROOT_HANDLE is a valid handle, but provides no gaurantee that other threads will
not also change things. If a consistent data state is desired, use a handle returned by MDOpenMetaObject.
--*/
{
HRESULT hresReturn;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((LPSTR)pszMDName == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER);
}
else {
g_LockMasterResource.ReadLock();
CMDBaseObject *pboAffected, *pboChild;
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
if ( SUCCEEDED(hresReturn) && ( pboAffected == NULL ) )
{
hresReturn = E_FAIL;
}
if (SUCCEEDED(hresReturn)) {
pboChild = pboAffected->EnumChildObject(dwMDEnumObjectIndex);
if (pboChild != NULL) {
PVOID pvName = (PVOID)pboChild->GetName(bUnicode);
if (pvName == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
hresReturn = ERROR_SUCCESS;
if (bUnicode) {
if( wcslen( (LPWSTR)pvName ) < METADATA_MAX_NAME_LEN )
{
wcscpy((LPWSTR)pszMDName, (LPWSTR)pvName);
}
else
{
hresReturn = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
}
}
else {
if( strlen( (LPSTR)pvName ) < METADATA_MAX_NAME_LEN )
{
MD_STRCPY((LPSTR)pszMDName, (LPSTR)pvName);
}
else
{
hresReturn = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
}
}
}
}
else {
hresReturn = RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS);
}
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDCopyMetaObjectA(
/* [in] */ METADATA_HANDLE hMDSourceHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDSourcePath,
/* [in] */ METADATA_HANDLE hMDDestHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDDestPath,
/* [in] */ BOOL bMDOverwriteFlag,
/* [in] */ BOOL bMDCopyFlag)
{
return ComMDCopyMetaObjectD(hMDSourceHandle,
pszMDSourcePath,
hMDDestHandle,
pszMDDestPath,
bMDOverwriteFlag,
bMDCopyFlag,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDCopyMetaObjectW(
/* [in] */ METADATA_HANDLE hMDSourceHandle,
/* [string][in][unique] */ LPCWSTR pszMDSourcePath,
/* [in] */ METADATA_HANDLE hMDDestHandle,
/* [string][in][unique] */ LPCWSTR pszMDDestPath,
/* [in] */ BOOL bMDOverwriteFlag,
/* [in] */ BOOL bMDCopyFlag)
{
return ComMDCopyMetaObjectD(hMDSourceHandle,
(PBYTE)pszMDSourcePath,
hMDDestHandle,
(PBYTE)pszMDDestPath,
bMDOverwriteFlag,
bMDCopyFlag,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDCopyMetaObjectD(
/* [in] */ METADATA_HANDLE hMDSourceHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDSourcePath,
/* [in] */ METADATA_HANDLE hMDDestHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDDestPath,
/* [in] */ BOOL bMDOverwriteFlag,
/* [in] */ BOOL bMDCopyFlag,
IN BOOL bUnicode)
/*++
Routine Description:
Copies or moves Source meta object and it's data and descendants to Dest. The
copied object is a child of Dest.
Arguments:
SourceHandle - The handle or the object to be copied. If copyflag is specified, read permission
is requried. If not, read/write permission is required.
SourcePath - Path of the object to be copied, relative to the path of SourceHandle.
eg. "Root Object/Child/GrandChild"
DestHandle - The handle of the new location for the object. Write permission is required.
DestPath - The path of the new location for the object, relative to the path of
DestHandle. The new object will be a child of the object specified by
DestHandle/DestPath. Must not be a descendant of SourceHandle/SourePath.
eg. "Root Object/Child2"
OverwriteFlag - Determines the behavior if the a meta object with the same name as Source is
already a child of Dest.
If TRUE, the existing object and all of its data and
descandants are deleted prior to copying/moving Source.
If FALSE, the existing object, data, and descendants remain, and Source is merged
in. In cases of data conflicts, the Source data overwrites the Dest data.
CopyFlag - Determines whether Source is deleted from its original location.
If TRUE, a copy is performed. Source is not deleted from its original location.
If FALSE, a move is performed. Source is deleted from its original location.
Return Value:
DWORD - Return Code
ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_ACCESS_DENIED
ERROR_NOT_ENOUGH_MEMORY
ERROR_PATH_NOT_FOUND
ERROR_DUP_NAME
Notes:
--*/
{
return CopyMetaObject(
hMDSourceHandle,
pszMDSourcePath,
true,
NULL,
hMDDestHandle,
pszMDDestPath,
bMDOverwriteFlag,
bMDCopyFlag,
bUnicode);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRenameMetaObjectA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDNewName)
{
return ComMDRenameMetaObjectD(hMDHandle,
pszMDPath,
pszMDNewName,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRenameMetaObjectW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [string][in][unique] */ LPCWSTR pszMDNewName)
{
return ComMDRenameMetaObjectD(hMDHandle,
(PBYTE)pszMDPath,
(PBYTE)pszMDNewName,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRenameMetaObjectD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDNewName,
IN BOOL bUnicode)
{
HRESULT hresReturn = ERROR_SUCCESS;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (((LPSTR)pszMDNewName == NULL) ||
//
// ExtractNameFromPath, below, checks name length so don't need to
// check that here.
//
(bUnicode &&
((wcschr((LPWSTR)pszMDNewName, MD_PATH_DELIMETERW) != NULL) ||
(wcschr((LPWSTR)pszMDNewName, MD_ALT_PATH_DELIMETERW) != NULL))) ||
(!bUnicode &&
((MD_STRCHR((LPSTR)pszMDNewName, MD_PATH_DELIMETERA) != NULL) ||
(MD_STRCHR((LPSTR)pszMDNewName, MD_ALT_PATH_DELIMETERA) != NULL)))) {
hresReturn = E_INVALIDARG;
}
else {
WCHAR strName[METADATA_MAX_NAME_LEN];
LPSTR pszNewName = (LPSTR)pszMDNewName;
LPSTR pszTempName = pszNewName;
hresReturn = ExtractNameFromPath(pszTempName, (LPSTR)strName, bUnicode);
if (SUCCEEDED(hresReturn)) {
g_LockMasterResource.WriteLock();
CMDBaseObject *pboAffected, *pboParent;
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
if (SUCCEEDED(hresReturn)) {
pboParent = pboAffected->GetParent();
if ( pboParent == NULL) {
//
// Can't rename MasterRoot
//
hresReturn = E_INVALIDARG;
}
else {
if (pboAffected->GetParent()->GetChildObject(pszNewName, &hresReturn, bUnicode) != NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS);
}
if (SUCCEEDED(hresReturn)) {
BUFFER OriginalKeyName;
DWORD dwStringLen = 0;
hresReturn= GetObjectPath(pboAffected,
&OriginalKeyName,
dwStringLen,
g_pboMasterRoot,
bUnicode);
if (SUCCEEDED(hresReturn)) {
//
// First Remove the object, to get it out of the hash table.
//
pboParent->RemoveChildObjectFromHash( pboAffected );
//
// Must use pszMDNewName, as this does not include delimeters
//
if (!pboAffected->SetName((LPSTR)pszMDNewName, bUnicode)) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
//
// Attempt to reinsert the object
// Preserve previous error code by ignoreing this one.
//
pboParent->AddChildObjectToHash(pboAffected);
}
else {
CMDHandle *phoHandle;
//
// Reinsert the object with the new name.
//
hresReturn = pboParent->AddChildObjectToHash( pboAffected );
phoHandle = GetHandleObject(hMDHandle);
g_dwSystemChangeNumber++;
MD_ASSERT(phoHandle != NULL);
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
phoHandle,
(LPSTR)pszMDNewName,
bUnicode
);
phoHandle->SetChangeData(pboAffected, MD_CHANGE_TYPE_RENAME_OBJECT,
0, (LPWSTR)OriginalKeyName.QueryPtr ());
}
}
}
}
}
g_LockMasterResource.WriteUnlock();
}
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSetMetaDataA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ PMETADATA_RECORD pmdrMDData)
{
return ComMDSetMetaDataD(hMDHandle,
pszMDPath,
pmdrMDData,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSetMetaDataW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [in] */ PMETADATA_RECORD pmdrMDData)
{
return ComMDSetMetaDataD(hMDHandle,
(PBYTE)pszMDPath,
pmdrMDData,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSetMetaDataD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [size_is][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ PMETADATA_RECORD pmdrMDData,
IN BOOL bUnicode)
/*++
Routine Description:
Sets a data object.
If data of that name does not already exist, it creates and
inserts a data object into the list of data objects of that type.
If data of that name aready exists, it sets the new data values.
Arguments:
Handle - A handle returned by MDOpenMetaObject with write permission.
Path - The path of the meta object with which this data is associated, relative to the
path of Handle.
Data - The data to set. See IMD.H.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
ERROR_ACCESS_DENIED
ERROR_NOT_ENOUGH_MEMORY
MD_ERROR_CANNOT_REMOVE_SECURE_ATTRIBUTE
Notes:
METADATA_MASTER_ROOT_HANDLE is not valid for this operation.
Duplicate data names are not allowed, even for different types.
--*/
{
HRESULT hresReturn;
CMDHandle *hHandleObject;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (!ValidateData(pmdrMDData, bUnicode)) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
CMDBaseObject *AffectedObject = NULL;
hHandleObject = GetHandleObject(hMDHandle);
if(hHandleObject != NULL)
{
hresReturn = GetObjectFromPathWithHandle(AffectedObject,
hMDHandle,
hHandleObject,
METADATA_PERMISSION_WRITE,
pszPath,
bUnicode);
}
else
{
hresReturn = E_HANDLE;
}
if (hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) {
pszPath = (LPSTR)pszMDPath;
MD_ASSERT(pszMDPath != NULL);
hresReturn = AddObjectToDataBase(hMDHandle,
hHandleObject,
(LPSTR)pszMDPath,
bUnicode);
if (SUCCEEDED(hresReturn)) {
g_dwSystemChangeNumber++;
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
hHandleObject,
(LPSTR)pszMDPath,
bUnicode);
hresReturn = GetObjectFromPath(AffectedObject, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
MD_ASSERT(SUCCEEDED(hresReturn));
}
}
if (SUCCEEDED(hresReturn) && AffectedObject) {
hresReturn = AffectedObject->SetDataObject(pmdrMDData, bUnicode);
}
if (SUCCEEDED(hresReturn)) {
g_dwSystemChangeNumber++;
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
hHandleObject,
(LPSTR)pszMDPath,
bUnicode);
hHandleObject = GetHandleObject( hMDHandle );
if( !hHandleObject )
{
hresReturn = MD_ERROR_DATA_NOT_FOUND;
}
else
{
hHandleObject->SetChangeData(AffectedObject, MD_CHANGE_TYPE_SET_DATA, pmdrMDData->dwMDIdentifier);
}
}
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetMetaDataA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [out][in] */ PMETADATA_RECORD pmdrMDData,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen)
{
return ComMDGetMetaDataD(hMDHandle,
pszMDPath,
pmdrMDData,
pdwMDRequiredDataLen,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetMetaDataW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [out][in] */ PMETADATA_RECORD pmdrMDData,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen)
{
return ComMDGetMetaDataD(hMDHandle,
(PBYTE)pszMDPath,
pmdrMDData,
pdwMDRequiredDataLen,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetMetaDataD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [out][in] */ PMETADATA_RECORD pmdrMDData,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen,
IN BOOL bUnicode)
/*++
Routine Description:
Gets one metadata value.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with read permission.
Path - The path of the meta object with which this data is associated, relative to the
path of Handle.
Data - The data structure. See IMD.H.
RequiredDataLen - If ERROR_INSUFFICIENT_BUFFER is returned, this is set to the required buffer size.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_ACCESS_DENIED
ERROR_PATH_NOT_FOUND
MD_ERROR_DATA_NOT_FOUND
ERROR_INSUFFICIENT_BUFFER
Notes:
METADATA_MASTER_ROOT_HANDLE is a valid handle, but provides no gaurantee that other threads will
not also change things. If a consistent data state is desired, use a handle returned by
ComMDOpenMetaObject.
--*/
{
HRESULT hresReturn;
CMDBaseData *pbdRetrieve = NULL;
CMDBaseObject *pboAssociated = NULL;
LPSTR pszPath = (LPSTR)pszMDPath;
BOOL bInheritableOnly = FALSE;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((pmdrMDData == NULL) ||
((pmdrMDData->dwMDDataLen != 0) && (pmdrMDData->pbMDData == NULL)) ||
((pmdrMDData->dwMDAttributes & METADATA_PARTIAL_PATH) &&
!(pmdrMDData->dwMDAttributes & METADATA_INHERIT)) ||
(pmdrMDData->dwMDDataType >= INVALID_END_METADATA)) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
CMDBaseObject *pboAffected = NULL;
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
if ( SUCCEEDED(hresReturn) && ( pboAffected == NULL ) )
{
hresReturn = E_FAIL;
}
if (SUCCEEDED(hresReturn)) {
//
// Found the object, get the data.
//
pbdRetrieve = pboAffected->GetDataObject(pmdrMDData->dwMDIdentifier,
pmdrMDData->dwMDAttributes,
pmdrMDData->dwMDDataType,
&pboAssociated);
}
else if ((hresReturn == (RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND))) && (pboAffected != NULL) &&
(pmdrMDData->dwMDAttributes & METADATA_PARTIAL_PATH)) {
//
// Object not found, get inheritable data.
//
pbdRetrieve = pboAffected->GetInheritableDataObject(pmdrMDData->dwMDIdentifier,
pmdrMDData->dwMDDataType,
&pboAssociated);
hresReturn = ERROR_SUCCESS;
bInheritableOnly = TRUE;
}
if (SUCCEEDED(hresReturn)) {
if (pbdRetrieve == NULL) {
hresReturn = MD_ERROR_DATA_NOT_FOUND;
}
else {
PBYTE pbData = (PBYTE)(pbdRetrieve->GetData(bUnicode));
DWORD dwDataLen = pbdRetrieve->GetDataLen(bUnicode);
if (pbData == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
if (((pmdrMDData->dwMDAttributes) & (pbdRetrieve->GetAttributes()) &
METADATA_REFERENCE) != 0) {
MD_ASSERT(((pbdRetrieve->GetAttributes()) & METADATA_INSERT_PATH) == 0);
pmdrMDData->pbMDData = (PBYTE) pbdRetrieve->GetData(bUnicode);
pbdRetrieve->IncrementReferenceCount();
pmdrMDData->dwMDDataTag = pbdRetrieve->GetMappingId();
}
else {
BUFFER bufData;
STRAU strData;
if ((pmdrMDData->dwMDAttributes & pbdRetrieve->GetAttributes() & METADATA_INSERT_PATH) != 0) {
hresReturn= InsertPathIntoData(&bufData,
&strData,
&pbData,
&dwDataLen,
pbdRetrieve,
hMDHandle,
pboAssociated,
bUnicode);
}
if (SUCCEEDED(hresReturn)) {
if (pmdrMDData->dwMDDataLen < dwDataLen) {
hresReturn = RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
pmdrMDData->dwMDDataLen = 0;
*pdwMDRequiredDataLen = dwDataLen;
}
else {
MD_COPY(pmdrMDData->pbMDData, pbData, dwDataLen);
pmdrMDData->dwMDDataTag = 0;
}
}
}
}
if (SUCCEEDED(hresReturn)) {
BOOL bIsInherited = FALSE;
if ((pmdrMDData->dwMDAttributes & METADATA_ISINHERITED) &&
(pmdrMDData->dwMDAttributes & METADATA_INHERIT)) {
//
// Set the ISINHERITED flag
//
if (bInheritableOnly) {
bIsInherited = TRUE;
}
else {
if (pboAffected->GetDataObject(pmdrMDData->dwMDIdentifier,
pmdrMDData->dwMDAttributes &
~(METADATA_INHERIT | METADATA_PARTIAL_PATH),
pbdRetrieve->GetDataType()) == NULL) {
bIsInherited = TRUE;
}
}
}
pmdrMDData->dwMDAttributes =
(pbdRetrieve->GetAttributes() | ((bIsInherited) ? METADATA_ISINHERITED : 0));
pmdrMDData->dwMDUserType = pbdRetrieve->GetUserType();
pmdrMDData->dwMDDataType = pbdRetrieve->GetDataType();
pmdrMDData->dwMDDataLen = dwDataLen;
}
}
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumMetaDataA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [out][in] */ PMETADATA_RECORD pmdrMDData,
/* [in] */ DWORD dwMDEnumDataIndex,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen)
{
return ComMDEnumMetaDataD(hMDHandle,
pszMDPath,
pmdrMDData,
dwMDEnumDataIndex,
pdwMDRequiredDataLen,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumMetaDataW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [out][in] */ PMETADATA_RECORD pmdrMDData,
/* [in] */ DWORD dwMDEnumDataIndex,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen)
{
return ComMDEnumMetaDataD(hMDHandle,
(PBYTE)pszMDPath,
pmdrMDData,
dwMDEnumDataIndex,
pdwMDRequiredDataLen,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumMetaDataD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [out][in] */ PMETADATA_RECORD pmdrMDData,
/* [in] */ DWORD dwMDEnumDataIndex,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen,
IN BOOL bUnicode)
/*++
Routine Description:
Enumerates all metadata values once per call. Values are numbered from 0 to NumValues - 1, where
NumValues is the number of current valules. If EnumDataIndex is >= NumValues, ERROR_NO_MORE_ITEMS
is returned.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with read permission.
Path - The path of the meta object with which this data is associated, , relative to the
path of Handle.
Data - The data structure. See IMD.H.
RequiredDataLen - If ERROR_INSUFFICIENT_BUFFER is returned, this is set to the required buffer size.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
ERROR_ACCESS_DENIED
ERROR_INSUFFICIENT_BUFFER
ERROR_NO_MORE_ITEMS
Notes:
METADATA_MASTER_ROOT_HANDLE is a valid handle, but provides no gaurantee that other threads will
not also change things. If a consistent data state is desired, use a handle returned by MDOpenMetaObject.
--*/
{
HRESULT hresReturn;
CMDBaseData *pbdRetrieve = NULL;
CMDBaseObject *pboAssociated = NULL;
LPSTR pszPath = (LPSTR)pszMDPath;
BOOL bInheritableOnly = FALSE;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((pmdrMDData == NULL) ||
((pmdrMDData->dwMDDataLen != 0) && (pmdrMDData->pbMDData == NULL)) ||
((pmdrMDData->dwMDAttributes & METADATA_PARTIAL_PATH) &&
!(pmdrMDData->dwMDAttributes & METADATA_INHERIT)) ||
(pmdrMDData->dwMDDataType >= INVALID_END_METADATA)) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
CMDBaseObject *pboAffected = NULL;
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
if ( SUCCEEDED(hresReturn) && ( pboAffected == NULL ) )
{
hresReturn = E_FAIL;
}
if (SUCCEEDED(hresReturn)) {
pbdRetrieve = pboAffected->EnumDataObject(dwMDEnumDataIndex,
pmdrMDData->dwMDAttributes,
pmdrMDData->dwMDUserType,
pmdrMDData->dwMDDataType,
&pboAssociated);
}
else if ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboAffected != NULL) &&
(pmdrMDData->dwMDAttributes & METADATA_PARTIAL_PATH)) {
pbdRetrieve = pboAffected->EnumInheritableDataObject(dwMDEnumDataIndex,
pmdrMDData->dwMDUserType,
pmdrMDData->dwMDDataType,
&pboAssociated);
hresReturn = ERROR_SUCCESS;
bInheritableOnly = TRUE;
}
if (SUCCEEDED(hresReturn)) {
if (pbdRetrieve == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS);
}
else {
PBYTE pbData = (PBYTE)(pbdRetrieve->GetData(bUnicode));
DWORD dwDataLen = pbdRetrieve->GetDataLen(bUnicode);
if (pbData == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
if (((pmdrMDData->dwMDAttributes) & (pbdRetrieve->GetAttributes()) &
METADATA_REFERENCE) != 0) {
MD_ASSERT(((pbdRetrieve->GetAttributes()) & METADATA_INSERT_PATH) == 0);
pmdrMDData->pbMDData = (PBYTE)pbdRetrieve->GetData(bUnicode);
pbdRetrieve->IncrementReferenceCount();
pmdrMDData->dwMDDataTag = pbdRetrieve->GetMappingId();
}
else {
BUFFER bufData;
STRAU strData;
if ((pmdrMDData->dwMDAttributes & pbdRetrieve->GetAttributes() & METADATA_INSERT_PATH) != 0) {
hresReturn= InsertPathIntoData(&bufData,
&strData,
&pbData,
&dwDataLen,
pbdRetrieve,
hMDHandle,
pboAssociated,
bUnicode);
}
if (SUCCEEDED(hresReturn)) {
if (pmdrMDData->dwMDDataLen < dwDataLen) {
hresReturn = RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
pmdrMDData->dwMDDataLen = 0;
*pdwMDRequiredDataLen = dwDataLen;
}
else {
MD_COPY(pmdrMDData->pbMDData, pbData, dwDataLen);
pmdrMDData->dwMDDataTag = 0;
}
}
}
}
if (SUCCEEDED(hresReturn)) {
BOOL bIsInherited = FALSE;
if ((pmdrMDData->dwMDAttributes & METADATA_ISINHERITED) &&
(pmdrMDData->dwMDAttributes & METADATA_INHERIT)) {
//
// Set the ISINHERITED flag
//
if (bInheritableOnly) {
bIsInherited = TRUE;
}
else {
if (pboAffected->GetDataObject(pbdRetrieve->GetIdentifier(),
pmdrMDData->dwMDAttributes &
~(METADATA_INHERIT | METADATA_PARTIAL_PATH),
pbdRetrieve->GetDataType()) == NULL) {
bIsInherited = TRUE;
}
}
}
pmdrMDData->dwMDAttributes =
(pbdRetrieve->GetAttributes() | ((bIsInherited) ? METADATA_ISINHERITED : 0));
pmdrMDData->dwMDIdentifier = pbdRetrieve->GetIdentifier();
pmdrMDData->dwMDUserType = pbdRetrieve->GetUserType();
pmdrMDData->dwMDDataType = pbdRetrieve->GetDataType();
pmdrMDData->dwMDDataLen = dwDataLen;
hresReturn = ERROR_SUCCESS;
}
}
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteMetaDataA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDIdentifier,
/* [in] */ DWORD dwMDDataType)
{
return ComMDDeleteMetaDataD(hMDHandle,
pszMDPath,
dwMDIdentifier,
dwMDDataType,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteMetaDataW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [in] */ DWORD dwMDIdentifier,
/* [in] */ DWORD dwMDDataType)
{
return ComMDDeleteMetaDataD(hMDHandle,
(PBYTE)pszMDPath,
dwMDIdentifier,
dwMDDataType,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteMetaDataD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDIdentifier,
/* [in] */ DWORD dwMDDataType,
IN BOOL bUnicode)
/*++
Routine Description:
Deletes a data object.
Arguments:
Handle - A handle returned by MDOpenMetaObject with write permission.
Path - The path of the meta object with which this data is associated, relative to the
path of Handle.
Identifier - The identifier of the data to remove.
DataType - Optional type of the data to remove. If specified, only data of that
type will be removed. See imd.h.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
ERROR_ACCESS_DENIED
MD_ERROR_DATA_NOT_FOUND
Notes:
METADATA_MASTER_ROOT_HANDLE is not valid for this operation.
--*/
{
HRESULT hresReturn;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (dwMDDataType >= INVALID_END_METADATA) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
CMDBaseObject *pboAffected;
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
if (SUCCEEDED(hresReturn)) {
if (pboAffected->RemoveDataObject(dwMDIdentifier, dwMDDataType, TRUE) != NULL) {
CMDHandle *phoHandle;
hresReturn = ERROR_SUCCESS;
g_dwSystemChangeNumber++;
phoHandle = GetHandleObject(hMDHandle);
if( !phoHandle )
{
hresReturn = MD_ERROR_DATA_NOT_FOUND;
}
else
{
phoHandle->SetChangeData(pboAffected, MD_CHANGE_TYPE_DELETE_DATA, dwMDIdentifier);
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
phoHandle,
(LPSTR)pszMDPath,
bUnicode);
}
}
else {
hresReturn = MD_ERROR_DATA_NOT_FOUND;
}
}
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetAllMetaDataA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDAttributes,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType,
/* [out] */ DWORD __RPC_FAR *pdwMDNumDataEntries,
/* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber,
/* [in] */ DWORD dwMDBufferSize,
/* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
{
return ComMDGetAllMetaDataD(hMDHandle,
pszMDPath,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
pdwMDNumDataEntries,
pdwMDDataSetNumber,
dwMDBufferSize,
pbBuffer,
pdwMDRequiredBufferSize,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetAllMetaDataW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [in] */ DWORD dwMDAttributes,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType,
/* [out] */ DWORD __RPC_FAR *pdwMDNumDataEntries,
/* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber,
/* [in] */ DWORD dwMDBufferSize,
/* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
{
return ComMDGetAllMetaDataD(hMDHandle,
(PBYTE)pszMDPath,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
pdwMDNumDataEntries,
pdwMDDataSetNumber,
dwMDBufferSize,
pbBuffer,
pdwMDRequiredBufferSize,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetAllMetaDataD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDAttributes,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType,
/* [out] */ DWORD __RPC_FAR *pdwMDNumDataEntries,
/* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber,
/* [in] */ DWORD dwMDBufferSize,
/* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize,
IN BOOL bUnicode)
/*++
Routine Description:
Gets all data associated with a Meta Object.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by ComMDOpenMetaObject with read permission.
Path - The path of the meta object with which this data is associated, relative to the
path of Handle.
Attributes - The flags for the data. See imd.h.
UserType - The User Type for the data. If not set to ALL_METADATA, only metadata of the specified
User Type will be returned. Se imd.h.
DataType - The Type of the data. If not set to ALL_METADATA only metadata
of the specified Data Type will be returned. See imd.h.
NumDataEntries - On successful output, specifes the number of entries copied to Buffer.
DataSetNumber - A number associated with this data set. Can be used to identify common data sets.
Filled in if ERROR_SUCCESS or ERROR_INSUFFICIENT_BUFFER is returned. See ComMDGetDataSetNumber.
BufferSize - The size in bytes of buffer. If the return code is ERROR_INSUFFICIENT_BUFFER, this contains
the number of bytes needed.
Buffer - Buffer to store the data. On successful return it will
contain an array of METADATA_GETALL_RECORD.
RequiredBufferSize - If ERROR_INSUFFICIENT_BUFFER is returned, This contains
the required buffer length, in bytes.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
ERROR_ACCESS_DENIED
ERROR_INSUFFICIENT_BUFFER
Notes:
METADATA_MASTER_ROOT_HANDLE is a valid handle, but provides no gaurantee that other threads will
not also change things. If a consistent data state is desired, use
a handle returned by ComMDOpenMetaObject.
DWORD data is aligned on non-Intel platforms. This may not hold true on remote clients.
--*/
{
BOOL fUseInternalStructure = !!(dwMDAttributes & METADATA_REFERENCE);
BOOL fNonSecureOnly = !!(dwMDAttributes & METADATA_NON_SECURE_ONLY);
HRESULT hresReturn;
BOOL bInheritableOnly = FALSE;
CMDBaseData *pbdCurrent;
DWORD i, dwNumDataObjects;
PVOID *ppvMainDataBuf = NULL;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((pdwMDNumDataEntries == NULL) || ((dwMDBufferSize != 0) && (pbBuffer == NULL)) ||
((dwMDAttributes & METADATA_PARTIAL_PATH) && !(dwMDAttributes & METADATA_INHERIT)) ||
(dwMDDataType >= INVALID_END_METADATA)) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
CMDBaseObject *pboAffected = NULL;
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
if ( SUCCEEDED(hresReturn) && ( pboAffected == NULL ) )
{
hresReturn = E_FAIL;
}
if (SUCCEEDED(hresReturn)) {
if (pdwMDDataSetNumber != NULL) {
*pdwMDDataSetNumber = pboAffected->GetDataSetNumber();
}
bInheritableOnly = FALSE;
}
else if ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) &&
(pboAffected != NULL) &&
(dwMDAttributes & METADATA_PARTIAL_PATH)) {
if (pdwMDDataSetNumber != NULL) {
*pdwMDDataSetNumber = pboAffected->GetDescendantDataSetNumber();
}
bInheritableOnly = TRUE;
hresReturn = ERROR_SUCCESS;
}
if ( SUCCEEDED(hresReturn) )
{
ppvMainDataBuf = GetMainDataBuffer();
MD_ASSERT (ppvMainDataBuf != NULL);
if ( ppvMainDataBuf == NULL )
{
hresReturn = E_FAIL;
}
}
if (SUCCEEDED(hresReturn)) {
dwNumDataObjects = pboAffected->GetAllDataObjects(ppvMainDataBuf,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
bInheritableOnly,
fNonSecureOnly
);
PBYTE pbEnd = pbBuffer + dwMDBufferSize;
PBYTE pbDataStart;
if (fUseInternalStructure)
{
pbDataStart = pbBuffer + (dwNumDataObjects * sizeof(METADATA_GETALL_INTERNAL_RECORD));
}
else
{
pbDataStart = pbBuffer + (dwNumDataObjects * sizeof(METADATA_GETALL_RECORD));
}
PBYTE pbNextDataStart = pbDataStart;
for (i = 0;
(i < dwNumDataObjects) ;
i++, pbDataStart = pbNextDataStart) {
pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
MD_ASSERT(pbdCurrent != NULL);
if ( pbdCurrent == NULL )
{
hresReturn = E_FAIL;
break;
}
DWORD dwDataLen = pbdCurrent->GetDataLen(bUnicode);
PBYTE pbData = (PBYTE)(pbdCurrent->GetData(bUnicode));
CMDBaseObject *pboAssociated;
BUFFER bufData;
STRAU strData;
if (pbData == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
break;
}
if ((dwMDAttributes & (pbdCurrent->GetAttributes()) &
METADATA_REFERENCE) == 0) {
if ((dwMDAttributes & pbdCurrent->GetAttributes() & METADATA_INSERT_PATH) != 0) {
//
// First do a get to get the metaobject associated with this data object
//
if (bInheritableOnly) {
MD_REQUIRE(pboAffected->GetInheritableDataObject(pbdCurrent->GetIdentifier(),
pbdCurrent->GetDataType(),
&pboAssociated) != NULL);
}
else {
MD_REQUIRE(pboAffected->GetDataObject(pbdCurrent->GetIdentifier(),
dwMDAttributes,
pbdCurrent->GetDataType(),
&pboAssociated) != NULL);
}
hresReturn= InsertPathIntoData(&bufData,
&strData,
&pbData,
&dwDataLen,
pbdCurrent,
hMDHandle,
pboAssociated,
bUnicode);
}
pbNextDataStart = (pbDataStart + dwDataLen);
// The following will ensure that the pointer remains on a DWORD boundary.
pbNextDataStart = (PBYTE)(((DWORD_PTR)pbNextDataStart + 3) & ~((DWORD_PTR)(3)));
}
if (SUCCEEDED(hresReturn)) {
if (pbEnd < pbNextDataStart) {
hresReturn = RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
}
else {
if (fUseInternalStructure)
{
if ((dwMDAttributes & (pbdCurrent->GetAttributes()) &
METADATA_REFERENCE) == 0) {
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDDataOffset = DIFF(pbDataStart - pbBuffer);
MD_COPY(pbDataStart, pbData, dwDataLen);
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDDataTag = 0;
}
else {
MD_ASSERT((dwMDAttributes & pbdCurrent->GetAttributes() & METADATA_INSERT_PATH) == 0);
MD_ASSERT(pbdCurrent->GetData(bUnicode) != NULL);
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].pbMDData = (PBYTE)pbdCurrent->GetData(bUnicode);
pbdCurrent->IncrementReferenceCount();
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDDataTag = pbdCurrent->GetMappingId();
}
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDIdentifier = pbdCurrent->GetIdentifier();
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDAttributes = pbdCurrent->GetAttributes();
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDUserType = pbdCurrent->GetUserType();
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDDataType = pbdCurrent->GetDataType();
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDDataLen = dwDataLen;
}
else
{
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDDataOffset = (DWORD)DIFF(pbDataStart - pbBuffer);
MD_COPY(pbDataStart, pbData, dwDataLen);
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDDataTag = 0;
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDIdentifier = pbdCurrent->GetIdentifier();
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDAttributes = pbdCurrent->GetAttributes();
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDUserType = pbdCurrent->GetUserType();
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDDataType = pbdCurrent->GetDataType();
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDDataLen = dwDataLen;
}
}
}
}
FreeMainDataBuffer(ppvMainDataBuf);
if (SUCCEEDED(hresReturn)) {
*pdwMDNumDataEntries = dwNumDataObjects;
if ((dwNumDataObjects > 0) &&
(dwMDAttributes & METADATA_ISINHERITED) &&
(dwMDAttributes & METADATA_INHERIT)) {
//
// Set the ISINHERITED flag
//
if (bInheritableOnly) {
for (i = 0; i < dwNumDataObjects; i++) {
if (fUseInternalStructure)
{
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDAttributes |= METADATA_ISINHERITED;
}
else
{
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDAttributes |= METADATA_ISINHERITED;
}
}
}
else {
ppvMainDataBuf = GetMainDataBuffer();
dwNumDataObjects = pboAffected->GetAllDataObjects(ppvMainDataBuf,
dwMDAttributes & ~(METADATA_INHERIT | METADATA_PARTIAL_PATH),
dwMDUserType,
dwMDDataType,
bInheritableOnly,
fNonSecureOnly);
//
// Current implementation puts the local items first
// So just set the rest to inherited
//
// DBG loop asserts that the implementation has not changed.
//
#if DBG
for (i = 0; i < dwNumDataObjects ; i++) {
pbdCurrent = (CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
MD_ASSERT(pbdCurrent != NULL);
if (fUseInternalStructure)
{
MD_ASSERT(pbdCurrent->GetIdentifier() == ((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDIdentifier);
}
else
{
MD_ASSERT(pbdCurrent->GetIdentifier() == ((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDIdentifier);
}
}
#endif //DBG
for (i = dwNumDataObjects; i < *pdwMDNumDataEntries; i++) {
if (fUseInternalStructure)
{
((PMETADATA_GETALL_INTERNAL_RECORD)pbBuffer)[i].dwMDAttributes |= METADATA_ISINHERITED;
}
else
{
((PMETADATA_GETALL_RECORD)pbBuffer)[i].dwMDAttributes |= METADATA_ISINHERITED;
}
}
FreeMainDataBuffer(ppvMainDataBuf);
}
}
}
*pdwMDRequiredBufferSize = (DWORD)DIFF(pbNextDataStart - pbBuffer);
#ifndef _X86_
//
// Alignment fluff. Alignment could cause up to 3 bytes to be added to
// the total needed if the buffer size ends in a different modulo 4
// than the one passed in.
//
if (FAILED(hresReturn)) {
*pdwMDRequiredBufferSize +=3;
}
#endif
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteAllMetaDataA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType)
{
return ComMDDeleteAllMetaDataD(hMDHandle,
pszMDPath,
dwMDUserType,
dwMDDataType,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteAllMetaDataW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType)
{
return ComMDDeleteAllMetaDataD(hMDHandle,
(PBYTE)pszMDPath,
dwMDUserType,
dwMDDataType,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteAllMetaDataD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType,
IN BOOL bUnicode)
{
HRESULT hresReturn;
CMDBaseData *pbdCurrent;
DWORD i, dwNumDataObjects;
PVOID *ppvMainDataBuf = NULL;
CMDHandle *phoHandle;
CMDBaseObject *pboAffected;
DWORD dwCurrentDataID;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (dwMDDataType >= INVALID_END_METADATA) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
if ( SUCCEEDED(hresReturn) && ( pboAffected == NULL ) )
{
hresReturn = E_FAIL;
}
if ( SUCCEEDED(hresReturn) )
{
ppvMainDataBuf = GetMainDataBuffer();
MD_ASSERT (ppvMainDataBuf != NULL);
if ( ppvMainDataBuf == NULL )
{
hresReturn = E_FAIL;
}
}
if (SUCCEEDED(hresReturn)) {
MD_REQUIRE((phoHandle = GetHandleObject(hMDHandle)) != NULL);
dwNumDataObjects = pboAffected->GetAllDataObjects(ppvMainDataBuf,
METADATA_NO_ATTRIBUTES,
dwMDUserType,
dwMDDataType,
FALSE,
FALSE);
for (i = 0; i < dwNumDataObjects ; i++) {
pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
MD_ASSERT(pbdCurrent != NULL);
dwCurrentDataID = pbdCurrent->GetIdentifier();
MD_REQUIRE(pboAffected->RemoveDataObject(pbdCurrent, TRUE) == ERROR_SUCCESS);
phoHandle->SetChangeData(pboAffected, MD_CHANGE_TYPE_DELETE_DATA, dwCurrentDataID);
}
if (dwNumDataObjects > 0) {
g_dwSystemChangeNumber++;
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDHandle,
phoHandle,
(LPSTR)pszMDPath,
bUnicode);
}
FreeMainDataBuffer(ppvMainDataBuf);
}
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDCopyMetaDataA(
/* [in] */ METADATA_HANDLE hMDSourceHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDSourcePath,
/* [in] */ METADATA_HANDLE hMDDestHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDDestPath,
/* [in] */ DWORD dwMDAttributes,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType,
/* [in] */ BOOL bMDCopyFlag)
{
return ComMDCopyMetaDataD(hMDSourceHandle,
pszMDSourcePath,
hMDDestHandle,
pszMDDestPath,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
bMDCopyFlag,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDCopyMetaDataW(
/* [in] */ METADATA_HANDLE hMDSourceHandle,
/* [string][in][unique] */ LPCWSTR pszMDSourcePath,
/* [in] */ METADATA_HANDLE hMDDestHandle,
/* [string][in][unique] */ LPCWSTR pszMDDestPath,
/* [in] */ DWORD dwMDAttributes,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType,
/* [in] */ BOOL bMDCopyFlag)
{
return ComMDCopyMetaDataD(hMDSourceHandle,
(PBYTE)pszMDSourcePath,
hMDDestHandle,
(PBYTE)pszMDDestPath,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
bMDCopyFlag,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDCopyMetaDataD(
/* [in] */ METADATA_HANDLE hMDSourceHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDSourcePath,
/* [in] */ METADATA_HANDLE hMDDestHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDDestPath,
/* [in] */ DWORD dwMDAttributes,
/* [in] */ DWORD dwMDUserType,
/* [in] */ DWORD dwMDDataType,
/* [in] */ BOOL bMDCopyFlag,
IN BOOL bUnicode)
/*++
Routine Description:
Copies or moves data associated with the source object to the destination object.
Optionally copies inherited data based on the value of Attributes.
Arguments:
SrcHandle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with read permission.
SrcPath - The path of the meta object with which then source data is associated, relative to the
path of SrcHandle.
DestHandle - A handle returned by MDOpenMetaObject with write permission.
DestPath - The path of the meta object for data to be copied to, relative to the path of Handle.
Attributes - The flags for the data. See imd.h.
UserType - The User Type for the data. If not set to ALL_METADATA, only metadata of the specified
User Type will be copied. See imd.h.
DataType - Optional type of the data to copy. If not set to ALL_METADATA,
only data of that type will be copied.
CopyFlag - If true, data will be copied. If false, data will be moved.
Must be true if METADATA_INHERIT is set.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
ERROR_ACCESS_DENIED
ERROR_NOT_ENOUGH_MEMORY
Notes:
METADATA_MASTER_ROOT_HANDLE is a valid source handle if CopyFlag == TRUE,
but provides no gaurantee that other threads will not also change
things. If a consistent data state is desired, use a handle returned by
MDOpenMetaObject. METADATA_MASTER_ROOT_HANDLE is not a valid destination
handle.
If inherited data is copied, it will be copied to the destination object,
not the corresponding ancestor objects.
--*/
{
HRESULT hresReturn;
BOOL bInheritableOnly = FALSE;
CMDBaseData *pbdCurrent;
DWORD i, dwNumDataObjects;
PVOID *ppvMainDataBuf = NULL;
CMDBaseObject *pboSource = NULL, *pboDest = NULL;
LPSTR pszSourcePath = (LPSTR)pszMDSourcePath;
LPSTR pszDestPath = (LPSTR)pszMDDestPath;
BOOL fReadLocked = FALSE;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (((!bMDCopyFlag) && (dwMDAttributes & METADATA_INHERIT)) ||
((dwMDAttributes & METADATA_PARTIAL_PATH) && !(dwMDAttributes & METADATA_INHERIT))){
hresReturn = E_INVALIDARG;
}
else {
//
// Lock for source object. If copying, just get read lock. If moving,
// Need write lock.
//
if (bMDCopyFlag)
{
g_LockMasterResource.ReadLock();
fReadLocked = TRUE;
}
else
{
g_LockMasterResource.WriteLock();
fReadLocked = FALSE;
}
hresReturn = GetObjectFromPath(pboSource,
hMDSourceHandle,
((bMDCopyFlag) ? METADATA_PERMISSION_READ : METADATA_PERMISSION_WRITE),
(LPSTR)pszSourcePath,
bUnicode);
if ( SUCCEEDED(hresReturn) && ( pboSource == NULL ) )
{
hresReturn = E_FAIL;
}
if (SUCCEEDED(hresReturn)) {
bInheritableOnly = FALSE;
}
else if ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) &&
(pboSource != NULL) &&
(dwMDAttributes & METADATA_PARTIAL_PATH)) {
bInheritableOnly = TRUE;
hresReturn = ERROR_SUCCESS;
}
if ( SUCCEEDED(hresReturn) )
{
ppvMainDataBuf = GetMainDataBuffer();
MD_ASSERT (ppvMainDataBuf != NULL);
if ( ppvMainDataBuf == NULL )
{
hresReturn = E_FAIL;
}
}
if (SUCCEEDED(hresReturn)) {
dwNumDataObjects = pboSource->GetAllDataObjects(ppvMainDataBuf,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
bInheritableOnly,
FALSE);
if (fReadLocked)
{
g_LockMasterResource.ConvertSharedToExclusive();
fReadLocked = FALSE;
}
CMDHandle *hMDDestHandleObject = GetHandleObject(hMDDestHandle);
if(hMDDestHandleObject == NULL)
{
hresReturn = E_HANDLE;
}
else
{
hresReturn = GetObjectFromPathWithHandle(pboDest,
hMDDestHandle,
hMDDestHandleObject,
METADATA_PERMISSION_WRITE,
(LPSTR)pszDestPath,
bUnicode);
}
if (SUCCEEDED(hresReturn)) {
for (i = 0; (i < dwNumDataObjects) && (SUCCEEDED(hresReturn)) ; i++) {
pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
MD_ASSERT(pbdCurrent != NULL);
hresReturn = pboDest->SetDataObject(pbdCurrent);
if (SUCCEEDED(hresReturn)) {
MD_ASSERT(GetHandleObject(hMDDestHandle) != NULL);
hMDDestHandleObject->SetChangeData(pboDest,
MD_CHANGE_TYPE_SET_DATA,
pbdCurrent->GetIdentifier());
}
}
if ((!bMDCopyFlag) && (SUCCEEDED(hresReturn))) {
for (i = 0; i < dwNumDataObjects; i++) {
pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
MD_ASSERT(pbdCurrent != NULL);
MD_REQUIRE(pboSource->RemoveDataObject(pbdCurrent, TRUE) == ERROR_SUCCESS);
MD_ASSERT(GetHandleObject(hMDSourceHandle) != NULL);
GetHandleObject(hMDSourceHandle)->SetChangeData(pboSource,
MD_CHANGE_TYPE_DELETE_DATA,
pbdCurrent->GetIdentifier());
}
}
g_dwSystemChangeNumber++;
INCREMENT_SCHEMA_CHANGE_NUMBER(hMDDestHandle,
hMDDestHandleObject,
pszDestPath,
bUnicode);
}
FreeMainDataBuffer(ppvMainDataBuf);
}
if (fReadLocked)
{
g_LockMasterResource.ReadUnlock();
}
else
{
g_LockMasterResource.WriteUnlock();
}
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetMetaDataPathsA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDIdentifier,
/* [in] */ DWORD dwMDDataType,
/* [in] */ DWORD dwMDBufferSize,
/* [size_is][out] */ unsigned char __RPC_FAR *pszMDBuffer,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
{
return ComMDGetMetaDataPathsD(hMDHandle,
pszMDPath,
dwMDIdentifier,
dwMDDataType,
dwMDBufferSize,
pszMDBuffer,
pdwMDRequiredBufferSize,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetMetaDataPathsW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [in] */ DWORD dwMDIdentifier,
/* [in] */ DWORD dwMDDataType,
/* [in] */ DWORD dwMDBufferSize,
/* [size_is][out] */ LPWSTR pszMDBuffer,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
{
return ComMDGetMetaDataPathsD(hMDHandle,
(PBYTE)pszMDPath,
dwMDIdentifier,
dwMDDataType,
dwMDBufferSize,
(PBYTE)pszMDBuffer,
pdwMDRequiredBufferSize,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetMetaDataPathsD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDIdentifier,
/* [in] */ DWORD dwMDDataType,
/* [in] */ DWORD dwMDBufferSize,
/* [size_is][out] */ unsigned char __RPC_FAR *pszMDBuffer,
/* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize,
IN BOOL bUnicode)
{
HRESULT hresReturn = S_OK;
CMDHandle * phMDHandle;
CMDBaseObject *pboAssociated;
CMDBaseObject *pboHandle;
LPSTR pszPath = (LPSTR)pszMDPath;
DWORD i, dwNumMetaObjects;
DWORD dwBytesPerChar = ((bUnicode) ? sizeof(WCHAR) : sizeof(char));
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (((dwMDBufferSize != 0) && (pszMDBuffer == NULL)) ||
(dwMDDataType >= INVALID_END_METADATA) ||
(pdwMDRequiredBufferSize == NULL)) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
hresReturn = GetObjectFromPath(pboAssociated, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
if (SUCCEEDED(hresReturn)) {
PBYTE pbDataStart = pszMDBuffer;
PBYTE pbNextDataStart = pbDataStart;
PBYTE pbDataEnd = pszMDBuffer + (dwMDBufferSize * dwBytesPerChar);
CMDBaseObject *pboCurrent;
BUFFER bufPath;
BUFFER bufMainDataBuf;
DWORD dwReturn;
phMDHandle = GetHandleObject(hMDHandle);
if( !phMDHandle )
{
hresReturn = MD_ERROR_DATA_NOT_FOUND;
}
else
{
pboHandle = phMDHandle->GetObject();
MD_ASSERT(pboHandle != NULL);
dwNumMetaObjects = 0;
hresReturn = pboAssociated->GetDataRecursive(&bufMainDataBuf,
dwMDIdentifier,
dwMDDataType,
dwNumMetaObjects);
if (SUCCEEDED(hresReturn)) {
if (dwNumMetaObjects != 0) {
CMDBaseObject **ppboList = (CMDBaseObject **)bufMainDataBuf.QueryPtr();
for (i = 0;
(i < dwNumMetaObjects) &&
( SUCCEEDED(hresReturn) ||
hresReturn == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER));
i++, pbDataStart = pbNextDataStart) {
pboCurrent=ppboList[i];
MD_ASSERT(pboCurrent != NULL);
DWORD dwStringLen = 0;
dwReturn = GetObjectPath(pboCurrent,
&bufPath,
dwStringLen,
pboHandle,
bUnicode);
if (dwReturn != ERROR_SUCCESS) {
//
// Only blow away previous hresReturn if this failed.
//
hresReturn = RETURNCODETOHRESULT(dwReturn);
}
else {
//
// Need 2 extra characters for "/"
//
pbNextDataStart = pbDataStart + ((dwStringLen + 2) * dwBytesPerChar);
if (pbDataEnd < pbNextDataStart) {
hresReturn = RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
}
else {
MD_COPY(pbDataStart,
bufPath.QueryPtr(),
dwStringLen * dwBytesPerChar);
if (bUnicode) {
*(((LPWSTR)pbDataStart) + dwStringLen) = MD_PATH_DELIMETERW;
*(((LPWSTR)pbDataStart) + (dwStringLen + 1)) = (WCHAR)L'\0';
}
else {
*(((LPSTR)pbDataStart) + dwStringLen) = MD_PATH_DELIMETER;
*(((LPSTR)pbDataStart) + (dwStringLen + 1)) = (CHAR)'\0';
}
}
}
}
//
// Append a final 0 for double NULL termination
//
pbNextDataStart = pbDataStart + dwBytesPerChar;
if (SUCCEEDED(hresReturn)) {
if ((pbDataStart + dwBytesPerChar) <= pbDataEnd) {
if (bUnicode) {
*((LPWSTR)pbDataStart) = (WCHAR)L'\0';
}
else {
*((LPSTR)pbDataStart) = (CHAR)'\0';
}
}
else {
hresReturn = RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
}
}
}
else {
if (pszMDBuffer != NULL) {
//
// If NULL, just return success
// No strings, need to append 2 0's for double NULL termination
//
pbNextDataStart = pbDataStart + (dwBytesPerChar * 2);
if (pbNextDataStart <= pbDataEnd) {
if (bUnicode) {
*((LPWSTR)pbDataStart) = (WCHAR)L'\0';
*(((LPWSTR)pbDataStart) + 1) = (WCHAR)L'\0';
}
else {
*((LPSTR)pbDataStart) = (CHAR)'\0';
*(((LPSTR)pbDataStart) + 1) = (CHAR)'\0';
}
}
else {
hresReturn = RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
}
}
}
if (hresReturn == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER)) {
*pdwMDRequiredBufferSize = (DWORD)DIFF(pbNextDataStart - (PBYTE)pszMDBuffer) / dwBytesPerChar;
}
}
}
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDOpenMetaObjectA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDAccessRequested,
/* [in] */ DWORD dwMDTimeOut,
/* [out] */ PMETADATA_HANDLE phMDNewHandle)
{
return ComMDOpenMetaObjectD(hMDHandle,
pszMDPath,
dwMDAccessRequested,
dwMDTimeOut,
phMDNewHandle,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDOpenMetaObjectW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [in] */ DWORD dwMDAccessRequested,
/* [in] */ DWORD dwMDTimeOut,
/* [out] */ PMETADATA_HANDLE phMDNewHandle)
{
return ComMDOpenMetaObjectD(hMDHandle,
(PBYTE)pszMDPath,
dwMDAccessRequested,
dwMDTimeOut,
phMDNewHandle,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDOpenMetaObjectD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ DWORD dwMDAccessRequested,
/* [in] */ DWORD dwMDTimeOut,
/* [out] */ PMETADATA_HANDLE phMDNewHandle,
IN BOOL bUnicode)
/*++
Routine Description:
Opens a meta object for read and/or write access. The returned handle is
used by several of the other API's. Opening an object for Read access
guarantees that that view of the data will not change while the object
is open. Opening an object for write gaurantees that no other objects
will read or write any changed data until the handle is closed.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject.
Path - The path of the object to be opened.
AccessRequested - The permissions requested. See imd.h.
TimeOut - The time to block waiting for open to succeed, in miliseconds.
NewHandle - The handled to be passed to other MD routines.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
ERROR_PATH_BUSY
Notes:
Multiple read handles or a single write handle can be open on any given
object.
Opens for read will wait if the object being opened, any of its ancestor
objects, or any of its descendant objects is open for write.
Opens for write will wait if the object being opened, any of its ancestor
objects, or any of its descendant objects is open for read and/or write.
If the request is for write access or Handle has write access, Handle must be closed before
this request can succeed, unless Handle = METADATA_MASTER_ROOT_HANDLE.
Handles should be closed as quickly as possible, as open handles can cause other requests to block.
--*/
{
HRESULT hresReturn;
DWORD WaitRetCode;
METADATA_HANDLE mhTemp = NULL;
_int64 ExpireTime, CurrentTime, TimeLeft;
FILETIME TempTime;
BOOL bPermissionsAvailable = FALSE;
LPSTR pszPath = (LPSTR)pszMDPath;
BOOLEAN bSchemaKey = FALSE;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((phMDNewHandle == NULL) ||
((dwMDAccessRequested & (METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE)) == 0)) {
hresReturn = E_INVALIDARG;
}
else {
CMDBaseObject *pboOpen = NULL;
GetSystemTimeAsFileTime(&TempTime);
ExpireTime = ((_int64)TempTime.dwHighDateTime << 32) +
(_int64)TempTime.dwLowDateTime +
((_int64)dwMDTimeOut * 10000);
TimeLeft = dwMDTimeOut;
g_LockMasterResource.WriteLock();
hresReturn = GetObjectFromPath(pboOpen, hMDHandle, 0, pszPath, bUnicode);
if (SUCCEEDED(hresReturn)) {
bPermissionsAvailable = PermissionsAvailable(pboOpen, dwMDAccessRequested, 0);
}
//
// Spin loop waiting for permissions. Events get pulsed whenever a handle is closed.
// Use a wait interval in case the close comes between the Unlock and the Wait.
//
while ((SUCCEEDED(hresReturn)) && (!bPermissionsAvailable) && (TimeLeft > 0)) {
g_LockMasterResource.WriteUnlock();
if (dwMDAccessRequested & METADATA_PERMISSION_WRITE) {
WaitRetCode = WaitForMultipleObjects(EVENT_ARRAY_LENGTH, g_phEventHandles, FALSE, LESSOROF((DWORD)TimeLeft, OPEN_WAIT_INTERVAL));
}
else {
WaitRetCode = WaitForSingleObject(g_phEventHandles[EVENT_WRITE_INDEX], LESSOROF((DWORD)TimeLeft, OPEN_WAIT_INTERVAL));
}
GetSystemTimeAsFileTime(&TempTime);
CurrentTime = ((_int64)TempTime.dwHighDateTime << 32) + (_int64)TempTime.dwLowDateTime;
TimeLeft = ((ExpireTime - CurrentTime) / 10000);
g_LockMasterResource.WriteLock();
//
// Get object again to make sure the object hasn't been deleted
// Should probably put an exception handler PermissionsAvailable and use
// the current object
//
hresReturn = GetObjectFromPath(pboOpen, hMDHandle, 0, pszPath, bUnicode);
if (SUCCEEDED(hresReturn)) {
bPermissionsAvailable = PermissionsAvailable(pboOpen, dwMDAccessRequested, 0);
}
}
if (SUCCEEDED(hresReturn)) {
if (bPermissionsAvailable) {
if(METADATA_MASTER_ROOT_HANDLE == hMDHandle)
{
if((pszPath != NULL) && (0 != *pszPath))
{
if(bUnicode)
{
if( (0 == _wcsnicmp((LPWSTR)(pszMDPath), WSZSCHEMA_KEY_NAME1, WSZSCHEMA_KEY_LENGTH1)) ||
(0 == _wcsnicmp((LPWSTR)(pszMDPath), WSZSCHEMA_KEY_NAME2, WSZSCHEMA_KEY_LENGTH2)) ||
(0 == _wcsnicmp((LPWSTR)(pszMDPath), WSZSCHEMA_KEY_NAME3, WSZSCHEMA_KEY_LENGTH3))
)
{
bSchemaKey = TRUE;
}
}
else
{
if( (0 == _strnicmp((LPSTR)(pszMDPath), SZSCHEMA_KEY_NAME1, SZSCHEMA_KEY_LENGTH1)) ||
(0 == _strnicmp((LPSTR)(pszMDPath), SZSCHEMA_KEY_NAME2, SZSCHEMA_KEY_LENGTH2)) ||
(0 == _strnicmp((LPSTR)(pszMDPath), SZSCHEMA_KEY_NAME3, SZSCHEMA_KEY_LENGTH3))
)
{
bSchemaKey = TRUE;
}
}
}
}
else
{
CMDHandle *phoHandle;
phoHandle = GetHandleObject(hMDHandle);
if(phoHandle->IsSchemaHandle())
{
bSchemaKey = TRUE;
}
}
hresReturn = AddHandle(pboOpen, dwMDAccessRequested, mhTemp, bSchemaKey);
if (SUCCEEDED(hresReturn)) {
*phMDNewHandle = mhTemp;
}
}
else {
hresReturn = RETURNCODETOHRESULT(ERROR_PATH_BUSY);
}
}
if (bUnicode) {
if (SUCCEEDED(hresReturn)) {
DBGINFO((DBG_CONTEXT,
"Metabase handle %u opened, From handle %u and path %S, permissions = %u\n",
mhTemp,
hMDHandle,
((pszMDPath == NULL) || *((WCHAR *)pszMDPath) == (WCHAR)L'\0') ? L"NULL" : (WCHAR *)pszMDPath,
dwMDAccessRequested));
}
else {
DBGINFO((DBG_CONTEXT,
"Metabase Open of handle %u and path %S failed, return code = %X\n",
hMDHandle,
((pszMDPath == NULL) || *((WCHAR *)pszMDPath) == (WCHAR)L'\0') ? L"NULL" : (WCHAR *)pszMDPath,
hresReturn));
}
}
else {
if (SUCCEEDED(hresReturn)) {
DBGINFO((DBG_CONTEXT,
"Metabase handle %u opened, From handle %u and path %s, permissions = %u\n",
mhTemp,
hMDHandle,
((pszMDPath == NULL) || *((CHAR *)pszMDPath) == (CHAR)'\0') ? "NULL" : (CHAR *)pszMDPath,
dwMDAccessRequested));
}
else {
DBGINFO((DBG_CONTEXT,
"Metabase Open of handle %u and path %s failed, return code = %X\n",
hMDHandle,
((pszMDPath == NULL) || *((CHAR *)pszMDPath) == (CHAR)'\0') ? "NULL" : (CHAR *)pszMDPath,
hresReturn));
}
}
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDCloseMetaObject(
/* [in] */ METADATA_HANDLE hMDHandle)
/*++
Routine Description:
Closes a handle to a meta object. If the handle was opened with write
permission and changes have been made via this handle, this will cause all
registered callback functions to be called.
Arguments:
Handle - The handle returned by MDOpenMetaObject.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_HANDLE
--*/
{
HRESULT hresReturn;
CMDHandle *hoTemp = NULL;
BOOL bPulseWrite = FALSE;
BOOL bPulseRead = FALSE;
BOOL bSendNotifications = FALSE;
BOOL bDeleteChangeData = FALSE;
DWORD dwNumChangeEntries = 0;
PMD_CHANGE_OBJECT_W pcoBuffer = NULL;
BUFFER **ppbufStorageArray = NULL;
BOOL fReadLocked = FALSE;
g_LockMasterResource.WriteLock();
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((hMDHandle == METADATA_MASTER_ROOT_HANDLE) ||
((hoTemp = RemoveHandleObject(hMDHandle)) == NULL)) {
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
}
else {
if (hoTemp->IsWriteAllowed()) {
RemovePermissions(hoTemp->GetObject(), METADATA_PERMISSION_WRITE);
bPulseWrite = TRUE;
bSendNotifications = TRUE;
bDeleteChangeData = TRUE;
}
if (hoTemp->IsReadAllowed()) {
RemovePermissions(hoTemp->GetObject(), METADATA_PERMISSION_READ);
bPulseRead = TRUE;
}
if (bPulseWrite) {
bPulseWrite = PulseEvent(g_phEventHandles[EVENT_WRITE_INDEX]);
}
if (bPulseRead && !bPulseWrite) {
//
// A write pulse activates everyone, so only do this if we didn't already do a write pulse
//
bPulseRead = PulseEvent(g_phEventHandles[EVENT_READ_INDEX]);
}
if (bSendNotifications) {
g_LockMasterResource.ConvertExclusiveToShared();
fReadLocked = TRUE;
if (FAILED(CreateNotifications(hoTemp,
&dwNumChangeEntries,
&pcoBuffer,
&ppbufStorageArray))) {
bSendNotifications = FALSE;
}
}
hresReturn = ERROR_SUCCESS;
}
if (SUCCEEDED(hresReturn)) {
DBGINFO((DBG_CONTEXT,
"Metabase handle %u closed\n",
hMDHandle));
}
if (fReadLocked)
{
g_LockMasterResource.ReadUnlock();
}
else
{
g_LockMasterResource.WriteUnlock();
}
if (bSendNotifications) {
SendNotifications(hMDHandle,
dwNumChangeEntries,
pcoBuffer,
ppbufStorageArray);
DeleteNotifications(dwNumChangeEntries,
pcoBuffer,
ppbufStorageArray);
}
if (bDeleteChangeData) {
//
// Need to delete handle with write lock held,
// Since this can delete metaobjects which can delete
// data which accesses the data cache table.
//
g_LockMasterResource.WriteLock();
}
delete (hoTemp);
if (bDeleteChangeData) {
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDChangePermissions(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [in] */ DWORD dwMDTimeOut,
/* [in] */ DWORD dwMDAccessRequested)
/*++
Routine Description:
Changes permissions on an open meta object handle. If the handle had write permission and is being changed
to read only, this will cause all registered callback functions to be called.
Arguments:
Handle - The handle to be modified.
TimeOut - The time to block waiting for open to succeed, in miliseconds.
AccessRequested - The requested permissions. See imd.h.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_HANDLE
ERROR_PATH_BUSY
Notes:
Success or failure when adding permissions follows the same rules as OpenMetaObject.
TimeOut values should be short for this call, as it is quite possible for 2 threads
with read permission on the same data to attempt to update to write at the same time.
Both will block until one read handle is closed.
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
CMDHandle *hoTemp = NULL;
DWORD WaitRetCode;
_int64 ExpireTime, CurrentTime, TimeLeft;
FILETIME TempTime;
BOOL bPermissionsAvailable;
BOOL bAddRead, bAddWrite, bRemoveRead, bRemoveWrite = FALSE;
BOOL bEventPulsed = FALSE;
BOOL bSendNotifications = FALSE;
CMDHandle *phoNotifyHandle = NULL;
DWORD dwNumChangeEntries = 0;
PMD_CHANGE_OBJECT_W pcoBuffer = NULL;
BUFFER **ppbufStorageArray = NULL;
g_LockMasterResource.WriteLock();
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if ((hMDHandle == METADATA_MASTER_ROOT_HANDLE) || ((hoTemp = GetHandleObject(hMDHandle)) == NULL) ||
((dwMDAccessRequested & (METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE)) == 0)) {
hresReturn = E_INVALIDARG;
}
else if ((hoTemp = GetHandleObject(hMDHandle)) == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
}
else {
bAddRead = (!(hoTemp->IsReadAllowed()) && (dwMDAccessRequested & METADATA_PERMISSION_READ));
bAddWrite = (!(hoTemp->IsWriteAllowed()) && (dwMDAccessRequested & METADATA_PERMISSION_WRITE));
bRemoveRead = ((hoTemp->IsReadAllowed()) && !(dwMDAccessRequested & METADATA_PERMISSION_READ));
bRemoveWrite = ((hoTemp->IsWriteAllowed()) && !(dwMDAccessRequested & METADATA_PERMISSION_WRITE));
MD_ASSERT(!(bAddRead && bAddWrite));
MD_ASSERT(!(bRemoveRead && bRemoveWrite));
MD_ASSERT(!(bAddRead && bRemoveRead));
MD_ASSERT(!(bAddWrite && bRemoveWrite));
//
// Add permissions first, because if delete comes first, another
// object could open a handle to this in the interim, and the
// object could get deleted.
// Also, AddWrite can fail so it must be before RemoveRead
// to avoid partial completion.
//
if (bAddWrite) {
MD_ASSERT(hoTemp->IsReadAllowed());
GetSystemTimeAsFileTime(&TempTime);
ExpireTime = ((_int64)TempTime.dwHighDateTime << 32) + (_int64)TempTime.dwLowDateTime + ((_int64)dwMDTimeOut * 10000);
TimeLeft = dwMDTimeOut;
bPermissionsAvailable = PermissionsAvailable(hoTemp->GetObject(), METADATA_PERMISSION_WRITE, 1);
while ((!bPermissionsAvailable) && (TimeLeft > 0) && (hoTemp!=NULL)) {
g_LockMasterResource.WriteUnlock();
WaitRetCode = WaitForMultipleObjects(EVENT_ARRAY_LENGTH, g_phEventHandles, FALSE, LESSOROF((DWORD)TimeLeft, OPEN_WAIT_INTERVAL));
GetSystemTimeAsFileTime(&TempTime);
CurrentTime = ((_int64)TempTime.dwHighDateTime << 32) + (_int64)TempTime.dwLowDateTime;
TimeLeft = ((ExpireTime - CurrentTime) / 10000);
g_LockMasterResource.WriteLock();
//
// The meta object could not have been deleted while the handle is open
// but the handle object could have been deleted, so get it again.
//
hoTemp = GetHandleObject(hMDHandle);
if (hoTemp != NULL) {
bPermissionsAvailable = PermissionsAvailable(hoTemp->GetObject(), METADATA_PERMISSION_WRITE, 1);
}
}
if (hoTemp == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
}
else if (!bPermissionsAvailable) {
hresReturn = RETURNCODETOHRESULT(ERROR_PATH_BUSY);
}
else {
AddPermissions(hoTemp->GetObject(), METADATA_PERMISSION_WRITE);
}
}
if (SUCCEEDED(hresReturn)) {
if (bAddRead) {
MD_ASSERT(hoTemp->IsWriteAllowed());
//
// Must already have write access
// Just add read access
//
AddPermissions(hoTemp->GetObject(), METADATA_PERMISSION_READ);
}
if (bRemoveRead) {
RemovePermissions(hoTemp->GetObject(), METADATA_PERMISSION_READ);
bEventPulsed = PulseEvent(g_phEventHandles[EVENT_READ_INDEX]);
}
if (bRemoveWrite) {
RemovePermissions(hoTemp->GetObject(), METADATA_PERMISSION_WRITE);
bEventPulsed = PulseEvent(g_phEventHandles[EVENT_WRITE_INDEX]);
}
hoTemp->SetPermissions(dwMDAccessRequested);
}
}
if ((SUCCEEDED(hresReturn)) && bRemoveWrite) {
if (SUCCEEDED(CreateNotifications(hoTemp,
&dwNumChangeEntries,
&pcoBuffer,
&ppbufStorageArray))) {
phoNotifyHandle = new CMDHandle(hoTemp);
if (phoNotifyHandle == NULL) {
DeleteNotifications(dwNumChangeEntries,
pcoBuffer,
ppbufStorageArray);
}
else {
bSendNotifications = TRUE;
hoTemp->ZeroChangeList();
}
}
hoTemp->RemoveNotifications();
}
g_LockMasterResource.WriteUnlock();
if (bSendNotifications) {
SendNotifications(hMDHandle,
dwNumChangeEntries,
pcoBuffer,
ppbufStorageArray);
DeleteNotifications(dwNumChangeEntries,
pcoBuffer,
ppbufStorageArray);
//
// Need to delete handle with write lock held,
// Since this can delete metaobjects which can delete
// data which accesses the data cache table.
//
g_LockMasterResource.WriteLock();
delete (phoNotifyHandle);
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSaveData(
IN METADATA_HANDLE hMDHandle)
/*++
Routine Description:
Saves all data changed since the last load or save to permanent storage.
Arguments:
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
Errors returned by the file system.
Notes:
If the main file has been modified by other applications, this call will overwrite them.
--*/
{
HRESULT hresReturn;
IIS_CRYPTO_STORAGE CryptoStorage;
PIIS_CRYPTO_BLOB pSessionKeyBlob;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else {
hresReturn = InitStorageAndSessionKey(
&CryptoStorage,
&pSessionKeyBlob
);
if( SUCCEEDED(hresReturn) ) {
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else {
hresReturn = SaveAllData(FALSE, &CryptoStorage, pSessionKeyBlob, NULL, NULL, hMDHandle);
}
::IISCryptoFreeBlob(pSessionKeyBlob);
}
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetHandleInfo(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [out] */ PMETADATA_HANDLE_INFO pmdhiInfo)
/*++
Routine Description:
Gets the information associated with a handle.
Arguments:
Handle - The handle to get information about.
Info - Structure filled in with the information. See imd.h.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_HANDLE
Notes:
pmdhiInfo->dwMDSystemChangeNumber will correspond to the System Change Number at the time
the handle was created. It will not change if writes are done via this handle, or any other
handle. A client can compare this number with the value returned by MDGetSystemChangeNumber
to see if any writes have been done since the handle was opened.
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
CMDHandle *HandleObject;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (pmdhiInfo == NULL) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
HandleObject = GetHandleObject(hMDHandle);
if (HandleObject == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
}
else {
HandleObject->GetHandleInfo(pmdhiInfo);
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetSystemChangeNumber(
/* [out] */ DWORD __RPC_FAR *pdwSystemChangeNumber)
/*++
Routine Description:
Gets the System Change Number.
Arguments:
SystemChangeNumber - The system change number. This is incremented every time the metadata is updated.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
Notes:
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (pdwSystemChangeNumber == NULL) {
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
*pdwSystemChangeNumber = g_dwSystemChangeNumber;
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetDataSetNumberA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber)
{
return ComMDGetDataSetNumberD(hMDHandle,
pszMDPath,
pdwMDDataSetNumber,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetDataSetNumberW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber)
{
return ComMDGetDataSetNumberD(hMDHandle,
(PBYTE)pszMDPath,
pdwMDDataSetNumber,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetDataSetNumberD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in] */ unsigned char __RPC_FAR *pszMDPath,
/* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber,
IN BOOL bUnicode)
/*++
Routine Description:
Gets all the data set number associated with a Meta Object.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with read permission.
Path - The path of the meta object with which this data is associated, relative to the
path of Handle.
DataSetNumber - A number associated with this data set. Can be used to identify common data sets.
Filled in if successful.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
Notes:
All paths with the same data set number have identical data if inherited data is included.
The inverse is not true, eg. there may be paths with identical data but different data set numbers.
--*/
{
HRESULT hresReturn;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (pdwMDDataSetNumber == NULL){
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
CMDBaseObject *pboQueried = NULL;
hresReturn = GetObjectFromPath(pboQueried, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
if ( SUCCEEDED(hresReturn) && ( pboQueried == NULL ) )
{
hresReturn = E_FAIL;
}
if (SUCCEEDED(hresReturn)) {
*pdwMDDataSetNumber=pboQueried->GetDataSetNumber();
}
else if ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboQueried != NULL)) {
*pdwMDDataSetNumber=pboQueried->GetDescendantDataSetNumber();
hresReturn = ERROR_SUCCESS;
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDAddRefReferenceData(
/* [in] */ DWORD dwMDDataTag)
/*++
Routine Description:
AddRefs data gotten by reference via the ComMDGetMetaData, ComMDEnumMetadata, or ComMDGetAllMetadata.
Arguments:
DataTag - The tag returned with the data.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
Notes:
Tags are used without validation. Clients must not pass in invalid tags.
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (dwMDDataTag == 0){
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
#if DBG
//
// Make sure this is in the table
//
CMDBaseData *pbdAddRef = (CMDBaseData *)g_PointerMapper->FindMapping(dwMDDataTag);
DWORD dwHash = DATA_HASH(pbdAddRef->GetIdentifier());
CMDBaseData *pbdIndex;
BOOL bFound = FALSE;
if (g_ppbdDataHashTable[dwHash] == pbdAddRef) {
bFound = TRUE;
}
else {
for (pbdIndex=g_ppbdDataHashTable[dwHash];
(pbdIndex != NULL ) && (pbdIndex->GetNextPtr() != pbdAddRef);
pbdIndex = pbdIndex->GetNextPtr()) {
}
if (pbdIndex != NULL) {
bFound = TRUE;
}
}
MD_ASSERT(bFound);
#endif
((CMDBaseData *)(g_PointerMapper->FindMapping(dwMDDataTag)))->IncrementReferenceCount();
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDReleaseReferenceData(
/* [in] */ DWORD dwMDDataTag)
/*++
Routine Description:
Releases data gotten by reference via the ComMDGetMetaData, ComMDEnumMetadata, or ComMDGetAllMetadata.
Arguments:
DataTag - The tag returned with the data.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
Notes:
Tags are used without validation. Clients must not pass in invalid tags.
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (dwMDDataTag == 0){
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
DeleteDataObject((CMDBaseData *)(g_PointerMapper->FindMapping(dwMDDataTag)));
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSetLastChangeTimeA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ PFILETIME pftMDLastChangeTime)
{
return ComMDSetLastChangeTimeD(hMDHandle,
pszMDPath,
pftMDLastChangeTime,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSetLastChangeTimeW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [in] */ PFILETIME pftMDLastChangeTime)
{
return ComMDSetLastChangeTimeD(hMDHandle,
(PBYTE)pszMDPath,
pftMDLastChangeTime,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDSetLastChangeTimeD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [in] */ PFILETIME pftMDLastChangeTime,
IN BOOL bUnicode)
/*++
Routine Description:
Set the last change time associated with a Meta Object.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with write permission.
Path - The path of the affected meta object, relative to the path of Handle.
LastChangeTime - The new change time for the meta object.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
Notes:
Last change times are also updated whenever data or child objects are set, added, or deleted.
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
LPSTR pszPath = (LPSTR)pszMDPath;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (pftMDLastChangeTime == NULL){
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.WriteLock();
CMDBaseObject *pboAffected = NULL;
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
if (SUCCEEDED(hresReturn)) {
pboAffected->SetLastChangeTime(pftMDLastChangeTime);
}
g_LockMasterResource.WriteUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetLastChangeTimeA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [out] */ PFILETIME pftMDLastChangeTime)
{
return ComMDGetLastChangeTimeD(hMDHandle,
pszMDPath,
pftMDLastChangeTime,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetLastChangeTimeW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDPath,
/* [out] */ PFILETIME pftMDLastChangeTime)
{
return ComMDGetLastChangeTimeD(hMDHandle,
(PBYTE)pszMDPath,
pftMDLastChangeTime,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetLastChangeTimeD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDPath,
/* [out] */ PFILETIME pftMDLastChangeTime,
IN BOOL bUnicode)
/*++
Routine Description:
Set the last change time associated with a Meta Object.
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with write permission.
Path - The path of the affected meta object, relative to the path of Handle.
LastChangeTime - Place to return the change time for the meta object.
Return Value:
DWORD - ERROR_SUCCESS
MD_ERROR_NOT_INITIALIZED
ERROR_INVALID_PARAMETER
ERROR_PATH_NOT_FOUND
Notes:
Last change times are also updated whenever data or child objects are set, added, or deleted.
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
LPSTR pszPath = (LPSTR)pszMDPath;
PFILETIME pftTemp;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (pftMDLastChangeTime == NULL){
hresReturn = E_INVALIDARG;
}
else {
g_LockMasterResource.ReadLock();
CMDBaseObject *pboQueried = NULL;
hresReturn = GetObjectFromPath(pboQueried, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
if ((SUCCEEDED(hresReturn)) ||
((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboQueried != NULL))) {
pftTemp = pboQueried->GetLastChangeTime();
*pftMDLastChangeTime = *pftTemp;
}
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDBackupA(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags)
{
return ComMDBackupD(hMDHandle,
(LPSTR) pszMDBackupLocation,
dwMDVersion,
dwMDFlags,
FALSE,
NULL);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDBackupW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags)
{
return ComMDBackupD(hMDHandle,
(LPSTR) pszMDBackupLocation,
dwMDVersion,
dwMDFlags,
TRUE,
NULL);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDBackupWithPasswdW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [string][in][unique] */ LPCWSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags,
/* [string][in][unique] */ LPCWSTR pszPasswd)
{
STRAU strauPasswd;
if( !strauPasswd.Copy( (LPWSTR)pszPasswd ) )
{
return E_OUTOFMEMORY;
}
return ComMDBackupD(hMDHandle,
(LPSTR) pszMDBackupLocation,
dwMDVersion,
dwMDFlags,
TRUE,
strauPasswd.QueryStrA());
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDBackupD(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [in] */ LPSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags,
/* [in] */ BOOL bUnicode,
/* [in] */ LPSTR pszPasswd)
{
HRESULT hresReturn = ERROR_SUCCESS;
HRESULT hresWarning = ERROR_SUCCESS;
IIS_CRYPTO_STORAGE * pCryptoStorage = NULL;
PIIS_CRYPTO_BLOB pSessionKeyBlob = NULL;
OFSTRUCT ReOpenBuff;
STRAU strauBackupLocation;
STRAU strauSchemaLocation;
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else if (((dwMDFlags & !(MD_BACKUP_OVERWRITE |
MD_BACKUP_SAVE_FIRST |
MD_BACKUP_FORCE_BACKUP)) != 0) ||
(((dwMDFlags & MD_BACKUP_SAVE_FIRST) == 0) &&
((dwMDFlags & MD_BACKUP_FORCE_BACKUP) != 0))) {
hresReturn = E_INVALIDARG;
}
else {
if( dwMDFlags == 0 )
{
dwMDFlags = MD_BACKUP_SAVE_FIRST;
}
hresReturn = CreateBackupFileName(pszMDBackupLocation,
dwMDVersion,
bUnicode,
&strauBackupLocation,
&strauSchemaLocation);
if( FAILED( hresReturn ) )
{
return hresReturn;
}
MD_ASSERT(strauBackupLocation.QueryStr(FALSE) != NULL);
MD_ASSERT(strauSchemaLocation.QueryStr(FALSE) != NULL);
if( ( ( dwMDFlags & MD_BACKUP_OVERWRITE ) == 0 ) &&
( ( HFILE_ERROR != OpenFile( strauBackupLocation.QueryStr(FALSE),
&ReOpenBuff,
OF_EXIST ) ) ||
( HFILE_ERROR != OpenFile( strauSchemaLocation.QueryStr(FALSE),
&ReOpenBuff,
OF_EXIST ) ) ) )
{
return HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
}
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
if ((dwMDFlags & MD_BACKUP_SAVE_FIRST) != 0 || pszPasswd != NULL) {
if( !pszPasswd )
{
pCryptoStorage = new IIS_CRYPTO_STORAGE;
if( !pCryptoStorage )
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
hresReturn = InitStorageAndSessionKey(
pCryptoStorage,
&pSessionKeyBlob
);
}
}
else
{
pCryptoStorage = new IIS_CRYPTO_STORAGE2;
if( !pCryptoStorage )
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
hresReturn = InitStorageAndSessionKey2(
pszPasswd,
pCryptoStorage,
&pSessionKeyBlob
);
}
}
if( SUCCEEDED(hresReturn) ) {
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else {
if( !pszPasswd )
{
hresReturn = SaveAllData(FALSE,
pCryptoStorage,
pSessionKeyBlob,
NULL,
NULL,
hMDHandle,
TRUE
);
}
else
{
hresReturn = SaveAllData(FALSE,
pCryptoStorage,
pSessionKeyBlob,
(LPWSTR)strauBackupLocation.QueryStr(TRUE),
(LPWSTR)strauSchemaLocation.QueryStr(TRUE),
hMDHandle,
TRUE
);
}
}
if( !pszPasswd )
{
::IISCryptoFreeBlob(pSessionKeyBlob);
}
else
{
::IISCryptoFreeBlob2(pSessionKeyBlob);
}
}
if (FAILED(hresReturn)) {
hresWarning = MD_WARNING_SAVE_FAILED;
}
}
if (SUCCEEDED(hresReturn) || ((dwMDFlags & MD_BACKUP_FORCE_BACKUP) != 0)) {
//
// Copy the file
//
if ( !pszPasswd ) {
BOOL bFailIfExists = ((dwMDFlags & MD_BACKUP_OVERWRITE) == 0) ? TRUE : FALSE;
//
// Copy the file, for old backup method
//
if (!CopyFile(g_strRealFileName->QueryStr(),
strauBackupLocation.QueryStr(FALSE),
bFailIfExists) ||
!CopyFile(g_strSchemaFileName->QueryStr(),
strauSchemaLocation.QueryStr(FALSE),
bFailIfExists)) {
hresReturn = RETURNCODETOHRESULT(GetLastError());
}
}
if (SUCCEEDED(hresReturn)) {
HANDLE hTempFileHandle;
hTempFileHandle = CreateFile(strauBackupLocation.QueryStr(FALSE),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hTempFileHandle != INVALID_HANDLE_VALUE) {
FILETIME ftCurrent;
GetSystemTimeAsFileTime(&ftCurrent);
SetFileTime(hTempFileHandle,
NULL, // Creation Time
&ftCurrent, // Last AccessTime
&ftCurrent); // Last Change Time
CloseHandle(hTempFileHandle);
}
hresReturn = BackupCertificates ((LPCWSTR)pszMDBackupLocation,
strauBackupLocation.QueryStr(FALSE),
g_strRealFileName->QueryStr());
}
}
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
}
if (hresReturn == ERROR_SUCCESS) {
hresReturn = hresWarning;
}
if( pCryptoStorage )
{
delete pCryptoStorage;
pCryptoStorage = NULL;
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRestoreA(
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags)
{
return ComMDRestoreD((LPSTR) pszMDBackupLocation,
dwMDVersion,
dwMDFlags,
FALSE,
NULL);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRestoreW(
/* [string][in][unique] */ LPCWSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags)
{
return ComMDRestoreD((LPSTR) pszMDBackupLocation,
dwMDVersion,
dwMDFlags,
TRUE,
NULL);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRestoreWithPasswdW(
/* [string][in][unique] */ LPCWSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags,
/* [string][in][unique] */ LPCWSTR pszPasswd
)
{
STRAU strauPasswd;
if( !strauPasswd.Copy( (LPWSTR)pszPasswd ) )
{
return E_OUTOFMEMORY;
}
return ComMDRestoreD((LPSTR) pszMDBackupLocation,
dwMDVersion,
dwMDFlags,
TRUE,
strauPasswd.QueryStrA());
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRestoreD(
/* [in] */ LPSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ DWORD dwMDFlags,
/* [in] */ BOOL bUnicode,
/* [in] */ LPSTR pszPasswd
)
{
HRESULT hresReturn = ERROR_SUCCESS;
if ((dwMDVersion == MD_BACKUP_NEXT_VERSION) ||
(dwMDFlags != 0)) {
//
// CreateBackupFileName checks for valid name,
// but it allows NEXT_VERSION, so we check that here.
// Currently, no flags are defined
//
hresReturn = E_INVALIDARG;
}
else {
STRAU strauBackupLocation;
STRAU strauSchemaLocation;
hresReturn = CreateBackupFileName(pszMDBackupLocation,
dwMDVersion,
bUnicode,
&strauBackupLocation,
&strauSchemaLocation);
if(SUCCEEDED(hresReturn))
{
hresReturn = Restore(
pszMDBackupLocation,
&strauBackupLocation,
&strauSchemaLocation,
pszPasswd);
}
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumBackupsA(
/* [size_is (MD_BACKUP_MAX_LEN)][in, out] */ unsigned char __RPC_FAR *pszMDBackupLocation,
/* [out] */ DWORD *pdwMDVersion,
/* [out] */ PFILETIME pftMDBackupTime,
/* [in] */ DWORD dwMDEnumIndex)
{
return ComMDEnumBackupsD((LPSTR) pszMDBackupLocation,
pdwMDVersion,
pftMDBackupTime,
dwMDEnumIndex,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumBackupsW(
/* [size_is (MD_BACKUP_MAX_LEN)][in, out] */ LPWSTR pszMDBackupLocation,
/* [out] */ DWORD *pdwMDVersion,
/* [out] */ PFILETIME pftMDBackupTime,
/* [in] */ DWORD dwMDEnumIndex)
{
return ComMDEnumBackupsD((LPSTR) pszMDBackupLocation,
pdwMDVersion,
pftMDBackupTime,
dwMDEnumIndex,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumBackupsD(
/* [size_is (MD_BACKUP_MAX_LEN)][in, out] */ LPSTR pszMDBackupLocation,
/* [out] */ DWORD *pdwMDVersion,
/* [out] */ PFILETIME pftMDBackupTime,
/* [in] */ DWORD dwMDEnumIndex,
/* [in] */ BOOL bUnicode)
{
HRESULT hresReturn = ERROR_SUCCESS;
DWORD cchBackupNameLen;
if ((pszMDBackupLocation == NULL) ||
(pdwMDVersion == NULL)) {
//
// CreateBackupFileName checks for valid name,
// but it allows NEXT_VERSION, so we check that here.
// Currently, no flags are defined
//
hresReturn = E_INVALIDARG;
}
else {
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
STRAU strauBackupLocation;
if (!strauBackupLocation.Copy(g_pstrBackupFilePath->QueryStr())) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else if (!strauBackupLocation.Append("\\")) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
if (bUnicode) {
if (*(LPWSTR)pszMDBackupLocation == (WCHAR)L'\0') {
if (!strauBackupLocation.Append(L"*")) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
}
else {
if (!strauBackupLocation.Append((LPWSTR)pszMDBackupLocation)) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
}
}
else {
if (*(LPSTR)pszMDBackupLocation == '\0') {
if (!strauBackupLocation.Append("*")) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
}
else {
if (!strauBackupLocation.Append((LPSTR)pszMDBackupLocation)) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
}
}
}
if (SUCCEEDED(hresReturn)) {
if (SUCCEEDED(hresReturn)) {
if (!strauBackupLocation.Append(MD_BACKUP_SUFFIX)) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
if (!strauBackupLocation.Append("*")) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
//
// Make sure MultiByte string is valid
//
if (strauBackupLocation.QueryStrA() == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
}
}
}
}
if (SUCCEEDED(hresReturn))
{
//
// Successfully created the search name
// Enumerate files
//
MD_ASSERT(strauBackupLocation.QueryStr(FALSE) != NULL);
HANDLE hFile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA wfdFile;
DWORD dwEnumIndex = (DWORD) -1;
hFile = FindFirstFile(strauBackupLocation.QueryStrA(),
&wfdFile);
if (hFile == INVALID_HANDLE_VALUE)
{
hresReturn = RETURNCODETOHRESULT(GetLastError());
}
else
{
if (CheckDigits(wfdFile.cFileName +
GetBackupNameLen(wfdFile.cFileName) +
(sizeof(MD_BACKUP_SUFFIX) - 1)))
{
if ((!strauBackupLocation.Copy(wfdFile.cFileName) ||
(strauBackupLocation.QueryStrW() == NULL)))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
if ( bUnicode )
{
cchBackupNameLen = GetBackupNameLen( strauBackupLocation.QueryStrW() );
}
else
{
cchBackupNameLen = GetBackupNameLen( strauBackupLocation.QueryStrA() );
}
if ( ( cchBackupNameLen != 0 ) &&
( cchBackupNameLen <= MD_BACKUP_MAX_LEN ) )
{
//
// One of our files
//
dwEnumIndex++;
}
}
}
while (SUCCEEDED(hresReturn) && (dwEnumIndex != dwMDEnumIndex))
{
//
// Process the remaining files
//
if (FindNextFile(hFile, &wfdFile))
{
if (CheckDigits(wfdFile.cFileName +
GetBackupNameLen(wfdFile.cFileName) +
(sizeof(MD_BACKUP_SUFFIX) - 1)))
{
if ((!strauBackupLocation.Copy(wfdFile.cFileName) ||
(strauBackupLocation.QueryStrW() == NULL)))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
if ( bUnicode )
{
cchBackupNameLen = GetBackupNameLen( strauBackupLocation.QueryStrW() );
}
else
{
cchBackupNameLen = GetBackupNameLen( strauBackupLocation.QueryStrA() );
}
if ( ( cchBackupNameLen != 0 ) &&
( cchBackupNameLen <= MD_BACKUP_MAX_LEN ) )
{
//
// One of our files
//
dwEnumIndex++;
}
}
}
}
else
{
hresReturn = GetLastHResult();
}
}
FindClose(hFile);
}
if (SUCCEEDED(hresReturn))
{
//
// Found the file
// File name is in wfdFile.cFileName
// Time is in wfdFile.ftLastWriteTime
// Need to separate the name and version
// Reuse strauBackupLocation
//
DWORD dwNameLen;
if ((!strauBackupLocation.Copy(wfdFile.cFileName) ||
(strauBackupLocation.QueryStrW() == NULL)))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
//
// ANSI bytes might not equal characters, so use unicode
//
dwNameLen = GetBackupNameLen(strauBackupLocation.QueryStrW());
strauBackupLocation.SetLen(dwNameLen);
if ( bUnicode )
{
cchBackupNameLen = strauBackupLocation.QueryCCH();
}
else
{
cchBackupNameLen = strauBackupLocation.QueryCBA();
}
if ( ( cchBackupNameLen == 0 ) ||
( cchBackupNameLen > MD_BACKUP_MAX_LEN ) )
{
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
}
else
{
MD_COPY(pszMDBackupLocation,
strauBackupLocation.QueryStr(bUnicode),
strauBackupLocation.QueryCB(bUnicode) +
((bUnicode) ? sizeof(WCHAR) : sizeof(char)));
*pdwMDVersion = atol(wfdFile.cFileName +
//
// dwNameLen is # characters
// Need to add # bytes, so
// Get it from STRAU
//
strauBackupLocation.QueryCBA() +
(sizeof(MD_BACKUP_SUFFIX) - 1));
MD_COPY(pftMDBackupTime,
&(wfdFile.ftLastWriteTime),
sizeof(FILETIME));
}
}
}
else
{
if ((hresReturn == RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND)) ||
(hresReturn == RETURNCODETOHRESULT(ERROR_NO_MORE_FILES)))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS);
}
}
}
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteBackupA(
/* [string][in][unique] */ unsigned char __RPC_FAR *pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion)
{
return ComMDDeleteBackupD((LPSTR) pszMDBackupLocation,
dwMDVersion,
FALSE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteBackupW(
/* [string][in][unique] */ LPCWSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion)
{
return ComMDDeleteBackupD((LPSTR) pszMDBackupLocation,
dwMDVersion,
TRUE);
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDDeleteBackupD(
/* [in] */ LPSTR pszMDBackupLocation,
/* [in] */ DWORD dwMDVersion,
/* [in] */ BOOL bUnicode)
{
HRESULT hresReturn = ERROR_SUCCESS;
if (dwMDVersion == MD_BACKUP_NEXT_VERSION) {
//
// CreateBackupFileName checks for valid name,
// but it allows NEXT_VERSION, so we check that here.
//
hresReturn = E_INVALIDARG;
}
else {
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
STRAU strauBackupLocation;
STRAU strauSchemaLocation;
hresReturn = CreateBackupFileName(pszMDBackupLocation,
dwMDVersion,
bUnicode,
&strauBackupLocation,
&strauSchemaLocation);
if (SUCCEEDED(hresReturn)) {
MD_ASSERT(strauBackupLocation.QueryStr(FALSE) != NULL);
//
// Delete the file
//
if (!DeleteFile(strauBackupLocation.QueryStr(FALSE)) ||
!DeleteFile(strauSchemaLocation.QueryStr(FALSE)) ) {
hresReturn = RETURNCODETOHRESULT(GetLastError());
}
}
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDExportW(
/* [in] */ METADATA_HANDLE i_hMDHandle,
/* [string][in][unique] */ LPCWSTR i_wszPasswd,
/* [string][in][unique] */ LPCWSTR i_wszFileName,
/* [string][in][unique] */ LPCWSTR i_wszAbsSourcePath,
/* [in] */ DWORD i_dwMDFlags)
{
HRESULT hresReturn = ERROR_SUCCESS;
HRESULT hresWarning = ERROR_SUCCESS;
IIS_CRYPTO_STORAGE* pCryptoStorage = NULL;
PIIS_CRYPTO_BLOB pSessionKeyBlob = NULL;
//
// Validate parameters
//
if(i_wszFileName == NULL || i_wszAbsSourcePath == NULL)
{
return RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER);
}
//
// Validate flags
//
if( (i_dwMDFlags & ~(MD_EXPORT_INHERITED | MD_EXPORT_NODE_ONLY)) != 0 &&
i_dwMDFlags != 0 )
{
return RETURNCODETOHRESULT(ERROR_INVALID_FLAGS);
}
//
// We need ansi versions of these
//
STRAU strauPasswd;
if (g_dwInitialized == 0)
{
return MD_ERROR_NOT_INITIALIZED;
}
if(!strauPasswd.Copy(i_wszPasswd == NULL ? L"" : (LPWSTR)i_wszPasswd))
{
return RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
//
// TODO: Verify I need this semaphore.
// I think it is needed to read/write from the xml metabase. And, possibly
// for a temp file. I am not sure.
//
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
//
// Never do machine dependent encryption.
//
pCryptoStorage = new IIS_CRYPTO_STORAGE2;
if( !pCryptoStorage )
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
hresReturn = InitStorageAndSessionKey2(
strauPasswd.QueryStrA(),
pCryptoStorage,
&pSessionKeyBlob);
}
if( SUCCEEDED(hresReturn) ) {
if (g_dwInitialized == 0) {
hresReturn = MD_ERROR_NOT_INITIALIZED;
}
else {
hresReturn = SaveSomeData(
i_dwMDFlags & MD_EXPORT_INHERITED,
i_dwMDFlags & MD_EXPORT_NODE_ONLY,
true, // bOverwriteFile
pCryptoStorage,
pSessionKeyBlob,
i_wszFileName,
i_hMDHandle,
i_wszAbsSourcePath,
TRUE);
}
::IISCryptoFreeBlob2(pSessionKeyBlob);
}
// Now just set the file time
if (SUCCEEDED(hresReturn)) {
HANDLE hTempFileHandle;
hTempFileHandle = CreateFileW(i_wszFileName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hTempFileHandle != INVALID_HANDLE_VALUE) {
FILETIME ftCurrent;
GetSystemTimeAsFileTime(&ftCurrent);
SetFileTime(hTempFileHandle,
NULL, // Creation Time
&ftCurrent, // Last AccessTime
&ftCurrent); // Last Change Time
CloseHandle(hTempFileHandle);
}
//
// TODO: Figure out what this is and if i need it
//
/*hresReturn = BackupCertificates ((LPCWSTR)pszFileName,
strauFileName.QueryStr(FALSE),
g_strRealFileName->QueryStr());*/
}
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
if (hresReturn == ERROR_SUCCESS) {
hresReturn = hresWarning;
}
if( pCryptoStorage )
{
delete pCryptoStorage;
pCryptoStorage = NULL;
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDImportW(
/* [in] */ METADATA_HANDLE i_hMDHandle,
/* [string][in][unique] */ LPCWSTR i_wszDestPath,
/* [string][in][unique] */ LPCWSTR i_wszKeyType,
/* [string][in][unique] */ LPCWSTR i_wszPasswd,
/* [string][in][unique] */ LPCWSTR i_wszFileName,
/* [string][in][unique] */ LPCWSTR i_wszSourcePath,
/* [in] */ DWORD i_dwMDFlags)
{
HRESULT hresReturn = ERROR_SUCCESS;
if (i_wszFileName == NULL ||
i_wszSourcePath == NULL ||
i_wszDestPath == NULL ||
i_wszKeyType == NULL)
{
return E_INVALIDARG;
}
//
// Validate flags
//
if( (i_dwMDFlags & ~(MD_IMPORT_INHERITED | MD_IMPORT_NODE_ONLY | MD_IMPORT_MERGE)) != 0 &&
i_dwMDFlags != 0 )
{
return RETURNCODETOHRESULT(ERROR_INVALID_FLAGS);
}
//
// We need ANSI versions of the following
//
STRAU strauPasswd;
if (g_dwInitialized == 0)
{
return MD_ERROR_NOT_INITIALIZED;
}
if(!strauPasswd.Copy(i_wszPasswd == NULL ? L"" : (LPWSTR)i_wszPasswd))
{
return E_OUTOFMEMORY;
}
CMDBaseObject* pboNew = NULL;
//
// Clean up source path.
//
ULONG cchSource = (ULONG)wcslen(i_wszSourcePath);
LPWSTR wszSource = new WCHAR[cchSource+1];
if(wszSource == NULL)
{
return RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
for(ULONG i = 0; i <= cchSource; i++)
{
wszSource[i] = (i_wszSourcePath[i] == MD_ALT_PATH_DELIMETERW) ?
MD_PATH_DELIMETERW : i_wszSourcePath[i];
}
//
// Read the data from XML
//
if(SUCCEEDED(hresReturn))
{
hresReturn = ReadSomeDataFromXML(
strauPasswd.QueryStrA(),
(LPWSTR)i_wszFileName,
wszSource,
i_wszKeyType,
i_dwMDFlags,
FALSE, // do not have ReadSave semaphore
&pboNew);
if(FAILED(hresReturn)) {
DBGPRINTF(( DBG_CONTEXT,
"[CMDCOM::ComMDImportW] ReadSomeDataFromXML failed - error 0x%08lx\n", hresReturn));
}
}
//
// Copy the data into the metabase
//
if(SUCCEEDED(hresReturn)) {
hresReturn = CopyMetaObject(
NULL, //hMDSourceHandle
(LPBYTE)L"", //pszMDSourcePath
false, //bUseSourceHandle
pboNew, //we already have a pbo, use this instead
i_hMDHandle,
(LPBYTE)i_wszDestPath,
!(i_dwMDFlags & MD_IMPORT_MERGE),
TRUE, //bMDCopyFlag
TRUE //bUnicode
);
if(FAILED(hresReturn)) {
DBGPRINTF(( DBG_CONTEXT,
"[CMDCOM::ComMDImportW] CopyMetaObject failed - error 0x%08lx\n", hresReturn));
}
}
delete pboNew;
delete [] wszSource;
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDRestoreHistoryW(
/* [unique][in][string] */ LPCWSTR i_wszMDHistoryLocation,
/* [in] */ DWORD i_dwMDMajorVersion,
/* [in] */ DWORD i_dwMDMinorVersion,
/* [in] */ DWORD i_dwMDFlags)
{
int iLenHistoryLocation = 0;
HRESULT hresReturn = ERROR_SUCCESS;
//
// Validate string len
//
if(i_wszMDHistoryLocation)
{
for(iLenHistoryLocation = 0; iLenHistoryLocation < MD_BACKUP_MAX_LEN; iLenHistoryLocation++)
{
if(i_wszMDHistoryLocation[iLenHistoryLocation] == L'\0') break;
}
if(iLenHistoryLocation == MD_BACKUP_MAX_LEN)
{
hresReturn = E_INVALIDARG;
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
return hresReturn;
}
}
//
// Validate flags
//
if( (i_dwMDFlags & ~MD_HISTORY_LATEST) != 0 &&
i_dwMDFlags != 0 )
{
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_FLAGS);
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
return hresReturn;
}
LPWSTR wszHistoryPathPlusFile = NULL;
LPWSTR wszHistoryPathPlusSchema = NULL;
STRAU strauHistoryPathPlusFile;
STRAU strauHistoryPathPlusSchema;
LPCWSTR wszHistoryLocation = NULL;
ULONG cchHistoryLocation = NULL;
//
// Use i_wszMDHistoryLocation if supplied, else defaults
//
if(i_wszMDHistoryLocation == NULL || i_wszMDHistoryLocation[0] == L'\0' || iLenHistoryLocation == 0)
{
wszHistoryLocation = g_wszHistoryFileDir;
cchHistoryLocation = g_cchHistoryFileDir;
}
else
{
wszHistoryLocation = i_wszMDHistoryLocation;
cchHistoryLocation = iLenHistoryLocation;
}
//
// Construct wszHistoryPathPlusFile, wszHistoryPathPlusSchema
//
hresReturn = ConstructHistoryFileName(
&wszHistoryPathPlusFile,
(LPWSTR)wszHistoryLocation,
cchHistoryLocation,
g_wszRealFileNameWithoutPathWithoutExtension,
g_cchRealFileNameWithoutPathWithoutExtension,
g_wszRealFileNameExtension,
g_cchRealFileNameExtension,
i_dwMDMajorVersion,
i_dwMDMinorVersion);
if(FAILED(hresReturn))
{
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
goto exit;
}
hresReturn = ConstructHistoryFileName(
&wszHistoryPathPlusSchema,
(LPWSTR)wszHistoryLocation,
cchHistoryLocation,
g_wszSchemaFileNameWithoutPathWithoutExtension,
g_cchSchemaFileNameWithoutPathWithoutExtension,
g_wszSchemaFileNameExtension,
g_cchSchemaFileNameExtension,
i_dwMDMajorVersion,
i_dwMDMinorVersion);
if(FAILED(hresReturn))
{
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
goto exit;
}
//
// Use MD_HISTORY_LATEST flag if supplied
//
LPWSTR awszFiles[] = { wszHistoryPathPlusFile, wszHistoryPathPlusSchema, NULL };
LPWSTR awszExts[] = { g_wszRealFileNameExtension, g_wszSchemaFileNameExtension, NULL };
LPWSTR apInsert[] = { NULL, NULL, NULL };
if(i_dwMDFlags & MD_HISTORY_LATEST)
{
DWORD dwMajor = 0;
DWORD dwMinor = 0;
for(ULONG i = 0; awszFiles[i] != NULL; i++)
{
SIZE_T cch = wcslen(awszFiles[i]);
apInsert[i] = awszFiles[i] + cch;
apInsert[i] -= wcslen(awszExts[i]); // i.e. Go to start of: .xml
apInsert[i] -= MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW;
memcpy(
apInsert[i],
MD_HISTORY_FILE_SEARCH_EXTENSIONW,
(MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW) * sizeof(WCHAR));
}
hresReturn = GetMostRecentHistoryFile(
awszFiles[0], // this is: blah\metabase_??????????_??????????.xml
&dwMajor,
&dwMinor);
if(FAILED(hresReturn))
{
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
goto exit;
}
for(ULONG i = 0; apInsert[i] != NULL; i++)
{
// Move to first set of "?"
apInsert[i]++;
_snwprintf(apInsert[i], MD_DEFAULT_HISTORY_MAJOR_NUM_DIGITS, L"%010lu", dwMajor);
// Move to second set of "?"
apInsert[i] += MD_DEFAULT_HISTORY_MAJOR_NUM_DIGITS+1;
_snwprintf(apInsert[i], MD_DEFAULT_HISTORY_MINOR_NUM_DIGITS, L"%010lu", dwMinor);
}
}
if(!strauHistoryPathPlusFile.Copy(wszHistoryPathPlusFile))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
goto exit;
}
if(!strauHistoryPathPlusSchema.Copy(wszHistoryPathPlusSchema))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
goto exit;
}
hresReturn = Restore(
NULL,
&strauHistoryPathPlusFile,
&strauHistoryPathPlusSchema,
NULL);
if(FAILED(hresReturn))
{
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
goto exit;
}
exit:
delete [] wszHistoryPathPlusFile;
delete [] wszHistoryPathPlusSchema;
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDEnumHistoryW(
/* [size_is (MD_BACKUP_MAX_LEN)][in, out] */ LPWSTR io_wszMDHistoryLocation,
/* [out] */ DWORD *o_pdwMDMajorVersion,
/* [out] */ DWORD *o_pdwMDMinorVersion,
/* [out] */ PFILETIME o_pftMDHistoryTime,
/* [in] */ DWORD i_dwMDEnumIndex)
{
STRAU strauPattern;
int iLenHistoryLocation;
HRESULT hresReturn = ERROR_SUCCESS;
//
// Copies of out params
//
DWORD dwMDMajorVersion;
DWORD dwMDMinorVersion;
FILETIME ftMDHistoryTime;
//
// Validate parameters
//
if(io_wszMDHistoryLocation == NULL || o_pdwMDMajorVersion == NULL ||
o_pdwMDMinorVersion == NULL || o_pftMDHistoryTime == NULL) {
return E_INVALIDARG;
}
//
// Validate string len
//
for(iLenHistoryLocation = 0; iLenHistoryLocation < MD_BACKUP_MAX_LEN; iLenHistoryLocation++)
{
if(io_wszMDHistoryLocation[iLenHistoryLocation] == L'\0') break;
}
if(iLenHistoryLocation == MD_BACKUP_MAX_LEN) {
return E_INVALIDARG;
}
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
//
// Eg. c:\windows\system32\inetsrv\history\
//
if(io_wszMDHistoryLocation[0] == L'\0') {
//
// TODO: Get more meaningful hr
//
if(wcslen(g_wszHistoryFileDir) > MD_BACKUP_MAX_LEN-1) {
hresReturn = E_INVALIDARG;
goto exit;
}
if(!strauPattern.Copy(g_wszHistoryFileDir)) {
hresReturn = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
}
else {
if(!strauPattern.Copy(io_wszMDHistoryLocation)) {
hresReturn = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
if(io_wszMDHistoryLocation[iLenHistoryLocation-1] != L'\\') {
if(!strauPattern.Append(L"\\")) {
hresReturn = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
}
}
//
// Eg. c:\windows\system32\inetsrv\history\metabase_??????????_??????????.xml
//
if(!strauPattern.Append(g_wszRealFileNameWithoutPathWithoutExtension)) {
hresReturn = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
if(!strauPattern.Append(MD_HISTORY_FILE_SEARCH_EXTENSIONW)) {
hresReturn = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
if(!strauPattern.Append(g_wszRealFileNameExtension)) {
hresReturn = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
hresReturn = EnumFiles(strauPattern.QueryStrW(),
i_dwMDEnumIndex,
&dwMDMajorVersion,
&dwMDMinorVersion,
&ftMDHistoryTime);
if(FAILED(hresReturn)) {
goto exit;
}
//
// If everything succeeded, set out parameters
//
if(io_wszMDHistoryLocation[0] == L'\0') {
if( wcslen( g_wszHistoryFileDir ) < MD_BACKUP_MAX_LEN )
{
wcscpy(io_wszMDHistoryLocation, g_wszHistoryFileDir);
}
else
{
hresReturn = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto exit;
}
}
*o_pdwMDMajorVersion = dwMDMajorVersion;
*o_pdwMDMinorVersion = dwMDMinorVersion;
memcpy(o_pftMDHistoryTime, &ftMDHistoryTime, sizeof(FILETIME));
exit:
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDGetChildPathsW(
/* [in] */ METADATA_HANDLE hMDHandle,
/* [unique, in, string] */ LPCWSTR pszMDPath,
/* [in] */ DWORD cchMDBufferSize,
/* [out, size_is(dwMDBufferSize)] */ WCHAR *pszBuffer,
/* [out] */ DWORD *pcchMDRequiredBufferSize)
/*++
Routine Description:
Retrieves all child metaobjects by name and places them in a MULTISZ containing strings terminated by an empty string
Arguments:
Handle - METADATA_MASTER_ROOT_HANDLE or a handle returned by MDOpenMetaObject with read permission.
Path - Path of parent object, relative to the path of Handle.
eg. "Root Object/Child/GrandChild"
cchMDBufferSize - sizeof buffer passed in, in wchars
pszBuffer - buffer, allocated by caller, that result is placed into
pcchMDRequiredBufferSize - required size, filled in only if buffer is insufficient
Return Value:
HRESULT, S_OK on success
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
PBASEOBJECT_CONTAINER pboContainer = NULL;
CMDBaseObject *pboAffected = NULL;
LPSTR pszPath = (LPSTR)pszMDPath;
BOOL fLocked = FALSE;
BUFFER buffTemp;
size_t stCurrentSize = 0;
BOOL fRet = TRUE;
if (g_dwInitialized == 0)
{
hresReturn = MD_ERROR_NOT_INITIALIZED;
goto done;
}
fLocked = TRUE;
g_LockMasterResource.ReadLock();
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, TRUE);
if (FAILED(hresReturn))
{
goto done;
}
if ( pboAffected == NULL )
{
hresReturn = E_FAIL;
goto done;
}
// get the beginning of the child list (NULL)
pboContainer = pboAffected->NextChildObject(NULL);
while (pboContainer != NULL )
{
CMDBaseObject * pboChild;
pboChild = pboContainer->pboMetaObject;
// get the name of the child (the TRUE indicates in UNICODE)
LPWSTR pszName = (LPWSTR)pboChild->GetName(TRUE);
if (pszName == NULL)
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
size_t stNameLen = wcslen(pszName);
// the new size is the current size + length of new string + 1 for terminating NULL
size_t stNewSize = stCurrentSize + stNameLen + 1;
fRet = buffTemp.Resize((UINT)(stNewSize * sizeof(WCHAR)), (UINT)(stNewSize * sizeof(WCHAR)));
if (FALSE == fRet)
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
// setup the destination pointer for the current name
WCHAR *pDest = (WCHAR*)buffTemp.QueryPtr();
pDest += stCurrentSize;
// actually do the copy
memcpy(pDest, pszName, sizeof(WCHAR) * (stNameLen + 1));
// get the size setup for the next iteration of the loop
stCurrentSize = stNewSize;
// get the next child in the list
pboContainer = pboAffected->NextChildObject(pboContainer);
}
if (0 == stCurrentSize)
{
// there were no children, place a NULL into the buffer.
fRet = buffTemp.Resize(sizeof(WCHAR), 0);
if (FALSE == fRet)
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
WCHAR *pDest = (WCHAR*)buffTemp.QueryPtr();
pDest[0] = '\0';
// and setup the currentsize correctly
stCurrentSize = 1;
}
// require one extra character for the extra terminating NULL
if (cchMDBufferSize >= (stCurrentSize + 1))
{
if (pszBuffer)
{
// copy over from the buffer to the outgoing buffer
memcpy(pszBuffer, buffTemp.QueryPtr(), stCurrentSize * sizeof(WCHAR));
// add the final terminating null
*( pszBuffer + stCurrentSize ) = L'\0';
// everything suceeded
hresReturn = ERROR_SUCCESS;
}
else
{
// received a buffer size that was large enough, but no buffer
hresReturn = HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
}
}
else if (pcchMDRequiredBufferSize)
{
// didn't receive a large enough buffer.
// indicate the required size
*pcchMDRequiredBufferSize = (DWORD)(stCurrentSize + 1);
// and there was insufficient buffer
hresReturn = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
else
{
// passed in buffer wasn't large enough, and nowhere to store the needed size
hresReturn = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
done:
if (fLocked)
{
g_LockMasterResource.ReadUnlock();
}
return hresReturn;
}
HRESULT STDMETHODCALLTYPE
CMDCOM::ComMDStopEWR(VOID)
/*++
Routine Description:
Signal EWR to stop and waits for EWR thread to exit.
This must be done before ABO terminates, because EWR uses ABO although living in metadata.
Arguments:
None
Return Value:
HRESULT
--*/
{
// Locals
HRESULT hr = S_OK;
CListenerController * pListenerController = NULL;
if ( g_pListenerController == NULL )
{
goto exit;
}
g_LockMasterResource.ReadLock();
pListenerController = g_pListenerController;
if (pListenerController != NULL )
{
pListenerController->AddRef();
}
g_LockMasterResource.ReadUnlock();
if ( pListenerController != NULL )
{
hr = pListenerController->Stop( iSTATE_STOP_PERMANENT, NULL );
}
exit:
if ( pListenerController != NULL )
{
pListenerController->Release();
pListenerController = NULL;
}
return hr;
}
HRESULT CMDCOM::Restore(
LPSTR i_pszMDBackupLocation,
STRAU* i_pstrauFile,
STRAU* i_pstrauSchema,
LPSTR i_pszPasswd)
/*++
Synopsis:
Private method used by Restore and RestoreHistory
Arguments: [i_pszMDBackupLocation] - can be NULL
[i_pstrauFile] -
[i_pstrauSchema] -
[i_pszPasswd] - can be NULL (always NULL in case of RestoreHistory)
Return Value:
--*/
{
MD_ASSERT(i_pstrauFile);
MD_ASSERT(i_pstrauSchema);
HRESULT hresReturn = S_OK;
DWORD dwInitializedSave = 0;
//
// Send notifications before we grab locks in case users
// try to access metabase. It would be nice to check the
// file name before doing this but that requires ReadSaveSemaphore.
//
// Send Shutdown Notification since we don't have a Restore
// Notification and it's close enough.
//
SendShutdownNotifications();
//
// Give applications some time to close their interfaces,
// but don't wait too long, user is waiting.
// Wait until references are closed, unless they take too long.
// IISADMIN and factory both have refences we do not wait for.
//
// We don't actually need to wait during restore, since
// interfaces are preserved, but waiting will allow clients
// to cleanup properly.
//
for (int i = 0;
(InterlockedIncrement((long *)&m_dwRefCount) > 3) &&
(i < MD_SHUTDOWN_WAIT_SECONDS);
i++) {
InterlockedDecrement((long *)&m_dwRefCount);
Sleep(1000);
}
InterlockedDecrement((long *)&m_dwRefCount);
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
if (SUCCEEDED(hresReturn)) {
//
// Got a valid name
// See if the file exists
//
MD_ASSERT(i_pstrauFile->QueryStr(FALSE) != NULL);
MD_ASSERT(i_pstrauSchema->QueryStr(FALSE) != NULL);
HANDLE hFile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA wfdFile;
STR strCopyOfMetabaseFileName (*g_strRealFileName);
hFile = FindFirstFile(i_pstrauFile->QueryStrA(),
&wfdFile);
if (hFile == INVALID_HANDLE_VALUE) {
hresReturn = RETURNCODETOHRESULT(GetLastError());
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
}
else {
FindClose(hFile);
//
// File actually exists,
// Go ahead and restore.
//
g_LockMasterResource.WriteLock();
//
// Prevent saves during termination.
//
BOOL bPrevSaveDisallowed = g_bSaveDisallowed;
g_bSaveDisallowed = TRUE;
dwInitializedSave = 0;
if( g_dwInitialized != 0 )
{
dwInitializedSave = g_dwInitialized;
while (g_dwInitialized > 0) {
TerminateWorker1(TRUE);
}
}
g_bSaveDisallowed = bPrevSaveDisallowed;
while (SUCCEEDED(hresReturn) && (g_dwInitialized < dwInitializedSave))
{
hresReturn = InitWorker(TRUE,
i_pszPasswd,
i_pstrauFile->QueryStr(FALSE),
i_pstrauSchema->QueryStr(FALSE));
if(HRESULT_FACILITY(hresReturn) == FACILITY_CONFIGURATION)
{
//
// Some facility_configuration errors are converted to md_error
// in InitWorker. For the remainder, this has to suffice.
//
DBGERROR((DBG_CONTEXT,
"[CMDCOM::Restore] InitWorker returned hr=0x%x\n", hresReturn));
hresReturn = MD_ERROR_READ_METABASE_FILE;
}
}
if( SUCCEEDED(hresReturn) && i_pszMDBackupLocation)
{
RestoreCertificates ((LPCWSTR)i_pszMDBackupLocation,
i_pstrauFile->QueryStr(FALSE),
strCopyOfMetabaseFileName.QueryStr());
}
//
// Need to flush the newly restored data out
//
g_dwSystemChangeNumber++;
g_dwSchemaChangeNumber++;
g_LockMasterResource.WriteUnlock();
//
// At this point all old handles are invalidated
// and all no new handles have been opened.
// So tell clients to invalidate any open handles now.
//
if (SUCCEEDED(hresReturn)) {
SendEventNotifications(MD_EVENT_MID_RESTORE);
}
}
}
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
//
// Try to load metadata from metabase.bin file on failure
//
if( FAILED( hresReturn ) )
{
HRESULT hrTemp = S_OK;
while (SUCCEEDED(hrTemp) && (g_dwInitialized < dwInitializedSave))
{
hrTemp = InitWorker(FALSE, NULL, NULL, NULL);
//
// Some facility_configuration errors are converted to md_error
// in InitWorker. For the remainder, this has to suffice.
//
if(HRESULT_FACILITY(hresReturn) == FACILITY_CONFIGURATION)
{
DBGERROR((DBG_CONTEXT,
"[CMDCOM::Restore] InitWorker returned hr=0x%x\n", hresReturn));
hresReturn = MD_ERROR_READ_METABASE_FILE;
}
}
}
else
{
//
// Need to flush newly restored data to Metabase.bin file
//
hresReturn = ComMDSaveData( METADATA_MASTER_ROOT_HANDLE );
}
if(FAILED(hresReturn))
{
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
}
return hresReturn;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: COPaper::NotifySinks
Summary: Internal utility method of this COM object used to fire event
notification calls to all listening connection sinks in the
client.
Modifies: ...
Returns: HRESULT
Standard COM result code. S_OK for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
HRESULT
CMDCOM::NotifySinks(
METADATA_HANDLE hHandle,
PMD_CHANGE_OBJECT pcoChangeList,
DWORD dwNumEntries,
BOOL bUnicode,
DWORD dwNotificationType,
DWORD dwEvent)
{
HRESULT hr = S_OK;
HRESULT hrT = S_OK;
COConnectionPoint *pCoConnectionPoint = NULL;
CONNECTDATA *pConnData = NULL;
ULONG cConnData = 0;
ULONG i;
IMDCOMSINKA *pIMDCOMSINKA = NULL;
IMDCOMSINKW *pIMDCOMSINKW = NULL;
DBG_ASSERT( ( dwNotificationType == MD_SINK_MAIN ) ||
( dwNotificationType == MD_SINK_SHUTDOWN ) ||
( ( dwNotificationType == MD_SINK_EVENT ) && bUnicode ) );
FlushSomeData();
if ( bUnicode )
{
pCoConnectionPoint = (COConnectionPoint*)m_aConnectionPoints[MD_CONNPOINT_WRITESINK_W];
}
else
{
pCoConnectionPoint = (COConnectionPoint*)m_aConnectionPoints[MD_CONNPOINT_WRITESINK_A];
}
if ( pCoConnectionPoint == NULL )
{
goto exit;
}
pCoConnectionPoint->AddRef();
hr = pCoConnectionPoint->InternalEnumSinks( &pConnData, &cConnData );
if ( FAILED( hr ) || ( cConnData == 0 ) )
{
goto exit;
}
if (bUnicode)
{
// Loop thru the connection point's connections
// dispatch the event notification to that sink.
for ( i = 0; i<cConnData; i++ )
{
DBG_ASSERT( pConnData[i].pUnk != NULL );
hrT = pConnData[i].pUnk->QueryInterface( IID_IMDCOMSINK_W,
(VOID**)&pIMDCOMSINKW );
if ( FAILED( hrT ) )
{
continue;
}
DBG_ASSERT( pIMDCOMSINKW != NULL );
switch ( dwNotificationType )
{
case MD_SINK_MAIN:
pIMDCOMSINKW->ComMDSinkNotify( hHandle,
dwNumEntries,
(PMD_CHANGE_OBJECT_W)pcoChangeList );
break;
case MD_SINK_SHUTDOWN:
//
// Shutdown Notifications
//
pIMDCOMSINKW->ComMDShutdownNotify();
break;
case MD_SINK_EVENT:
pIMDCOMSINKW->ComMDEventNotify( dwEvent );
break;
}
pIMDCOMSINKW->Release();
pIMDCOMSINKW = NULL;
}
}
else
{
// Loop thru the connection point's connections
// dispatch the event notification to that sink.
for ( i = 0; i<cConnData; i++ )
{
DBG_ASSERT( pConnData[i].pUnk != NULL );
hrT = pConnData[i].pUnk->QueryInterface( IID_IMDCOMSINK_A,
(VOID**)&pIMDCOMSINKA );
if ( FAILED( hrT ) )
{
continue;
}
DBG_ASSERT( pIMDCOMSINKA != NULL );
switch ( dwNotificationType )
{
case MD_SINK_MAIN:
pIMDCOMSINKA->ComMDSinkNotify( hHandle,
dwNumEntries,
(PMD_CHANGE_OBJECT_A)pcoChangeList );
break;
case MD_SINK_SHUTDOWN:
//
// Shutdown Notifications
//
pIMDCOMSINKA->ComMDShutdownNotify();
break;
}
pIMDCOMSINKA->Release();
pIMDCOMSINKA = NULL;
}
}
exit:
DBG_ASSERT( pIMDCOMSINKA == NULL );
DBG_ASSERT( pIMDCOMSINKW == NULL );
if ( pConnData != NULL )
{
for ( i = 0; i<cConnData; i++ )
{
if ( pConnData[i].pUnk != NULL )
{
pConnData[i].pUnk->Release();
pConnData[i].pUnk = NULL;
}
}
delete [] pConnData;
pConnData = NULL;
}
if ( pCoConnectionPoint != NULL )
{
pCoConnectionPoint->Release();
pCoConnectionPoint = NULL;
}
return hr;
}
HRESULT
CMDCOM::ConvertNotificationsToDBCS(DWORD dwNumChangeEntries,
BUFFER **ppbufStorageArray)
{
HRESULT hresReturn = S_OK;
//
// ppbufStorageArray is an array of buffer pointers,
// where each buffer contains a UNICODE path string
// which needs to be converted to a Local System path string
//
STRAU strauPath;
STRAU strauPathOptional;
LPSTR pszDBCSPath;
LPSTR pszDBCSPathOptional = NULL;
LPSTR pmultiszTarget;
DWORD dwStrLen1,dwStrLen2 = 0;
for (DWORD i = 0; i < dwNumChangeEntries; i++) {
MD_ASSERT(ppbufStorageArray[i] != NULL);
pmultiszTarget = (LPSTR) ppbufStorageArray[i]->QueryPtr();
if (!strauPath.Copy((LPWSTR)pmultiszTarget))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
if ((PWORD)(pmultiszTarget + strauPath.QueryCBW() + sizeof (WCHAR)))
{
if (!strauPathOptional.Copy((LPWSTR)(pmultiszTarget + strauPath.QueryCBW() + sizeof (WCHAR))))
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
pszDBCSPathOptional = strauPathOptional.QueryStrA();
if (pszDBCSPathOptional == NULL)
{
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
dwStrLen2 = strauPathOptional.QueryCBA() + 1 ;
}
}
}
if (hresReturn == S_OK)
{
pszDBCSPath = strauPath.QueryStrA();
if (pszDBCSPath == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
dwStrLen1 = strauPath.QueryCBA() + 1 ;
MD_ASSERT(ppbufStorageArray[i]->QuerySize() >= (dwStrLen1 + dwStrLen2 + sizeof(char)));
MD_COPY(pmultiszTarget, pszDBCSPath, dwStrLen1 );
if ( ( dwStrLen2 >0 ) && ( pszDBCSPathOptional != NULL ) )
{
MD_COPY(pmultiszTarget + dwStrLen1 , pszDBCSPathOptional, dwStrLen2 );
}
*(pmultiszTarget + dwStrLen1 + dwStrLen2) = '\0';
}
}
}
}
return hresReturn;
}
VOID
CMDCOM::SendShutdownNotifications()
{
NotifySinks(0,
NULL,
0,
TRUE,
MD_SINK_SHUTDOWN);
NotifySinks(0,
NULL,
0,
FALSE,
MD_SINK_SHUTDOWN);
}
VOID
CMDCOM::SendEventNotifications(DWORD dwEvent)
{
NotifySinks(0,
NULL,
0,
TRUE,
MD_SINK_EVENT,
dwEvent);
}
VOID
CMDCOM::SendNotifications(METADATA_HANDLE hHandle,
DWORD dwTotalNumChangeEntries,
PMD_CHANGE_OBJECT_W pcoBuffer,
BUFFER **ppbufStorageArray
)
{
DWORD dwNumChangeEntries;
DWORD dwRemainingNumChangeEntries = dwTotalNumChangeEntries;
while (dwRemainingNumChangeEntries != 0) {
dwNumChangeEntries = LESSOROF(dwRemainingNumChangeEntries, MD_MAX_CHANGE_ENTRIES);
NotifySinks(hHandle,
(PMD_CHANGE_OBJECT)(pcoBuffer + (dwTotalNumChangeEntries - dwRemainingNumChangeEntries)),
dwNumChangeEntries,
TRUE,
MD_SINK_MAIN);
dwRemainingNumChangeEntries -= dwNumChangeEntries;
}
if (SUCCEEDED(ConvertNotificationsToDBCS(dwTotalNumChangeEntries,
ppbufStorageArray))) {
dwRemainingNumChangeEntries = dwTotalNumChangeEntries;
while (dwRemainingNumChangeEntries != 0) {
dwNumChangeEntries = LESSOROF(dwRemainingNumChangeEntries, MD_MAX_CHANGE_ENTRIES);
NotifySinks(hHandle,
(PMD_CHANGE_OBJECT)(pcoBuffer + (dwTotalNumChangeEntries - dwRemainingNumChangeEntries)),
dwNumChangeEntries,
FALSE,
MD_SINK_MAIN);
dwRemainingNumChangeEntries -= dwNumChangeEntries;
}
}
}
VOID
CMDCOM::DeleteNotifications(DWORD dwNumChangeEntries,
PMD_CHANGE_OBJECT_W pcoBuffer,
BUFFER **ppbufStorageArray
)
{
if (dwNumChangeEntries != 0 )
{
if( ppbufStorageArray != NULL )
{
for( DWORD i = 0; i < dwNumChangeEntries; i++ )
{
if (ppbufStorageArray[i] != NULL)
{
delete ppbufStorageArray[i];
ppbufStorageArray[i] = NULL;
}
}
delete [] ppbufStorageArray;
}
delete pcoBuffer;
}
}
HRESULT
CMDCOM::CreateNotifications(CMDHandle *phoHandle,
DWORD *pdwNumChangeEntries,
PMD_CHANGE_OBJECT_W *ppcoBuffer,
BUFFER ***pppbufStorageArray
)
{
HRESULT hRes = ERROR_SUCCESS;
DWORD dwReturn = ERROR_SUCCESS;
PCHANGE_ENTRY pceChange;
DWORD i;
BUFFER **ppbufStorageArray = NULL;
DWORD dwStringLen, dwStringOldNameLen;
DWORD dwNumChangeEntries;
PMD_CHANGE_OBJECT_W pcoBuffer = NULL;
dwNumChangeEntries = phoHandle->GetNumChangeEntries();
if (dwNumChangeEntries != 0) {
ppbufStorageArray = new BUFFER *[dwNumChangeEntries];
if (ppbufStorageArray == NULL) {
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
}
else {
for (i = 0; i < dwNumChangeEntries; i++) {
ppbufStorageArray[i] = new BUFFER();
if (ppbufStorageArray[i] == NULL) {
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
}
}
if (dwReturn == ERROR_SUCCESS) {
//
// Create UNICODE callbacks
//
pcoBuffer = new MD_CHANGE_OBJECT_W[dwNumChangeEntries];
if (pcoBuffer == NULL) {
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
}
else {
for (i = 0;
(dwReturn == ERROR_SUCCESS) && (i < dwNumChangeEntries);
i++) {
MD_REQUIRE((pceChange = phoHandle->EnumChangeEntries(i)) != NULL);
dwStringLen = 0;
dwReturn = GetObjectPath(pceChange->pboChanged,
ppbufStorageArray[i],
dwStringLen,
g_pboMasterRoot,
TRUE);
if (dwReturn == ERROR_SUCCESS) {
dwStringOldNameLen = 0;
if ( pceChange->pStrOrigName !=NULL) {
dwStringOldNameLen = pceChange->pStrOrigName->QueryCCH ();
}
// we adding 5, because: 1 for path_delimiter first line 1 for term-zero for first line
// 1 for path_delimiter second line 1 for term-zero for second line
// and last 1 for multisz term-zero
if (!ppbufStorageArray[i]->Resize((dwStringLen + dwStringOldNameLen + 5 ) * sizeof(WCHAR))) {
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
}
else {
pcoBuffer[i].dwMDChangeType = pceChange->dwChangeType;
pcoBuffer[i].pszMDPath = (LPWSTR)(ppbufStorageArray[i]->QueryPtr());
pcoBuffer[i].pszMDPath[dwStringLen] = MD_PATH_DELIMETERW;
pcoBuffer[i].pszMDPath[dwStringLen + 1] = (WCHAR)L'\0';
pcoBuffer[i].pszMDPath[dwStringLen + 2] = (WCHAR)L'\0';
if ( dwStringOldNameLen )
{
memcpy (&(pcoBuffer[i].pszMDPath[dwStringLen + 2]),
pceChange->pStrOrigName->QueryStrW(),
dwStringOldNameLen * sizeof(WCHAR) );
pcoBuffer[i].pszMDPath[dwStringLen + 2 + dwStringOldNameLen] = MD_PATH_DELIMETERW;
pcoBuffer[i].pszMDPath[dwStringLen + 3 + dwStringOldNameLen] = (WCHAR)L'\0';
}
pcoBuffer[i].dwMDNumDataIDs = pceChange->dwNumDataIDs;
if (pceChange->dwNumDataIDs != 0) {
MD_ASSERT(pceChange->pbufDataIDs != NULL);
pcoBuffer[i].pdwMDDataIDs = (DWORD *)(pceChange->pbufDataIDs->QueryPtr());
}
}
}
}
}
}
}
}
if (dwReturn != ERROR_SUCCESS) {
//
// Free Buffers
//
DeleteNotifications(dwNumChangeEntries,
pcoBuffer,
ppbufStorageArray);
hRes = RETURNCODETOHRESULT(dwReturn);
}
else {
//
// Pass back info
// DeleteNotifications will be called later
//
*pdwNumChangeEntries = dwNumChangeEntries;
*pppbufStorageArray = ppbufStorageArray;
*ppcoBuffer = pcoBuffer;
}
if (dwReturn != ERROR_SUCCESS) {
hRes = RETURNCODETOHRESULT(dwReturn);
}
return hRes;
}
VOID CMDCOM::InitializeFlusher (VOID)
{
if (!fFlusherInitialized)
{
fFlusherInitialized = TRUE;
EnterCriticalSection( &csFlushLock );
dwFlushCnt = 0;
dwFlushPeriodExtensions = 0;
if ( dwMBFlushCookie )
{
RemoveWorkItem( dwMBFlushCookie );
dwMBFlushCookie = 0;
}
LeaveCriticalSection( &csFlushLock );
}
}
// The algorithm for flushing changes of metabase to hard disk is the following:
// when change to metabase is made, and SlushSomeData is called from NotifySinks
// counter which counts the number of changes in metabase is incremented and first time
// the change happens work item is schedulled for scheduller to flush a metabase after 60 seconds
// if during 60 seconds more than INETA_MB_FLUSH_TRESHOLD changes will happen , then metabase will not
// flush changes to disk, but will extend flushing period for another 60 seconds. If during another 60 secs
// number of changes will be higer than INETA_MB_FLUSH_TRESHOLD agian period will be extended
// but no more times than INETA_MB_FLUSH_PERIODS_EXTENSION
// if in some period number of changes in metabase will be less than INETA_MB_FLUSH_TRESHOLD then
// peirod will not be extended and metabase will be saved to disk
VOID WINAPI CMDCOM::MetabaseLazyFlush(
VOID * pv
)
/*++
Description:
Scheduler callback for flushing the metabase
--*/
{
BOOL fExtendPeriod =FALSE;
CMDCOM *pMasterObject = (CMDCOM *)pv;
MD_ASSERT(pMasterObject != NULL);
EnterCriticalSection( &pMasterObject->csFlushLock );
if (pMasterObject->fFlusherInitialized)
{
RemoveWorkItem( pMasterObject->dwMBFlushCookie );
pMasterObject->dwMBFlushCookie = 0;
if ( pMasterObject->dwFlushCnt > INETA_MB_FLUSH_TRESHOLD)
{
if ( pMasterObject->dwFlushPeriodExtensions < INETA_MB_FLUSH_PERIODS_EXTENSION)
{
fExtendPeriod = TRUE;
pMasterObject->dwFlushPeriodExtensions ++;
}
}
pMasterObject->dwFlushCnt = 0;
if (!fExtendPeriod)
{
pMasterObject->dwFlushPeriodExtensions = 0;
}
else
{
pMasterObject->dwMBFlushCookie = ScheduleWorkItem( MetabaseLazyFlush,
pv, //context,
pMasterObject->msMBFlushTime);
}
}
LeaveCriticalSection( &pMasterObject->csFlushLock );
if (pMasterObject->fFlusherInitialized && !fExtendPeriod)
{
MB mb(pMasterObject);
mb.Save();
}
}
VOID CMDCOM::FlushSomeData (VOID)
{
EnterCriticalSection( &csFlushLock );
if ( fFlusherInitialized )
{
dwFlushCnt++;
if ( !dwMBFlushCookie )
{
dwMBFlushCookie = ScheduleWorkItem( MetabaseLazyFlush,
this, //context,
msMBFlushTime,
FALSE);
}
}
LeaveCriticalSection( &csFlushLock );
}
VOID CMDCOM::TerminateFlusher(VOID)
{
EnterCriticalSection( &csFlushLock );
if ( fFlusherInitialized )
{
fFlusherInitialized = FALSE;
if ( dwMBFlushCookie )
{
RemoveWorkItem( dwMBFlushCookie );
dwMBFlushCookie = 0;
}
}
LeaveCriticalSection( &csFlushLock );
}