From 26a2b604e32ae517aed24313ddba4eaccd4e1e23 Mon Sep 17 00:00:00 2001
From: Hugh McMaster <hugh.mcmaster@outlook.com>
Date: Sun, 27 Mar 2016 22:19:17 +1100
Subject: reg: Add support for querying the registry with the /v and /ve
 switches (v2)

Recursion is supported.

Signed-off-by: Hugh McMaster <hugh.mcmaster@outlook.com>
---
 programs/reg/reg.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 80 insertions(+), 8 deletions(-)

diff --git a/programs/reg/reg.c b/programs/reg/reg.c
index ab04ee9..8dd7e50 100644
--- a/programs/reg/reg.c
+++ b/programs/reg/reg.c
@@ -754,6 +754,83 @@ static int query_all(HKEY key, WCHAR *path, BOOL recurse)
     return 0;
 }
 
+static int num_values_found = 0;
+
+static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse)
+{
+    LONG rc;
+    DWORD num_subkeys, max_subkey_len, subkey_len;
+    DWORD max_data_bytes, data_size;
+    DWORD type, path_len;
+    BYTE *data;
+    WCHAR fmt[] = {'%','1','\n',0};
+    WCHAR newlineW[] = {'\n',0};
+    WCHAR *subkey_name, *subkey_path;
+    int i;
+    HKEY subkey;
+
+    rc = RegQueryInfoKeyW(key, NULL, NULL, NULL, &num_subkeys, &max_subkey_len,
+                          NULL, NULL, NULL, &max_data_bytes, NULL, NULL);
+    if (rc)
+    {
+        ERR("RegQueryInfoKey failed: %d\n", rc);
+        return 1;
+    }
+
+    data = HeapAlloc(GetProcessHeap(), 0, max_data_bytes);
+    if (!data)
+    {
+        ERR("Failed to allocate memory for data\n");
+        return 1;
+    }
+
+    data_size = max_data_bytes;
+    rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size);
+    if (rc == ERROR_SUCCESS)
+    {
+        output_string(fmt, path);
+        output_value(value_name, type, data, data_size);
+        output_string(newlineW);
+        num_values_found++;
+    }
+
+    HeapFree(GetProcessHeap(), 0, data);
+
+    if (!recurse)
+    {
+        if (rc == ERROR_FILE_NOT_FOUND)
+            return 1;
+        return 0;
+    }
+
+    max_subkey_len++;
+    subkey_name = HeapAlloc(GetProcessHeap(), 0, max_subkey_len * sizeof(WCHAR));
+    if (!subkey_name)
+    {
+        ERR("Failed to allocate memory for subkey_name\n");
+        return 1;
+    }
+
+    path_len = strlenW(path);
+
+    for (i = 0; i < num_subkeys; i++)
+    {
+        subkey_len = max_subkey_len;
+        rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
+        if (rc == ERROR_SUCCESS)
+        {
+            subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
+            RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey);
+            query_value(subkey, value_name, subkey_path, recurse);
+            RegCloseKey(subkey);
+            HeapFree(GetProcessHeap(), 0, subkey_path);
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, subkey_name);
+    return 0;
+}
+
 static WCHAR *get_long_path(HKEY root, WCHAR *path)
 {
     DWORD i, len;
@@ -785,8 +862,6 @@ static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL
 {
     WCHAR *p, *path;
     HKEY root, key;
-    static const WCHAR stubW[] = {'S','T','U','B',' ','Q','U','E','R','Y',' ',
-        '-',' ','%','1',' ','%','2',' ','%','3','!','d','!',' ','%','4','!','d','!','\n',0};
     int ret;
 
     if (!sane_path(key_name))
@@ -817,12 +892,9 @@ static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL
     path = get_long_path(root, p);
 
     if (value_name || value_empty)
-    {
-        output_string(stubW, key_name, value_name, value_empty, recurse);
-        return 1;
-    }
-
-    ret = query_all(key, path, recurse);
+        ret = query_value(key, value_name, path, recurse);
+    else
+        ret = query_all(key, path, recurse);
 
     HeapFree(GetProcessHeap(), 0, path);
     RegCloseKey(key);
-- 
2.7.1

