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.

591 lines
18 KiB

  1. //
  2. // REGSVAL.C
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995
  5. //
  6. // Implementation of RegSetValue, RegSetValueEx and supporting functions.
  7. //
  8. #include "pch.h"
  9. //
  10. // RgReAllocKeyRecord
  11. //
  12. int
  13. INTERNAL
  14. RgReAllocKeyRecord(
  15. HKEY hKey,
  16. DWORD Length,
  17. LPKEY_RECORD FAR* lplpKeyRecord
  18. )
  19. {
  20. int ErrorCode;
  21. LPKEY_RECORD lpOldKeyRecord;
  22. UINT BlockIndex;
  23. UINT KeyRecordIndex;
  24. LPDATABLOCK_INFO lpOldDatablockInfo;
  25. LPKEYNODE lpKeynode;
  26. if (Length > MAXIMUM_KEY_RECORD_SIZE) {
  27. return ERROR_BIGKEY_NEEDED; // A big key is required
  28. }
  29. lpOldKeyRecord = *lplpKeyRecord;
  30. BlockIndex = HIWORD(lpOldKeyRecord-> DatablockAddress);
  31. KeyRecordIndex = LOWORD(lpOldKeyRecord-> DatablockAddress);
  32. //
  33. // Check if we can simply extend this key record by taking space from an
  34. // adjacent free record.
  35. //
  36. if (RgExtendKeyRecord(hKey-> lpFileInfo, BlockIndex, (UINT) Length,
  37. lpOldKeyRecord) == ERROR_SUCCESS)
  38. return ERROR_SUCCESS;
  39. //
  40. // Check if there's enough space in the datablock lpCurrKeyRecord is in to
  41. // contain a key record of the specified size. If so, then we don't have
  42. // to dirty the keynode.
  43. //
  44. if (RgAllocKeyRecordFromDatablock(hKey-> lpFileInfo, BlockIndex,
  45. (UINT) Length, lplpKeyRecord) == ERROR_SUCCESS) {
  46. // After an alloc, we must refetch these pointers because they may be
  47. // invalid.
  48. lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
  49. BlockIndex);
  50. lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
  51. KeyRecordIndex);
  52. // Transfer all the data to the new record, except for the allocated
  53. // size which is already correctly set.
  54. MoveMemory(&(*lplpKeyRecord)-> DatablockAddress, &lpOldKeyRecord->
  55. DatablockAddress, SmallDword(lpOldKeyRecord-> RecordSize) -
  56. sizeof(DWORD));
  57. RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
  58. // Update the key record table to point to the new key record.
  59. lpOldDatablockInfo-> lpKeyRecordTable[KeyRecordIndex] =
  60. (KEY_RECORD_TABLE_ENTRY) ((LPBYTE) (*lplpKeyRecord) -
  61. (LPBYTE) lpOldDatablockInfo-> lpDatablockHeader);
  62. return ERROR_SUCCESS;
  63. }
  64. //
  65. // Check if we can allocate a key record from another datablock. If so,
  66. // then copy the key to the other datablock and update the keynode.
  67. //
  68. if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  69. &lpKeynode) == ERROR_SUCCESS) {
  70. if ((ErrorCode = RgAllocKeyRecord(hKey-> lpFileInfo, (UINT) Length,
  71. lplpKeyRecord)) == ERROR_SUCCESS) {
  72. // After an alloc, we must refetch these pointers because they may
  73. // be invalid.
  74. lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
  75. BlockIndex);
  76. lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
  77. KeyRecordIndex);
  78. // Transfer all the data to the new record, except for the
  79. // allocated size which is already correctly set.
  80. MoveMemory(&(*lplpKeyRecord)-> RecordSize, &lpOldKeyRecord->
  81. RecordSize, SmallDword(lpOldKeyRecord-> RecordSize) -
  82. (sizeof(DWORD) * 2));
  83. RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
  84. RgFreeKeyRecordIndex(lpOldDatablockInfo, KeyRecordIndex);
  85. // Unlock the old datablock.
  86. RgUnlockDatablock(hKey-> lpFileInfo, BlockIndex, TRUE);
  87. // Update the open key and keynode to point to the key record in
  88. // the new datablock.
  89. hKey-> BlockIndex = (*lplpKeyRecord)-> BlockIndex;
  90. hKey-> BigKeyLockedBlockIndex = hKey-> BlockIndex;
  91. lpKeynode-> BlockIndex = hKey-> BlockIndex;
  92. hKey-> KeyRecordIndex = (BYTE) (*lplpKeyRecord)-> KeyRecordIndex;
  93. lpKeynode-> KeyRecordIndex = hKey-> KeyRecordIndex;
  94. }
  95. RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
  96. return ErrorCode;
  97. }
  98. return ERROR_OUTOFMEMORY;
  99. }
  100. //
  101. // RgSetValue
  102. // (BIGKEY aware)
  103. //
  104. int
  105. INTERNAL
  106. RgSetValue(
  107. HKEY hKey,
  108. LPCSTR lpValueName,
  109. DWORD Type,
  110. LPBYTE lpData,
  111. UINT cbData
  112. )
  113. {
  114. int ErrorCode;
  115. HKEY hKeyExtent;
  116. UINT Index;
  117. LPSTR ExtentKeyName;
  118. DWORD cbExtentKeyName;
  119. WORD NameID = 1;
  120. WORD MaxNameID = 0;
  121. LPKEY_RECORD lpKeyRecord;
  122. LPVALUE_RECORD lpValueRecord;
  123. LPKEYNODE lpKeynode;
  124. BOOL fTryRoot = FALSE;
  125. ErrorCode = RgSetValueStd(hKey, lpValueName, Type, lpData, cbData, FALSE);
  126. if (ErrorCode == ERROR_BIGKEY_NEEDED)
  127. {
  128. //
  129. // Couldn't fit the value in the key, make it a big key
  130. // (if it isn't one already)
  131. //
  132. // First delete its old value if it exists
  133. ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord,
  134. &lpValueRecord);
  135. if (ErrorCode == ERROR_SUCCESS)
  136. {
  137. // If a value record already existed, and it was not in the root of the big key
  138. // then we should try inserting the new value record into the root, after deleting
  139. // it from its old location.
  140. if (hKey-> BigKeyLockedBlockIndex != hKey-> BlockIndex)
  141. fTryRoot = TRUE;
  142. RgDeleteValueRecord(lpKeyRecord, lpValueRecord);
  143. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, TRUE);
  144. }
  145. else if (ErrorCode != ERROR_CANTREAD16_FILENOTFOUND32) {
  146. return ERROR_OUTOFMEMORY;
  147. }
  148. if (IsNullPtr(ExtentKeyName = RgSmAllocMemory(MAXIMUM_SUB_KEY_LENGTH)))
  149. return ERROR_OUTOFMEMORY;
  150. // Second, search for room in each of the big key's extents
  151. // (we should never mark the root with an LK_BIGKEYEXT, otherwise it won't be found
  152. // by RgLookupKey and RgLookupKeyByIndex)
  153. if ((hKey-> Flags & KEYF_BIGKEYROOT)) {
  154. if (fTryRoot) {
  155. // This happens if the value record previously existed in a big key extension,
  156. // but the new value record doesn't fit in the same extension, so we want to try
  157. // the root of the big key.
  158. if ((ErrorCode = RgSetValueStd(hKey, lpValueName, Type, lpData, cbData, TRUE)) ==
  159. ERROR_SUCCESS) {
  160. goto lFreeKeyName;
  161. }
  162. }
  163. Index = 0;
  164. do {
  165. cbExtentKeyName = MAXIMUM_SUB_KEY_LENGTH;
  166. if (RgLookupKeyByIndex(hKey, Index++, ExtentKeyName, &cbExtentKeyName, LK_BIGKEYEXT) !=
  167. ERROR_SUCCESS) {
  168. goto lGrowKey;
  169. }
  170. NameID = RgAtoW(ExtentKeyName);
  171. if (NameID > MaxNameID)
  172. MaxNameID = NameID;
  173. if (RgLookupKey(hKey, ExtentKeyName, &hKeyExtent, LK_OPEN | LK_BIGKEYEXT) != ERROR_SUCCESS) {
  174. goto lGrowKey;
  175. }
  176. ErrorCode = RgSetValueStd(hKeyExtent, lpValueName, Type, lpData, cbData, TRUE);
  177. RgDestroyKeyHandle(hKeyExtent);
  178. } while (ErrorCode == ERROR_BIGKEY_NEEDED);
  179. goto lFreeKeyName;
  180. }
  181. // Third, make it a big key, or if it is a big key, then grow it
  182. lGrowKey:
  183. // Create a unique name for the big key extent
  184. if (MaxNameID)
  185. NameID = MaxNameID + 1;
  186. RgWtoA(NameID, ExtentKeyName);
  187. if ((ErrorCode = RgLookupKey(hKey, ExtentKeyName, &hKeyExtent, LK_CREATE)) ==
  188. ERROR_SUCCESS) {
  189. // Mark the parent as the big key root, if it isn't already
  190. if (!(hKey-> Flags & KEYF_BIGKEYROOT))
  191. {
  192. if ((ErrorCode = RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  193. &lpKeynode)) != ERROR_SUCCESS)
  194. goto lFreeKeyName;
  195. lpKeynode-> Flags |= KNF_BIGKEYROOT;
  196. hKey-> Flags |= KEYF_BIGKEYROOT;
  197. RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
  198. }
  199. // Mark the new key as a big key extent
  200. if ((ErrorCode = RgLockInUseKeynode(hKeyExtent-> lpFileInfo, hKeyExtent-> KeynodeIndex,
  201. &lpKeynode)) != ERROR_SUCCESS)
  202. goto lFreeKeyName;
  203. lpKeynode-> Flags |= KNF_BIGKEYEXT;
  204. RgUnlockKeynode(hKeyExtent-> lpFileInfo, hKeyExtent-> KeynodeIndex, TRUE);
  205. // Now add the value record to the new key
  206. ErrorCode = RgSetValueStd(hKeyExtent, lpValueName, Type, lpData, cbData, TRUE);
  207. ASSERT(ErrorCode != ERROR_BIGKEY_NEEDED);
  208. RgDestroyKeyHandle(hKeyExtent);
  209. }
  210. lFreeKeyName:
  211. RgSmFreeMemory(ExtentKeyName);
  212. if (ErrorCode == ERROR_BIGKEY_NEEDED)
  213. ErrorCode = ERROR_OUTOFMEMORY;
  214. }
  215. return ErrorCode;
  216. }
  217. //
  218. // RgSetValueStd
  219. //
  220. int
  221. INTERNAL
  222. RgSetValueStd(
  223. HKEY hKey,
  224. LPCSTR lpValueName,
  225. DWORD Type,
  226. LPBYTE lpData,
  227. UINT cbData,
  228. BOOL fBigKeyExtent
  229. )
  230. {
  231. int ErrorCode;
  232. UINT ValueNameLength;
  233. UINT NewValueRecordLength;
  234. LPKEY_RECORD lpKeyRecord;
  235. LPVALUE_RECORD lpValueRecord;
  236. UINT CurrentValueRecordLength;
  237. LPBYTE lpDestination;
  238. UINT BytesToExtend;
  239. UINT TempCount;
  240. LPKEYNODE lpKeynode;
  241. ValueNameLength = (IsNullPtr(lpValueName) ? 0 : (UINT) StrLen(lpValueName));
  242. if (ValueNameLength > MAXIMUM_VALUE_NAME_LENGTH - 1)
  243. return ERROR_INVALID_PARAMETER;
  244. NewValueRecordLength = sizeof(VALUE_RECORD) + ValueNameLength + cbData - 1;
  245. if (!fBigKeyExtent) {
  246. ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord,
  247. &lpValueRecord);
  248. }
  249. else {
  250. // If we didn't find it searching from the root of a bigkey, then we won't
  251. // find it beginning from an extent.
  252. ErrorCode = ERROR_CANTREAD16_FILENOTFOUND32;
  253. }
  254. //
  255. // A value with this name already exists, so update the existing
  256. // VALUE_RECORD with the new information.
  257. //
  258. if (ErrorCode == ERROR_SUCCESS) {
  259. CurrentValueRecordLength = sizeof(VALUE_RECORD) + lpValueRecord->
  260. NameLength + lpValueRecord-> DataLength - 1;
  261. // Is the value record staying the same?
  262. if (NewValueRecordLength == CurrentValueRecordLength) {
  263. if (lpValueRecord-> DataLength == cbData && lpValueRecord->
  264. DataType == Type && CompareMemory((LPBYTE) lpValueRecord->
  265. Name + ValueNameLength, lpData, cbData) == 0) {
  266. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, FALSE);
  267. return ERROR_SUCCESS;
  268. }
  269. }
  270. // Is the value record shrinking?
  271. if (NewValueRecordLength < CurrentValueRecordLength) {
  272. lpKeyRecord-> RecordSize -= (CurrentValueRecordLength -
  273. NewValueRecordLength);
  274. }
  275. // Is the value record growing?
  276. else if (NewValueRecordLength > CurrentValueRecordLength) {
  277. BytesToExtend = NewValueRecordLength - CurrentValueRecordLength;
  278. // Does the value record fit in the allocated key size?
  279. if (BytesToExtend > SmallDword(lpKeyRecord-> AllocatedSize) -
  280. SmallDword(lpKeyRecord-> RecordSize)) {
  281. TempCount = (LPBYTE) lpValueRecord - (LPBYTE) lpKeyRecord;
  282. // Grow the key record
  283. if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
  284. RecordSize + BytesToExtend, &lpKeyRecord)) !=
  285. ERROR_SUCCESS) {
  286. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex,
  287. FALSE);
  288. return ErrorCode;
  289. }
  290. lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
  291. TempCount);
  292. }
  293. lpKeyRecord-> RecordSize += BytesToExtend;
  294. }
  295. lpDestination = (LPBYTE) lpValueRecord + NewValueRecordLength;
  296. TempCount = (UINT) ((LPBYTE) lpKeyRecord + SmallDword(lpKeyRecord->
  297. RecordSize) - lpDestination);
  298. if (TempCount > 0) {
  299. MoveMemory(lpDestination, (LPBYTE) lpValueRecord +
  300. CurrentValueRecordLength, TempCount);
  301. }
  302. }
  303. //
  304. // No value exists with this name. Place a new VALUE_RECORD at the end of
  305. // the KEY_RECORD.
  306. //
  307. else if (ErrorCode == ERROR_CANTREAD16_FILENOTFOUND32) {
  308. // Handle Win95 registries that don't have a key record for the root
  309. // key. We don't check if this is really the root key, but it doesn't
  310. // matter much.
  311. if (IsNullBlockIndex(hKey-> BlockIndex)) {
  312. if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  313. &lpKeynode) != ERROR_SUCCESS)
  314. goto LockKeynodeFailed;
  315. if (RgAllocKeyRecord(hKey-> lpFileInfo, sizeof(KEY_RECORD) +
  316. NewValueRecordLength, &lpKeyRecord) != ERROR_SUCCESS) {
  317. RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, FALSE);
  318. LockKeynodeFailed:
  319. TRAP();
  320. return ERROR_CANTOPEN; // Win95 compatibility
  321. }
  322. lpKeyRecord-> RecordSize = sizeof(KEY_RECORD);
  323. lpKeyRecord-> NameLength = 1; // Win95 compatibility
  324. lpKeyRecord-> Name[0] = '\0'; // Win95 compatibility
  325. lpKeyRecord-> ValueCount = 0;
  326. lpKeyRecord-> ClassLength = 0;
  327. lpKeyRecord-> Reserved = 0;
  328. lpKeynode-> BlockIndex = lpKeyRecord-> BlockIndex;
  329. lpKeynode-> KeyRecordIndex = lpKeyRecord-> KeyRecordIndex;
  330. hKey-> BlockIndex = (WORD) lpKeynode-> BlockIndex;
  331. hKey-> KeyRecordIndex = (BYTE) lpKeynode-> KeyRecordIndex;
  332. RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
  333. ErrorCode = ERROR_SUCCESS;
  334. goto AddValueRecord;
  335. }
  336. if ((ErrorCode = RgLockKeyRecord(hKey-> lpFileInfo, hKey-> BlockIndex,
  337. hKey-> KeyRecordIndex, &lpKeyRecord)) == ERROR_SUCCESS) {
  338. if (NewValueRecordLength > SmallDword(lpKeyRecord-> AllocatedSize) -
  339. SmallDword(lpKeyRecord-> RecordSize)) {
  340. if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
  341. RecordSize + NewValueRecordLength, &lpKeyRecord)) !=
  342. ERROR_SUCCESS) {
  343. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex,
  344. FALSE);
  345. return ErrorCode;
  346. }
  347. }
  348. AddValueRecord:
  349. hKey-> BigKeyLockedBlockIndex = hKey-> BlockIndex;
  350. lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
  351. SmallDword(lpKeyRecord-> RecordSize));
  352. lpKeyRecord-> RecordSize += NewValueRecordLength;
  353. lpKeyRecord-> ValueCount++;
  354. }
  355. }
  356. //
  357. // If we're successful at this point, then lpValueRecord is valid and we
  358. // should copy the data into this record.
  359. //
  360. if (ErrorCode == ERROR_SUCCESS) {
  361. lpValueRecord-> DataType = Type;
  362. lpValueRecord-> NameLength = (WORD) ValueNameLength;
  363. MoveMemory(lpValueRecord-> Name, lpValueName, ValueNameLength);
  364. lpValueRecord-> DataLength = (WORD) cbData;
  365. MoveMemory((LPBYTE) lpValueRecord-> Name + ValueNameLength, lpData,
  366. cbData);
  367. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, TRUE);
  368. }
  369. return ErrorCode;
  370. }
  371. //
  372. // VMMRegSetValueEx
  373. //
  374. // See Win32 documentation of RegSetValueEx.
  375. //
  376. LONG
  377. REGAPI
  378. VMMRegSetValueEx(
  379. HKEY hKey,
  380. LPCSTR lpValueName,
  381. DWORD Reserved,
  382. DWORD Type,
  383. LPBYTE lpData,
  384. DWORD cbData
  385. )
  386. {
  387. int ErrorCode;
  388. if (IsBadOptionalStringPtr(lpValueName, (UINT) -1))
  389. return ERROR_INVALID_PARAMETER;
  390. //
  391. // bad Windows 95 compatibility problem. If the type is REG_SZ,
  392. // then override cbData with the length of the string pointed to by lpData.
  393. // This should have only been done in RegSetValue, but we're stuck with it
  394. // now...
  395. //
  396. if (Type == REG_SZ) {
  397. if (IsBadStringPtr(lpData, (UINT) -1))
  398. return ERROR_INVALID_PARAMETER;
  399. cbData = StrLen(lpData);
  400. // Must leave room for the null terminator
  401. if (cbData >= MAXIMUM_DATA_LENGTH)
  402. return ERROR_INVALID_PARAMETER;
  403. }
  404. else {
  405. if (cbData > 0 && IsBadHugeReadPtr(lpData, cbData))
  406. return ERROR_INVALID_PARAMETER;
  407. }
  408. if (cbData > MAXIMUM_DATA_LENGTH)
  409. return ERROR_INVALID_PARAMETER;
  410. if (!RgLockRegistry())
  411. return ERROR_LOCK_FAILED;
  412. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS) {
  413. if (IsDynDataKey(hKey) || (hKey-> lpFileInfo-> Flags & FI_READONLY))
  414. ErrorCode = ERROR_ACCESS_DENIED;
  415. else {
  416. if ((ErrorCode = RgSetValue(hKey, lpValueName, Type, lpData,
  417. (UINT) cbData)) == ERROR_SUCCESS) {
  418. RgSignalWaitingNotifies(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  419. REG_NOTIFY_CHANGE_LAST_SET);
  420. }
  421. }
  422. }
  423. RgUnlockRegistry();
  424. return ErrorCode;
  425. UNREFERENCED_PARAMETER(Reserved);
  426. }
  427. //
  428. // VMMRegSetValue
  429. //
  430. // See Win32 documentation of RegSetValue.
  431. //
  432. LONG
  433. REGAPI
  434. VMMRegSetValue(
  435. HKEY hKey,
  436. LPCSTR lpSubKey,
  437. DWORD Type,
  438. LPBYTE lpData,
  439. DWORD cbData
  440. )
  441. {
  442. LONG ErrorCode;
  443. HKEY hSubKey;
  444. if ((ErrorCode = RgCreateOrOpenKey(hKey, lpSubKey, &hSubKey, LK_CREATE)) ==
  445. ERROR_SUCCESS) {
  446. ErrorCode = VMMRegSetValueEx(hSubKey, NULL, 0, REG_SZ, lpData, 0);
  447. VMMRegCloseKey(hSubKey);
  448. }
  449. return ErrorCode;
  450. UNREFERENCED_PARAMETER(Type);
  451. UNREFERENCED_PARAMETER(cbData);
  452. }