/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    cmapi2.c

Abstract:

    This module contains CM level entry points for the registry,
    particularly those which we don't want to link into tools,
    setup, the boot loader, etc.

Author:

    Bryan M. Willman (bryanwi) 26-Jan-1993

Revision History:

--*/

#include "cmp.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmDeleteKey)
#endif


NTSTATUS
CmDeleteKey(
    IN PCM_KEY_BODY KeyBody
    )
/*++

Routine Description:

    Delete a registry key, clean up Notify block.

Arguments:

    KeyBody - pointer to key handle object

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS    status;
    PCM_KEY_NODE  ptarget;
    PHHIVE      Hive;
    HCELL_INDEX Cell;
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock;


    CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmDeleteKey\n"));

    CmpLockRegistryExclusive();

    //
    // If already marked for deletion, storage is gone, so
    // do nothing and return success.
    //
    KeyControlBlock = KeyBody->KeyControlBlock;
    if (KeyControlBlock->Delete == TRUE) {
        status = STATUS_SUCCESS;
        goto Exit;
    }

    ptarget = KeyControlBlock->KeyNode;

    if ( ((ptarget->SubKeyCounts[Stable] +
           ptarget->SubKeyCounts[Volatile]) == 0) &&
         ((ptarget->Flags & KEY_NO_DELETE) == 0))
    {
        //
        // Cell is NOT marked NO_DELETE and does NOT have children
        // Send Notification while key still present, if delete fails,
        //   we'll have sent a spurious notify, that doesn't matter
        // Delete the actual storage
        //
        Hive = KeyControlBlock->KeyHive;
        Cell = KeyControlBlock->KeyCell;

        CmpReportNotify(
            KeyControlBlock->FullName,
            Hive,
            Cell,
            REG_NOTIFY_CHANGE_NAME
            );

        status = CmpFreeKeyByCell(Hive, Cell, TRUE);

        if (NT_SUCCESS(status)) {
            //
            // post any waiting notifies
            //
            CmpFlushNotify(KeyBody);

            //
            // Remove kcb from kcb list/tree, but do NOT
            // free its storage, CmDelete will do that when
            // the last refering handle is closed
            //
            CmpRemoveKeyControlBlock(KeyControlBlock);
            KeyControlBlock->KeyHive = NULL;
            KeyControlBlock->KeyCell = HCELL_NIL;
            KeyControlBlock->KeyNode = NULL;

            KeyControlBlock->Delete = TRUE;
        }

    } else {

        status = STATUS_CANNOT_DELETE;

    }

Exit:
    CmpUnlockRegistry();
    return status;
}