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.

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