Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1167 lines
32 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dmlocal.c
  5. Abstract:
  6. Contains the routines for local transactions that can be called within
  7. gum handlers.
  8. Author:
  9. Sunita Shrivastava (sunitas) 24-Apr-1996
  10. Revision History:
  11. --*/
  12. #include "dmp.h"
  13. #include "clusudef.h"
  14. extern BOOL gbIsQuoLoggingOn;
  15. extern PFM_RESOURCE gpQuoResource;
  16. extern DWORD gbIsQuoResOnline;
  17. extern HLOG ghQuoLog;
  18. #if NO_SHARED_LOCKS
  19. extern CRITICAL_SECTION gLockDmpRoot;
  20. #else
  21. extern RTL_RESOURCE gLockDmpRoot;
  22. #endif
  23. /****
  24. @doc EXTERNAL INTERFACES CLUSSVC DM
  25. ****/
  26. /****
  27. @func HXSACTION | DmBeginLocalUpdate| Called by gum handlers to make consistent
  28. changes to the local registry. The log is reset and a start transaction
  29. record is written to the log, if the log is active.
  30. @comm When GumHandlers need to update the registry consitently they must use the
  31. LocalApis provided by DM.
  32. @rdesc Returns a transaction handle. NULL on failure. Call GetLastError()
  33. for error code.
  34. @xref <f DmAbortLocalUpdate> <f DmCommitLocalUpdate>
  35. ****/
  36. HLOCALXSACTION DmBeginLocalUpdate()
  37. {
  38. DWORD dwError=ERROR_SUCCESS;
  39. LSN StartXsactionLsn;
  40. DWORD dwSequence;
  41. HXSACTION hXsaction = NULL;
  42. PLOCALXSACTION pLocalXsaction = NULL;
  43. ClRtlLogPrint(LOG_NOISE,
  44. "[DM] DmBeginLocalUpdate Entry\r\n");
  45. //lock the data base, so that a check point is not taken in this duration
  46. //this lock is released in DmCommitLocalUpdate() or DmAbortLocalUpdate()
  47. //this lock also prevents the the registry from being flushed.
  48. ACQUIRE_EXCLUSIVE_LOCK(gLockDmpRoot);
  49. //Commit the registry so that it can be restored on abort
  50. if ((dwError = DmCommitRegistry()) != ERROR_SUCCESS)
  51. {
  52. goto FnExit;
  53. }
  54. //allocate memory for local transaction
  55. pLocalXsaction = LocalAlloc(LMEM_FIXED, sizeof(LOCALXSACTION));
  56. if (!pLocalXsaction)
  57. {
  58. dwError = ERROR_NOT_ENOUGH_MEMORY;
  59. goto FnExit;
  60. }
  61. pLocalXsaction->dwSig = LOCALXSAC_SIG;
  62. dwSequence = GumGetCurrentSequence(GumUpdateRegistry);
  63. pLocalXsaction->dwSequence = dwSequence;
  64. pLocalXsaction->hLogXsaction = NULL;
  65. InitializeListHead(&pLocalXsaction->PendingNotifyListHead);
  66. //log the start checkpoint record
  67. if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource) && ghQuoLog)
  68. {
  69. hXsaction = LogStartXsaction(ghQuoLog, dwSequence ,RMRegistryMgr, 0);
  70. if (!hXsaction)
  71. {
  72. dwError = GetLastError();
  73. }
  74. pLocalXsaction->hLogXsaction = hXsaction;
  75. }
  76. FnExit:
  77. if (dwError != ERROR_SUCCESS)
  78. {
  79. if (pLocalXsaction) LocalFree(pLocalXsaction);
  80. pLocalXsaction = NULL;
  81. RELEASE_LOCK(gLockDmpRoot);
  82. ClRtlLogPrint(LOG_NOISE,
  83. "[DM] DmBeginLocalUpdate Exit, pLocalXsaction=0x%1!08lx! Error=0x%2!08lx!\r\n",
  84. pLocalXsaction, dwError);
  85. SetLastError(dwError);
  86. } else {
  87. ClRtlLogPrint(LOG_NOISE,
  88. "[DM] DmBeginLocalUpdate Exit, pLocalXsaction=0x%1!08lx!\r\n",
  89. pLocalXsaction);
  90. }
  91. return((HLOCALXSACTION)pLocalXsaction);
  92. }
  93. /****
  94. @func DWORD | DmCommitLocalUpdate| This api must be called to commit
  95. the changes to the local registry.
  96. @parm IN HXSACTION | hXsaction | The handle to the transaction to be committed.
  97. @comm A commit record is written the quorum log if logging is active.
  98. @rdesc Returns a result code. ERROR_SUCCESS on success.
  99. @xref <f DmBeginLocalUpdate> <f DmAbortLocalUpdate>
  100. ****/
  101. DWORD DmCommitLocalUpdate(IN HLOCALXSACTION hLocalXsaction)
  102. {
  103. DWORD dwError=ERROR_SUCCESS;
  104. PLOCALXSACTION pLocalXsaction;
  105. ClRtlLogPrint(LOG_NOISE,
  106. "[DM] DmCommitLocalUpdate Entry\r\n");
  107. GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
  108. //update the gum sequence
  109. DmpUpdateSequence();
  110. DmpReportPendingNotifications(pLocalXsaction, TRUE );
  111. //write a commit record to the quorum log
  112. if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
  113. && ghQuoLog && pLocalXsaction->hLogXsaction)
  114. {
  115. CL_ASSERT(pLocalXsaction->hLogXsaction);
  116. dwError = LogCommitXsaction(ghQuoLog, pLocalXsaction->hLogXsaction, 0);
  117. //
  118. // Chittur Subbaraman (chitturs) - 1/19/99
  119. //
  120. pLocalXsaction->hLogXsaction = NULL;
  121. }
  122. //
  123. // Chittur Subbaraman (chitturs) - 1/19/99
  124. //
  125. // Make sure that the hLogXsaction memory is freed (even in the case
  126. // in which you started a local xsaction and didn't get a chance to
  127. // commit it or abort it to the log because quorum logging got turned
  128. // off in the middle, for example. This turning off of the logging
  129. // in the middle of a transaction could be considered as a bug ?)
  130. //
  131. LocalFree( pLocalXsaction->hLogXsaction );
  132. //invalidate the signature and free the transaction structure
  133. pLocalXsaction->dwSig = 0;
  134. LocalFree(pLocalXsaction);
  135. //release the database
  136. RELEASE_LOCK(gLockDmpRoot);
  137. ClRtlLogPrint(LOG_NOISE,
  138. "[DM] DmCommitLocalUpdate Exit, returning 0x%1!08lx!\r\n",
  139. dwError);
  140. return(dwError);
  141. }
  142. /****
  143. @func DWORD | DmAbortLocalUpdate| DmAbortLocalUpdate aborts all the changes
  144. to the local registry associated with this transaction.
  145. @parm IN HXSACTION | hXsaction | The handle to the transaction to be committed.
  146. @rdesc Returns a result code. ERROR_SUCCESS on success.
  147. @xref <f DmBeginLocalUpdate> <f DmCommitLocalUpdate>
  148. ****/
  149. DWORD DmAbortLocalUpdate(IN HLOCALXSACTION hLocalXsaction)
  150. {
  151. DWORD dwError=ERROR_SUCCESS;
  152. PLOCALXSACTION pLocalXsaction;
  153. ClRtlLogPrint(LOG_NOISE,
  154. "[DM] DmAbortLocalUpdate Entry\r\n");
  155. GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
  156. //write the abort chkpoint record
  157. //if the locker node is logging this is valid,
  158. //if the nonlocker node is logging, and it aborts
  159. // some other node will inherit the quorum log and
  160. //checkpoint and hence commit this update.
  161. if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
  162. && ghQuoLog && pLocalXsaction->hLogXsaction)
  163. {
  164. CL_ASSERT(pLocalXsaction->hLogXsaction);
  165. LogAbortXsaction(ghQuoLog, pLocalXsaction->hLogXsaction, 0);
  166. //
  167. // Chittur Subbaraman (chitturs) - 1/19/99
  168. //
  169. pLocalXsaction->hLogXsaction = NULL;
  170. }
  171. //SS: if the rollback fails, then we kill ourselves??
  172. //restore the old registry
  173. if ((dwError = DmRollbackRegistry()) != ERROR_SUCCESS)
  174. {
  175. CL_UNEXPECTED_ERROR(dwError);
  176. }
  177. //free any pending notifications that were built up for
  178. //this transaction
  179. DmpReportPendingNotifications(pLocalXsaction, FALSE );
  180. //
  181. // Chittur Subbaraman (chitturs) - 1/19/99
  182. //
  183. // Make sure that the hLogXsaction memory is freed (even in the case
  184. // in which you started a local xsaction and didn't get a chance to
  185. // commit it or abort it to the log because quorum logging got turned
  186. // off in the middle, for example. This turning off of the logging
  187. // in the middle of a transaction could be considered as a bug ?)
  188. //
  189. LocalFree( pLocalXsaction->hLogXsaction );
  190. //free the transaction structure, it cannot be used any more
  191. pLocalXsaction->dwSig = 0;
  192. LocalFree(pLocalXsaction);
  193. //release the database
  194. RELEASE_LOCK(gLockDmpRoot);
  195. ClRtlLogPrint(LOG_NOISE,
  196. "[DM] DmAbortLocalUpdate Exit, returning 0x%1!08lx!\r\n",
  197. dwError);
  198. return(dwError);
  199. }
  200. DWORD
  201. DmLocalSetValue(
  202. IN HLOCALXSACTION hLocalXsaction,
  203. IN HDMKEY hKey,
  204. IN LPCWSTR lpValueName,
  205. IN DWORD dwType,
  206. IN CONST BYTE *lpData,
  207. IN DWORD cbData
  208. )
  209. /*++
  210. Routine Description:
  211. This routine sets the named value for the specified
  212. cluster registry key on the local machine
  213. Arguments:
  214. hKey - Supplies the cluster registry subkey whose value is to be set
  215. lpValueName - Supplies the name of the value to be set.
  216. dwType - Supplies the value data type
  217. lpData - Supplies a pointer to the value data
  218. cbData - Supplies the length of the value data.
  219. Return Value:
  220. ERROR_SUCCESS if successful
  221. Win32 error code otherwise
  222. --*/
  223. {
  224. DWORD Status = ERROR_SUCCESS;
  225. PDMKEY Key;
  226. PUCHAR Dest;
  227. DWORD NameLength;
  228. DWORD ValueNameLength;
  229. DWORD UpdateLength;
  230. PDM_SET_VALUE_UPDATE Update = NULL;
  231. PLOCALXSACTION pLocalXsaction;
  232. Key = (PDMKEY)hKey;
  233. GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
  234. Status = RegSetValueExW(Key->hKey,
  235. lpValueName,
  236. 0,
  237. dwType,
  238. lpData,
  239. cbData);
  240. if (Status != ERROR_SUCCESS)
  241. {
  242. goto FnExit;
  243. }
  244. DmpAddToPendingNotifications(pLocalXsaction, Key->Name, CLUSTER_CHANGE_REGISTRY_VALUE);
  245. //write it to the quorum log
  246. if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
  247. && ghQuoLog && pLocalXsaction->hLogXsaction)
  248. {
  249. Key = (PDMKEY)hKey;
  250. NameLength = (lstrlenW(Key->Name)+1)*sizeof(WCHAR);
  251. ValueNameLength = (lstrlenW(lpValueName)+1)*sizeof(WCHAR);
  252. UpdateLength = sizeof(DM_SET_VALUE_UPDATE) +
  253. NameLength +
  254. ValueNameLength +
  255. cbData;
  256. Update = (PDM_SET_VALUE_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
  257. if (Update == NULL)
  258. {
  259. Status = ERROR_NOT_ENOUGH_MEMORY;
  260. goto FnExit;
  261. }
  262. Update->lpStatus = NULL;
  263. Update->NameOffset = FIELD_OFFSET(DM_SET_VALUE_UPDATE, KeyName)+NameLength;
  264. Update->DataOffset = Update->NameOffset + ValueNameLength;
  265. Update->DataLength = cbData;
  266. Update->Type = dwType;
  267. CopyMemory(Update->KeyName, Key->Name, NameLength);
  268. Dest = (PUCHAR)Update + Update->NameOffset;
  269. CopyMemory(Dest, lpValueName, ValueNameLength);
  270. Dest = (PUCHAR)Update + Update->DataOffset;
  271. CopyMemory(Dest, lpData, cbData);
  272. if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
  273. DmUpdateSetValue, Update, UpdateLength) == NULL_LSN)
  274. {
  275. Status = GetLastError();
  276. }
  277. }
  278. FnExit:
  279. if (Update) LocalFree(Update);
  280. return(Status);
  281. }
  282. HDMKEY
  283. DmLocalCreateKey(
  284. IN HLOCALXSACTION hLocalXsaction,
  285. IN HDMKEY hKey,
  286. IN LPCWSTR lpSubKey,
  287. IN DWORD dwOptions,
  288. IN DWORD samDesired,
  289. IN OPTIONAL LPVOID lpSecurityDescriptor,
  290. OUT LPDWORD lpDisposition
  291. )
  292. /*++
  293. Routine Description:
  294. Creates a key in the local registry. If the key exists, it
  295. is opened. If it does not exist, it is created.
  296. Arguments:
  297. hKey - Supplies the key that the create is relative to.
  298. lpSubKey - Supplies the key name relative to hKey
  299. dwOptions - Supplies any registry option flags.
  300. samDesired - Supplies desired security access mask
  301. lpSecurityDescriptor - Supplies security for the newly created key.
  302. Disposition - Returns whether the key was opened (REG_OPENED_EXISTING_KEY)
  303. or created (REG_CREATED_NEW_KEY)
  304. Return Value:
  305. A handle to the specified key if successful
  306. NULL otherwise. LastError will be set to the specific error code.
  307. --*/
  308. {
  309. PDMKEY Parent;
  310. PDMKEY Key = NULL;
  311. DWORD NameLength;
  312. DWORD Status;
  313. PDM_CREATE_KEY_UPDATE CreateUpdate = NULL;
  314. PVOID pBuffer = NULL;
  315. DWORD dwBufLength;
  316. DWORD dwSecurityLength;
  317. PLOCALXSACTION pLocalXsaction;
  318. GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
  319. if (dwOptions == REG_OPTION_VOLATILE)
  320. {
  321. Status = ERROR_INVALID_PARAMETER;
  322. goto FnExit;
  323. }
  324. Parent = (PDMKEY)hKey;
  325. //
  326. // Allocate the DMKEY structure.
  327. //
  328. NameLength = (lstrlenW(Parent->Name) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR);
  329. Key = LocalAlloc(LMEM_FIXED, sizeof(DMKEY)+NameLength);
  330. if (Key == NULL) {
  331. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  332. Status = ERROR_NOT_ENOUGH_MEMORY;
  333. goto FnExit;
  334. }
  335. //
  336. // Create the key on the local machine.
  337. //
  338. Status = RegCreateKeyExW(Parent->hKey,
  339. lpSubKey,
  340. 0,
  341. NULL,
  342. 0,
  343. samDesired,
  344. lpSecurityDescriptor,
  345. &Key->hKey,
  346. lpDisposition);
  347. if (Status != ERROR_SUCCESS) {
  348. goto FnExit;
  349. }
  350. //
  351. // Create the key name
  352. //
  353. lstrcpyW(Key->Name, Parent->Name);
  354. if (Key->Name[0] != UNICODE_NULL) {
  355. lstrcatW(Key->Name, L"\\");
  356. }
  357. lstrcatW(Key->Name, lpSubKey);
  358. Key->GrantedAccess = samDesired;
  359. EnterCriticalSection(&KeyLock);
  360. InsertHeadList(&KeyList, &Key->ListEntry);
  361. InitializeListHead(&Key->NotifyList);
  362. LeaveCriticalSection(&KeyLock);
  363. //add the pending notification to be delivered on commit
  364. DmpAddToPendingNotifications(pLocalXsaction, Key->Name, CLUSTER_CHANGE_REGISTRY_NAME);
  365. //successfully created key, write to the log
  366. if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
  367. && ghQuoLog && pLocalXsaction->hLogXsaction)
  368. {
  369. //get the length of the security structure
  370. if (ARGUMENT_PRESENT(lpSecurityDescriptor))
  371. {
  372. dwSecurityLength = GetSecurityDescriptorLength(lpSecurityDescriptor);
  373. }
  374. else
  375. {
  376. dwSecurityLength = 0;
  377. }
  378. CreateUpdate = (PDM_CREATE_KEY_UPDATE)LocalAlloc(LMEM_FIXED, sizeof(DM_CREATE_KEY_UPDATE));
  379. if (CreateUpdate == NULL) {
  380. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  381. Status = ERROR_NOT_ENOUGH_MEMORY;
  382. goto FnExit;
  383. }
  384. //
  385. // Issue the update.
  386. //
  387. CreateUpdate->lpDisposition = lpDisposition;
  388. CreateUpdate->phKey = &Key->hKey;
  389. CreateUpdate->samDesired = samDesired;
  390. CreateUpdate->dwOptions = dwOptions;
  391. if (ARGUMENT_PRESENT(lpSecurityDescriptor)) {
  392. CreateUpdate->SecurityPresent = TRUE;
  393. } else {
  394. CreateUpdate->SecurityPresent = FALSE;
  395. }
  396. //marshall the data,
  397. pBuffer = GumMarshallArgs(&dwBufLength,
  398. 3,
  399. sizeof(DM_CREATE_KEY_UPDATE),
  400. CreateUpdate,
  401. (lstrlenW(Key->Name)+1)*sizeof(WCHAR),
  402. Key->Name,
  403. dwSecurityLength,
  404. lpSecurityDescriptor);
  405. if (pBuffer)
  406. {
  407. CL_ASSERT(pLocalXsaction->hLogXsaction);
  408. //write it to the logger
  409. if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
  410. DmUpdateCreateKey, pBuffer, dwBufLength) == NULL_LSN)
  411. {
  412. Status = GetLastError();
  413. goto FnExit;
  414. }
  415. }
  416. }
  417. FnExit:
  418. if (Status != ERROR_SUCCESS)
  419. {
  420. if (Key) LocalFree(Key);
  421. Key = NULL;
  422. SetLastError(Status);
  423. }
  424. if (CreateUpdate) LocalFree(CreateUpdate);
  425. if (pBuffer) LocalFree(pBuffer);
  426. return((HDMKEY)Key);
  427. }
  428. DWORD
  429. DmLocalRemoveFromMultiSz(
  430. IN HLOCALXSACTION hLocalXsaction,
  431. IN HDMKEY hKey,
  432. IN LPCWSTR lpValueName,
  433. IN LPCWSTR lpString
  434. )
  435. /*++
  436. Routine Description:
  437. Removes a string from a REG_MULTI_SZ value.
  438. Arguments:
  439. hKey - Supplies the key where the value exists. This key must
  440. have been opened with READ | KEY_SET_VALUE access
  441. lpValueName - Supplies the name of the value.
  442. lpString - Supplies the string to be removed from the REG_MULTI_SZ value
  443. Return Value:
  444. ERROR_SUCCESS if successful
  445. Win32 error code otherwise
  446. --*/
  447. {
  448. DWORD Status;
  449. LPWSTR Buffer=NULL;
  450. DWORD BufferSize;
  451. DWORD DataSize;
  452. LPWSTR Current;
  453. DWORD CurrentLength;
  454. DWORD i;
  455. LPWSTR Next;
  456. PCHAR Src, Dest;
  457. DWORD NextLength;
  458. DWORD MultiLength;
  459. BufferSize = 0;
  460. Status = DmQueryString(hKey,
  461. lpValueName,
  462. REG_MULTI_SZ,
  463. &Buffer,
  464. &BufferSize,
  465. &DataSize);
  466. if (Status != ERROR_SUCCESS) {
  467. return(Status);
  468. }
  469. MultiLength = DataSize/sizeof(WCHAR);
  470. Status = ClRtlMultiSzRemove(Buffer,
  471. &MultiLength,
  472. lpString);
  473. if (Status == ERROR_SUCCESS) {
  474. //
  475. // Set the new value back.
  476. //
  477. Status = DmLocalSetValue(hLocalXsaction,
  478. hKey,
  479. lpValueName,
  480. REG_MULTI_SZ,
  481. (CONST BYTE *)Buffer,
  482. MultiLength * sizeof(WCHAR));
  483. } else if (Status == ERROR_FILE_NOT_FOUND) {
  484. Status = ERROR_SUCCESS;
  485. }
  486. if (Buffer) LocalFree(Buffer);
  487. return(Status);
  488. }
  489. DWORD
  490. DmLocalAppendToMultiSz(
  491. IN HLOCALXSACTION hLocalXsaction,
  492. IN HDMKEY hKey,
  493. IN LPCWSTR lpValueName,
  494. IN LPCWSTR lpString
  495. )
  496. /*++
  497. Routine Description:
  498. Adds another string to a REG_MULTI_SZ value. If the value does
  499. not exist, it will be created.
  500. Arguments:
  501. hLocalXsaction - A handle to a local transaction.
  502. hKey - Supplies the key where the value exists. This key must
  503. have been opened with KEY_READ | KEY_SET_VALUE access
  504. lpValueName - Supplies the name of the value.
  505. lpString - Supplies the string to be appended to the REG_MULTI_SZ value
  506. Return Value:
  507. ERROR_SUCCESS if successful
  508. Win32 error code otherwise
  509. --*/
  510. {
  511. DWORD ValueLength = 512;
  512. DWORD ReturnedLength;
  513. LPWSTR ValueData;
  514. DWORD StringLength;
  515. DWORD Status;
  516. DWORD cbValueData;
  517. PWSTR s;
  518. DWORD Type;
  519. StringLength = (lstrlenW(lpString)+1)*sizeof(WCHAR);
  520. retry:
  521. ValueData = LocalAlloc(LMEM_FIXED, ValueLength + StringLength);
  522. if (ValueData == NULL) {
  523. return(ERROR_NOT_ENOUGH_MEMORY);
  524. }
  525. cbValueData = ValueLength;
  526. Status = DmQueryValue(hKey,
  527. lpValueName,
  528. &Type,
  529. (LPBYTE)ValueData,
  530. &cbValueData);
  531. if (Status == ERROR_MORE_DATA) {
  532. //
  533. // The existing value is too large for our buffer.
  534. // Retry with a larger buffer.
  535. //
  536. ValueLength = cbValueData;
  537. LocalFree(ValueData);
  538. goto retry;
  539. }
  540. if (Status == ERROR_FILE_NOT_FOUND) {
  541. //
  542. // The value does not currently exist. Create the
  543. // value with our data.
  544. //
  545. s = ValueData;
  546. } else if (Status == ERROR_SUCCESS) {
  547. //
  548. // A value already exists. Append our string to the
  549. // MULTI_SZ.
  550. //
  551. s = (PWSTR)((PCHAR)ValueData + cbValueData) - 1;
  552. } else {
  553. LocalFree(ValueData);
  554. return(Status);
  555. }
  556. CopyMemory(s, lpString, StringLength);
  557. s += (StringLength / sizeof(WCHAR));
  558. *s++ = L'\0';
  559. Status = DmLocalSetValue(
  560. hLocalXsaction,
  561. hKey,
  562. lpValueName,
  563. REG_MULTI_SZ,
  564. (CONST BYTE *)ValueData,
  565. (DWORD)((s-ValueData)*sizeof(WCHAR)));
  566. LocalFree(ValueData);
  567. return(Status);
  568. }
  569. DWORD
  570. DmLocalDeleteKey(
  571. IN HLOCALXSACTION hLocalXsaction,
  572. IN HDMKEY hKey,
  573. IN LPCWSTR lpSubKey
  574. )
  575. /*++
  576. Routine Description:
  577. Deletes the specified key from the local registry. A key that has subkeys cannot
  578. be deleted.
  579. Arguments:
  580. hKey - Supplies a handle to a currently open key.
  581. lpSubKey - Points to a null-terminated string specifying the
  582. name of the key to delete. This parameter cannot be NULL,
  583. and the specified key must not have subkeys.
  584. Return Value:
  585. If the function succeeds, the return value is ERROR_SUCCESS.
  586. If the function fails, the return value is an error value.
  587. --*/
  588. {
  589. PDMKEY Key;
  590. DWORD NameLength;
  591. DWORD UpdateLength;
  592. PDM_DELETE_KEY_UPDATE Update=NULL;
  593. DWORD Status;
  594. PLOCALXSACTION pLocalXsaction;
  595. GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
  596. Key = (PDMKEY)hKey;
  597. NameLength = (lstrlenW(Key->Name) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR);
  598. UpdateLength = NameLength + sizeof(DM_DELETE_KEY_UPDATE);
  599. Update = (PDM_DELETE_KEY_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
  600. if (Update == NULL)
  601. {
  602. Status = ERROR_NOT_ENOUGH_MEMORY;
  603. goto FnExit;
  604. }
  605. //dont need an update on status thru marshalled data
  606. Update->lpStatus = NULL;
  607. CopyMemory(Update->Name, Key->Name, (lstrlenW(Key->Name) + 1) * sizeof(WCHAR));
  608. if (Update->Name[0] != L'\0')
  609. {
  610. lstrcatW(Update->Name, L"\\");
  611. }
  612. lstrcatW(Update->Name, lpSubKey);
  613. Status = RegDeleteKeyW(DmpRoot, Update->Name);
  614. if (Status != ERROR_SUCCESS)
  615. goto FnExit;
  616. //add the pending notification to be delivered on commit
  617. DmpAddToPendingNotifications(pLocalXsaction, Update->Name, CLUSTER_CHANGE_REGISTRY_NAME);
  618. //successfully deleted key, write to the log
  619. if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
  620. && ghQuoLog && pLocalXsaction->hLogXsaction)
  621. {
  622. if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
  623. DmUpdateDeleteKey, Update, UpdateLength) == NULL_LSN)
  624. {
  625. Status = GetLastError();
  626. goto FnExit;
  627. }
  628. }
  629. FnExit:
  630. if (Update) LocalFree(Update);
  631. return(Status);
  632. }
  633. DWORD
  634. DmLocalDeleteTree(
  635. IN HLOCALXSACTION hLocalXsaction,
  636. IN HDMKEY hKey,
  637. IN LPCWSTR lpSubKey
  638. )
  639. /*++
  640. Routine Description:
  641. Deletes the specified registry subtree in the local registry.
  642. All subkeys are deleted.
  643. Arguments:
  644. hKey - Supplies a handle to a currently open key.
  645. lpSubKey - Points to a null-terminated string specifying the
  646. name of the key to delete. This parameter cannot be NULL.
  647. Any subkeys of the specified key will also be deleted.
  648. Return Value:
  649. If the function succeeds, the return value is ERROR_SUCCESS.
  650. If the function fails, the return value is an error value.
  651. --*/
  652. {
  653. HDMKEY Subkey;
  654. DWORD i;
  655. DWORD Status;
  656. LPWSTR KeyBuffer=NULL;
  657. DWORD MaxKeyLen;
  658. DWORD NeededSize;
  659. Subkey = DmOpenKey(hKey,
  660. lpSubKey,
  661. MAXIMUM_ALLOWED);
  662. if (Subkey == NULL) {
  663. Status = GetLastError();
  664. return(Status);
  665. }
  666. //
  667. // Get the size of name buffer we will need.
  668. //
  669. Status = DmQueryInfoKey(Subkey,
  670. NULL,
  671. &MaxKeyLen,
  672. NULL,
  673. NULL,
  674. NULL,
  675. NULL,
  676. NULL);
  677. if (Status != ERROR_SUCCESS) {
  678. CL_UNEXPECTED_ERROR( Status );
  679. DmCloseKey(Subkey);
  680. return(Status);
  681. }
  682. KeyBuffer = LocalAlloc(LMEM_FIXED, (MaxKeyLen+1)*sizeof(WCHAR));
  683. if (KeyBuffer == NULL) {
  684. CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
  685. DmCloseKey(Subkey);
  686. return(ERROR_NOT_ENOUGH_MEMORY);
  687. }
  688. //
  689. // Enumerate the subkeys and apply ourselves recursively to each one.
  690. //
  691. i=0;
  692. do {
  693. NeededSize = MaxKeyLen+1;
  694. Status = DmEnumKey(Subkey,
  695. i,
  696. KeyBuffer,
  697. &NeededSize,
  698. NULL);
  699. if (Status == ERROR_SUCCESS) {
  700. //
  701. // Call ourselves recursively on this keyname.
  702. //
  703. DmLocalDeleteTree(hLocalXsaction, Subkey, KeyBuffer);
  704. } else {
  705. //
  706. // Some odd error, keep going with the next key.
  707. //
  708. ++i;
  709. }
  710. } while ( Status != ERROR_NO_MORE_ITEMS );
  711. DmCloseKey(Subkey);
  712. Status = DmLocalDeleteKey(hLocalXsaction, hKey, lpSubKey);
  713. if (KeyBuffer != NULL) {
  714. LocalFree(KeyBuffer);
  715. }
  716. return(Status);
  717. }
  718. DWORD
  719. DmLocalDeleteValue(
  720. IN HLOCALXSACTION hLocalXsaction,
  721. IN HDMKEY hKey,
  722. IN LPCWSTR lpValueName
  723. )
  724. {
  725. PDMKEY Key;
  726. DWORD NameLength;
  727. DWORD ValueNameLength;
  728. DWORD UpdateLength;
  729. PDM_DELETE_VALUE_UPDATE Update=NULL;
  730. PUCHAR Dest;
  731. DWORD Status;
  732. HKEY hRegKey;
  733. PLOCALXSACTION pLocalXsaction;
  734. GETLOCALXSACTION(pLocalXsaction, hLocalXsaction);
  735. Key = (PDMKEY)hKey;
  736. Status = RegOpenKeyExW(DmpRoot,
  737. Key->Name,
  738. 0,
  739. KEY_SET_VALUE,
  740. &hRegKey);
  741. if (Status != ERROR_SUCCESS) {
  742. goto FnExit;
  743. }
  744. Status = RegDeleteValueW(hRegKey, lpValueName);
  745. RegCloseKey(hRegKey);
  746. if (Status!=ERROR_SUCCESS)
  747. goto FnExit;
  748. //add the pending notification to be delivered on commit
  749. DmpAddToPendingNotifications(pLocalXsaction, Key->Name, CLUSTER_CHANGE_REGISTRY_VALUE);
  750. //successfully created key, write to the log
  751. if (gbIsQuoLoggingOn && gbIsQuoResOnline && AMIOWNEROFQUORES(gpQuoResource)
  752. && ghQuoLog && pLocalXsaction->hLogXsaction)
  753. {
  754. //if successful and this is the logging node, then log
  755. // the transaction
  756. NameLength = (lstrlenW(Key->Name)+1)*sizeof(WCHAR);
  757. ValueNameLength = (lstrlenW(lpValueName)+1)*sizeof(WCHAR);
  758. UpdateLength = sizeof(DM_DELETE_VALUE_UPDATE) +
  759. NameLength +
  760. ValueNameLength;
  761. Update = (PDM_DELETE_VALUE_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
  762. if (Update == NULL) {
  763. Status = ERROR_NOT_ENOUGH_MEMORY;
  764. goto FnExit;
  765. }
  766. Update->lpStatus = NULL;
  767. Update->NameOffset = FIELD_OFFSET(DM_DELETE_VALUE_UPDATE, KeyName)+NameLength;
  768. CopyMemory(Update->KeyName, Key->Name, NameLength);
  769. Dest = (PUCHAR)Update + Update->NameOffset;
  770. CopyMemory(Dest, lpValueName, ValueNameLength);
  771. if (LogWriteXsaction(ghQuoLog, pLocalXsaction->hLogXsaction,
  772. DmUpdateDeleteValue, Update, UpdateLength) == NULL_LSN)
  773. {
  774. Status = GetLastError();
  775. goto FnExit;
  776. }
  777. }
  778. FnExit:
  779. if (Update) LocalFree(Update);
  780. return(Status);
  781. }
  782. /****
  783. @func VOID | DmpReportPendingNotifications| This is called
  784. on commit or abort of a local transactions. On a commit,
  785. notifications related to changes within a transaction
  786. are delivered.
  787. @parm IN PLOCALXSACTION | pLocalXsaction| A pointer to the local
  788. transation context.
  789. @parm IN BOOL | bCommit| Set to TRUE when the transaction is
  790. commited.
  791. @comm The pending notification structure associated with the
  792. transaction is cleaned up.
  793. @xref <f DmAbortLocalUpdate> <f DmCommitLocalUpdate>
  794. ****/
  795. VOID
  796. DmpReportPendingNotifications(
  797. IN PLOCALXSACTION pLocalXsaction,
  798. IN BOOL bCommit
  799. )
  800. {
  801. PLIST_ENTRY pListEntry;
  802. PDM_PENDING_NOTIFY pDmPendingNotify;
  803. pListEntry = pLocalXsaction->PendingNotifyListHead.Flink;
  804. //remove the entries and proces them one by one
  805. //free them when done
  806. while (pListEntry != &pLocalXsaction->PendingNotifyListHead)
  807. {
  808. pDmPendingNotify = CONTAINING_RECORD(pListEntry, DM_PENDING_NOTIFY, ListEntry);
  809. // if transaction is commited
  810. if (bCommit)
  811. DmpReportNotify(pDmPendingNotify->pszKeyName, pDmPendingNotify->dwFilter);
  812. pListEntry = pListEntry->Flink;
  813. RemoveEntryList( &pDmPendingNotify->ListEntry );
  814. LocalFree(pDmPendingNotify->pszKeyName);
  815. LocalFree(pDmPendingNotify);
  816. }
  817. return;
  818. }
  819. /****
  820. @func DWORD | DmpAddToPendingNotifications| This is called
  821. by the DmLocal Api's to queue registry notifications
  822. on success. The notifications are delivered or
  823. thrown away depending on whether the transaction commits
  824. or aborts.
  825. @parm IN PLOCALXSACTION | pLocalXsaction| A pointer to the local
  826. transation context.
  827. @parm IN LPCWSTR | pszName| A pointer to the registry key name.
  828. @parm IN DWORD | dwFilter | The filters associated with the notification.
  829. @comm A new pending notification structure is created and associated
  830. with the transaction.
  831. @xref <f DmAbortLocalUpdate> <f DmCommitLocalUpdate>
  832. ****/
  833. DWORD
  834. DmpAddToPendingNotifications(
  835. IN PLOCALXSACTION pLocalXsaction,
  836. IN LPCWSTR pszName,
  837. IN DWORD dwFilter
  838. )
  839. {
  840. DWORD dwError = ERROR_SUCCESS;
  841. PDM_PENDING_NOTIFY pDmPendingNotify;
  842. pDmPendingNotify = LocalAlloc(LPTR, sizeof(DM_PENDING_NOTIFY));
  843. if (!pDmPendingNotify)
  844. {
  845. dwError = ERROR_NOT_ENOUGH_MEMORY;
  846. CL_LOGFAILURE(dwError);
  847. goto FnExit;
  848. }
  849. pDmPendingNotify->pszKeyName = LocalAlloc(LMEM_FIXED,
  850. ((lstrlenW(pszName) + 1 ) * sizeof(WCHAR)));
  851. if (!pDmPendingNotify->pszKeyName)
  852. {
  853. dwError = ERROR_NOT_ENOUGH_MEMORY;
  854. CL_LOGFAILURE(dwError);
  855. goto FnExit;
  856. }
  857. //initialize the structure
  858. lstrcpyW(pDmPendingNotify->pszKeyName, pszName);
  859. pDmPendingNotify->dwFilter = dwFilter;
  860. InitializeListHead(&pDmPendingNotify->ListEntry);
  861. //add to the list
  862. InsertTailList(&pLocalXsaction->PendingNotifyListHead,
  863. &pDmPendingNotify->ListEntry);
  864. FnExit:
  865. return(dwError);
  866. }
  867. /****
  868. @func DWORD | DmAmITheOwnerOfTheQuorumResource| This harmless
  869. function is used by regroup module to determine whether
  870. a node thinks that it is the owner of the quorum resource or not.
  871. ****/
  872. DWORD DmAmITheOwnerOfTheQuorumResource() {
  873. return gpQuoResource
  874. && gpQuoResource->Group
  875. && gbIsQuoResOnline
  876. && AMIOWNEROFQUORES(gpQuoResource);
  877. }
  878. DWORD
  879. DmRtlLocalCreateKey(
  880. IN HLOCALXSACTION hLocalXsaction,
  881. IN HDMKEY hKey,
  882. IN LPCWSTR lpSubKey,
  883. IN DWORD dwOptions,
  884. IN DWORD samDesired,
  885. IN OPTIONAL LPVOID lpSecurityDescriptor,
  886. OUT HDMKEY * phkResult,
  887. OUT LPDWORD lpDisposition
  888. )
  889. /*++
  890. Routine Description:
  891. Wrapper function for DmLocalCreateKey to be used with CLRtl* functions.
  892. --*/
  893. {
  894. DWORD status;
  895. *phkResult= DmLocalCreateKey(
  896. hLocalXsaction,
  897. hKey,
  898. lpSubKey,
  899. dwOptions,
  900. samDesired,
  901. lpSecurityDescriptor,
  902. lpDisposition
  903. );
  904. if(* phkResult == NULL)
  905. status=GetLastError();
  906. else
  907. status=ERROR_SUCCESS;
  908. return status;
  909. }