| /* 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 <wchar.h> |
| |
| /* 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; |
| } |