winprefs v0.3.2
A registry exporter for programmers.
Loading...
Searching...
No Matches
io.c
1#include "io.h"
2#include "constants.h"
3#include "io_default_writer.h"
4#include "reg_code.h"
5#include "reg_command.h"
6
7bool write_output(wchar_t *out, bool use_crlf, writer_t *writer) {
8 bool ret = true;
9 char *mb_out = nullptr;
10 DWORD written = 0;
11 size_t req_size =
12 (size_t)WideCharToMultiByte(CP_UTF8, 0, out, -1, nullptr, 0, nullptr, nullptr);
13 if (req_size == 0) {
14 goto cleanup;
15 }
16 size_t total_size = req_size + (use_crlf ? 1 : 0);
17 mb_out = malloc(total_size);
18 if (!mb_out) { // LCOV_EXCL_START
19 goto fail;
20 } // LCOV_EXCL_STOP
21 memset(mb_out, 0, total_size);
22 if (!WideCharToMultiByte(CP_UTF8, 0, out, -1, mb_out, (int)total_size, nullptr, nullptr)) {
23 free(mb_out);
24 debug_print(L"Skipping possibly malformed wide character data.\n");
25 return true;
26 }
27 if (use_crlf) {
28 mb_out[total_size - 2] = '\r';
29 }
30 mb_out[total_size - 1] = '\n';
31 ret = writer->write_output(writer, mb_out, total_size, &written);
32 goto cleanup;
33fail: // LCOV_EXCL_START
34 ret = false;
35 // LCOV_EXCL_STOP
36cleanup:
37 free(mb_out);
38 return ret && written > 0;
39}
40
41bool do_writes(HKEY hk,
42 long unsigned n_values,
43 const wchar_t *full_path,
44 enum OUTPUT_FORMAT format,
45 writer_t *writer) {
46 bool ret = true;
47 wchar_t *value = nullptr;
48 if (n_values == 0) {
49 goto cleanup;
50 }
51 if (!writer || !full_path) {
52 errno = EINVAL;
53 goto fail;
54 }
55 size_t data_len;
56 DWORD i;
57 DWORD reg_type;
58 size_t value_len;
59 value = calloc(MAX_VALUE_NAME, WL);
60 if (!value) { // LCOV_EXCL_START
61 return false;
62 } // LCOV_EXCL_STOP
63 if (format == OUTPUT_FORMAT_UNKNOWN) {
64 goto fail;
65 }
66 LSTATUS enum_value_ret = ERROR_SUCCESS;
67 char data[8192];
68 for (i = 0; i < n_values; i++) {
69 data_len = sizeof(data);
70 wmemset(value, L'\0', MAX_VALUE_NAME);
71 memset(data, 0, 8192);
72 value_len = MAX_VALUE_NAME * WL;
73 reg_type = REG_NONE;
74 enum_value_ret = RegEnumValue(
75 hk, i, value, (LPDWORD)&value_len, 0, &reg_type, (LPBYTE)data, (LPDWORD)&data_len);
76 if (enum_value_ret == ERROR_MORE_DATA) { // LCOV_EXCL_START
77 continue;
78 }
79 if (enum_value_ret == ERROR_NO_MORE_ITEMS) {
80 break;
81 }
82 // LCOV_EXCL_STOP
83 bool write_ret = false;
84 switch (format) {
85 case OUTPUT_FORMAT_REG:
86 write_ret = do_write_reg_command(writer, full_path, value, data, data_len, reg_type);
87 break;
88 case OUTPUT_FORMAT_C:
89 write_ret = do_write_c_reg_code(writer, full_path, value, data, data_len, reg_type);
90 break;
91 case OUTPUT_FORMAT_C_SHARP:
92 write_ret =
93 do_write_c_sharp_reg_code(writer, full_path, value, data, data_len, reg_type);
94 break;
95 case OUTPUT_FORMAT_POWERSHELL:
96 write_ret =
97 do_write_powershell_reg_code(writer, full_path, value, data, data_len, reg_type);
98 break;
99 default: // LCOV_EXCL_START
100 goto fail;
101 // LCOV_EXCL_STOP
102 }
103 if (!write_ret) {
104 goto fail;
105 }
106 }
107 goto cleanup;
108fail:
109 ret = false;
110cleanup:
111 free(value);
112 return ret;
113}
114
115bool write_key_filtered_recursive(HKEY hk,
116 const wchar_t *stem,
117 int max_depth,
118 int depth,
119 const wchar_t *prior_stem,
120 enum OUTPUT_FORMAT format,
121 writer_t *writer) {
122 bool ret = true;
123 wchar_t *ach_key, *full_path;
124 ach_key = full_path = nullptr;
125 if (depth >= max_depth) {
126 debug_print(L"%ls: Skipping %ls due to depth limit of %d.\n", prior_stem, stem, max_depth);
127 errno = EDOM;
128 goto cleanup;
129 }
130 HKEY hk_out;
131 size_t full_path_len = WL * MAX_KEY_LENGTH;
132 full_path = calloc(MAX_KEY_LENGTH, WL);
133 if (!full_path) { // LCOV_EXCL_START
134 goto fail;
135 } // LCOV_EXCL_STOP
136 wmemset(full_path, L'\0', MAX_KEY_LENGTH);
137 size_t prior_stem_len = wcslen(prior_stem) * WL;
138 size_t stem_len = stem ? wcslen(stem) : 0;
139 if ((prior_stem_len + (stem_len * WL) + 2) > (full_path_len - 2)) {
140 debug_print(L"%ls: Skipping %ls because of length limitation.\n", prior_stem, stem);
141 errno = E2BIG;
142 goto cleanup;
143 }
144 memcpy(full_path, prior_stem, prior_stem_len);
145 if (stem) {
146 wcsncat(full_path, L"\\", 1);
147 wcsncat(full_path, stem, stem_len);
148 }
149 if (wcsstr(full_path, L"Classes\\Extensions\\ContractId\\Windows.BackgroundTasks\\PackageId") ||
150 wcsstr(full_path, L"CloudStore\\Store\\Cache\\") ||
151 wcsstr(full_path,
152 L"CurrentVersion\\Authentication\\LogonUI\\Notifications\\BackgroundCapability") ||
153 wcsstr(full_path, L"CurrentVersion\\CloudStore\\Store\\DefaultAccount\\Current\\") ||
154 wcsstr(full_path, L"Explorer\\ComDlg32\\CIDSizeMRU") ||
155 wcsstr(full_path, L"Explorer\\ComDlg32\\FirstFolder") ||
156 wcsstr(full_path, L"Explorer\\ComDlg32\\LastVisitedPidlMRU") ||
157 wcsstr(full_path, L"Explorer\\ComDlg32\\OpenSavePidlMRU") ||
158 wcsstr(full_path, L"IrisService\\Cache") ||
159 wcsstr(full_path, L"Microsoft\\Windows\\Shell\\Bags") ||
160 wcsstr(full_path, L"Windows\\Shell\\BagMRU") ||
161 wcsstr(full_path, L"Windows\\Shell\\MuiCache")) {
162 debug_print(L"%ls: Skipping %ls due to filter.\n", prior_stem, stem);
163 errno = EKEYREJECTED;
164 goto cleanup;
165 }
166 if (RegOpenKeyEx(hk, stem, 0, KEY_READ, &hk_out) == ERROR_SUCCESS) {
167 DWORD n_sub_keys = 0;
168 DWORD n_values = 0;
169 LSTATUS ret_code = RegQueryInfoKey(hk_out,
170 nullptr,
171 nullptr,
172 nullptr,
173 &n_sub_keys,
174 nullptr,
175 nullptr,
176 &n_values,
177 nullptr,
178 nullptr,
179 nullptr,
180 nullptr);
181 if (ret_code != ERROR_SUCCESS) {
182 debug_print(L"RegQueryInfoKey failed (stem = %ls).\n", stem);
183 goto fail;
184 }
185 if (n_sub_keys) {
186 size_t ach_key_len = 0;
187 ach_key = calloc(MAX_KEY_LENGTH, WL);
188 if (!ach_key) { // LCOV_EXCL_START
189 goto fail;
190 } // LCOV_EXCL_STOP
191 unsigned i;
192 for (i = 0; i < n_sub_keys; i++) {
193 ach_key_len = MAX_KEY_LENGTH;
194 wmemset(ach_key, L'\0', MAX_KEY_LENGTH);
195 ret_code = RegEnumKeyEx(
196 hk_out, i, ach_key, (LPDWORD)&ach_key_len, nullptr, nullptr, nullptr, nullptr);
197 if (ret_code == ERROR_SUCCESS) {
198 if (!write_key_filtered_recursive(
199 hk_out, ach_key, max_depth, depth + 1, full_path, format, writer)) {
200 goto fail;
201 }
202 } else {
203 debug_print(L"%ls: Skipping %ls because RegEnumKeyEx() failed.\n",
204 prior_stem,
205 full_path);
206 }
207 }
208 } else {
209 debug_print(L"%ls: No subkeys in %ls.\n", prior_stem, stem);
210 }
211 if (n_values) {
212 if (!do_writes(hk_out, n_values, full_path, format, writer)) { // LCOV_EXCL_START
213 goto fail;
214 } // LCOV_EXCL_STOP
215 } else {
216 debug_print(L"%ls: No values in %ls.\n", prior_stem, stem);
217 }
218 RegCloseKey(hk_out);
219 } else {
220 debug_print(L"%ls: Skipping %ls. Does the location exist?\n", prior_stem, stem);
221 }
222 goto cleanup;
223fail:
224 ret = false;
225cleanup:
226 free(ach_key);
227 free(full_path);
228 return ret;
229}