Calculate hive header checksum.

Use update counters for hive flushing.
Invalidate more than one block if a cell crosses block boundaries.

svn path=/trunk/; revision=4149
This commit is contained in:
Eric Kohl 2003-02-14 23:01:06 +00:00
parent e8f191a72e
commit e028c60886
2 changed files with 193 additions and 33 deletions

View file

@ -63,11 +63,11 @@ typedef struct _HIVE_HEADER
/* Hive identifier "regf" (0x66676572) */ /* Hive identifier "regf" (0x66676572) */
ULONG BlockId; ULONG BlockId;
/* File version ? */ /* Update counter */
ULONG Version; ULONG UpdateCounter1;
/* File version ? - same as Version */ /* Update counter */
ULONG VersionOld; ULONG UpdateCounter2;
/* When this hive file was last modified */ /* When this hive file was last modified */
FILETIME DateModified; FILETIME DateModified;

View file

@ -25,6 +25,7 @@
#endif #endif
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
#define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
BOOLEAN CmiDoVerify = FALSE; BOOLEAN CmiDoVerify = FALSE;
@ -36,9 +37,10 @@ CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
assert(Header); assert(Header);
RtlZeroMemory(Header, sizeof(HIVE_HEADER)); RtlZeroMemory(Header, sizeof(HIVE_HEADER));
Header->BlockId = REG_HIVE_ID; Header->BlockId = REG_HIVE_ID;
Header->UpdateCounter1 = 0;
Header->UpdateCounter2 = 0;
Header->DateModified.dwLowDateTime = 0; Header->DateModified.dwLowDateTime = 0;
Header->DateModified.dwHighDateTime = 0; Header->DateModified.dwHighDateTime = 0;
Header->Version = 1;
Header->Unused3 = 1; Header->Unused3 = 1;
Header->Unused4 = 3; Header->Unused4 = 3;
Header->Unused5 = 0; Header->Unused5 = 0;
@ -607,6 +609,8 @@ CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive,
return Status; return Status;
} }
/* FIXME: Check hive header */
Status = NtQueryInformationFile(FileHandle, Status = NtQueryInformationFile(FileHandle,
&IoSB, &IoSB,
&fsi, &fsi,
@ -882,33 +886,46 @@ CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
} }
NTSTATUS static ULONG
CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive) CmiCalcChecksum(PULONG Buffer)
{
ULONG Sum = 0;
ULONG i;
for (i = 0; i < 127; i++)
Sum += Buffer[i];
return(Sum);
}
static NTSTATUS
CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
{
return(STATUS_SUCCESS);
}
static NTSTATUS
CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
{
return(STATUS_SUCCESS);
}
static NTSTATUS
CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
{ {
ULONG BlockIndex;
ULONG BlockOffset;
PVOID BlockPtr;
LARGE_INTEGER FileOffset;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle; HANDLE FileHandle;
LARGE_INTEGER FileOffset;
ULONG BlockIndex;
ULONG BlockOffset;
PVOID BlockPtr;
NTSTATUS Status; NTSTATUS Status;
DPRINT("CmiStartHiveUpdate() called\n");
DPRINT("CmiFlushRegistryHive() called\n");
if (RegistryHive->HiveDirty == FALSE)
{
return(STATUS_SUCCESS);
}
DPRINT1("Hive '%wZ' is dirty\n",
&RegistryHive->HiveFileName);
DPRINT1("Log file: '%wZ'\n",
&RegistryHive->LogFileName);
/* Open hive for writing */ /* Open hive for writing */
InitializeObjectAttributes(&ObjectAttributes, InitializeObjectAttributes(&ObjectAttributes,
@ -934,15 +951,41 @@ CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
return(Status); return(Status);
} }
/* Update hive header */
RegistryHive->HiveHeader->UpdateCounter1++;
NtQuerySystemTime((PTIME)&RegistryHive->HiveHeader->DateModified);
/* Update header checksum */
RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
/* Write hive block */
FileOffset.QuadPart = 0ULL;
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
RegistryHive->HiveHeader,
sizeof(HIVE_HEADER),
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
NtClose(FileHandle);
return(Status);
}
BlockIndex = 0; BlockIndex = 0;
while (TRUE) while (TRUE)
{ {
BlockIndex = RtlFindSetBitsAndClear(&RegistryHive->DirtyBitMap, BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1, 1,
BlockIndex); BlockIndex);
if (BlockIndex == (ULONG)-1) if (BlockIndex == (ULONG)-1)
{ {
DPRINT("No more set bits\n"); DPRINT("No more set bits\n");
Status = STATUS_SUCCESS;
break; break;
} }
@ -975,14 +1018,132 @@ CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
return(Status); return(Status);
} }
BlockIndex++;
} }
NtClose(FileHandle); NtClose(FileHandle);
/* Clear dirty flag */ return(Status);
}
static NTSTATUS
CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
HANDLE FileHandle;
NTSTATUS Status;
DPRINT1("CmiFinishHiveUpdate() called\n");
InitializeObjectAttributes(&ObjectAttributes,
&RegistryHive->HiveFileName,
0,
NULL,
NULL);
Status = NtCreateFile(&FileHandle,
FILE_ALL_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
return(Status);
}
/* Update hive header */
RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->HiveHeader->UpdateCounter1;
/* Update header checksum */
RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
/* Write hive block */
FileOffset.QuadPart = 0ULL;
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
RegistryHive->HiveHeader,
sizeof(HIVE_HEADER),
&FileOffset,
NULL);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
}
return(Status);
}
NTSTATUS
CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
{
NTSTATUS Status;
DPRINT("CmiFlushRegistryHive() called\n");
if (RegistryHive->HiveDirty == FALSE)
{
return(STATUS_SUCCESS);
}
DPRINT1("Hive '%wZ' is dirty\n",
&RegistryHive->HiveFileName);
DPRINT1("Log file: '%wZ'\n",
&RegistryHive->LogFileName);
/* Start log update */
Status = CmiStartLogUpdate(RegistryHive);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiStartLogUpdate() failed (Status %lx)\n", Status);
return(Status);
}
/* Finish log update */
Status = CmiFinishLogUpdate(RegistryHive);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
return(Status);
}
/* Start hive update */
Status = CmiStartHiveUpdate(RegistryHive);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
return(Status);
}
/* Finish the hive update */
Status = CmiFinishHiveUpdate(RegistryHive);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
return(Status);
}
/* Clear dirty bitmap and dirty flag */
RtlClearAllBits(&RegistryHive->DirtyBitMap);
RegistryHive->HiveDirty = FALSE; RegistryHive->HiveDirty = FALSE;
DPRINT("CmiFlushRegistryHive() done\n"); DPRINT1("CmiFlushRegistryHive() done\n");
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -2405,7 +2566,7 @@ CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
if (CellSize < 0) if (CellSize < 0)
CellSize = -CellSize; CellSize = -CellSize;
BlockCount = 1; BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
DPRINT1(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n", DPRINT1(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
BlockNumber, BlockNumber,
@ -2413,7 +2574,6 @@ CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
(Cell->CellSize < 0) ? "used" : "free", (Cell->CellSize < 0) ? "used" : "free",
BlockCount); BlockCount);
RegistryHive->HiveDirty = TRUE; RegistryHive->HiveDirty = TRUE;
RtlSetBits(&RegistryHive->DirtyBitMap, RtlSetBits(&RegistryHive->DirtyBitMap,
BlockNumber, BlockNumber,