[BTRFS]
[reactos.git] / reactos / drivers / filesystems / btrfs / registry.c
1 /* Copyright (c) Mark Harmstone 2016
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
9 *
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "btrfs_drv.h"
19
20 extern UNICODE_STRING log_device, log_file, registry_path;
21
22 static WCHAR option_mounted[] = L"Mounted";
23
24 #define hex_digit(c) ((c) >= 0 && (c) <= 9) ? ((c) + '0') : ((c) - 10 + 'a')
25
26 NTSTATUS registry_load_volume_options(device_extension* Vcb) {
27 BTRFS_UUID* uuid = &Vcb->superblock.uuid;
28 mount_options* options = &Vcb->options;
29 UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus,
30 maxinlineus, subvolidus;
31 OBJECT_ATTRIBUTES oa;
32 NTSTATUS Status;
33 ULONG i, j, kvfilen, index, retlen;
34 KEY_VALUE_FULL_INFORMATION* kvfi = NULL;
35 HANDLE h;
36
37 options->compress = mount_compress;
38 options->compress_force = mount_compress_force;
39 options->compress_type = mount_compress_type > BTRFS_COMPRESSION_LZO ? 0 : mount_compress_type;
40 options->readonly = FALSE;
41 options->zlib_level = mount_zlib_level;
42 options->flush_interval = mount_flush_interval;
43 options->max_inline = min(mount_max_inline, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
44 options->subvol_id = 0;
45
46 path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
47 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
48
49 if (!path.Buffer) {
50 ERR("out of memory\n");
51 return STATUS_INSUFFICIENT_RESOURCES;
52 }
53
54 RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
55 i = registry_path.Length / sizeof(WCHAR);
56
57 path.Buffer[i] = '\\';
58 i++;
59
60 for (j = 0; j < 16; j++) {
61 path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
62 path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
63
64 i += 2;
65
66 if (j == 3 || j == 5 || j == 7 || j == 9) {
67 path.Buffer[i] = '-';
68 i++;
69 }
70 }
71
72 kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR));
73 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
74 if (!kvfi) {
75 ERR("out of memory\n");
76 Status = STATUS_INSUFFICIENT_RESOURCES;
77 goto end;
78 }
79
80 InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
81
82 Status = ZwOpenKey(&h, KEY_QUERY_VALUE, &oa);
83 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
84 Status = STATUS_SUCCESS;
85 goto end;
86 } else if (!NT_SUCCESS(Status)) {
87 ERR("ZwOpenKey returned %08x\n", Status);
88 goto end;
89 }
90
91 index = 0;
92
93 RtlInitUnicodeString(&ignoreus, L"Ignore");
94 RtlInitUnicodeString(&compressus, L"Compress");
95 RtlInitUnicodeString(&compressforceus, L"CompressForce");
96 RtlInitUnicodeString(&compresstypeus, L"CompressType");
97 RtlInitUnicodeString(&readonlyus, L"Readonly");
98 RtlInitUnicodeString(&zliblevelus, L"ZlibLevel");
99 RtlInitUnicodeString(&flushintervalus, L"FlushInterval");
100 RtlInitUnicodeString(&maxinlineus, L"MaxInline");
101 RtlInitUnicodeString(&subvolidus, L"SubvolId");
102
103 do {
104 Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
105
106 index++;
107
108 if (NT_SUCCESS(Status)) {
109 UNICODE_STRING us;
110
111 us.Length = us.MaximumLength = kvfi->NameLength;
112 us.Buffer = kvfi->Name;
113
114 if (FsRtlAreNamesEqual(&ignoreus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
115 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
116
117 options->ignore = *val != 0 ? TRUE : FALSE;
118 } else if (FsRtlAreNamesEqual(&compressus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
119 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
120
121 options->compress = *val != 0 ? TRUE : FALSE;
122 } else if (FsRtlAreNamesEqual(&compressforceus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
123 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
124
125 options->compress_force = *val != 0 ? TRUE : FALSE;
126 } else if (FsRtlAreNamesEqual(&compresstypeus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
127 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
128
129 options->compress_type = *val > BTRFS_COMPRESSION_LZO ? 0 : *val;
130 } else if (FsRtlAreNamesEqual(&readonlyus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
131 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
132
133 options->readonly = *val != 0 ? TRUE : FALSE;
134 } else if (FsRtlAreNamesEqual(&zliblevelus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
135 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
136
137 options->zlib_level = *val;
138 } else if (FsRtlAreNamesEqual(&flushintervalus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
139 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
140
141 options->flush_interval = *val;
142 } else if (FsRtlAreNamesEqual(&maxinlineus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
143 DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
144
145 options->max_inline = min(*val, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
146 } else if (FsRtlAreNamesEqual(&subvolidus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_QWORD) {
147 UINT64* val = (UINT64*)((UINT8*)kvfi + kvfi->DataOffset);
148
149 options->subvol_id = *val;
150 }
151 } else if (Status != STATUS_NO_MORE_ENTRIES) {
152 ERR("ZwEnumerateValueKey returned %08x\n", Status);
153 goto end2;
154 }
155 } while (NT_SUCCESS(Status));
156
157 if (!options->compress && options->compress_force)
158 options->compress = TRUE;
159
160 if (options->zlib_level > 9)
161 options->zlib_level = 9;
162
163 if (options->flush_interval == 0)
164 options->flush_interval = mount_flush_interval;
165
166 Status = STATUS_SUCCESS;
167
168 end2:
169 ZwClose(h);
170
171 end:
172 ExFreePool(path.Buffer);
173
174 if (kvfi)
175 ExFreePool(kvfi);
176
177 return Status;
178 }
179
180 NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid) {
181 UNICODE_STRING path, mountedus;
182 ULONG i, j;
183 NTSTATUS Status;
184 OBJECT_ATTRIBUTES oa;
185 HANDLE h;
186 DWORD data;
187
188 path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
189 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
190
191 if (!path.Buffer) {
192 ERR("out of memory\n");
193 return STATUS_INSUFFICIENT_RESOURCES;
194 }
195
196 RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
197 i = registry_path.Length / sizeof(WCHAR);
198
199 path.Buffer[i] = '\\';
200 i++;
201
202 for (j = 0; j < 16; j++) {
203 path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
204 path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
205
206 i += 2;
207
208 if (j == 3 || j == 5 || j == 7 || j == 9) {
209 path.Buffer[i] = '-';
210 i++;
211 }
212 }
213
214 InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
215
216 Status = ZwCreateKey(&h, KEY_SET_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
217 if (!NT_SUCCESS(Status)) {
218 ERR("ZwCreateKey returned %08x\n", Status);
219 goto end;
220 }
221
222 mountedus.Buffer = option_mounted;
223 mountedus.Length = mountedus.MaximumLength = wcslen(option_mounted) * sizeof(WCHAR);
224
225 data = 1;
226
227 Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
228 if (!NT_SUCCESS(Status)) {
229 ERR("ZwSetValueKey returned %08x\n", Status);
230 goto end2;
231 }
232
233 Status = STATUS_SUCCESS;
234
235 end2:
236 ZwClose(h);
237
238 end:
239 ExFreePool(path.Buffer);
240
241 return Status;
242 }
243
244 static NTSTATUS registry_mark_volume_unmounted_path(PUNICODE_STRING path) {
245 HANDLE h;
246 OBJECT_ATTRIBUTES oa;
247 NTSTATUS Status;
248 ULONG index, kvbilen = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen;
249 KEY_VALUE_BASIC_INFORMATION* kvbi;
250 BOOL has_options = FALSE;
251 UNICODE_STRING mountedus;
252
253 // If a volume key has any options in it, we set Mounted to 0 and return. Otherwise,
254 // we delete the whole thing.
255
256 kvbi = ExAllocatePoolWithTag(PagedPool, kvbilen, ALLOC_TAG);
257 if (!kvbi) {
258 ERR("out of memory\n");
259 return STATUS_INSUFFICIENT_RESOURCES;
260 }
261
262 InitializeObjectAttributes(&oa, path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
263
264 Status = ZwOpenKey(&h, KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE, &oa);
265 if (!NT_SUCCESS(Status)) {
266 ERR("ZwOpenKey returned %08x\n", Status);
267 goto end;
268 }
269
270 index = 0;
271
272 mountedus.Buffer = option_mounted;
273 mountedus.Length = mountedus.MaximumLength = wcslen(option_mounted) * sizeof(WCHAR);
274
275 do {
276 Status = ZwEnumerateValueKey(h, index, KeyValueBasicInformation, kvbi, kvbilen, &retlen);
277
278 index++;
279
280 if (NT_SUCCESS(Status)) {
281 UNICODE_STRING us;
282
283 us.Length = us.MaximumLength = kvbi->NameLength;
284 us.Buffer = kvbi->Name;
285
286 if (!FsRtlAreNamesEqual(&mountedus, &us, TRUE, NULL)) {
287 has_options = TRUE;
288 break;
289 }
290 } else if (Status != STATUS_NO_MORE_ENTRIES) {
291 ERR("ZwEnumerateValueKey returned %08x\n", Status);
292 goto end2;
293 }
294 } while (NT_SUCCESS(Status));
295
296 if (has_options) {
297 DWORD data = 0;
298
299 Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
300 if (!NT_SUCCESS(Status)) {
301 ERR("ZwSetValueKey returned %08x\n", Status);
302 goto end2;
303 }
304 } else {
305 Status = ZwDeleteKey(h);
306 if (!NT_SUCCESS(Status)) {
307 ERR("ZwDeleteKey returned %08x\n", Status);
308 goto end2;
309 }
310 }
311
312 Status = STATUS_SUCCESS;
313
314 end2:
315 ZwClose(h);
316
317 end:
318 ExFreePool(kvbi);
319
320 return Status;
321 }
322
323 NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID* uuid) {
324 UNICODE_STRING path;
325 NTSTATUS Status;
326 ULONG i, j;
327
328 path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
329 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
330
331 if (!path.Buffer) {
332 ERR("out of memory\n");
333 return STATUS_INSUFFICIENT_RESOURCES;
334 }
335
336 RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
337 i = registry_path.Length / sizeof(WCHAR);
338
339 path.Buffer[i] = '\\';
340 i++;
341
342 for (j = 0; j < 16; j++) {
343 path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
344 path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
345
346 i += 2;
347
348 if (j == 3 || j == 5 || j == 7 || j == 9) {
349 path.Buffer[i] = '-';
350 i++;
351 }
352 }
353
354 Status = registry_mark_volume_unmounted_path(&path);
355 if (!NT_SUCCESS(Status)) {
356 ERR("registry_mark_volume_unmounted_path returned %08x\n", Status);
357 goto end;
358 }
359
360 Status = STATUS_SUCCESS;
361
362 end:
363 ExFreePool(path.Buffer);
364
365 return Status;
366 }
367
368 #define is_hex(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
369
370 static BOOL is_uuid(ULONG namelen, WCHAR* name) {
371 ULONG i;
372
373 if (namelen != 36 * sizeof(WCHAR))
374 return FALSE;
375
376 for (i = 0; i < 36; i++) {
377 if (i == 8 || i == 13 || i == 18 || i == 23) {
378 if (name[i] != '-')
379 return FALSE;
380 } else if (!is_hex(name[i]))
381 return FALSE;
382 }
383
384 return TRUE;
385 }
386
387 typedef struct {
388 UNICODE_STRING name;
389 LIST_ENTRY list_entry;
390 } key_name;
391
392 static void reset_subkeys(HANDLE h, PUNICODE_STRING reg_path) {
393 NTSTATUS Status;
394 KEY_BASIC_INFORMATION* kbi;
395 ULONG kbilen = sizeof(KEY_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen, index = 0;
396 LIST_ENTRY key_names, *le;
397
398 InitializeListHead(&key_names);
399
400 kbi = ExAllocatePoolWithTag(PagedPool, kbilen, ALLOC_TAG);
401 if (!kbi) {
402 ERR("out of memory\n");
403 return;
404 }
405
406 do {
407 Status = ZwEnumerateKey(h, index, KeyBasicInformation, kbi, kbilen, &retlen);
408
409 index++;
410
411 if (NT_SUCCESS(Status)) {
412 key_name* kn;
413
414 ERR("key: %.*S\n", kbi->NameLength / sizeof(WCHAR), kbi->Name);
415
416 if (is_uuid(kbi->NameLength, kbi->Name)) {
417 kn = ExAllocatePoolWithTag(PagedPool, sizeof(key_name), ALLOC_TAG);
418 if (!kn) {
419 ERR("out of memory\n");
420 goto end;
421 }
422
423 kn->name.Length = kn->name.MaximumLength = kbi->NameLength;
424 kn->name.Buffer = ExAllocatePoolWithTag(PagedPool, kn->name.Length, ALLOC_TAG);
425
426 if (!kn->name.Buffer) {
427 ERR("out of memory\n");
428 ExFreePool(kn);
429 goto end;
430 }
431
432 RtlCopyMemory(kn->name.Buffer, kbi->Name, kbi->NameLength);
433
434 InsertTailList(&key_names, &kn->list_entry);
435 }
436 } else if (Status != STATUS_NO_MORE_ENTRIES)
437 ERR("ZwEnumerateKey returned %08x\n", Status);
438 } while (NT_SUCCESS(Status));
439
440 le = key_names.Flink;
441 while (le != &key_names) {
442 key_name* kn = CONTAINING_RECORD(le, key_name, list_entry);
443 UNICODE_STRING path;
444
445 path.Length = path.MaximumLength = reg_path->Length + sizeof(WCHAR) + kn->name.Length;
446 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
447
448 if (!path.Buffer) {
449 ERR("out of memory\n");
450 goto end;
451 }
452
453 RtlCopyMemory(path.Buffer, reg_path->Buffer, reg_path->Length);
454 path.Buffer[reg_path->Length / sizeof(WCHAR)] = '\\';
455 RtlCopyMemory(&path.Buffer[(reg_path->Length / sizeof(WCHAR)) + 1], kn->name.Buffer, kn->name.Length);
456
457 Status = registry_mark_volume_unmounted_path(&path);
458 if (!NT_SUCCESS(Status))
459 WARN("registry_mark_volume_unmounted_path returned %08x\n", Status);
460
461 ExFreePool(path.Buffer);
462
463 le = le->Flink;
464 }
465
466 end:
467 while (!IsListEmpty(&key_names)) {
468 key_name* kn;
469
470 le = RemoveHeadList(&key_names);
471 kn = CONTAINING_RECORD(le, key_name, list_entry);
472
473 if (kn->name.Buffer)
474 ExFreePool(kn->name.Buffer);
475
476 ExFreePool(kn);
477 }
478
479 ExFreePool(kbi);
480 }
481
482 static void read_mappings(PUNICODE_STRING regpath) {
483 WCHAR* path;
484 UNICODE_STRING us;
485 HANDLE h;
486 OBJECT_ATTRIBUTES oa;
487 ULONG dispos;
488 NTSTATUS Status;
489 ULONG kvfilen, retlen, i;
490 KEY_VALUE_FULL_INFORMATION* kvfi;
491
492 const WCHAR mappings[] = L"\\Mappings";
493
494 path = ExAllocatePoolWithTag(PagedPool, regpath->Length + (wcslen(mappings) * sizeof(WCHAR)), ALLOC_TAG);
495 if (!path) {
496 ERR("out of memory\n");
497 return;
498 }
499
500 RtlCopyMemory(path, regpath->Buffer, regpath->Length);
501 RtlCopyMemory((UINT8*)path + regpath->Length, mappings, wcslen(mappings) * sizeof(WCHAR));
502
503 us.Buffer = path;
504 us.Length = us.MaximumLength = regpath->Length + ((USHORT)wcslen(mappings) * sizeof(WCHAR));
505
506 InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
507
508 // FIXME - keep open and do notify for changes
509 Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
510
511 if (!NT_SUCCESS(Status)) {
512 ERR("ZwCreateKey returned %08x\n", Status);
513 ExFreePool(path);
514 return;
515 }
516
517 if (dispos == REG_OPENED_EXISTING_KEY) {
518 kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
519 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
520
521 if (!kvfi) {
522 ERR("out of memory\n");
523 ExFreePool(path);
524 ZwClose(h);
525 return;
526 }
527
528 i = 0;
529 do {
530 Status = ZwEnumerateValueKey(h, i, KeyValueFullInformation, kvfi, kvfilen, &retlen);
531
532 if (NT_SUCCESS(Status) && kvfi->DataLength > 0) {
533 UINT32 val = 0;
534
535 RtlCopyMemory(&val, (UINT8*)kvfi + kvfi->DataOffset, min(kvfi->DataLength, sizeof(UINT32)));
536
537 TRACE("entry %u = %.*S = %u\n", i, kvfi->NameLength / sizeof(WCHAR), kvfi->Name, val);
538
539 add_user_mapping(kvfi->Name, kvfi->NameLength / sizeof(WCHAR), val);
540 }
541
542 i = i + 1;
543 } while (Status != STATUS_NO_MORE_ENTRIES);
544 }
545
546 ZwClose(h);
547
548 ExFreePool(path);
549 }
550
551 static void get_registry_value(HANDLE h, WCHAR* string, ULONG type, void* val, ULONG size) {
552 ULONG kvfilen;
553 KEY_VALUE_FULL_INFORMATION* kvfi;
554 UNICODE_STRING us;
555 NTSTATUS Status;
556
557 RtlInitUnicodeString(&us, string);
558
559 kvfi = NULL;
560 kvfilen = 0;
561 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
562
563 if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
564 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
565
566 if (!kvfi) {
567 ERR("out of memory\n");
568 ZwClose(h);
569 return;
570 }
571
572 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
573
574 if (NT_SUCCESS(Status)) {
575 if (kvfi->Type == type && kvfi->DataLength >= size) {
576 RtlCopyMemory(val, ((UINT8*)kvfi) + kvfi->DataOffset, size);
577 } else {
578 Status = ZwDeleteValueKey(h, &us);
579 if (!NT_SUCCESS(Status)) {
580 ERR("ZwDeleteValueKey returned %08x\n", Status);
581 }
582
583 Status = ZwSetValueKey(h, &us, 0, type, val, size);
584 if (!NT_SUCCESS(Status)) {
585 ERR("ZwSetValueKey returned %08x\n", Status);
586 }
587 }
588 }
589
590 ExFreePool(kvfi);
591 } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
592 Status = ZwSetValueKey(h, &us, 0, type, val, size);
593
594 if (!NT_SUCCESS(Status)) {
595 ERR("ZwSetValueKey returned %08x\n", Status);
596 }
597 } else {
598 ERR("ZwQueryValueKey returned %08x\n", Status);
599 }
600 }
601
602 void STDCALL read_registry(PUNICODE_STRING regpath) {
603 #ifndef __REACTOS__
604 UNICODE_STRING us;
605 #endif
606 OBJECT_ATTRIBUTES oa;
607 NTSTATUS Status;
608 HANDLE h;
609 ULONG dispos;
610 #ifndef __REACTOS__
611 ULONG kvfilen;
612 KEY_VALUE_FULL_INFORMATION* kvfi;
613 #endif
614
615 #ifndef __REACTOS__
616 static WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
617 #endif
618
619 read_mappings(regpath);
620
621 InitializeObjectAttributes(&oa, regpath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
622
623 Status = ZwCreateKey(&h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
624
625 if (!NT_SUCCESS(Status)) {
626 ERR("ZwCreateKey returned %08x\n", Status);
627 return;
628 }
629
630 reset_subkeys(h, regpath);
631
632 get_registry_value(h, L"Compress", REG_DWORD, &mount_compress, sizeof(mount_compress));
633 get_registry_value(h, L"CompressForce", REG_DWORD, &mount_compress_force, sizeof(mount_compress_force));
634 get_registry_value(h, L"CompressType", REG_DWORD, &mount_compress_type, sizeof(mount_compress_type));
635 get_registry_value(h, L"ZlibLevel", REG_DWORD, &mount_zlib_level, sizeof(mount_zlib_level));
636 get_registry_value(h, L"FlushInterval", REG_DWORD, &mount_flush_interval, sizeof(mount_flush_interval));
637 get_registry_value(h, L"MaxInline", REG_DWORD, &mount_max_inline, sizeof(mount_max_inline));
638
639 if (mount_flush_interval == 0)
640 mount_flush_interval = 1;
641
642 #ifdef _DEBUG
643 get_registry_value(h, L"DebugLogLevel", REG_DWORD, &debug_log_level, sizeof(debug_log_level));
644
645 RtlInitUnicodeString(&us, L"LogDevice");
646
647 kvfi = NULL;
648 kvfilen = 0;
649 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
650
651 if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
652 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
653
654 if (!kvfi) {
655 ERR("out of memory\n");
656 ZwClose(h);
657 return;
658 }
659
660 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
661
662 if (NT_SUCCESS(Status)) {
663 if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
664 log_device.Length = log_device.MaximumLength = kvfi->DataLength;
665 log_device.Buffer = ExAllocatePoolWithTag(PagedPool, kvfi->DataLength, ALLOC_TAG);
666
667 if (!log_device.Buffer) {
668 ERR("out of memory\n");
669 ExFreePool(kvfi);
670 ZwClose(h);
671 return;
672 }
673
674 RtlCopyMemory(log_device.Buffer, ((UINT8*)kvfi) + kvfi->DataOffset, kvfi->DataLength);
675
676 if (log_device.Buffer[(log_device.Length / sizeof(WCHAR)) - 1] == 0)
677 log_device.Length -= sizeof(WCHAR);
678 } else {
679 ERR("LogDevice was type %u, length %u\n", kvfi->Type, kvfi->DataLength);
680
681 Status = ZwDeleteValueKey(h, &us);
682 if (!NT_SUCCESS(Status)) {
683 ERR("ZwDeleteValueKey returned %08x\n", Status);
684 }
685 }
686 }
687
688 ExFreePool(kvfi);
689 } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
690 ERR("ZwQueryValueKey returned %08x\n", Status);
691 }
692
693 RtlInitUnicodeString(&us, L"LogFile");
694
695 kvfi = NULL;
696 kvfilen = 0;
697 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
698
699 if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
700 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
701
702 if (!kvfi) {
703 ERR("out of memory\n");
704 ZwClose(h);
705 return;
706 }
707
708 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
709
710 if (NT_SUCCESS(Status)) {
711 if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
712 log_file.Length = log_file.MaximumLength = kvfi->DataLength;
713 log_file.Buffer = ExAllocatePoolWithTag(PagedPool, kvfi->DataLength, ALLOC_TAG);
714
715 if (!log_file.Buffer) {
716 ERR("out of memory\n");
717 ExFreePool(kvfi);
718 ZwClose(h);
719 return;
720 }
721
722 RtlCopyMemory(log_file.Buffer, ((UINT8*)kvfi) + kvfi->DataOffset, kvfi->DataLength);
723
724 if (log_file.Buffer[(log_file.Length / sizeof(WCHAR)) - 1] == 0)
725 log_file.Length -= sizeof(WCHAR);
726 } else {
727 ERR("LogFile was type %u, length %u\n", kvfi->Type, kvfi->DataLength);
728
729 Status = ZwDeleteValueKey(h, &us);
730 if (!NT_SUCCESS(Status)) {
731 ERR("ZwDeleteValueKey returned %08x\n", Status);
732 }
733 }
734 }
735
736 ExFreePool(kvfi);
737 } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
738 Status = ZwSetValueKey(h, &us, 0, REG_SZ, def_log_file, (wcslen(def_log_file) + 1) * sizeof(WCHAR));
739
740 if (!NT_SUCCESS(Status)) {
741 ERR("ZwSetValueKey returned %08x\n", Status);
742 }
743 } else {
744 ERR("ZwQueryValueKey returned %08x\n", Status);
745 }
746
747 if (log_file.Length == 0) {
748 log_file.Length = log_file.MaximumLength = wcslen(def_log_file) * sizeof(WCHAR);
749 log_file.Buffer = ExAllocatePoolWithTag(PagedPool, log_file.MaximumLength, ALLOC_TAG);
750
751 if (!log_file.Buffer) {
752 ERR("out of memory\n");
753 ZwClose(h);
754 return;
755 }
756
757 RtlCopyMemory(log_file.Buffer, def_log_file, log_file.Length);
758 }
759 #endif
760
761 ZwClose(h);
762 }