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
);
32 typedef BOOL (WINAPI
*LPFN_ISWOW64PROCESS
) (HANDLE
, PBOOL
);
35 static int init
= TRUE
;
36 static int bIsWow64
= FALSE
;
40 LPFN_ISWOW64PROCESS fnIsWow64Process
= NULL
;
42 hModule
= GetModuleHandle(TEXT("kernel32"));
44 fnIsWow64Process
= (LPFN_ISWOW64PROCESS
)GetProcAddress(hModule
, "IsWow64Process");
46 if (NULL
!= fnIsWow64Process
)
48 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64
))
50 // on error, assume FALSE.
51 // in other words, do nothing.
62 /* ----------------------- exported functions ----------------------- */
65 /* RegOpenKeyAlt() -- Open a key in the registry and return its handle.
66 * If create is set, the subkey (and all its parent keys on the path)
67 * is created if it does not exist. In either case, the disposition of
68 * the key is indicated as REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY.
70 * Note: if key is null (AFSREG_NULL_KEY) then the first component of
71 * subKeyName must be one of the predefined keys; resultKeyDispP
76 RegOpenKeyAlt(HKEY key
, /* [in] open key from which to start */
77 const char *subKeyName
, /* [in] sub key path */
78 DWORD mode
, /* [in] desired access */
79 int create
, /* [in] if set, creates key(s) on path */
80 HKEY
*resultKeyP
, /* [out] open key handle */
81 DWORD
*resultKeyDispP
) /* [out] open key disposition */
84 DWORD keyDisp
= REG_OPENED_EXISTING_KEY
;
86 if (key
== AFSREG_NULL_KEY
) {
87 /* No starting key; first path component must be predefined key.
88 * NOTE: predefined keys are always open (i.e., don't need opening).
90 const char *tokenP
= subKeyName
+ strspn(subKeyName
, "\\");
91 size_t tokenSz
= strcspn(tokenP
, "\\");
93 if (!strncmp(tokenP
, "HKEY_LOCAL_MACHINE", tokenSz
))
94 key
= HKEY_LOCAL_MACHINE
;
95 else if (!strncmp(tokenP
, "HKEY_CURRENT_USER", tokenSz
))
96 key
= HKEY_CURRENT_USER
;
97 else if (!strncmp(tokenP
, "HKEY_CURRENT_CONFIG", tokenSz
))
98 key
= HKEY_CURRENT_CONFIG
;
99 else if (!strncmp(tokenP
, "HKEY_USERS", tokenSz
))
101 else if (!strncmp(tokenP
, "HKEY_CLASSES_ROOT", tokenSz
))
102 key
= HKEY_CLASSES_ROOT
;
103 else if (!strncmp(tokenP
, "HKEY_PERFORMANCE_DATA", tokenSz
))
104 key
= HKEY_PERFORMANCE_DATA
;
105 else if (!strncmp(tokenP
, "HKEY_DYN_DATA", tokenSz
))
108 return ERROR_INVALID_PARAMETER
;
111 subKeyName
= tokenP
+ tokenSz
+ 1;
114 /* open (and possibly create) sub key */
116 status
= RegCreateKeyEx(key
, subKeyName
,
117 (DWORD
)0, "AFS", REG_OPTION_NON_VOLATILE
,
118 (IsWow64()?KEY_WOW64_64KEY
:0)|mode
, NULL
, resultKeyP
, &keyDisp
);
120 status
= RegOpenKeyEx(key
, subKeyName
, (DWORD
)0, (IsWow64()?KEY_WOW64_64KEY
:0)|mode
, resultKeyP
);
123 if (resultKeyDispP
) {
124 *resultKeyDispP
= keyDisp
;
132 * RegQueryValueAlt() -- Read data associated with a key value.
133 * If a buffer is supplied (i.e., *dataPP is not NULL) then
134 * the data is placed in that buffer; in this case *dataSizeP
135 * is the buffer size on input and the data size on output.
136 * Otherwise, if *dataPP is NULL, a data buffer is allocated
137 * and *dataPP is set to point to that buffer.
139 * NOTE: dataTypeP can always be NULL, and dataSizeP can be NULL
140 * only if *dataPP is NULL.
144 RegQueryValueAlt(HKEY key
, /* [in] open key handle */
145 const char *valueName
, /* [in] value name */
146 DWORD
*dataTypeP
, /* [out] type of value's data */
147 void **dataPP
, /* [in/out] buffer for value's data */
148 DWORD
*dataSizeP
) /* [in/out] size of data (buffer) */
153 /* Use user-supplied data buffer; no real work */
154 status
= RegQueryValueEx(key
, valueName
, NULL
,
155 dataTypeP
, *dataPP
, dataSizeP
);
157 DWORD bufType
, bufSize
, dwordData
;
160 /* get size of value's data; optimize read for common REG_DWORD */
161 bufSize
= sizeof(DWORD
);
163 status
= RegQueryValueEx(key
, valueName
, NULL
,
164 &bufType
, (void*)&dwordData
, &bufSize
);
166 if (status
== ERROR_SUCCESS
|| status
== ERROR_MORE_DATA
) {
167 /* allocate buffer for value's data */
168 buf
= malloc(bufSize
);
171 status
= ERROR_NOT_ENOUGH_MEMORY
;
173 if (status
== ERROR_SUCCESS
) {
174 /* data fit in DWORD buffer; don't read registry again */
175 memcpy(buf
, &dwordData
, bufSize
);
177 /* data did not fit in DWORD buffer; read registry again */
178 status
= RegQueryValueEx(key
, valueName
, NULL
,
179 &bufType
, buf
, &bufSize
);
182 if (status
== ERROR_SUCCESS
) {
183 /* return requested results */
185 if (dataTypeP
) *dataTypeP
= bufType
;
186 if (dataSizeP
) *dataSizeP
= bufSize
;
188 /* registry read failed */
201 * RegEnumKeyAlt() -- Enumerate subkey names of specified key.
202 * Subkey names are returned in a single multistring (REG_MULTI_SZ).
203 * If the key has no subkeys, then *subkeyNames is set to NULL.
205 * Note: A multistring is a char buffer containing individual strings
206 * separated by a '\0' char with the last string being followed by
211 RegEnumKeyAlt(HKEY key
, /* [in] open key handle */
212 char **subkeyNames
) /* [out] subkey name buf (multistring) */
215 DWORD skCount
, skNameLenMax
;
216 char *skNameBuf
= NULL
;
218 status
= RegQueryInfoKey(key
,
220 &skCount
, &skNameLenMax
,
221 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
223 if (status
== ERROR_SUCCESS
&& skCount
> 0) {
224 skNameBuf
= malloc((skCount
* (skNameLenMax
+ 1)) + 1);
227 status
= ERROR_NOT_ENOUGH_MEMORY
;
230 char *skBufP
= skNameBuf
;
232 for (i
= 0; i
< skCount
&& status
== ERROR_SUCCESS
; i
++) {
233 skFillLen
= skNameLenMax
+ 1;
234 status
= RegEnumKeyEx(key
, i
, skBufP
, &skFillLen
,
235 NULL
, NULL
, NULL
, NULL
);
236 if (status
== ERROR_SUCCESS
) {
237 skBufP
+= skFillLen
+ 1;
242 if (status
!= ERROR_SUCCESS
) {
249 *subkeyNames
= skNameBuf
;
255 * RegDeleteKeyAlt() -- Delete named subkey and all its subkeys and values.
257 * This is just a recursive version of RegDeleteKey(), which does not
258 * recurse on NT (though it does on Win95/98).
261 RegDeleteKeyAlt(HKEY key
,
262 const char *subKeyName
)
266 status
= RegDeleteKey(key
, subKeyName
);
268 if (status
!= ERROR_SUCCESS
) {
269 /* determine if delete failed due to subkeys */
272 status
= RegOpenKeyEx(key
, subKeyName
, 0, (IsWow64()?KEY_WOW64_64KEY
:0)|KEY_ALL_ACCESS
, &subKey
);
273 if (status
== ERROR_SUCCESS
) {
276 status
= RegEnumKeyAlt(subKey
, &keyEnum
);
277 if (status
== ERROR_SUCCESS
&& keyEnum
!= NULL
) {
278 /* subkeys found; try to delete each; ignore errors */
281 for (keyEnumName
= keyEnum
;
282 *keyEnumName
!= '\0';
283 keyEnumName
+= strlen(keyEnumName
) + 1) {
284 (void) RegDeleteKeyAlt(subKey
, keyEnumName
);
288 (void) RegCloseKey(subKey
);
291 /* try delete again */
292 status
= RegDeleteKey(key
, subKeyName
);
299 * RegDeleteEntryAlt() -- delete named key or value; if key, then all subkeys
300 * and values are removed; entryName must be in canonical path format.
303 RegDeleteEntryAlt(const char *entryName
, regentry_t entryType
)
305 long status
= ERROR_SUCCESS
;
306 char *entryBuf
= _strdup(entryName
);
308 if (entryBuf
== NULL
) {
309 status
= ERROR_NOT_ENOUGH_MEMORY
;
311 char *keyPath
= entryBuf
;
312 char *entryName
= strrchr(entryBuf
, '\\');
314 if (entryName
== NULL
) {
315 status
= ERROR_INVALID_PARAMETER
;
322 status
= RegOpenKeyAlt(AFSREG_NULL_KEY
,
323 keyPath
, KEY_ALL_ACCESS
, 0, &key
, NULL
);
324 if (status
== ERROR_SUCCESS
) {
325 if (entryType
== REGENTRY_KEY
) {
326 status
= RegDeleteKeyAlt(key
, entryName
);
327 } else if (entryType
== REGENTRY_VALUE
) {
328 status
= RegDeleteValue(key
, entryName
);
330 status
= ERROR_INVALID_PARAMETER
;
332 (void) RegCloseKey(key
);
342 * RegDupKeyAlt() -- duplicate sourceKey as targetKey; both sourceKey and
343 * targetKey must be in canonical path format.
345 * NOTE: if targetKey already exists it will be replaced.
348 RegDupKeyAlt(const char *sourceKey
, const char *targetKey
)
352 /* delete target key if extant */
353 status
= RegDeleteEntryAlt(targetKey
, REGENTRY_KEY
);
355 if (status
== ERROR_SUCCESS
|| status
== ERROR_FILE_NOT_FOUND
) {
356 status
= CopyKey(sourceKey
, targetKey
);
358 if (status
!= ERROR_SUCCESS
) {
359 /* clean-up partial duplication */
360 (void) RegDeleteEntryAlt(targetKey
, REGENTRY_KEY
);
368 /* ----------------------- local functions ----------------------- */
372 * CopyKey() -- worker function implementing RegDupKeyAlt().
374 * Note: - assumes target does not exist (i.e., deleted by RegDupKeyAlt())
375 * - no cleanup on failure (i.e., assumes done by RegDupKeyAlt())
378 CopyKey(const char *sourceKey
, const char *targetKey
)
383 /* open source key */
384 status
= RegOpenKeyAlt(AFSREG_NULL_KEY
, sourceKey
,
385 KEY_READ
, 0, &srcKey
, NULL
);
386 if (status
== ERROR_SUCCESS
) {
387 /* create target key */
388 status
= RegOpenKeyAlt(AFSREG_NULL_KEY
, targetKey
,
389 KEY_ALL_ACCESS
, 1 /* create */, &dupKey
, NULL
);
390 if (status
== ERROR_SUCCESS
) {
391 /* copy values and their data from source to target */
392 status
= CopyValues(srcKey
, dupKey
);
394 if (status
== ERROR_SUCCESS
) {
395 /* copy subkeys from source to target */
396 status
= CopySubkeys(sourceKey
, srcKey
, targetKey
, dupKey
);
398 (void) RegCloseKey(dupKey
);
400 (void) RegCloseKey(srcKey
);
407 * CopyValues() -- copy values and their data from srcKey to dupKey
410 CopyValues(HKEY srcKey
, HKEY dupKey
)
413 DWORD valCount
, valNameLenMax
, valDataLenMax
;
415 status
= RegQueryInfoKey(srcKey
,
416 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
417 &valCount
, &valNameLenMax
, &valDataLenMax
,
420 if (status
== ERROR_SUCCESS
&& valCount
> 0) {
421 char *valBuffer
= malloc(valNameLenMax
+ 1 + valDataLenMax
);
423 if (valBuffer
== NULL
) {
424 status
= ERROR_NOT_ENOUGH_MEMORY
;
427 char *valName
= valBuffer
;
428 char *valData
= valBuffer
+ (valNameLenMax
+ 1);
430 for (i
= 0; i
< valCount
&& status
== ERROR_SUCCESS
; i
++) {
431 DWORD valNameFillLen
= valNameLenMax
+ 1;
432 DWORD valDataFillLen
= valDataLenMax
;
435 status
= RegEnumValue(srcKey
, i
,
436 valName
, &valNameFillLen
,
439 valData
, &valDataFillLen
);
441 if (status
== ERROR_SUCCESS
) {
442 status
= RegSetValueEx(dupKey
,
445 valData
, valDataFillLen
);
456 * CopySubkeys() -- copy subkeys from srcKey to dupKey
458 * Note - srcName and dupName are the canonical path names of the
459 * open keys srcKey and dupKey, respectively.
462 CopySubkeys(const char *srcName
, HKEY srcKey
, const char *dupName
, HKEY dupKey
)
467 status
= RegEnumKeyAlt(srcKey
, &skEnum
);
469 if (status
== ERROR_SUCCESS
&& skEnum
!= NULL
) {
470 char *skEnumName
, *skNameBuf
;
471 size_t skSrcNameMax
, skDupNameMax
, skNameMax
;
475 while (*skEnumName
!= '\0') {
476 size_t skNameLen
= strlen(skEnumName
);
477 skNameMax
= max(skNameMax
, skNameLen
);
479 skEnumName
+= skNameLen
+ 1;
482 skSrcNameMax
= strlen(srcName
) + 1 + skNameMax
+ 1;
483 skDupNameMax
= strlen(dupName
) + 1 + skNameMax
+ 1;
485 skNameBuf
= malloc(skSrcNameMax
+ skDupNameMax
);
486 if (skNameBuf
== NULL
) {
487 status
= ERROR_NOT_ENOUGH_MEMORY
;
489 char *skSrcName
= skNameBuf
;
490 char *skDupName
= skNameBuf
+ skSrcNameMax
;
492 for (skEnumName
= skEnum
;
493 *skEnumName
!= '\0' && status
== ERROR_SUCCESS
;
494 skEnumName
+= strlen(skEnumName
) + 1) {
495 sprintf(skSrcName
, "%s\\%s", srcName
, skEnumName
);
496 sprintf(skDupName
, "%s\\%s", dupName
, skEnumName
);
498 status
= CopyKey(skSrcName
, skDupName
);