/* registry.cc: registry interface This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" #include "registry.h" #include "cygerrno.h" #include "path.h" #include "fhandler.h" #include "dtable.h" #include "cygheap.h" #include "tls_pbuf.h" #include "ntdll.h" #include /* Opens a key under the appropriate Cygwin key. Do not use HKCU per MS KB 199190 */ static NTSTATUS top_key (bool isHKLM, REGSAM access, PHANDLE top) { WCHAR rbuf[PATH_MAX], *p; UNICODE_STRING rpath; OBJECT_ATTRIBUTES attr; NTSTATUS status; InitializeObjectAttributes (&attr, &rpath, OBJ_CASE_INSENSITIVE, NULL, NULL); if (isHKLM) { wcpcpy (rbuf, L"\\Registry\\Machine"); RtlInitUnicodeString (&rpath, rbuf); status = NtOpenKey (top, access, &attr); } else { WCHAR name[128]; PCWSTR names[2] = {cygheap->user.get_windows_id (name), L".DEFAULT"}; p = wcpcpy (rbuf, L"\\Registry\\User\\"); for (int i = 0; i < 2; i++) { wcpcpy (p, names[i]); RtlInitUnicodeString (&rpath, rbuf); status = NtOpenKey (top, access, &attr); if (NT_SUCCESS (status)) break; } } return status; } reg_key::reg_key (HKEY top, REGSAM access, ...): _disposition (0) { va_list av; va_start (av, access); build_reg (top, access, av); va_end (av); } reg_key::reg_key (bool isHKLM, REGSAM access, ...): _disposition (0) { va_list av; HANDLE top; key_is_invalid = top_key (isHKLM, access, &top); if (NT_SUCCESS (key_is_invalid)) { new (this) reg_key ((HKEY) top, access, L"SOFTWARE", _WIDE (CYGWIN_INFO_CYGWIN_REGISTRY_NAME), NULL); NtClose (top); if (key_is_invalid) return; top = key; va_start (av, access); build_reg ((HKEY) top, access, av); va_end (av); if (top != key) NtClose (top); } } void reg_key::build_reg (HKEY top, REGSAM access, va_list av) { PWCHAR name; HANDLE r; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; if (top != HKEY_LOCAL_MACHINE && top != HKEY_CURRENT_USER) r = (HANDLE) top; else if (!NT_SUCCESS (top_key (top == HKEY_LOCAL_MACHINE, access, &r))) return; key_is_invalid = 0; while ((name = va_arg (av, PWCHAR)) != NULL) { RtlInitUnicodeString (&uname, name); InitializeObjectAttributes (&attr, &uname, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, r, NULL); status = NtCreateKey (&key, access, &attr, 0, NULL, REG_OPTION_NON_VOLATILE, &_disposition); if (r != (HANDLE) top) NtClose (r); r = key; if (!NT_SUCCESS (status)) { key_is_invalid = status; debug_printf ("failed to create key %S in the registry", &uname); break; } } } /* Given the current registry key, return the specific DWORD value requested. Return def on failure. */ DWORD reg_key::get_dword (PCWSTR name, DWORD def) { if (key_is_invalid) return def; NTSTATUS status; UNICODE_STRING uname; ULONG size = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + sizeof (DWORD); ULONG rsize; PKEY_VALUE_PARTIAL_INFORMATION vbuf = (PKEY_VALUE_PARTIAL_INFORMATION) alloca (size); RtlInitUnicodeString (&uname, name); status = NtQueryValueKey (key, &uname, KeyValuePartialInformation, vbuf, size, &rsize); if (status != STATUS_SUCCESS || vbuf->Type != REG_DWORD) return def; DWORD *dst = (DWORD *) vbuf->Data; return *dst; } /* Given the current registry key, set a specific DWORD value. */ NTSTATUS reg_key::set_dword (PCWSTR name, DWORD val) { if (key_is_invalid) return key_is_invalid; DWORD value = (DWORD) val; UNICODE_STRING uname; RtlInitUnicodeString (&uname, name); return NtSetValueKey (key, &uname, 0, REG_DWORD, &value, sizeof (value)); } /* Given the current registry key, return the specific string value requested. Return zero on success, non-zero on failure. */ NTSTATUS reg_key::get_string (PCWSTR name, PWCHAR dst, size_t max, PCWSTR def) { NTSTATUS status; if (key_is_invalid) { status = key_is_invalid; if (def != NULL) wcpncpy (dst, def, max); } else { UNICODE_STRING uname; ULONG size = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + max * sizeof (WCHAR); ULONG rsize; PKEY_VALUE_PARTIAL_INFORMATION vbuf = (PKEY_VALUE_PARTIAL_INFORMATION) alloca (size); RtlInitUnicodeString (&uname, name); status = NtQueryValueKey (key, &uname, KeyValuePartialInformation, vbuf, size, &rsize); if (status != STATUS_SUCCESS || vbuf->Type != REG_SZ) wcpncpy (dst, def, max); else wcpncpy (dst, (PWCHAR) vbuf->Data, max); } return status; } /* Given the current registry key, set a specific string value. */ NTSTATUS reg_key::set_string (PCWSTR name, PCWSTR src) { if (key_is_invalid) return key_is_invalid; UNICODE_STRING uname; RtlInitUnicodeString (&uname, name); return NtSetValueKey (key, &uname, 0, REG_SZ, (PVOID) src, (wcslen (src) + 1) * sizeof (WCHAR)); } reg_key::~reg_key () { if (!key_is_invalid) NtClose (key); key_is_invalid = 1; }