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.

421 lines
12 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. TRACE(("key record too big\n"));
  28. return ERROR_OUTOFMEMORY;
  29. }
  30. lpOldKeyRecord = *lplpKeyRecord;
  31. BlockIndex = HIWORD(lpOldKeyRecord-> DatablockAddress);
  32. KeyRecordIndex = LOWORD(lpOldKeyRecord-> DatablockAddress);
  33. //
  34. // Check if we can simply extend this key record by taking space from an
  35. // adjacent free record.
  36. //
  37. if (RgExtendKeyRecord(hKey-> lpFileInfo, BlockIndex, (UINT) Length,
  38. lpOldKeyRecord) == ERROR_SUCCESS)
  39. return ERROR_SUCCESS;
  40. //
  41. // Check if there's enough space in the datablock lpCurrKeyRecord is in to
  42. // contain a key record of the specified size. If so, then we don't have
  43. // to dirty the keynode.
  44. //
  45. if (RgAllocKeyRecordFromDatablock(hKey-> lpFileInfo, BlockIndex,
  46. (UINT) Length, lplpKeyRecord) == ERROR_SUCCESS) {
  47. // After an alloc, we must refetch these pointers because they may be
  48. // invalid.
  49. lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
  50. BlockIndex);
  51. lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
  52. KeyRecordIndex);
  53. // Transfer all the data to the new record, except for the allocated
  54. // size which is already correctly set.
  55. MoveMemory(&(*lplpKeyRecord)-> DatablockAddress, &lpOldKeyRecord->
  56. DatablockAddress, SmallDword(lpOldKeyRecord-> RecordSize) -
  57. sizeof(DWORD));
  58. RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
  59. // Update the key record table to point to the new key record.
  60. lpOldDatablockInfo-> lpKeyRecordTable[KeyRecordIndex] =
  61. (KEY_RECORD_TABLE_ENTRY) ((LPBYTE) (*lplpKeyRecord) -
  62. (LPBYTE) lpOldDatablockInfo-> lpDatablockHeader);
  63. return ERROR_SUCCESS;
  64. }
  65. //
  66. // Check if we can allocate a key record from another datablock. If so,
  67. // then copy the key to the other datablock and update the keynode.
  68. //
  69. if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  70. &lpKeynode) == ERROR_SUCCESS) {
  71. if ((ErrorCode = RgAllocKeyRecord(hKey-> lpFileInfo, (UINT) Length,
  72. lplpKeyRecord)) == ERROR_SUCCESS) {
  73. // After an alloc, we must refetch these pointers because they may
  74. // be invalid.
  75. lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
  76. BlockIndex);
  77. lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
  78. KeyRecordIndex);
  79. // Transfer all the data to the new record, except for the
  80. // allocated size which is already correctly set.
  81. MoveMemory(&(*lplpKeyRecord)-> RecordSize, &lpOldKeyRecord->
  82. RecordSize, SmallDword(lpOldKeyRecord-> RecordSize) -
  83. (sizeof(DWORD) * 2));
  84. RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
  85. RgFreeKeyRecordIndex(lpOldDatablockInfo, KeyRecordIndex);
  86. // Unlock the old datablock.
  87. RgUnlockDatablock(hKey-> lpFileInfo, BlockIndex, TRUE);
  88. // Update the open key and keynode to point to the key record in
  89. // the new datablock.
  90. hKey-> BlockIndex = (*lplpKeyRecord)-> 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. //
  103. int
  104. INTERNAL
  105. RgSetValue(
  106. HKEY hKey,
  107. LPCSTR lpValueName,
  108. DWORD Type,
  109. LPBYTE lpData,
  110. UINT cbData
  111. )
  112. {
  113. int ErrorCode;
  114. UINT ValueNameLength;
  115. UINT NewValueRecordLength;
  116. LPKEY_RECORD lpKeyRecord;
  117. LPVALUE_RECORD lpValueRecord;
  118. UINT CurrentValueRecordLength;
  119. LPBYTE lpDestination;
  120. UINT BytesToExtend;
  121. UINT TempCount;
  122. LPKEYNODE lpKeynode;
  123. ValueNameLength = (IsNullPtr(lpValueName) ? 0 : (UINT) StrLen(lpValueName));
  124. if (ValueNameLength > MAXIMUM_VALUE_NAME_LENGTH - 1)
  125. return ERROR_INVALID_PARAMETER;
  126. NewValueRecordLength = sizeof(VALUE_RECORD) + ValueNameLength + cbData - 1;
  127. ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord,
  128. &lpValueRecord);
  129. //
  130. // A value with this name already exists, so update the existing
  131. // VALUE_RECORD with the new information.
  132. //
  133. if (ErrorCode == ERROR_SUCCESS) {
  134. CurrentValueRecordLength = sizeof(VALUE_RECORD) + lpValueRecord->
  135. NameLength + lpValueRecord-> DataLength - 1;
  136. if (NewValueRecordLength == CurrentValueRecordLength) {
  137. if (lpValueRecord-> DataLength == cbData && lpValueRecord->
  138. DataType == Type && CompareMemory((LPBYTE) lpValueRecord->
  139. Name + ValueNameLength, lpData, cbData) == 0) {
  140. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex, FALSE);
  141. return ERROR_SUCCESS;
  142. }
  143. }
  144. if (NewValueRecordLength < CurrentValueRecordLength) {
  145. lpKeyRecord-> RecordSize -= (CurrentValueRecordLength -
  146. NewValueRecordLength);
  147. }
  148. else if (NewValueRecordLength > CurrentValueRecordLength) {
  149. BytesToExtend = NewValueRecordLength - CurrentValueRecordLength;
  150. if (BytesToExtend > SmallDword(lpKeyRecord-> AllocatedSize) -
  151. SmallDword(lpKeyRecord-> RecordSize)) {
  152. TempCount = (LPBYTE) lpValueRecord - (LPBYTE) lpKeyRecord;
  153. if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
  154. RecordSize + BytesToExtend, &lpKeyRecord)) !=
  155. ERROR_SUCCESS) {
  156. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex,
  157. FALSE);
  158. return ErrorCode;
  159. }
  160. lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
  161. TempCount);
  162. }
  163. lpKeyRecord-> RecordSize += BytesToExtend;
  164. }
  165. lpDestination = (LPBYTE) lpValueRecord + NewValueRecordLength;
  166. TempCount = (UINT) ((LPBYTE) lpKeyRecord + SmallDword(lpKeyRecord->
  167. RecordSize) - lpDestination);
  168. if (TempCount > 0) {
  169. MoveMemory(lpDestination, (LPBYTE) lpValueRecord +
  170. CurrentValueRecordLength, TempCount);
  171. }
  172. }
  173. //
  174. // No value exists with this name. Place a new VALUE_RECORD at the end of
  175. // the KEY_RECORD.
  176. //
  177. else if (ErrorCode == ERROR_CANTREAD16_FILENOTFOUND32) {
  178. // Handle Win95 registries that don't have a key record for the root
  179. // key. We don't check if this is really the root key, but it doesn't
  180. // matter much.
  181. if (IsNullBlockIndex(hKey-> BlockIndex)) {
  182. if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  183. &lpKeynode) != ERROR_SUCCESS)
  184. goto LockKeynodeFailed;
  185. if (RgAllocKeyRecord(hKey-> lpFileInfo, sizeof(KEY_RECORD) +
  186. NewValueRecordLength, &lpKeyRecord) != ERROR_SUCCESS) {
  187. RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, FALSE);
  188. LockKeynodeFailed:
  189. TRAP();
  190. return ERROR_CANTOPEN; // Win95 compatibility
  191. }
  192. lpKeyRecord-> RecordSize = sizeof(KEY_RECORD);
  193. lpKeyRecord-> NameLength = 1; // Win95 compatibility
  194. lpKeyRecord-> Name[0] = '\0'; // Win95 compatibility
  195. lpKeyRecord-> ValueCount = 0;
  196. lpKeyRecord-> ClassLength = 0;
  197. lpKeyRecord-> Reserved = 0;
  198. lpKeynode-> BlockIndex = lpKeyRecord-> BlockIndex;
  199. lpKeynode-> KeyRecordIndex = lpKeyRecord-> KeyRecordIndex;
  200. hKey-> BlockIndex = (WORD) lpKeynode-> BlockIndex;
  201. hKey-> KeyRecordIndex = (BYTE) lpKeynode-> KeyRecordIndex;
  202. RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
  203. ErrorCode = ERROR_SUCCESS;
  204. goto AddValueRecord;
  205. }
  206. if ((ErrorCode = RgLockKeyRecord(hKey-> lpFileInfo, hKey-> BlockIndex,
  207. hKey-> KeyRecordIndex, &lpKeyRecord)) == ERROR_SUCCESS) {
  208. if (NewValueRecordLength > SmallDword(lpKeyRecord-> AllocatedSize) -
  209. SmallDword(lpKeyRecord-> RecordSize)) {
  210. if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
  211. RecordSize + NewValueRecordLength, &lpKeyRecord)) !=
  212. ERROR_SUCCESS) {
  213. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex,
  214. FALSE);
  215. return ErrorCode;
  216. }
  217. }
  218. AddValueRecord:
  219. lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
  220. SmallDword(lpKeyRecord-> RecordSize));
  221. lpKeyRecord-> RecordSize += NewValueRecordLength;
  222. lpKeyRecord-> ValueCount++;
  223. }
  224. }
  225. //
  226. // If we're successful at this point, then lpValueRecord is valid and we
  227. // should copy the data into this record.
  228. //
  229. if (ErrorCode == ERROR_SUCCESS) {
  230. lpValueRecord-> DataType = Type;
  231. lpValueRecord-> NameLength = (WORD) ValueNameLength;
  232. MoveMemory(lpValueRecord-> Name, lpValueName, ValueNameLength);
  233. lpValueRecord-> DataLength = (WORD) cbData;
  234. MoveMemory((LPBYTE) lpValueRecord-> Name + ValueNameLength, lpData,
  235. cbData);
  236. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex, TRUE);
  237. }
  238. return ErrorCode;
  239. }
  240. //
  241. // VMMRegSetValueEx
  242. //
  243. // See Win32 documentation of RegSetValueEx.
  244. //
  245. LONG
  246. REGAPI
  247. VMMRegSetValueEx(
  248. HKEY hKey,
  249. LPCSTR lpValueName,
  250. DWORD Reserved,
  251. DWORD Type,
  252. LPBYTE lpData,
  253. DWORD cbData
  254. )
  255. {
  256. int ErrorCode;
  257. if (IsBadOptionalStringPtr(lpValueName, (UINT) -1))
  258. return ERROR_INVALID_PARAMETER;
  259. //
  260. // Windows 95 compatibility problem. If the type is REG_SZ,
  261. // then override cbData with the length of the string pointed to by lpData.
  262. // This should have only been done in RegSetValue, but we're stuck with it
  263. // now...
  264. //
  265. if (Type == REG_SZ) {
  266. if (IsBadStringPtr(lpData, (UINT) -1))
  267. return ERROR_INVALID_PARAMETER;
  268. cbData = StrLen(lpData);
  269. }
  270. else {
  271. if (cbData > 0 && IsBadHugeReadPtr(lpData, cbData))
  272. return ERROR_INVALID_PARAMETER;
  273. }
  274. if (cbData > MAXIMUM_DATA_LENGTH)
  275. return ERROR_INVALID_PARAMETER;
  276. if (!RgLockRegistry())
  277. return ERROR_LOCK_FAILED;
  278. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS) {
  279. if ((hKey-> PredefinedKeyIndex == INDEX_DYN_DATA) || (hKey->
  280. lpFileInfo-> Flags & FI_READONLY))
  281. ErrorCode = ERROR_ACCESS_DENIED;
  282. else {
  283. if ((ErrorCode = RgSetValue(hKey, lpValueName, Type, lpData,
  284. (UINT) cbData)) == ERROR_SUCCESS) {
  285. RgSignalWaitingNotifies(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  286. REG_NOTIFY_CHANGE_LAST_SET);
  287. }
  288. }
  289. }
  290. RgUnlockRegistry();
  291. return ErrorCode;
  292. UNREFERENCED_PARAMETER(Reserved);
  293. }
  294. //
  295. // VMMRegSetValue
  296. //
  297. // See Win32 documentation of RegSetValue.
  298. //
  299. LONG
  300. REGAPI
  301. VMMRegSetValue(
  302. HKEY hKey,
  303. LPCSTR lpSubKey,
  304. DWORD Type,
  305. LPBYTE lpData,
  306. DWORD cbData
  307. )
  308. {
  309. LONG ErrorCode;
  310. HKEY hSubKey;
  311. if ((ErrorCode = RgCreateOrOpenKey(hKey, lpSubKey, &hSubKey, LK_CREATE)) ==
  312. ERROR_SUCCESS) {
  313. ErrorCode = VMMRegSetValueEx(hSubKey, NULL, 0, REG_SZ, lpData, 0);
  314. VMMRegCloseKey(hSubKey);
  315. }
  316. return ErrorCode;
  317. UNREFERENCED_PARAMETER(Type);
  318. UNREFERENCED_PARAMETER(cbData);
  319. }