989 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			989 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
/* 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>
 | 
						|
#include <windows.h>
 | 
						|
#include <sys/cygwin.h>
 | 
						|
#include <cygwin/version.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 __attribute__ ((__noreturn__))
 | 
						|
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\n"
 | 
						|
      " -W, --wow32    access 32 bit registry view\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"
 | 
						|
      "You can use forward slash ('/') as a separator instead of backslash, in\n"
 | 
						|
      "that case backslash is treated as an escape character.\n"
 | 
						|
      "You can also supply the registry path prefix /proc/registry{,32,64}/ to\n"
 | 
						|
      "use path completion.\n");
 | 
						|
      fprintf (where, ""
 | 
						|
      "Example:\n"
 | 
						|
      "%s list '/HKLM/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;
 | 
						|
    }
 | 
						|
  else if (strncmp ("\\proc\\registry", n, strlen ("\\proc\\registry")) == 0)
 | 
						|
    {
 | 
						|
      /* skip /proc/registry{,32,64}/ prefix */
 | 
						|
      n += strlen ("\\proc\\registry");
 | 
						|
      if (strncmp ("64", n, strlen ("64")) == 0)
 | 
						|
        n += strlen ("64");
 | 
						|
      else if (strncmp ("32", n, strlen ("32")) == 0)
 | 
						|
        n += strlen ("32");
 | 
						|
    }
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
cmd_remove ()
 | 
						|
{
 | 
						|
  DWORD rv;
 | 
						|
 | 
						|
  find_key (2, KEY_ALL_ACCESS);
 | 
						|
  if (wow64)
 | 
						|
    rv = RegDeleteKeyExW (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 ();
 | 
						|
  find_key (1, 0);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
cmd_unload ()
 | 
						|
{
 | 
						|
  if (argv[1])
 | 
						|
    usage ();
 | 
						|
  find_key (1, 0);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
cmd_save ()
 | 
						|
{
 | 
						|
  if (!argv[1])
 | 
						|
    usage ();
 | 
						|
  /* 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 ();
 | 
						|
  /* 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 ();
 | 
						|
}
 |