Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1317 lines
41 KiB

  1. //
  2. // REGDBLK.C
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995
  5. //
  6. #include "pch.h"
  7. DECLARE_DEBUG_COUNT(g_RgDatablockLockCount);
  8. // Don't let a FREE_RECORD shrink less than this value.
  9. #define MINIMUM_FREE_RECORD_LENGTH (sizeof(KEY_RECORD) + sizeof(VALUE_RECORD))
  10. //
  11. // RgAllocDatablockInfoBuffers
  12. //
  13. // Allocates the buffers associated with a DATABLOCK_INFO structure. The
  14. // size of the datablock buffer is determined by the BlockSize member.
  15. //
  16. int
  17. INTERNAL
  18. RgAllocDatablockInfoBuffers(
  19. LPDATABLOCK_INFO lpDatablockInfo
  20. )
  21. {
  22. lpDatablockInfo-> lpDatablockHeader = (LPDATABLOCK_HEADER)
  23. RgAllocMemory(lpDatablockInfo-> BlockSize);
  24. if (!IsNullPtr(lpDatablockInfo-> lpDatablockHeader)) {
  25. lpDatablockInfo-> lpKeyRecordTable = (LPKEY_RECORD_TABLE_ENTRY)
  26. RgSmAllocMemory(sizeof(KEY_RECORD_TABLE_ENTRY) *
  27. KEY_RECORDS_PER_DATABLOCK);
  28. if (!IsNullPtr(lpDatablockInfo-> lpKeyRecordTable))
  29. return ERROR_SUCCESS;
  30. RgFreeDatablockInfoBuffers(lpDatablockInfo);
  31. }
  32. return ERROR_OUTOFMEMORY;
  33. }
  34. //
  35. // RgFreeDatablockInfoBuffers
  36. //
  37. // Frees the buffers associated with a DATABLOCK_INFO structure.
  38. //
  39. VOID
  40. INTERNAL
  41. RgFreeDatablockInfoBuffers(
  42. LPDATABLOCK_INFO lpDatablockInfo
  43. )
  44. {
  45. if (!IsNullPtr(lpDatablockInfo-> lpDatablockHeader)) {
  46. RgFreeMemory(lpDatablockInfo-> lpDatablockHeader);
  47. lpDatablockInfo-> lpDatablockHeader = NULL;
  48. }
  49. if (!IsNullPtr(lpDatablockInfo-> lpKeyRecordTable)) {
  50. RgSmFreeMemory(lpDatablockInfo-> lpKeyRecordTable);
  51. lpDatablockInfo-> lpKeyRecordTable = NULL;
  52. }
  53. }
  54. //
  55. // RgBuildKeyRecordTable
  56. //
  57. // Builds a KEY_RECORD index table for the given datablock.
  58. //
  59. // A datablock consists of a header followed by a series of variable-sized
  60. // KEY_RECORDs, each with a unique id. To make lookups fast, an index table is
  61. // used to map from the unique id to that KEY_RECORD's location.
  62. //
  63. // As we walk over each KEY_RECORD, we do checks to validate the structure of
  64. // the datablock, so the error code should be checked for corruption.
  65. //
  66. int
  67. INTERNAL
  68. RgBuildKeyRecordTable(
  69. LPDATABLOCK_INFO lpDatablockInfo
  70. )
  71. {
  72. LPDATABLOCK_HEADER lpDatablockHeader;
  73. UINT Offset;
  74. UINT BytesRemaining;
  75. LPKEY_RECORD lpKeyRecord;
  76. DWORD DatablockAddress;
  77. ZeroMemory(lpDatablockInfo-> lpKeyRecordTable,
  78. sizeof(KEY_RECORD_TABLE_ENTRY) * KEY_RECORDS_PER_DATABLOCK);
  79. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  80. Offset = sizeof(DATABLOCK_HEADER);
  81. BytesRemaining = lpDatablockInfo-> BlockSize - sizeof(DATABLOCK_HEADER);
  82. while (BytesRemaining) {
  83. lpKeyRecord = (LPKEY_RECORD) ((LPBYTE) lpDatablockHeader + Offset);
  84. DatablockAddress = lpKeyRecord-> DatablockAddress;
  85. if ((lpKeyRecord-> AllocatedSize == 0) || (lpKeyRecord-> AllocatedSize >
  86. BytesRemaining) || ((DatablockAddress != REG_NULL) &&
  87. (LOWORD(DatablockAddress) >= KEY_RECORDS_PER_DATABLOCK))) {
  88. TRACE(("RgBuildKeyRecordTable: invalid key record detected\n"));
  89. TRACE(("lpdh=%x\n", lpDatablockHeader));
  90. TRACE(("lpkr=%x\n", lpKeyRecord));
  91. TRACE(("as=%x\n", lpKeyRecord-> AllocatedSize));
  92. TRACE(("br=%x\n", BytesRemaining));
  93. TRACE(("dba=%x\n", DatablockAddress));
  94. TRAP();
  95. return ERROR_BADDB;
  96. }
  97. if (DatablockAddress != REG_NULL) {
  98. lpDatablockInfo-> lpKeyRecordTable[LOWORD(DatablockAddress)] =
  99. (KEY_RECORD_TABLE_ENTRY) Offset;
  100. }
  101. Offset += SmallDword(lpKeyRecord-> AllocatedSize);
  102. BytesRemaining -= SmallDword(lpKeyRecord-> AllocatedSize);
  103. }
  104. return ERROR_SUCCESS;
  105. }
  106. //
  107. // RgLockDatablock
  108. //
  109. // Locks the specified datablock in memory, indicating that it is about to be
  110. // used. If the datablock is not currently in memory, then it is brought in.
  111. // Unlocked datablocks are freed as necessary to make room for this new
  112. // datablock.
  113. //
  114. // IMPORTANT: Locking a datablock only means that it's guaranteed to be kept
  115. // in memory. It does not mean that pointers contained in a DATABLOCK_INFO
  116. // structure will remain the same: routines that could change the
  117. // DATABLOCK_INFO pointers are labeled "IMPORTANT" as well.
  118. //
  119. // lpFileInfo, registry file containing the datablock.
  120. // BlockIndex, index of the datablock.
  121. //
  122. int
  123. INTERNAL
  124. RgLockDatablock(
  125. LPFILE_INFO lpFileInfo,
  126. UINT BlockIndex
  127. )
  128. {
  129. int ErrorCode;
  130. LPDATABLOCK_INFO lpDatablockInfo;
  131. HFILE hFile = HFILE_ERROR;
  132. if (BlockIndex >= lpFileInfo-> FileHeader.BlockCount) {
  133. TRACE(("RgLockDatablock: invalid datablock number\n"));
  134. return ERROR_BADDB;
  135. }
  136. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  137. //
  138. // Is the datablock currently in memory?
  139. //
  140. if (!(lpDatablockInfo-> Flags & DIF_PRESENT)) {
  141. NOISE(("RgLockDatablock: "));
  142. NOISE((lpFileInfo-> FileName));
  143. NOISE((", block %d\n", BlockIndex));
  144. ASSERT(lpDatablockInfo-> FileOffset != -1);
  145. if ((ErrorCode = RgAllocDatablockInfoBuffers(lpDatablockInfo)) !=
  146. ERROR_SUCCESS)
  147. goto CleanupAfterError;
  148. NOISE((" lpDatablockHeader=%x\n", lpDatablockInfo-> lpDatablockHeader));
  149. NOISE((" lpKeyRecordTable=%x\n", lpDatablockInfo-> lpKeyRecordTable));
  150. if ((hFile = RgOpenFile(lpFileInfo-> FileName, OF_READ)) == HFILE_ERROR)
  151. goto CleanupAfterFileError;
  152. if (!RgSeekFile(hFile, lpDatablockInfo-> FileOffset))
  153. goto CleanupAfterFileError;
  154. if (!RgReadFile(hFile, lpDatablockInfo-> lpDatablockHeader,
  155. (UINT) lpDatablockInfo-> BlockSize))
  156. goto CleanupAfterFileError;
  157. if (!RgIsValidDatablockHeader(lpDatablockInfo-> lpDatablockHeader)) {
  158. ErrorCode = ERROR_BADDB;
  159. goto CleanupAfterError;
  160. }
  161. if ((ErrorCode = RgBuildKeyRecordTable(lpDatablockInfo)) !=
  162. ERROR_SUCCESS)
  163. goto CleanupAfterError;
  164. RgCloseFile(hFile);
  165. }
  166. lpDatablockInfo-> Flags |= (DIF_ACCESSED | DIF_PRESENT);
  167. lpDatablockInfo-> LockCount++;
  168. INCREMENT_DEBUG_COUNT(g_RgDatablockLockCount);
  169. return ERROR_SUCCESS;
  170. CleanupAfterFileError:
  171. ErrorCode = ERROR_REGISTRY_IO_FAILED;
  172. CleanupAfterError:
  173. if (hFile != HFILE_ERROR)
  174. RgCloseFile(hFile);
  175. RgFreeDatablockInfoBuffers(lpDatablockInfo);
  176. DEBUG_OUT(("RgLockDatablock() returning error %d\n", ErrorCode));
  177. return ErrorCode;
  178. }
  179. //
  180. // RgUnlockDatablock
  181. //
  182. // Unlocks the datablock, indicating that the datablock is no longer in active
  183. // use. After a datablock has been unlocked, the datablock may be freed after
  184. // flushing to disk if dirty.
  185. //
  186. VOID
  187. INTERNAL
  188. RgUnlockDatablock(
  189. LPFILE_INFO lpFileInfo,
  190. UINT BlockIndex,
  191. BOOL fMarkDirty
  192. )
  193. {
  194. LPDATABLOCK_INFO lpDatablockInfo;
  195. ASSERT(BlockIndex < lpFileInfo-> FileHeader.BlockCount);
  196. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  197. ASSERT(lpDatablockInfo-> LockCount > 0);
  198. lpDatablockInfo-> LockCount--;
  199. if (fMarkDirty) {
  200. lpDatablockInfo-> Flags |= DIF_DIRTY;
  201. lpFileInfo-> Flags |= FI_DIRTY;
  202. RgDelayFlush();
  203. }
  204. DECREMENT_DEBUG_COUNT(g_RgDatablockLockCount);
  205. }
  206. //
  207. // RgLockKeyRecord
  208. //
  209. // Wraps RgLockDatablock, returning the address of the specified KEY_RECORD
  210. // structure.
  211. //
  212. int
  213. INTERNAL
  214. RgLockKeyRecord(
  215. LPFILE_INFO lpFileInfo,
  216. UINT BlockIndex,
  217. BYTE KeyRecordIndex,
  218. LPKEY_RECORD FAR* lplpKeyRecord
  219. )
  220. {
  221. int ErrorCode;
  222. LPDATABLOCK_INFO lpDatablockInfo;
  223. if ((ErrorCode = RgLockDatablock(lpFileInfo, BlockIndex)) ==
  224. ERROR_SUCCESS) {
  225. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  226. if (IsNullKeyRecordTableEntry(lpDatablockInfo->
  227. lpKeyRecordTable[KeyRecordIndex])) {
  228. RgUnlockDatablock(lpFileInfo, BlockIndex, FALSE);
  229. TRACE(("RgLockKeyRecord: invalid datablock address %x:%x\n",
  230. BlockIndex, KeyRecordIndex));
  231. ErrorCode = ERROR_BADDB;
  232. }
  233. else {
  234. *lplpKeyRecord = RgIndexKeyRecordPtr(lpDatablockInfo,
  235. KeyRecordIndex);
  236. }
  237. }
  238. return ErrorCode;
  239. }
  240. //
  241. // RgCompactDatablock
  242. //
  243. // Compacts the datablock by pushing all KEY_RECORDS together and leaving a
  244. // single FREEKEY_RECORD at the end.
  245. //
  246. // The datablock must be marked dirty by the caller, if desired.
  247. //
  248. // Returns TRUE if any action was taken.
  249. //
  250. BOOL
  251. INTERNAL
  252. RgCompactDatablock(
  253. LPDATABLOCK_INFO lpDatablockInfo
  254. )
  255. {
  256. LPDATABLOCK_HEADER lpDatablockHeader;
  257. LPFREEKEY_RECORD lpFreeKeyRecord;
  258. LPBYTE lpSource;
  259. LPBYTE lpDestination;
  260. UINT Offset;
  261. UINT BlockSize;
  262. UINT BytesToPushDown;
  263. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  264. // Only need to compact if there's a free record in this datablock.
  265. if (lpDatablockHeader-> FirstFreeOffset == REG_NULL)
  266. return FALSE;
  267. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpDatablockHeader +
  268. SmallDword(lpDatablockHeader-> FirstFreeOffset));
  269. // Only need to compact if the all the free bytes aren't already at the end
  270. // of the datablock (datablocks can't be greater than 64K-1, so no overflow
  271. // is possible).
  272. if ((SmallDword(lpDatablockHeader-> FirstFreeOffset) +
  273. SmallDword(lpFreeKeyRecord-> AllocatedSize) >= lpDatablockInfo->
  274. BlockSize) && (lpFreeKeyRecord-> NextFreeOffset == REG_NULL))
  275. return FALSE;
  276. NOISE(("RgCompactDatablock: block %d\n", lpDatablockHeader-> BlockIndex));
  277. lpSource = NULL;
  278. lpDestination = NULL;
  279. Offset = sizeof(DATABLOCK_HEADER);
  280. BlockSize = lpDatablockInfo-> BlockSize;
  281. while (Offset < BlockSize) {
  282. // Advance to the next free record or the end of the block.
  283. for (;;) {
  284. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpDatablockHeader +
  285. Offset);
  286. if (Offset >= BlockSize || IsKeyRecordFree(lpFreeKeyRecord)) {
  287. //
  288. // If lpSource is valid, then we can push down the bytes from
  289. // lpSource through lpFreeKeyRecord to lpDestination.
  290. //
  291. if (!IsNullPtr(lpSource)) {
  292. BytesToPushDown = (LPBYTE) lpFreeKeyRecord -
  293. (LPBYTE) lpSource;
  294. MoveMemory(lpDestination, lpSource, BytesToPushDown);
  295. lpDestination += BytesToPushDown;
  296. }
  297. if (IsNullPtr(lpDestination))
  298. lpDestination = (LPBYTE) lpFreeKeyRecord;
  299. break;
  300. }
  301. Offset += SmallDword(lpFreeKeyRecord-> AllocatedSize);
  302. }
  303. // Advance to the next key record.
  304. while (Offset < BlockSize) {
  305. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpDatablockHeader +
  306. Offset);
  307. if (!IsKeyRecordFree(lpFreeKeyRecord)) {
  308. lpSource = (LPBYTE) lpFreeKeyRecord;
  309. break;
  310. }
  311. Offset += SmallDword(lpFreeKeyRecord-> AllocatedSize);
  312. }
  313. }
  314. // lpDestination now points at the end of the datablock where the giant
  315. // free record is to be placed. Initialize this record and patch up the
  316. // datablock header.
  317. lpDatablockHeader-> FirstFreeOffset = (LPBYTE) lpDestination -
  318. (LPBYTE) lpDatablockHeader;
  319. ((LPFREEKEY_RECORD) lpDestination)-> AllocatedSize = lpDatablockInfo->
  320. FreeBytes;
  321. ((LPFREEKEY_RECORD) lpDestination)-> DatablockAddress = REG_NULL;
  322. ((LPFREEKEY_RECORD) lpDestination)-> NextFreeOffset = REG_NULL;
  323. // The key record table is now invalid, so we must refresh its contents.
  324. RgBuildKeyRecordTable(lpDatablockInfo);
  325. return TRUE;
  326. }
  327. //
  328. // RgCreateDatablock
  329. //
  330. // Creates a new datablock at the end of the file of the specified length (plus
  331. // padding to align the block).
  332. //
  333. // The datablock is locked, so RgUnlockDatablock must be called on the last
  334. // datablock in the file.
  335. //
  336. int
  337. INTERNAL
  338. RgCreateDatablock(
  339. LPFILE_INFO lpFileInfo,
  340. UINT Length
  341. )
  342. {
  343. UINT BlockCount;
  344. LPDATABLOCK_INFO lpDatablockInfo;
  345. LPDATABLOCK_HEADER lpDatablockHeader;
  346. LPFREEKEY_RECORD lpFreeKeyRecord;
  347. BlockCount = lpFileInfo-> FileHeader.BlockCount;
  348. if (BlockCount >= DATABLOCKS_PER_FILE)
  349. return ERROR_OUTOFMEMORY;
  350. if (BlockCount >= lpFileInfo-> DatablockInfoAllocCount) {
  351. // lpDatablockInfo is too small to hold the info for a new datablock,
  352. // so we must grow it a bit.
  353. if (IsNullPtr((lpDatablockInfo = (LPDATABLOCK_INFO)
  354. RgSmReAllocMemory(lpFileInfo-> lpDatablockInfo, (BlockCount +
  355. DATABLOCK_INFO_SLACK_ALLOC) * sizeof(DATABLOCK_INFO)))))
  356. return ERROR_OUTOFMEMORY;
  357. lpFileInfo-> lpDatablockInfo = lpDatablockInfo;
  358. lpFileInfo-> DatablockInfoAllocCount += DATABLOCK_INFO_SLACK_ALLOC;
  359. }
  360. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockCount);
  361. Length = RgAlignBlockSize(Length + sizeof(DATABLOCK_HEADER));
  362. lpDatablockInfo-> BlockSize = Length;
  363. if (RgAllocDatablockInfoBuffers(lpDatablockInfo) != ERROR_SUCCESS)
  364. return ERROR_OUTOFMEMORY;
  365. lpDatablockInfo-> FreeBytes = Length - sizeof(DATABLOCK_HEADER);
  366. lpDatablockInfo-> FirstFreeIndex = 0;
  367. lpDatablockInfo-> FileOffset = -1; // Set during file flush
  368. lpDatablockInfo-> Flags = DIF_PRESENT | DIF_ACCESSED | DIF_DIRTY;
  369. lpDatablockInfo-> LockCount = 1;
  370. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  371. lpDatablockHeader-> Signature = DH_SIGNATURE;
  372. lpDatablockHeader-> BlockSize = Length;
  373. lpDatablockHeader-> FreeBytes = lpDatablockInfo-> FreeBytes;
  374. lpDatablockHeader-> Flags = DHF_HASBLOCKNUMBERS;
  375. lpDatablockHeader-> BlockIndex = (WORD) BlockCount;
  376. lpDatablockHeader-> FirstFreeOffset = sizeof(DATABLOCK_HEADER);
  377. lpDatablockHeader-> MaxAllocatedIndex = 0;
  378. // lpDatablockHeader-> FirstFreeIndex is copied back on the flush.
  379. // lpDatablockHeader-> Reserved is worthless because it was randomly set
  380. // to a pointer in the old code.
  381. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpDatablockHeader +
  382. sizeof(DATABLOCK_HEADER));
  383. lpFreeKeyRecord-> AllocatedSize = lpDatablockInfo-> FreeBytes;
  384. lpFreeKeyRecord-> DatablockAddress = REG_NULL;
  385. lpFreeKeyRecord-> NextFreeOffset = REG_NULL;
  386. lpFileInfo-> FileHeader.BlockCount++;
  387. lpFileInfo-> FileHeader.Flags |= FHF_DIRTY;
  388. lpFileInfo-> Flags |= FI_DIRTY | FI_EXTENDED;
  389. RgDelayFlush();
  390. INCREMENT_DEBUG_COUNT(g_RgDatablockLockCount);
  391. // We must initialize the key record table, so we might as well let
  392. // RgBuildKeyRecordTable check the validity of what we just created...
  393. return RgBuildKeyRecordTable(lpDatablockInfo);
  394. }
  395. //
  396. // RgExtendDatablock
  397. //
  398. // Extends the given datablock to the specified size. If successful, then the
  399. // resulting datablock will be compacted with a single FREEKEY_RECORD at the
  400. // end of the datablock which will include the added space.
  401. //
  402. int
  403. INTERNAL
  404. RgExtendDatablock(
  405. LPFILE_INFO lpFileInfo,
  406. UINT BlockIndex,
  407. UINT Length
  408. )
  409. {
  410. LPDATABLOCK_INFO lpDatablockInfo;
  411. DWORD NewBlockSize;
  412. LPDATABLOCK_HEADER lpNewDatablockHeader;
  413. LPFREEKEY_RECORD lpFreeKeyRecord;
  414. ASSERT(BlockIndex < lpFileInfo-> FileHeader.BlockCount);
  415. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  416. ASSERT(lpDatablockInfo-> Flags & DIF_PRESENT);
  417. // Check if enough free bytes already exist: if so, no need to extend.
  418. if (lpDatablockInfo-> FreeBytes >= Length) {
  419. DEBUG_OUT(("RgExtendDatablock: unexpectedly called\n"));
  420. return ERROR_SUCCESS;
  421. }
  422. NewBlockSize = RgAlignBlockSize(lpDatablockInfo-> BlockSize + Length -
  423. lpDatablockInfo-> FreeBytes);
  424. if (NewBlockSize > MAXIMUM_DATABLOCK_SIZE) {
  425. TRACE(("RgExtendDatablock: datablock too big\n"));
  426. return ERROR_OUTOFMEMORY;
  427. }
  428. NOISE(("RgExtendDatablock: block %d\n", BlockIndex));
  429. NOISE(("block size=%x, new block size=%x\n", lpDatablockInfo-> BlockSize,
  430. NewBlockSize));
  431. if (IsNullPtr((lpNewDatablockHeader = (LPDATABLOCK_HEADER)
  432. RgReAllocMemory(lpDatablockInfo-> lpDatablockHeader, (UINT)
  433. NewBlockSize))))
  434. return ERROR_OUTOFMEMORY;
  435. lpDatablockInfo-> lpDatablockHeader = lpNewDatablockHeader;
  436. RgCompactDatablock(lpDatablockInfo);
  437. if (lpNewDatablockHeader-> FirstFreeOffset == REG_NULL) {
  438. lpNewDatablockHeader-> FirstFreeOffset = lpDatablockInfo-> BlockSize;
  439. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpNewDatablockHeader +
  440. SmallDword(lpNewDatablockHeader-> FirstFreeOffset));
  441. lpFreeKeyRecord-> DatablockAddress = REG_NULL;
  442. lpFreeKeyRecord-> NextFreeOffset = REG_NULL;
  443. }
  444. else {
  445. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpNewDatablockHeader +
  446. SmallDword(lpNewDatablockHeader-> FirstFreeOffset));
  447. }
  448. lpDatablockInfo-> FreeBytes += (UINT) NewBlockSize - lpDatablockInfo->
  449. BlockSize;
  450. lpFreeKeyRecord-> AllocatedSize = lpDatablockInfo-> FreeBytes;
  451. lpDatablockInfo-> BlockSize = (UINT) NewBlockSize;
  452. lpDatablockInfo-> Flags |= (DIF_DIRTY | DIF_EXTENDED);
  453. lpFileInfo-> Flags |= FI_DIRTY | FI_EXTENDED;
  454. RgDelayFlush();
  455. return ERROR_SUCCESS;
  456. }
  457. //
  458. // RgAllocKeyRecordFromDatablock
  459. //
  460. // Creates an uninitialized KEY_RECORD of the desired size from the provided
  461. // datablock. On exit, only AllocatedSize is valid.
  462. //
  463. // The datablock referred to by lpDatablockInfo must have been locked to
  464. // guarantee that the its data is actually present. The datablock is not
  465. // dirtied.
  466. //
  467. // IMPORTANT: Any datablock may be relocated as a result of calling this
  468. // routine. All pointers to datablocks should be refetched.
  469. //
  470. int
  471. INTERNAL
  472. RgAllocKeyRecordFromDatablock(
  473. LPFILE_INFO lpFileInfo,
  474. UINT BlockIndex,
  475. UINT Length,
  476. LPKEY_RECORD FAR* lplpKeyRecord
  477. )
  478. {
  479. LPDATABLOCK_INFO lpDatablockInfo;
  480. LPDATABLOCK_HEADER lpDatablockHeader;
  481. LPFREEKEY_RECORD lpFreeKeyRecord;
  482. UINT AllocatedSize;
  483. LPFREEKEY_RECORD lpNewFreeKeyRecord;
  484. UINT ExtraBytes;
  485. ASSERT(BlockIndex < lpFileInfo-> FileHeader.BlockCount);
  486. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  487. ASSERT(lpDatablockInfo-> Flags & DIF_PRESENT);
  488. if (Length > lpDatablockInfo-> FreeBytes)
  489. return ERROR_OUTOFMEMORY;
  490. RgCompactDatablock(lpDatablockInfo);
  491. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  492. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpDatablockHeader +
  493. SmallDword(lpDatablockHeader-> FirstFreeOffset));
  494. AllocatedSize = SmallDword(lpFreeKeyRecord-> AllocatedSize);
  495. if (Length > AllocatedSize) {
  496. TRACE(("RgAllocKeyRecordFromDatablock() detected corruption?\n"));
  497. return ERROR_OUTOFMEMORY;
  498. }
  499. ExtraBytes = AllocatedSize - Length;
  500. //
  501. // If we were to break this FREEKEY_RECORD into two records, would the
  502. // second chunk be too small? If so, then don't do it. Just give back
  503. // the full allocated size to the caller.
  504. //
  505. if (ExtraBytes >= MINIMUM_FREE_RECORD_LENGTH) {
  506. lpNewFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpFreeKeyRecord +
  507. Length);
  508. lpDatablockHeader-> FirstFreeOffset += Length;
  509. lpFreeKeyRecord-> AllocatedSize = Length;
  510. // IMPORTANT: Note that lpNewFreeKeyRecord and lpFreeKeyRecord may
  511. // overlap so we have to be careful when changing these fields!
  512. lpNewFreeKeyRecord-> NextFreeOffset = lpFreeKeyRecord-> NextFreeOffset;
  513. lpNewFreeKeyRecord-> DatablockAddress = REG_NULL;
  514. lpNewFreeKeyRecord-> AllocatedSize = ExtraBytes;
  515. }
  516. else {
  517. Length = AllocatedSize;
  518. lpDatablockHeader-> FirstFreeOffset = lpFreeKeyRecord-> NextFreeOffset;
  519. }
  520. // Adjust the number of free bytes in this datablock. At this point,
  521. // Length is equal to the size of the newly formed record.
  522. lpDatablockInfo-> FreeBytes -= Length;
  523. *lplpKeyRecord = (LPKEY_RECORD) lpFreeKeyRecord;
  524. return ERROR_SUCCESS;
  525. }
  526. //
  527. // RgAllocKeyRecordIndex
  528. //
  529. // Allocates a key record index from the provided datablock. If no indexs
  530. // are available in the datablock, then KEY_RECORDS_PER_DATABLOCK is returned.
  531. //
  532. // The datablock referred to by lpDatablockInfo must have been locked to
  533. // guarantee that the its data is actually present. The datablock is not
  534. // dirtied.
  535. //
  536. UINT
  537. INTERNAL
  538. RgAllocKeyRecordIndex(
  539. LPDATABLOCK_INFO lpDatablockInfo
  540. )
  541. {
  542. LPDATABLOCK_HEADER lpDatablockHeader;
  543. UINT KeyRecordIndex;
  544. UINT NextFreeIndex;
  545. LPKEY_RECORD_TABLE_ENTRY lpKeyRecordTableEntry;
  546. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  547. KeyRecordIndex = lpDatablockInfo-> FirstFreeIndex;
  548. NextFreeIndex = KeyRecordIndex + 1;
  549. ASSERT(KeyRecordIndex < KEY_RECORDS_PER_DATABLOCK);
  550. ASSERT(IsNullKeyRecordTableEntry(lpDatablockInfo->
  551. lpKeyRecordTable[KeyRecordIndex]));
  552. if (KeyRecordIndex > lpDatablockHeader-> MaxAllocatedIndex)
  553. lpDatablockHeader-> MaxAllocatedIndex = (WORD) KeyRecordIndex;
  554. else {
  555. // Find the next free hole in the key record table or leave ourselves
  556. // at the end of the table.
  557. for (lpKeyRecordTableEntry =
  558. &lpDatablockInfo-> lpKeyRecordTable[NextFreeIndex]; NextFreeIndex <=
  559. lpDatablockHeader-> MaxAllocatedIndex; NextFreeIndex++,
  560. lpKeyRecordTableEntry++) {
  561. if (IsNullKeyRecordTableEntry(*lpKeyRecordTableEntry))
  562. break;
  563. }
  564. }
  565. lpDatablockInfo-> FirstFreeIndex = NextFreeIndex;
  566. return KeyRecordIndex;
  567. }
  568. //
  569. // RgAllocKeyRecord
  570. //
  571. //
  572. // IMPORTANT: Any datablock may be relocated as a result of calling this
  573. // routine. All pointers to datablocks should be refetched.
  574. //
  575. int
  576. INTERNAL
  577. RgAllocKeyRecord(
  578. LPFILE_INFO lpFileInfo,
  579. UINT Length,
  580. LPKEY_RECORD FAR* lplpKeyRecord
  581. )
  582. {
  583. BOOL fExtendDatablock;
  584. UINT BlockIndex;
  585. LPDATABLOCK_INFO lpDatablockInfo;
  586. UINT KeyRecordIndex;
  587. if (lpFileInfo-> FileHeader.BlockCount == 0)
  588. goto MakeNewDatablock;
  589. //
  590. // Find a datablock that can satisfy the allocation request. Two passes
  591. // may be made over this routine-- during the second pass, datablocks may
  592. // be extended.
  593. //
  594. fExtendDatablock = FALSE;
  595. DoSecondPass:
  596. BlockIndex = lpFileInfo-> FileHeader.BlockCount;
  597. // We overindex by one, but this gets decremented at the start of the loop.
  598. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  599. while (BlockIndex--) {
  600. lpDatablockInfo--;
  601. // Are there any more ids available in this datablock?
  602. if (lpDatablockInfo-> FirstFreeIndex >= KEY_RECORDS_PER_DATABLOCK)
  603. continue;
  604. if (fExtendDatablock) {
  605. // Can we grow this datablock without exceeding the maximum size?
  606. if ((DWORD) (lpDatablockInfo-> BlockSize - lpDatablockInfo->
  607. FreeBytes) + Length > MAXIMUM_DATABLOCK_SIZE)
  608. continue;
  609. } else {
  610. // Is there enough free space in this datablock for this record?
  611. if (Length > lpDatablockInfo-> FreeBytes)
  612. continue;
  613. }
  614. if (RgLockDatablock(lpFileInfo, BlockIndex) == ERROR_SUCCESS) {
  615. if (!fExtendDatablock || RgExtendDatablock(lpFileInfo, BlockIndex,
  616. Length) == ERROR_SUCCESS) {
  617. if (RgAllocKeyRecordFromDatablock(lpFileInfo, BlockIndex,
  618. Length, lplpKeyRecord) == ERROR_SUCCESS)
  619. goto AllocatedKeyRecord;
  620. }
  621. RgUnlockDatablock(lpFileInfo, BlockIndex, FALSE);
  622. }
  623. }
  624. // If we haven't already tried to extend some datablock, make another
  625. // pass over the blocks to do so.
  626. if (!fExtendDatablock) {
  627. fExtendDatablock = TRUE;
  628. goto DoSecondPass;
  629. }
  630. //
  631. // No datablock has enough space to satisfy the request, so attempt to
  632. // create a new one at the end of the file.
  633. //
  634. MakeNewDatablock:
  635. if (RgCreateDatablock(lpFileInfo, Length) == ERROR_SUCCESS) {
  636. BlockIndex = lpFileInfo-> FileHeader.BlockCount - 1;
  637. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  638. if (RgAllocKeyRecordFromDatablock(lpFileInfo, BlockIndex, Length,
  639. lplpKeyRecord) == ERROR_SUCCESS) {
  640. AllocatedKeyRecord:
  641. KeyRecordIndex = RgAllocKeyRecordIndex(lpDatablockInfo);
  642. (*lplpKeyRecord)-> DatablockAddress = MAKELONG(KeyRecordIndex,
  643. BlockIndex);
  644. lpDatablockInfo-> lpKeyRecordTable[KeyRecordIndex] =
  645. (KEY_RECORD_TABLE_ENTRY) ((LPBYTE) (*lplpKeyRecord) -
  646. (LPBYTE) lpDatablockInfo-> lpDatablockHeader);
  647. return ERROR_SUCCESS;
  648. }
  649. RgUnlockDatablock(lpFileInfo, BlockIndex, FALSE);
  650. }
  651. return ERROR_OUTOFMEMORY;
  652. }
  653. //
  654. // RgExtendKeyRecord
  655. //
  656. // Attempts to extend the given KEY_RECORD by combining it with an adjacent
  657. // FREE_RECORD.
  658. //
  659. // The datablock referred to by lpDatablockInfo must have been locked to
  660. // guarantee that the its data is actually present. The datablock is not
  661. // dirtied.
  662. //
  663. // Returns ERROR_SUCCESS if the KEY_RECORD could be extended, else
  664. // ERROR_OUTOFMEMORY.
  665. //
  666. int
  667. INTERNAL
  668. RgExtendKeyRecord(
  669. LPFILE_INFO lpFileInfo,
  670. UINT BlockIndex,
  671. UINT Length,
  672. LPKEY_RECORD lpKeyRecord
  673. )
  674. {
  675. LPDATABLOCK_INFO lpDatablockInfo;
  676. LPDATABLOCK_HEADER lpDatablockHeader;
  677. LPFREEKEY_RECORD lpFreeKeyRecord;
  678. UINT AllocatedSize;
  679. UINT FreeSizeAllocation;
  680. UINT ExtraBytes;
  681. LPFREEKEY_RECORD lpTempFreeKeyRecord;
  682. DWORD NewFreeOffset; // May be REG_NULL
  683. UINT FreeOffset;
  684. DWORD Offset; // May be REG_NULL
  685. ASSERT(BlockIndex < lpFileInfo-> FileHeader.BlockCount);
  686. lpDatablockInfo = RgIndexDatablockInfoPtr(lpFileInfo, BlockIndex);
  687. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  688. AllocatedSize = SmallDword(lpKeyRecord-> AllocatedSize);
  689. lpFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpKeyRecord +
  690. AllocatedSize);
  691. FreeOffset = (LPBYTE) lpFreeKeyRecord - (LPBYTE) lpDatablockHeader;
  692. // Check if this key record is at the very end of the datablock and that
  693. // lpFreeKeyRecord is really a free key record.
  694. if (FreeOffset >= lpDatablockInfo-> BlockSize ||
  695. !IsKeyRecordFree(lpFreeKeyRecord))
  696. return ERROR_OUTOFMEMORY;
  697. ASSERT(Length >= AllocatedSize);
  698. FreeSizeAllocation = Length - AllocatedSize;
  699. AllocatedSize = SmallDword(lpFreeKeyRecord-> AllocatedSize);
  700. if (FreeSizeAllocation > AllocatedSize)
  701. return ERROR_OUTOFMEMORY;
  702. ExtraBytes = AllocatedSize - FreeSizeAllocation;
  703. //
  704. // If we were to break this FREEKEY_RECORD into two records, would the
  705. // second chunk be too small? If so, then don't do it. Just give back
  706. // the full allocated size to the caller.
  707. //
  708. if (ExtraBytes >= MINIMUM_FREE_RECORD_LENGTH) {
  709. NewFreeOffset = FreeOffset + FreeSizeAllocation;
  710. lpTempFreeKeyRecord = (LPFREEKEY_RECORD) ((LPBYTE) lpFreeKeyRecord +
  711. FreeSizeAllocation);
  712. // IMPORTANT: Note that lpNewFreeKeyRecord and lpFreeKeyRecord may
  713. // overlap so we have to be careful when changing these fields!
  714. lpTempFreeKeyRecord-> NextFreeOffset = lpFreeKeyRecord-> NextFreeOffset;
  715. lpTempFreeKeyRecord-> DatablockAddress = REG_NULL;
  716. lpTempFreeKeyRecord-> AllocatedSize = ExtraBytes;
  717. }
  718. else {
  719. NewFreeOffset = lpFreeKeyRecord-> NextFreeOffset;
  720. // The key record's allocated length will also include all of the extra
  721. // bytes.
  722. FreeSizeAllocation += ExtraBytes;
  723. }
  724. lpKeyRecord-> AllocatedSize += FreeSizeAllocation;
  725. lpDatablockInfo-> FreeBytes -= FreeSizeAllocation;
  726. //
  727. // Unlink the free record that we just extended into and possibly link in
  728. // the new FREEKEY_RECORD if a split occurred.
  729. //
  730. Offset = lpDatablockHeader-> FirstFreeOffset;
  731. if (Offset == FreeOffset) {
  732. lpDatablockHeader-> FirstFreeOffset = NewFreeOffset;
  733. }
  734. else {
  735. while (Offset != REG_NULL) {
  736. lpTempFreeKeyRecord =
  737. (LPFREEKEY_RECORD) ((LPBYTE) lpDatablockHeader +
  738. SmallDword(Offset));
  739. Offset = lpTempFreeKeyRecord-> NextFreeOffset;
  740. if (Offset == FreeOffset) {
  741. lpTempFreeKeyRecord-> NextFreeOffset = NewFreeOffset;
  742. break;
  743. }
  744. }
  745. }
  746. return ERROR_SUCCESS;
  747. }
  748. //
  749. // RgFreeKeyRecord
  750. //
  751. // The datablock referred to by lpDatablockInfo must have been locked to
  752. // guarantee that the its data is actually present. The datablock is not
  753. // dirtied.
  754. //
  755. VOID
  756. INTERNAL
  757. RgFreeKeyRecord(
  758. LPDATABLOCK_INFO lpDatablockInfo,
  759. LPKEY_RECORD lpKeyRecord
  760. )
  761. {
  762. LPDATABLOCK_HEADER lpDatablockHeader;
  763. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  764. ((LPFREEKEY_RECORD) lpKeyRecord)-> DatablockAddress = REG_NULL;
  765. ((LPFREEKEY_RECORD) lpKeyRecord)-> NextFreeOffset = lpDatablockHeader->
  766. FirstFreeOffset;
  767. lpDatablockHeader-> FirstFreeOffset = (LPBYTE) lpKeyRecord - (LPBYTE)
  768. lpDatablockHeader;
  769. lpDatablockInfo-> FreeBytes += SmallDword(((LPFREEKEY_RECORD) lpKeyRecord)->
  770. AllocatedSize);
  771. }
  772. //
  773. // RgFreeKeyRecordIndex
  774. //
  775. // The datablock referred to by lpDatablockInfo must have been locked to
  776. // guarantee that the its data is actually present. The datablock is not
  777. // dirtied.
  778. //
  779. // We don't bother updated MaxAllocatedIndex because it's only really useful
  780. // if we're always freeing from the maximum index to zero. This is very
  781. // rarely the case, so no point in keeping that test around or touching the
  782. // datablock header page just to do it.
  783. //
  784. VOID
  785. INTERNAL
  786. RgFreeKeyRecordIndex(
  787. LPDATABLOCK_INFO lpDatablockInfo,
  788. UINT KeyRecordIndex
  789. )
  790. {
  791. ASSERT(lpDatablockInfo-> lpDatablockHeader-> MaxAllocatedIndex >=
  792. KeyRecordIndex);
  793. if (lpDatablockInfo-> FirstFreeIndex > KeyRecordIndex)
  794. lpDatablockInfo-> FirstFreeIndex = KeyRecordIndex;
  795. lpDatablockInfo-> lpKeyRecordTable[KeyRecordIndex] =
  796. NULL_KEY_RECORD_TABLE_ENTRY;
  797. }
  798. //
  799. // RgWriteDatablocks
  800. //
  801. // Writes all dirty datablocks to the file specified by the file handle.
  802. //
  803. int
  804. INTERNAL
  805. RgWriteDatablocks(
  806. LPFILE_INFO lpFileInfo,
  807. HFILE hSourceFile,
  808. HFILE hDestinationFile
  809. )
  810. {
  811. UINT BlockIndex;
  812. LPDATABLOCK_INFO lpDatablockInfo;
  813. LPDATABLOCK_HEADER lpDatablockHeader;
  814. LONG FileOffset;
  815. lpDatablockInfo = lpFileInfo-> lpDatablockInfo;
  816. FileOffset = lpFileInfo-> FileHeader.Size;
  817. for (BlockIndex = 0; BlockIndex < lpFileInfo-> FileHeader.BlockCount;
  818. BlockIndex++, lpDatablockInfo++) {
  819. if (lpDatablockInfo-> Flags & DIF_PRESENT) {
  820. // The block is currently in memory. If we're either extending
  821. // the file or the block is dirty, then write out our in-memory
  822. // copy to disk.
  823. if (hSourceFile != HFILE_ERROR || lpDatablockInfo-> Flags &
  824. DIF_DIRTY) {
  825. NOISE(("writing datablock #%d of ", BlockIndex));
  826. NOISE((lpFileInfo-> FileName));
  827. NOISE(("\n"));
  828. lpDatablockHeader = lpDatablockInfo-> lpDatablockHeader;
  829. // Copy back the fields that we've been maintaining in the
  830. // DATABLOCK_INFO structure.
  831. lpDatablockHeader-> BlockSize = lpDatablockInfo-> BlockSize;
  832. lpDatablockHeader-> FreeBytes = lpDatablockInfo-> FreeBytes;
  833. lpDatablockHeader-> FirstFreeIndex = (WORD) lpDatablockInfo->
  834. FirstFreeIndex;
  835. // The checksum is not currently calculated, so we must clear
  836. // the flag so we don't confuse Win95.
  837. lpDatablockHeader-> Flags &= ~DHF_HASCHECKSUM;
  838. if (!RgSeekFile(hDestinationFile, FileOffset))
  839. return ERROR_REGISTRY_IO_FAILED;
  840. if (!RgWriteFile(hDestinationFile, lpDatablockHeader,
  841. lpDatablockInfo-> BlockSize))
  842. return ERROR_REGISTRY_IO_FAILED;
  843. }
  844. }
  845. else {
  846. // The block is not currently in memory. If we're extending the
  847. // file, then we must write out this datablock. The overhead is
  848. // too great to lock the datablock down, so just copy it from the
  849. // original file to the extended file.
  850. if (hSourceFile != HFILE_ERROR) {
  851. if (RgCopyFileBytes(hSourceFile, lpDatablockInfo-> FileOffset,
  852. hDestinationFile, FileOffset, lpDatablockInfo->
  853. BlockSize) != ERROR_SUCCESS)
  854. return ERROR_REGISTRY_IO_FAILED;
  855. }
  856. }
  857. FileOffset += lpDatablockInfo-> BlockSize;
  858. }
  859. return ERROR_SUCCESS;
  860. }
  861. //
  862. // RgWriteDatablocksComplete
  863. //
  864. // Called after a file has been successfully written. We can now safely clear
  865. // all dirty flags and update our state information with the knowledge that
  866. // the file is in a consistent state.
  867. //
  868. VOID
  869. INTERNAL
  870. RgWriteDatablocksComplete(
  871. LPFILE_INFO lpFileInfo
  872. )
  873. {
  874. UINT BlockIndex;
  875. LPDATABLOCK_INFO lpDatablockInfo;
  876. LONG FileOffset;
  877. lpDatablockInfo = lpFileInfo-> lpDatablockInfo;
  878. FileOffset = lpFileInfo-> FileHeader.Size;
  879. for (BlockIndex = 0; BlockIndex < lpFileInfo-> FileHeader.BlockCount;
  880. BlockIndex++, lpDatablockInfo++) {
  881. lpDatablockInfo-> Flags &= ~DIF_DIRTY;
  882. lpDatablockInfo-> FileOffset = FileOffset;
  883. FileOffset += lpDatablockInfo-> BlockSize;
  884. }
  885. }
  886. //
  887. // RgSweepDatablocks
  888. //
  889. // Makes a pass through all the present datablocks of the given FILE_INFO
  890. // structure and discards datablocks that have not been accessed since the last
  891. // sweep.
  892. //
  893. VOID
  894. INTERNAL
  895. RgSweepDatablocks(
  896. LPFILE_INFO lpFileInfo
  897. )
  898. {
  899. UINT BlocksLeft;
  900. LPDATABLOCK_INFO lpDatablockInfo;
  901. for (BlocksLeft = lpFileInfo-> FileHeader.BlockCount, lpDatablockInfo =
  902. lpFileInfo-> lpDatablockInfo; BlocksLeft > 0; BlocksLeft--,
  903. lpDatablockInfo++) {
  904. if (((lpDatablockInfo-> Flags & (DIF_PRESENT | DIF_ACCESSED |
  905. DIF_DIRTY)) == DIF_PRESENT) && (lpDatablockInfo-> LockCount == 0)) {
  906. NOISE(("discarding datablock #%d of ",
  907. lpFileInfo-> FileHeader.BlockCount - BlocksLeft));
  908. NOISE((lpFileInfo-> FileName));
  909. NOISE(("\n"));
  910. RgFreeDatablockInfoBuffers(lpDatablockInfo);
  911. lpDatablockInfo-> Flags = 0;
  912. }
  913. // Reset the accessed bit for the next sweep.
  914. lpDatablockInfo-> Flags &= ~DIF_ACCESSED;
  915. }
  916. }
  917. //
  918. // RgIsValidDatablockHeader
  919. //
  920. // Returns TRUE if lpDatablockHeader is a valid DATABLOCK_HEADER structure.
  921. //
  922. BOOL
  923. INTERNAL
  924. RgIsValidDatablockHeader(
  925. LPDATABLOCK_HEADER lpDatablockHeader
  926. )
  927. {
  928. if (lpDatablockHeader-> Signature != DH_SIGNATURE ||
  929. HIWORD(lpDatablockHeader-> BlockSize) != 0)
  930. return FALSE;
  931. return TRUE;
  932. }
  933. #ifdef VXD
  934. #pragma VxD_RARE_CODE_SEG
  935. #endif
  936. //
  937. // RgInitDatablockInfo
  938. //
  939. // Initializes fields in the provided FILE_INFO related to the datablocks.
  940. //
  941. int
  942. INTERNAL
  943. RgInitDatablockInfo(
  944. LPFILE_INFO lpFileInfo,
  945. HFILE hFile
  946. )
  947. {
  948. UINT BlockCount;
  949. UINT BlockIndex;
  950. LPDATABLOCK_INFO lpDatablockInfo;
  951. LONG FileOffset;
  952. DATABLOCK_HEADER DatablockHeader;
  953. BlockCount = lpFileInfo-> FileHeader.BlockCount;
  954. if (IsNullPtr((lpDatablockInfo = (LPDATABLOCK_INFO)
  955. RgSmAllocMemory((BlockCount + DATABLOCK_INFO_SLACK_ALLOC) *
  956. sizeof(DATABLOCK_INFO)))))
  957. return ERROR_OUTOFMEMORY;
  958. ZeroMemory(lpDatablockInfo, BlockCount * sizeof(DATABLOCK_INFO));
  959. lpFileInfo-> lpDatablockInfo = lpDatablockInfo;
  960. lpFileInfo-> DatablockInfoAllocCount = BlockCount +
  961. DATABLOCK_INFO_SLACK_ALLOC;
  962. FileOffset = lpFileInfo-> FileHeader.Size;
  963. for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex++,
  964. lpDatablockInfo++) {
  965. if (!RgSeekFile(hFile, FileOffset))
  966. return ERROR_REGISTRY_IO_FAILED;
  967. if (!RgReadFile(hFile, &DatablockHeader, sizeof(DATABLOCK_HEADER)))
  968. return ERROR_REGISTRY_IO_FAILED;
  969. if (!RgIsValidDatablockHeader(&DatablockHeader))
  970. return ERROR_BADDB;
  971. // Following fields already zeroed by above ZeroMemory.
  972. // lpDatablockInfo-> lpDatablockHeader = NULL;
  973. // lpDatablockInfo-> lpKeyRecordTable = NULL;
  974. // lpDatablockInfo-> Flags = 0;
  975. // lpDatablockInfo-> LockCount = 0;
  976. lpDatablockInfo-> FileOffset = FileOffset;
  977. // Cache these fields from the datablock header. These fields should
  978. // not be considered valid when the datablock is physically in memory.
  979. lpDatablockInfo-> BlockSize = SmallDword(DatablockHeader.BlockSize);
  980. lpDatablockInfo-> FreeBytes = SmallDword(DatablockHeader.FreeBytes);
  981. lpDatablockInfo-> FirstFreeIndex = DatablockHeader.FirstFreeIndex;
  982. NOISE(("DB#%d fileoff=%lx, size=%x free=%x 1stindex=%d\n", BlockIndex,
  983. FileOffset, lpDatablockInfo-> BlockSize, lpDatablockInfo->
  984. FreeBytes, lpDatablockInfo-> FirstFreeIndex));
  985. FileOffset += lpDatablockInfo-> BlockSize;
  986. }
  987. return ERROR_SUCCESS;
  988. }