1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00
putty-source/windows/utils/registry.c

185 lines
5.3 KiB
C
Raw Permalink Normal View History

/*
* Implement convenience wrappers on the awkward low-level functions
* for accessing the Windows registry.
*/
#include "putty.h"
2022-09-14 15:04:14 +00:00
HKEY open_regkey_fn(bool create, bool write, HKEY hk, const char *path, ...)
{
HKEY toret = NULL;
bool hk_needs_close = false;
va_list ap;
va_start(ap, path);
for (; path; path = va_arg(ap, const char *)) {
HKEY hk_sub = NULL;
2022-09-14 15:04:14 +00:00
DWORD access = KEY_READ | (write ? KEY_WRITE : 0);
LONG status;
if (create)
status = RegCreateKeyEx(
hk, path, 0, NULL, REG_OPTION_NON_VOLATILE,
2022-09-14 15:04:14 +00:00
access, NULL, &hk_sub, NULL);
else
2022-09-14 15:04:14 +00:00
status = RegOpenKeyEx(hk, path, 0, access, &hk_sub);
if (status != ERROR_SUCCESS)
goto out;
if (hk_needs_close)
RegCloseKey(hk);
hk = hk_sub;
hk_needs_close = true;
}
toret = hk;
hk = NULL;
hk_needs_close = false;
out:
va_end(ap);
if (hk_needs_close)
RegCloseKey(hk);
return toret;
}
void close_regkey(HKEY key)
{
RegCloseKey(key);
}
void del_regkey(HKEY key, const char *name)
{
RegDeleteKey(key, name);
}
char *enum_regkey(HKEY key, int index)
{
size_t regbuf_size = MAX_PATH + 1;
char *regbuf = snewn(regbuf_size, char);
while (1) {
LONG status = RegEnumKey(key, index, regbuf, regbuf_size);
if (status == ERROR_SUCCESS)
return regbuf;
if (status != ERROR_MORE_DATA) {
sfree(regbuf);
return NULL;
}
sgrowarray(regbuf, regbuf_size, regbuf_size);
}
}
bool get_reg_dword(HKEY key, const char *name, DWORD *out)
{
DWORD type, size;
size = sizeof(*out);
if (RegQueryValueEx(key, name, 0, &type,
(BYTE *)out, &size) != ERROR_SUCCESS ||
size != sizeof(*out) || type != REG_DWORD)
return false;
else
return true;
}
bool put_reg_dword(HKEY key, const char *name, DWORD value)
{
return RegSetValueEx(key, name, 0, REG_DWORD, (CONST BYTE *) &value,
sizeof(value)) == ERROR_SUCCESS;
}
char *get_reg_sz(HKEY key, const char *name)
{
DWORD type, size;
if (RegQueryValueEx(key, name, 0, &type, NULL,
&size) != ERROR_SUCCESS || type != REG_SZ)
return NULL; /* not a string */
size_t allocsize = size+1; /* allow for an extra NUL if needed */
char *toret = snewn(allocsize, char);
if (RegQueryValueEx(key, name, 0, &type, (BYTE *)toret,
&size) != ERROR_SUCCESS || type != REG_SZ) {
sfree(toret);
return NULL;
}
assert(size < allocsize);
toret[size] = '\0'; /* add an extra NUL in case RegQueryValueEx
* didn't supply one */
return toret;
}
bool put_reg_sz(HKEY key, const char *name, const char *str)
{
/* You have to store the trailing NUL as well */
return RegSetValueEx(key, name, 0, REG_SZ, (CONST BYTE *)str,
1 + strlen(str)) == ERROR_SUCCESS;
}
/*
* REG_MULTI_SZ items are stored as a concatenation of NUL-terminated
* strings, terminated in turn with an empty string, i.e. a second
* consecutive NUL.
*
* We represent these in their storage format, as a strbuf - but
* *without* the second consecutive NUL.
*
* So you can build up a new MULTI_SZ value in a strbuf by calling
* put_asciz once per output string and then put_reg_multi_sz; and you
* can consume one by initialising a BinarySource to the result of
* get_reg_multi_sz, and then calling get_asciz on it and assuming
* that !get_err(src) means you have a real output string.
*
* Also, calling strbuf_to_str on one of these will give you back a
* bare 'char *' with the same double-NUL termination, to pass back to
* a caller.
*/
strbuf *get_reg_multi_sz(HKEY key, const char *name)
{
DWORD type, size;
if (RegQueryValueEx(key, name, 0, &type, NULL,
&size) != ERROR_SUCCESS || type != REG_MULTI_SZ)
return NULL; /* not a string */
strbuf *toret = strbuf_new();
void *ptr = strbuf_append(toret, (size_t)size + 2);
if (RegQueryValueEx(key, name, 0, &type, (BYTE *)ptr,
&size) != ERROR_SUCCESS || type != REG_MULTI_SZ) {
strbuf_free(toret);
return NULL;
}
strbuf_shrink_to(toret, size);
/* Ensure we end with exactly one \0 */
while (strbuf_chomp(toret, '\0'));
put_byte(toret, '\0');
return toret;
}
bool put_reg_multi_sz(HKEY key, const char *name, strbuf *str)
{
/*
* Of course, to write our string list into the registry, we _do_
* have to include both trailing NULs. But this is easy, because a
* strbuf is also designed to hold a single string and make it
* conveniently accessible in NUL-terminated form, so it stores a
* NUL in its buffer just beyond its formal length. So we just
* include that extra byte in the data we write.
*/
return RegSetValueEx(key, name, 0, REG_MULTI_SZ, (CONST BYTE *)str->s,
str->len + 1) == ERROR_SUCCESS;
}
char *get_reg_sz_simple(HKEY key, const char *name, const char *leaf)
{
2022-09-14 15:04:14 +00:00
HKEY subkey = open_regkey_ro(key, name);
if (!subkey)
return NULL;
char *toret = get_reg_sz(subkey, leaf);
RegCloseKey(subkey);
return toret;
}