windows-nt/Source/XPSP1/NT/base/cluster/service/dm/dmlocal.c

1167 lines
31 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
dmlocal.c
Abstract:
Contains the routines for local transactions that can be called within
gum handlers.
Author:
Sunita Shrivastava (sunitas) 24-Apr-1996
Revision History:
--*/
#include "dmp.h"
#include "clusudef.h"
extern BOOL gbIsQuoLoggingOn;
extern PFM_RESOURCE gpQuoResource;
extern DWORD gbIsQuoResOnline;
extern HLOG ghQuoLog;
#if NO_SHARED_LOCKS
extern CRITICAL_SECTION gLockDmpRoot;
#else
extern RTL_RESOURCE gLockDmpRoot;
#endif
/****
@doc EXTERNAL INTERFACES CLUSSVC DM
****/
/****
@func HXSACTION | DmBeginLocalUpdate| Called by gum handlers to make consistent
changes to the local registry. The log is reset and a start transaction
record is written to the log, if the log is active.
@comm When GumHandlers need to update the registry consitently they must use the
LocalApis provided by DM.
@rdesc Returns a transaction handle. NULL on failure. Call GetLastError()
for error code.
@xref <f DmAbortLocalUpdate> <f DmCommitLocalUpdate>
****/
HLOCALXSACTION DmBeginLocalUpdate()
{
DWORD dwError=ERROR_SUCCESS;
LSN StartXsactionLsn;
DWORD dwSequence;
HXSACTION hXsaction = NULL;
PLOCALXSACTION pLocalXsaction;
ClRtlLogPrint(LOG_NOISE,
"[DM] DmBeginLocalUpdate Entry\r\n");
//lock the data base, so that a check point is not taken in this duration
//this lock is released in DmCommitLocalUpdate() or DmAbortLocalUpdate()
//this lock also prevents the the registry from being flushed.
ACQUIRE_EXCLUSIVE_LOCK(gLockDmpRoot);
//Commit the registry so that it can be restored on abort
if ((dwError = DmCommitRegistry()) != ERROR_SUCCESS)
{
goto FnExit;
}
//allocate memory for local transaction
pLocalXsaction = LocalAlloc(LMEM_FIXED, sizeof(LOCALXSACTION));
if (!pLocalXsaction)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto FnExit;
}
pLocalXsaction->dwSig = LOCALXSAC_SIG;
dwSequence = GumGetCurrentSequence(GumUpdateRegistry);
pLocalXsaction->dwSequence = dwSequence;
pLocalXsaction->hLogXsaction = NULL;
InitializeListHead(&pLocalXsaction->PendingNotifyListHead);
//log the start checkpoint record
if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource) && ghQuoLog)
{
hXsaction = LogStartXsaction(ghQuoLog, dwSequence ,RMRegistryMgr, 0);
if (!hXsaction)
{
dwError = GetLastError();
}
pLocalXsaction->hLogXsaction = hXsaction;
}
FnExit:
if (dwError != ERROR_SUCCESS)
{
if (pLocalXsaction) LocalFree(pLocalXsaction);
pLocalXsaction = NULL;
RELEASE_LOCK(gLockDmpRoot);
ClRtlLogPrint(LOG_NOISE,
"[DM] DmBeginLocalUpdate Exit, pLocalXsaction=0x%1!08lx! Error=0x%2!08lx!\r\n",
pLocalXsaction, dwError);
} else {
ClRtlLogPrint(LOG_NOISE,
"[DM] DmBeginLocalUpdate Exit, pLocalXsaction=0x%1!08lx!\r\n",
pLocalXsaction);
}
return((HLOCALXSACTION)pLocalXsaction);
}
/****
@func DWORD | DmCommitLocalUpdate| This api must be called to commit
the changes to the local registry.
@parm IN HXSACTION | hXsaction | The handle to the transaction to be committed.
@comm A commit record is written the quorum log if logging is active.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@xref <f DmBeginLocalUpdate> <f DmAbortLocalUpdate>
****/
DWORD DmCommitLocalUpdate(IN HLOCALXSACTION hLocalXsaction)
{
DWORD dwError=ERROR_SUCCESS;
PLOCALXSACTION pLocalXsaction;
ClRtlLogPrint(LOG_NOISE,
"[DM] DmCommitLocalUpdate Entry\r\n");
GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
//update the gum sequence
DmpUpdateSequence();
DmpReportPendingNotifications(pLocalXsaction, TRUE );
//write a commit record to the quorum log
if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
&& ghQuoLog && pLocalXsaction->hLogXsaction)
{
CL_ASSERT(pLocalXsaction->hLogXsaction);
dwError = LogCommitXsaction(ghQuoLog, pLocalXsaction->hLogXsaction, 0);
//
// Chittur Subbaraman (chitturs) - 1/19/99
//
pLocalXsaction->hLogXsaction = NULL;
}
//
// Chittur Subbaraman (chitturs) - 1/19/99
//
// Make sure that the hLogXsaction memory is freed (even in the case
// in which you started a local xsaction and didn't get a chance to
// commit it or abort it to the log because quorum logging got turned
// off in the middle, for example. This turning off of the logging
// in the middle of a transaction could be considered as a bug ?)
//
LocalFree( pLocalXsaction->hLogXsaction );
//invalidate the signature and free the transaction structure
pLocalXsaction->dwSig = 0;
LocalFree(pLocalXsaction);
//release the database
RELEASE_LOCK(gLockDmpRoot);
ClRtlLogPrint(LOG_NOISE,
"[DM] DmCommitLocalUpdate Exit, returning 0x%1!08lx!\r\n",
dwError);
return(dwError);
}
/****
@func DWORD | DmAbortLocalUpdate| DmAbortLocalUpdate aborts all the changes
to the local registry associated with this transaction.
@parm IN HXSACTION | hXsaction | The handle to the transaction to be committed.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@xref <f DmBeginLocalUpdate> <f DmCommitLocalUpdate>
****/
DWORD DmAbortLocalUpdate(IN HLOCALXSACTION hLocalXsaction)
{
DWORD dwError=ERROR_SUCCESS;
PLOCALXSACTION pLocalXsaction;
ClRtlLogPrint(LOG_NOISE,
"[DM] DmAbortLocalUpdate Entry\r\n");
GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
//write the abort chkpoint record
//if the locker node is logging this is valid,
//if the nonlocker node is logging, and it aborts
// some other node will inherit the quorum log and
//checkpoint and hence commit this update.
if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
&& ghQuoLog && pLocalXsaction->hLogXsaction)
{
CL_ASSERT(pLocalXsaction->hLogXsaction);
LogAbortXsaction(ghQuoLog, pLocalXsaction->hLogXsaction, 0);
//
// Chittur Subbaraman (chitturs) - 1/19/99
//
pLocalXsaction->hLogXsaction = NULL;
}
//SS: if the rollback fails, then we kill ourselves??
//restore the old registry
if ((dwError = DmRollbackRegistry()) != ERROR_SUCCESS)
{
CL_UNEXPECTED_ERROR(dwError);
}
//free any pending notifications that were built up for
//this transaction
DmpReportPendingNotifications(pLocalXsaction, FALSE );
//
// Chittur Subbaraman (chitturs) - 1/19/99
//
// Make sure that the hLogXsaction memory is freed (even in the case
// in which you started a local xsaction and didn't get a chance to
// commit it or abort it to the log because quorum logging got turned
// off in the middle, for example. This turning off of the logging
// in the middle of a transaction could be considered as a bug ?)
//
LocalFree( pLocalXsaction->hLogXsaction );
//free the transaction structure, it cannot be used any more
pLocalXsaction->dwSig = 0;
LocalFree(pLocalXsaction);
//release the database
RELEASE_LOCK(gLockDmpRoot);
ClRtlLogPrint(LOG_NOISE,
"[DM] DmAbortLocalUpdate Exit, returning 0x%1!08lx!\r\n",
dwError);
return(dwError);
}
DWORD
DmLocalSetValue(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpValueName,
IN DWORD dwType,
IN CONST BYTE *lpData,
IN DWORD cbData
)
/*++
Routine Description:
This routine sets the named value for the specified
cluster registry key on the local machine
Arguments:
hKey - Supplies the cluster registry subkey whose value is to be set
lpValueName - Supplies the name of the value to be set.
dwType - Supplies the value data type
lpData - Supplies a pointer to the value data
cbData - Supplies the length of the value data.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{
DWORD Status = ERROR_SUCCESS;
PDMKEY Key;
PUCHAR Dest;
DWORD NameLength;
DWORD ValueNameLength;
DWORD UpdateLength;
PDM_SET_VALUE_UPDATE Update = NULL;
PLOCALXSACTION pLocalXsaction;
Key = (PDMKEY)hKey;
GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
Status = RegSetValueExW(Key->hKey,
lpValueName,
0,
dwType,
lpData,
cbData);
if (Status != ERROR_SUCCESS)
{
goto FnExit;
}
DmpAddToPendingNotifications(pLocalXsaction, Key->Name, CLUSTER_CHANGE_REGISTRY_VALUE);
//write it to the quorum log
if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
&& ghQuoLog && pLocalXsaction->hLogXsaction)
{
Key = (PDMKEY)hKey;
NameLength = (lstrlenW(Key->Name)+1)*sizeof(WCHAR);
ValueNameLength = (lstrlenW(lpValueName)+1)*sizeof(WCHAR);
UpdateLength = sizeof(DM_SET_VALUE_UPDATE) +
NameLength +
ValueNameLength +
cbData;
Update = (PDM_SET_VALUE_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
if (Update == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
goto FnExit;
}
Update->lpStatus = NULL;
Update->NameOffset = FIELD_OFFSET(DM_SET_VALUE_UPDATE, KeyName)+NameLength;
Update->DataOffset = Update->NameOffset + ValueNameLength;
Update->DataLength = cbData;
Update->Type = dwType;
CopyMemory(Update->KeyName, Key->Name, NameLength);
Dest = (PUCHAR)Update + Update->NameOffset;
CopyMemory(Dest, lpValueName, ValueNameLength);
Dest = (PUCHAR)Update + Update->DataOffset;
CopyMemory(Dest, lpData, cbData);
if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
DmUpdateSetValue, Update, UpdateLength) == NULL_LSN)
{
Status = GetLastError();
}
}
FnExit:
if (Update) LocalFree(Update);
return(Status);
}
HDMKEY
DmLocalCreateKey(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpSubKey,
IN DWORD dwOptions,
IN DWORD samDesired,
IN OPTIONAL LPVOID lpSecurityDescriptor,
OUT LPDWORD lpDisposition
)
/*++
Routine Description:
Creates a key in the local registry. If the key exists, it
is opened. If it does not exist, it is created.
Arguments:
hKey - Supplies the key that the create is relative to.
lpSubKey - Supplies the key name relative to hKey
dwOptions - Supplies any registry option flags.
samDesired - Supplies desired security access mask
lpSecurityDescriptor - Supplies security for the newly created key.
Disposition - Returns whether the key was opened (REG_OPENED_EXISTING_KEY)
or created (REG_CREATED_NEW_KEY)
Return Value:
A handle to the specified key if successful
NULL otherwise. LastError will be set to the specific error code.
--*/
{
PDMKEY Parent;
PDMKEY Key = NULL;
DWORD NameLength;
DWORD Status;
PDM_CREATE_KEY_UPDATE CreateUpdate = NULL;
PVOID pBuffer = NULL;
DWORD dwBufLength;
DWORD dwSecurityLength;
PLOCALXSACTION pLocalXsaction;
GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
if (dwOptions == REG_OPTION_VOLATILE)
{
Status = ERROR_INVALID_PARAMETER;
goto FnExit;
}
Parent = (PDMKEY)hKey;
//
// Allocate the DMKEY structure.
//
NameLength = (lstrlenW(Parent->Name) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR);
Key = LocalAlloc(LMEM_FIXED, sizeof(DMKEY)+NameLength);
if (Key == NULL) {
CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
Status = ERROR_NOT_ENOUGH_MEMORY;
goto FnExit;
}
//
// Create the key on the local machine.
//
Status = RegCreateKeyExW(Parent->hKey,
lpSubKey,
0,
NULL,
0,
samDesired,
lpSecurityDescriptor,
&Key->hKey,
lpDisposition);
if (Status != ERROR_SUCCESS) {
goto FnExit;
}
//
// Create the key name
//
lstrcpyW(Key->Name, Parent->Name);
if (Key->Name[0] != UNICODE_NULL) {
lstrcatW(Key->Name, L"\\");
}
lstrcatW(Key->Name, lpSubKey);
Key->GrantedAccess = samDesired;
EnterCriticalSection(&KeyLock);
InsertHeadList(&KeyList, &Key->ListEntry);
InitializeListHead(&Key->NotifyList);
LeaveCriticalSection(&KeyLock);
//add the pending notification to be delivered on commit
DmpAddToPendingNotifications(pLocalXsaction, Key->Name, CLUSTER_CHANGE_REGISTRY_NAME);
//successfully created key, write to the log
if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
&& ghQuoLog && pLocalXsaction->hLogXsaction)
{
//get the length of the security structure
if (ARGUMENT_PRESENT(lpSecurityDescriptor))
{
dwSecurityLength = GetSecurityDescriptorLength(lpSecurityDescriptor);
}
else
{
dwSecurityLength = 0;
}
CreateUpdate = (PDM_CREATE_KEY_UPDATE)LocalAlloc(LMEM_FIXED, sizeof(DM_CREATE_KEY_UPDATE));
if (CreateUpdate == NULL) {
CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
Status = ERROR_NOT_ENOUGH_MEMORY;
goto FnExit;
}
//
// Issue the update.
//
CreateUpdate->lpDisposition = lpDisposition;
CreateUpdate->phKey = &Key->hKey;
CreateUpdate->samDesired = samDesired;
CreateUpdate->dwOptions = dwOptions;
if (ARGUMENT_PRESENT(lpSecurityDescriptor)) {
CreateUpdate->SecurityPresent = TRUE;
} else {
CreateUpdate->SecurityPresent = FALSE;
}
//marshall the data,
pBuffer = GumMarshallArgs(&dwBufLength,
3,
sizeof(DM_CREATE_KEY_UPDATE),
CreateUpdate,
(lstrlenW(Key->Name)+1)*sizeof(WCHAR),
Key->Name,
dwSecurityLength,
lpSecurityDescriptor);
if (pBuffer)
{
CL_ASSERT(pLocalXsaction->hLogXsaction);
//write it to the logger
if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
DmUpdateCreateKey, pBuffer, dwBufLength) == NULL_LSN)
{
Status = GetLastError();
goto FnExit;
}
}
}
FnExit:
if (Status != ERROR_SUCCESS)
{
if (Key) LocalFree(Key);
Key = NULL;
SetLastError(Status);
}
if (CreateUpdate) LocalFree(CreateUpdate);
if (pBuffer) LocalFree(pBuffer);
return((HDMKEY)Key);
}
DWORD
DmLocalRemoveFromMultiSz(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpValueName,
IN LPCWSTR lpString
)
/*++
Routine Description:
Removes a string from a REG_MULTI_SZ value.
Arguments:
hKey - Supplies the key where the value exists. This key must
have been opened with READ | KEY_SET_VALUE access
lpValueName - Supplies the name of the value.
lpString - Supplies the string to be removed from the REG_MULTI_SZ value
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{
DWORD Status;
LPWSTR Buffer=NULL;
DWORD BufferSize;
DWORD DataSize;
LPWSTR Current;
DWORD CurrentLength;
DWORD i;
LPWSTR Next;
PCHAR Src, Dest;
DWORD NextLength;
DWORD MultiLength;
BufferSize = 0;
Status = DmQueryString(hKey,
lpValueName,
REG_MULTI_SZ,
&Buffer,
&BufferSize,
&DataSize);
if (Status != ERROR_SUCCESS) {
return(Status);
}
MultiLength = DataSize/sizeof(WCHAR);
Status = ClRtlMultiSzRemove(Buffer,
&MultiLength,
lpString);
if (Status == ERROR_SUCCESS) {
//
// Set the new value back.
//
Status = DmLocalSetValue(hLocalXsaction,
hKey,
lpValueName,
REG_MULTI_SZ,
(CONST BYTE *)Buffer,
MultiLength * sizeof(WCHAR));
} else if (Status == ERROR_FILE_NOT_FOUND) {
Status = ERROR_SUCCESS;
}
if (Buffer) LocalFree(Buffer);
return(Status);
}
DWORD
DmLocalAppendToMultiSz(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpValueName,
IN LPCWSTR lpString
)
/*++
Routine Description:
Adds another string to a REG_MULTI_SZ value. If the value does
not exist, it will be created.
Arguments:
hLocalXsaction - A handle to a local transaction.
hKey - Supplies the key where the value exists. This key must
have been opened with KEY_READ | KEY_SET_VALUE access
lpValueName - Supplies the name of the value.
lpString - Supplies the string to be appended to the REG_MULTI_SZ value
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{
DWORD ValueLength = 512;
DWORD ReturnedLength;
LPWSTR ValueData;
DWORD StringLength;
DWORD Status;
DWORD cbValueData;
PWSTR s;
DWORD Type;
StringLength = (lstrlenW(lpString)+1)*sizeof(WCHAR);
retry:
ValueData = LocalAlloc(LMEM_FIXED, ValueLength + StringLength);
if (ValueData == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
cbValueData = ValueLength;
Status = DmQueryValue(hKey,
lpValueName,
&Type,
(LPBYTE)ValueData,
&cbValueData);
if (Status == ERROR_MORE_DATA) {
//
// The existing value is too large for our buffer.
// Retry with a larger buffer.
//
ValueLength = cbValueData;
LocalFree(ValueData);
goto retry;
}
if (Status == ERROR_FILE_NOT_FOUND) {
//
// The value does not currently exist. Create the
// value with our data.
//
s = ValueData;
} else if (Status == ERROR_SUCCESS) {
//
// A value already exists. Append our string to the
// MULTI_SZ.
//
s = (PWSTR)((PCHAR)ValueData + cbValueData) - 1;
} else {
LocalFree(ValueData);
return(Status);
}
CopyMemory(s, lpString, StringLength);
s += (StringLength / sizeof(WCHAR));
*s++ = L'\0';
Status = DmLocalSetValue(
hLocalXsaction,
hKey,
lpValueName,
REG_MULTI_SZ,
(CONST BYTE *)ValueData,
(DWORD)((s-ValueData)*sizeof(WCHAR)));
LocalFree(ValueData);
return(Status);
}
DWORD
DmLocalDeleteKey(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpSubKey
)
/*++
Routine Description:
Deletes the specified key from the local registry. A key that has subkeys cannot
be deleted.
Arguments:
hKey - Supplies a handle to a currently open key.
lpSubKey - Points to a null-terminated string specifying the
name of the key to delete. This parameter cannot be NULL,
and the specified key must not have subkeys.
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{
PDMKEY Key;
DWORD NameLength;
DWORD UpdateLength;
PDM_DELETE_KEY_UPDATE Update=NULL;
DWORD Status;
PLOCALXSACTION pLocalXsaction;
GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
Key = (PDMKEY)hKey;
NameLength = (lstrlenW(Key->Name) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR);
UpdateLength = NameLength + sizeof(DM_DELETE_KEY_UPDATE);
Update = (PDM_DELETE_KEY_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
if (Update == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
goto FnExit;
}
//dont need an update on status thru marshalled data
Update->lpStatus = NULL;
CopyMemory(Update->Name, Key->Name, (lstrlenW(Key->Name) + 1) * sizeof(WCHAR));
if (Update->Name[0] != L'\0')
{
lstrcatW(Update->Name, L"\\");
}
lstrcatW(Update->Name, lpSubKey);
Status = RegDeleteKeyW(DmpRoot, Update->Name);
if (Status != ERROR_SUCCESS)
goto FnExit;
//add the pending notification to be delivered on commit
DmpAddToPendingNotifications(pLocalXsaction, Update->Name, CLUSTER_CHANGE_REGISTRY_NAME);
//successfully deleted key, write to the log
if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
&& ghQuoLog && pLocalXsaction->hLogXsaction)
{
if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
DmUpdateDeleteKey, Update, UpdateLength) == NULL_LSN)
{
Status = GetLastError();
goto FnExit;
}
}
FnExit:
if (Update) LocalFree(Update);
return(Status);
}
DWORD
DmLocalDeleteTree(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpSubKey
)
/*++
Routine Description:
Deletes the specified registry subtree in the local registry.
All subkeys are deleted.
Arguments:
hKey - Supplies a handle to a currently open key.
lpSubKey - Points to a null-terminated string specifying the
name of the key to delete. This parameter cannot be NULL.
Any subkeys of the specified key will also be deleted.
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{
HDMKEY Subkey;
DWORD i;
DWORD Status;
LPWSTR KeyBuffer=NULL;
DWORD MaxKeyLen;
DWORD NeededSize;
Subkey = DmOpenKey(hKey,
lpSubKey,
MAXIMUM_ALLOWED);
if (Subkey == NULL) {
Status = GetLastError();
return(Status);
}
//
// Get the size of name buffer we will need.
//
Status = DmQueryInfoKey(Subkey,
NULL,
&MaxKeyLen,
NULL,
NULL,
NULL,
NULL,
NULL);
if (Status != ERROR_SUCCESS) {
CL_UNEXPECTED_ERROR( Status );
DmCloseKey(Subkey);
return(Status);
}
KeyBuffer = LocalAlloc(LMEM_FIXED, (MaxKeyLen+1)*sizeof(WCHAR));
if (KeyBuffer == NULL) {
CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
DmCloseKey(Subkey);
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Enumerate the subkeys and apply ourselves recursively to each one.
//
i=0;
do {
NeededSize = MaxKeyLen+1;
Status = DmEnumKey(Subkey,
i,
KeyBuffer,
&NeededSize,
NULL);
if (Status == ERROR_SUCCESS) {
//
// Call ourselves recursively on this keyname.
//
DmLocalDeleteTree(hLocalXsaction, Subkey, KeyBuffer);
} else {
//
// Some odd error, keep going with the next key.
//
++i;
}
} while ( Status != ERROR_NO_MORE_ITEMS );
DmCloseKey(Subkey);
Status = DmLocalDeleteKey(hLocalXsaction, hKey, lpSubKey);
if (KeyBuffer != NULL) {
LocalFree(KeyBuffer);
}
return(Status);
}
DWORD
DmLocalDeleteValue(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpValueName
)
{
PDMKEY Key;
DWORD NameLength;
DWORD ValueNameLength;
DWORD UpdateLength;
PDM_DELETE_VALUE_UPDATE Update=NULL;
PUCHAR Dest;
DWORD Status;
HKEY hRegKey;
PLOCALXSACTION pLocalXsaction;
GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
Key = (PDMKEY)hKey;
Status = RegOpenKeyExW(DmpRoot,
Key->Name,
0,
KEY_SET_VALUE,
&hRegKey);
if (Status != ERROR_SUCCESS) {
goto FnExit;
}
Status = RegDeleteValueW(hRegKey, lpValueName);
RegCloseKey(hRegKey);
if (Status!=ERROR_SUCCESS)
goto FnExit;
//add the pending notification to be delivered on commit
DmpAddToPendingNotifications(pLocalXsaction, Key->Name, CLUSTER_CHANGE_REGISTRY_VALUE);
//successfully created key, write to the log
if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
&& ghQuoLog && pLocalXsaction->hLogXsaction)
{
//if successful and this is the logging node, then log
// the transaction
NameLength = (lstrlenW(Key->Name)+1)*sizeof(WCHAR);
ValueNameLength = (lstrlenW(lpValueName)+1)*sizeof(WCHAR);
UpdateLength = sizeof(DM_DELETE_VALUE_UPDATE) +
NameLength +
ValueNameLength;
Update = (PDM_DELETE_VALUE_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
if (Update == NULL) {
Status = ERROR_NOT_ENOUGH_MEMORY;
goto FnExit;
}
Update->lpStatus = NULL;
Update->NameOffset = FIELD_OFFSET(DM_DELETE_VALUE_UPDATE, KeyName)+NameLength;
CopyMemory(Update->KeyName, Key->Name, NameLength);
Dest = (PUCHAR)Update + Update->NameOffset;
CopyMemory(Dest, lpValueName, ValueNameLength);
if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
DmUpdateDeleteValue, Update, UpdateLength) == NULL_LSN)
{
Status = GetLastError();
goto FnExit;
}
}
FnExit:
if (Update) LocalFree(Update);
return(Status);
}
/****
@func VOID | DmpReportPendingNotifications| This is called
on commit or abort of a local transactions. On a commit,
notifications related to changes within a transaction
are delivered.
@parm IN PLOCALXSACTION | pLocalXsaction| A pointer to the local
transation context.
@parm IN BOOL | bCommit| Set to TRUE when the transaction is
commited.
@comm The pending notification structure associated with the
transaction is cleaned up.
@xref <f DmAbortLocalUpdate> <f DmCommitLocalUpdate>
****/
VOID
DmpReportPendingNotifications(
IN PLOCALXSACTION pLocalXsaction,
IN BOOL bCommit
)
{
PLIST_ENTRY pListEntry;
PDM_PENDING_NOTIFY pDmPendingNotify;
pListEntry = pLocalXsaction->PendingNotifyListHead.Flink;
//remove the entries and proces them one by one
//free them when done
while (pListEntry != &pLocalXsaction->PendingNotifyListHead)
{
pDmPendingNotify = CONTAINING_RECORD(pListEntry, DM_PENDING_NOTIFY, ListEntry);
// if transaction is commited
if (bCommit)
DmpReportNotify(pDmPendingNotify->pszKeyName, pDmPendingNotify->dwFilter);
pListEntry = pListEntry->Flink;
RemoveEntryList( &pDmPendingNotify->ListEntry );
LocalFree(pDmPendingNotify->pszKeyName);
LocalFree(pDmPendingNotify);
}
return;
}
/****
@func DWORD | DmpAddToPendingNotifications| This is called
by the DmLocal Api's to queue registry notifications
on success. The notifications are delivered or
thrown away depending on whether the transaction commits
or aborts.
@parm IN PLOCALXSACTION | pLocalXsaction| A pointer to the local
transation context.
@parm IN LPCWSTR | pszName| A pointer to the registry key name.
@parm IN DWORD | dwFilter | The filters associated with the notification.
@comm A new pending notification structure is created and associated
with the transaction.
@xref <f DmAbortLocalUpdate> <f DmCommitLocalUpdate>
****/
DWORD
DmpAddToPendingNotifications(
IN PLOCALXSACTION pLocalXsaction,
IN LPCWSTR pszName,
IN DWORD dwFilter
)
{
DWORD dwError = ERROR_SUCCESS;
PDM_PENDING_NOTIFY pDmPendingNotify;
pDmPendingNotify = LocalAlloc(LPTR, sizeof(DM_PENDING_NOTIFY));
if (!pDmPendingNotify)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
CL_LOGFAILURE(dwError);
goto FnExit;
}
pDmPendingNotify->pszKeyName = LocalAlloc(LMEM_FIXED,
((lstrlenW(pszName) + 1 ) * sizeof(WCHAR)));
if (!pDmPendingNotify->pszKeyName)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
CL_LOGFAILURE(dwError);
goto FnExit;
}
//initialize the structure
lstrcpyW(pDmPendingNotify->pszKeyName, pszName);
pDmPendingNotify->dwFilter = dwFilter;
InitializeListHead(&pDmPendingNotify->ListEntry);
//add to the list
InsertTailList(&pLocalXsaction->PendingNotifyListHead,
&pDmPendingNotify->ListEntry);
FnExit:
return(dwError);
}
/****
@func DWORD | DmAmITheOwnerOfTheQuorumResource| This harmless
function is used by regroup module to determine whether
a node thinks that it is the owner of the quorum resource or not.
****/
DWORD DmAmITheOwnerOfTheQuorumResource() {
return gpQuoResource
&& gpQuoResource->Group
&& gbIsQuoResOnline
&& AMIOWNEROFQUORES(gpQuoResource);
}
DWORD
DmRtlLocalCreateKey(
IN HLOCALXSACTION hLocalXsaction,
IN HDMKEY hKey,
IN LPCWSTR lpSubKey,
IN DWORD dwOptions,
IN DWORD samDesired,
IN OPTIONAL LPVOID lpSecurityDescriptor,
OUT HDMKEY * phkResult,
OUT LPDWORD lpDisposition
)
/*++
Routine Description:
Wrapper function for DmLocalCreateKey to be used with CLRtl* functions.
--*/
{
DWORD status;
*phkResult= DmLocalCreateKey(
hLocalXsaction,
hKey,
lpSubKey,
dwOptions,
samDesired,
lpSecurityDescriptor,
lpDisposition
);
if(* phkResult == NULL)
status=GetLastError();
else
status=ERROR_SUCCESS;
return status;
}