Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

hiveload.c File Reference

#include "cmp.h"

Go to the source code of this file.

Defines

#define IO_BUFFER_SIZE   0x10000

Typedefs

typedef enum _RESULT RESULT

Enumerations

enum  _RESULT {
  NotHive, Fail, NoMemory, HiveSuccess,
  RecoverHeader, RecoverData
}

Functions

RESULT HvpGetHiveHeader (PHHIVE Hive, PHBASE_BLOCK *BaseBlock, PLARGE_INTEGER TimeStamp)
RESULT HvpGetLogHeader (PHHIVE Hive, PHBASE_BLOCK *BaseBlock, PLARGE_INTEGER TimeStamp)
RESULT HvpRecoverData (PHHIVE Hive, BOOLEAN ReadOnly, PHCELL_INDEX TailDisplay OPTIONAL)
NTSTATUS HvpReadFileImageAndBuildMap (PHHIVE Hive, ULONG Length, PHCELL_INDEX TailDisplay OPTIONAL)
VOID HvpDelistBinFreeCells (PHHIVE Hive, PHBIN Bin, HSTORAGE_TYPE Type, PHCELL_INDEX TailDisplay OPTIONAL)
NTSTATUS HvLoadHive (PHHIVE Hive, PHCELL_INDEX TailDisplay OPTIONAL)

Variables

struct {
   PHHIVE   Hive
   ULONG   Status
   ULONG   Space
   HCELL_INDEX   MapPoint
   PHBIN   BinPoint
HvCheckHiveDebug


Define Documentation

#define IO_BUFFER_SIZE   0x10000
 

Definition at line 34 of file hiveload.c.

Referenced by HvpReadFileImageAndBuildMap().


Typedef Documentation

typedef enum _RESULT RESULT
 


Enumeration Type Documentation

enum _RESULT
 

Enumeration values:
NotHive 
Fail 
NoMemory 
HiveSuccess 
RecoverHeader 
RecoverData 

Definition at line 36 of file hiveload.c.

00036 { 00037 NotHive, 00038 Fail, 00039 NoMemory, 00040 HiveSuccess, 00041 RecoverHeader, 00042 RecoverData 00043 } RESULT;


Function Documentation

NTSTATUS HvLoadHive PHHIVE  Hive,
PHCELL_INDEX TailDisplay  OPTIONAL
 

Definition at line 100 of file hiveload.c.

References ASSERT, _HHIVE::BaseBlock, _HHIVE::DirtyCount, Fail, FALSE, _HHIVE::Free, HFILE_TYPE_PRIMARY, HHIVE_SIGNATURE, Hive, HvpCleanMap(), HvpFreeAllocatedBins(), HvpGetHiveHeader(), HvpGetLogHeader(), HvpReadFileImageAndBuildMap(), HvpRecoverData(), _HBASE_BLOCK::Length, _HHIVE::Log, _HBASE_BLOCK::Minor, NoMemory, NotHive, NT_SUCCESS, NTSTATUS(), NULL, _HHIVE::ReadOnly, RecoverData, RecoverHeader, _HBASE_BLOCK::Sequence1, _HBASE_BLOCK::Sequence2, _HHIVE::Signature, TRUE, _HBASE_BLOCK::Type, and _HHIVE::Version.

Referenced by HvInitializeHive().

00106 : 00107 00108 Hive must be fully initialized, in particular, file handles 00109 must be set up. This routine is not intended for loading hives 00110 from images already in memory. 00111 00112 This routine will apply whatever fixes are available for errors 00113 in the hive image. In particular, if a log exists, and is applicable, 00114 this routine will automatically apply it. 00115 00116 ALGORITHM: 00117 00118 call HvpGetHiveHeader() 00119 00120 if (NoMemory or NoHive) 00121 return failure 00122 00123 if (RecoverData or RecoverHeader) and (no log) 00124 return falure 00125 00126 if (RecoverHeader) 00127 call HvpGetLogHeader 00128 if (fail) 00129 return failure 00130 fix up baseblock 00131 00132 Read Data 00133 00134 if (RecoverData or RecoverHeader) 00135 HvpRecoverData 00136 return STATUS_REGISTRY_RECOVERED 00137 00138 clean up sequence numbers 00139 00140 return success OR STATUS_REGISTRY_RECOVERED 00141 00142 If STATUS_REGISTRY_RECOVERED is returned, then 00143 00144 If (Log) was used, DirtyVector and DirtyCount are set, 00145 caller is expected to flush the changes (using a 00146 NEW log file) 00147 00148 Arguments: 00149 00150 Hive - supplies a pointer to the hive control structure for the 00151 hive of interest 00152 00153 TailDisplay - array containing the tail ends of the free cell lists - optional 00154 00155 Return Value: 00156 00157 STATUS: 00158 00159 STATUS_INSUFFICIENT_RESOURCES - memory alloc failure, etc 00160 STATUS_NOT_REGISTRY_FILE - bad signatures and the like 00161 STATUS_REGISTRY_CORRUPT - bad signatures in the log, 00162 bad stuff in both in alternate, 00163 inconsistent log 00164 00165 STATUS_REGISTRY_IO_FAILED - data read failed 00166 00167 STATUS_RECOVERED - successfully recovered the hive, 00168 a semi-flush of logged data 00169 is necessary. 00170 00171 STATUS_SUCCESS - it worked, no recovery needed 00172 00173 --*/ 00174 { 00175 PHBASE_BLOCK BaseBlock; 00176 ULONG result1; 00177 ULONG result2; 00178 NTSTATUS status; 00179 LARGE_INTEGER TimeStamp; 00180 ULONG FileOffset; 00181 PHBIN pbin; 00182 BOOLEAN ReadOnlyFlagCopy; 00183 00184 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 00185 00186 BaseBlock = NULL; 00187 result1 = HvpGetHiveHeader(Hive, &BaseBlock, &TimeStamp); 00188 00189 // 00190 // bomb out for total errors 00191 // 00192 if (result1 == NoMemory) { 00193 status = STATUS_INSUFFICIENT_RESOURCES; 00194 goto Exit1; 00195 } 00196 if (result1 == NotHive) { 00197 status = STATUS_NOT_REGISTRY_FILE; 00198 goto Exit1; 00199 } 00200 00201 00202 ReadOnlyFlagCopy = Hive->ReadOnly; 00203 // 00204 // if recovery needed, and no log, bomb out 00205 // 00206 if ( ((result1 == RecoverData) || 00207 (result1 == RecoverHeader)) ) 00208 { 00209 // 00210 // recovery needed 00211 // 00212 if(Hive->Log == FALSE) 00213 { 00214 // 00215 // no log ==> bomb out 00216 // 00217 status = STATUS_REGISTRY_CORRUPT; 00218 goto Exit1; 00219 } else { 00220 // 00221 // TRICK: simulate hive as read-only; Free cells will not 00222 // be enlisted in HvpReadFileImageAndBuildMap; Instead, they 00223 // will be enlisted in HvpRecoverData, when we are sure we have 00224 // the right info loaded up into memory 00225 // 00226 Hive->ReadOnly = TRUE; 00227 } 00228 } 00229 00230 // 00231 // need to recover header using log, so try to get it from log 00232 // 00233 if (result1 == RecoverHeader) { 00234 result2 = HvpGetLogHeader(Hive, &BaseBlock, &TimeStamp); 00235 if (result2 == NoMemory) { 00236 status = STATUS_INSUFFICIENT_RESOURCES; 00237 goto Exit1; 00238 } 00239 if (result2 == Fail) { 00240 status = STATUS_REGISTRY_CORRUPT; 00241 goto Exit1; 00242 } 00243 BaseBlock->Type = HFILE_TYPE_PRIMARY; 00244 } 00245 Hive->BaseBlock = BaseBlock; 00246 Hive->Version = Hive->BaseBlock->Minor; 00247 00248 // 00249 // at this point, we have a sane baseblock. we may or may not still 00250 // need to apply data recovery 00251 // 00252 status = HvpReadFileImageAndBuildMap(Hive,BaseBlock->Length,TailDisplay); 00253 00254 00255 // 00256 // if STATUS_REGISTRY_CORRUPT and RecoverData don't bail out, keep recovering 00257 // 00258 if( !NT_SUCCESS(status) && ((status != STATUS_REGISTRY_CORRUPT) || (result1 != RecoverData)) ) { 00259 goto Exit2; 00260 } 00261 00262 // 00263 // apply data recovery if we need it 00264 // 00265 status = STATUS_SUCCESS; 00266 if ( (result1 == RecoverHeader) || // -> implies recover data 00267 (result1 == RecoverData) ) 00268 { 00269 // 00270 // recover data will enllist the free cells as well and 00271 // will restore the original read-only state of the hive 00272 // 00273 result2 = HvpRecoverData(Hive,ReadOnlyFlagCopy,TailDisplay); 00274 if (result2 == NoMemory) { 00275 status = STATUS_INSUFFICIENT_RESOURCES; 00276 goto Exit2; 00277 } 00278 if (result2 == Fail) { 00279 status = STATUS_REGISTRY_CORRUPT; 00280 goto Exit2; 00281 } 00282 status = STATUS_REGISTRY_RECOVERED; 00283 } 00284 00285 BaseBlock->Sequence2 = BaseBlock->Sequence1; 00286 return status; 00287 00288 00289 Exit2: 00290 // 00291 // Clean up the bins already allocated 00292 // 00293 HvpFreeAllocatedBins( Hive ); 00294 00295 // 00296 // Clean up the directory table 00297 // 00298 HvpCleanMap( Hive ); 00299 00300 Exit1: 00301 if (BaseBlock != NULL) { 00302 (Hive->Free)(BaseBlock, sizeof(HBASE_BLOCK)); 00303 } 00304 00305 Hive->BaseBlock = NULL; 00306 Hive->DirtyCount = 0; 00307 return status; 00308 }

VOID HvpDelistBinFreeCells PHHIVE  Hive,
PHBIN  Bin,
HSTORAGE_TYPE  Type,
PHCELL_INDEX TailDisplay  OPTIONAL
 

RESULT HvpGetHiveHeader PHHIVE  Hive,
PHBASE_BLOCK BaseBlock,
PLARGE_INTEGER  TimeStamp
 

Definition at line 592 of file hiveload.c.

References _HHIVE::Allocate, ASSERT, _HHIVE::Cluster, FALSE, _HHIVE::FileRead, _HHIVE::Free, HBASE_BLOCK, HBASE_BLOCK_SIGNATURE, HBASE_FORMAT_MEMORY, HBIN_SIGNATURE, HBLOCK_SIZE, HFILE_TYPE_PRIMARY, Hive, HiveSuccess, HSECTOR_SIZE, HSYS_MAJOR, HSYS_MINOR, HvpHeaderCheckSum(), NoMemory, NotHive, NULL, PAGE_SIZE, RecoverData, RecoverHeader, _HBASE_BLOCK::TimeStamp, and TRUE.

Referenced by HvLoadHive().

00599 : 00600 00601 Examine the base block sector and possibly the first sector of 00602 the first bin, and decide what (if any) recovery needs to be applied 00603 based on what we find there. 00604 00605 ALGORITHM: 00606 00607 read BaseBlock from offset 0 00608 if ( (I/O error) OR 00609 (checksum wrong) ) 00610 { 00611 read bin block from offset HBLOCK_SIZE (4k) 00612 if (2nd I/O error) 00613 return NotHive 00614 } 00615 check bin sign., offset. 00616 if (OK) 00617 return RecoverHeader, TimeStamp=from Link field 00618 } else { 00619 return NotHive 00620 } 00621 } 00622 00623 if (wrong type or signature or version or format) 00624 return NotHive 00625 } 00626 00627 if (seq1 != seq2) { 00628 return RecoverData, TimeStamp=BaseBlock->TimeStamp, valid BaseBlock 00629 } 00630 00631 return ReadData, valid BaseBlock 00632 00633 Arguments: 00634 00635 Hive - supplies a pointer to the hive control structure for the 00636 hive of interest 00637 00638 FileType - HFILE_TYPE_PRIMARY or HFILE_TYPE_ALTERNATE - which copy 00639 of the hive to read from. 00640 00641 BaseBlock - supplies pointer to variable to receive pointer to 00642 HBASE_BLOCK, if we can successfully read one. 00643 00644 TimeStamp - pointer to variable to receive time stamp (serial number) 00645 of hive, be it from the baseblock or from the Link field 00646 of the first bin. 00647 00648 Return Value: 00649 00650 RESULT code 00651 00652 --*/ 00653 { 00654 PHBASE_BLOCK buffer; 00655 BOOLEAN rc; 00656 ULONG FileOffset; 00657 ULONG Alignment; 00658 00659 ASSERT(sizeof(HBASE_BLOCK) >= (HSECTOR_SIZE * Hive->Cluster)); 00660 00661 // 00662 // allocate buffer to hold base block 00663 // 00664 *BaseBlock = NULL; 00665 buffer = (PHBASE_BLOCK)((Hive->Allocate)(sizeof(HBASE_BLOCK), TRUE)); 00666 if (buffer == NULL) { 00667 return NoMemory; 00668 } 00669 // 00670 // Make sure the buffer we got back is cluster-aligned. If not, try 00671 // harder to get an aligned buffer. 00672 // 00673 Alignment = Hive->Cluster * HSECTOR_SIZE - 1; 00674 if (((ULONG_PTR)buffer & Alignment) != 0) { 00675 (Hive->Free)(buffer, sizeof(HBASE_BLOCK)); 00676 buffer = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE)); 00677 if (buffer == NULL) { 00678 return NoMemory; 00679 } 00680 } 00681 RtlZeroMemory((PVOID)buffer, sizeof(HBASE_BLOCK)); 00682 00683 // 00684 // attempt to read base block 00685 // 00686 FileOffset = 0; 00687 rc = (Hive->FileRead)(Hive, 00688 HFILE_TYPE_PRIMARY, 00689 &FileOffset, 00690 (PVOID)buffer, 00691 HSECTOR_SIZE * Hive->Cluster); 00692 00693 if ( (rc == FALSE) || 00694 (HvpHeaderCheckSum(buffer) != buffer->CheckSum)) { 00695 // 00696 // base block is toast, try the first block in the first bin 00697 // 00698 FileOffset = HBLOCK_SIZE; 00699 rc = (Hive->FileRead)(Hive, 00700 HFILE_TYPE_PRIMARY, 00701 &FileOffset, 00702 (PVOID)buffer, 00703 HSECTOR_SIZE * Hive->Cluster); 00704 00705 if ( (rc == FALSE) || 00706 ( ((PHBIN)buffer)->Signature != HBIN_SIGNATURE) || 00707 ( ((PHBIN)buffer)->FileOffset != 0) 00708 ) 00709 { 00710 // 00711 // the bin is toast too, punt 00712 // 00713 (Hive->Free)(buffer, sizeof(HBASE_BLOCK)); 00714 return NotHive; 00715 } 00716 00717 // 00718 // base block is bogus, but bin is OK, so tell caller 00719 // to look for a log file and apply recovery 00720 // 00721 *TimeStamp = ((PHBIN)buffer)->TimeStamp; 00722 (Hive->Free)(buffer, sizeof(HBASE_BLOCK)); 00723 return RecoverHeader; 00724 } 00725 00726 // 00727 // base block read OK, but is it valid? 00728 // 00729 if ( (buffer->Signature != HBASE_BLOCK_SIGNATURE) || 00730 (buffer->Type != HFILE_TYPE_PRIMARY) || 00731 (buffer->Major != HSYS_MAJOR) || 00732 (buffer->Minor > HSYS_MINOR) || 00733 ((buffer->Major == 1) && (buffer->Minor == 0)) || 00734 (buffer->Format != HBASE_FORMAT_MEMORY) 00735 ) 00736 { 00737 // 00738 // file is simply not a valid hive 00739 // 00740 (Hive->Free)(buffer, sizeof(HBASE_BLOCK)); 00741 return NotHive; 00742 } 00743 00744 // 00745 // see if recovery is necessary 00746 // 00747 *BaseBlock = buffer; 00748 *TimeStamp = buffer->TimeStamp; 00749 if ( (buffer->Sequence1 != buffer->Sequence2) ) { 00750 return RecoverData; 00751 } 00752 00753 return HiveSuccess; 00754 }

RESULT HvpGetLogHeader PHHIVE  Hive,
PHBASE_BLOCK BaseBlock,
PLARGE_INTEGER  TimeStamp
 

Definition at line 758 of file hiveload.c.

References _HHIVE::Allocate, ASSERT, _HHIVE::Cluster, Fail, FALSE, _HHIVE::FileRead, _HHIVE::Free, HBASE_BLOCK, HBASE_BLOCK_SIGNATURE, HBLOCK_SIZE, HFILE_TYPE_LOG, Hive, HiveSuccess, HSECTOR_SIZE, HvpHeaderCheckSum(), NoMemory, NULL, and TRUE.

Referenced by HvLoadHive().

00765 : 00766 00767 Read and validate log file header. Return it if it's valid. 00768 00769 ALGORITHM: 00770 00771 read header 00772 if ( (I/O error) or 00773 (wrong signature, 00774 wrong type, 00775 seq mismatch 00776 wrong checksum, 00777 wrong timestamp 00778 ) 00779 return Fail 00780 } 00781 return baseblock, OK 00782 00783 Arguments: 00784 00785 Hive - supplies a pointer to the hive control structure for the 00786 hive of interest 00787 00788 BaseBlock - supplies pointer to variable to receive pointer to 00789 HBASE_BLOCK, if we can successfully read one. 00790 00791 TimeStamp - pointer to variable holding TimeStamp, which must 00792 match the one in the log file. 00793 00794 Return Value: 00795 00796 RESULT 00797 00798 --*/ 00799 { 00800 PHBASE_BLOCK buffer; 00801 BOOLEAN rc; 00802 ULONG FileOffset; 00803 00804 ASSERT(sizeof(HBASE_BLOCK) == HBLOCK_SIZE); 00805 ASSERT(sizeof(HBASE_BLOCK) >= (HSECTOR_SIZE * Hive->Cluster)); 00806 00807 // 00808 // allocate buffer to hold base block 00809 // 00810 *BaseBlock = NULL; 00811 buffer = (PHBASE_BLOCK)((Hive->Allocate)(sizeof(HBASE_BLOCK), TRUE)); 00812 if (buffer == NULL) { 00813 return NoMemory; 00814 } 00815 RtlZeroMemory((PVOID)buffer, HSECTOR_SIZE); 00816 00817 // 00818 // attempt to read base block 00819 // 00820 FileOffset = 0; 00821 rc = (Hive->FileRead)(Hive, 00822 HFILE_TYPE_LOG, 00823 &FileOffset, 00824 (PVOID)buffer, 00825 HSECTOR_SIZE * Hive->Cluster); 00826 00827 if ( (rc == FALSE) || 00828 (buffer->Signature != HBASE_BLOCK_SIGNATURE) || 00829 (buffer->Type != HFILE_TYPE_LOG) || 00830 (buffer->Sequence1 != buffer->Sequence2) || 00831 (HvpHeaderCheckSum(buffer) != buffer->CheckSum) || 00832 (TimeStamp->LowPart != buffer->TimeStamp.LowPart) || 00833 (TimeStamp->HighPart != buffer->TimeStamp.HighPart)) { 00834 // 00835 // Log is unreadable, invalid, or doesn't apply the right hive 00836 // 00837 (Hive->Free)(buffer, sizeof(HBASE_BLOCK)); 00838 return Fail; 00839 } 00840 00841 *BaseBlock = buffer; 00842 return HiveSuccess; 00843 }

NTSTATUS HvpReadFileImageAndBuildMap PHHIVE  Hive,
ULONG  Length,
PHCELL_INDEX TailDisplay  OPTIONAL
 

Definition at line 311 of file hiveload.c.

References _HHIVE::Allocate, ASSERT, Bin, ErrorExit(), ExAllocatePool, ExFreePool(), _HBIN::FileOffset, _HHIVE::FileRead, HBIN_SIGNATURE, HBLOCK_SIZE, HFILE_TYPE_PRIMARY, Hive, HvCheckHiveDebug, HvpCleanMap(), HvpEnlistBinInMap(), HvpInitMap(), IO_BUFFER_SIZE, NT_SUCCESS, NTSTATUS(), NULL, PagedPool, _HBIN::Signature, _HBIN::Size, Status, and TRUE.

Referenced by HvLoadHive().

00319 : 00320 00321 Read the hive from the file and allocate storage for the hive 00322 image in chunks of HBINs. Build the hive map "on the fly". 00323 Optimized to read chunks of 64K from the file. 00324 00325 Arguments: 00326 00327 Hive - supplies a pointer to the hive control structure for the 00328 hive of interest 00329 00330 Length - the length of the hive, in bytes 00331 00332 TailDisplay - array containing the tail ends of the free cell lists - optional 00333 00334 Return Value: 00335 00336 STATUS: 00337 00338 STATUS_INSUFFICIENT_RESOURCES - memory alloc failure, etc 00339 00340 STATUS_REGISTRY_IO_FAILED - data read failed 00341 00342 STATUS_REGISTRY_CORRUPT - base block is corrupt 00343 00344 STATUS_SUCCESS - it worked 00345 00346 --*/ 00347 { 00348 ULONG FileOffset; 00349 NTSTATUS Status = STATUS_SUCCESS; 00350 PHBIN Bin; // current bin 00351 ULONG BinSize; // size of the current bin 00352 ULONG BinOffset; // current offset inside current bin 00353 ULONG BinFileOffset; // physical offset of the bin in the file (used for consistency checking) 00354 ULONG BinDataInBuffer;// the amount of data needed to be copied in the current bin available in the buffer 00355 ULONG BinDataNeeded; // 00356 PUCHAR IOBuffer; 00357 ULONG IOBufferSize; // valid data in IOBuffer (only at the end of the file this is different than IO_BUFFER_SIZE) 00358 ULONG IOBufferOffset; // current offset inside IOBuffer 00359 00360 // 00361 // Init the map 00362 // 00363 Status = HvpInitMap(Hive); 00364 00365 if( !NT_SUCCESS(Status) ) { 00366 // 00367 // return failure 00368 // 00369 return Status; 00370 } 00371 00372 // 00373 // Allocate a IO_BUFFER_SIZE for I/O operations from paged pool. 00374 // It will be freed at the end of the function. 00375 // 00376 IOBuffer = (PUCHAR)ExAllocatePool(PagedPool, IO_BUFFER_SIZE); 00377 if (IOBuffer == NULL) { 00378 Status = STATUS_INSUFFICIENT_RESOURCES; 00379 HvpCleanMap( Hive ); 00380 return Status; 00381 } 00382 00383 // 00384 // Start right after the hive header 00385 // 00386 FileOffset = HBLOCK_SIZE; 00387 BinFileOffset = FileOffset; 00388 Bin = NULL; 00389 00390 // 00391 // outer loop : reads IO_BUFFER_SIZE chunks from the file 00392 // 00393 while( FileOffset < (Length + HBLOCK_SIZE) ) { 00394 // 00395 // we are at the begining of the IO buffer 00396 // 00397 IOBufferOffset = 0; 00398 00399 // 00400 // the buffer size will be either IO_BufferSize, or the amount 00401 // uread from the file (when this is smaller than IO_BUFFER_SIZE) 00402 // 00403 IOBufferSize = Length + HBLOCK_SIZE - FileOffset; 00404 IOBufferSize = ( IOBufferSize > IO_BUFFER_SIZE ) ? IO_BUFFER_SIZE : IOBufferSize; 00405 00406 ASSERT( (IOBufferSize % HBLOCK_SIZE) == 0 ); 00407 00408 // 00409 // read data from the file 00410 // 00411 if ( ! (Hive->FileRead)( 00412 Hive, 00413 HFILE_TYPE_PRIMARY, 00414 &FileOffset, 00415 (PVOID)IOBuffer, 00416 IOBufferSize 00417 ) 00418 ) 00419 { 00420 Status = STATUS_REGISTRY_IO_FAILED; 00421 goto ErrorExit; 00422 } 00423 00424 // 00425 // inner loop: breaks the buffer into bins 00426 // 00427 while( IOBufferOffset < IOBufferSize ) { 00428 00429 if( Bin == NULL ) { 00430 // 00431 // this is the beginning of a new bin 00432 // perform bin validation and allocate the bin 00433 // 00434 // temporary bin points to the current location inside the buffer 00435 Bin = (PHBIN)(IOBuffer + IOBufferOffset); 00436 // 00437 // Check the validity of the bin header 00438 // 00439 BinSize = Bin->Size; 00440 if ( (BinSize > Length) || 00441 (BinSize < HBLOCK_SIZE) || 00442 (Bin->Signature != HBIN_SIGNATURE) || 00443 (Bin->FileOffset != (BinFileOffset - HBLOCK_SIZE) )) { 00444 // 00445 // Bin is bogus 00446 // 00447 Bin = (PHBIN)(Hive->Allocate)(HBLOCK_SIZE, TRUE); 00448 if (Bin == NULL) { 00449 Status = STATUS_INSUFFICIENT_RESOURCES; 00450 goto ErrorExit; 00451 } 00452 // 00453 // copy the data already read in the first HBLOCK of the bin 00454 // 00455 RtlCopyMemory(Bin,(IOBuffer + IOBufferOffset), HBLOCK_SIZE); 00456 00457 Status = STATUS_REGISTRY_CORRUPT; 00458 HvCheckHiveDebug.Hive = Hive; 00459 HvCheckHiveDebug.Status = 0xA001; 00460 HvCheckHiveDebug.Space = Length; 00461 HvCheckHiveDebug.MapPoint = BinFileOffset; 00462 HvCheckHiveDebug.BinPoint = Bin; 00463 00464 //goto ErrorExit; 00465 // 00466 // DO NOT EXIT; Fix this bin header and go on. RecoverData should fix it. 00467 // If not, CmCheckRegistry called later will prevent loading of an invalid hive 00468 // 00469 // NOTE: Still, mess the signature, to make sure that if this particular bin doesn't get recovered, 00470 // we'll fail the hive loading request. 00471 // 00472 Bin->Signature = 0; //TRICK!!!! 00473 BinSize = Bin->Size = HBLOCK_SIZE; 00474 Bin->FileOffset = BinFileOffset - HBLOCK_SIZE; 00475 00476 // 00477 // simulate as the entire bin is a used cell 00478 // 00479 ((PHCELL)((PUCHAR)Bin + sizeof(HBIN)))->Size = sizeof(HBIN) - BinSize; //TRICK!!!! 00480 // 00481 // Now that we have the entire bin in memory, Enlist It! 00482 // 00483 Status = HvpEnlistBinInMap(Hive, Length, Bin, BinFileOffset - HBLOCK_SIZE, TailDisplay); 00484 00485 if( !NT_SUCCESS(Status) ) { 00486 goto ErrorExit; 00487 } 00488 00489 // 00490 // Adjust the offsets 00491 // 00492 BinFileOffset += Bin->Size; 00493 IOBufferOffset += Bin->Size; 00494 00495 // 00496 // another bin is on his way 00497 // 00498 Bin = NULL; 00499 } else { 00500 // 00501 // bin is valid; allocate a pool chunk of the right size 00502 // 00503 Bin = (PHBIN)(Hive->Allocate)(BinSize, TRUE); 00504 if (Bin == NULL) { 00505 Status = STATUS_INSUFFICIENT_RESOURCES; 00506 goto ErrorExit; 00507 } 00508 00509 // 00510 // the chunk is allocated; set the offset inside the bin and continue 00511 // the next iteration of the inner loop will start by copying data in this bin 00512 // 00513 BinOffset = 0; 00514 } 00515 } else { 00516 // 00517 // if we are here, the bin is allocated, the BinSize and BinOffset are set 00518 // We have to calculate how much for this bin is available in the buffer, 00519 // and copy it. If we finished with this bin, enlist it and mark the begining of a new one 00520 // 00521 ASSERT( Bin != NULL ); 00522 BinDataInBuffer = (IOBufferSize - IOBufferOffset); 00523 BinDataNeeded = (BinSize - BinOffset); 00524 00525 if( BinDataInBuffer >= BinDataNeeded ) { 00526 // 00527 // we have available more than what we need; Finish the bin 00528 // 00529 RtlCopyMemory(((PUCHAR)Bin + BinOffset),(IOBuffer + IOBufferOffset), BinDataNeeded); 00530 // 00531 // enlist it 00532 // 00533 Status = HvpEnlistBinInMap(Hive, Length, Bin, BinFileOffset - HBLOCK_SIZE, TailDisplay); 00534 00535 if( !NT_SUCCESS(Status) ) { 00536 goto ErrorExit; 00537 } 00538 // 00539 // Adjust the offsets 00540 // 00541 BinFileOffset += BinSize; 00542 IOBufferOffset += BinDataNeeded; 00543 // 00544 // mark the begining of a new bin 00545 // 00546 Bin = NULL; 00547 } else { 00548 // 00549 // we do not have all bin data in the buffer 00550 // copy what we can 00551 // 00552 RtlCopyMemory(((PUCHAR)Bin + BinOffset),(IOBuffer + IOBufferOffset), BinDataInBuffer); 00553 00554 // 00555 // adjust the offsets; this should be the last iteration of the inner loop 00556 // 00557 BinOffset += BinDataInBuffer; 00558 IOBufferOffset += BinDataInBuffer; 00559 00560 // 00561 // if we are here, the buffer must have beed exausted 00562 // 00563 ASSERT( IOBufferOffset == IOBufferSize ); 00564 } 00565 } 00566 } 00567 } 00568 00569 // 00570 // if we got here, we shouldn't have a bin under construction 00571 // 00572 ASSERT( Bin == NULL ); 00573 00574 // 00575 // Free the buffer used for I/O operations 00576 // 00577 ExFreePool(IOBuffer); 00578 00579 return Status; 00580 00581 ErrorExit: 00582 // 00583 // Free the buffer used for I/O operations 00584 // 00585 ExFreePool(IOBuffer); 00586 00587 return Status; 00588 }

RESULT HvpRecoverData PHHIVE  Hive,
BOOLEAN  ReadOnly,
PHCELL_INDEX TailDisplay  OPTIONAL
 

Definition at line 847 of file hiveload.c.

References _HHIVE::Allocate, ASSERT, _HHIVE::BaseBlock, Bin, _HMAP_ENTRY::BinAddress, BitMap, _HMAP_ENTRY::BlockAddress, _HHIVE::Cluster, _HHIVE::DirtyAlloc, _HHIVE::DirtyCount, _HHIVE::DirtyVector, End, ErrorExit(), ExAllocatePoolWithTag, ExFreePool(), Fail, FALSE, _HBIN::FileOffset, _HHIVE::FileRead, _HHIVE::Free, HBIN_SIGNATURE, HFILE_TYPE_LOG, Hive, HiveSuccess, HLOG_DV_SIGNATURE, HMAP_BASE, HMAP_NEWALLOC, HSECTOR_SIZE, HvCheckHiveDebug, HvMarkDirty(), HvpEnlistBinInMap(), HvpEnlistFreeCells(), HvpGetCellMap(), _HBASE_BLOCK::Length, NoMemory, NT_SUCCESS, NULL, PagedPool, _HHIVE::ReadOnly, ROUND_UP, RtlInitializeBitMap(), RtlNumberOfSetBits(), _HBIN::Signature, Size, _HBIN::Size, Start, TRUE, and VALIDATE_CELL_MAP.

Referenced by HvLoadHive().

00854 : 00855 00856 Apply the corrections in the log file to the hive memory image. 00857 00858 ALGORITHM: 00859 00860 compute size of dirty vector 00861 read in dirty vector 00862 if (i/o error) 00863 return Fail 00864 00865 skip first cluster of data (already processed as log) 00866 sweep vector, looking for runs of bits 00867 address of first bit is used to compute memory offset 00868 length of run is length of block to read 00869 assert always a cluster multiple 00870 file offset kept by running counter 00871 read 00872 if (i/o error) 00873 return fail 00874 00875 return success 00876 00877 NOTE: It is assumed that the data part of the Hive has been 00878 read into a single contiguous block, at Image. 00879 00880 Arguments: 00881 00882 Hive - supplies a pointer to the hive control structure for the 00883 hive of interest 00884 00885 ReadOnly - by the time this function is called, the hive is forced to the 00886 ready-only state. At the end, if recovery goes OK, we restore the 00887 hive at it's original state, and enlist all free cells. 00888 00889 TailDisplay - array containing the tail ends of the free cell lists - optional 00890 00891 Return Value: 00892 00893 RESULT 00894 00895 --*/ 00896 { 00897 ULONG Cluster; 00898 ULONG ClusterSize; 00899 ULONG VectorSize; 00900 PULONG Vector; 00901 ULONG FileOffset; 00902 BOOLEAN rc; 00903 ULONG Current; 00904 ULONG Start; 00905 ULONG End; 00906 ULONG Address; 00907 PUCHAR MemoryBlock; 00908 RTL_BITMAP BitMap; 00909 ULONG Length; 00910 ULONG DirtyVectorSignature = 0; 00911 ULONG i; 00912 PHMAP_ENTRY Me; 00913 PHBIN Bin; 00914 PHBIN NewBin; 00915 PUCHAR SectorImage; 00916 PUCHAR Source; 00917 PHBIN SourceBin; 00918 ULONG SectorOffsetInBin; 00919 ULONG SectorOffsetInBlock; 00920 ULONG BlockOffsetInBin; 00921 ULONG NumberOfSectors; 00922 00923 // 00924 // compute size of dirty vector, read and check signature, read vector 00925 // 00926 Cluster = Hive->Cluster; 00927 ClusterSize = Cluster * HSECTOR_SIZE; 00928 Length = Hive->BaseBlock->Length; 00929 VectorSize = (Length / HSECTOR_SIZE) / 8; // VectorSize == Bytes 00930 FileOffset = ClusterSize; 00931 00932 // 00933 // get and check signature 00934 // 00935 rc = (Hive->FileRead)( 00936 Hive, 00937 HFILE_TYPE_LOG, 00938 &FileOffset, 00939 (PVOID)&DirtyVectorSignature, 00940 sizeof(DirtyVectorSignature) 00941 ); 00942 if (rc == FALSE) { 00943 return Fail; 00944 } 00945 00946 if (DirtyVectorSignature != HLOG_DV_SIGNATURE) { 00947 return Fail; 00948 } 00949 00950 // 00951 // get the actual vector 00952 // 00953 Vector = (PULONG)((Hive->Allocate)(ROUND_UP(VectorSize,sizeof(ULONG)), TRUE)); 00954 if (Vector == NULL) { 00955 return NoMemory; 00956 } 00957 rc = (Hive->FileRead)( 00958 Hive, 00959 HFILE_TYPE_LOG, 00960 &FileOffset, // dirty vector right after header 00961 (PVOID)Vector, 00962 VectorSize 00963 ); 00964 if (rc == FALSE) { 00965 (Hive->Free)(Vector, VectorSize); 00966 return Fail; 00967 } 00968 FileOffset = ROUND_UP(FileOffset, ClusterSize); 00969 00970 00971 // 00972 // step through the diry map, reading in the corresponding file bytes 00973 // 00974 Current = 0; 00975 VectorSize = VectorSize * 8; // VectorSize == bits 00976 00977 RtlInitializeBitMap(&BitMap, Vector, VectorSize); 00978 00979 while (Current < VectorSize) { 00980 00981 // 00982 // find next contiguous block of entries to read in 00983 // 00984 for (i = Current; i < VectorSize; i++) { 00985 if (RtlCheckBit(&BitMap, i) == 1) { 00986 break; 00987 } 00988 } 00989 Start = i; 00990 00991 for ( ; i < VectorSize; i++) { 00992 if (RtlCheckBit(&BitMap, i) == 0) { 00993 break; 00994 } 00995 } 00996 End = i; 00997 Current = End; 00998 00999 // 01000 // Start == number of 1st sector, End == number of Last sector + 1 01001 // 01002 Length = (End - Start) * HSECTOR_SIZE; 01003 01004 if( 0 == Length ) { 01005 // no more dirty blocks. 01006 break; 01007 } 01008 // 01009 // allocate a buffer to read the whole run from the file; This is a temporary 01010 // block that'll be freed immediately, so don't charge quota for it. 01011 // 01012 MemoryBlock = (PUCHAR)ExAllocatePoolWithTag(PagedPool, Length, CM_POOL_TAG); 01013 if( MemoryBlock == NULL ) { 01014 goto ErrorExit; 01015 } 01016 01017 rc = (Hive->FileRead)( 01018 Hive, 01019 HFILE_TYPE_LOG, 01020 &FileOffset, 01021 (PVOID)MemoryBlock, 01022 Length 01023 ); 01024 01025 ASSERT((FileOffset % ClusterSize) == 0); 01026 if (rc == FALSE) { 01027 ExFreePool(MemoryBlock); 01028 goto ErrorExit; 01029 } 01030 01031 Source = MemoryBlock; 01032 // 01033 // copy recovered data in the right locations inside the in-memory bins 01034 // 01035 while( Start < End ) { 01036 Address = Start * HSECTOR_SIZE; 01037 01038 Me = HvpGetCellMap(Hive, Address); 01039 VALIDATE_CELL_MAP(__LINE__,Me,Hive,Address); 01040 01041 Bin = (PHBIN)(Me->BinAddress & HMAP_BASE); 01042 // 01043 // compute the memory address where data should be copied 01044 // 01045 SectorOffsetInBin = Address - Bin->FileOffset; 01046 01047 if( ( SectorOffsetInBin == 0 ) && ( ((PHBIN)Source)->Size > Bin->Size ) ){ 01048 // 01049 // Bin in the log file is bigger than the one in memory; 01050 // two or more bins must have been coalesced 01051 // 01052 ASSERT( Me->BinAddress & HMAP_NEWALLOC ); 01053 01054 SourceBin = (PHBIN)Source; 01055 01056 // 01057 // new bin must have the right offset 01058 // 01059 ASSERT( Address == SourceBin->FileOffset ); 01060 ASSERT( SourceBin->Signature == HBIN_SIGNATURE ); 01061 // 01062 // entire bin should be dirty 01063 // 01064 ASSERT( (SourceBin->FileOffset + SourceBin->Size) <= End * HSECTOR_SIZE ); 01065 01066 // 01067 // Allocate the right size for the new bin 01068 // 01069 NewBin = (PHBIN)(Hive->Allocate)(SourceBin->Size, TRUE); 01070 if (NewBin == NULL) { 01071 goto ErrorExit; 01072 } 01073 01074 // 01075 // Copy the old data into the new bin and free old bins 01076 // 01077 while(Bin->FileOffset < (Address + SourceBin->Size)) { 01078 01079 RtlCopyMemory((PUCHAR)NewBin + (Bin->FileOffset - Address),Bin, Bin->Size); 01080 01081 // 01082 // Do not delist as we didn't enlisted (when hive needs recovery) 01083 // 01084 //HvpDelistBinFreeCells(Hive,Bin,Stable,TailDisplay); 01085 01086 // 01087 // Advance to the new bin 01088 // 01089 if( (Bin->FileOffset + Bin->Size) < Hive->BaseBlock->Length ) { 01090 Me = HvpGetCellMap(Hive, Bin->FileOffset + Bin->Size); 01091 VALIDATE_CELL_MAP(__LINE__,Me,Hive,Bin->FileOffset + Bin->Size); 01092 01093 // 01094 // Free the old bin 01095 // 01096 (Hive->Free)(Bin, Bin->Size); 01097 01098 // 01099 // the new address must be the begining of a new allocation 01100 // 01101 ASSERT( Me->BinAddress & HMAP_NEWALLOC ); 01102 01103 Bin = (PHBIN)(Me->BinAddress & HMAP_BASE); 01104 } else { 01105 // 01106 // we are at the end of the hive here; just break out of the loop 01107 // 01108 ASSERT( (Address + SourceBin->Size) == Hive->BaseBlock->Length ); 01109 ASSERT( (Bin->FileOffset + Bin->Size) == Hive->BaseBlock->Length ); 01110 01111 // 01112 // Free the old bin 01113 // 01114 (Hive->Free)(Bin, Bin->Size); 01115 01116 // 01117 // debug purposes only 01118 // 01119 ASSERT( (Bin = NULL) == NULL ); 01120 01121 // bail out of while loop 01122 break; 01123 } 01124 01125 } 01126 01127 #if DBG 01128 // 01129 // validation: bin size increase must come from coalescing of former bins 01130 // (i.e. bins are never split!!!) 01131 // 01132 if( Bin != NULL ) { 01133 ASSERT( Bin->FileOffset == (Address + SourceBin->Size)); 01134 } 01135 #endif 01136 01137 // 01138 // Now overwrite the modified data ! 01139 // 01140 01141 while( (Address < (SourceBin->FileOffset + SourceBin->Size)) && (Start < End) ) { 01142 RtlCopyMemory((PUCHAR)NewBin + (Address - SourceBin->FileOffset),Source, HSECTOR_SIZE); 01143 01144 // 01145 // skip to the next sector 01146 // 01147 Start++; 01148 Source += HSECTOR_SIZE; 01149 Address += HSECTOR_SIZE; 01150 } 01151 01152 // 01153 // first sector of the new bin is always restaured from the log file! 01154 // 01155 ASSERT(NewBin->FileOffset == SourceBin->FileOffset); 01156 ASSERT(NewBin->Size == SourceBin->Size); 01157 01158 } else { 01159 // 01160 // Normal case: sector recovery somewhere in the middle of the bin 01161 // 01162 01163 01164 // 01165 // Do not delist as we didn't enlisted (when hive needs recovery) 01166 // 01167 //HvpDelistBinFreeCells(Hive,Bin,Stable,TailDisplay); 01168 01169 // 01170 // Offset should fall within bin memory layout 01171 // 01172 ASSERT( SectorOffsetInBin < Bin->Size ); 01173 01174 BlockOffsetInBin = (ULONG)((PUCHAR)Me->BlockAddress - (PUCHAR)Bin); 01175 SectorOffsetInBlock = SectorOffsetInBin - BlockOffsetInBin; 01176 01177 // 01178 // sanity check; address should be the same relative to eigther begining of the bin or begining of the block 01179 // 01180 ASSERT(((PUCHAR)Me->BlockAddress + SectorOffsetInBlock) == ((PUCHAR)Bin + SectorOffsetInBin)); 01181 01182 SectorImage = (PUCHAR)((PUCHAR)Me->BlockAddress + SectorOffsetInBlock); 01183 01184 // 01185 // both source and destination should be valid at this point 01186 // 01187 ASSERT( SectorImage < ((PUCHAR)Bin + Bin->Size) ); 01188 ASSERT( Source < (MemoryBlock + Length) ); 01189 01190 NumberOfSectors = 0; 01191 while( ( (SectorImage + (NumberOfSectors * HSECTOR_SIZE)) < (PUCHAR)((PUCHAR)Bin + Bin->Size) ) && 01192 ( (Start + NumberOfSectors ) < End ) ) { 01193 // 01194 // we are still inside the same bin; 01195 // deal with all sectors inside the same bin at once 01196 // 01197 NumberOfSectors++; 01198 } 01199 01200 // 01201 // finally, copy the memory 01202 // 01203 RtlCopyMemory(SectorImage,Source, NumberOfSectors * HSECTOR_SIZE); 01204 01205 NewBin = Bin; 01206 01207 // 01208 // skip to the next sector 01209 // 01210 Start += NumberOfSectors; 01211 Source += NumberOfSectors * HSECTOR_SIZE; 01212 01213 } 01214 01215 // 01216 // rebuild the map anyway 01217 // 01218 if( !NT_SUCCESS(HvpEnlistBinInMap(Hive, Length, NewBin, NewBin->FileOffset, TailDisplay)) ) { 01219 goto ErrorExit; 01220 } 01221 } 01222 01223 // 01224 // get rid of the temporary pool 01225 // 01226 ExFreePool(MemoryBlock); 01227 } 01228 01229 // 01230 // now, after we have successfully recovered, enlist all free cells 01231 // and restore the hive to it's original state 01232 // 01233 Hive->ReadOnly = ReadOnly; 01234 01235 if( ReadOnly == FALSE ) { 01236 // 01237 // no point going through this loop if the hive is read-only 01238 // 01239 Address = 0; 01240 while( Address < Hive->BaseBlock->Length ) { 01241 Me = HvpGetCellMap(Hive, Address); 01242 VALIDATE_CELL_MAP(__LINE__,Me,Hive,Address); 01243 Bin = (PHBIN)(Me->BinAddress & HMAP_BASE); 01244 01245 ASSERT( Bin->FileOffset == Address ); 01246 ASSERT( Bin->Signature == HBIN_SIGNATURE ); 01247 01248 // 01249 // add free cells in the bin to the appropriate free lists 01250 // 01251 if ( ! HvpEnlistFreeCells(Hive, Bin, Address,TailDisplay)) { 01252 HvCheckHiveDebug.Hive = Hive; 01253 HvCheckHiveDebug.Status = 0xA004; 01254 HvCheckHiveDebug.Space = Bin->Size; 01255 HvCheckHiveDebug.MapPoint = Address; 01256 HvCheckHiveDebug.BinPoint = Bin; 01257 goto ErrorExit; 01258 } 01259 01260 Address += Bin->Size; 01261 } 01262 } 01263 01264 // 01265 // put correct dirty vector in Hive so that recovered data 01266 // can be correctly flushed 01267 // 01268 RtlInitializeBitMap(&(Hive->DirtyVector), Vector, VectorSize); 01269 Hive->DirtyCount = RtlNumberOfSetBits(&Hive->DirtyVector); 01270 Hive->DirtyAlloc = VectorSize * 8; 01271 HvMarkDirty(Hive, 0, sizeof(HBIN)); // force header of 1st bin dirty 01272 return HiveSuccess; 01273 01274 ErrorExit: 01275 // 01276 // free the dirty vector and return failure 01277 // 01278 (Hive->Free)(Vector, VectorSize); 01279 return Fail; 01280 }


Variable Documentation

PHBIN BinPoint
 

Definition at line 95 of file hiveload.c.

PHHIVE Hive
 

Definition at line 91 of file hiveload.c.

struct { ... } HvCheckHiveDebug
 

HCELL_INDEX MapPoint
 

Definition at line 94 of file hiveload.c.

ULONG Space
 

Definition at line 93 of file hiveload.c.

ULONG Status
 

Definition at line 92 of file hiveload.c.


Generated on Sat May 15 19:44:05 2004 for test by doxygen 1.3.7