예제 #1
0
NTSTATUS
HvInitializeHive(
    PHHIVE                  Hive,
    ULONG                   OperationType,
    ULONG                   HiveFlags,
    ULONG                   FileType,
    PVOID                   HiveData OPTIONAL,
    PALLOCATE_ROUTINE       AllocateRoutine,
    PFREE_ROUTINE           FreeRoutine,
    PFILE_SET_SIZE_ROUTINE  FileSetSizeRoutine,
    PFILE_WRITE_ROUTINE     FileWriteRoutine,
    PFILE_READ_ROUTINE      FileReadRoutine,
    PFILE_FLUSH_ROUTINE     FileFlushRoutine,
    ULONG                   Cluster,
    PUNICODE_STRING         FileName OPTIONAL
)
/*++

Routine Description:

    Initialize a hive.

    Core HHive fields are always initializeed.

    File calls WILL be made BEFORE this call returns.

    Caller is expected to create/open files and store file handles
    in a way that can be derived from the hive pointer.

    Three kinds of initialization can be done, selected by OperationType:

        HINIT_CREATE

            Create a new hive from scratch.  Will have 0 storage.
            [Used to do things like create HARDWARE hive and for parts
             of SaveKey and RestoreKey]


        HINIT_MEMORY_INPLACE

            Build a hive control structure which allows read only
            access to a contiguous in-memory image of a hive.
            No part of the image will be copied, but a map will
            be made.
            [Used by osloader.]


        HINIT_FLAT

            Support very limited (read-only, no checking code) operation
            against a hive image.


        HINIT_MEMORY

            Create a new hive, using a hive image already in memory,
            at address supplied by pointer HiveData.  The data will
            be copied.  Caller is expected to free HiveData.
            [Used for SYSTEM hive]


        HINIT_FILE

            Create a hive, reading its data from a file.  Recovery processing
            via log file will be done if a log is available.  If a log
            is recovered, flush and clear operation will proceed.


        HINIT_MAPFILE

            Create a hive, reading its data from a file.  Data reading is
            done by mapping views of the file in the system cache.


  NOTE:   The HHive is not a completely opaque structure, because it
            is really only used by a limited set of code.  Do not assume
            that only this routine sets all of these values.


Arguments:

    Hive - supplies a pointer to hive control structure to be initialized
            to describe this hive.

    OperationType - specifies whether to create a new hive from scratch,
            from a memory image, or by reading a file from disk.

    HiveFlags - HIVE_VOLATILE - Entire hive is to be volatile, regardless
                                   of the types of cells allocated
                HIVE_NO_LAZY_FLUSH - Data in this hive is never written
                                   to disk except by an explicit FlushKey

    FileType - HFILE_TYPE_*, HFILE_TYPE_LOG set up for logging support respectively.

    HiveData - if present, supplies a pointer to an in memory image of
            from which to init the hive.  Only useful when OperationType
            is set to HINIT_MEMORY.

    AllocateRoutine - supplies a pointer to routine called to allocate
                        memory.  WILL be called before this routine returns.

    FreeRoutine - supplies a pointer to routine called to free memory.
                   CAN be called before this routine returns.

    FileSetSizeRoutine - supplies a pointer to a routine used to set the
                         size of a file. CAN be called before this
                         routine returns.

    FileWriteRoutine - supplies a pointer to routine called to write memory
                        to a file.

    FileReadRoutine - supplies a pointer to routine called to read from
                        a file into memory. CAN be called before this
                        routine returns.

    FileFlushRoutine - supplies a pointer to routine called to flush a file.

    Cluster - clustering factor in HSECTOR_SIZE units.  (i.e.  Size of
            physical sector in media / HSECTOR_SIZE.  1 for 512 byte
            physical sectors (or smaller), 2 for 1024, 4 for 2048, etc.
            (Numbers greater than 8 won't work.)

    FileName - some path like "...\system32\config\system", last
                32 or so characters will be copied into baseblock
                (and thus to disk) as a debugging aid.  May be null.


Return Value:

    NTSTATUS code.

--*/
{
    BOOLEAN         UseForIo;
    PHBASE_BLOCK    BaseBlock = NULL;
    NTSTATUS        Status;
    ULONG           i;
    ULONG           Alignment;

    CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"HvInitializeHive:\n"));
    CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"\tHive=%p\n", Hive));

    //
    // reject invalid parameter combinations
    //
    if ( (! ARGUMENT_PRESENT(HiveData)) &&
            ((OperationType == HINIT_MEMORY) ||
             (OperationType == HINIT_FLAT) ||
             (OperationType == HINIT_MEMORY_INPLACE))
       )
    {
        return STATUS_INVALID_PARAMETER;
    }

    if ( ! ((OperationType == HINIT_CREATE) ||
            (OperationType == HINIT_MEMORY) ||
            (OperationType == HINIT_MEMORY_INPLACE) ||
            (OperationType == HINIT_FLAT) ||
            (OperationType == HINIT_FILE) ||
            (OperationType == HINIT_MAPFILE))
       )
    {
        return STATUS_INVALID_PARAMETER;
    }


    //
    // static and global control values
    //
    Hive->Signature = HHIVE_SIGNATURE;

    Hive->Allocate = AllocateRoutine;
    Hive->Free = FreeRoutine;
    Hive->FileSetSize = FileSetSizeRoutine;
    Hive->FileWrite = FileWriteRoutine;
    Hive->FileRead = FileReadRoutine;
    Hive->FileFlush = FileFlushRoutine;

    Hive->Log = (BOOLEAN)((FileType == HFILE_TYPE_LOG) ? TRUE : FALSE);

    if (Hive->Log  && (HiveFlags & HIVE_VOLATILE)) {
        return STATUS_INVALID_PARAMETER;
    }

    Hive->HiveFlags = HiveFlags;

    if ((Cluster == 0) || (Cluster > HSECTOR_COUNT)) {
        return STATUS_INVALID_PARAMETER;
    }
    Hive->Cluster = Cluster;

    Hive->RefreshCount = 0;

    Hive->StorageTypeCount = HTYPE_COUNT;


    Hive->Storage[Volatile].Length = 0;
    Hive->Storage[Volatile].Map = NULL;
    Hive->Storage[Volatile].SmallDir = NULL;
    Hive->Storage[Volatile].Guard = (ULONG)-1;
    Hive->Storage[Volatile].FreeSummary = 0;
    InitializeListHead(&Hive->Storage[Volatile].FreeBins);
    for (i = 0; i < HHIVE_FREE_DISPLAY_SIZE; i++) {
        RtlInitializeBitMap(&(Hive->Storage[Volatile].FreeDisplay[i].Display), NULL, 0);
        Hive->Storage[Volatile].FreeDisplay[i].RealVectorSize = 0;
    }

    Hive->Storage[Stable].Length = 0;
    Hive->Storage[Stable].Map = NULL;
    Hive->Storage[Stable].SmallDir = NULL;
    Hive->Storage[Stable].Guard = (ULONG)-1;
    Hive->Storage[Stable].FreeSummary = 0;
    InitializeListHead(&Hive->Storage[Stable].FreeBins);
    for (i = 0; i < HHIVE_FREE_DISPLAY_SIZE; i++) {
        RtlInitializeBitMap(&(Hive->Storage[Stable].FreeDisplay[i].Display), NULL, 0);
        Hive->Storage[Stable].FreeDisplay[i].RealVectorSize = 0;
    }

    RtlInitializeBitMap(&(Hive->DirtyVector), NULL, 0);
    Hive->DirtyCount = 0;
    Hive->DirtyAlloc = 0;
    Hive->DirtyFlag = FALSE;
    Hive->LogSize = 0;
    Hive->BaseBlockAlloc = sizeof(HBASE_BLOCK);

    Hive->GetCellRoutine = HvpGetCellPaged;
    Hive->ReleaseCellRoutine = NULL;
    Hive->Flat = FALSE;
    Hive->ReadOnly = FALSE;
    UseForIo = (BOOLEAN)!(Hive->HiveFlags & HIVE_VOLATILE);

    //
    // new create case
    //
    if (OperationType == HINIT_CREATE) {

        BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(Hive->BaseBlockAlloc, UseForIo,CM_FIND_LEAK_TAG11));
        if (BaseBlock == NULL) {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
        //
        // Make sure the buffer we got back is cluster-aligned. If not, try
        // harder to get an aligned buffer.
        //
        Alignment = Cluster * HSECTOR_SIZE - 1;
        if (((ULONG_PTR)BaseBlock & Alignment) != 0) {
            (Hive->Free)(BaseBlock, Hive->BaseBlockAlloc);
            BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE,CM_FIND_LEAK_TAG12));
            if (BaseBlock == NULL) {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            Hive->BaseBlockAlloc = PAGE_SIZE;
        }

        BaseBlock->Signature = HBASE_BLOCK_SIGNATURE;
        BaseBlock->Sequence1 = 1;
        BaseBlock->Sequence2 = 1;
        BaseBlock->TimeStamp.HighPart = 0;
        BaseBlock->TimeStamp.LowPart = 0;
        BaseBlock->Major = HSYS_MAJOR;
        BaseBlock->Minor = HSYS_MINOR;
        BaseBlock->Type = HFILE_TYPE_PRIMARY;
        BaseBlock->Format = HBASE_FORMAT_MEMORY;
        BaseBlock->RootCell = HCELL_NIL;
        BaseBlock->Length = 0;
        BaseBlock->Cluster = Cluster;
        BaseBlock->CheckSum = 0;
        HvpFillFileName(BaseBlock, FileName);
        Hive->BaseBlock = BaseBlock;
        Hive->Version = HSYS_MINOR;
        Hive->BaseBlock->BootType = 0;

        return STATUS_SUCCESS;
    }

    //
    // flat image case
    //
    if (OperationType == HINIT_FLAT) {
        Hive->BaseBlock = (PHBASE_BLOCK)HiveData;
        Hive->Version = Hive->BaseBlock->Minor;
        Hive->Flat = TRUE;
        Hive->ReadOnly = TRUE;
        Hive->GetCellRoutine = HvpGetCellFlat;
        Hive->Storage[Stable].Length = Hive->BaseBlock->Length;
        Hive->StorageTypeCount = 1;
        Hive->BaseBlock->BootType = 0;

        return STATUS_SUCCESS;
    }

    //
    // readonly image case
    //
    if (OperationType == HINIT_MEMORY_INPLACE) {
        BaseBlock = (PHBASE_BLOCK)HiveData;

        if ( (BaseBlock->Signature != HBASE_BLOCK_SIGNATURE)    ||
                (BaseBlock->Type != HFILE_TYPE_PRIMARY)            ||
                (BaseBlock->Major != HSYS_MAJOR)                   ||
                (BaseBlock->Minor > HSYS_MINOR_SUPPORTED)          ||
                (BaseBlock->Format != HBASE_FORMAT_MEMORY)         ||
                (BaseBlock->Sequence1 != BaseBlock->Sequence2)     ||
                (HvpHeaderCheckSum(BaseBlock) !=
                 (BaseBlock->CheckSum))
           )
        {
            return STATUS_REGISTRY_CORRUPT;
        }

        Hive->BaseBlock = BaseBlock;
        Hive->Version = BaseBlock->Minor;
        Hive->ReadOnly = TRUE;
        Hive->StorageTypeCount = 1;
        Hive->BaseBlock->BootType = 0;
        Status = HvpAdjustHiveFreeDisplay(Hive,BaseBlock->Length,Stable);
        if( !NT_SUCCESS(Status) ) {
            return Status;
        }

        if ( !NT_SUCCESS(HvpBuildMap(
                             Hive,
                             (PUCHAR)HiveData + HBLOCK_SIZE
                         )))
        {
            return STATUS_REGISTRY_CORRUPT;
        }

        return(STATUS_SUCCESS);
    }

    //
    // memory copy case
    //
    if (OperationType == HINIT_MEMORY) {
        BaseBlock = (PHBASE_BLOCK)HiveData;

        if ( (BaseBlock->Signature != HBASE_BLOCK_SIGNATURE)    ||
                (BaseBlock->Type != HFILE_TYPE_PRIMARY)            ||
                (BaseBlock->Format != HBASE_FORMAT_MEMORY)         ||
                (BaseBlock->Major != HSYS_MAJOR)                   ||
                (BaseBlock->Minor > HSYS_MINOR_SUPPORTED)          ||
                (HvpHeaderCheckSum(BaseBlock) !=
                 (BaseBlock->CheckSum))
           )
        {
            return STATUS_REGISTRY_CORRUPT;
        }

        Hive->BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(Hive->BaseBlockAlloc, UseForIo,CM_FIND_LEAK_TAG13));
        if (Hive->BaseBlock==NULL) {
            return(STATUS_INSUFFICIENT_RESOURCES);
        }
        //
        // Make sure the buffer we got back is cluster-aligned. If not, try
        // harder to get an aligned buffer.
        //
        Alignment = Cluster * HSECTOR_SIZE - 1;
        if (((ULONG_PTR)Hive->BaseBlock & Alignment) != 0) {
            (Hive->Free)(Hive->BaseBlock, Hive->BaseBlockAlloc);
            Hive->BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE,CM_FIND_LEAK_TAG14));
            if (Hive->BaseBlock == NULL) {
                return (STATUS_INSUFFICIENT_RESOURCES);
            }
            Hive->BaseBlockAlloc = PAGE_SIZE;
        }
        RtlCopyMemory(Hive->BaseBlock, BaseBlock, HSECTOR_SIZE);
        Hive->BaseBlock->BootRecover = BaseBlock->BootRecover;
        Hive->BaseBlock->BootType = BaseBlock->BootType;

        Hive->Version = Hive->BaseBlock->Minor;

        Status = HvpAdjustHiveFreeDisplay(Hive,BaseBlock->Length,Stable);
        if( !NT_SUCCESS(Status) ) {
            (Hive->Free)(Hive->BaseBlock, Hive->BaseBlockAlloc);
            Hive->BaseBlock = NULL;
            return Status;
        }

        if ( !NT_SUCCESS(HvpBuildMapAndCopy(Hive,
                                            (PUCHAR)HiveData + HBLOCK_SIZE))) {

            (Hive->Free)(Hive->BaseBlock, Hive->BaseBlockAlloc);
            Hive->BaseBlock = NULL;
            return STATUS_REGISTRY_CORRUPT;
        }

        HvpFillFileName(Hive->BaseBlock, FileName);


        return(STATUS_SUCCESS);
    }

    //
    // file read case
    //
    if (OperationType == HINIT_FILE) {

        CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvInitializeHive(%wZ,HINIT_FILE) :\n", FileName));
        //
        // get the file image (possible recovered via log) into memory
        //
        Status = HvLoadHive(Hive);
        if ((Status != STATUS_SUCCESS) && (Status != STATUS_REGISTRY_RECOVERED)) {
            return Status;
        }

        CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"\n"));

        if (Status == STATUS_REGISTRY_RECOVERED) {

            //
            // We have a good hive, with a log, and a dirty map,
            // all set up.  Only problem is that we need to flush
            // the file so the log can be cleared and new writes
            // posted against the hive.  Since we know we have
            // a good log in hand, we just write the hive image.
            //
            if ( ! HvpDoWriteHive(Hive, HFILE_TYPE_PRIMARY)) {
                //
                // Clean up the bins already allocated
                //
                HvpFreeAllocatedBins( Hive );

                return STATUS_REGISTRY_IO_FAILED;
            }

            //
            // If we get here, we have recovered the hive, and
            // written it out to disk correctly.  So we clear
            // the log here.
            //
            RtlClearAllBits(&(Hive->DirtyVector));
            Hive->DirtyCount = 0;
            (Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, 0,0);
            Hive->LogSize = 0;
        }

        //
        // slam debug name data into base block
        //
        HvpFillFileName(Hive->BaseBlock, FileName);

        return STATUS_SUCCESS;
    }

    //
    // file map case
    //
    if (OperationType == HINIT_MAPFILE) {

        Hive->GetCellRoutine = HvpGetCellMapped;
        Hive->ReleaseCellRoutine = HvpReleaseCellMapped;

        CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvInitializeHive(%wZ,HINIT_MAPFILE) :\n", FileName));

        Status = HvMapHive(Hive);
        if ((Status != STATUS_SUCCESS) && (Status != STATUS_REGISTRY_RECOVERED)) {
            return Status;
        }

        CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"\n"));

        if (Status == STATUS_REGISTRY_RECOVERED) {

            //
            // We have a good hive, with a log, and a dirty map,
            // all set up.  Only problem is that we need to flush
            // the file so the log can be cleared and new writes
            // posted against the hive.  Since we know we have
            // a good log in hand, we just write the hive image.
            //
            if ( ! HvpDoWriteHive(Hive, HFILE_TYPE_PRIMARY)) {
                //
                // Clean up the bins already allocated
                //
                HvpFreeAllocatedBins( Hive );

                return STATUS_REGISTRY_IO_FAILED;
            }

            //
            // If we get here, we have recovered the hive, and
            // written it out to disk correctly.  So we clear
            // the log here.
            //
            RtlClearAllBits(&(Hive->DirtyVector));
            Hive->DirtyCount = 0;
            (Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, 0,0);
            Hive->LogSize = 0;
        }

        //
        // slam debug name data into base block
        //
        HvpFillFileName(Hive->BaseBlock, FileName);

        return STATUS_SUCCESS;
    }

    return STATUS_INVALID_PARAMETER;
}
예제 #2
0
파일: hiveinit.c 프로젝트: Strongc/reactos
NTSTATUS CMAPI
HvInitialize(
   PHHIVE RegistryHive,
   ULONG Operation,
   ULONG HiveType,
   ULONG HiveFlags,
   PVOID HiveData OPTIONAL,
   PALLOCATE_ROUTINE Allocate,
   PFREE_ROUTINE Free,
   PFILE_SET_SIZE_ROUTINE FileSetSize,
   PFILE_WRITE_ROUTINE FileWrite,
   PFILE_READ_ROUTINE FileRead,
   PFILE_FLUSH_ROUTINE FileFlush,
   ULONG Cluster OPTIONAL,
   PCUNICODE_STRING FileName OPTIONAL)
{
   NTSTATUS Status;
   PHHIVE Hive = RegistryHive;

   UNREFERENCED_PARAMETER(HiveType);

   /*
    * Create a new hive structure that will hold all the maintenance data.
    */

   RtlZeroMemory(Hive, sizeof(HHIVE));

   Hive->Allocate = Allocate;
   Hive->Free = Free;
   Hive->FileRead = FileRead;
   Hive->FileWrite = FileWrite;
   Hive->FileSetSize = FileSetSize;
   Hive->FileFlush = FileFlush;
   Hive->StorageTypeCount = HTYPE_COUNT;
   Hive->Cluster = 1;
   Hive->Version = HSYS_MINOR;
   Hive->HiveFlags = HiveFlags &~ HIVE_NOLAZYFLUSH;

   switch (Operation)
   {
      case HINIT_CREATE:
         Status = HvpCreateHive(Hive, FileName);
         break;

      case HINIT_MEMORY:
         Status = HvpInitializeMemoryHive(Hive, HiveData);
         break;

      case HINIT_FLAT:
         Status = HvpInitializeMemoryInplaceHive(Hive, HiveData);
         break;

      case HINIT_FILE:
      {
         /* HACK of doom: Cluster is actually the file size. */
         Status = HvLoadHive(Hive, Cluster);
         if ((Status != STATUS_SUCCESS) &&
             (Status != STATUS_REGISTRY_RECOVERED))
         {
             /* Unrecoverable failure */
             return Status;
         }

         /* Check for previous damage */
         ASSERT(Status != STATUS_REGISTRY_RECOVERED);
         break;
     }

      default:
         /* FIXME: A better return status value is needed */
         Status = STATUS_NOT_IMPLEMENTED;
         ASSERT(FALSE);
   }

   if (!NT_SUCCESS(Status)) return Status;

   if (Operation != HINIT_CREATE) CmPrepareHive(Hive);

   return Status;
}