Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / afsreg / afsreg.c
blob3564c3ca77f85ae63f33c9d2ef1a237904e5ee49
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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
8 */
10 #include <afs/param.h>
11 #include <afs/stds.h>
13 #include <windows.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <stdio.h>
19 #include "afsreg.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);
33 int IsWow64(void)
35 static int init = TRUE;
36 static int bIsWow64 = FALSE;
38 if (init) {
39 HMODULE hModule;
40 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
42 hModule = GetModuleHandle(TEXT("kernel32"));
43 if (hModule) {
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.
54 FreeLibrary(hModule);
56 init = FALSE;
58 return bIsWow64;
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
72 * can always be NULL.
75 long
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 */
83 long status;
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))
100 key = HKEY_USERS;
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))
106 key = HKEY_DYN_DATA;
107 else {
108 return ERROR_INVALID_PARAMETER;
111 subKeyName = tokenP + tokenSz + 1;
114 /* open (and possibly create) sub key */
115 if (create) {
116 status = RegCreateKeyEx(key, subKeyName,
117 (DWORD)0, "AFS", REG_OPTION_NON_VOLATILE,
118 (IsWow64()?KEY_WOW64_64KEY:0)|mode, NULL, resultKeyP, &keyDisp);
119 } else {
120 status = RegOpenKeyEx(key, subKeyName, (DWORD)0, (IsWow64()?KEY_WOW64_64KEY:0)|mode, resultKeyP);
123 if (resultKeyDispP) {
124 *resultKeyDispP = keyDisp;
127 return status;
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.
143 long
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) */
150 long status;
152 if (*dataPP) {
153 /* Use user-supplied data buffer; no real work */
154 status = RegQueryValueEx(key, valueName, NULL,
155 dataTypeP, *dataPP, dataSizeP);
156 } else {
157 DWORD bufType, bufSize, dwordData;
158 char *buf;
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);
170 if (!buf) {
171 status = ERROR_NOT_ENOUGH_MEMORY;
172 } else {
173 if (status == ERROR_SUCCESS) {
174 /* data fit in DWORD buffer; don't read registry again */
175 memcpy(buf, &dwordData, bufSize);
176 } else {
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 */
184 *dataPP = buf;
185 if (dataTypeP) *dataTypeP = bufType;
186 if (dataSizeP) *dataSizeP = bufSize;
187 } else {
188 /* registry read failed */
189 free(buf);
195 return status;
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
207 * two '\0' chars.
210 long
211 RegEnumKeyAlt(HKEY key, /* [in] open key handle */
212 char **subkeyNames) /* [out] subkey name buf (multistring) */
214 long status;
215 DWORD skCount, skNameLenMax;
216 char *skNameBuf = NULL;
218 status = RegQueryInfoKey(key,
219 NULL, NULL, NULL,
220 &skCount, &skNameLenMax,
221 NULL, NULL, NULL, NULL, NULL, NULL);
223 if (status == ERROR_SUCCESS && skCount > 0) {
224 skNameBuf = malloc((skCount * (skNameLenMax + 1)) + 1);
226 if (!skNameBuf) {
227 status = ERROR_NOT_ENOUGH_MEMORY;
228 } else {
229 DWORD i, skFillLen;
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;
240 *skBufP = '\0';
242 if (status != ERROR_SUCCESS) {
243 free(skNameBuf);
244 skNameBuf = NULL;
249 *subkeyNames = skNameBuf;
250 return status;
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).
260 long
261 RegDeleteKeyAlt(HKEY key,
262 const char *subKeyName)
264 long status;
266 status = RegDeleteKey(key, subKeyName);
268 if (status != ERROR_SUCCESS) {
269 /* determine if delete failed due to subkeys */
270 HKEY subKey;
272 status = RegOpenKeyEx(key, subKeyName, 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_ALL_ACCESS, &subKey);
273 if (status == ERROR_SUCCESS) {
274 char *keyEnum;
276 status = RegEnumKeyAlt(subKey, &keyEnum);
277 if (status == ERROR_SUCCESS && keyEnum != NULL) {
278 /* subkeys found; try to delete each; ignore errors */
279 char *keyEnumName;
281 for (keyEnumName = keyEnum;
282 *keyEnumName != '\0';
283 keyEnumName += strlen(keyEnumName) + 1) {
284 (void) RegDeleteKeyAlt(subKey, keyEnumName);
286 free(keyEnum);
288 (void) RegCloseKey(subKey);
291 /* try delete again */
292 status = RegDeleteKey(key, subKeyName);
294 return status;
299 * RegDeleteEntryAlt() -- delete named key or value; if key, then all subkeys
300 * and values are removed; entryName must be in canonical path format.
302 long
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;
310 } else {
311 char *keyPath = entryBuf;
312 char *entryName = strrchr(entryBuf, '\\');
314 if (entryName == NULL) {
315 status = ERROR_INVALID_PARAMETER;
316 } else {
317 HKEY key;
319 *entryName = '\0';
320 entryName++;
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);
329 } else {
330 status = ERROR_INVALID_PARAMETER;
332 (void) RegCloseKey(key);
335 free(entryBuf);
337 return status;
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.
347 long
348 RegDupKeyAlt(const char *sourceKey, const char *targetKey)
350 long status;
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);
363 return status;
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())
377 static long
378 CopyKey(const char *sourceKey, const char *targetKey)
380 long status;
381 HKEY srcKey, dupKey;
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);
402 return status;
407 * CopyValues() -- copy values and their data from srcKey to dupKey
409 static long
410 CopyValues(HKEY srcKey, HKEY dupKey)
412 long status;
413 DWORD valCount, valNameLenMax, valDataLenMax;
415 status = RegQueryInfoKey(srcKey,
416 NULL, NULL, NULL, NULL, NULL, NULL,
417 &valCount, &valNameLenMax, &valDataLenMax,
418 NULL, NULL);
420 if (status == ERROR_SUCCESS && valCount > 0) {
421 char *valBuffer = malloc(valNameLenMax + 1 + valDataLenMax);
423 if (valBuffer == NULL) {
424 status = ERROR_NOT_ENOUGH_MEMORY;
425 } else {
426 DWORD i;
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;
433 DWORD valDataType;
435 status = RegEnumValue(srcKey, i,
436 valName, &valNameFillLen,
437 NULL,
438 &valDataType,
439 valData, &valDataFillLen);
441 if (status == ERROR_SUCCESS) {
442 status = RegSetValueEx(dupKey,
443 valName, 0,
444 valDataType,
445 valData, valDataFillLen);
448 free(valBuffer);
451 return status;
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.
461 static long
462 CopySubkeys(const char *srcName, HKEY srcKey, const char *dupName, HKEY dupKey)
464 long status;
465 char *skEnum;
467 status = RegEnumKeyAlt(srcKey, &skEnum);
469 if (status == ERROR_SUCCESS && skEnum != NULL) {
470 char *skEnumName, *skNameBuf;
471 size_t skSrcNameMax, skDupNameMax, skNameMax;
473 skNameMax = 0;
474 skEnumName = skEnum;
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;
488 } else {
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);
500 free(skNameBuf);
502 free(skEnum);
504 return status;