Source code of Windows XP (NT5)
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.

957 lines
28 KiB

  1. //
  2. // REGKNODE.C
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995
  5. //
  6. #include "pch.h"
  7. DECLARE_DEBUG_COUNT(g_RgKeynodeLockCount);
  8. #define HAS_COMPACT_KEYNODES(lpfi) ((lpfi)-> Flags & FI_VERSION20)
  9. #define SIZEOF_KEYNODE_BLOCK(lpfi) \
  10. ((HAS_COMPACT_KEYNODES(lpfi)) ? sizeof(KEYNODE_BLOCK) : sizeof(W95KEYNODE_BLOCK))
  11. #define SIZEOF_FILE_KEYNODE(lpfi) \
  12. ((HAS_COMPACT_KEYNODES(lpfi)) ? sizeof(KEYNODE) : sizeof(W95KEYNODE))
  13. #define ROUND_UP(i, basesize) (((((i) + (basesize) - 1) / (basesize))) * (basesize))
  14. #define BLOCK_DESC_GROW_SIZE 0x400
  15. #define W95KEYNODES_PER_PAGE (PAGESIZE / sizeof(W95KEYNODE))
  16. typedef BOOL (INTERNAL *LPPROCESSKEYNODEPROC)(LPKEYNODE, LPW95KEYNODE);
  17. //
  18. // RgOffsetToIndex
  19. //
  20. DWORD
  21. INTERNAL
  22. RgOffsetToIndex(
  23. DWORD W95KeynodeOffset
  24. )
  25. {
  26. return (W95KeynodeOffset == REG_NULL) ? W95KeynodeOffset :
  27. (W95KeynodeOffset / sizeof(W95KEYNODE));
  28. }
  29. //
  30. // RgIndexToOffset
  31. //
  32. DWORD
  33. INTERNAL
  34. RgIndexToOffset(
  35. DWORD KeynodeIndex
  36. )
  37. {
  38. if (IsNullKeynodeIndex(KeynodeIndex))
  39. return REG_NULL;
  40. else {
  41. if (KeynodeIndex >= 2 * W95KEYNODES_PER_PAGE) {
  42. DWORD dwUnroundedOff = (KeynodeIndex * sizeof(W95KEYNODE))
  43. + sizeof(W95KEYNODE)-1;
  44. DWORD dwRoundPage = ((dwUnroundedOff & PAGEMASK) / sizeof(W95KEYNODE))
  45. * sizeof(W95KEYNODE);
  46. return ((dwUnroundedOff & ~PAGEMASK) + dwRoundPage);
  47. } else {
  48. return (((KeynodeIndex-1)*sizeof(W95KEYNODE))+sizeof(KEYNODE_HEADER));
  49. }
  50. }
  51. }
  52. //
  53. // RgPackKeynode
  54. //
  55. // Packs the data from the provided W95KEYNODE to the KEYNODE structure.
  56. //
  57. BOOL
  58. INTERNAL
  59. RgPackKeynode(
  60. LPKEYNODE lpKeynode,
  61. LPW95KEYNODE lpW95Keynode
  62. )
  63. {
  64. lpKeynode->Flags = 0;
  65. // Don't use a switch statement here. Apparently the compiler will treat
  66. // lpW95Keynode->W95State as an integer, so the 16-bit compiler ends up truncating
  67. // the value.
  68. if (lpW95Keynode->W95State == KNS_USED) {
  69. lpKeynode->Flags = KNF_INUSE;
  70. lpKeynode->ParentIndex = RgOffsetToIndex(lpW95Keynode->W95ParentOffset);
  71. lpKeynode->NextIndex = RgOffsetToIndex(lpW95Keynode->W95NextOffset);
  72. lpKeynode->ChildIndex = RgOffsetToIndex(lpW95Keynode->W95ChildOffset);
  73. lpKeynode->KeyRecordIndex = LOWORD(lpW95Keynode->W95DatablockAddress);
  74. lpKeynode->BlockIndex = HIWORD(lpW95Keynode->W95DatablockAddress);
  75. lpKeynode->Hash = (WORD)lpW95Keynode->W95Hash;
  76. }
  77. else if (lpW95Keynode->W95State == KNS_FREE || lpW95Keynode->W95State ==
  78. KNS_ALLFREE) {
  79. lpKeynode->FreeRecordSize = lpW95Keynode->W95FreeRecordSize;
  80. lpKeynode->NextIndex = RgOffsetToIndex(lpW95Keynode->W95NextFreeOffset);
  81. // Review this later. Previous versions of this code checked
  82. // if the next index was REG_NULL and bailed out of the processing
  83. // loop. It's possible to have a registry with a free keynode sitting
  84. // in the middle of some keynode block and that keynode is the last
  85. // in the chain. We don't want to bail out in those cases.
  86. //
  87. // For now, just bail out if the free record size is greater than a
  88. // couple keynodes indicating that this is probably the last free
  89. // record and the last record of the keynode.
  90. if (lpKeynode-> FreeRecordSize > (sizeof(W95KEYNODE)*2))
  91. return TRUE;
  92. }
  93. else {
  94. DEBUG_OUT(("RgPackKeynode: Unrecognized state (%lx)\n", lpW95Keynode->
  95. W95State));
  96. }
  97. return FALSE;
  98. }
  99. //
  100. // RgUnpackKeynode
  101. //
  102. // Unpacks the data from the provided KEYNODE to the W95KEYNODE structure.
  103. //
  104. BOOL
  105. INTERNAL
  106. RgUnpackKeynode(
  107. LPKEYNODE lpKeynode,
  108. LPW95KEYNODE lpW95Keynode
  109. )
  110. {
  111. if (lpKeynode->Flags & KNF_INUSE) {
  112. lpW95Keynode->W95State = KNS_USED;
  113. lpW95Keynode->W95ParentOffset = RgIndexToOffset(lpKeynode->ParentIndex);
  114. lpW95Keynode->W95NextOffset = RgIndexToOffset(lpKeynode->NextIndex);
  115. lpW95Keynode->W95ChildOffset = RgIndexToOffset(lpKeynode->ChildIndex);
  116. lpW95Keynode->W95Hash = lpKeynode->Hash;
  117. // Handle Win95 registries that don't have a key record for the root
  118. // key. The datablock address must be REG_NULL for Win95 to work.
  119. lpW95Keynode->W95DatablockAddress = IsNullBlockIndex(lpKeynode->
  120. BlockIndex) ? REG_NULL : MAKELONG(lpKeynode-> KeyRecordIndex,
  121. lpKeynode-> BlockIndex);
  122. }
  123. else {
  124. lpW95Keynode->W95State = KNS_FREE;
  125. lpW95Keynode->W95FreeRecordSize = lpKeynode->FreeRecordSize;
  126. lpW95Keynode->W95NextFreeOffset = RgIndexToOffset(lpKeynode->NextIndex);
  127. }
  128. return FALSE;
  129. }
  130. //
  131. // RgProcessKeynodeBlock
  132. //
  133. // The provided callback function is called for each pair of KEYNODE and
  134. // W95KEYNODE structures from the given keynode blocks.
  135. //
  136. VOID
  137. INTERNAL
  138. RgProcessKeynodeBlock(
  139. DWORD dwStartOffset,
  140. DWORD dwBlockSize,
  141. LPKEYNODE_BLOCK lpKeynodeBlock,
  142. LPW95KEYNODE_BLOCK lpW95KeynodeBlock,
  143. LPPROCESSKEYNODEPROC lpfnProcessKeynode
  144. )
  145. {
  146. DWORD dwCurOffset;
  147. LPKEYNODE lpKeynode;
  148. LPW95KEYNODE lpW95Keynode;
  149. UINT SkipSize;
  150. dwCurOffset = dwStartOffset;
  151. lpW95Keynode = &lpW95KeynodeBlock->aW95KN[0];
  152. SkipSize = (dwStartOffset == 0) ? sizeof(KEYNODE_HEADER) : 0;
  153. for (;;) {
  154. lpW95Keynode = (LPW95KEYNODE)(((LPBYTE)lpW95Keynode)+SkipSize);
  155. dwCurOffset += SkipSize;
  156. if (dwCurOffset >= dwStartOffset+dwBlockSize) {
  157. goto Done;
  158. }
  159. lpKeynode = &lpKeynodeBlock->aKN[KN_INDEX_IN_BLOCK(RgOffsetToIndex(dwCurOffset))];
  160. while ((dwCurOffset < dwStartOffset+dwBlockSize) &&
  161. ((dwCurOffset >> PAGESHIFT) == 0) ||
  162. ((dwCurOffset >> PAGESHIFT) ==
  163. ((dwCurOffset + sizeof(W95KEYNODE)) >> PAGESHIFT))) {
  164. if (lpfnProcessKeynode(lpKeynode, lpW95Keynode)) {
  165. goto Done;
  166. }
  167. dwCurOffset += sizeof(W95KEYNODE);
  168. lpW95Keynode++;
  169. lpKeynode++;
  170. }
  171. //
  172. // Compute the number of bytes to skip to get to the next page
  173. //
  174. SkipSize = PAGESIZE - (UINT) (dwCurOffset & PAGEMASK);
  175. }
  176. Done: {};
  177. }
  178. //
  179. // RgLockKeynode
  180. //
  181. int
  182. INTERNAL
  183. RgLockKeynode(
  184. LPFILE_INFO lpFileInfo,
  185. DWORD KeynodeIndex,
  186. LPKEYNODE FAR* lplpKeynode
  187. )
  188. {
  189. int ErrorCode;
  190. UINT KeynodeBlockIndex;
  191. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
  192. UINT KeynodeBlockSize;
  193. HFILE hFile;
  194. LPKEYNODE_BLOCK lpKeynodeBlock;
  195. LPW95KEYNODE_BLOCK lpW95KeynodeBlock;
  196. DWORD BlockOffset;
  197. UINT ReadBlockSize;
  198. KeynodeBlockIndex = KN_BLOCK_NUMBER(KeynodeIndex);
  199. if (KeynodeBlockIndex > lpFileInfo-> KeynodeBlockCount) {
  200. DEBUG_OUT(("RgLockKeynode: invalid keynode offset\n"));
  201. return ERROR_BADDB;
  202. }
  203. //
  204. // Is the keynode block currently in memory?
  205. //
  206. lpKeynodeBlockInfo = RgIndexKeynodeBlockInfoPtr(lpFileInfo,
  207. KeynodeBlockIndex);
  208. lpKeynodeBlock = lpKeynodeBlockInfo-> lpKeynodeBlock;
  209. if (IsNullPtr(lpKeynodeBlock)) {
  210. NOISE(("RgLockKeynode: "));
  211. NOISE((lpFileInfo-> FileName));
  212. NOISE((", block %d\n", KeynodeBlockIndex));
  213. if (IsNullPtr((lpKeynodeBlock = (LPKEYNODE_BLOCK)
  214. RgAllocMemory(sizeof(KEYNODE_BLOCK)))))
  215. return ERROR_OUTOFMEMORY;
  216. KeynodeBlockSize = SIZEOF_KEYNODE_BLOCK(lpFileInfo);
  217. BlockOffset = (DWORD) KeynodeBlockIndex * KeynodeBlockSize;
  218. if (BlockOffset < lpFileInfo-> KeynodeHeader.FileKnSize) {
  219. ASSERT(!(lpFileInfo-> Flags & FI_VOLATILE));
  220. ReadBlockSize = (UINT) min(KeynodeBlockSize, (lpFileInfo->
  221. KeynodeHeader.FileKnSize - BlockOffset));
  222. if ((hFile = RgOpenFile(lpFileInfo-> FileName, OF_READ)) ==
  223. HFILE_ERROR)
  224. goto CleanupAfterFileError;
  225. if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
  226. if (!RgSeekFile(hFile, sizeof(VERSION20_HEADER_PAGE) +
  227. BlockOffset))
  228. goto CleanupAfterFileError;
  229. if (!RgReadFile(hFile, lpKeynodeBlock, ReadBlockSize))
  230. goto CleanupAfterFileError;
  231. }
  232. else {
  233. if (!RgSeekFile(hFile, sizeof(FILE_HEADER) + BlockOffset))
  234. goto CleanupAfterFileError;
  235. lpW95KeynodeBlock = (LPW95KEYNODE_BLOCK) RgLockWorkBuffer();
  236. if (!RgReadFile(hFile, lpW95KeynodeBlock, ReadBlockSize)) {
  237. RgUnlockWorkBuffer(lpW95KeynodeBlock);
  238. goto CleanupAfterFileError;
  239. }
  240. RgProcessKeynodeBlock(BlockOffset, ReadBlockSize,
  241. lpKeynodeBlock, lpW95KeynodeBlock, RgPackKeynode);
  242. RgUnlockWorkBuffer(lpW95KeynodeBlock);
  243. }
  244. RgCloseFile(hFile);
  245. }
  246. lpKeynodeBlockInfo-> lpKeynodeBlock = lpKeynodeBlock;
  247. lpKeynodeBlockInfo-> Flags = 0;
  248. lpKeynodeBlockInfo-> LockCount = 0;
  249. }
  250. *lplpKeynode = &lpKeynodeBlock-> aKN[KN_INDEX_IN_BLOCK(KeynodeIndex)];
  251. lpKeynodeBlockInfo-> Flags |= KBIF_ACCESSED;
  252. lpKeynodeBlockInfo-> LockCount++;
  253. INCREMENT_DEBUG_COUNT(g_RgKeynodeLockCount);
  254. return ERROR_SUCCESS;
  255. CleanupAfterFileError:
  256. ErrorCode = ERROR_REGISTRY_IO_FAILED;
  257. RgFreeMemory(lpKeynodeBlock);
  258. if (hFile != HFILE_ERROR)
  259. RgCloseFile(hFile);
  260. DEBUG_OUT(("RgLockKeynode() returning error %d\n", ErrorCode));
  261. return ErrorCode;
  262. }
  263. //
  264. // RgLockInUseKeynode
  265. //
  266. // Wrapper for RgLockKeynode that guarantees that the returned keynode is
  267. // marked as being in-use. If not, ERROR_BADDB is returned.
  268. //
  269. int
  270. INTERNAL
  271. RgLockInUseKeynode(
  272. LPFILE_INFO lpFileInfo,
  273. DWORD KeynodeIndex,
  274. LPKEYNODE FAR* lplpKeynode
  275. )
  276. {
  277. int ErrorCode;
  278. if ((ErrorCode = RgLockKeynode(lpFileInfo, KeynodeIndex, lplpKeynode)) ==
  279. ERROR_SUCCESS) {
  280. if (!((*lplpKeynode)-> Flags & KNF_INUSE)) {
  281. DEBUG_OUT(("RgLockInUseKeynode: keynode unexpectedly not marked used\n"));
  282. RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
  283. ErrorCode = ERROR_BADDB;
  284. }
  285. }
  286. return ErrorCode;
  287. }
  288. //
  289. // RgUnlockKeynode
  290. //
  291. VOID
  292. INTERNAL
  293. RgUnlockKeynode(
  294. LPFILE_INFO lpFileInfo,
  295. DWORD KeynodeIndex,
  296. BOOL fMarkDirty
  297. )
  298. {
  299. UINT KeynodeBlockIndex;
  300. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
  301. KeynodeBlockIndex = KN_BLOCK_NUMBER(KeynodeIndex);
  302. ASSERT(KeynodeBlockIndex < lpFileInfo-> KeynodeBlockCount);
  303. lpKeynodeBlockInfo = RgIndexKeynodeBlockInfoPtr(lpFileInfo,
  304. KeynodeBlockIndex);
  305. ASSERT(lpKeynodeBlockInfo-> LockCount > 0);
  306. lpKeynodeBlockInfo-> LockCount--;
  307. if (fMarkDirty) {
  308. lpKeynodeBlockInfo-> Flags |= KBIF_DIRTY;
  309. lpFileInfo-> Flags |= FI_DIRTY | FI_KEYNODEDIRTY;
  310. RgDelayFlush();
  311. }
  312. DECREMENT_DEBUG_COUNT(g_RgKeynodeLockCount);
  313. }
  314. //
  315. // RgAllocKeynode
  316. //
  317. int
  318. INTERNAL
  319. RgAllocKeynode(
  320. LPFILE_INFO lpFileInfo,
  321. LPDWORD lpKeynodeIndex,
  322. LPKEYNODE FAR* lplpKeynode
  323. )
  324. {
  325. int ErrorCode;
  326. DWORD FreeKeynodeOffset;
  327. DWORD FreeKeynodeIndex;
  328. UINT FreeRecordSize;
  329. UINT ExtraPadding;
  330. UINT KeynodeBlockIndex;
  331. UINT AllocCount;
  332. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
  333. LPKEYNODE lpKeynode;
  334. DWORD NextFreeKeynodeIndex;
  335. LPKEYNODE lpNextFreeKeynode;
  336. UINT KeynodeSize;
  337. FreeKeynodeIndex = lpFileInfo-> KeynodeHeader.FirstFreeIndex;
  338. // If no more free keynodes exist, then we try to extend the keynode table
  339. // to provide more entries.
  340. if (IsNullKeynodeIndex(FreeKeynodeIndex)) {
  341. if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
  342. FreeKeynodeIndex = ROUND_UP(lpFileInfo-> CurTotalKnSize, PAGESIZE) /
  343. sizeof(KEYNODE);
  344. FreeRecordSize = PAGESIZE;
  345. ExtraPadding = 0;
  346. }
  347. else {
  348. // Handle the special case of a new file being created: for
  349. // uncompacted keynode tables, the first offset is immediately
  350. // after the keynode header and the size of the free record must
  351. // account for the size of this header.
  352. if (lpFileInfo-> CurTotalKnSize == sizeof(KEYNODE_HEADER)) {
  353. FreeKeynodeOffset = sizeof(KEYNODE_HEADER);
  354. // Win95 compatiblity: Same initial table size, plus
  355. // causes us to stress the below special grow case.
  356. FreeRecordSize = PAGESIZE - sizeof(KEYNODE_HEADER) * 2;
  357. ExtraPadding = 0;
  358. }
  359. else {
  360. FreeKeynodeOffset = ROUND_UP(lpFileInfo-> CurTotalKnSize,
  361. PAGESIZE);
  362. FreeRecordSize = PAGESIZE;
  363. ExtraPadding = (UINT) (FreeKeynodeOffset - lpFileInfo->
  364. CurTotalKnSize);
  365. // Handle the case of a keynode table with a non-integral
  366. // number of pages. We'll place the new free keynode at the
  367. // top of the existing keynode table with a size including
  368. // the remaining bytes on the page plus a new page (effectively
  369. // the same as Win95).
  370. if (ExtraPadding > sizeof(W95KEYNODE) || FreeKeynodeOffset ==
  371. PAGESIZE) {
  372. // Although this code will work for any non-integral
  373. // number of pages, it should ONLY occur for <4K tables.
  374. ASSERT(FreeKeynodeOffset == PAGESIZE);
  375. FreeRecordSize += ExtraPadding;
  376. FreeKeynodeOffset = lpFileInfo-> CurTotalKnSize;
  377. ExtraPadding = 0;
  378. }
  379. }
  380. FreeKeynodeIndex = RgOffsetToIndex(FreeKeynodeOffset);
  381. }
  382. KeynodeBlockIndex = KN_BLOCK_NUMBER(FreeKeynodeIndex);
  383. // Check if lpKeynodeBlockInfo is too small to hold the info for a new
  384. // keynode block. If so, then we must grow it a bit.
  385. if (KeynodeBlockIndex >= lpFileInfo-> KeynodeBlockInfoAllocCount) {
  386. AllocCount = KeynodeBlockIndex + KEYNODE_BLOCK_INFO_SLACK_ALLOC;
  387. if (IsNullPtr((lpKeynodeBlockInfo = (LPKEYNODE_BLOCK_INFO)
  388. RgSmReAllocMemory(lpFileInfo-> lpKeynodeBlockInfo, AllocCount *
  389. sizeof(KEYNODE_BLOCK_INFO)))))
  390. return ERROR_OUTOFMEMORY;
  391. ZeroMemory(lpKeynodeBlockInfo + lpFileInfo->
  392. KeynodeBlockInfoAllocCount, (AllocCount - lpFileInfo->
  393. KeynodeBlockInfoAllocCount) * sizeof(KEYNODE_BLOCK_INFO));
  394. lpFileInfo-> lpKeynodeBlockInfo = lpKeynodeBlockInfo;
  395. lpFileInfo-> KeynodeBlockInfoAllocCount = AllocCount;
  396. }
  397. if (KeynodeBlockIndex >= lpFileInfo-> KeynodeBlockCount)
  398. lpFileInfo-> KeynodeBlockCount = KeynodeBlockIndex + 1;
  399. lpFileInfo-> CurTotalKnSize += (FreeRecordSize + ExtraPadding);
  400. lpFileInfo-> Flags |= FI_EXTENDED;
  401. lpFileInfo-> KeynodeHeader.FirstFreeIndex = FreeKeynodeIndex;
  402. if ((ErrorCode = RgLockKeynode(lpFileInfo, FreeKeynodeIndex,
  403. &lpKeynode)) != ERROR_SUCCESS)
  404. return ErrorCode;
  405. lpKeynode-> NextIndex = REG_NULL;
  406. lpKeynode-> Flags = 0;
  407. lpKeynode-> FreeRecordSize = FreeRecordSize;
  408. }
  409. else {
  410. if ((ErrorCode = RgLockKeynode(lpFileInfo, FreeKeynodeIndex,
  411. &lpKeynode)) != ERROR_SUCCESS)
  412. return ErrorCode;
  413. }
  414. NextFreeKeynodeIndex = lpKeynode-> NextIndex;
  415. KeynodeSize = SIZEOF_FILE_KEYNODE(lpFileInfo);
  416. // If the free keynode record can be broken up into smaller chunks, then
  417. // create another free record immediately after the one we're about to
  418. // snag.
  419. if ((lpKeynode-> FreeRecordSize >= KeynodeSize * 2) &&
  420. (RgLockKeynode(lpFileInfo, FreeKeynodeIndex + 1, &lpNextFreeKeynode) ==
  421. ERROR_SUCCESS)) {
  422. // Copy the next link from the current free keynode (likely REG_NULL).
  423. lpNextFreeKeynode-> NextIndex = NextFreeKeynodeIndex;
  424. lpNextFreeKeynode-> Flags = 0;
  425. lpNextFreeKeynode-> FreeRecordSize = lpKeynode-> FreeRecordSize -
  426. KeynodeSize;
  427. NextFreeKeynodeIndex = FreeKeynodeIndex + 1;
  428. RgUnlockKeynode(lpFileInfo, NextFreeKeynodeIndex, TRUE);
  429. }
  430. lpFileInfo-> KeynodeHeader.FirstFreeIndex = NextFreeKeynodeIndex;
  431. lpKeynode-> Flags |= KNF_INUSE;
  432. // Mark the keynode block that holds this keynode dirty.
  433. lpKeynodeBlockInfo = RgIndexKeynodeBlockInfoPtr(lpFileInfo,
  434. KN_BLOCK_NUMBER(FreeKeynodeIndex));
  435. lpKeynodeBlockInfo-> Flags |= KBIF_DIRTY;
  436. lpFileInfo-> Flags |= FI_DIRTY | FI_KEYNODEDIRTY;
  437. RgDelayFlush();
  438. // WARNING: The following two statements used to be above the block that
  439. // dirtied the keynode. The 16-bit compiler messed up and
  440. // lpKeynodeBlockInfo ended up with a bogus offset thus corrupting random
  441. // memory. Be sure to trace through this function if you change it!
  442. *lpKeynodeIndex = FreeKeynodeIndex;
  443. *lplpKeynode = lpKeynode;
  444. return ERROR_SUCCESS;
  445. }
  446. //
  447. // RgFreeKeynode
  448. //
  449. // Marks the specified keynode index free and adds it to the hive's free
  450. // keynode list.
  451. //
  452. int
  453. INTERNAL
  454. RgFreeKeynode(
  455. LPFILE_INFO lpFileInfo,
  456. DWORD KeynodeIndex
  457. )
  458. {
  459. int ErrorCode;
  460. LPKEYNODE lpKeynode;
  461. if ((ErrorCode = RgLockKeynode(lpFileInfo, KeynodeIndex, &lpKeynode)) ==
  462. ERROR_SUCCESS) {
  463. lpKeynode-> Flags &= ~KNF_INUSE;
  464. lpKeynode-> NextIndex = lpFileInfo-> KeynodeHeader.FirstFreeIndex;
  465. lpKeynode-> FreeRecordSize = SIZEOF_FILE_KEYNODE(lpFileInfo);
  466. lpFileInfo-> KeynodeHeader.FirstFreeIndex = KeynodeIndex;
  467. RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE);
  468. }
  469. return ErrorCode;
  470. }
  471. //
  472. // RgGetKnBlockIOInfo
  473. //
  474. VOID
  475. INTERNAL
  476. RgGetKnBlockIOInfo(
  477. LPFILE_INFO lpFileInfo,
  478. DWORD BaseKeynodeIndex,
  479. UINT FAR* lpFileBlockSize,
  480. LONG FAR* lpFileOffset
  481. )
  482. {
  483. UINT FileBlockSize;
  484. DWORD FileOffset;
  485. DWORD BaseKeynodeOffset;
  486. if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
  487. FileBlockSize = sizeof(KEYNODE_BLOCK);
  488. BaseKeynodeOffset = BaseKeynodeIndex * sizeof(KEYNODE);
  489. if (BaseKeynodeOffset + FileBlockSize > lpFileInfo-> CurTotalKnSize)
  490. FileBlockSize = (UINT) (lpFileInfo-> CurTotalKnSize -
  491. BaseKeynodeOffset);
  492. FileOffset = sizeof(VERSION20_HEADER_PAGE) + BaseKeynodeIndex *
  493. sizeof(KEYNODE);
  494. }
  495. else {
  496. FileBlockSize = sizeof(W95KEYNODE_BLOCK);
  497. // The first keynode block of an uncompacted keynode table should
  498. // start writing AFTER the keynode header.
  499. if (BaseKeynodeIndex == 0) {
  500. BaseKeynodeIndex = RgOffsetToIndex(sizeof(KEYNODE_HEADER));
  501. FileBlockSize -= sizeof(KEYNODE_HEADER);
  502. }
  503. BaseKeynodeOffset = RgIndexToOffset(BaseKeynodeIndex);
  504. if (BaseKeynodeOffset + FileBlockSize > lpFileInfo-> CurTotalKnSize)
  505. FileBlockSize = (UINT) (lpFileInfo-> CurTotalKnSize -
  506. BaseKeynodeOffset);
  507. FileOffset = sizeof(FILE_HEADER) + BaseKeynodeOffset;
  508. }
  509. *lpFileBlockSize = FileBlockSize;
  510. *lpFileOffset = FileOffset;
  511. }
  512. int
  513. _inline
  514. RgCopyKeynodeBlock(
  515. LPFILE_INFO lpFileInfo,
  516. DWORD BaseIndex,
  517. HFILE hSrcFile,
  518. HFILE hDestFile
  519. )
  520. {
  521. UINT FileBlockSize;
  522. LONG FileOffset;
  523. RgGetKnBlockIOInfo(lpFileInfo, BaseIndex, &FileBlockSize, &FileOffset);
  524. return RgCopyFileBytes(hSrcFile,
  525. FileOffset,
  526. hDestFile,
  527. FileOffset,
  528. FileBlockSize);
  529. }
  530. //
  531. // RgWriteKeynodeBlock
  532. //
  533. int
  534. INTERNAL
  535. RgWriteKeynodeBlock(
  536. LPFILE_INFO lpFileInfo,
  537. DWORD BaseIndex,
  538. HFILE hDestFile,
  539. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo
  540. )
  541. {
  542. int ErrorCode;
  543. UINT FileBlockSize;
  544. LONG FileOffset;
  545. LPW95KEYNODE_BLOCK lpW95KeynodeBlock;
  546. RgGetKnBlockIOInfo(lpFileInfo, BaseIndex, &FileBlockSize, &FileOffset);
  547. ErrorCode = ERROR_REGISTRY_IO_FAILED; // Assume I/O fails
  548. if (!RgSeekFile(hDestFile, FileOffset)) {
  549. goto Exit;
  550. }
  551. if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
  552. if (RgWriteFile(hDestFile, lpKeynodeBlockInfo->lpKeynodeBlock, FileBlockSize)) {
  553. ErrorCode = ERROR_SUCCESS;
  554. }
  555. } else {
  556. LPBYTE lpWriteBlock;
  557. lpW95KeynodeBlock = (LPW95KEYNODE_BLOCK) RgLockWorkBuffer();
  558. RgProcessKeynodeBlock(
  559. BaseIndex * sizeof(W95KEYNODE),
  560. FileBlockSize,
  561. lpKeynodeBlockInfo->lpKeynodeBlock,
  562. lpW95KeynodeBlock,
  563. RgUnpackKeynode);
  564. lpWriteBlock = (LPBYTE)lpW95KeynodeBlock;
  565. if (BaseIndex == 0) {
  566. lpWriteBlock += sizeof(KEYNODE_HEADER);
  567. }
  568. if (RgWriteFile(hDestFile, lpWriteBlock, FileBlockSize)) {
  569. ErrorCode = ERROR_SUCCESS;
  570. }
  571. RgUnlockWorkBuffer(lpW95KeynodeBlock);
  572. }
  573. Exit: ;
  574. return (ErrorCode);
  575. }
  576. //
  577. // RgWriteKeynodes
  578. //
  579. int
  580. INTERNAL
  581. RgWriteKeynodes(
  582. LPFILE_INFO lpFileInfo,
  583. HFILE hSrcFile,
  584. HFILE hDestFile
  585. )
  586. {
  587. DWORD SavedRootIndex;
  588. DWORD SavedFreeIndex;
  589. DWORD SavedFileKnSize;
  590. BOOL fResult;
  591. UINT KeynodeBlockIndex;
  592. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
  593. if ((hSrcFile == HFILE_ERROR) && !(lpFileInfo->Flags & FI_KEYNODEDIRTY))
  594. return ERROR_SUCCESS;
  595. NOISE(("writing keynodes of "));
  596. NOISE((lpFileInfo-> FileName));
  597. NOISE(("\n"));
  598. //
  599. // Write out the keynode header. If the keynodes are not compact then
  600. // convert to offsets before writing.
  601. //
  602. if (!RgSeekFile(hDestFile, sizeof(FILE_HEADER)))
  603. return ERROR_REGISTRY_IO_FAILED;
  604. SavedFileKnSize = lpFileInfo-> KeynodeHeader.FileKnSize;
  605. SavedRootIndex = lpFileInfo-> KeynodeHeader.RootIndex;
  606. SavedFreeIndex = lpFileInfo-> KeynodeHeader.FirstFreeIndex;
  607. // Write the real size of the keynode table to disk.
  608. lpFileInfo-> KeynodeHeader.FileKnSize = lpFileInfo-> CurTotalKnSize;
  609. // Convert keynode indexes back to offsets temporarily for uncompacted
  610. // keynode tables.
  611. if (!HAS_COMPACT_KEYNODES(lpFileInfo)) {
  612. lpFileInfo-> KeynodeHeader.RootIndex = RgIndexToOffset(lpFileInfo->
  613. KeynodeHeader.RootIndex);
  614. lpFileInfo-> KeynodeHeader.FirstFreeIndex = RgIndexToOffset(lpFileInfo->
  615. KeynodeHeader.FirstFreeIndex);
  616. }
  617. fResult = RgWriteFile(hDestFile, &lpFileInfo-> KeynodeHeader,
  618. sizeof(KEYNODE_HEADER));
  619. lpFileInfo-> KeynodeHeader.FileKnSize = SavedFileKnSize;
  620. lpFileInfo-> KeynodeHeader.RootIndex = SavedRootIndex;
  621. lpFileInfo-> KeynodeHeader.FirstFreeIndex = SavedFreeIndex;
  622. if (!fResult)
  623. return ERROR_REGISTRY_IO_FAILED;
  624. //
  625. // Now loop through each block.
  626. //
  627. lpKeynodeBlockInfo = lpFileInfo-> lpKeynodeBlockInfo;
  628. for (KeynodeBlockIndex = 0; KeynodeBlockIndex < lpFileInfo->
  629. KeynodeBlockCount; KeynodeBlockIndex++, lpKeynodeBlockInfo++) {
  630. DWORD BaseKeynodeIndex = KeynodeBlockIndex * KEYNODES_PER_BLOCK;
  631. if (!IsNullPtr(lpKeynodeBlockInfo-> lpKeynodeBlock)) {
  632. if (hSrcFile != HFILE_ERROR || lpKeynodeBlockInfo-> Flags &
  633. KBIF_DIRTY) {
  634. if (RgWriteKeynodeBlock(lpFileInfo, BaseKeynodeIndex, hDestFile,
  635. lpKeynodeBlockInfo) != ERROR_SUCCESS)
  636. return ERROR_REGISTRY_IO_FAILED;
  637. }
  638. }
  639. else {
  640. if (hSrcFile != HFILE_ERROR) {
  641. if (RgCopyKeynodeBlock(lpFileInfo, BaseKeynodeIndex, hSrcFile,
  642. hDestFile) != ERROR_SUCCESS)
  643. return ERROR_REGISTRY_IO_FAILED;
  644. }
  645. }
  646. }
  647. return ERROR_SUCCESS;
  648. }
  649. //
  650. // RgWriteKeynodesComplete
  651. //
  652. // Called after a file has been successfully written. We can now safely clear
  653. // all dirty flags and update our state information with the knowledge that
  654. // the file is in a consistent state.
  655. //
  656. VOID
  657. INTERNAL
  658. RgWriteKeynodesComplete(
  659. LPFILE_INFO lpFileInfo
  660. )
  661. {
  662. UINT BlocksLeft;
  663. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
  664. lpFileInfo-> Flags &= ~FI_KEYNODEDIRTY;
  665. lpFileInfo-> KeynodeHeader.FileKnSize = lpFileInfo-> CurTotalKnSize;
  666. for (BlocksLeft = lpFileInfo-> KeynodeBlockCount, lpKeynodeBlockInfo =
  667. lpFileInfo-> lpKeynodeBlockInfo; BlocksLeft > 0; BlocksLeft--,
  668. lpKeynodeBlockInfo++)
  669. lpKeynodeBlockInfo-> Flags &= ~KBIF_DIRTY;
  670. }
  671. //
  672. // RgSweepKeynodes
  673. //
  674. // Makes a pass through all the present keynode blocks of the given FILE_INFO
  675. // structure and discards keynode blocks that have not been accessed since the
  676. // last sweep.
  677. //
  678. VOID
  679. INTERNAL
  680. RgSweepKeynodes(
  681. LPFILE_INFO lpFileInfo
  682. )
  683. {
  684. UINT BlocksLeft;
  685. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
  686. for (BlocksLeft = lpFileInfo-> KeynodeBlockCount, lpKeynodeBlockInfo =
  687. lpFileInfo-> lpKeynodeBlockInfo; BlocksLeft > 0; BlocksLeft--,
  688. lpKeynodeBlockInfo++) {
  689. if (!IsNullPtr(lpKeynodeBlockInfo-> lpKeynodeBlock)) {
  690. if (((lpKeynodeBlockInfo-> Flags & (KBIF_ACCESSED | KBIF_DIRTY)) ==
  691. 0) && (lpKeynodeBlockInfo-> LockCount == 0)) {
  692. RgFreeMemory(lpKeynodeBlockInfo-> lpKeynodeBlock);
  693. lpKeynodeBlockInfo-> lpKeynodeBlock = NULL;
  694. }
  695. lpKeynodeBlockInfo-> Flags &= ~KBIF_ACCESSED;
  696. }
  697. }
  698. }
  699. #ifdef VXD
  700. #pragma VxD_RARE_CODE_SEG
  701. #endif
  702. //
  703. // RgInitKeynodeInfo
  704. //
  705. // Initializes fields in the provided FILE_INFO related to the keynode table.
  706. //
  707. int
  708. INTERNAL
  709. RgInitKeynodeInfo(
  710. LPFILE_INFO lpFileInfo
  711. )
  712. {
  713. UINT KeynodeBlockSize;
  714. UINT BlockCount;
  715. UINT AllocCount;
  716. LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
  717. KeynodeBlockSize = SIZEOF_KEYNODE_BLOCK(lpFileInfo);
  718. BlockCount = (UINT) ((DWORD) (lpFileInfo-> KeynodeHeader.FileKnSize +
  719. KeynodeBlockSize - 1) / (DWORD) KeynodeBlockSize);
  720. AllocCount = BlockCount + KEYNODE_BLOCK_INFO_SLACK_ALLOC;
  721. if (IsNullPtr((lpKeynodeBlockInfo = (LPKEYNODE_BLOCK_INFO)
  722. RgSmAllocMemory(AllocCount * sizeof(KEYNODE_BLOCK_INFO)))))
  723. return ERROR_OUTOFMEMORY;
  724. ZeroMemory(lpKeynodeBlockInfo, AllocCount * sizeof(KEYNODE_BLOCK_INFO));
  725. lpFileInfo-> lpKeynodeBlockInfo = lpKeynodeBlockInfo;
  726. lpFileInfo-> KeynodeBlockCount = BlockCount;
  727. lpFileInfo-> KeynodeBlockInfoAllocCount = AllocCount;
  728. lpFileInfo-> KeynodeHeader.Flags &= ~(KHF_DIRTY | KHF_EXTENDED |
  729. KHF_HASCHECKSUM);
  730. // Convert file offsets to index values for uncompressed files
  731. if (!HAS_COMPACT_KEYNODES(lpFileInfo)) {
  732. lpFileInfo-> KeynodeHeader.RootIndex = RgOffsetToIndex(lpFileInfo->
  733. KeynodeHeader.RootIndex);
  734. lpFileInfo-> KeynodeHeader.FirstFreeIndex = RgOffsetToIndex(lpFileInfo->
  735. KeynodeHeader.FirstFreeIndex);
  736. }
  737. lpFileInfo-> CurTotalKnSize = lpFileInfo-> KeynodeHeader.FileKnSize;
  738. return ERROR_SUCCESS;
  739. }