Source code of Windows XP (NT5)
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.

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