| /* regtool.cc |
| |
| 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 <stdio.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <ctype.h> |
| #include <wchar.h> |
| #include <getopt.h> |
| #include <locale.h> |
| #define WINVER 0x0502 |
| #include <windows.h> |
| #include <sys/cygwin.h> |
| #include <cygwin/version.h> |
| #include "loadlib.h" |
| |
| #define DEFAULT_KEY_SEPARATOR '\\' |
| |
| #define REG_AUTO -1 |
| |
| int value_type = REG_AUTO; |
| |
| char key_sep = DEFAULT_KEY_SEPARATOR; |
| |
| #define LIST_KEYS 0x01 |
| #define LIST_VALS 0x02 |
| #define LIST_ALL (LIST_KEYS | LIST_VALS) |
| |
| static char *prog_name; |
| |
| static struct option longopts[] = |
| { |
| {"binary", no_argument, NULL, 'b' }, |
| {"dword", no_argument, NULL, 'd' }, |
| {"dword-be", no_argument, NULL, 'D' }, |
| {"expand-string", no_argument, NULL, 'e' }, |
| {"force", no_argument, NULL, 'f' }, |
| {"help", no_argument, NULL, 'h' }, |
| {"integer", no_argument, NULL, 'i' }, |
| {"keys", no_argument, NULL, 'k'}, |
| {"list", no_argument, NULL, 'l'}, |
| {"multi-string", no_argument, NULL, 'm'}, |
| {"none", no_argument, NULL, 'n' }, |
| {"postfix", no_argument, NULL, 'p'}, |
| {"quiet", no_argument, NULL, 'q'}, |
| {"qword", no_argument, NULL, 'Q' }, |
| {"string", no_argument, NULL, 's'}, |
| {"verbose", no_argument, NULL, 'v'}, |
| {"version", no_argument, NULL, 'V'}, |
| {"wow64", no_argument, NULL, 'w'}, |
| {"wow32", no_argument, NULL, 'W'}, |
| {"hex", no_argument, NULL, 'x'}, |
| {"key-separator", required_argument, NULL, 'K'}, |
| {NULL, 0, NULL, 0} |
| }; |
| |
| static char opts[] = "bdDefhiklmnpqQsvVwWxK:"; |
| |
| const char *types[] = |
| { |
| "REG_NONE", |
| "REG_SZ", |
| "REG_EXPAND_SZ", |
| "REG_BINARY", |
| "REG_DWORD", |
| "REG_DWORD_BIG_ENDIAN", |
| "REG_LINK", |
| "REG_MULTI_SZ", |
| "REG_RESOURCE_LIST", |
| "REG_FULL_RESOURCE_DESCRIPTOR", |
| "REG_RESOURCE_REQUIREMENTS_LIST", |
| "REG_QWORD", |
| }; |
| |
| int listwhat = 0; |
| int postfix = 0; |
| int verbose = 0; |
| int quiet = 0; |
| int hex = 0; |
| DWORD wow64 = 0; |
| DWORD restore_flags = 0; |
| char **argv; |
| |
| HKEY key; |
| wchar_t *value; |
| |
| static void |
| usage (FILE *where = stderr) |
| { |
| fprintf (where, "" |
| "Usage: %s [OPTION] ACTION KEY [data...]\n" |
| "\n" |
| "View or edit the Win32 registry\n" |
| "\n", prog_name); |
| if (where == stdout) |
| { |
| fprintf (where, "" |
| "Actions:\n" |
| "\n" |
| " add KEY\\SUBKEY add new SUBKEY\n" |
| " check KEY exit 0 if KEY exists, 1 if not\n" |
| " get KEY\\VALUE prints VALUE to stdout\n" |
| " list KEY list SUBKEYs and VALUEs\n" |
| " remove KEY remove KEY\n" |
| " set KEY\\VALUE [data ...] set VALUE\n" |
| " unset KEY\\VALUE removes VALUE from KEY\n" |
| " load KEY\\SUBKEY PATH load hive from PATH into new SUBKEY\n" |
| " unload KEY\\SUBKEY unload hive and remove SUBKEY\n" |
| " save KEY\\SUBKEY PATH save SUBKEY into new file PATH\n" |
| " restore KEY\\SUBKEY PATH restore SUBKEY from file PATH\n" |
| "\n"); |
| fprintf (where, "" |
| "Options for 'list' action:\n" |
| "\n" |
| " -k, --keys print only KEYs\n" |
| " -l, --list print only VALUEs\n" |
| " -p, --postfix like ls -p, appends '\\' postfix to KEY names\n" |
| "\n" |
| "Options for 'get' action:\n" |
| "\n" |
| " -b, --binary print data as printable hex bytes\n" |
| " -n, --none print data as stream of bytes as stored in registry\n" |
| " -x, --hex print numerical data as hex numbers\n" |
| "\n" |
| "Options for 'set' action:\n" |
| "\n" |
| " -b, --binary set type to REG_BINARY (hex args or '-')\n" |
| " -d, --dword set type to REG_DWORD\n" |
| " -D, --dword-be set type to REG_DWORD_BIG_ENDIAN\n" |
| " -e, --expand-string set type to REG_EXPAND_SZ\n" |
| " -i, --integer set type to REG_DWORD\n" |
| " -m, --multi-string set type to REG_MULTI_SZ\n" |
| " -n, --none set type to REG_NONE\n" |
| " -Q, --qword set type to REG_QWORD\n" |
| " -s, --string set type to REG_SZ\n" |
| "\n" |
| "Options for 'set' and 'unset' Actions:\n" |
| "\n" |
| " -K<c>, --key-separator[=]<c> set key-value separator to <c> instead of '\\'\n" |
| "\n" |
| "Options for 'restore' action:\n" |
| "\n" |
| " -f, --force restore even if open handles exist at or beneath the location\n" |
| " in the registry hierarchy to which KEY\\SUBKEY points\n" |
| "\n" |
| "Other Options:\n" |
| "\n" |
| " -h, --help output usage information and exit\n" |
| " -q, --quiet no error output, just nonzero return if KEY/VALUE missing\n" |
| " -v, --verbose verbose output, including VALUE contents when applicable\n" |
| " -w, --wow64 access 64 bit registry view (ignored on 32 bit Windows)\n" |
| " -W, --wow32 access 32 bit registry view (ignored on 32 bit Windows)\n" |
| " -V, --version output version information and exit\n" |
| "\n"); |
| fprintf (where, "" |
| "KEY is in the format [host]\\prefix\\KEY\\KEY\\VALUE, where host is optional\n" |
| "remote host in either \\\\hostname or hostname: format and prefix is any of:\n" |
| " root HKCR HKEY_CLASSES_ROOT (local only)\n" |
| " config HKCC HKEY_CURRENT_CONFIG (local only)\n" |
| " user HKCU HKEY_CURRENT_USER (local only)\n" |
| " machine HKLM HKEY_LOCAL_MACHINE\n" |
| " users HKU HKEY_USERS\n" |
| "\n" |
| "If the keyname starts with a forward slash ('/'), the forward slash is used\n" |
| "as separator and the backslash can be used as escape character.\n"); |
| fprintf (where, "" |
| "Example:\n" |
| "%s list '/machine/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n\n", prog_name); |
| } |
| if (where == stderr) |
| fprintf (where, |
| "ACTION is one of add, check, get, list, remove, set, unset, load, unload, save\n" |
| "\n" |
| "Try `%s --help' for more information.\n", prog_name); |
| exit (where == stderr ? 1 : 0); |
| } |
| |
| static void |
| print_version () |
| { |
| printf ("regtool (cygwin) %d.%d.%d\n" |
| "Registry tool\n" |
| "Copyright (C) 2000 - %s Cygwin Authors\n" |
| "This is free software; see the source for copying conditions. There is NO\n" |
| "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", |
| CYGWIN_VERSION_DLL_MAJOR / 1000, |
| CYGWIN_VERSION_DLL_MAJOR % 1000, |
| CYGWIN_VERSION_DLL_MINOR, |
| strrchr (__DATE__, ' ') + 1); |
| } |
| |
| void |
| Fail (unsigned int rv) |
| { |
| wchar_t *buf; |
| |
| if (!quiet) |
| { |
| FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
| | FORMAT_MESSAGE_FROM_SYSTEM, |
| 0, rv, 0, (WCHAR *)& buf, 0, 0); |
| fprintf (stderr, "Error (%d): %ls\n", rv, buf); |
| LocalFree (buf); |
| } |
| exit (1); |
| } |
| |
| static struct |
| { |
| const char *string; |
| HKEY key; |
| } wkprefixes[] = |
| { |
| {"root", HKEY_CLASSES_ROOT}, |
| {"HKCR", HKEY_CLASSES_ROOT}, |
| {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT}, |
| {"config", HKEY_CURRENT_CONFIG}, |
| {"HKCC", HKEY_CURRENT_CONFIG}, |
| {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG}, |
| {"user", HKEY_CURRENT_USER}, |
| {"HKCU", HKEY_CURRENT_USER}, |
| {"HKEY_CURRENT_USER", HKEY_CURRENT_USER}, |
| {"machine", HKEY_LOCAL_MACHINE}, |
| {"HKLM", HKEY_LOCAL_MACHINE}, |
| {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE}, |
| {"users", HKEY_USERS}, |
| {"HKU", HKEY_USERS}, |
| {"HKEY_USERS", HKEY_USERS}, |
| {0, 0} |
| }; |
| |
| void |
| translate (char *key) |
| { |
| #define isodigit(c) (strchr("01234567", c)) |
| #define tooct(c) ((c)-'0') |
| #define tohex(c) (strchr(_hs,tolower(c))-_hs) |
| static char _hs[] = "0123456789abcdef"; |
| |
| char *d = key; |
| char *s = key; |
| char c; |
| |
| while (*s) |
| { |
| if (*s == '\\') |
| switch (*++s) |
| { |
| case 'a': |
| *d++ = '\007'; |
| break; |
| case 'b': |
| *d++ = '\b'; |
| break; |
| case 'e': |
| *d++ = '\033'; |
| break; |
| case 'f': |
| *d++ = '\f'; |
| break; |
| case 'n': |
| *d++ = '\n'; |
| break; |
| case 'r': |
| *d++ = '\r'; |
| break; |
| case 't': |
| *d++ = '\t'; |
| break; |
| case 'v': |
| *d++ = '\v'; |
| break; |
| case '0': |
| case '1': |
| case '2': |
| case '3': |
| case '4': |
| case '5': |
| case '6': |
| case '7': |
| c = tooct (*s); |
| if (isodigit (s[1])) |
| { |
| c = (c << 3) | tooct (*++s); |
| if (isodigit (s[1])) |
| c = (c << 3) | tooct (*++s); |
| } |
| *d++ = c; |
| break; |
| case 'x': |
| if (!isxdigit (s[1])) |
| c = '0'; |
| else |
| { |
| c = tohex (*++s); |
| if (isxdigit (s[1])) |
| c = (c << 4) | tohex (*++s); |
| } |
| *d++ = c; |
| break; |
| default: /* before non-special char: just add the char */ |
| *d++ = *s; |
| break; |
| } |
| else if (*s == '/') |
| *d++ = '\\'; |
| else |
| *d++ = *s; |
| ++s; |
| } |
| *d = '\0'; |
| } |
| |
| void |
| find_key (int howmanyparts, REGSAM access, int option = 0) |
| { |
| HKEY base; |
| int rv; |
| char *n = argv[0], *e, *h, c; |
| char* host = NULL; |
| int i; |
| size_t len; |
| |
| if (*n == '/') |
| translate (n); |
| if (*n != '\\') |
| { |
| /* expect host:/key/value format */ |
| host = (char*) malloc (strlen (n) + 1); |
| host[0] = host [1] = '\\'; |
| for (e = n, h = host + 2; *e && *e != ':'; e++, h++) |
| *h = *e; |
| *h = 0; |
| n = e + 1; |
| if (*n == '/') |
| translate (n); |
| } |
| else if (n[0] == '\\' && n[1] == '\\') |
| { |
| /* expect //host/key/value format */ |
| host = (char*) malloc (strlen (n) + 1); |
| host[0] = host[1] = '\\'; |
| for (e = n + 2, h = host + 2; *e && *e != '\\'; e++, h++) |
| *h = *e; |
| *h = 0; |
| n = e; |
| } |
| while (*n != '\\') |
| n++; |
| *n++ = 0; |
| for (e = n; *e && *e != '\\'; e++); |
| c = *e; |
| *e = 0; |
| for (i = 0; wkprefixes[i].string; i++) |
| if (strcmp (wkprefixes[i].string, n) == 0) |
| break; |
| if (!wkprefixes[i].string) |
| { |
| fprintf (stderr, "Unknown key prefix. Valid prefixes are:\n"); |
| for (i = 0; wkprefixes[i].string; i++) |
| fprintf (stderr, "\t%s\n", wkprefixes[i].string); |
| exit (1); |
| } |
| |
| n = e; |
| *e = c; |
| while (*n && *n == '\\') |
| n++; |
| e = n + strlen (n); |
| if (howmanyparts > 1) |
| { |
| while (n < e && *e != key_sep) |
| e--; |
| if (*e != key_sep) |
| { |
| key = wkprefixes[i].key; |
| if (value) |
| free (value); |
| len = mbstowcs (NULL, n, 0) + 1; |
| value = (wchar_t *) malloc (len * sizeof (wchar_t)); |
| mbstowcs (value, n, len); |
| return; |
| } |
| else |
| { |
| *e = 0; |
| if (value) |
| free (value); |
| len = mbstowcs (NULL, e + 1, 0) + 1; |
| value = (wchar_t *) malloc (len * sizeof (wchar_t)); |
| mbstowcs (value, e + 1, len); |
| } |
| } |
| if (host) |
| { |
| rv = RegConnectRegistry (host, wkprefixes[i].key, &base); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| free (host); |
| } |
| else |
| base = wkprefixes[i].key; |
| |
| if (n[0] == 0) |
| key = base; |
| else |
| { |
| len = mbstowcs (NULL, n, 0) + 1; |
| wchar_t name[len]; |
| mbstowcs (name, n, len); |
| if (access) |
| { |
| rv = RegOpenKeyExW (base, name, 0, access | wow64, &key); |
| if (option && (rv == ERROR_SUCCESS || rv == ERROR_ACCESS_DENIED)) |
| { |
| /* reopen with desired option due to missing option support in |
| RegOpenKeyE */ |
| /* FIXME: may create the key in rare cases (e.g. access denied |
| in parent) */ |
| HKEY key2; |
| if (RegCreateKeyExW (base, name, 0, NULL, option, access | wow64, |
| NULL, &key2, NULL) |
| == ERROR_SUCCESS) |
| { |
| if (rv == ERROR_SUCCESS) |
| RegCloseKey (key); |
| key = key2; |
| rv = ERROR_SUCCESS; |
| } |
| } |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| } |
| else if (argv[1]) |
| { |
| ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0); |
| wchar_t win32_path[len]; |
| cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len); |
| rv = RegLoadKeyW (base, name, win32_path); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| if (verbose) |
| printf ("key %ls loaded from file %ls\n", name, win32_path); |
| } |
| else |
| { |
| rv = RegUnLoadKeyW (base, name); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| if (verbose) |
| printf ("key %ls unloaded\n", name); |
| } |
| } |
| } |
| |
| |
| int |
| cmd_list () |
| { |
| DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen; |
| DWORD maxclasslen; |
| wchar_t *subkey_name, *value_name, *class_name, *vd; |
| unsigned char *value_data; |
| DWORD i, j, m, n, t; |
| int v; |
| |
| find_key (1, KEY_READ); |
| RegQueryInfoKeyW (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen, |
| &num_values, &maxvalnamelen, &maxvaluelen, 0, 0); |
| |
| subkey_name = (wchar_t *) malloc ((maxsubkeylen + 1) * sizeof (wchar_t)); |
| class_name = (wchar_t *) malloc ((maxclasslen + 1) * sizeof (wchar_t)); |
| value_name = (wchar_t *) malloc ((maxvalnamelen + 1) * sizeof (wchar_t)); |
| value_data = (unsigned char *) malloc (maxvaluelen + 1); |
| |
| if (!listwhat) |
| listwhat = LIST_ALL; |
| |
| if (listwhat & LIST_KEYS) |
| for (i = 0; i < num_subkeys; i++) |
| { |
| m = (maxsubkeylen + 1) * sizeof (wchar_t); |
| n = (maxclasslen + 1) * sizeof (wchar_t); |
| RegEnumKeyExW (key, i, subkey_name, &m, 0, class_name, &n, 0); |
| printf ("%ls", subkey_name); |
| if (postfix || verbose) |
| fputc (key_sep, stdout); |
| |
| if (verbose) |
| printf (" (%ls)", class_name); |
| |
| puts (""); |
| } |
| |
| if (listwhat & LIST_VALS) |
| for (i = 0; i < num_values; i++) |
| { |
| m = (maxvalnamelen + 1) * sizeof (wchar_t); |
| n = maxvaluelen + 1; |
| RegEnumValueW (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n); |
| value_data[n] = 0; |
| if (!verbose) |
| printf ("%ls\n", value_name); |
| else |
| { |
| printf ("%ls (%s) = ", value_name, types[t]); |
| switch (t) |
| { |
| case REG_NONE: |
| case REG_BINARY: |
| for (j = 0; j < 8 && j < n; j++) |
| printf ("%02x ", value_data[j]); |
| printf ("\n"); |
| break; |
| case REG_DWORD: |
| printf ("0x%08x (%u)\n", *(unsigned int *) value_data, |
| *(unsigned int *) value_data); |
| break; |
| case REG_DWORD_BIG_ENDIAN: |
| v = ((value_data[0] << 24) |
| | (value_data[1] << 16) |
| | (value_data[2] << 8) |
| | (value_data[3])); |
| printf ("0x%08x (%d)\n", v, v); |
| break; |
| case REG_QWORD: |
| printf ("0x%016llx (%llu)\n", |
| *(unsigned long long *) value_data, |
| *(unsigned long long *) value_data); |
| break; |
| case REG_EXPAND_SZ: |
| case REG_SZ: |
| case REG_LINK: |
| printf ("\"%ls\"\n", (wchar_t *) value_data); |
| break; |
| case REG_MULTI_SZ: |
| vd = (wchar_t *) value_data; |
| while (vd && *vd) |
| { |
| printf ("\"%ls\"", vd); |
| vd = vd + wcslen (vd) + 1; |
| if (*vd) |
| printf (", "); |
| } |
| printf ("\n"); |
| break; |
| default: |
| printf ("?\n"); |
| break; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| int |
| cmd_add () |
| { |
| find_key (2, KEY_ALL_ACCESS); |
| HKEY newkey; |
| DWORD newtype; |
| int rv = RegCreateKeyExW (key, value, 0, NULL, REG_OPTION_NON_VOLATILE, |
| KEY_ALL_ACCESS | wow64, 0, &newkey, &newtype); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| |
| if (verbose) |
| { |
| if (newtype == REG_OPENED_EXISTING_KEY) |
| printf ("Key %ls already exists\n", value); |
| else |
| printf ("Key %ls created\n", value); |
| } |
| return 0; |
| } |
| |
| extern "C" { |
| LONG WINAPI (*regDeleteKeyEx)(HKEY, LPCWSTR, REGSAM, DWORD); |
| } |
| |
| int |
| cmd_remove () |
| { |
| DWORD rv; |
| |
| find_key (2, KEY_ALL_ACCESS); |
| if (wow64) |
| { |
| HMODULE mod = LoadLibrary ("advapi32.dll"); |
| if (mod) |
| regDeleteKeyEx = (LONG WINAPI (*)(HKEY, LPCWSTR, REGSAM, DWORD)) GetProcAddress (mod, "RegDeleteKeyExW"); |
| } |
| if (regDeleteKeyEx) |
| rv = (*regDeleteKeyEx) (key, value, wow64, 0); |
| else |
| rv = RegDeleteKeyW (key, value); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| if (verbose) |
| printf ("subkey %ls deleted\n", value); |
| return 0; |
| } |
| |
| int |
| cmd_check () |
| { |
| find_key (1, KEY_READ); |
| if (verbose) |
| printf ("key %s exists\n", argv[0]); |
| return 0; |
| } |
| |
| int |
| cmd_set () |
| { |
| int i, n, max_n; |
| DWORD v, rv; |
| unsigned long long llval; |
| char *a = argv[1], *data = 0; |
| find_key (2, KEY_ALL_ACCESS); |
| |
| if (!a) |
| usage (); |
| if (value_type == REG_AUTO) |
| { |
| char *e; |
| llval = strtoull (a, &e, 0); |
| if (a[0] == '%') |
| value_type = REG_EXPAND_SZ; |
| else if (a[0] && !*e) |
| value_type = llval > 0xffffffffULL ? REG_QWORD : REG_DWORD; |
| else if (argv[2]) |
| value_type = REG_MULTI_SZ; |
| else |
| value_type = REG_SZ; |
| } |
| |
| switch (value_type) |
| { |
| case REG_NONE: |
| case REG_BINARY: |
| for (n = 0; argv[n+1]; n++) |
| ; |
| if (n == 1 && strcmp (argv[1], "-") == 0) |
| { /* read from stdin */ |
| i = n = 0; |
| for (;;) |
| { |
| if (i <= n) |
| { |
| i = n + BUFSIZ; |
| data = (char *) realloc (data, i); |
| } |
| int r = fread (data+n, 1, i-n, stdin); |
| if (r <= 0) |
| break; |
| n += r; |
| } |
| } |
| else if (n > 0) |
| { /* parse hex from argv */ |
| data = (char *) malloc (n); |
| for (i = 0; i < n; i++) |
| { |
| char *e; |
| errno = 0; |
| v = strtoul (argv[i+1], &e, 16); |
| if (errno || v > 0xff || *e) |
| { |
| fprintf (stderr, "Invalid hex constant `%s'\n", argv[i+1]); |
| exit (1); |
| } |
| data[i] = (char) v; |
| } |
| } |
| rv = RegSetValueExW (key, value, 0, value_type, (const BYTE *) data, n); |
| break; |
| case REG_DWORD: |
| v = strtoul (a, 0, 0); |
| rv = RegSetValueExW (key, value, 0, REG_DWORD, (const BYTE *) &v, |
| sizeof (v)); |
| break; |
| case REG_DWORD_BIG_ENDIAN: |
| v = strtoul (a, 0, 0); |
| v = (((v & 0xff) << 24) |
| | ((v & 0xff00) << 8) |
| | ((v & 0xff0000) >> 8) |
| | ((v & 0xff000000) >> 24)); |
| rv = RegSetValueExW (key, value, 0, REG_DWORD_BIG_ENDIAN, |
| (const BYTE *) &v, sizeof (v)); |
| break; |
| case REG_QWORD: |
| llval = strtoul (a, 0, 0); |
| rv = RegSetValueExW (key, value, 0, REG_QWORD, (const BYTE *) &llval, |
| sizeof (llval)); |
| break; |
| case REG_SZ: |
| case REG_EXPAND_SZ: |
| { |
| n = mbstowcs (NULL, a, 0); |
| wchar_t w[n + 1]; |
| mbstowcs (w, a, n + 1); |
| rv = RegSetValueExW (key, value, 0, value_type, |
| (const BYTE *) w, (n + 1) * sizeof (wchar_t)); |
| } |
| break; |
| case REG_MULTI_SZ: |
| for (i = 1, max_n = 1; argv[i]; i++) |
| max_n += mbstowcs (NULL, argv[i], 0) + 1; |
| data = (char *) malloc (max_n * sizeof (wchar_t)); |
| for (i = 1, n = 0; argv[i]; i++) |
| n += mbstowcs ((wchar_t *) data + n, argv[i], max_n - n) + 1; |
| ((wchar_t *)data)[n] = L'\0'; |
| rv = RegSetValueExW (key, value, 0, REG_MULTI_SZ, (const BYTE *) data, |
| (n + 1) * sizeof (wchar_t)); |
| break; |
| case REG_AUTO: |
| rv = ERROR_SUCCESS; |
| break; |
| default: |
| rv = ERROR_INVALID_CATEGORY; |
| break; |
| } |
| |
| if (data) |
| free(data); |
| |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| |
| return 0; |
| } |
| |
| int |
| cmd_unset () |
| { |
| find_key (2, KEY_ALL_ACCESS); |
| DWORD rv = RegDeleteValueW (key, value); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| if (verbose) |
| printf ("value %ls deleted\n", value); |
| return 0; |
| } |
| |
| int |
| cmd_get () |
| { |
| find_key (2, KEY_READ); |
| DWORD vtype, dsize, rv; |
| PBYTE data; |
| wchar_t *vd; |
| |
| rv = RegQueryValueExW (key, value, 0, &vtype, 0, &dsize); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| data = (PBYTE) malloc (dsize + 1); |
| rv = RegQueryValueExW (key, value, 0, &vtype, data, &dsize); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| if (value_type == REG_BINARY) |
| { |
| for (unsigned i = 0; i < dsize; i++) |
| printf ("%02x%c", (unsigned char)data[i], |
| (i < dsize-1 ? ' ' : '\n')); |
| } |
| else if (value_type == REG_NONE) |
| fwrite (data, dsize, 1, stdout); |
| else |
| switch (vtype) |
| { |
| case REG_NONE: |
| case REG_BINARY: |
| fwrite (data, dsize, 1, stdout); |
| break; |
| case REG_DWORD: |
| printf (hex ? "0x%08x\n" : "%u\n", *(unsigned int *) data); |
| break; |
| case REG_DWORD_BIG_ENDIAN: |
| rv = ((data[0] << 24) |
| | (data[1] << 16) |
| | (data[2] << 8) |
| | (data[3])); |
| printf (hex ? "0x%08x\n" : "%u\n", (unsigned int) rv); |
| break; |
| case REG_QWORD: |
| printf (hex ? "0x%016llx\n" : "%llu\n", *(unsigned long long *) data); |
| break; |
| case REG_SZ: |
| case REG_LINK: |
| printf ("%ls\n", (wchar_t *) data); |
| break; |
| case REG_EXPAND_SZ: |
| if (value_type == REG_EXPAND_SZ) // hack |
| { |
| wchar_t *buf; |
| DWORD bufsize; |
| bufsize = ExpandEnvironmentStringsW ((wchar_t *) data, 0, 0); |
| buf = (wchar_t *) malloc (bufsize + 1); |
| ExpandEnvironmentStringsW ((wchar_t *) data, buf, bufsize + 1); |
| free (data); |
| data = (PBYTE) buf; |
| } |
| printf ("%ls\n", (wchar_t *) data); |
| break; |
| case REG_MULTI_SZ: |
| vd = (wchar_t *) data; |
| while (vd && *vd) |
| { |
| printf ("%ls\n", vd); |
| vd = vd + wcslen (vd) + 1; |
| } |
| break; |
| } |
| return 0; |
| } |
| |
| int |
| cmd_load () |
| { |
| if (!argv[1]) |
| { |
| usage (); |
| return 1; |
| } |
| find_key (1, 0); |
| return 0; |
| } |
| |
| int |
| cmd_unload () |
| { |
| if (argv[1]) |
| { |
| usage (); |
| return 1; |
| } |
| find_key (1, 0); |
| return 0; |
| } |
| |
| int |
| cmd_save () |
| { |
| if (!argv[1]) |
| { |
| usage (); |
| return 1; |
| } |
| /* REG_OPTION_BACKUP_RESTORE is necessary to save /HKLM/SECURITY */ |
| find_key (1, KEY_QUERY_VALUE, REG_OPTION_BACKUP_RESTORE); |
| ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0); |
| wchar_t win32_path[len]; |
| cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len); |
| DWORD rv = RegSaveKeyW (key, win32_path, NULL); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| if (verbose) |
| printf ("key saved to %ls\n", win32_path); |
| return 0; |
| } |
| |
| int |
| cmd_restore () |
| { |
| if (!argv[1]) |
| { |
| usage (); |
| return 1; |
| } |
| /* REG_OPTION_BACKUP_RESTORE is necessary to restore /HKLM/SECURITY */ |
| find_key (1, KEY_ALL_ACCESS, REG_OPTION_BACKUP_RESTORE); |
| ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0); |
| wchar_t win32_path[len]; |
| cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len); |
| DWORD rv = RegRestoreKeyW (key, win32_path, restore_flags); |
| if (rv != ERROR_SUCCESS) |
| Fail (rv); |
| if (verbose) |
| printf ("key saved to %ls\n", win32_path); |
| return 0; |
| } |
| |
| static struct |
| { |
| const char *name; |
| int (*func) (); |
| } commands[] = |
| { |
| {"list", cmd_list}, |
| {"add", cmd_add}, |
| {"remove", cmd_remove}, |
| {"check", cmd_check}, |
| {"set", cmd_set}, |
| {"unset", cmd_unset}, |
| {"get", cmd_get}, |
| {"load", cmd_load}, |
| {"unload", cmd_unload}, |
| {"save", cmd_save}, |
| {"restore", cmd_restore}, |
| {0, 0} |
| }; |
| |
| int |
| main (int argc, char **_argv) |
| { |
| int g; |
| |
| setlocale (LC_ALL, ""); |
| |
| prog_name = program_invocation_short_name; |
| |
| while ((g = getopt_long (argc, _argv, opts, longopts, NULL)) != EOF) |
| switch (g) |
| { |
| case 'b': |
| value_type = REG_BINARY; |
| break; |
| case 'd': |
| value_type = REG_DWORD; |
| break; |
| case 'D': |
| value_type = REG_DWORD_BIG_ENDIAN; |
| break; |
| case 'e': |
| value_type = REG_EXPAND_SZ; |
| break; |
| case 'f': |
| restore_flags = REG_FORCE_RESTORE; |
| break; |
| case 'k': |
| listwhat |= LIST_KEYS; |
| break; |
| case 'h': |
| usage (stdout); |
| case 'i': |
| value_type = REG_DWORD; |
| break; |
| case 'l': |
| listwhat |= LIST_VALS; |
| break; |
| case 'm': |
| value_type = REG_MULTI_SZ; |
| break; |
| case 'n': |
| value_type = REG_NONE; |
| break; |
| case 'p': |
| postfix++; |
| break; |
| case 'q': |
| quiet++; |
| break; |
| case 'Q': |
| value_type = REG_QWORD; |
| break; |
| case 's': |
| value_type = REG_SZ; |
| break; |
| case 'v': |
| verbose++; |
| break; |
| case 'V': |
| print_version (); |
| exit (0); |
| case 'w': |
| wow64 = KEY_WOW64_64KEY; |
| break; |
| case 'W': |
| wow64 = KEY_WOW64_32KEY; |
| break; |
| case 'x': |
| hex++; |
| break; |
| case 'K': |
| key_sep = *optarg; |
| break; |
| default : |
| fprintf (stderr, "Try `%s --help' for more information.\n", |
| prog_name); |
| return 1; |
| } |
| |
| if ((_argv[optind] == NULL) || (_argv[optind+1] == NULL)) |
| usage (); |
| |
| argv = _argv + optind; |
| int i; |
| for (i = 0; commands[i].name; i++) |
| if (strcmp (commands[i].name, argv[0]) == 0) |
| { |
| argv++; |
| return commands[i].func (); |
| } |
| usage (); |
| |
| return 0; |
| } |