ReactOS  0.4.15-dev-5452-g3c95c95
registry.c
Go to the documentation of this file.
1 /* Copyright (c) Mark Harmstone 2016-17
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 #include "zstd/zstd.h"
20 
23 extern ERESOURCE mapping_lock;
24 
25 #ifdef _DEBUG
26 extern HANDLE log_handle;
27 extern ERESOURCE log_lock;
28 extern PFILE_OBJECT comfo;
29 extern PDEVICE_OBJECT comdo;
30 #endif
31 
33 
34 static const WCHAR option_mounted[] = L"Mounted";
35 
37  BTRFS_UUID* uuid = &Vcb->superblock.uuid;
38  mount_options* options = &Vcb->options;
39  UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus,
40  maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus,
41  norootdirus, nodatacowus;
44  ULONG i, j, kvfilen, index, retlen;
46  HANDLE h;
47 
48  options->compress = mount_compress;
49  options->compress_force = mount_compress_force;
51  options->readonly = mount_readonly;
52  options->zlib_level = mount_zlib_level;
53  options->zstd_level = mount_zstd_level;
54  options->flush_interval = mount_flush_interval;
55  options->max_inline = min(mount_max_inline, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
56  options->skip_balance = mount_skip_balance;
57  options->no_barrier = mount_no_barrier;
58  options->no_trim = mount_no_trim;
59  options->clear_cache = mount_clear_cache;
60  options->allow_degraded = mount_allow_degraded;
61  options->subvol_id = 0;
62  options->no_root_dir = mount_no_root_dir;
63  options->nodatacow = mount_nodatacow;
64 
65  path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
67 
68  if (!path.Buffer) {
69  ERR("out of memory\n");
71  }
72 
74  i = registry_path.Length / sizeof(WCHAR);
75 
76  path.Buffer[i] = '\\';
77  i++;
78 
79  for (j = 0; j < 16; j++) {
80  path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
81  path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
82 
83  i += 2;
84 
85  if (j == 3 || j == 5 || j == 7 || j == 9) {
86  path.Buffer[i] = '-';
87  i++;
88  }
89  }
90 
91  kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR));
92  kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
93  if (!kvfi) {
94  ERR("out of memory\n");
96  goto end;
97  }
98 
100 
101  Status = ZwOpenKey(&h, KEY_QUERY_VALUE, &oa);
104  goto end;
105  } else if (!NT_SUCCESS(Status)) {
106  ERR("ZwOpenKey returned %08lx\n", Status);
107  goto end;
108  }
109 
110  index = 0;
111 
112  RtlInitUnicodeString(&ignoreus, L"Ignore");
113  RtlInitUnicodeString(&compressus, L"Compress");
114  RtlInitUnicodeString(&compressforceus, L"CompressForce");
115  RtlInitUnicodeString(&compresstypeus, L"CompressType");
116  RtlInitUnicodeString(&readonlyus, L"Readonly");
117  RtlInitUnicodeString(&zliblevelus, L"ZlibLevel");
118  RtlInitUnicodeString(&flushintervalus, L"FlushInterval");
119  RtlInitUnicodeString(&maxinlineus, L"MaxInline");
120  RtlInitUnicodeString(&subvolidus, L"SubvolId");
121  RtlInitUnicodeString(&skipbalanceus, L"SkipBalance");
122  RtlInitUnicodeString(&nobarrierus, L"NoBarrier");
123  RtlInitUnicodeString(&notrimus, L"NoTrim");
124  RtlInitUnicodeString(&clearcacheus, L"ClearCache");
125  RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded");
126  RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel");
127  RtlInitUnicodeString(&norootdirus, L"NoRootDir");
128  RtlInitUnicodeString(&nodatacowus, L"NoDataCOW");
129 
130  do {
131  Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
132 
133  index++;
134 
135  if (NT_SUCCESS(Status)) {
137 
138  us.Length = us.MaximumLength = (USHORT)kvfi->NameLength;
139  us.Buffer = kvfi->Name;
140 
141  if (FsRtlAreNamesEqual(&ignoreus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
142  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
143 
144  options->ignore = *val != 0 ? true : false;
145  } else if (FsRtlAreNamesEqual(&compressus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
146  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
147 
148  options->compress = *val != 0 ? true : false;
149  } else if (FsRtlAreNamesEqual(&compressforceus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
150  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
151 
152  options->compress_force = *val != 0 ? true : false;
153  } else if (FsRtlAreNamesEqual(&compresstypeus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
154  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
155 
156  options->compress_type = (uint8_t)(*val > BTRFS_COMPRESSION_ZSTD ? 0 : *val);
157  } else if (FsRtlAreNamesEqual(&readonlyus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
158  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
159 
160  options->readonly = *val != 0 ? true : false;
161  } else if (FsRtlAreNamesEqual(&zliblevelus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
162  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
163 
164  options->zlib_level = *val;
165  } else if (FsRtlAreNamesEqual(&flushintervalus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
166  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
167 
168  options->flush_interval = *val;
169  } else if (FsRtlAreNamesEqual(&maxinlineus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
170  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
171 
172  options->max_inline = min(*val, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
173  } else if (FsRtlAreNamesEqual(&subvolidus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_QWORD) {
174  uint64_t* val = (uint64_t*)((uint8_t*)kvfi + kvfi->DataOffset);
175 
176  options->subvol_id = *val;
177  } else if (FsRtlAreNamesEqual(&skipbalanceus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
178  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
179 
180  options->skip_balance = *val;
181  } else if (FsRtlAreNamesEqual(&nobarrierus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
182  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
183 
184  options->no_barrier = *val;
185  } else if (FsRtlAreNamesEqual(&notrimus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
186  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
187 
188  options->no_trim = *val;
189  } else if (FsRtlAreNamesEqual(&clearcacheus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
190  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
191 
192  options->clear_cache = *val;
193  } else if (FsRtlAreNamesEqual(&allowdegradedus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
194  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
195 
196  options->allow_degraded = *val;
197  } else if (FsRtlAreNamesEqual(&zstdlevelus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
198  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
199 
200  options->zstd_level = *val;
201  } else if (FsRtlAreNamesEqual(&norootdirus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
202  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
203 
204  options->no_root_dir = *val;
205  } else if (FsRtlAreNamesEqual(&nodatacowus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
206  DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
207 
208  options->nodatacow = *val;
209  }
210  } else if (Status != STATUS_NO_MORE_ENTRIES) {
211  ERR("ZwEnumerateValueKey returned %08lx\n", Status);
212  goto end2;
213  }
214  } while (NT_SUCCESS(Status));
215 
216  if (!options->compress && options->compress_force)
217  options->compress = true;
218 
219  if (options->zlib_level > 9)
220  options->zlib_level = 9;
221 
222  if (options->zstd_level > (uint32_t)ZSTD_maxCLevel())
223  options->zstd_level = ZSTD_maxCLevel();
224 
225  if (options->flush_interval == 0)
226  options->flush_interval = mount_flush_interval;
227 
229 
230 end2:
231  ZwClose(h);
232 
233 end:
234  ExFreePool(path.Buffer);
235 
236  if (kvfi)
237  ExFreePool(kvfi);
238 
239  return Status;
240 }
241 
243  UNICODE_STRING path, mountedus;
244  ULONG i, j;
247  HANDLE h;
248  DWORD data;
249 
250  path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
252 
253  if (!path.Buffer) {
254  ERR("out of memory\n");
256  }
257 
259  i = registry_path.Length / sizeof(WCHAR);
260 
261  path.Buffer[i] = '\\';
262  i++;
263 
264  for (j = 0; j < 16; j++) {
265  path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
266  path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
267 
268  i += 2;
269 
270  if (j == 3 || j == 5 || j == 7 || j == 9) {
271  path.Buffer[i] = '-';
272  i++;
273  }
274  }
275 
277 
278  Status = ZwCreateKey(&h, KEY_SET_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
279  if (!NT_SUCCESS(Status)) {
280  ERR("ZwCreateKey returned %08lx\n", Status);
281  goto end;
282  }
283 
284  mountedus.Buffer = (WCHAR*)option_mounted;
285  mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
286 
287  data = 1;
288 
289  Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
290  if (!NT_SUCCESS(Status)) {
291  ERR("ZwSetValueKey returned %08lx\n", Status);
292  goto end2;
293  }
294 
296 
297 end2:
298  ZwClose(h);
299 
300 end:
301  ExFreePool(path.Buffer);
302 
303  return Status;
304 }
305 
307  HANDLE h;
310  ULONG index, kvbilen = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen;
312  bool has_options = false;
313  UNICODE_STRING mountedus;
314 
315  // If a volume key has any options in it, we set Mounted to 0 and return. Otherwise,
316  // we delete the whole thing.
317 
318  kvbi = ExAllocatePoolWithTag(PagedPool, kvbilen, ALLOC_TAG);
319  if (!kvbi) {
320  ERR("out of memory\n");
322  }
323 
325 
326  Status = ZwOpenKey(&h, KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE, &oa);
327  if (!NT_SUCCESS(Status)) {
328  ERR("ZwOpenKey returned %08lx\n", Status);
329  goto end;
330  }
331 
332  index = 0;
333 
334  mountedus.Buffer = (WCHAR*)option_mounted;
335  mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
336 
337  do {
338  Status = ZwEnumerateValueKey(h, index, KeyValueBasicInformation, kvbi, kvbilen, &retlen);
339 
340  index++;
341 
342  if (NT_SUCCESS(Status)) {
344 
345  us.Length = us.MaximumLength = (USHORT)kvbi->NameLength;
346  us.Buffer = kvbi->Name;
347 
348  if (!FsRtlAreNamesEqual(&mountedus, &us, true, NULL)) {
349  has_options = true;
350  break;
351  }
352  } else if (Status != STATUS_NO_MORE_ENTRIES) {
353  ERR("ZwEnumerateValueKey returned %08lx\n", Status);
354  goto end2;
355  }
356  } while (NT_SUCCESS(Status));
357 
358  if (has_options) {
359  DWORD data = 0;
360 
361  Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
362  if (!NT_SUCCESS(Status)) {
363  ERR("ZwSetValueKey returned %08lx\n", Status);
364  goto end2;
365  }
366  } else {
367  Status = ZwDeleteKey(h);
368  if (!NT_SUCCESS(Status)) {
369  ERR("ZwDeleteKey returned %08lx\n", Status);
370  goto end2;
371  }
372  }
373 
375 
376 end2:
377  ZwClose(h);
378 
379 end:
380  ExFreePool(kvbi);
381 
382  return Status;
383 }
384 
388  ULONG i, j;
389 
390  path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
392 
393  if (!path.Buffer) {
394  ERR("out of memory\n");
396  }
397 
399  i = registry_path.Length / sizeof(WCHAR);
400 
401  path.Buffer[i] = '\\';
402  i++;
403 
404  for (j = 0; j < 16; j++) {
405  path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
406  path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
407 
408  i += 2;
409 
410  if (j == 3 || j == 5 || j == 7 || j == 9) {
411  path.Buffer[i] = '-';
412  i++;
413  }
414  }
415 
417  if (!NT_SUCCESS(Status)) {
418  ERR("registry_mark_volume_unmounted_path returned %08lx\n", Status);
419  goto end;
420  }
421 
423 
424 end:
425  ExFreePool(path.Buffer);
426 
427  return Status;
428 }
429 
430 #define is_hex(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
431 
432 static bool is_uuid(ULONG namelen, WCHAR* name) {
433  ULONG i;
434 
435  if (namelen != 36 * sizeof(WCHAR))
436  return false;
437 
438  for (i = 0; i < 36; i++) {
439  if (i == 8 || i == 13 || i == 18 || i == 23) {
440  if (name[i] != '-')
441  return false;
442  } else if (!is_hex(name[i]))
443  return false;
444  }
445 
446  return true;
447 }
448 
449 typedef struct {
452 } key_name;
453 
454 static void reset_subkeys(HANDLE h, PUNICODE_STRING reg_path) {
457  ULONG kbilen = sizeof(KEY_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen, index = 0;
458  LIST_ENTRY key_names, *le;
459 
461 
462  kbi = ExAllocatePoolWithTag(PagedPool, kbilen, ALLOC_TAG);
463  if (!kbi) {
464  ERR("out of memory\n");
465  return;
466  }
467 
468  do {
469  Status = ZwEnumerateKey(h, index, KeyBasicInformation, kbi, kbilen, &retlen);
470 
471  index++;
472 
473  if (NT_SUCCESS(Status)) {
474  key_name* kn;
475 
476  TRACE("key: %.*S\n", (int)(kbi->NameLength / sizeof(WCHAR)), kbi->Name);
477 
478  if (is_uuid(kbi->NameLength, kbi->Name)) {
480  if (!kn) {
481  ERR("out of memory\n");
482  goto end;
483  }
484 
485  kn->name.Length = kn->name.MaximumLength = (USHORT)min(0xffff, kbi->NameLength);
487 
488  if (!kn->name.Buffer) {
489  ERR("out of memory\n");
490  ExFreePool(kn);
491  goto end;
492  }
493 
494  RtlCopyMemory(kn->name.Buffer, kbi->Name, kn->name.Length);
495 
497  }
498  } else if (Status != STATUS_NO_MORE_ENTRIES)
499  ERR("ZwEnumerateKey returned %08lx\n", Status);
500  } while (NT_SUCCESS(Status));
501 
502  le = key_names.Flink;
503  while (le != &key_names) {
506 
507  path.Length = path.MaximumLength = reg_path->Length + sizeof(WCHAR) + kn->name.Length;
509 
510  if (!path.Buffer) {
511  ERR("out of memory\n");
512  goto end;
513  }
514 
515  RtlCopyMemory(path.Buffer, reg_path->Buffer, reg_path->Length);
516  path.Buffer[reg_path->Length / sizeof(WCHAR)] = '\\';
517  RtlCopyMemory(&path.Buffer[(reg_path->Length / sizeof(WCHAR)) + 1], kn->name.Buffer, kn->name.Length);
518 
520  if (!NT_SUCCESS(Status))
521  WARN("registry_mark_volume_unmounted_path returned %08lx\n", Status);
522 
523  ExFreePool(path.Buffer);
524 
525  le = le->Flink;
526  }
527 
528 end:
529  while (!IsListEmpty(&key_names)) {
530  key_name* kn;
531 
532  le = RemoveHeadList(&key_names);
534 
535  if (kn->name.Buffer)
536  ExFreePool(kn->name.Buffer);
537 
538  ExFreePool(kn);
539  }
540 
541  ExFreePool(kbi);
542 }
543 
544 static void read_mappings(PUNICODE_STRING regpath) {
545  WCHAR* path;
547  HANDLE h;
549  ULONG dispos;
551 
552  static const WCHAR mappings[] = L"\\Mappings";
553 
554  while (!IsListEmpty(&uid_map_list)) {
556 
557  if (um->sid) ExFreePool(um->sid);
558  ExFreePool(um);
559  }
560 
561  path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) - sizeof(WCHAR), ALLOC_TAG);
562  if (!path) {
563  ERR("out of memory\n");
564  return;
565  }
566 
567  RtlCopyMemory(path, regpath->Buffer, regpath->Length);
568  RtlCopyMemory((uint8_t*)path + regpath->Length, mappings, sizeof(mappings) - sizeof(WCHAR));
569 
570  us.Buffer = path;
571  us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) - sizeof(WCHAR);
572 
574 
575  Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
576 
577  if (!NT_SUCCESS(Status)) {
578  ERR("ZwCreateKey returned %08lx\n", Status);
579  ExFreePool(path);
580  return;
581  }
582 
585  ULONG kvfilen, retlen, i;
586 
587  kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
588  kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
589 
590  if (!kvfi) {
591  ERR("out of memory\n");
592  ExFreePool(path);
593  ZwClose(h);
594  return;
595  }
596 
597  i = 0;
598  do {
599  Status = ZwEnumerateValueKey(h, i, KeyValueFullInformation, kvfi, kvfilen, &retlen);
600 
601  if (NT_SUCCESS(Status) && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
602  uint32_t val = 0;
603 
604  RtlCopyMemory(&val, (uint8_t*)kvfi + kvfi->DataOffset, min(kvfi->DataLength, sizeof(uint32_t)));
605 
606  TRACE("entry %lu = %.*S = %u\n", i, (int)(kvfi->NameLength / sizeof(WCHAR)), kvfi->Name, val);
607 
608  add_user_mapping(kvfi->Name, kvfi->NameLength / sizeof(WCHAR), val);
609  }
610 
611  i = i + 1;
612  } while (Status != STATUS_NO_MORE_ENTRIES);
613 
614  ExFreePool(kvfi);
615  }
616 
617  ZwClose(h);
618 
619  ExFreePool(path);
620 }
621 
622 static void read_group_mappings(PUNICODE_STRING regpath) {
623  WCHAR* path;
625  HANDLE h;
627  ULONG dispos;
629 
630  static const WCHAR mappings[] = L"\\GroupMappings";
631 
632  while (!IsListEmpty(&gid_map_list)) {
634 
635  if (gm->sid) ExFreePool(gm->sid);
636  ExFreePool(gm);
637  }
638 
639  path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) - sizeof(WCHAR), ALLOC_TAG);
640  if (!path) {
641  ERR("out of memory\n");
642  return;
643  }
644 
645  RtlCopyMemory(path, regpath->Buffer, regpath->Length);
646  RtlCopyMemory((uint8_t*)path + regpath->Length, mappings, sizeof(mappings) - sizeof(WCHAR));
647 
648  us.Buffer = path;
649  us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) - sizeof(WCHAR);
650 
652 
653  Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
654 
655  if (!NT_SUCCESS(Status)) {
656  ERR("ZwCreateKey returned %08lx\n", Status);
657  ExFreePool(path);
658  return;
659  }
660 
661  ExFreePool(path);
662 
665  ULONG kvfilen, retlen, i;
666 
667  kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
668  kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
669 
670  if (!kvfi) {
671  ERR("out of memory\n");
672  ZwClose(h);
673  return;
674  }
675 
676  i = 0;
677  do {
678  Status = ZwEnumerateValueKey(h, i, KeyValueFullInformation, kvfi, kvfilen, &retlen);
679 
680  if (NT_SUCCESS(Status) && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
681  uint32_t val = 0;
682 
683  RtlCopyMemory(&val, (uint8_t*)kvfi + kvfi->DataOffset, min(kvfi->DataLength, sizeof(uint32_t)));
684 
685  TRACE("entry %lu = %.*S = %u\n", i, (int)(kvfi->NameLength / sizeof(WCHAR)), kvfi->Name, val);
686 
687  add_group_mapping(kvfi->Name, kvfi->NameLength / sizeof(WCHAR), val);
688  }
689 
690  i = i + 1;
691  } while (Status != STATUS_NO_MORE_ENTRIES);
692 
693  ExFreePool(kvfi);
694  } else if (dispos == REG_CREATED_NEW_KEY) {
695  static const WCHAR builtin_users[] = L"S-1-5-32-545";
696 
697  UNICODE_STRING us2;
698  DWORD val;
699 
700  // If we're creating the key for the first time, we add a default mapping of
701  // BUILTIN\Users to gid 100, which ought to correspond to the "users" group on Linux.
702 
703  us2.Length = us2.MaximumLength = sizeof(builtin_users) - sizeof(WCHAR);
705 
706  if (us2.Buffer) {
707  RtlCopyMemory(us2.Buffer, builtin_users, us2.Length);
708 
709  val = 100;
710  Status = ZwSetValueKey(h, &us2, 0, REG_DWORD, &val, sizeof(DWORD));
711  if (!NT_SUCCESS(Status)) {
712  ERR("ZwSetValueKey returned %08lx\n", Status);
713  ZwClose(h);
714  return;
715  }
716 
717  add_group_mapping(us2.Buffer, us2.Length / sizeof(WCHAR), val);
718 
719  ExFreePool(us2.Buffer);
720  }
721  }
722 
723  ZwClose(h);
724 }
725 
726 static void get_registry_value(HANDLE h, WCHAR* string, ULONG type, void* val, ULONG size) {
727  ULONG kvfilen;
731 
732  RtlInitUnicodeString(&us, string);
733 
734  kvfi = NULL;
735  kvfilen = 0;
736  Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
737 
738  if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
739  kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
740 
741  if (!kvfi) {
742  ERR("out of memory\n");
743  ZwClose(h);
744  return;
745  }
746 
747  Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
748 
749  if (NT_SUCCESS(Status)) {
750  if (kvfi->Type == type && kvfi->DataLength >= size) {
751  RtlCopyMemory(val, ((uint8_t*)kvfi) + kvfi->DataOffset, size);
752  } else {
754  if (!NT_SUCCESS(Status)) {
755  ERR("ZwDeleteValueKey returned %08lx\n", Status);
756  }
757 
758  Status = ZwSetValueKey(h, &us, 0, type, val, size);
759  if (!NT_SUCCESS(Status)) {
760  ERR("ZwSetValueKey returned %08lx\n", Status);
761  }
762  }
763  }
764 
765  ExFreePool(kvfi);
766  } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
767  Status = ZwSetValueKey(h, &us, 0, type, val, size);
768 
769  if (!NT_SUCCESS(Status)) {
770  ERR("ZwSetValueKey returned %08lx\n", Status);
771  }
772  } else {
773  ERR("ZwQueryValueKey returned %08lx\n", Status);
774  }
775 }
776 
777 void read_registry(PUNICODE_STRING regpath, bool refresh) {
780  HANDLE h;
781  ULONG dispos;
782 #ifdef _DEBUG
784  ULONG kvfilen, old_debug_log_level = debug_log_level;
785  UNICODE_STRING us, old_log_file, old_log_device;
786 
787  static const WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
788 #endif
789 
791 
792  read_mappings(regpath);
793  read_group_mappings(regpath);
794 
796 
798 
800 
801  if (!NT_SUCCESS(Status)) {
802  ERR("ZwCreateKey returned %08lx\n", Status);
803  return;
804  }
805 
806  if (!refresh)
807  reset_subkeys(h, regpath);
808 
824 
825  if (!refresh)
826  get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp));
827 
828  if (mount_flush_interval == 0)
830 
831 #ifdef _DEBUG
832  get_registry_value(h, L"DebugLogLevel", REG_DWORD, &debug_log_level, sizeof(debug_log_level));
833 
834  RtlInitUnicodeString(&us, L"LogDevice");
835 
836  kvfi = NULL;
837  kvfilen = 0;
838  Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
839 
840  old_log_device = log_device;
841 
844 
845  if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
846  kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
847 
848  if (!kvfi) {
849  ERR("out of memory\n");
850  ZwClose(h);
851  return;
852  }
853 
854  Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
855 
856  if (NT_SUCCESS(Status)) {
857  if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
860 
861  if (!log_device.Buffer) {
862  ERR("out of memory\n");
863  ExFreePool(kvfi);
864  ZwClose(h);
865  return;
866  }
867 
868  RtlCopyMemory(log_device.Buffer, ((uint8_t*)kvfi) + kvfi->DataOffset, log_device.Length);
869 
870  if (log_device.Buffer[(log_device.Length / sizeof(WCHAR)) - 1] == 0)
871  log_device.Length -= sizeof(WCHAR);
872  } else {
873  ERR("LogDevice was type %lu, length %lu\n", kvfi->Type, kvfi->DataLength);
874 
876  if (!NT_SUCCESS(Status)) {
877  ERR("ZwDeleteValueKey returned %08lx\n", Status);
878  }
879  }
880  }
881 
882  ExFreePool(kvfi);
883  } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
884  ERR("ZwQueryValueKey returned %08lx\n", Status);
885  }
886 
887  ExAcquireResourceExclusiveLite(&log_lock, true);
888 
889  if (refresh && (log_device.Length != old_log_device.Length || RtlCompareMemory(log_device.Buffer, old_log_device.Buffer, log_device.Length) != log_device.Length ||
890  (!comfo && log_device.Length > 0) || (old_debug_log_level == 0 && debug_log_level > 0) || (old_debug_log_level > 0 && debug_log_level == 0))) {
891  if (comfo)
892  ObDereferenceObject(comfo);
893 
894  if (log_handle) {
895  ZwClose(log_handle);
896  log_handle = NULL;
897  }
898 
899  comfo = NULL;
900  comdo = NULL;
901 
902  if (log_device.Length > 0 && debug_log_level > 0) {
904  if (!NT_SUCCESS(Status))
905  DbgPrint("IoGetDeviceObjectPointer returned %08lx\n", Status);
906  }
907  }
908 
909  ExReleaseResourceLite(&log_lock);
910 
911  if (old_log_device.Buffer)
912  ExFreePool(old_log_device.Buffer);
913 
914  RtlInitUnicodeString(&us, L"LogFile");
915 
916  kvfi = NULL;
917  kvfilen = 0;
918  Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
919 
920  old_log_file = log_file;
921 
922  if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
923  kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
924 
925  if (!kvfi) {
926  ERR("out of memory\n");
927  ZwClose(h);
928  return;
929  }
930 
931  Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
932 
933  if (NT_SUCCESS(Status)) {
934  if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
937 
938  if (!log_file.Buffer) {
939  ERR("out of memory\n");
940  ExFreePool(kvfi);
941  ZwClose(h);
942  return;
943  }
944 
945  RtlCopyMemory(log_file.Buffer, ((uint8_t*)kvfi) + kvfi->DataOffset, log_file.Length);
946 
947  if (log_file.Buffer[(log_file.Length / sizeof(WCHAR)) - 1] == 0)
948  log_file.Length -= sizeof(WCHAR);
949  } else {
950  ERR("LogFile was type %lu, length %lu\n", kvfi->Type, kvfi->DataLength);
951 
953  if (!NT_SUCCESS(Status))
954  ERR("ZwDeleteValueKey returned %08lx\n", Status);
955 
956  log_file.Length = 0;
957  }
958  } else {
959  ERR("ZwQueryValueKey returned %08lx\n", Status);
960  log_file.Length = 0;
961  }
962 
963  ExFreePool(kvfi);
964  } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
965  Status = ZwSetValueKey(h, &us, 0, REG_SZ, (void*)def_log_file, sizeof(def_log_file));
966 
967  if (!NT_SUCCESS(Status))
968  ERR("ZwSetValueKey returned %08lx\n", Status);
969 
970  log_file.Length = 0;
971  } else {
972  ERR("ZwQueryValueKey returned %08lx\n", Status);
973  log_file.Length = 0;
974  }
975 
976  if (log_file.Length == 0) {
977  log_file.Length = log_file.MaximumLength = sizeof(def_log_file) - sizeof(WCHAR);
979 
980  if (!log_file.Buffer) {
981  ERR("out of memory\n");
982  ZwClose(h);
983  return;
984  }
985 
986  RtlCopyMemory(log_file.Buffer, def_log_file, log_file.Length);
987  }
988 
989  ExAcquireResourceExclusiveLite(&log_lock, true);
990 
991  if (refresh && (log_file.Length != old_log_file.Length || RtlCompareMemory(log_file.Buffer, old_log_file.Buffer, log_file.Length) != log_file.Length ||
992  (!log_handle && log_file.Length > 0) || (old_debug_log_level == 0 && debug_log_level > 0) || (old_debug_log_level > 0 && debug_log_level == 0))) {
993  if (log_handle) {
994  ZwClose(log_handle);
995  log_handle = NULL;
996  }
997 
998  if (!comfo && log_file.Length > 0 && refresh && debug_log_level > 0) {
1000 
1002 
1003  Status = ZwCreateFile(&log_handle, FILE_WRITE_DATA, &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
1005  if (!NT_SUCCESS(Status)) {
1006  DbgPrint("ZwCreateFile returned %08lx\n", Status);
1007  log_handle = NULL;
1008  }
1009  }
1010  }
1011 
1012  ExReleaseResourceLite(&log_lock);
1013 
1014  if (old_log_file.Buffer)
1015  ExFreePool(old_log_file.Buffer);
1016 #endif
1017 
1018  ZwClose(h);
1019 }
1020 
1021 _Function_class_(WORKER_THREAD_ROUTINE)
1022 static void __stdcall registry_work_item(PVOID Parameter) {
1023  NTSTATUS Status;
1024  HANDLE regh = (HANDLE)Parameter;
1026 
1027  TRACE("registry changed\n");
1028 
1029  read_registry(&registry_path, true);
1030 
1031  Status = ZwNotifyChangeKey(regh, NULL, (PVOID)&wqi, (PVOID)DelayedWorkQueue, &iosb, REG_NOTIFY_CHANGE_LAST_SET, true, NULL, 0, true);
1032  if (!NT_SUCCESS(Status))
1033  ERR("ZwNotifyChangeKey returned %08lx\n", Status);
1034 }
1035 
1037  NTSTATUS Status;
1039 
1040  ExInitializeWorkItem(&wqi, registry_work_item, regh);
1041 
1042  Status = ZwNotifyChangeKey(regh, NULL, (PVOID)&wqi, (PVOID)DelayedWorkQueue, &iosb, REG_NOTIFY_CHANGE_LAST_SET, true, NULL, 0, true);
1043  if (!NT_SUCCESS(Status))
1044  ERR("ZwNotifyChangeKey returned %08lx\n", Status);
1045 }
static void read_group_mappings(PUNICODE_STRING regpath)
Definition: registry.c:622
#define hex_digit(c)
Definition: btrfs_drv.h:1748
static PIO_STATUS_BLOCK iosb
Definition: file.c:98
static void read_mappings(PUNICODE_STRING regpath)
Definition: registry.c:544
struct _KEY_VALUE_BASIC_INFORMATION KEY_VALUE_BASIC_INFORMATION
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define FILE_OPEN_IF
Definition: from_kernel.h:56
#define STATUS_NO_MORE_ENTRIES
Definition: ntstatus.h:205
#define DbgPrint
Definition: hal.h:12
#define KEY_SET_VALUE
Definition: nt_native.h:1017
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
USHORT MaximumLength
Definition: env_spec_w32.h:370
struct _KEY_VALUE_FULL_INFORMATION KEY_VALUE_FULL_INFORMATION
void add_user_mapping(WCHAR *sidstring, ULONG sidstringlength, uint32_t uid)
Definition: security.c:56
static const BYTE us[]
Definition: encode.c:689
GLsizei const GLchar ** path
Definition: glext.h:7234
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
WORK_QUEUE_ITEM wqi
Definition: registry.c:32
#define WARN(fmt,...)
Definition: debug.h:112
LONG NTSTATUS
Definition: precomp.h:26
struct _KEY_BASIC_INFORMATION KEY_BASIC_INFORMATION
void watch_registry(HANDLE regh)
Definition: registry.c:1036
NTSYSAPI NTSTATUS NTAPI ZwDeleteValueKey(__in IN HANDLE Key, __in IN PUNICODE_STRING ValueName)
uint32_t mount_max_inline
Definition: btrfs.c:78
uint32_t mount_clear_cache
Definition: btrfs.c:82
uint32_t mount_no_barrier
Definition: btrfs.c:80
#define is_hex(c)
Definition: registry.c:430
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1435
#define BTRFS_COMPRESSION_ZSTD
Definition: btrfs.h:68
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1085
_In_ PVOID Parameter
Definition: ldrtypes.h:241
#define InsertTailList(ListHead, Entry)
if(dx==0 &&dy==0)
Definition: linetemp.h:174
NTSTATUS registry_mark_volume_mounted(BTRFS_UUID *uuid)
Definition: registry.c:242
UNICODE_STRING name
Definition: registry.c:450
GLint namelen
Definition: glext.h:7232
PSID sid
Definition: btrfs_drv.h:910
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
uint32_t debug_log_level
Definition: btrfs.c:71
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define FILE_SHARE_READ
Definition: compat.h:136
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
static void reset_subkeys(HANDLE h, PUNICODE_STRING reg_path)
Definition: registry.c:454
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
#define ALLOC_TAG
Definition: btrfs_drv.h:87
void read_registry(PUNICODE_STRING regpath, bool refresh)
Definition: registry.c:777
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
#define L(x)
Definition: ntvdm.h:50
PSID sid
Definition: btrfs_drv.h:904
uint32_t mount_readonly
Definition: btrfs.c:84
uint32_t no_pnp
Definition: btrfs.c:87
static NTSTATUS registry_mark_volume_unmounted_path(PUNICODE_STRING path)
Definition: registry.c:306
NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID *uuid)
Definition: registry.c:385
#define FILE_WRITE_THROUGH
Definition: from_kernel.h:26
#define REG_NOTIFY_CHANGE_LAST_SET
Definition: winreg.h:40
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1084
GLuint index
Definition: glext.h:6031
uint32_t mount_zlib_level
Definition: btrfs.c:75
#define FILE_WRITE_DATA
Definition: nt_native.h:631
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
GLuint GLfloat * val
Definition: glext.h:7180
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
Status
Definition: gdiplustypes.h:24
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
BOOLEAN NTAPI FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1, IN PCUNICODE_STRING Name2, IN BOOLEAN IgnoreCase, IN PCWCH UpcaseTable OPTIONAL)
Definition: name.c:296
#define TRACE(s)
Definition: solgame.cpp:4
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
GLsizeiptr size
Definition: glext.h:5919
uint32_t mount_nodatacow
Definition: btrfs.c:86
ERESOURCE mapping_lock
Definition: btrfs.c:103
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define Vcb
Definition: cdprocs.h:1415
#define ObDereferenceObject
Definition: obfuncs.h:203
ZSTDLIB_API int ZSTD_maxCLevel(void)
PVOID HANDLE
Definition: typedefs.h:73
unsigned long DWORD
Definition: ntddk_ex.h:95
#define __stdcall
Definition: typedefs.h:25
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
* PFILE_OBJECT
Definition: iotypes.h:1998
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
LIST_ENTRY gid_map_list
Definition: btrfs.c:68
GLuint GLuint end
Definition: gl.h:1545
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
void add_group_mapping(WCHAR *sidstring, ULONG sidstringlength, uint32_t gid)
Definition: security.c:145
static bool is_uuid(ULONG namelen, WCHAR *name)
Definition: registry.c:432
NTSTATUS registry_load_volume_options(device_extension *Vcb)
Definition: registry.c:36
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
LIST_ENTRY uid_map_list
Definition: btrfs.c:68
#define index(s, c)
Definition: various.h:29
UNICODE_STRING log_device
Definition: btrfs.c:89
uint32_t mount_no_trim
Definition: btrfs.c:81
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
uint32_t mount_zstd_level
Definition: btrfs.c:76
UNICODE_STRING registry_path
Definition: btrfs.c:89
Definition: typedefs.h:119
BYTE uint8_t
Definition: msvideo1.c:66
#define ERR(fmt,...)
Definition: debug.h:110
uint32_t mount_compress_type
Definition: btrfs.c:74
UINT64 uint64_t
Definition: types.h:77
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
#define uint8_t
Definition: nsiface.idl:59
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
UNICODE_STRING log_file
Definition: btrfs.c:89
Definition: stddef.h:6
unsigned short USHORT
Definition: pedump.c:61
uint32_t mount_no_root_dir
Definition: btrfs.c:85
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
_Function_class_(WORKER_THREAD_ROUTINE)
Definition: registry.c:1021
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
uint32_t mount_skip_balance
Definition: btrfs.c:79
static void get_registry_value(HANDLE h, WCHAR *string, ULONG type, void *val, ULONG size)
Definition: registry.c:726
#define min(a, b)
Definition: monoChain.cc:55
Definition: list.h:27
uint32_t mount_flush_interval
Definition: btrfs.c:77
#define NULL
Definition: types.h:112
uint32_t mount_allow_degraded
Definition: btrfs.c:83
UINT32 uint32_t
Definition: types.h:75
uint32_t mount_compress
Definition: btrfs.c:72
static ACCESS_MASK const OBJECT_ATTRIBUTES ULONG const UNICODE_STRING ULONG PULONG dispos
Definition: reg.c:130
Definition: name.c:38
ULONG ERESOURCE
Definition: env_spec_w32.h:594
Definition: msctf.idl:510
#define REG_QWORD
Definition: sdbapi.c:597
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
LIST_ENTRY list_entry
Definition: registry.c:451
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
ROSDATA VSC_LPWSTR key_names[]
Definition: kbda1.c:260
static const WCHAR option_mounted[]
Definition: registry.c:34
#define STATUS_SUCCESS
Definition: shellext.h:65
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define REG_DWORD
Definition: sdbapi.c:596
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
uint32_t mount_compress_force
Definition: btrfs.c:73
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define DELETE
Definition: nt_native.h:57
#define KEY_ENUMERATE_SUB_KEYS
Definition: nt_native.h:1019
#define REG_SZ
Definition: layer.c:22