2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
22 /* Extended (alternative) versions of registry access functions.
23 * All functions return WIN32 style error codes.
27 static long CopyKey(const char *sourceKey, const char *targetKey);
28 static long CopyValues(HKEY srcKey, HKEY dupKey);
29 static long CopySubkeys(const char *srcName, HKEY srcKey,
30 const char *dupName, HKEY dupKey);
33 /* ----------------------- exported functions ----------------------- */
36 /* RegOpenKeyAlt() -- Open a key in the registry and return its handle.
37 * If create is set, the subkey (and all its parent keys on the path)
38 * is created if it does not exist. In either case, the disposition of
39 * the key is indicated as REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY.
41 * Note: if key is null (AFSREG_NULL_KEY) then the first component of
42 * subKeyName must be one of the predefined keys; resultKeyDispP
47 RegOpenKeyAlt(HKEY key, /* [in] open key from which to start */
48 const char *subKeyName, /* [in] sub key path */
49 DWORD mode, /* [in] desired access */
50 int create, /* [in] if set, creates key(s) on path */
51 HKEY *resultKeyP, /* [out] open key handle */
52 DWORD *resultKeyDispP) /* [out] open key disposition */
55 DWORD keyDisp = REG_OPENED_EXISTING_KEY;
57 if (key == AFSREG_NULL_KEY) {
58 /* No starting key; first path component must be predefined key.
59 * NOTE: predefined keys are always open (i.e., don't need opening).
61 const char *tokenP = subKeyName + strspn(subKeyName, "\\");
62 size_t tokenSz = strcspn(tokenP, "\\");
64 if (!strncmp(tokenP, "HKEY_LOCAL_MACHINE", tokenSz))
65 key = HKEY_LOCAL_MACHINE;
66 else if (!strncmp(tokenP, "HKEY_CURRENT_USER", tokenSz))
67 key = HKEY_CURRENT_USER;
68 else if (!strncmp(tokenP, "HKEY_CURRENT_CONFIG", tokenSz))
69 key = HKEY_CURRENT_CONFIG;
70 else if (!strncmp(tokenP, "HKEY_USERS", tokenSz))
72 else if (!strncmp(tokenP, "HKEY_CLASSES_ROOT", tokenSz))
73 key = HKEY_CLASSES_ROOT;
74 else if (!strncmp(tokenP, "HKEY_PERFORMANCE_DATA", tokenSz))
75 key = HKEY_PERFORMANCE_DATA;
76 else if (!strncmp(tokenP, "HKEY_DYN_DATA", tokenSz))
79 return ERROR_INVALID_PARAMETER;
82 subKeyName = tokenP + tokenSz + 1;
85 /* open (and possibly create) sub key */
87 status = RegCreateKeyEx(key, subKeyName,
88 (DWORD)0, "AFS", REG_OPTION_NON_VOLATILE,
89 mode, NULL, resultKeyP, &keyDisp);
91 status = RegOpenKeyEx(key, subKeyName, (DWORD)0, mode, resultKeyP);
95 *resultKeyDispP = keyDisp;
103 * RegQueryValueAlt() -- Read data associated with a key value.
104 * If a buffer is supplied (i.e., *dataPP is not NULL) then
105 * the data is placed in that buffer; in this case *dataSizeP
106 * is the buffer size on input and the data size on output.
107 * Otherwise, if *dataPP is NULL, a data buffer is allocated
108 * and *dataPP is set to point to that buffer.
110 * NOTE: dataTypeP can always be NULL, and dataSizeP can be NULL
111 * only if *dataPP is NULL.
115 RegQueryValueAlt(HKEY key, /* [in] open key handle */
116 const char *valueName, /* [in] value name */
117 DWORD *dataTypeP, /* [out] type of value's data */
118 void **dataPP, /* [in/out] buffer for value's data */
119 DWORD *dataSizeP) /* [in/out] size of data (buffer) */
124 /* Use user-supplied data buffer; no real work */
125 status = RegQueryValueEx(key, valueName, NULL,
126 dataTypeP, *dataPP, dataSizeP);
128 DWORD bufType, bufSize, dwordData;
131 /* get size of value's data; optimize read for common REG_DWORD */
132 bufSize = sizeof(DWORD);
134 status = RegQueryValueEx(key, valueName, NULL,
135 &bufType, (void*)&dwordData, &bufSize);
137 if (status == ERROR_SUCCESS || status == ERROR_MORE_DATA) {
138 /* allocate buffer for value's data */
139 buf = malloc(bufSize);
142 status = ERROR_NOT_ENOUGH_MEMORY;
144 if (status == ERROR_SUCCESS) {
145 /* data fit in DWORD buffer; don't read registry again */
146 memcpy(buf, &dwordData, bufSize);
148 /* data did not fit in DWORD buffer; read registry again */
149 status = RegQueryValueEx(key, valueName, NULL,
150 &bufType, buf, &bufSize);
153 if (status == ERROR_SUCCESS) {
154 /* return requested results */
156 if (dataTypeP) *dataTypeP = bufType;
157 if (dataSizeP) *dataSizeP = bufSize;
159 /* registry read failed */
172 * RegEnumKeyAlt() -- Enumerate subkey names of specified key.
173 * Subkey names are returned in a single multistring (REG_MULTI_SZ).
174 * If the key has no subkeys, then *subkeyNames is set to NULL.
176 * Note: A multistring is a char buffer containing individual strings
177 * separated by a '\0' char with the last string being followed by
182 RegEnumKeyAlt(HKEY key, /* [in] open key handle */
183 char **subkeyNames) /* [out] subkey name buf (multistring) */
186 DWORD skCount, skNameLenMax;
187 char *skNameBuf = NULL;
189 status = RegQueryInfoKey(key,
191 &skCount, &skNameLenMax,
192 NULL, NULL, NULL, NULL, NULL, NULL);
194 if (status == ERROR_SUCCESS && skCount > 0) {
195 skNameBuf = malloc((skCount * (skNameLenMax + 1)) + 1);
198 status = ERROR_NOT_ENOUGH_MEMORY;
201 char *skBufP = skNameBuf;
203 for (i = 0; i < skCount && status == ERROR_SUCCESS; i++) {
204 skFillLen = skNameLenMax + 1;
205 status = RegEnumKeyEx(key, i, skBufP, &skFillLen,
206 NULL, NULL, NULL, NULL);
207 if (status == ERROR_SUCCESS) {
208 skBufP += skFillLen + 1;
213 if (status != ERROR_SUCCESS) {
220 *subkeyNames = skNameBuf;
226 * RegDeleteKeyAlt() -- Delete named subkey and all its subkeys and values.
228 * This is just a recursive version of RegDeleteKey(), which does not
229 * recurse on NT (though it does on Win95/98).
232 RegDeleteKeyAlt(HKEY key,
233 const char *subKeyName)
237 status = RegDeleteKey(key, subKeyName);
239 if (status != ERROR_SUCCESS) {
240 /* determine if delete failed due to subkeys */
243 status = RegOpenKeyEx(key, subKeyName, 0, KEY_ALL_ACCESS, &subKey);
244 if (status == ERROR_SUCCESS) {
247 status = RegEnumKeyAlt(subKey, &keyEnum);
248 if (status == ERROR_SUCCESS && keyEnum != NULL) {
249 /* subkeys found; try to delete each; ignore errors */
252 for (keyEnumName = keyEnum;
253 *keyEnumName != '\0';
254 keyEnumName += strlen(keyEnumName) + 1) {
255 (void) RegDeleteKeyAlt(subKey, keyEnumName);
259 (void) RegCloseKey(subKey);
262 /* try delete again */
263 status = RegDeleteKey(key, subKeyName);
270 * RegDeleteEntryAlt() -- delete named key or value; if key, then all subkeys
271 * and values are removed; entryName must be in canonical path format.
274 RegDeleteEntryAlt(const char *entryName, regentry_t entryType)
276 long status = ERROR_SUCCESS;
277 char *entryBuf = _strdup(entryName);
279 if (entryBuf == NULL) {
280 status = ERROR_NOT_ENOUGH_MEMORY;
282 char *keyPath = entryBuf;
283 char *entryName = strrchr(entryBuf, '\\');
285 if (entryName == NULL) {
286 status = ERROR_INVALID_PARAMETER;
293 status = RegOpenKeyAlt(AFSREG_NULL_KEY,
294 keyPath, KEY_ALL_ACCESS, 0, &key, NULL);
295 if (status == ERROR_SUCCESS) {
296 if (entryType == REGENTRY_KEY) {
297 status = RegDeleteKeyAlt(key, entryName);
298 } else if (entryType == REGENTRY_VALUE) {
299 status = RegDeleteValue(key, entryName);
301 status = ERROR_INVALID_PARAMETER;
303 (void) RegCloseKey(key);
313 * RegDupKeyAlt() -- duplicate sourceKey as targetKey; both sourceKey and
314 * targetKey must be in canonical path format.
316 * NOTE: if targetKey already exists it will be replaced.
319 RegDupKeyAlt(const char *sourceKey, const char *targetKey)
323 /* delete target key if extant */
324 status = RegDeleteEntryAlt(targetKey, REGENTRY_KEY);
326 if (status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND) {
327 status = CopyKey(sourceKey, targetKey);
329 if (status != ERROR_SUCCESS) {
330 /* clean-up partial duplication */
331 (void) RegDeleteEntryAlt(targetKey, REGENTRY_KEY);
339 /* ----------------------- local functions ----------------------- */
343 * CopyKey() -- worker function implementing RegDupKeyAlt().
345 * Note: - assumes target does not exist (i.e., deleted by RegDupKeyAlt())
346 * - no cleanup on failure (i.e., assumes done by RegDupKeyAlt())
349 CopyKey(const char *sourceKey, const char *targetKey)
354 /* open source key */
355 status = RegOpenKeyAlt(AFSREG_NULL_KEY, sourceKey,
356 KEY_READ, 0, &srcKey, NULL);
357 if (status == ERROR_SUCCESS) {
358 /* create target key */
359 status = RegOpenKeyAlt(AFSREG_NULL_KEY, targetKey,
360 KEY_ALL_ACCESS, 1 /* create */, &dupKey, NULL);
361 if (status == ERROR_SUCCESS) {
362 /* copy values and their data from source to target */
363 status = CopyValues(srcKey, dupKey);
365 if (status == ERROR_SUCCESS) {
366 /* copy subkeys from source to target */
367 status = CopySubkeys(sourceKey, srcKey, targetKey, dupKey);
369 (void) RegCloseKey(dupKey);
371 (void) RegCloseKey(srcKey);
378 * CopyValues() -- copy values and their data from srcKey to dupKey
381 CopyValues(HKEY srcKey, HKEY dupKey)
384 DWORD valCount, valNameLenMax, valDataLenMax;
386 status = RegQueryInfoKey(srcKey,
387 NULL, NULL, NULL, NULL, NULL, NULL,
388 &valCount, &valNameLenMax, &valDataLenMax,
391 if (status == ERROR_SUCCESS && valCount > 0) {
392 char *valBuffer = malloc(valNameLenMax + 1 + valDataLenMax);
394 if (valBuffer == NULL) {
395 status = ERROR_NOT_ENOUGH_MEMORY;
398 char *valName = valBuffer;
399 char *valData = valBuffer + (valNameLenMax + 1);
401 for (i = 0; i < valCount && status == ERROR_SUCCESS; i++) {
402 DWORD valNameFillLen = valNameLenMax + 1;
403 DWORD valDataFillLen = valDataLenMax;
406 status = RegEnumValue(srcKey, i,
407 valName, &valNameFillLen,
410 valData, &valDataFillLen);
412 if (status == ERROR_SUCCESS) {
413 status = RegSetValueEx(dupKey,
416 valData, valDataFillLen);
427 * CopySubkeys() -- copy subkeys from srcKey to dupKey
429 * Note - srcName and dupName are the canonical path names of the
430 * open keys srcKey and dupKey, respectively.
433 CopySubkeys(const char *srcName, HKEY srcKey, const char *dupName, HKEY dupKey)
438 status = RegEnumKeyAlt(srcKey, &skEnum);
440 if (status == ERROR_SUCCESS && skEnum != NULL) {
441 char *skEnumName, *skNameBuf;
442 size_t skSrcNameMax, skDupNameMax, skNameMax;
446 while (*skEnumName != '\0') {
447 size_t skNameLen = strlen(skEnumName);
448 skNameMax = max(skNameMax, skNameLen);
450 skEnumName += skNameLen + 1;
453 skSrcNameMax = strlen(srcName) + 1 + skNameMax + 1;
454 skDupNameMax = strlen(dupName) + 1 + skNameMax + 1;
456 skNameBuf = malloc(skSrcNameMax + skDupNameMax);
457 if (skNameBuf == NULL) {
458 status = ERROR_NOT_ENOUGH_MEMORY;
460 char *skSrcName = skNameBuf;
461 char *skDupName = skNameBuf + skSrcNameMax;
463 for (skEnumName = skEnum;
464 *skEnumName != '\0' && status == ERROR_SUCCESS;
465 skEnumName += strlen(skEnumName) + 1) {
466 sprintf(skSrcName, "%s\\%s", srcName, skEnumName);
467 sprintf(skDupName, "%s\\%s", dupName, skEnumName);
469 status = CopyKey(skSrcName, skDupName);