mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 13:18:51 +00:00
1038 lines
35 KiB
C
1038 lines
35 KiB
C
/* Copyright (c) Mark Harmstone 2016-17
|
|
*
|
|
* This file is part of WinBtrfs.
|
|
*
|
|
* WinBtrfs is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public Licence as published by
|
|
* the Free Software Foundation, either version 3 of the Licence, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WinBtrfs is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public Licence for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public Licence
|
|
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "btrfs_drv.h"
|
|
#include "zstd/zstd.h"
|
|
|
|
extern UNICODE_STRING log_device, log_file, registry_path;
|
|
extern LIST_ENTRY uid_map_list, gid_map_list;
|
|
extern ERESOURCE mapping_lock;
|
|
|
|
#ifdef _DEBUG
|
|
extern HANDLE log_handle;
|
|
extern ERESOURCE log_lock;
|
|
extern PFILE_OBJECT comfo;
|
|
extern PDEVICE_OBJECT comdo;
|
|
#endif
|
|
|
|
WORK_QUEUE_ITEM wqi;
|
|
|
|
static const WCHAR option_mounted[] = L"Mounted";
|
|
|
|
NTSTATUS registry_load_volume_options(device_extension* Vcb) {
|
|
BTRFS_UUID* uuid = &Vcb->superblock.uuid;
|
|
mount_options* options = &Vcb->options;
|
|
UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus,
|
|
maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus,
|
|
norootdirus;
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS Status;
|
|
ULONG i, j, kvfilen, index, retlen;
|
|
KEY_VALUE_FULL_INFORMATION* kvfi = NULL;
|
|
HANDLE h;
|
|
|
|
options->compress = mount_compress;
|
|
options->compress_force = mount_compress_force;
|
|
options->compress_type = mount_compress_type > BTRFS_COMPRESSION_ZSTD ? 0 : mount_compress_type;
|
|
options->readonly = mount_readonly;
|
|
options->zlib_level = mount_zlib_level;
|
|
options->zstd_level = mount_zstd_level;
|
|
options->flush_interval = mount_flush_interval;
|
|
options->max_inline = min(mount_max_inline, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
|
|
options->skip_balance = mount_skip_balance;
|
|
options->no_barrier = mount_no_barrier;
|
|
options->no_trim = mount_no_trim;
|
|
options->clear_cache = mount_clear_cache;
|
|
options->allow_degraded = mount_allow_degraded;
|
|
options->subvol_id = 0;
|
|
|
|
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
|
|
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
|
|
|
if (!path.Buffer) {
|
|
ERR("out of memory\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
|
|
i = registry_path.Length / sizeof(WCHAR);
|
|
|
|
path.Buffer[i] = '\\';
|
|
i++;
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
|
|
path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
|
|
|
|
i += 2;
|
|
|
|
if (j == 3 || j == 5 || j == 7 || j == 9) {
|
|
path.Buffer[i] = '-';
|
|
i++;
|
|
}
|
|
}
|
|
|
|
kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR));
|
|
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
|
if (!kvfi) {
|
|
ERR("out of memory\n");
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto end;
|
|
}
|
|
|
|
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
Status = ZwOpenKey(&h, KEY_QUERY_VALUE, &oa);
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
Status = STATUS_SUCCESS;
|
|
goto end;
|
|
} else if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwOpenKey returned %08lx\n", Status);
|
|
goto end;
|
|
}
|
|
|
|
index = 0;
|
|
|
|
RtlInitUnicodeString(&ignoreus, L"Ignore");
|
|
RtlInitUnicodeString(&compressus, L"Compress");
|
|
RtlInitUnicodeString(&compressforceus, L"CompressForce");
|
|
RtlInitUnicodeString(&compresstypeus, L"CompressType");
|
|
RtlInitUnicodeString(&readonlyus, L"Readonly");
|
|
RtlInitUnicodeString(&zliblevelus, L"ZlibLevel");
|
|
RtlInitUnicodeString(&flushintervalus, L"FlushInterval");
|
|
RtlInitUnicodeString(&maxinlineus, L"MaxInline");
|
|
RtlInitUnicodeString(&subvolidus, L"SubvolId");
|
|
RtlInitUnicodeString(&skipbalanceus, L"SkipBalance");
|
|
RtlInitUnicodeString(&nobarrierus, L"NoBarrier");
|
|
RtlInitUnicodeString(¬rimus, L"NoTrim");
|
|
RtlInitUnicodeString(&clearcacheus, L"ClearCache");
|
|
RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded");
|
|
RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel");
|
|
RtlInitUnicodeString(&norootdirus, L"NoRootDir");
|
|
|
|
do {
|
|
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
|
|
|
|
index++;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
UNICODE_STRING us;
|
|
|
|
us.Length = us.MaximumLength = (USHORT)kvfi->NameLength;
|
|
us.Buffer = kvfi->Name;
|
|
|
|
if (FsRtlAreNamesEqual(&ignoreus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->ignore = *val != 0 ? true : false;
|
|
} else if (FsRtlAreNamesEqual(&compressus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->compress = *val != 0 ? true : false;
|
|
} else if (FsRtlAreNamesEqual(&compressforceus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->compress_force = *val != 0 ? true : false;
|
|
} else if (FsRtlAreNamesEqual(&compresstypeus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->compress_type = (uint8_t)(*val > BTRFS_COMPRESSION_ZSTD ? 0 : *val);
|
|
} else if (FsRtlAreNamesEqual(&readonlyus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->readonly = *val != 0 ? true : false;
|
|
} else if (FsRtlAreNamesEqual(&zliblevelus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->zlib_level = *val;
|
|
} else if (FsRtlAreNamesEqual(&flushintervalus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->flush_interval = *val;
|
|
} else if (FsRtlAreNamesEqual(&maxinlineus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->max_inline = min(*val, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
|
|
} else if (FsRtlAreNamesEqual(&subvolidus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_QWORD) {
|
|
uint64_t* val = (uint64_t*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->subvol_id = *val;
|
|
} else if (FsRtlAreNamesEqual(&skipbalanceus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->skip_balance = *val;
|
|
} else if (FsRtlAreNamesEqual(&nobarrierus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->no_barrier = *val;
|
|
} else if (FsRtlAreNamesEqual(¬rimus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->no_trim = *val;
|
|
} else if (FsRtlAreNamesEqual(&clearcacheus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->clear_cache = *val;
|
|
} else if (FsRtlAreNamesEqual(&allowdegradedus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->allow_degraded = *val;
|
|
} else if (FsRtlAreNamesEqual(&zstdlevelus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->zstd_level = *val;
|
|
} else if (FsRtlAreNamesEqual(&norootdirus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
|
|
|
|
options->no_root_dir = *val;
|
|
}
|
|
} else if (Status != STATUS_NO_MORE_ENTRIES) {
|
|
ERR("ZwEnumerateValueKey returned %08lx\n", Status);
|
|
goto end2;
|
|
}
|
|
} while (NT_SUCCESS(Status));
|
|
|
|
if (!options->compress && options->compress_force)
|
|
options->compress = true;
|
|
|
|
if (options->zlib_level > 9)
|
|
options->zlib_level = 9;
|
|
|
|
if (options->zstd_level > (uint32_t)ZSTD_maxCLevel())
|
|
options->zstd_level = ZSTD_maxCLevel();
|
|
|
|
if (options->flush_interval == 0)
|
|
options->flush_interval = mount_flush_interval;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
end2:
|
|
ZwClose(h);
|
|
|
|
end:
|
|
ExFreePool(path.Buffer);
|
|
|
|
if (kvfi)
|
|
ExFreePool(kvfi);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid) {
|
|
UNICODE_STRING path, mountedus;
|
|
ULONG i, j;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES oa;
|
|
HANDLE h;
|
|
DWORD data;
|
|
|
|
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
|
|
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
|
|
|
if (!path.Buffer) {
|
|
ERR("out of memory\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
|
|
i = registry_path.Length / sizeof(WCHAR);
|
|
|
|
path.Buffer[i] = '\\';
|
|
i++;
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
|
|
path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
|
|
|
|
i += 2;
|
|
|
|
if (j == 3 || j == 5 || j == 7 || j == 9) {
|
|
path.Buffer[i] = '-';
|
|
i++;
|
|
}
|
|
}
|
|
|
|
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
Status = ZwCreateKey(&h, KEY_SET_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwCreateKey returned %08lx\n", Status);
|
|
goto end;
|
|
}
|
|
|
|
mountedus.Buffer = (WCHAR*)option_mounted;
|
|
mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
|
|
|
|
data = 1;
|
|
|
|
Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwSetValueKey returned %08lx\n", Status);
|
|
goto end2;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
end2:
|
|
ZwClose(h);
|
|
|
|
end:
|
|
ExFreePool(path.Buffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS registry_mark_volume_unmounted_path(PUNICODE_STRING path) {
|
|
HANDLE h;
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS Status;
|
|
ULONG index, kvbilen = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen;
|
|
KEY_VALUE_BASIC_INFORMATION* kvbi;
|
|
bool has_options = false;
|
|
UNICODE_STRING mountedus;
|
|
|
|
// If a volume key has any options in it, we set Mounted to 0 and return. Otherwise,
|
|
// we delete the whole thing.
|
|
|
|
kvbi = ExAllocatePoolWithTag(PagedPool, kvbilen, ALLOC_TAG);
|
|
if (!kvbi) {
|
|
ERR("out of memory\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
InitializeObjectAttributes(&oa, path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
Status = ZwOpenKey(&h, KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE, &oa);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwOpenKey returned %08lx\n", Status);
|
|
goto end;
|
|
}
|
|
|
|
index = 0;
|
|
|
|
mountedus.Buffer = (WCHAR*)option_mounted;
|
|
mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
|
|
|
|
do {
|
|
Status = ZwEnumerateValueKey(h, index, KeyValueBasicInformation, kvbi, kvbilen, &retlen);
|
|
|
|
index++;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
UNICODE_STRING us;
|
|
|
|
us.Length = us.MaximumLength = (USHORT)kvbi->NameLength;
|
|
us.Buffer = kvbi->Name;
|
|
|
|
if (!FsRtlAreNamesEqual(&mountedus, &us, true, NULL)) {
|
|
has_options = true;
|
|
break;
|
|
}
|
|
} else if (Status != STATUS_NO_MORE_ENTRIES) {
|
|
ERR("ZwEnumerateValueKey returned %08lx\n", Status);
|
|
goto end2;
|
|
}
|
|
} while (NT_SUCCESS(Status));
|
|
|
|
if (has_options) {
|
|
DWORD data = 0;
|
|
|
|
Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwSetValueKey returned %08lx\n", Status);
|
|
goto end2;
|
|
}
|
|
} else {
|
|
Status = ZwDeleteKey(h);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwDeleteKey returned %08lx\n", Status);
|
|
goto end2;
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
end2:
|
|
ZwClose(h);
|
|
|
|
end:
|
|
ExFreePool(kvbi);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID* uuid) {
|
|
UNICODE_STRING path;
|
|
NTSTATUS Status;
|
|
ULONG i, j;
|
|
|
|
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
|
|
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
|
|
|
if (!path.Buffer) {
|
|
ERR("out of memory\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
|
|
i = registry_path.Length / sizeof(WCHAR);
|
|
|
|
path.Buffer[i] = '\\';
|
|
i++;
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
|
|
path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
|
|
|
|
i += 2;
|
|
|
|
if (j == 3 || j == 5 || j == 7 || j == 9) {
|
|
path.Buffer[i] = '-';
|
|
i++;
|
|
}
|
|
}
|
|
|
|
Status = registry_mark_volume_unmounted_path(&path);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("registry_mark_volume_unmounted_path returned %08lx\n", Status);
|
|
goto end;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
end:
|
|
ExFreePool(path.Buffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
#define is_hex(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
|
|
|
|
static bool is_uuid(ULONG namelen, WCHAR* name) {
|
|
ULONG i;
|
|
|
|
if (namelen != 36 * sizeof(WCHAR))
|
|
return false;
|
|
|
|
for (i = 0; i < 36; i++) {
|
|
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
|
if (name[i] != '-')
|
|
return false;
|
|
} else if (!is_hex(name[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
typedef struct {
|
|
UNICODE_STRING name;
|
|
LIST_ENTRY list_entry;
|
|
} key_name;
|
|
|
|
static void reset_subkeys(HANDLE h, PUNICODE_STRING reg_path) {
|
|
NTSTATUS Status;
|
|
KEY_BASIC_INFORMATION* kbi;
|
|
ULONG kbilen = sizeof(KEY_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen, index = 0;
|
|
LIST_ENTRY key_names, *le;
|
|
|
|
InitializeListHead(&key_names);
|
|
|
|
kbi = ExAllocatePoolWithTag(PagedPool, kbilen, ALLOC_TAG);
|
|
if (!kbi) {
|
|
ERR("out of memory\n");
|
|
return;
|
|
}
|
|
|
|
do {
|
|
Status = ZwEnumerateKey(h, index, KeyBasicInformation, kbi, kbilen, &retlen);
|
|
|
|
index++;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
key_name* kn;
|
|
|
|
TRACE("key: %.*S\n", (int)(kbi->NameLength / sizeof(WCHAR)), kbi->Name);
|
|
|
|
if (is_uuid(kbi->NameLength, kbi->Name)) {
|
|
kn = ExAllocatePoolWithTag(PagedPool, sizeof(key_name), ALLOC_TAG);
|
|
if (!kn) {
|
|
ERR("out of memory\n");
|
|
goto end;
|
|
}
|
|
|
|
kn->name.Length = kn->name.MaximumLength = (USHORT)min(0xffff, kbi->NameLength);
|
|
kn->name.Buffer = ExAllocatePoolWithTag(PagedPool, kn->name.MaximumLength, ALLOC_TAG);
|
|
|
|
if (!kn->name.Buffer) {
|
|
ERR("out of memory\n");
|
|
ExFreePool(kn);
|
|
goto end;
|
|
}
|
|
|
|
RtlCopyMemory(kn->name.Buffer, kbi->Name, kn->name.Length);
|
|
|
|
InsertTailList(&key_names, &kn->list_entry);
|
|
}
|
|
} else if (Status != STATUS_NO_MORE_ENTRIES)
|
|
ERR("ZwEnumerateKey returned %08lx\n", Status);
|
|
} while (NT_SUCCESS(Status));
|
|
|
|
le = key_names.Flink;
|
|
while (le != &key_names) {
|
|
key_name* kn = CONTAINING_RECORD(le, key_name, list_entry);
|
|
UNICODE_STRING path;
|
|
|
|
path.Length = path.MaximumLength = reg_path->Length + sizeof(WCHAR) + kn->name.Length;
|
|
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
|
|
|
if (!path.Buffer) {
|
|
ERR("out of memory\n");
|
|
goto end;
|
|
}
|
|
|
|
RtlCopyMemory(path.Buffer, reg_path->Buffer, reg_path->Length);
|
|
path.Buffer[reg_path->Length / sizeof(WCHAR)] = '\\';
|
|
RtlCopyMemory(&path.Buffer[(reg_path->Length / sizeof(WCHAR)) + 1], kn->name.Buffer, kn->name.Length);
|
|
|
|
Status = registry_mark_volume_unmounted_path(&path);
|
|
if (!NT_SUCCESS(Status))
|
|
WARN("registry_mark_volume_unmounted_path returned %08lx\n", Status);
|
|
|
|
ExFreePool(path.Buffer);
|
|
|
|
le = le->Flink;
|
|
}
|
|
|
|
end:
|
|
while (!IsListEmpty(&key_names)) {
|
|
key_name* kn;
|
|
|
|
le = RemoveHeadList(&key_names);
|
|
kn = CONTAINING_RECORD(le, key_name, list_entry);
|
|
|
|
if (kn->name.Buffer)
|
|
ExFreePool(kn->name.Buffer);
|
|
|
|
ExFreePool(kn);
|
|
}
|
|
|
|
ExFreePool(kbi);
|
|
}
|
|
|
|
static void read_mappings(PUNICODE_STRING regpath) {
|
|
WCHAR* path;
|
|
UNICODE_STRING us;
|
|
HANDLE h;
|
|
OBJECT_ATTRIBUTES oa;
|
|
ULONG dispos;
|
|
NTSTATUS Status;
|
|
|
|
static const WCHAR mappings[] = L"\\Mappings";
|
|
|
|
while (!IsListEmpty(&uid_map_list)) {
|
|
uid_map* um = CONTAINING_RECORD(RemoveHeadList(&uid_map_list), uid_map, listentry);
|
|
|
|
if (um->sid) ExFreePool(um->sid);
|
|
ExFreePool(um);
|
|
}
|
|
|
|
path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) - sizeof(WCHAR), ALLOC_TAG);
|
|
if (!path) {
|
|
ERR("out of memory\n");
|
|
return;
|
|
}
|
|
|
|
RtlCopyMemory(path, regpath->Buffer, regpath->Length);
|
|
RtlCopyMemory((uint8_t*)path + regpath->Length, mappings, sizeof(mappings) - sizeof(WCHAR));
|
|
|
|
us.Buffer = path;
|
|
us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) - sizeof(WCHAR);
|
|
|
|
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwCreateKey returned %08lx\n", Status);
|
|
ExFreePool(path);
|
|
return;
|
|
}
|
|
|
|
if (dispos == REG_OPENED_EXISTING_KEY) {
|
|
KEY_VALUE_FULL_INFORMATION* kvfi;
|
|
ULONG kvfilen, retlen, i;
|
|
|
|
kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
|
|
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
|
|
|
if (!kvfi) {
|
|
ERR("out of memory\n");
|
|
ExFreePool(path);
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
i = 0;
|
|
do {
|
|
Status = ZwEnumerateValueKey(h, i, KeyValueFullInformation, kvfi, kvfilen, &retlen);
|
|
|
|
if (NT_SUCCESS(Status) && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
uint32_t val = 0;
|
|
|
|
RtlCopyMemory(&val, (uint8_t*)kvfi + kvfi->DataOffset, min(kvfi->DataLength, sizeof(uint32_t)));
|
|
|
|
TRACE("entry %lu = %.*S = %u\n", i, (int)(kvfi->NameLength / sizeof(WCHAR)), kvfi->Name, val);
|
|
|
|
add_user_mapping(kvfi->Name, kvfi->NameLength / sizeof(WCHAR), val);
|
|
}
|
|
|
|
i = i + 1;
|
|
} while (Status != STATUS_NO_MORE_ENTRIES);
|
|
|
|
ExFreePool(kvfi);
|
|
}
|
|
|
|
ZwClose(h);
|
|
|
|
ExFreePool(path);
|
|
}
|
|
|
|
static void read_group_mappings(PUNICODE_STRING regpath) {
|
|
WCHAR* path;
|
|
UNICODE_STRING us;
|
|
HANDLE h;
|
|
OBJECT_ATTRIBUTES oa;
|
|
ULONG dispos;
|
|
NTSTATUS Status;
|
|
|
|
static const WCHAR mappings[] = L"\\GroupMappings";
|
|
|
|
while (!IsListEmpty(&gid_map_list)) {
|
|
gid_map* gm = CONTAINING_RECORD(RemoveHeadList(&gid_map_list), gid_map, listentry);
|
|
|
|
if (gm->sid) ExFreePool(gm->sid);
|
|
ExFreePool(gm);
|
|
}
|
|
|
|
path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) - sizeof(WCHAR), ALLOC_TAG);
|
|
if (!path) {
|
|
ERR("out of memory\n");
|
|
return;
|
|
}
|
|
|
|
RtlCopyMemory(path, regpath->Buffer, regpath->Length);
|
|
RtlCopyMemory((uint8_t*)path + regpath->Length, mappings, sizeof(mappings) - sizeof(WCHAR));
|
|
|
|
us.Buffer = path;
|
|
us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) - sizeof(WCHAR);
|
|
|
|
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwCreateKey returned %08lx\n", Status);
|
|
ExFreePool(path);
|
|
return;
|
|
}
|
|
|
|
ExFreePool(path);
|
|
|
|
if (dispos == REG_OPENED_EXISTING_KEY) {
|
|
KEY_VALUE_FULL_INFORMATION* kvfi;
|
|
ULONG kvfilen, retlen, i;
|
|
|
|
kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
|
|
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
|
|
|
if (!kvfi) {
|
|
ERR("out of memory\n");
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
i = 0;
|
|
do {
|
|
Status = ZwEnumerateValueKey(h, i, KeyValueFullInformation, kvfi, kvfilen, &retlen);
|
|
|
|
if (NT_SUCCESS(Status) && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
|
uint32_t val = 0;
|
|
|
|
RtlCopyMemory(&val, (uint8_t*)kvfi + kvfi->DataOffset, min(kvfi->DataLength, sizeof(uint32_t)));
|
|
|
|
TRACE("entry %lu = %.*S = %u\n", i, (int)(kvfi->NameLength / sizeof(WCHAR)), kvfi->Name, val);
|
|
|
|
add_group_mapping(kvfi->Name, kvfi->NameLength / sizeof(WCHAR), val);
|
|
}
|
|
|
|
i = i + 1;
|
|
} while (Status != STATUS_NO_MORE_ENTRIES);
|
|
|
|
ExFreePool(kvfi);
|
|
} else if (dispos == REG_CREATED_NEW_KEY) {
|
|
static const WCHAR builtin_users[] = L"S-1-5-32-545";
|
|
|
|
UNICODE_STRING us2;
|
|
DWORD val;
|
|
|
|
// If we're creating the key for the first time, we add a default mapping of
|
|
// BUILTIN\Users to gid 100, which ought to correspond to the "users" group on Linux.
|
|
|
|
us2.Length = us2.MaximumLength = sizeof(builtin_users) - sizeof(WCHAR);
|
|
us2.Buffer = ExAllocatePoolWithTag(PagedPool, us2.MaximumLength, ALLOC_TAG);
|
|
|
|
if (us2.Buffer) {
|
|
RtlCopyMemory(us2.Buffer, builtin_users, us2.Length);
|
|
|
|
val = 100;
|
|
Status = ZwSetValueKey(h, &us2, 0, REG_DWORD, &val, sizeof(DWORD));
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwSetValueKey returned %08lx\n", Status);
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
add_group_mapping(us2.Buffer, us2.Length / sizeof(WCHAR), val);
|
|
|
|
ExFreePool(us2.Buffer);
|
|
}
|
|
}
|
|
|
|
ZwClose(h);
|
|
}
|
|
|
|
static void get_registry_value(HANDLE h, WCHAR* string, ULONG type, void* val, ULONG size) {
|
|
ULONG kvfilen;
|
|
KEY_VALUE_FULL_INFORMATION* kvfi;
|
|
UNICODE_STRING us;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&us, string);
|
|
|
|
kvfi = NULL;
|
|
kvfilen = 0;
|
|
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
|
|
|
if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
|
|
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
|
|
|
if (!kvfi) {
|
|
ERR("out of memory\n");
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (kvfi->Type == type && kvfi->DataLength >= size) {
|
|
RtlCopyMemory(val, ((uint8_t*)kvfi) + kvfi->DataOffset, size);
|
|
} else {
|
|
Status = ZwDeleteValueKey(h, &us);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwDeleteValueKey returned %08lx\n", Status);
|
|
}
|
|
|
|
Status = ZwSetValueKey(h, &us, 0, type, val, size);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwSetValueKey returned %08lx\n", Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
ExFreePool(kvfi);
|
|
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
Status = ZwSetValueKey(h, &us, 0, type, val, size);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwSetValueKey returned %08lx\n", Status);
|
|
}
|
|
} else {
|
|
ERR("ZwQueryValueKey returned %08lx\n", Status);
|
|
}
|
|
}
|
|
|
|
void read_registry(PUNICODE_STRING regpath, bool refresh) {
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS Status;
|
|
HANDLE h;
|
|
ULONG dispos;
|
|
#ifdef _DEBUG
|
|
KEY_VALUE_FULL_INFORMATION* kvfi;
|
|
ULONG kvfilen, old_debug_log_level = debug_log_level;
|
|
UNICODE_STRING us, old_log_file, old_log_device;
|
|
|
|
static const WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
|
|
#endif
|
|
|
|
ExAcquireResourceExclusiveLite(&mapping_lock, true);
|
|
|
|
read_mappings(regpath);
|
|
read_group_mappings(regpath);
|
|
|
|
ExReleaseResourceLite(&mapping_lock);
|
|
|
|
InitializeObjectAttributes(&oa, regpath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
Status = ZwCreateKey(&h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwCreateKey returned %08lx\n", Status);
|
|
return;
|
|
}
|
|
|
|
if (!refresh)
|
|
reset_subkeys(h, regpath);
|
|
|
|
get_registry_value(h, L"Compress", REG_DWORD, &mount_compress, sizeof(mount_compress));
|
|
get_registry_value(h, L"CompressForce", REG_DWORD, &mount_compress_force, sizeof(mount_compress_force));
|
|
get_registry_value(h, L"CompressType", REG_DWORD, &mount_compress_type, sizeof(mount_compress_type));
|
|
get_registry_value(h, L"ZlibLevel", REG_DWORD, &mount_zlib_level, sizeof(mount_zlib_level));
|
|
get_registry_value(h, L"FlushInterval", REG_DWORD, &mount_flush_interval, sizeof(mount_flush_interval));
|
|
get_registry_value(h, L"MaxInline", REG_DWORD, &mount_max_inline, sizeof(mount_max_inline));
|
|
get_registry_value(h, L"SkipBalance", REG_DWORD, &mount_skip_balance, sizeof(mount_skip_balance));
|
|
get_registry_value(h, L"NoBarrier", REG_DWORD, &mount_no_barrier, sizeof(mount_no_barrier));
|
|
get_registry_value(h, L"NoTrim", REG_DWORD, &mount_no_trim, sizeof(mount_no_trim));
|
|
get_registry_value(h, L"ClearCache", REG_DWORD, &mount_clear_cache, sizeof(mount_clear_cache));
|
|
get_registry_value(h, L"AllowDegraded", REG_DWORD, &mount_allow_degraded, sizeof(mount_allow_degraded));
|
|
get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly, sizeof(mount_readonly));
|
|
get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level, sizeof(mount_zstd_level));
|
|
get_registry_value(h, L"NoRootDir", REG_DWORD, &mount_no_root_dir, sizeof(mount_no_root_dir));
|
|
|
|
if (!refresh)
|
|
get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp));
|
|
|
|
if (mount_flush_interval == 0)
|
|
mount_flush_interval = 1;
|
|
|
|
#ifdef _DEBUG
|
|
get_registry_value(h, L"DebugLogLevel", REG_DWORD, &debug_log_level, sizeof(debug_log_level));
|
|
|
|
RtlInitUnicodeString(&us, L"LogDevice");
|
|
|
|
kvfi = NULL;
|
|
kvfilen = 0;
|
|
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
|
|
|
old_log_device = log_device;
|
|
|
|
log_device.Length = log_device.MaximumLength = 0;
|
|
log_device.Buffer = NULL;
|
|
|
|
if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
|
|
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
|
|
|
if (!kvfi) {
|
|
ERR("out of memory\n");
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
|
|
log_device.Length = log_device.MaximumLength = (USHORT)min(0xffff, kvfi->DataLength);
|
|
log_device.Buffer = ExAllocatePoolWithTag(PagedPool, log_device.MaximumLength, ALLOC_TAG);
|
|
|
|
if (!log_device.Buffer) {
|
|
ERR("out of memory\n");
|
|
ExFreePool(kvfi);
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
RtlCopyMemory(log_device.Buffer, ((uint8_t*)kvfi) + kvfi->DataOffset, log_device.Length);
|
|
|
|
if (log_device.Buffer[(log_device.Length / sizeof(WCHAR)) - 1] == 0)
|
|
log_device.Length -= sizeof(WCHAR);
|
|
} else {
|
|
ERR("LogDevice was type %lu, length %lu\n", kvfi->Type, kvfi->DataLength);
|
|
|
|
Status = ZwDeleteValueKey(h, &us);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ERR("ZwDeleteValueKey returned %08lx\n", Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
ExFreePool(kvfi);
|
|
} else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
ERR("ZwQueryValueKey returned %08lx\n", Status);
|
|
}
|
|
|
|
ExAcquireResourceExclusiveLite(&log_lock, true);
|
|
|
|
if (refresh && (log_device.Length != old_log_device.Length || RtlCompareMemory(log_device.Buffer, old_log_device.Buffer, log_device.Length) != log_device.Length ||
|
|
(!comfo && log_device.Length > 0) || (old_debug_log_level == 0 && debug_log_level > 0) || (old_debug_log_level > 0 && debug_log_level == 0))) {
|
|
if (comfo)
|
|
ObDereferenceObject(comfo);
|
|
|
|
if (log_handle) {
|
|
ZwClose(log_handle);
|
|
log_handle = NULL;
|
|
}
|
|
|
|
comfo = NULL;
|
|
comdo = NULL;
|
|
|
|
if (log_device.Length > 0 && debug_log_level > 0) {
|
|
Status = IoGetDeviceObjectPointer(&log_device, FILE_WRITE_DATA, &comfo, &comdo);
|
|
if (!NT_SUCCESS(Status))
|
|
DbgPrint("IoGetDeviceObjectPointer returned %08lx\n", Status);
|
|
}
|
|
}
|
|
|
|
ExReleaseResourceLite(&log_lock);
|
|
|
|
if (old_log_device.Buffer)
|
|
ExFreePool(old_log_device.Buffer);
|
|
|
|
RtlInitUnicodeString(&us, L"LogFile");
|
|
|
|
kvfi = NULL;
|
|
kvfilen = 0;
|
|
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
|
|
|
old_log_file = log_file;
|
|
|
|
if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
|
|
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
|
|
|
if (!kvfi) {
|
|
ERR("out of memory\n");
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
|
|
log_file.Length = log_file.MaximumLength = (USHORT)min(0xffff, kvfi->DataLength);
|
|
log_file.Buffer = ExAllocatePoolWithTag(PagedPool, log_file.MaximumLength, ALLOC_TAG);
|
|
|
|
if (!log_file.Buffer) {
|
|
ERR("out of memory\n");
|
|
ExFreePool(kvfi);
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
RtlCopyMemory(log_file.Buffer, ((uint8_t*)kvfi) + kvfi->DataOffset, log_file.Length);
|
|
|
|
if (log_file.Buffer[(log_file.Length / sizeof(WCHAR)) - 1] == 0)
|
|
log_file.Length -= sizeof(WCHAR);
|
|
} else {
|
|
ERR("LogFile was type %lu, length %lu\n", kvfi->Type, kvfi->DataLength);
|
|
|
|
Status = ZwDeleteValueKey(h, &us);
|
|
if (!NT_SUCCESS(Status))
|
|
ERR("ZwDeleteValueKey returned %08lx\n", Status);
|
|
|
|
log_file.Length = 0;
|
|
}
|
|
} else {
|
|
ERR("ZwQueryValueKey returned %08lx\n", Status);
|
|
log_file.Length = 0;
|
|
}
|
|
|
|
ExFreePool(kvfi);
|
|
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
Status = ZwSetValueKey(h, &us, 0, REG_SZ, (void*)def_log_file, sizeof(def_log_file));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
ERR("ZwSetValueKey returned %08lx\n", Status);
|
|
|
|
log_file.Length = 0;
|
|
} else {
|
|
ERR("ZwQueryValueKey returned %08lx\n", Status);
|
|
log_file.Length = 0;
|
|
}
|
|
|
|
if (log_file.Length == 0) {
|
|
log_file.Length = log_file.MaximumLength = sizeof(def_log_file) - sizeof(WCHAR);
|
|
log_file.Buffer = ExAllocatePoolWithTag(PagedPool, log_file.MaximumLength, ALLOC_TAG);
|
|
|
|
if (!log_file.Buffer) {
|
|
ERR("out of memory\n");
|
|
ZwClose(h);
|
|
return;
|
|
}
|
|
|
|
RtlCopyMemory(log_file.Buffer, def_log_file, log_file.Length);
|
|
}
|
|
|
|
ExAcquireResourceExclusiveLite(&log_lock, true);
|
|
|
|
if (refresh && (log_file.Length != old_log_file.Length || RtlCompareMemory(log_file.Buffer, old_log_file.Buffer, log_file.Length) != log_file.Length ||
|
|
(!log_handle && log_file.Length > 0) || (old_debug_log_level == 0 && debug_log_level > 0) || (old_debug_log_level > 0 && debug_log_level == 0))) {
|
|
if (log_handle) {
|
|
ZwClose(log_handle);
|
|
log_handle = NULL;
|
|
}
|
|
|
|
if (!comfo && log_file.Length > 0 && refresh && debug_log_level > 0) {
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
InitializeObjectAttributes(&oa, &log_file, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
Status = ZwCreateFile(&log_handle, FILE_WRITE_DATA, &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
|
|
FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_ALERT, NULL, 0);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("ZwCreateFile returned %08lx\n", Status);
|
|
log_handle = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
ExReleaseResourceLite(&log_lock);
|
|
|
|
if (old_log_file.Buffer)
|
|
ExFreePool(old_log_file.Buffer);
|
|
#endif
|
|
|
|
ZwClose(h);
|
|
}
|
|
|
|
_Function_class_(WORKER_THREAD_ROUTINE)
|
|
static void __stdcall registry_work_item(PVOID Parameter) {
|
|
NTSTATUS Status;
|
|
HANDLE regh = (HANDLE)Parameter;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
TRACE("registry changed\n");
|
|
|
|
read_registry(®istry_path, true);
|
|
|
|
Status = ZwNotifyChangeKey(regh, NULL, (PVOID)&wqi, (PVOID)DelayedWorkQueue, &iosb, REG_NOTIFY_CHANGE_LAST_SET, true, NULL, 0, true);
|
|
if (!NT_SUCCESS(Status))
|
|
ERR("ZwNotifyChangeKey returned %08lx\n", Status);
|
|
}
|
|
|
|
void watch_registry(HANDLE regh) {
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
ExInitializeWorkItem(&wqi, registry_work_item, regh);
|
|
|
|
Status = ZwNotifyChangeKey(regh, NULL, (PVOID)&wqi, (PVOID)DelayedWorkQueue, &iosb, REG_NOTIFY_CHANGE_LAST_SET, true, NULL, 0, true);
|
|
if (!NT_SUCCESS(Status))
|
|
ERR("ZwNotifyChangeKey returned %08lx\n", Status);
|
|
}
|