Revert r66580 and r66579.
[reactos.git] / reactos / dll / shellext / ntobjshex / ntobjutil.cpp
1 /*
2 * Copyright 2004, 2005 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <precomp.h>
20
21 #include "ntobjutil.h"
22 #include <strsafe.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex);
25
26 typedef NTSTATUS(__stdcall* pfnNtGenericOpen)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
27 typedef NTSTATUS(__stdcall* pfnNtOpenFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG);
28
29 const LPCWSTR ObjectTypeNames [] = {
30 L"Directory", L"SymbolicLink",
31 L"Mutant", L"Section", L"Event", L"Semaphore",
32 L"Timer", L"Key", L"EventPair", L"IoCompletion",
33 L"Device", L"File", L"Controller", L"Profile",
34 L"Type", L"Desktop", L"WindowStatiom", L"Driver",
35 L"Token", L"Process", L"Thread", L"Adapter", L"Port",
36 0
37 };
38
39 const LPCWSTR RegistryTypeNames[] = {
40 L"REG_NONE",
41 L"REG_SZ",
42 L"REG_EXPAND_SZ",
43 L"REG_BINARY",
44 L"REG_DWORD",
45 L"REG_DWORD_BIG_ENDIAN",
46 L"REG_LINK",
47 L"REG_MULTI_SZ",
48 L"REG_RESOURCE_LIST",
49 L"REG_FULL_RESOURCE_DESCRIPTOR",
50 L"REG_RESOURCE_REQUIREMENTS_LIST ",
51 L"REG_QWORD"
52 };
53
54 static DWORD NtOpenObject(OBJECT_TYPE type, PHANDLE phandle, DWORD access, LPCWSTR path)
55 {
56 UNICODE_STRING ustr;
57
58 RtlInitUnicodeString(&ustr, path);
59
60 OBJECT_ATTRIBUTES open_struct = { sizeof(OBJECT_ATTRIBUTES), 0x00, &ustr, 0x40 };
61
62 if (type != FILE_OBJECT)
63 access |= STANDARD_RIGHTS_READ;
64
65 IO_STATUS_BLOCK ioStatusBlock;
66
67 switch (type)
68 {
69 case DIRECTORY_OBJECT: return NtOpenDirectoryObject(phandle, access, &open_struct);
70 case SYMBOLICLINK_OBJECT: return NtOpenSymbolicLinkObject(phandle, access, &open_struct);
71 case MUTANT_OBJECT: return NtOpenMutant(phandle, access, &open_struct);
72 case SECTION_OBJECT: return NtOpenSection(phandle, access, &open_struct);
73 case EVENT_OBJECT: return NtOpenEvent(phandle, access, &open_struct);
74 case SEMAPHORE_OBJECT: return NtOpenSemaphore(phandle, access, &open_struct);
75 case TIMER_OBJECT: return NtOpenTimer(phandle, access, &open_struct);
76 case KEY_OBJECT: return NtOpenKey(phandle, access, &open_struct);
77 case EVENTPAIR_OBJECT: return NtOpenEventPair(phandle, access, &open_struct);
78 case IOCOMPLETITION_OBJECT: return NtOpenIoCompletion(phandle, access, &open_struct);
79 case FILE_OBJECT: return NtOpenFile(phandle, access, &open_struct, &ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0);
80 default:
81 return ERROR_INVALID_FUNCTION;
82 }
83 }
84
85 OBJECT_TYPE MapTypeNameToType(LPCWSTR TypeName, DWORD cbTypeName)
86 {
87 if (!TypeName)
88 return UNKNOWN_OBJECT_TYPE;
89
90 for (UINT i = 0; i < _countof(ObjectTypeNames); i++)
91 {
92 LPCWSTR typeName = ObjectTypeNames[i];
93 if (!StrCmpNW(typeName, TypeName, cbTypeName / sizeof(WCHAR)))
94 {
95 return (OBJECT_TYPE) i;
96 }
97 }
98
99 return UNKNOWN_OBJECT_TYPE;
100 }
101
102 HRESULT EnumerateNtDirectory(HDPA hdpa, PCWSTR path, UINT * hdpaCount)
103 {
104 WCHAR buffer[MAX_PATH];
105 PWSTR pend;
106
107 *hdpaCount = 0;
108
109 StringCbCopyExW(buffer, sizeof(buffer), path, &pend, NULL, 0);
110
111 ULONG enumContext = 0;
112 HANDLE directory = NULL;
113
114 DWORD err = NtOpenObject(DIRECTORY_OBJECT, &directory, FILE_LIST_DIRECTORY, buffer);
115 if (!NT_SUCCESS(err))
116 {
117 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer, err);
118 return HRESULT_FROM_NT(err);
119 }
120
121 if (pend[-1] != '\\')
122 *pend++ = '\\';
123
124
125 BYTE dirbuffer[2048];
126
127 BOOL first = TRUE;
128 while (NtQueryDirectoryObject(directory, dirbuffer, 2048, TRUE, first, &enumContext, NULL) == STATUS_SUCCESS)
129 {
130 first = FALSE;
131 POBJECT_DIRECTORY_INFORMATION info = (POBJECT_DIRECTORY_INFORMATION) dirbuffer;
132 //for (; info->Name.Buffer != NULL; info++)
133 {
134 if (info->Name.Buffer)
135 {
136 StringCbCopyNW(pend, sizeof(buffer), info->Name.Buffer, info->Name.Length);
137 }
138
139 OBJECT_TYPE otype = MapTypeNameToType(info->TypeName.Buffer, info->TypeName.Length);
140 OBJECT_BASIC_INFORMATION object = { 0 };
141
142 WCHAR wbLink[_MAX_PATH] = { 0 };
143 UNICODE_STRING link;
144 RtlInitEmptyUnicodeString(&link, wbLink, sizeof(wbLink));
145
146 DWORD entryBufferLength = FIELD_OFFSET(NtPidlEntry,entryName) + sizeof(WCHAR);
147 if (info->Name.Buffer)
148 entryBufferLength += info->Name.Length;
149
150 if (otype < 0)
151 {
152 entryBufferLength += FIELD_OFFSET(NtPidlTypeData,typeName) + sizeof(WCHAR);
153
154 if (info->TypeName.Buffer)
155 {
156 entryBufferLength += info->TypeName.Length;
157 }
158 }
159
160 if (otype == SYMBOLICLINK_OBJECT)
161 {
162 entryBufferLength += FIELD_OFFSET(NtPidlSymlinkData,targetName) + sizeof(WCHAR);
163 }
164
165 DWORD access = STANDARD_RIGHTS_READ;
166 if ((otype == DIRECTORY_OBJECT) ||
167 (otype == SYMBOLICLINK_OBJECT))
168 access |= FILE_LIST_DIRECTORY;
169
170 HANDLE handle;
171 if (!NtOpenObject(otype, &handle, access, buffer))
172 {
173 DWORD read;
174
175 if (!NT_SUCCESS(NtQueryObject(handle, ObjectBasicInformation, &object, sizeof(OBJECT_BASIC_INFORMATION), &read)))
176 {
177 ZeroMemory(&object, sizeof(OBJECT_BASIC_INFORMATION));
178 }
179
180 if (otype == SYMBOLICLINK_OBJECT)
181 {
182 if (NtQuerySymbolicLinkObject(handle, &link, NULL) == STATUS_SUCCESS)
183 {
184 entryBufferLength += link.Length;
185 }
186 else
187 {
188 link.Length = 0;
189 }
190 }
191
192 NtClose(handle);
193 }
194
195 NtPidlEntry* entry = (NtPidlEntry*) CoTaskMemAlloc(entryBufferLength);
196 if (!entry)
197 return E_OUTOFMEMORY;
198
199 memset(entry, 0, entryBufferLength);
200
201 entry->cb = FIELD_OFFSET(NtPidlEntry,entryName);
202 entry->magic = NT_OBJECT_PIDL_MAGIC;
203 entry->objectType = otype;
204 entry->objectInformation = object;
205 memset(entry->objectInformation.Reserved, 0, sizeof(entry->objectInformation.Reserved));
206
207 if (info->Name.Buffer)
208 {
209 entry->entryNameLength = info->Name.Length;
210 StringCbCopyNW(entry->entryName, entryBufferLength, info->Name.Buffer, info->Name.Length);
211 entry->cb += entry->entryNameLength + sizeof(WCHAR);
212 }
213 else
214 {
215 entry->entryNameLength = 0;
216 entry->entryName[0] = 0;
217 entry->cb += sizeof(WCHAR);
218 }
219
220 if (otype < 0)
221 {
222 NtPidlTypeData * typedata = (NtPidlTypeData*) ((PBYTE) entry + entry->cb);
223 DWORD remainingSpace = entryBufferLength - ((PBYTE) (typedata->typeName) - (PBYTE) entry);
224
225 if (info->TypeName.Buffer)
226 {
227 typedata->typeNameLength = info->TypeName.Length;
228 StringCbCopyNW(typedata->typeName, remainingSpace, info->TypeName.Buffer, info->TypeName.Length);
229
230 entry->cb += typedata->typeNameLength + sizeof(WCHAR);
231 }
232 else
233 {
234 typedata->typeNameLength = 0;
235 typedata->typeName[0] = 0;
236 entry->cb += typedata->typeNameLength + sizeof(WCHAR);
237 }
238 }
239
240 if (otype == SYMBOLICLINK_OBJECT)
241 {
242 NtPidlSymlinkData * symlink = (NtPidlSymlinkData*) ((PBYTE) entry + entry->cb);
243 DWORD remainingSpace = entryBufferLength - ((PBYTE) (symlink->targetName) - (PBYTE) entry);
244
245 symlink->targetNameLength = link.Length;
246 StringCbCopyNW(symlink->targetName, remainingSpace, link.Buffer, link.Length);
247
248 entry->cb += symlink->targetNameLength + sizeof(WCHAR);
249 }
250
251 DPA_AppendPtr(hdpa, entry);
252 (*hdpaCount)++;
253 }
254 }
255
256 NtClose(directory);
257
258 return S_OK;
259 }
260
261 HRESULT EnumerateRegistryKey(HDPA hdpa, PCWSTR path, HKEY root, UINT * hdpaCount)
262 {
263 *hdpaCount = 0;
264
265 HKEY hkey;
266
267 DWORD res;
268 if (root)
269 {
270 res = RegOpenKeyExW(root, *path == '\\' ? path + 1 : path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkey);
271 }
272 else
273 {
274 res = NtOpenObject(KEY_OBJECT, (PHANDLE)&hkey, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, path);
275 }
276 if (!NT_SUCCESS(res))
277 {
278 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res);
279 return HRESULT_FROM_NT(res);
280 }
281
282 for (int idx = 0;; ++idx)
283 {
284 WCHAR name[MAX_PATH];
285 DWORD cchName = _countof(name);
286
287 WCHAR className[MAX_PATH];
288 DWORD cchClass = _countof(className);
289
290 if (RegEnumKeyExW(hkey, idx, name, &cchName, 0, className, &cchClass, NULL))
291 break;
292
293 name[cchName] = 0;
294 className[cchClass] = 0;
295
296 REG_ENTRY_TYPE otype = REG_ENTRY_KEY;
297
298 DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry,entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
299
300 if (cchClass > 0)
301 {
302 entryBufferLength += sizeof(WCHAR) + cchClass * sizeof(WCHAR);
303 }
304
305 RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
306 if (!entry)
307 return E_OUTOFMEMORY;
308
309 memset(entry, 0, entryBufferLength);
310
311 entry->cb = FIELD_OFFSET(NtPidlEntry,entryName);
312 entry->magic = REGISTRY_PIDL_MAGIC;
313 entry->entryType = otype;
314
315 if (cchName > 0)
316 {
317 entry->entryNameLength = cchName * sizeof(WCHAR);
318 StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
319 entry->cb += entry->entryNameLength + sizeof(WCHAR);
320 }
321 else
322 {
323 entry->entryNameLength = 0;
324 entry->entryName[0] = 0;
325 entry->cb += sizeof(WCHAR);
326 }
327
328 if (cchClass)
329 {
330 PWSTR contentData = (PWSTR) ((PBYTE) entry + entry->cb);
331 DWORD remainingSpace = entryBufferLength - entry->cb;
332
333 entry->contentsLength = cchClass * sizeof(WCHAR);
334 StringCbCopyNW(contentData, remainingSpace, className, entry->contentsLength);
335
336 entry->cb += entry->contentsLength + sizeof(WCHAR);
337 }
338
339 DPA_AppendPtr(hdpa, entry);
340 (*hdpaCount)++;
341
342 }
343
344 for (int idx = 0;; ++idx)
345 {
346 WCHAR name[MAX_PATH];
347 DWORD cchName = _countof(name);
348 DWORD type;
349 DWORD dataSize;
350
351 if (RegEnumValueW(hkey, idx, name, &cchName, 0, &type, NULL, &dataSize))
352 break;
353
354 REG_ENTRY_TYPE otype = REG_ENTRY_VALUE;
355
356 DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry,entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
357
358 BOOL copyData = dataSize < 32;
359 if (copyData)
360 {
361 entryBufferLength += dataSize + sizeof(WCHAR);
362
363 otype = REG_ENTRY_VALUE_WITH_CONTENT;
364 }
365
366 RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
367 if (!entry)
368 return E_OUTOFMEMORY;
369
370 memset(entry, 0, entryBufferLength);
371
372 entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
373 entry->magic = REGISTRY_PIDL_MAGIC;
374 entry->entryType = otype;
375
376 if (cchName > 0)
377 {
378 entry->entryNameLength = cchName * sizeof(WCHAR);
379 StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
380 entry->cb += entry->entryNameLength + sizeof(WCHAR);
381 }
382 else
383 {
384 entry->entryNameLength = 0;
385 entry->entryName[0] = 0;
386 entry->cb += sizeof(WCHAR);
387 }
388
389 if (copyData)
390 {
391 PBYTE contentData = (PBYTE) ((PBYTE) entry + entry->cb);
392
393 entry->contentsLength = dataSize;
394
395 // In case it's an unterminated string, RegGetValue will add the NULL termination
396 dataSize += sizeof(WCHAR);
397
398 if (!RegQueryValueExW(hkey, name, NULL, NULL, contentData, &dataSize))
399 {
400 entry->cb += entry->contentsLength + sizeof(WCHAR);
401 }
402 else
403 {
404 entry->contentsLength = 0;
405 entry->cb += sizeof(WCHAR);
406 }
407
408 }
409
410 DPA_AppendPtr(hdpa, entry);
411 (*hdpaCount)++;
412 }
413
414 RegCloseKey(hkey);
415
416 return S_OK;
417 }