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) */
ULONG BlockId;
/* File version ? */
ULONG Version;
/* Update counter */
ULONG UpdateCounter1;
/* File version ? - same as Version */
ULONG VersionOld;
/* Update counter */
ULONG UpdateCounter2;
/* When this hive file was last modified */
FILETIME DateModified;

View file

@ -25,6 +25,7 @@
#endif
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
#define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
BOOLEAN CmiDoVerify = FALSE;
@ -36,9 +37,10 @@ CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
assert(Header);
RtlZeroMemory(Header, sizeof(HIVE_HEADER));
Header->BlockId = REG_HIVE_ID;
Header->UpdateCounter1 = 0;
Header->UpdateCounter2 = 0;
Header->DateModified.dwLowDateTime = 0;
Header->DateModified.dwHighDateTime = 0;
Header->Version = 1;
Header->Unused3 = 1;
Header->Unused4 = 3;
Header->Unused5 = 0;
@ -607,6 +609,8 @@ CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive,
return Status;
}
/* FIXME: Check hive header */
Status = NtQueryInformationFile(FileHandle,
&IoSB,
&fsi,
@ -882,33 +886,46 @@ CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
}
NTSTATUS
CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
static ULONG
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;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
LARGE_INTEGER FileOffset;
ULONG BlockIndex;
ULONG BlockOffset;
PVOID BlockPtr;
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);
DPRINT("CmiStartHiveUpdate() called\n");
/* Open hive for writing */
InitializeObjectAttributes(&ObjectAttributes,
@ -934,15 +951,41 @@ CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
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;
while (TRUE)
{
BlockIndex = RtlFindSetBitsAndClear(&RegistryHive->DirtyBitMap,
1,
BlockIndex);
BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1,
BlockIndex);
if (BlockIndex == (ULONG)-1)
{
DPRINT("No more set bits\n");
Status = STATUS_SUCCESS;
break;
}
@ -975,14 +1018,132 @@ CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
return(Status);
}
BlockIndex++;
}
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;
DPRINT("CmiFlushRegistryHive() done\n");
DPRINT1("CmiFlushRegistryHive() done\n");
return(STATUS_SUCCESS);
}
@ -2405,7 +2566,7 @@ CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
if (CellSize < 0)
CellSize = -CellSize;
BlockCount = 1;
BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
DPRINT1(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
BlockNumber,
@ -2413,7 +2574,6 @@ CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
(Cell->CellSize < 0) ? "used" : "free",
BlockCount);
RegistryHive->HiveDirty = TRUE;
RtlSetBits(&RegistryHive->DirtyBitMap,
BlockNumber,