ReactOS  0.4.15-dev-4914-g2220e56
boot.c
Go to the documentation of this file.
1 /* Copyright (c) Mark Harmstone 2019
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 #ifndef __REACTOS__
21 #ifdef _MSC_VER
22 #include <ntstrsafe.h>
23 #endif
24 #else
25 #include <ntstrsafe.h>
26 #endif
27 
29 extern LIST_ENTRY pdo_list;
30 extern ERESOURCE boot_lock;
31 extern PDRIVER_OBJECT drvobj;
32 
33 BTRFS_UUID boot_uuid; // initialized to 0
35 
36 // Not in any headers? Windbg knows about it though.
37 #define DOE_START_PENDING 0x10
38 
39 // Just as much as we need - the version in mingw is truncated still further
40 typedef struct {
45  void* Dope;
48 
49 static bool get_system_root() {
51  HANDLE h;
53  OBJECT_ATTRIBUTES objatt;
54  ULONG retlen = 0;
55  bool second_time = false;
56 
57  static const WCHAR system_root[] = L"\\SystemRoot";
58  static const WCHAR boot_device[] = L"\\Device\\BootDevice";
59  static const WCHAR arc_btrfs_prefix[] = L"\\ArcName\\btrfs(";
60 
61  us.Buffer = (WCHAR*)system_root;
62  us.Length = us.MaximumLength = sizeof(system_root) - sizeof(WCHAR);
63 
65 
66  while (true) {
68  if (!NT_SUCCESS(Status)) {
69  ERR("ZwOpenSymbolicLinkObject returned %08lx\n", Status);
70  return false;
71  }
72 
73  target.Length = target.MaximumLength = 0;
74 
75  Status = ZwQuerySymbolicLinkObject(h, &target, &retlen);
77  ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
78  NtClose(h);
79  return false;
80  }
81 
82  if (retlen == 0) {
83  NtClose(h);
84  return false;
85  }
86 
88  if (!target.Buffer) {
89  ERR("out of memory\n");
90  NtClose(h);
91  return false;
92  }
93 
94  target.Length = target.MaximumLength = (USHORT)retlen;
95 
96  Status = ZwQuerySymbolicLinkObject(h, &target, NULL);
97  if (!NT_SUCCESS(Status)) {
98  ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
99  NtClose(h);
100  ExFreePool(target.Buffer);
101  return false;
102  }
103 
104  NtClose(h);
105 
106  if (second_time) {
107  TRACE("boot device is %.*S\n", (int)(target.Length / sizeof(WCHAR)), target.Buffer);
108  } else {
109  TRACE("system root is %.*S\n", (int)(target.Length / sizeof(WCHAR)), target.Buffer);
110  }
111 
112  if (!second_time && target.Length >= sizeof(boot_device) - sizeof(WCHAR) &&
113  RtlCompareMemory(target.Buffer, boot_device, sizeof(boot_device) - sizeof(WCHAR)) == sizeof(boot_device) - sizeof(WCHAR)) {
114  ExFreePool(target.Buffer);
115 
116  us.Buffer = (WCHAR*)boot_device;
117  us.Length = us.MaximumLength = sizeof(boot_device) - sizeof(WCHAR);
118 
119  second_time = true;
120  } else
121  break;
122  }
123 
124  if (target.Length >= sizeof(arc_btrfs_prefix) - sizeof(WCHAR) &&
125  RtlCompareMemory(target.Buffer, arc_btrfs_prefix, sizeof(arc_btrfs_prefix) - sizeof(WCHAR)) == sizeof(arc_btrfs_prefix) - sizeof(WCHAR)) {
126  WCHAR* s = &target.Buffer[(sizeof(arc_btrfs_prefix) / sizeof(WCHAR)) - 1];
127 
128  for (unsigned int i = 0; i < 16; i++) {
129  if (*s >= '0' && *s <= '9')
130  boot_uuid.uuid[i] = (*s - '0') << 4;
131  else if (*s >= 'a' && *s <= 'f')
132  boot_uuid.uuid[i] = (*s - 'a' + 0xa) << 4;
133  else if (*s >= 'A' && *s <= 'F')
134  boot_uuid.uuid[i] = (*s - 'A' + 0xa) << 4;
135  else {
136  ExFreePool(target.Buffer);
137  return false;
138  }
139 
140  s++;
141 
142  if (*s >= '0' && *s <= '9')
143  boot_uuid.uuid[i] |= *s - '0';
144  else if (*s >= 'a' && *s <= 'f')
145  boot_uuid.uuid[i] |= *s - 'a' + 0xa;
146  else if (*s >= 'A' && *s <= 'F')
147  boot_uuid.uuid[i] |= *s - 'A' + 0xa;
148  else {
149  ExFreePool(target.Buffer);
150  return false;
151  }
152 
153  s++;
154 
155  if (i == 3 || i == 5 || i == 7 || i == 9) {
156  if (*s != '-') {
157  ExFreePool(target.Buffer);
158  return false;
159  }
160 
161  s++;
162  }
163  }
164 
165  if (*s != ')') {
166  ExFreePool(target.Buffer);
167  return false;
168  }
169 
170  ExFreePool(target.Buffer);
171 
172  return true;
173  }
174 
175  ExFreePool(target.Buffer);
176 
177  return false;
178 }
179 
181  UNICODE_STRING mmdevpath;
185  ULONG mmtnlen;
186  MOUNTMGR_TARGET_NAME* mmtn;
187  WCHAR* w;
188 
191  if (!NT_SUCCESS(Status)) {
192  ERR("IoGetDeviceObjectPointer returned %08lx\n", Status);
193  return;
194  }
195 
196  mmtnlen = offsetof(MOUNTMGR_TARGET_NAME, DeviceName[0]) + sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
197 
198  mmtn = ExAllocatePoolWithTag(NonPagedPool, mmtnlen, ALLOC_TAG);
199  if (!mmtn) {
200  ERR("out of memory\n");
201  return;
202  }
203 
204  mmtn->DeviceNameLength = sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
205 
207 
208  w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
209 
210  for (unsigned int i = 0; i < 16; i++) {
211  *w = hex_digit(uuid->uuid[i] >> 4); w++;
212  *w = hex_digit(uuid->uuid[i] & 0xf); w++;
213 
214  if (i == 3 || i == 5 || i == 7 || i == 9) {
215  *w = L'-';
216  w++;
217  }
218  }
219 
220  *w = L'}';
221 
223  if (!NT_SUCCESS(Status)) {
224  ERR("IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION returned %08lx\n", Status);
225  ExFreePool(mmtn);
226  return;
227  }
228 
229  ExFreePool(mmtn);
230 }
231 
232 static void check_boot_options() {
234  WCHAR* s;
235 
236  static const WCHAR pathw[] = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control";
237  static const WCHAR namew[] = L"SystemStartOptions";
238  static const WCHAR subvol[] = L"SUBVOL=";
239 
240  _SEH2_TRY {
241  HANDLE control;
244  ULONG kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR));
247  WCHAR* options;
248 
249  path.Buffer = (WCHAR*)pathw;
250  path.Length = path.MaximumLength = sizeof(pathw) - sizeof(WCHAR);
251 
253 
254  Status = ZwOpenKey(&control, KEY_QUERY_VALUE, &oa);
255  if (!NT_SUCCESS(Status)) {
256  ERR("ZwOpenKey returned %08lx\n", Status);
257  return;
258  }
259 
260  // FIXME - don't fail if value too long (can we query for the length?)
261 
262  kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
263  if (!kvfi) {
264  ERR("out of memory\n");
265  NtClose(control);
266  return;
267  }
268 
269  name.Buffer = (WCHAR*)namew;
270  name.Length = name.MaximumLength = sizeof(namew) - sizeof(WCHAR);
271 
272  Status = ZwQueryValueKey(control, &name, KeyValueFullInformation, kvfi,
273  kvfilen, &kvfilen);
274  if (!NT_SUCCESS(Status)) {
275  ERR("ZwQueryValueKey returned %08lx\n", Status);
276  NtClose(control);
277  return;
278  }
279 
280  NtClose(control);
281 
282  options = (WCHAR*)((uint8_t*)kvfi + kvfi->DataOffset);
283  options[kvfi->DataLength / sizeof(WCHAR)] = 0; // FIXME - make sure buffer long enough to allow this
284 
285  s = wcsstr(options, subvol);
286 
287  if (!s)
288  return;
289 
290  s += (sizeof(subvol) / sizeof(WCHAR)) - 1;
291 
292  boot_subvol = 0;
293 
294  while (true) {
295  if (*s >= '0' && *s <= '9') {
296  boot_subvol <<= 4;
297  boot_subvol |= *s - '0';
298  } else if (*s >= 'a' && *s <= 'f') {
299  boot_subvol <<= 4;
300  boot_subvol |= *s - 'a' + 0xa;
301  } else if (*s >= 'A' && *s <= 'F') {
302  boot_subvol <<= 4;
303  boot_subvol |= *s - 'A' + 0xa;
304  } else
305  break;
306 
307  s++;
308  }
310  return;
311  } _SEH2_END;
312 
313  if (boot_subvol != 0) {
314  TRACE("passed subvol %I64x in boot options\n", boot_subvol);
315  }
316 }
317 
320 
321  AddDevice(drvobj, pdo);
322 
323  // To stop Windows sneakily setting DOE_START_PENDING
324  pdode->dont_report = true;
325 
326  if (pdo->DeviceObjectExtension) {
327  ((DEVOBJ_EXTENSION2*)pdo->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
328 
329  if (pdode && pdode->vde && pdode->vde->device)
330  ((DEVOBJ_EXTENSION2*)pdode->vde->device->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
331  }
332 
333  mountmgr_notification(&pdode->uuid);
334 }
335 
337  LIST_ENTRY* le;
338  PDEVICE_OBJECT pdo_to_add = NULL;
339 
340  TRACE("()\n");
341 
342  // wait for any PNP notifications in progress to finish
345 
346  if (!get_system_root())
347  return;
348 
350 
351  le = pdo_list.Flink;
352  while (le != &pdo_list) {
354 
355  if (RtlCompareMemory(&pdode->uuid, &boot_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
356  if (!pdode->vde)
357  pdo_to_add = pdode->pdo;
358  else if (pdode->vde->device && !(pdode->vde->device->Flags & DO_SYSTEM_BOOT_PARTITION)) { // AddDevice has beaten us to it
360 
363 
364  Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, false);
365  if (!NT_SUCCESS(Status))
366  ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
367 
368  Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, true);
369  if (!NT_SUCCESS(Status))
370  ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
371  }
372 
373  break;
374  }
375 
376  le = le->Flink;
377  }
378 
380 
382 
383  // If our FS depends on volumes that aren't there when we do our IoRegisterPlugPlayNotification calls
384  // in DriverEntry, bus_query_device_relations won't get called until it's too late. We need to do our
385  // own call to AddDevice here as a result. We need to clear the DOE_START_PENDING bits, or NtOpenFile
386  // will return STATUS_NO_SUCH_DEVICE.
387  if (pdo_to_add)
388  boot_add_device(pdo_to_add);
389 }
#define hex_digit(c)
Definition: btrfs_drv.h:1738
WCHAR DeviceName[1]
Definition: imports.h:155
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
ULONG PowerFlags
Definition: boot.c:44
struct _KEY_VALUE_FULL_INFORMATION KEY_VALUE_FULL_INFORMATION
#define TRUE
Definition: types.h:120
static const BYTE us[]
Definition: encode.c:689
GLsizei const GLchar ** path
Definition: glext.h:7234
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
DRIVER_ADD_DEVICE AddDevice
Definition: parport.h:72
PDEVICE_OBJECT device
Definition: btrfs_drv.h:867
LONG NTSTATUS
Definition: precomp.h:26
uint64_t boot_subvol
Definition: boot.c:34
CSHORT Type
Definition: boot.c:41
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1435
ERESOURCE boot_lock
Definition: btrfs.c:109
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define MOUNTMGR_DEVICE_NAME
Definition: imports.h:76
#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION
Definition: imports.h:130
void check_system_root()
Definition: boot.c:336
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
_SEH2_TRY
Definition: create.c:4226
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
PDEVICE_OBJECT pdo
Definition: btrfs_drv.h:882
void boot_add_device(DEVICE_OBJECT *pdo)
Definition: boot.c:318
#define ALLOC_TAG
Definition: btrfs_drv.h:87
UNICODE_STRING bus_name
Definition: btrfs_drv.h:871
BTRFS_UUID boot_uuid
Definition: boot.c:33
#define L(x)
Definition: ntvdm.h:50
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3272
#define DOE_START_PENDING
Definition: boot.c:37
LIST_ENTRY pdo_list
Definition: btrfs.c:103
static bool get_system_root()
Definition: boot.c:49
USHORT Size
Definition: boot.c:42
PVOID DeviceExtension
Definition: env_spec_w32.h:418
#define DO_SYSTEM_BOOT_PARTITION
Definition: env_spec_w32.h:400
#define offsetof(TYPE, MEMBER)
NTSTATUS NTAPI IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName, IN BOOLEAN Enable)
Definition: deviface.c:1311
int options
Definition: main.c:106
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
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:547
Status
Definition: gdiplustypes.h:24
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define TRACE(s)
Definition: solgame.cpp:4
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PDRIVER_OBJECT drvobj
Definition: btrfs.c:65
#define BTRFS_VOLUME_PREFIX
Definition: btrfs_drv.h:127
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ bool Override, _Out_opt_ IO_STATUS_BLOCK *iosb)
Definition: btrfs.c:2923
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
* PFILE_OBJECT
Definition: iotypes.h:1998
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
GLdouble s
Definition: gl.h:2039
#define GENERIC_READ
Definition: compat.h:135
Definition: typedefs.h:119
BYTE uint8_t
Definition: msvideo1.c:66
#define ERR(fmt,...)
Definition: debug.h:110
uint8_t uuid[16]
Definition: btrfs.h:140
USHORT DeviceNameLength
Definition: imports.h:154
_SEH2_END
Definition: create.c:4400
UINT64 uint64_t
Definition: types.h:77
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
static void mountmgr_notification(BTRFS_UUID *uuid)
Definition: boot.c:180
unsigned short USHORT
Definition: pedump.c:61
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
Definition: list.h:27
#define NULL
Definition: types.h:112
PDEVICE_OBJECT DeviceObject
Definition: boot.c:43
BOOLEAN NTAPI ExAcquireResourceSharedLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:885
volume_device_extension * vde
Definition: btrfs_drv.h:881
Definition: name.c:38
ULONG ERESOURCE
Definition: env_spec_w32.h:594
Definition: msctf.idl:510
unsigned int ULONG
Definition: retypes.h:1
GLenum target
Definition: glext.h:7315
void * Dope
Definition: boot.c:45
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
static void check_boot_options()
Definition: boot.c:232
short CSHORT
Definition: umtypes.h:127
ERESOURCE pdo_list_lock
Definition: btrfs.c:102
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
NTSYSAPI NTSTATUS NTAPI ZwOpenSymbolicLinkObject(_Out_ PHANDLE SymbolicLinkHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes)
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
ULONG ExtensionFlags
Definition: boot.c:46
GLuint const GLchar * name
Definition: glext.h:6031