4703 lines
173 KiB
C++
4703 lines
173 KiB
C++
|
|
#define INITGUID
|
|
#include <mdcommon.hxx>
|
|
#include <inetsvcs.h>
|
|
#include <issched.hxx>
|
|
#include <mbs.hxx>
|
|
#include <ptrmap.hxx>
|
|
#include <tuneprefix.h>
|
|
|
|
|
|
|
|
CIdToPointerMapper *g_PointerMapper = NULL;
|
|
|
|
|
|
CMDCOM::CMDCOM():
|
|
m_ImpIConnectionPointContainer(),
|
|
m_hresConstructorError(ERROR_SUCCESS)
|
|
{
|
|
UINT i;
|
|
HRESULT hRes;
|
|
|
|
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 );
|
|
|
|
|
|
// 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 );
|
|
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_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);
|
|
}
|
|
|
|
HRESULT
|
|
CMDCOM::ComMDTerminate(IN BOOL bSaveData)
|
|
/*++
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
|
|
return TerminateWorker1(FALSE);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CMDCOM::ComMDShutdown( void)
|
|
{
|
|
HRESULT hresReturn;
|
|
BOOL bSaveData;
|
|
IIS_CRYPTO_STORAGE CryptoStorage;
|
|
PIIS_CRYPTO_BLOB pSessionKeyBlob;
|
|
|
|
|
|
TerminateFlusher ();
|
|
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.
|
|
//
|
|
|
|
//
|
|
// 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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
|
|
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_rMasterResource->Unlock();
|
|
::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;
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
hresReturn = AddObjectToDataBase(hMDHandle, (LPSTR)pszMDPath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_dwSystemChangeNumber++;
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
hresReturn = RemoveObjectFromDataBase(hMDHandle, (LPSTR)pszMDPath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_dwSystemChangeNumber++;
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
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++;
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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 = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
g_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
CMDBaseObject *pboAffected, *pboChild;
|
|
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
|
|
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 {
|
|
if (bUnicode) {
|
|
wcscpy((LPWSTR)pszMDName, (LPWSTR)pvName);
|
|
}
|
|
else {
|
|
MD_STRCPY((LPSTR)pszMDName, (LPSTR)pvName);
|
|
}
|
|
}
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS);
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
LPSTR pszSourcePath = (LPSTR)pszMDSourcePath;
|
|
LPSTR pszDestPath = (LPSTR)pszMDDestPath;
|
|
CMDHandle *phoDestHandle, *phoSourceHandle;
|
|
CMDBaseObject *pboSource = NULL, *pboDest = NULL, *pboExisting = NULL, *pboIndex = NULL, *pboNew = NULL, *pboDestParent = NULL;
|
|
LPSTR pszTempPath;
|
|
LPSTR pszRemainingDestPath;
|
|
BOOL bChanged = FALSE;
|
|
WCHAR strName[METADATA_MAX_NAME_LEN];
|
|
|
|
if (g_dwInitialized == 0) {
|
|
hresReturn = MD_ERROR_NOT_INITIALIZED;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// check if pszDestPath is a valid parameter (non-NULL)
|
|
//
|
|
|
|
if (pszDestPath == NULL) {
|
|
hresReturn = E_INVALIDARG;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Must have access to Dest parent to add it.
|
|
// Make sure that a valid path was specified, ie. handle
|
|
// points to ancestor.
|
|
//
|
|
pszTempPath = pszDestPath;
|
|
SkipPathDelimeter(pszTempPath, bUnicode);
|
|
hresReturn = ExtractNameFromPath(pszTempPath, (LPSTR)strName, bUnicode);
|
|
if (FAILED(hresReturn)) {
|
|
hresReturn = E_INVALIDARG;
|
|
}
|
|
if (!bMDCopyFlag) {
|
|
//
|
|
// Must have access to source parent to remove it.
|
|
// Make sure that a valid path was specified, ie. handle
|
|
// points to ancestor.
|
|
//
|
|
pszTempPath = pszSourcePath;
|
|
SkipPathDelimeter(pszTempPath, bUnicode);
|
|
hresReturn = ExtractNameFromPath(pszTempPath, (LPSTR)strName, bUnicode);
|
|
if (FAILED(hresReturn)) {
|
|
hresReturn = E_INVALIDARG;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
hresReturn = GetObjectFromPath(pboSource, hMDSourceHandle,
|
|
(bMDCopyFlag) ? METADATA_PERMISSION_READ : METADATA_PERMISSION_WRITE,
|
|
(LPSTR)pszSourcePath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// GetObjectFromPath updates path, need both original and remainder
|
|
//
|
|
pszRemainingDestPath = pszDestPath;
|
|
hresReturn = GetObjectFromPath(pboDest, hMDDestHandle, METADATA_PERMISSION_WRITE,
|
|
(LPSTR)pszRemainingDestPath, bUnicode);
|
|
if ((SUCCEEDED(hresReturn)) ||
|
|
((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboDest != NULL))) {
|
|
//
|
|
// Make sure dest is not descendant of source
|
|
//
|
|
for (pboIndex = pboDest; pboIndex != NULL; pboIndex = pboIndex->GetParent()) {
|
|
if (pboIndex == pboSource) {
|
|
hresReturn = E_INVALIDARG;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
phoDestHandle = GetHandleObject(hMDDestHandle);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// Object already exists
|
|
//
|
|
if (pboDest == pboSource) {
|
|
//
|
|
// Copy to self
|
|
//
|
|
}
|
|
else {
|
|
MD_ASSERT (phoDestHandle != NULL);
|
|
if (bMDOverwriteFlag) {
|
|
if (pboDest->GetName(bUnicode) == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
pboDestParent = pboDest->GetParent();
|
|
hresReturn = MakeTreeCopy(pboSource, pboNew, pboDest->GetName(bUnicode), bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
MD_REQUIRE(SUCCEEDED(pboDestParent->RemoveChildObject(pboDest->GetName(bUnicode), bUnicode)));
|
|
hresReturn = pboDestParent->InsertChildObject(pboNew);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_dwSystemChangeNumber++;
|
|
if (phoDestHandle->SetChangeData(
|
|
pboDest, MD_CHANGE_TYPE_DELETE_OBJECT, 0) != ERROR_SUCCESS) {
|
|
delete(pboDest);
|
|
}
|
|
AddNewChangeData(phoDestHandle, pboNew);
|
|
}
|
|
else {
|
|
delete (pboNew);
|
|
pboDestParent->InsertChildObject(pboDest);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Object exists at destination and not overwrite.
|
|
// Add in missing objects and data.
|
|
//
|
|
hresReturn = CopyTree(phoDestHandle, pboDest, pboSource, bChanged);
|
|
if (bChanged) {
|
|
g_dwSystemChangeNumber++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboDest != NULL)) {
|
|
|
|
//
|
|
// Full destination path doesn't exist, so create it
|
|
//
|
|
|
|
hresReturn = MakeTreeCopyWithPath(pboSource,
|
|
pboNew,
|
|
pszRemainingDestPath,
|
|
bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
MD_ASSERT(pboDest != NULL);
|
|
hresReturn = pboDest->InsertChildObject(pboNew);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_dwSystemChangeNumber++;
|
|
AddNewChangeData(phoDestHandle, pboNew);
|
|
}
|
|
else {
|
|
delete (pboNew);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((SUCCEEDED(hresReturn)) && (!bMDCopyFlag)) {
|
|
MD_REQUIRE(SUCCEEDED(pboSource->GetParent()->RemoveChildObject(pboSource)));
|
|
phoSourceHandle = GetHandleObject(hMDSourceHandle);
|
|
MD_ASSERT (phoSourceHandle != NULL);
|
|
if (phoSourceHandle->SetChangeData(pboSource, MD_CHANGE_TYPE_DELETE_OBJECT, 0)
|
|
!= ERROR_SUCCESS) {
|
|
delete(pboSource);
|
|
}
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
return hresReturn;
|
|
}
|
|
|
|
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_DELIMETERA) != 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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
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 {
|
|
|
|
//
|
|
// Reinsert the object with the new name.
|
|
//
|
|
|
|
hresReturn = pboParent->AddChildObjectToHash( pboAffected );
|
|
|
|
g_dwSystemChangeNumber++;
|
|
MD_ASSERT(GetHandleObject(hMDHandle) != NULL);
|
|
GetHandleObject(hMDHandle)->SetChangeData(pboAffected, MD_CHANGE_TYPE_RENAME_OBJECT, 0,
|
|
(LPWSTR)OriginalKeyName.QueryPtr ());
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
}
|
|
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 * phMDHandle;
|
|
LPSTR pszPath = (LPSTR)pszMDPath;
|
|
if (g_dwInitialized == 0) {
|
|
hresReturn = MD_ERROR_NOT_INITIALIZED;
|
|
}
|
|
else if (!ValidateData(pmdrMDData, bUnicode)) {
|
|
hresReturn = E_INVALIDARG;
|
|
}
|
|
else {
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
CMDBaseObject *AffectedObject = NULL;
|
|
hresReturn = GetObjectFromPath(AffectedObject, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
|
|
|
|
if (hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) {
|
|
pszPath = (LPSTR)pszMDPath;
|
|
MD_ASSERT(pszMDPath != NULL);
|
|
hresReturn = AddObjectToDataBase(hMDHandle, (LPSTR)pszMDPath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_dwSystemChangeNumber++;
|
|
hresReturn = GetObjectFromPath(AffectedObject, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
|
|
MD_ASSERT(SUCCEEDED(hresReturn));
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = AffectedObject->SetDataObject(pmdrMDData, bUnicode);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_dwSystemChangeNumber++;
|
|
phMDHandle = GetHandleObject(hMDHandle);
|
|
if( phMDHandle == NULL )
|
|
{
|
|
hresReturn = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
phMDHandle->SetChangeData(AffectedObject, MD_CHANGE_TYPE_SET_DATA, pmdrMDData->dwMDIdentifier);
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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;
|
|
CMDBaseObject *pboAssociated;
|
|
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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
CMDBaseObject *pboAffected = NULL;
|
|
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
|
|
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_rMasterResource->Unlock();
|
|
}
|
|
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;
|
|
CMDBaseObject *pboAssociated;
|
|
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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
CMDBaseObject *pboAffected = NULL;
|
|
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
|
|
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_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
CMDBaseObject *pboAffected;
|
|
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (pboAffected->RemoveDataObject(dwMDIdentifier, dwMDDataType, TRUE) != NULL) {
|
|
CMDHandle * phoHandle = GetHandleObject(hMDHandle);
|
|
MD_ASSERT(phoHandle != NULL);
|
|
if( phoHandle != NULL ) {
|
|
hresReturn = ERROR_SUCCESS;
|
|
g_dwSystemChangeNumber++;
|
|
phoHandle->SetChangeData(pboAffected, MD_CHANGE_TYPE_DELETE_DATA, dwMDIdentifier);
|
|
}
|
|
else {
|
|
hresReturn = MD_ERROR_DATA_NOT_FOUND;
|
|
}
|
|
}
|
|
else {
|
|
hresReturn = MD_ERROR_DATA_NOT_FOUND;
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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);
|
|
HRESULT hresReturn;
|
|
BOOL bInheritableOnly;
|
|
CMDBaseData *pbdCurrent;
|
|
DWORD i, dwNumDataObjects;
|
|
PVOID *ppvMainDataBuf;
|
|
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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
CMDBaseObject *pboAffected = NULL;
|
|
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_READ, pszPath, bUnicode);
|
|
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);
|
|
dwNumDataObjects = pboAffected->GetAllDataObjects(ppvMainDataBuf,
|
|
dwMDAttributes,
|
|
dwMDUserType,
|
|
dwMDDataType,
|
|
bInheritableOnly);
|
|
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);
|
|
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 = 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);
|
|
|
|
//
|
|
// 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 = 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_rMasterResource->Unlock();
|
|
}
|
|
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;
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, METADATA_PERMISSION_WRITE, pszPath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
ppvMainDataBuf = GetMainDataBuffer();
|
|
MD_ASSERT (ppvMainDataBuf != NULL);
|
|
MD_REQUIRE((phoHandle = GetHandleObject(hMDHandle)) != NULL);
|
|
dwNumDataObjects = pboAffected->GetAllDataObjects(ppvMainDataBuf,
|
|
METADATA_NO_ATTRIBUTES,
|
|
dwMDUserType,
|
|
dwMDDataType,
|
|
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++;
|
|
}
|
|
FreeMainDataBuffer(ppvMainDataBuf);
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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;
|
|
CMDBaseData *pbdCurrent;
|
|
DWORD i, dwNumDataObjects;
|
|
PVOID *ppvMainDataBuf;
|
|
CMDBaseObject *pboSource = NULL, *pboDest = NULL;
|
|
LPSTR pszSourcePath = (LPSTR)pszMDSourcePath;
|
|
LPSTR pszDestPath = (LPSTR)pszMDDestPath;
|
|
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.
|
|
//
|
|
g_rMasterResource->Lock((bMDCopyFlag) ? TSRES_LOCK_READ : TSRES_LOCK_WRITE);
|
|
hresReturn = GetObjectFromPath(pboSource,
|
|
hMDSourceHandle,
|
|
((bMDCopyFlag) ? METADATA_PERMISSION_READ : METADATA_PERMISSION_WRITE),
|
|
(LPSTR)pszSourcePath,
|
|
bUnicode);
|
|
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);
|
|
dwNumDataObjects = pboSource->GetAllDataObjects(ppvMainDataBuf,
|
|
dwMDAttributes,
|
|
dwMDUserType,
|
|
dwMDDataType,
|
|
bInheritableOnly);
|
|
g_rMasterResource->Convert(TSRES_CONV_WRITE);
|
|
hresReturn = GetObjectFromPath(pboDest,
|
|
hMDDestHandle,
|
|
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);
|
|
GetHandleObject(hMDDestHandle)->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++;
|
|
}
|
|
FreeMainDataBuffer(ppvMainDataBuf);
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
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 )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
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)'\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)'\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)'\0';
|
|
*(((LPWSTR)pbDataStart) + 1) = (WCHAR)'\0';
|
|
}
|
|
else {
|
|
*((LPSTR)pbDataStart) = (CHAR)'\0';
|
|
*(((LPSTR)pbDataStart) + 1) = (CHAR)'\0';
|
|
}
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
}
|
|
}
|
|
if (hresReturn == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER)) {
|
|
*pdwMDRequiredBufferSize = DIFF(pbNextDataStart - (PBYTE)pszMDBuffer) / dwBytesPerChar;
|
|
}
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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;
|
|
_int64 ExpireTime, CurrentTime, TimeLeft;
|
|
FILETIME TempTime;
|
|
BOOL bPermissionsAvailable;
|
|
LPSTR pszPath = (LPSTR)pszMDPath;
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
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_rMasterResource->Unlock();
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
//
|
|
// 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) {
|
|
hresReturn = AddHandle(pboOpen, dwMDAccessRequested, mhTemp);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
*phMDNewHandle = mhTemp;
|
|
}
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_PATH_BUSY);
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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;
|
|
PMD_CHANGE_OBJECT_W pcoBuffer;
|
|
BUFFER **ppbufStorageArray;
|
|
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
|
|
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_rMasterResource->Convert(TSRES_CONV_READ);
|
|
if (FAILED(CreateNotifications(hoTemp,
|
|
&dwNumChangeEntries,
|
|
&pcoBuffer,
|
|
&ppbufStorageArray))) {
|
|
bSendNotifications = FALSE;
|
|
}
|
|
}
|
|
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
}
|
|
|
|
delete (hoTemp);
|
|
|
|
if (bDeleteChangeData) {
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
|
|
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;
|
|
DWORD WaitRetCode;
|
|
_int64 ExpireTime, CurrentTime, TimeLeft;
|
|
FILETIME TempTime;
|
|
BOOL bPermissionsAvailable;
|
|
BOOL bAddRead, bAddWrite, bRemoveRead, bRemoveWrite;
|
|
BOOL bEventPulsed = FALSE;
|
|
BOOL bSendNotifications = FALSE;
|
|
CMDHandle *phoNotifyHandle;
|
|
|
|
DWORD dwNumChangeEntries;
|
|
PMD_CHANGE_OBJECT_W pcoBuffer;
|
|
BUFFER **ppbufStorageArray;
|
|
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
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_rMasterResource->Unlock();
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
//
|
|
// 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_rMasterResource->Unlock();
|
|
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
delete (phoNotifyHandle);
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
|
|
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, hMDHandle);
|
|
// RetCode = SaveAllDataToRegistry();
|
|
}
|
|
::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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
HandleObject = GetHandleObject(hMDHandle);
|
|
if (HandleObject == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
|
|
}
|
|
else {
|
|
HandleObject->GetHandleInfo(pmdhiInfo);
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
*pdwSystemChangeNumber = g_dwSystemChangeNumber;
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
CMDBaseObject *pboQueried = NULL;
|
|
hresReturn = GetObjectFromPath(pboQueried, hMDHandle, 0, pszPath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
*pdwMDDataSetNumber=pboQueried->GetDataSetNumber();
|
|
}
|
|
else if ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboQueried != NULL)) {
|
|
*pdwMDDataSetNumber=pboQueried->GetDescendantDataSetNumber();
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
#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;
|
|
}
|
|
}
|
|
if (!bFound) {
|
|
MD_ASSERT(FALSE);
|
|
}
|
|
#endif
|
|
|
|
((CMDBaseData *)(g_PointerMapper->FindMapping(dwMDDataTag)))->IncrementReferenceCount();
|
|
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
DeleteDataObject((CMDBaseData *)(g_PointerMapper->FindMapping(dwMDDataTag)));
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
CMDBaseObject *pboAffected = NULL;
|
|
hresReturn = GetObjectFromPath(pboAffected, hMDHandle, 0, pszPath, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
pboAffected->SetLastChangeTime(pftMDLastChangeTime);
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
CMDBaseObject *pboQueried = NULL;
|
|
hresReturn = GetObjectFromPath(pboQueried, hMDHandle, 0, pszPath, bUnicode);
|
|
if ((SUCCEEDED(hresReturn)) ||
|
|
((hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboQueried != NULL))) {
|
|
pftTemp = pboQueried->GetLastChangeTime();
|
|
*pftMDLastChangeTime = *pftTemp;
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
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;
|
|
|
|
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);
|
|
if( FAILED( hresReturn ) )
|
|
{
|
|
return hresReturn;
|
|
}
|
|
|
|
MD_ASSERT(strauBackupLocation.QueryStr(FALSE) != NULL);
|
|
|
|
if( ( ( dwMDFlags & MD_BACKUP_OVERWRITE ) == 0 ) &&
|
|
( HFILE_ERROR != OpenFile( strauBackupLocation.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,
|
|
hMDHandle,
|
|
TRUE
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hresReturn = SaveAllData(FALSE,
|
|
pCryptoStorage,
|
|
pSessionKeyBlob,
|
|
strauBackupLocation.QueryStr(FALSE),
|
|
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
|
|
//
|
|
if (!CopyFile(g_strRealFileName->QueryStr(),
|
|
strauBackupLocation.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 {
|
|
|
|
//
|
|
// 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);
|
|
|
|
STRAU strauBackupLocation;
|
|
|
|
hresReturn = CreateBackupFileName(pszMDBackupLocation,
|
|
dwMDVersion,
|
|
bUnicode,
|
|
&strauBackupLocation);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// Got a valid name
|
|
// See if the file exists
|
|
//
|
|
MD_ASSERT(strauBackupLocation.QueryStr(FALSE) != NULL);
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA wfdFile;
|
|
STR strCopyOfMetabaseFileName (*g_strRealFileName);
|
|
|
|
hFile = FindFirstFile(strauBackupLocation.QueryStrA(),
|
|
&wfdFile);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
}
|
|
else {
|
|
FindClose(hFile);
|
|
//
|
|
// File actually exists,
|
|
// Go ahead and restore.
|
|
//
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
//
|
|
// Need to do the file copy before Terminate
|
|
// so the global variables are still set.
|
|
// Also good to not terminate if it fails.
|
|
//
|
|
if (!pszPasswd && !CopyFile(strauBackupLocation.QueryStr(FALSE),
|
|
g_strRealFileName->QueryStr(),
|
|
FALSE)) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
}
|
|
else {
|
|
//
|
|
// Prevent saves during termination.
|
|
//
|
|
BOOL bPrevSaveDisallowed = g_bSaveDisallowed;
|
|
g_bSaveDisallowed = TRUE;
|
|
static DWORD 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,
|
|
pszPasswd,
|
|
strauBackupLocation.QueryStr(FALSE));
|
|
}
|
|
|
|
if( SUCCEEDED(hresReturn) )
|
|
{
|
|
RestoreCertificates ((LPCWSTR)pszMDBackupLocation,
|
|
strauBackupLocation.QueryStr(FALSE),
|
|
strCopyOfMetabaseFileName.QueryStr());
|
|
}
|
|
}
|
|
|
|
if( pszPasswd )
|
|
{
|
|
//
|
|
// Need to flush the newly restored data out
|
|
//
|
|
g_dwSystemChangeNumber++;
|
|
}
|
|
|
|
g_rMasterResource->Unlock();
|
|
|
|
//
|
|
// 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 ) )
|
|
{
|
|
InitWorker(FALSE, NULL, NULL);
|
|
}
|
|
else if( pszPasswd )
|
|
{
|
|
//
|
|
// Need to flush newly restored data to Metabase.bin file
|
|
//
|
|
hresReturn = ComMDSaveData( METADATA_MASTER_ROOT_HANDLE );
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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)'\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))) {
|
|
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))) {
|
|
//
|
|
// 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 (strauBackupLocation.QueryCB(bUnicode) >
|
|
(MD_BACKUP_MAX_LEN * ((bUnicode) ? sizeof(WCHAR) : sizeof(char)))) {
|
|
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;
|
|
|
|
hresReturn = CreateBackupFileName(pszMDBackupLocation,
|
|
dwMDVersion,
|
|
bUnicode,
|
|
&strauBackupLocation);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
MD_ASSERT(strauBackupLocation.QueryStr(FALSE) != NULL);
|
|
|
|
//
|
|
// Delete the file
|
|
//
|
|
|
|
if (!DeleteFile(strauBackupLocation.QueryStr(FALSE))) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
}
|
|
}
|
|
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
|
|
|
|
}
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CMDCOM::ComMDExportW(
|
|
/* [in] */ METADATA_HANDLE hMDHandle,
|
|
/* [string][in][unique] */ LPCWSTR pszPasswd,
|
|
/* [string][in][unique] */ LPCWSTR pszFileName,
|
|
/* [string][in][unique] */ LPCWSTR pszAbsSourcePath,
|
|
/* [in] */ DWORD dwMDFlags)
|
|
{
|
|
return RETURNCODETOHRESULT(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CMDCOM::ComMDImportW(
|
|
/* [in] */ METADATA_HANDLE hMDHandle,
|
|
/* [string][in][unique] */ LPCWSTR pszDestPath,
|
|
/* [string][in][unique] */ LPCWSTR pszKeyType,
|
|
/* [string][in][unique] */ LPCWSTR pszPasswd,
|
|
/* [string][in][unique] */ LPCWSTR pszFileName,
|
|
/* [string][in][unique] */ LPCWSTR pszAbsSourcePath,
|
|
/* [in] */ DWORD dwMDFlags)
|
|
{
|
|
return RETURNCODETOHRESULT(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CMDCOM::ComMDRestoreHistoryW(
|
|
/* [unique][in][string] */ LPCWSTR pszMDHistoryLocation,
|
|
/* [in] */ DWORD dwMDMajorVersion,
|
|
/* [in] */ DWORD dwMDMinorVersion,
|
|
/* [in] */ DWORD dwMDFlags)
|
|
{
|
|
return RETURNCODETOHRESULT(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CMDCOM::ComMDEnumHistoryW(
|
|
/* [size_is (MD_BACKUP_MAX_LEN)][in, out] */ LPWSTR pszMDHistoryLocation,
|
|
/* [out] */ DWORD *pdwMDMajorVersion,
|
|
/* [out] */ DWORD *pdwMDMinorVersion,
|
|
/* [out] */ PFILETIME pftMDHistoryTime,
|
|
/* [in] */ DWORD dwMDEnumIndex)
|
|
{
|
|
return RETURNCODETOHRESULT(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
/*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.
|
|
|
|
Args: PAPER_EVENT PaperEvent
|
|
Type of notification event.
|
|
SHORT nX
|
|
X cordinate. Value is 0 unless event needs it.
|
|
SHORT nY
|
|
Y cordinate. Value is 0 unless event needs it.
|
|
SHORT nInkWidth
|
|
Ink Width. Value is 0 unless event needs it.
|
|
SHORT crInkColor
|
|
COLORREF RGB color value. Value is 0 unless event needs it.
|
|
|
|
Modifies: ...
|
|
|
|
Returns: HRESULT
|
|
Standard OLE result code. NOERROR 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 = NOERROR;
|
|
IConnectionPoint* pIConnectionPoint;
|
|
IEnumConnections* pIEnum;
|
|
CONNECTDATA ConnData;
|
|
HRESULT hrTemp;
|
|
|
|
|
|
FlushSomeData ();
|
|
|
|
//
|
|
// Correct broken connections.
|
|
// It's not likely to be a high number so
|
|
// save a memory allocation by using an array.
|
|
//
|
|
DWORD pdwLostConnections[10];
|
|
DWORD dwNumLostConnections = 0;
|
|
|
|
// If there was a paper event, broadcast appropriate notifications to
|
|
// all Sinks connected to each connection point.
|
|
// if (PAPER_EVENT_NONE != PaperEvent)
|
|
{
|
|
if (bUnicode) {
|
|
pIConnectionPoint = m_aConnectionPoints[MD_CONNPOINT_WRITESINK_W];
|
|
}
|
|
else {
|
|
pIConnectionPoint = m_aConnectionPoints[MD_CONNPOINT_WRITESINK_A];
|
|
}
|
|
if (NULL != pIConnectionPoint)
|
|
{
|
|
pIConnectionPoint->AddRef();
|
|
g_rSinkResource->Lock(TSRES_LOCK_READ);
|
|
hr = pIConnectionPoint->EnumConnections(&pIEnum);
|
|
if (SUCCEEDED(hr)) {
|
|
// Loop thru the connection point's connections and if the
|
|
// listening connection supports IPaperSink (ie, PaperSink events)
|
|
// then dispatch the PaperEvent event notification to that sink.
|
|
while (NOERROR == pIEnum->Next(1, &ConnData, NULL))
|
|
{
|
|
IMDCOMSINK* pIMDCOMSINK;
|
|
|
|
if (bUnicode) {
|
|
hr = ConnData.pUnk->QueryInterface(IID_IMDCOMSINK_W,
|
|
(PPVOID)&pIMDCOMSINK);
|
|
}
|
|
else {
|
|
hr = ConnData.pUnk->QueryInterface(IID_IMDCOMSINK_A,
|
|
(PPVOID)&pIMDCOMSINK);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
switch (dwNotificationType) {
|
|
case MD_SINK_MAIN: {
|
|
if (bUnicode) {
|
|
hrTemp = ((IMDCOMSINKW*)pIMDCOMSINK)->ComMDSinkNotify(hHandle,
|
|
dwNumEntries,
|
|
(PMD_CHANGE_OBJECT_W)pcoChangeList);
|
|
}
|
|
else {
|
|
hrTemp = ((IMDCOMSINKA*)pIMDCOMSINK)->ComMDSinkNotify(hHandle,
|
|
dwNumEntries,
|
|
(PMD_CHANGE_OBJECT_A)pcoChangeList);
|
|
}
|
|
}
|
|
break;
|
|
case MD_SINK_SHUTDOWN: {
|
|
//
|
|
// Shutdown Notifications
|
|
//
|
|
if (bUnicode) {
|
|
hrTemp = ((IMDCOMSINKW*)pIMDCOMSINK)->ComMDShutdownNotify();
|
|
}
|
|
else {
|
|
hrTemp = ((IMDCOMSINKA*)pIMDCOMSINK)->ComMDShutdownNotify();
|
|
}
|
|
}
|
|
break;
|
|
case MD_SINK_EVENT: {
|
|
//
|
|
// Shutdown Notifications
|
|
//
|
|
if (bUnicode) {
|
|
hrTemp = ((IMDCOMSINKW*)pIMDCOMSINK)->ComMDEventNotify(dwEvent);
|
|
}
|
|
else {
|
|
DBG_ASSERT(FALSE);
|
|
}
|
|
}
|
|
break;
|
|
default: {
|
|
DBG_ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
pIMDCOMSINK->Release();
|
|
if (FAILED(hrTemp)) {
|
|
if ((HRESULT_CODE(hrTemp) == RPC_S_SERVER_UNAVAILABLE) ||
|
|
((HRESULT_CODE(hrTemp) >= RPC_S_NO_CALL_ACTIVE) &&
|
|
(HRESULT_CODE(hrTemp) <= RPC_S_CALL_FAILED_DNE))) {
|
|
if (dwNumLostConnections < 10) {
|
|
pdwLostConnections[dwNumLostConnections++] = ConnData.dwCookie;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ConnData.pUnk->Release();
|
|
}
|
|
pIEnum->Release();
|
|
}
|
|
g_rSinkResource->Unlock();
|
|
while (dwNumLostConnections > 0) {
|
|
pIConnectionPoint->Unadvise(pdwLostConnections[--dwNumLostConnections]);
|
|
}
|
|
pIConnectionPoint->Release();
|
|
}
|
|
}
|
|
|
|
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;
|
|
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 )
|
|
{
|
|
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;
|
|
|
|
|
|
MD_ASSERT(sizeof(MD_CHANGE_OBJECT_A) == sizeof(MD_CHANGE_OBJECT_W));
|
|
|
|
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,j;
|
|
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] = NULL;
|
|
}
|
|
|
|
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)'\0';
|
|
pcoBuffer[i].pszMDPath[dwStringLen + 2] = (WCHAR)'\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)'\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 emtabase to ahrd 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 60seconds
|
|
// if during 60 seconds more than INETA_MB_FLUSH_TRESHOLD changes will happen , then metabase will not
|
|
// flush cahnges 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)
|
|
{
|
|
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 );
|
|
}
|