1 /* Copyright (C) 1998 Transarc Corporation - All rights reserved.
17 /* Extended (alternative) versions of registry access functions.
18 * All functions return WIN32 style error codes.
22 static long CopyKey(const char *sourceKey, const char *targetKey);
23 static long CopyValues(HKEY srcKey, HKEY dupKey);
24 static long CopySubkeys(const char *srcName, HKEY srcKey,
25 const char *dupName, HKEY dupKey);
28 /* ----------------------- exported functions ----------------------- */
31 /* RegOpenKeyAlt() -- Open a key in the registry and return its handle.
32 * If create is set, the subkey (and all its parent keys on the path)
33 * is created if it does not exist. In either case, the disposition of
34 * the key is indicated as REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY.
36 * Note: if key is null (AFSREG_NULL_KEY) then the first component of
37 * subKeyName must be one of the predefined keys; resultKeyDispP
42 RegOpenKeyAlt(HKEY key, /* [in] open key from which to start */
43 const char *subKeyName, /* [in] sub key path */
44 DWORD mode, /* [in] desired access */
45 int create, /* [in] if set, creates key(s) on path */
46 HKEY *resultKeyP, /* [out] open key handle */
47 DWORD *resultKeyDispP) /* [out] open key disposition */
50 DWORD keyDisp = REG_OPENED_EXISTING_KEY;
52 if (key == AFSREG_NULL_KEY) {
53 /* No starting key; first path component must be predefined key.
54 * NOTE: predefined keys are always open (i.e., don't need opening).
56 const char *tokenP = subKeyName + strspn(subKeyName, "\\");
57 size_t tokenSz = strcspn(tokenP, "\\");
59 if (!strncmp(tokenP, "HKEY_LOCAL_MACHINE", tokenSz))
60 key = HKEY_LOCAL_MACHINE;
61 else if (!strncmp(tokenP, "HKEY_CURRENT_USER", tokenSz))
62 key = HKEY_CURRENT_USER;
63 else if (!strncmp(tokenP, "HKEY_CURRENT_CONFIG", tokenSz))
64 key = HKEY_CURRENT_CONFIG;
65 else if (!strncmp(tokenP, "HKEY_USERS", tokenSz))
67 else if (!strncmp(tokenP, "HKEY_CLASSES_ROOT", tokenSz))
68 key = HKEY_CLASSES_ROOT;
69 else if (!strncmp(tokenP, "HKEY_PERFORMANCE_DATA", tokenSz))
70 key = HKEY_PERFORMANCE_DATA;
71 else if (!strncmp(tokenP, "HKEY_DYN_DATA", tokenSz))
74 return ERROR_INVALID_PARAMETER;
77 subKeyName = tokenP + tokenSz + 1;
80 /* open (and possibly create) sub key */
82 status = RegCreateKeyEx(key, subKeyName,
83 (DWORD)0, "AFS", REG_OPTION_NON_VOLATILE,
84 mode, NULL, resultKeyP, &keyDisp);
86 status = RegOpenKeyEx(key, subKeyName, (DWORD)0, mode, resultKeyP);
90 *resultKeyDispP = keyDisp;
98 * RegQueryValueAlt() -- Read data associated with a key value.
99 * If a buffer is supplied (i.e., *dataPP is not NULL) then
100 * the data is placed in that buffer; in this case *dataSizeP
101 * is the buffer size on input and the data size on output.
102 * Otherwise, if *dataPP is NULL, a data buffer is allocated
103 * and *dataPP is set to point to that buffer.
105 * NOTE: dataTypeP can always be NULL, and dataSizeP can be NULL
106 * only if *dataPP is NULL.
110 RegQueryValueAlt(HKEY key, /* [in] open key handle */
111 const char *valueName, /* [in] value name */
112 DWORD *dataTypeP, /* [out] type of value's data */
113 void **dataPP, /* [in/out] buffer for value's data */
114 DWORD *dataSizeP) /* [in/out] size of data (buffer) */
119 /* Use user-supplied data buffer; no real work */
120 status = RegQueryValueEx(key, valueName, NULL,
121 dataTypeP, *dataPP, dataSizeP);
123 DWORD bufType, bufSize, dwordData;
126 /* get size of value's data; optimize read for common REG_DWORD */
127 bufSize = sizeof(DWORD);
129 status = RegQueryValueEx(key, valueName, NULL,
130 &bufType, (void*)&dwordData, &bufSize);
132 if (status == ERROR_SUCCESS || status == ERROR_MORE_DATA) {
133 /* allocate buffer for value's data */
134 buf = malloc(bufSize);
137 status = ERROR_NOT_ENOUGH_MEMORY;
139 if (status == ERROR_SUCCESS) {
140 /* data fit in DWORD buffer; don't read registry again */
141 memcpy(buf, &dwordData, bufSize);
143 /* data did not fit in DWORD buffer; read registry again */
144 status = RegQueryValueEx(key, valueName, NULL,
145 &bufType, buf, &bufSize);
148 if (status == ERROR_SUCCESS) {
149 /* return requested results */
151 if (dataTypeP) *dataTypeP = bufType;
152 if (dataSizeP) *dataSizeP = bufSize;
154 /* registry read failed */
167 * RegEnumKeyAlt() -- Enumerate subkey names of specified key.
168 * Subkey names are returned in a single multistring (REG_MULTI_SZ).
169 * If the key has no subkeys, then *subkeyNames is set to NULL.
171 * Note: A multistring is a char buffer containing individual strings
172 * separated by a '\0' char with the last string being followed by
177 RegEnumKeyAlt(HKEY key, /* [in] open key handle */
178 char **subkeyNames) /* [out] subkey name buf (multistring) */
181 DWORD skCount, skNameLenMax;
182 char *skNameBuf = NULL;
184 status = RegQueryInfoKey(key,
186 &skCount, &skNameLenMax,
187 NULL, NULL, NULL, NULL, NULL, NULL);
189 if (status == ERROR_SUCCESS && skCount > 0) {
190 skNameBuf = malloc((skCount * (skNameLenMax + 1)) + 1);
193 status = ERROR_NOT_ENOUGH_MEMORY;
196 char *skBufP = skNameBuf;
198 for (i = 0; i < skCount && status == ERROR_SUCCESS; i++) {
199 skFillLen = skNameLenMax + 1;
200 status = RegEnumKeyEx(key, i, skBufP, &skFillLen,
201 NULL, NULL, NULL, NULL);
202 if (status == ERROR_SUCCESS) {
203 skBufP += skFillLen + 1;
208 if (status != ERROR_SUCCESS) {
215 *subkeyNames = skNameBuf;
221 * RegDeleteKeyAlt() -- Delete named subkey and all its subkeys and values.
223 * This is just a recursive version of RegDeleteKey(), which does not
224 * recurse on NT (though it does on Win95/98).
227 RegDeleteKeyAlt(HKEY key,
228 const char *subKeyName)
232 status = RegDeleteKey(key, subKeyName);
234 if (status != ERROR_SUCCESS) {
235 /* determine if delete failed due to subkeys */
238 status = RegOpenKeyEx(key, subKeyName, 0, KEY_ALL_ACCESS, &subKey);
239 if (status == ERROR_SUCCESS) {
242 status = RegEnumKeyAlt(subKey, &keyEnum);
243 if (status == ERROR_SUCCESS && keyEnum != NULL) {
244 /* subkeys found; try to delete each; ignore errors */
247 for (keyEnumName = keyEnum;
248 *keyEnumName != '\0';
249 keyEnumName += strlen(keyEnumName) + 1) {
250 (void) RegDeleteKeyAlt(subKey, keyEnumName);
254 (void) RegCloseKey(subKey);
257 /* try delete again */
258 status = RegDeleteKey(key, subKeyName);
265 * RegDeleteEntryAlt() -- delete named key or value; if key, then all subkeys
266 * and values are removed; entryName must be in canonical path format.
269 RegDeleteEntryAlt(const char *entryName, regentry_t entryType)
271 long status = ERROR_SUCCESS;
272 char *entryBuf = _strdup(entryName);
274 if (entryBuf == NULL) {
275 status = ERROR_NOT_ENOUGH_MEMORY;
277 char *keyPath = entryBuf;
278 char *entryName = strrchr(entryBuf, '\\');
280 if (entryName == NULL) {
281 status = ERROR_INVALID_PARAMETER;
288 status = RegOpenKeyAlt(AFSREG_NULL_KEY,
289 keyPath, KEY_ALL_ACCESS, 0, &key, NULL);
290 if (status == ERROR_SUCCESS) {
291 if (entryType == REGENTRY_KEY) {
292 status = RegDeleteKeyAlt(key, entryName);
293 } else if (entryType == REGENTRY_VALUE) {
294 status = RegDeleteValue(key, entryName);
296 status = ERROR_INVALID_PARAMETER;
298 (void) RegCloseKey(key);
308 * RegDupKeyAlt() -- duplicate sourceKey as targetKey; both sourceKey and
309 * targetKey must be in canonical path format.
311 * NOTE: if targetKey already exists it will be replaced.
314 RegDupKeyAlt(const char *sourceKey, const char *targetKey)
318 /* delete target key if extant */
319 status = RegDeleteEntryAlt(targetKey, REGENTRY_KEY);
321 if (status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND) {
322 status = CopyKey(sourceKey, targetKey);
324 if (status != ERROR_SUCCESS) {
325 /* clean-up partial duplication */
326 (void) RegDeleteEntryAlt(targetKey, REGENTRY_KEY);
334 /* ----------------------- local functions ----------------------- */
338 * CopyKey() -- worker function implementing RegDupKeyAlt().
340 * Note: - assumes target does not exist (i.e., deleted by RegDupKeyAlt())
341 * - no cleanup on failure (i.e., assumes done by RegDupKeyAlt())
344 CopyKey(const char *sourceKey, const char *targetKey)
349 /* open source key */
350 status = RegOpenKeyAlt(AFSREG_NULL_KEY, sourceKey,
351 KEY_READ, 0, &srcKey, NULL);
352 if (status == ERROR_SUCCESS) {
353 /* create target key */
354 status = RegOpenKeyAlt(AFSREG_NULL_KEY, targetKey,
355 KEY_ALL_ACCESS, 1 /* create */, &dupKey, NULL);
356 if (status == ERROR_SUCCESS) {
357 /* copy values and their data from source to target */
358 status = CopyValues(srcKey, dupKey);
360 if (status == ERROR_SUCCESS) {
361 /* copy subkeys from source to target */
362 status = CopySubkeys(sourceKey, srcKey, targetKey, dupKey);
364 (void) RegCloseKey(dupKey);
366 (void) RegCloseKey(srcKey);
373 * CopyValues() -- copy values and their data from srcKey to dupKey
376 CopyValues(HKEY srcKey, HKEY dupKey)
379 DWORD valCount, valNameLenMax, valDataLenMax;
381 status = RegQueryInfoKey(srcKey,
382 NULL, NULL, NULL, NULL, NULL, NULL,
383 &valCount, &valNameLenMax, &valDataLenMax,
386 if (status == ERROR_SUCCESS && valCount > 0) {
387 char *valBuffer = malloc(valNameLenMax + 1 + valDataLenMax);
389 if (valBuffer == NULL) {
390 status = ERROR_NOT_ENOUGH_MEMORY;
393 char *valName = valBuffer;
394 char *valData = valBuffer + (valNameLenMax + 1);
396 for (i = 0; i < valCount && status == ERROR_SUCCESS; i++) {
397 DWORD valNameFillLen = valNameLenMax + 1;
398 DWORD valDataFillLen = valDataLenMax;
401 status = RegEnumValue(srcKey, i,
402 valName, &valNameFillLen,
405 valData, &valDataFillLen);
407 if (status == ERROR_SUCCESS) {
408 status = RegSetValueEx(dupKey,
411 valData, valDataFillLen);
422 * CopySubkeys() -- copy subkeys from srcKey to dupKey
424 * Note - srcName and dupName are the canonical path names of the
425 * open keys srcKey and dupKey, respectively.
428 CopySubkeys(const char *srcName, HKEY srcKey, const char *dupName, HKEY dupKey)
433 status = RegEnumKeyAlt(srcKey, &skEnum);
435 if (status == ERROR_SUCCESS && skEnum != NULL) {
436 char *skEnumName, *skNameBuf;
437 size_t skSrcNameMax, skDupNameMax, skNameMax;
441 while (*skEnumName != '\0') {
442 size_t skNameLen = strlen(skEnumName);
443 skNameMax = max(skNameMax, skNameLen);
445 skEnumName += skNameLen + 1;
448 skSrcNameMax = strlen(srcName) + 1 + skNameMax + 1;
449 skDupNameMax = strlen(dupName) + 1 + skNameMax + 1;
451 skNameBuf = malloc(skSrcNameMax + skDupNameMax);
452 if (skNameBuf == NULL) {
453 status = ERROR_NOT_ENOUGH_MEMORY;
455 char *skSrcName = skNameBuf;
456 char *skDupName = skNameBuf + skSrcNameMax;
458 for (skEnumName = skEnum;
459 *skEnumName != '\0' && status == ERROR_SUCCESS;
460 skEnumName += strlen(skEnumName) + 1) {
461 sprintf(skSrcName, "%s\\%s", srcName, skEnumName);
462 sprintf(skDupName, "%s\\%s", dupName, skEnumName);
464 status = CopyKey(skSrcName, skDupName);