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.

295 lines
9.3 KiB

  1. //
  2. // REGDKEY.C
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995
  5. //
  6. // Implementation of RegDeleteKey and supporting functions.
  7. //
  8. #include "pch.h"
  9. //
  10. // RgFreeDatablockStructures
  11. //
  12. // Helper routine for RgDeleteKey. Deletes the specified datablock structures.
  13. // The datablock is not assumed to be locked. We don't care about the success
  14. // of this routine-- in the worst case, some stuff will be orphaned in the
  15. // file.
  16. //
  17. VOID
  18. INTERNAL
  19. RgFreeDatablockStructures(
  20. LPFILE_INFO lpFileInfo,
  21. UINT BlockIndex,
  22. UINT KeyRecordIndex
  23. )
  24. {
  25. LPDATABLOCK_INFO lpDatablockInfo;
  26. LPKEY_RECORD lpKeyRecord;
  27. if (RgLockKeyRecord(lpFileInfo, BlockIndex, (BYTE) KeyRecordIndex,
  28. &lpKeyRecord) == ERROR_SUCCESS) {
  29. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  30. RgFreeKeyRecord(lpDatablockInfo, lpKeyRecord);
  31. RgFreeKeyRecordIndex(lpDatablockInfo, KeyRecordIndex);
  32. RgUnlockDatablock(lpFileInfo, BlockIndex, TRUE);
  33. }
  34. }
  35. //
  36. // RgDeleteKey
  37. //
  38. // Worker routine for VMMRegDeleteKey. The given key handle references a key
  39. // that has already been validated as "deleteable".
  40. //
  41. int
  42. INTERNAL
  43. RgDeleteKey(
  44. HKEY hKey
  45. )
  46. {
  47. int ErrorCode;
  48. LPFILE_INFO lpFileInfo;
  49. DWORD KeynodeIndex;
  50. LPKEYNODE lpKeynode;
  51. DWORD NextKeynodeIndex;
  52. LPKEYNODE lpNextKeynode;
  53. DWORD ReplacementKeynodeIndex;
  54. HKEY hTempKey;
  55. lpFileInfo = hKey-> lpFileInfo;
  56. //
  57. // Stage one: unlink the keynode of the specified key from the keynode
  58. // tree and free all associate file structures with the key.
  59. //
  60. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, hKey-> KeynodeIndex,
  61. &lpKeynode)) != ERROR_SUCCESS)
  62. return ErrorCode;
  63. KeynodeIndex = lpKeynode-> ParentIndex;
  64. ReplacementKeynodeIndex = lpKeynode-> NextIndex;
  65. RgUnlockKeynode(lpFileInfo, hKey-> KeynodeIndex, FALSE);
  66. // Signal any waiting notifies on the parent that this key is about to be
  67. // deleted.
  68. //
  69. // Note that we may fail below, but NT does _exactly_ the same thing in
  70. // this case: doesn't care. If we get an error and don't actually delete
  71. // this key, then we'll have sent a spurious notify.
  72. //
  73. // Note also that we don't send any notification that the key itself has
  74. // been deleted. REG_NOTIFY_CHANGE_NAME is supposed to be for subkey
  75. // changes only, not changes to the key itself. But because of the
  76. // incompatible way we must deal with subkeys of the key we're about to
  77. // delete, we may well end up notifying the key if it has subkeys.
  78. RgSignalWaitingNotifies(lpFileInfo, KeynodeIndex, REG_NOTIFY_CHANGE_NAME);
  79. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex,
  80. &lpKeynode)) != ERROR_SUCCESS)
  81. return ErrorCode;
  82. // The per-key cache that we use for RegEnumKey may be invalid, so it must
  83. // be zapped.
  84. if (!IsNullPtr(hTempKey = RgFindOpenKeyHandle(lpFileInfo, KeynodeIndex)))
  85. hTempKey-> Flags &= ~KEYF_ENUMKEYCACHED;
  86. NextKeynodeIndex = lpKeynode-> ChildIndex;
  87. if (NextKeynodeIndex == hKey-> KeynodeIndex) {
  88. // Update the cached child keynode index in the open handle on the
  89. // parent.
  90. if (!IsNullPtr(hTempKey))
  91. hTempKey-> ChildKeynodeIndex = ReplacementKeynodeIndex;
  92. // This is the parent of the keynode that we need to delete. Replace
  93. // it's "child" link.
  94. lpKeynode-> ChildIndex = ReplacementKeynodeIndex;
  95. }
  96. else {
  97. // Loop through the siblings of the keynode we're trying to delete.
  98. do {
  99. RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
  100. KeynodeIndex = NextKeynodeIndex;
  101. if (IsNullKeynodeIndex(KeynodeIndex)) {
  102. DEBUG_OUT(("RgDeleteKey: couldn't find the keynode to delete\n"));
  103. return ERROR_BADDB;
  104. }
  105. if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex,
  106. &lpKeynode)) != ERROR_SUCCESS)
  107. return ErrorCode;
  108. NextKeynodeIndex = lpKeynode-> NextIndex;
  109. } while (NextKeynodeIndex != hKey-> KeynodeIndex);
  110. // This is the previous sibling of the keynode that we need to delete.
  111. // Replace it's "next" link.
  112. lpKeynode-> NextIndex = ReplacementKeynodeIndex;
  113. }
  114. // Unlock the updated "parent" or "next" of this keynode.
  115. RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE);
  116. // Free the structures associated with the datablock.
  117. RgFreeDatablockStructures(lpFileInfo, hKey-> BlockIndex, hKey->
  118. KeyRecordIndex);
  119. // Free the structures associated with the keynode tables.
  120. RgFreeKeynode(lpFileInfo, hKey-> KeynodeIndex);
  121. // The key is definitely toast now.
  122. hKey-> Flags |= KEYF_DELETED;
  123. //
  124. // Stage two: the specified key is unlinked, but any of its subkeys now
  125. // have to be freed. Errors are ignored at this point: we won't try to
  126. // undo the stuff we did in stage one. The worst thing that can happen is
  127. // that some file structures are orphaned.
  128. //
  129. NextKeynodeIndex = hKey-> ChildKeynodeIndex;
  130. if (IsNullKeynodeIndex(NextKeynodeIndex) || RgLockInUseKeynode(lpFileInfo,
  131. NextKeynodeIndex, &lpNextKeynode) != ERROR_SUCCESS)
  132. return ERROR_SUCCESS;
  133. while (!IsNullKeynodeIndex(NextKeynodeIndex)) {
  134. KeynodeIndex = NextKeynodeIndex;
  135. lpKeynode = lpNextKeynode;
  136. // Check if the keynode has any children. If it does and we can lock
  137. // it down, then move to it.
  138. NextKeynodeIndex = lpKeynode-> ChildIndex;
  139. if (!IsNullKeynodeIndex(NextKeynodeIndex) &&
  140. RgLockInUseKeynode(lpFileInfo, NextKeynodeIndex, &lpNextKeynode) ==
  141. ERROR_SUCCESS) {
  142. ASSERT(KeynodeIndex == lpNextKeynode-> ParentIndex);
  143. RgYield();
  144. // "Burn" the link to our child, so that on the way back out of
  145. // the tree, we don't end up recursing. Plus, if we hit any errors
  146. // deep in the tree deletion, the child of the current keynode
  147. // could have already been toasted, so we have to zap our link to
  148. // it.
  149. lpKeynode-> ChildIndex = REG_NULL;
  150. RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE);
  151. // We've now caused a change in the subkeys of the current key.
  152. // Note that we don't bother signaling notifies that are doing a
  153. // subtree watch because any such notifies should have already been
  154. // signaled by the above call or they've already been signaled
  155. // during our recursion. In the off chance that we have a lot of
  156. // notifications registered, this will avoid a lot of unnecessary
  157. // checking.
  158. RgSignalWaitingNotifies(lpFileInfo, KeynodeIndex,
  159. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_NO_WATCH_SUBTREE);
  160. continue;
  161. }
  162. // The keynode doesn't have any children. Check for sibling keynodes.
  163. NextKeynodeIndex = lpKeynode-> NextIndex;
  164. if (IsNullKeynodeIndex(NextKeynodeIndex) ||
  165. RgLockInUseKeynode(lpFileInfo, NextKeynodeIndex, &lpNextKeynode) !=
  166. ERROR_SUCCESS) {
  167. // The keynode doesn't have any siblings or we were unable to get
  168. // at them. Move back to the parent.
  169. NextKeynodeIndex = lpKeynode-> ParentIndex;
  170. // If we wrapped back up to the top of the deleted branch or if we
  171. // just can't access the parent keynode, then set next to REG_NULL
  172. // and bail out on the next iteration.
  173. if ((NextKeynodeIndex == hKey-> KeynodeIndex) ||
  174. RgLockInUseKeynode(lpFileInfo, NextKeynodeIndex,
  175. &lpNextKeynode) != ERROR_SUCCESS)
  176. NextKeynodeIndex = REG_NULL;
  177. }
  178. // If an open key refers to this file and keynode index, mark it as
  179. // deleted.
  180. if (!IsNullPtr(hTempKey = RgFindOpenKeyHandle(lpFileInfo,
  181. KeynodeIndex)))
  182. hTempKey-> Flags |= KEYF_DELETED;
  183. // Free the structures associated with the datablock.
  184. RgFreeDatablockStructures(lpFileInfo, lpKeynode-> BlockIndex,
  185. (BYTE) lpKeynode-> KeyRecordIndex);
  186. // Free the structures associated with the keynode tables.
  187. RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE);
  188. RgFreeKeynode(lpFileInfo, KeynodeIndex);
  189. }
  190. return ERROR_SUCCESS;
  191. }
  192. //
  193. // VMMRegDeleteKey
  194. //
  195. // See Win32 documentation for a description of the behavior.
  196. //
  197. // Although the Win32 documentation states that lpSubKey must be NULL, NT
  198. // actually allows this to pass through. Win95 rejected the call, but the only
  199. // reason we didn't change it then was because we realized too late in the
  200. // product that it was different.
  201. //
  202. LONG
  203. REGAPI
  204. VMMRegDeleteKey(
  205. HKEY hKey,
  206. LPCSTR lpSubKey
  207. )
  208. {
  209. LONG ErrorCode;
  210. HKEY hSubKey = 0;
  211. if ((ErrorCode = VMMRegOpenKey(hKey, lpSubKey, &hSubKey)) != ERROR_SUCCESS)
  212. return ErrorCode;
  213. if (!RgLockRegistry())
  214. ErrorCode = ERROR_LOCK_FAILED;
  215. else {
  216. if (IsKeyRootOfHive(hSubKey) || (hSubKey-> lpFileInfo-> Flags &
  217. FI_READONLY))
  218. ErrorCode = ERROR_ACCESS_DENIED;
  219. else
  220. ErrorCode = RgDeleteKey(hSubKey);
  221. RgUnlockRegistry();
  222. }
  223. VMMRegCloseKey(hSubKey);
  224. return ErrorCode;
  225. }