/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    cmwraper.c

Abstract:

    Provides wrapper routines to support ntos\config routines called from
    user-mode.

Author:

    John Vert (jvert) 26-Mar-1992

Revision History:

--*/
#include "edithive.h"
#include "nturtl.h"
#include "stdlib.h"
#include "stdio.h"

extern  ULONG   UsedStorage;

CCHAR KiFindFirstSetRight[256] = {
        0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};


ULONG   MmSizeOfPagedPoolInBytes = 0xffffffff;  // stub out

ULONG
DbgPrint (
    IN PCH Format,
    ...
    )
{
    va_list arglist;
    UCHAR Buffer[512];
    STRING Output;

    //
    // Format the output into a buffer and then print it.
    //

    va_start(arglist, Format);
    Output.Length = _vsnprintf(Buffer, sizeof(Buffer), Format, arglist);
    Output.Buffer = Buffer;
    printf("%s", Buffer);
    return 0;
}


//
// Structure that describes the mapping of generic access rights to object
// specific access rights for registry key and keyroot objects.
//

GENERIC_MAPPING CmpKeyMapping = {
    KEY_READ,
    KEY_WRITE,
    KEY_EXECUTE,
    KEY_ALL_ACCESS
};
BOOLEAN CmpNoWrite = FALSE;
PCMHIVE CmpMasterHive = NULL;
LIST_ENTRY CmpHiveListHead;            // List of CMHIVEs

NTSTATUS
MyCmpInitHiveFromFile(
    IN PUNICODE_STRING FileName,
    OUT PCMHIVE *CmHive,
    OUT PBOOLEAN Allocate
    );


VOID
CmpLazyFlush(
    VOID
    )
{
}


VOID
CmpFreeSecurityDescriptor(
    IN PHHIVE Hive,
    IN HCELL_INDEX Cell
    )
{
    return;
}

VOID
CmpReportNotify(
    UNICODE_STRING          Name,
    PHHIVE                  Hive,
    HCELL_INDEX             Cell,
    ULONG                   Filter
    )
{
}

VOID
CmpLockRegistry(VOID)
{
    return;
}

BOOLEAN
CmpTryLockRegistryExclusive(
    IN BOOLEAN CanWait
    )
{
    return TRUE;
}

VOID
CmpUnlockRegistry(
    )
{
}

BOOLEAN
CmpTestRegistryLock()
{
    return TRUE;
}

BOOLEAN
CmpTestRegistryLockExclusive()
{
    return TRUE;
}
LONG
KeReleaseMutex (
    IN PKMUTEX Mutex,
    IN BOOLEAN Wait
    )
{
    return(0);
}
NTSTATUS
KeWaitForSingleObject (
    IN PVOID Object,
    IN KWAIT_REASON WaitReason,
    IN KPROCESSOR_MODE WaitMode,
    IN BOOLEAN Alertable,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )
{
    return(STATUS_SUCCESS);
}

BOOLEAN
CmpValidateHiveSecurityDescriptors(
    IN PHHIVE Hive
    )
{
    PCM_KEY_NODE RootNode;
    PCM_KEY_SECURITY SecurityCell;
    HCELL_INDEX ListAnchor;
    HCELL_INDEX NextCell;
    HCELL_INDEX LastCell;
    BOOLEAN ValidHive = TRUE;

    KdPrint(("CmpValidateHiveSecurityDescriptor: Hive = %lx\n",(ULONG)Hive));
    RootNode = (PCM_KEY_NODE) HvGetCell(Hive, Hive->BaseBlock->RootCell);
    ListAnchor = NextCell = RootNode->u1.s1.Security;

    do {
        SecurityCell = (PCM_KEY_SECURITY) HvGetCell(Hive, NextCell);
        if (NextCell != ListAnchor) {
            //
            // Check to make sure that our Blink points to where we just
            // came from.
            //
            if (SecurityCell->Blink != LastCell) {
                KdPrint(("  Invalid Blink (%ld) on security cell %ld\n",SecurityCell->Blink, NextCell));
                KdPrint(("  should point to %ld\n", LastCell));
                ValidHive = FALSE;
            }
        }
        KdPrint(("CmpValidSD:  SD shared by %d nodes\n",SecurityCell->ReferenceCount));
//        SetUsed(Hive, NextCell);
        LastCell = NextCell;
        NextCell = SecurityCell->Flink;
    } while ( NextCell != ListAnchor );
    return(TRUE);
}

VOID
KeBugCheck(
    IN ULONG BugCheckCode
    )
{
    printf("BugCheck: code = %08lx\n", BugCheckCode);
    exit(1);
}

VOID
KeBugCheckEx(
    IN ULONG BugCheckCode,
    IN ULONG Arg1,
    IN ULONG Arg2,
    IN ULONG Arg3,
    IN ULONG Arg4
    )
{
    printf("BugCheck: code = %08lx\n", BugCheckCode);
    printf("Args =%08lx %08lx %08lx %08lx\n", Arg1, Arg2, Arg3, Arg4);
    exit(1);
}


VOID
KeQuerySystemTime(
    OUT PLARGE_INTEGER SystemTime
    )
{
    NtQuerySystemTime(SystemTime);
}

#ifdef POOL_TAGGING
PVOID
ExAllocatePoolWithTag(
    IN POOL_TYPE PoolType,
    IN ULONG NumberOfBytes,
    IN ULONG Tag
    )
{
    PVOID   Address = NULL;
    ULONG   Size;
    NTSTATUS    status;

    Size = ROUND_UP(NumberOfBytes, HBLOCK_SIZE);
    status = NtAllocateVirtualMemory(
                NtCurrentProcess(),
                &Address,
                0,
                &Size,
                MEM_COMMIT,
                PAGE_READWRITE
                );
    if (!NT_SUCCESS(status)) {
        return NULL;
    }
    return Address;
}
#else

PVOID
ExAllocatePool(
    IN POOL_TYPE PoolType,
    IN ULONG NumberOfBytes
    )
{
    PVOID   Address = NULL;
    ULONG   Size;
    NTSTATUS    status;

    Size = ROUND_UP(NumberOfBytes, HBLOCK_SIZE);
    status = NtAllocateVirtualMemory(
                NtCurrentProcess(),
                &Address,
                0,
                &Size,
                MEM_COMMIT,
                PAGE_READWRITE
                );
    if (!NT_SUCCESS(status)) {
        return NULL;
    }
    return Address;
}
#endif

VOID
ExFreePool(
    IN PVOID P
    )
{
    ULONG   size;
    size = HBLOCK_SIZE;

    // if it was really more than 1 page, well, too bad
    NtFreeVirtualMemory(
        NtCurrentProcess(),
        &P,
        &size,
        MEM_DECOMMIT
        );
    return;
}


NTSTATUS
CmpWorkerCommand(
    IN OUT PREGISTRY_COMMAND Command
    )

/*++

Routine Description:

    This routine just encapsulates all the necessary synchronization for
    sending a command to the worker thread.

Arguments:

    Command - Supplies a pointer to an initialized REGISTRY_COMMAND structure
            which will be copied into the global communication structure.

Return Value:

    NTSTATUS = Command.Status

--*/

{
    PCMHIVE CmHive;
    PUNICODE_STRING FileName;
    ULONG i;

    switch (Command->Command) {

        case REG_CMD_FLUSH_KEY:
            return CmFlushKey(Command->Hive, Command->Cell);
            break;

        case REG_CMD_FILE_SET_SIZE:
            return CmpDoFileSetSize(
                      Command->Hive,
                      Command->FileType,
                      Command->FileSize
                      );
            break;

        case REG_CMD_HIVE_OPEN:

            //
            // Open the file.
            //
            FileName = Command->FileAttributes->ObjectName;

            return MyCmpInitHiveFromFile(FileName,
                                         &Command->CmHive,
                                         &Command->Allocate);

            break;

        case REG_CMD_HIVE_CLOSE:

            //
            // Close the files associated with this hive.
            //
            CmHive = Command->CmHive;

            for (i=0; i<HFILE_TYPE_MAX; i++) {
                if (CmHive->FileHandles[i] != NULL) {
                    NtClose(CmHive->FileHandles[i]);
                }
            }
            return STATUS_SUCCESS;
            break;

        case REG_CMD_SHUTDOWN:

            //
            // shut down the registry
            //
            break;

        default:
            return STATUS_INVALID_PARAMETER;
    }
}

NTSTATUS
MyCmpInitHiveFromFile(
    IN PUNICODE_STRING FileName,
    OUT PCMHIVE *CmHive,
    OUT PBOOLEAN Allocate
    )

/*++

Routine Description:

    This routine opens a file and log, allocates a CMHIVE, and initializes
    it.

Arguments:

    FileName - Supplies name of file to be loaded.

    CmHive   - Returns pointer to initialized hive (if successful)

    Allocate - Returns whether the hive was allocated or existing.

Return Value:

    NTSTATUS

--*/

{
    PCMHIVE NewHive;
    ULONG Disposition;
    ULONG SecondaryDisposition;
    HANDLE PrimaryHandle;
    HANDLE LogHandle;
    NTSTATUS Status;
    ULONG FileType;
    ULONG Operation;

    BOOLEAN Success;

    *CmHive = NULL;

    Status = CmpOpenHiveFiles(FileName,
                              L".log",
                              &PrimaryHandle,
                              &LogHandle,
                              &Disposition,
                              &SecondaryDisposition,
                              TRUE,
                              NULL
                              );
    if (!NT_SUCCESS(Status)) {
        return(Status);
    }

    if (LogHandle == NULL) {
        FileType = HFILE_TYPE_PRIMARY;
    } else {
        FileType = HFILE_TYPE_LOG;
    }

    if (Disposition == FILE_CREATED) {
        Operation = HINIT_CREATE;
        *Allocate = TRUE;
    } else {
        Operation = HINIT_FILE;
        *Allocate = FALSE;
    }

    Success = CmpInitializeHive(&NewHive,
                                Operation,
                                FALSE,
                                FileType,
                                NULL,
                                PrimaryHandle,
                                NULL,
                                LogHandle,
                                NULL,
                                NULL);
    if (!Success) {
        NtClose(PrimaryHandle);
        if (LogHandle != NULL) {
            NtClose(LogHandle);
        }
        return(STATUS_REGISTRY_CORRUPT);
    } else {
        *CmHive = NewHive;
        return(STATUS_SUCCESS);
    }
}

NTSTATUS
CmpLinkHiveToMaster(
    PUNICODE_STRING LinkName,
    HANDLE RootDirectory,
    PCMHIVE CmHive,
    BOOLEAN Allocate,
    PSECURITY_DESCRIPTOR SecurityDescriptor
    )
{
    return( STATUS_SUCCESS );
}


BOOLEAN
CmpFileSetSize(
    PHHIVE      Hive,
    ULONG       FileType,
    ULONG       FileSize
    )
/*++

Routine Description:

    This routine sets the size of a file.  It must not return until
    the size is guaranteed, therefore, it does a flush.

    It is environment specific.

    This routine will force execution to the correct thread context.

Arguments:

    Hive - Hive we are doing I/O for

    FileType - which supporting file to use

    FileSize - 32 bit value to set the file's size to

Return Value:

    FALSE if failure
    TRUE if success

--*/
{
    NTSTATUS    status;

    status = CmpDoFileSetSize(Hive, FileType, FileSize);
    if (!NT_SUCCESS(status)) {
        KdPrint(("CmpFileSetSize:\n\t"));
        KdPrint(("Failure: status = %08lx ", status));
        return FALSE;
    }

    return TRUE;
}