// // REGDKEY.C // // Copyright (C) Microsoft Corporation, 1995 // // Implementation of RegDeleteKey and supporting functions. // #include "pch.h" // // RgFreeDatablockStructures // // Helper routine for RgDeleteKey. Deletes the specified datablock structures. // The datablock is not assumed to be locked. We don't care about the success // of this routine-- in the worst case, some stuff will be orphaned in the // file. // VOID INTERNAL RgFreeDatablockStructures( LPFILE_INFO lpFileInfo, UINT BlockIndex, UINT KeyRecordIndex ) { LPDATABLOCK_INFO lpDatablockInfo; LPKEY_RECORD lpKeyRecord; if (RgLockKeyRecord(lpFileInfo, BlockIndex, (BYTE) KeyRecordIndex, &lpKeyRecord) == ERROR_SUCCESS) { lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex); RgFreeKeyRecord(lpDatablockInfo, lpKeyRecord); RgFreeKeyRecordIndex(lpDatablockInfo, KeyRecordIndex); RgUnlockDatablock(lpFileInfo, BlockIndex, TRUE); } } // // RgDeleteKey // // Worker routine for VMMRegDeleteKey. The given key handle references a key // that has already been validated as "deleteable". // int INTERNAL RgDeleteKey( HKEY hKey ) { int ErrorCode; LPFILE_INFO lpFileInfo; DWORD KeynodeIndex; LPKEYNODE lpKeynode; DWORD NextKeynodeIndex; LPKEYNODE lpNextKeynode; DWORD ReplacementKeynodeIndex; HKEY hTempKey; lpFileInfo = hKey-> lpFileInfo; // // Stage one: unlink the keynode of the specified key from the keynode // tree and free all associate file structures with the key. // if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, hKey-> KeynodeIndex, &lpKeynode)) != ERROR_SUCCESS) return ErrorCode; KeynodeIndex = lpKeynode-> ParentIndex; ReplacementKeynodeIndex = lpKeynode-> NextIndex; RgUnlockKeynode(lpFileInfo, hKey-> KeynodeIndex, FALSE); // Signal any waiting notifies on the parent that this key is about to be // deleted. // // Note that we may fail below, but NT does _exactly_ the same thing in // this case: doesn't care. If we get an error and don't actually delete // this key, then we'll have sent a spurious notify. // // Note also that we don't send any notification that the key itself has // been deleted. REG_NOTIFY_CHANGE_NAME is supposed to be for subkey // changes only, not changes to the key itself. But because of the // incompatible way we must deal with subkeys of the key we're about to // delete, we may well end up notifying the key if it has subkeys. RgSignalWaitingNotifies(lpFileInfo, KeynodeIndex, REG_NOTIFY_CHANGE_NAME); if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex, &lpKeynode)) != ERROR_SUCCESS) return ErrorCode; // The per-key cache that we use for RegEnumKey may be invalid, so it must // be zapped. if (!IsNullPtr(hTempKey = RgFindOpenKeyHandle(lpFileInfo, KeynodeIndex))) hTempKey-> Flags &= ~KEYF_ENUMKEYCACHED; NextKeynodeIndex = lpKeynode-> ChildIndex; if (NextKeynodeIndex == hKey-> KeynodeIndex) { // Update the cached child keynode index in the open handle on the // parent. if (!IsNullPtr(hTempKey)) hTempKey-> ChildKeynodeIndex = ReplacementKeynodeIndex; // This is the parent of the keynode that we need to delete. Replace // it's "child" link. lpKeynode-> ChildIndex = ReplacementKeynodeIndex; } else { // Loop through the siblings of the keynode we're trying to delete. do { RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE); KeynodeIndex = NextKeynodeIndex; if (IsNullKeynodeIndex(KeynodeIndex)) { DEBUG_OUT(("RgDeleteKey: couldn't find the keynode to delete\n")); return ERROR_BADDB; } if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex, &lpKeynode)) != ERROR_SUCCESS) return ErrorCode; NextKeynodeIndex = lpKeynode-> NextIndex; } while (NextKeynodeIndex != hKey-> KeynodeIndex); // This is the previous sibling of the keynode that we need to delete. // Replace it's "next" link. lpKeynode-> NextIndex = ReplacementKeynodeIndex; } // Unlock the updated "parent" or "next" of this keynode. RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE); // Free the structures associated with the datablock. RgFreeDatablockStructures(lpFileInfo, hKey-> BlockIndex, hKey-> KeyRecordIndex); // Free the structures associated with the keynode tables. RgFreeKeynode(lpFileInfo, hKey-> KeynodeIndex); // The key is definitely toast now. hKey-> Flags |= KEYF_DELETED; // // Stage two: the specified key is unlinked, but any of its subkeys now // have to be freed. Errors are ignored at this point: we won't try to // undo the stuff we did in stage one. The worst thing that can happen is // that some file structures are orphaned. // NextKeynodeIndex = hKey-> ChildKeynodeIndex; if (IsNullKeynodeIndex(NextKeynodeIndex) || RgLockInUseKeynode(lpFileInfo, NextKeynodeIndex, &lpNextKeynode) != ERROR_SUCCESS) return ERROR_SUCCESS; while (!IsNullKeynodeIndex(NextKeynodeIndex)) { KeynodeIndex = NextKeynodeIndex; lpKeynode = lpNextKeynode; // Check if the keynode has any children. If it does and we can lock // it down, then move to it. NextKeynodeIndex = lpKeynode-> ChildIndex; if (!IsNullKeynodeIndex(NextKeynodeIndex) && RgLockInUseKeynode(lpFileInfo, NextKeynodeIndex, &lpNextKeynode) == ERROR_SUCCESS) { ASSERT(KeynodeIndex == lpNextKeynode-> ParentIndex); RgYield(); // "Burn" the link to our child, so that on the way back out of // the tree, we don't end up recursing. Plus, if we hit any errors // deep in the tree deletion, the child of the current keynode // could have already been toasted, so we have to zap our link to // it. lpKeynode-> ChildIndex = REG_NULL; RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE); // We've now caused a change in the subkeys of the current key. // Note that we don't bother signaling notifies that are doing a // subtree watch because any such notifies should have already been // signaled by the above call or they've already been signaled // during our recursion. In the off chance that we have a lot of // notifications registered, this will avoid a lot of unnecessary // checking. RgSignalWaitingNotifies(lpFileInfo, KeynodeIndex, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_NO_WATCH_SUBTREE); continue; } // The keynode doesn't have any children. Check for sibling keynodes. NextKeynodeIndex = lpKeynode-> NextIndex; if (IsNullKeynodeIndex(NextKeynodeIndex) || RgLockInUseKeynode(lpFileInfo, NextKeynodeIndex, &lpNextKeynode) != ERROR_SUCCESS) { // The keynode doesn't have any siblings or we were unable to get // at them. Move back to the parent. NextKeynodeIndex = lpKeynode-> ParentIndex; // If we wrapped back up to the top of the deleted branch or if we // just can't access the parent keynode, then set next to REG_NULL // and bail out on the next iteration. if ((NextKeynodeIndex == hKey-> KeynodeIndex) || RgLockInUseKeynode(lpFileInfo, NextKeynodeIndex, &lpNextKeynode) != ERROR_SUCCESS) NextKeynodeIndex = REG_NULL; } // If an open key refers to this file and keynode index, mark it as // deleted. if (!IsNullPtr(hTempKey = RgFindOpenKeyHandle(lpFileInfo, KeynodeIndex))) hTempKey-> Flags |= KEYF_DELETED; // Free the structures associated with the datablock. RgFreeDatablockStructures(lpFileInfo, lpKeynode-> BlockIndex, (BYTE) lpKeynode-> KeyRecordIndex); // Free the structures associated with the keynode tables. RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE); RgFreeKeynode(lpFileInfo, KeynodeIndex); } return ERROR_SUCCESS; } // // VMMRegDeleteKey // // See Win32 documentation for a description of the behavior. // // Although the Win32 documentation states that lpSubKey must be NULL, NT // actually allows this to pass through. Win95 rejected the call, but the only // reason we didn't change it then was because we realized too late in the // product that it was different. // LONG REGAPI VMMRegDeleteKey( HKEY hKey, LPCSTR lpSubKey ) { LONG ErrorCode; HKEY hSubKey = 0; if ((ErrorCode = VMMRegOpenKey(hKey, lpSubKey, &hSubKey)) != ERROR_SUCCESS) return ErrorCode; if (!RgLockRegistry()) ErrorCode = ERROR_LOCK_FAILED; else { if (IsKeyRootOfHive(hSubKey) || (hSubKey-> lpFileInfo-> Flags & FI_READONLY)) ErrorCode = ERROR_ACCESS_DENIED; else ErrorCode = RgDeleteKey(hSubKey); RgUnlockRegistry(); } VMMRegCloseKey(hSubKey); return ErrorCode; }