ReactOS  0.4.14-dev-376-gaedba84
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 #ifndef _MSC_VER
34 NTSTATUS RtlUnicodeStringPrintf(PUNICODE_STRING DestinationString, const WCHAR* pszFormat, ...); // not in mingw
35 #endif
36 
37 // Not in any headers? Windbg knows about it though.
38 #define DOE_START_PENDING 0x10
39 
40 // Just as much as we need - the version in mingw is truncated still further
41 typedef struct {
46  void* Dope;
49 
50 static bool get_system_root_partition(uint32_t* disk_num, uint32_t* partition_num) {
52  HANDLE h;
54  OBJECT_ATTRIBUTES objatt;
55  WCHAR* s;
56  ULONG retlen = 0, left;
57 
58  static const WCHAR system_root[] = L"\\SystemRoot";
59  static const WCHAR arc_prefix[] = L"\\ArcName\\multi(0)disk(0)rdisk(";
60  static const WCHAR arc_middle[] = L")partition(";
61 
62  us.Buffer = (WCHAR*)system_root;
63  us.Length = us.MaximumLength = sizeof(system_root) - sizeof(WCHAR);
64 
66 
68  if (!NT_SUCCESS(Status)) {
69  ERR("ZwOpenSymbolicLinkObject returned %08x\n", Status);
70  return false;
71  }
72 
73  target.Length = target.MaximumLength = 0;
74 
75  Status = ZwQuerySymbolicLinkObject(h, &target, &retlen);
77  ERR("ZwQuerySymbolicLinkObject returned %08x\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 %08x\n", Status);
99  NtClose(h);
100  ExFreePool(target.Buffer);
101  return false;
102  }
103 
104  NtClose(h);
105 
106  TRACE("system root is %.*S\n", target.Length / sizeof(WCHAR), target.Buffer);
107 
108  if (target.Length <= sizeof(arc_prefix) - sizeof(WCHAR) ||
109  RtlCompareMemory(target.Buffer, arc_prefix, sizeof(arc_prefix) - sizeof(WCHAR)) != sizeof(arc_prefix) - sizeof(WCHAR)) {
110  ExFreePool(target.Buffer);
111  return false;
112  }
113 
114  s = &target.Buffer[(sizeof(arc_prefix) / sizeof(WCHAR)) - 1];
115  left = ((target.Length - sizeof(arc_prefix)) / sizeof(WCHAR)) + 1;
116 
117  if (left == 0 || s[0] < '0' || s[0] > '9') {
118  ExFreePool(target.Buffer);
119  return false;
120  }
121 
122  *disk_num = 0;
123 
124  while (left > 0 && s[0] >= '0' && s[0] <= '9') {
125  *disk_num *= 10;
126  *disk_num += s[0] - '0';
127  s++;
128  left--;
129  }
130 
131  if (left <= (sizeof(arc_middle) / sizeof(WCHAR)) - 1 ||
132  RtlCompareMemory(s, arc_middle, sizeof(arc_middle) - sizeof(WCHAR)) != sizeof(arc_middle) - sizeof(WCHAR)) {
133  ExFreePool(target.Buffer);
134  return false;
135  }
136 
137  s = &s[(sizeof(arc_middle) / sizeof(WCHAR)) - 1];
138  left -= (sizeof(arc_middle) / sizeof(WCHAR)) - 1;
139 
140  if (left == 0 || s[0] < '0' || s[0] > '9') {
141  ExFreePool(target.Buffer);
142  return false;
143  }
144 
145  *partition_num = 0;
146 
147  while (left > 0 && s[0] >= '0' && s[0] <= '9') {
148  *partition_num *= 10;
149  *partition_num += s[0] - '0';
150  s++;
151  left--;
152  }
153 
154  ExFreePool(target.Buffer);
155 
156  return true;
157 }
158 
159 static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID* uuid) {
161  UNICODE_STRING us, us2;
162  WCHAR symlink[60], target[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) + 36], *w;
163 #ifdef __REACTOS__
164  unsigned int i;
165 #endif
166 
167  us.Buffer = symlink;
168  us.Length = 0;
169  us.MaximumLength = sizeof(symlink);
170 
171  Status = RtlUnicodeStringPrintf(&us, L"\\Device\\Harddisk%u\\Partition%u", disk_num, partition_num);
172  if (!NT_SUCCESS(Status)) {
173  ERR("RtlUnicodeStringPrintf returned %08x\n", Status);
174  return;
175  }
176 
178  if (!NT_SUCCESS(Status))
179  ERR("IoDeleteSymbolicLink returned %08x\n", Status);
180 
182 
183  w = &target[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
184 
185 #ifndef __REACTOS__
186  for (unsigned int i = 0; i < 16; i++) {
187 #else
188  for (i = 0; i < 16; i++) {
189 #endif
190  *w = hex_digit(uuid->uuid[i] >> 4); w++;
191  *w = hex_digit(uuid->uuid[i] & 0xf); w++;
192 
193  if (i == 3 || i == 5 || i == 7 || i == 9) {
194  *w = L'-';
195  w++;
196  }
197  }
198 
199  *w = L'}';
200 
201  us2.Buffer = target;
202  us2.Length = us2.MaximumLength = sizeof(target);
203 
204  Status = IoCreateSymbolicLink(&us, &us2);
205  if (!NT_SUCCESS(Status))
206  ERR("IoCreateSymbolicLink returned %08x\n", Status);
207 }
208 
210  UNICODE_STRING mmdevpath;
214  ULONG mmtnlen;
215  MOUNTMGR_TARGET_NAME* mmtn;
216  WCHAR* w;
217 #ifdef __REACTOS__
218  unsigned int i;
219 #endif
220 
223  if (!NT_SUCCESS(Status)) {
224  ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
225  return;
226  }
227 
228  mmtnlen = offsetof(MOUNTMGR_TARGET_NAME, DeviceName[0]) + sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
229 
230  mmtn = ExAllocatePoolWithTag(NonPagedPool, mmtnlen, ALLOC_TAG);
231  if (!mmtn) {
232  ERR("out of memory\n");
233  return;
234  }
235 
236  mmtn->DeviceNameLength = sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
237 
239 
240  w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
241 
242 #ifndef __REACTOS__
243  for (unsigned int i = 0; i < 16; i++) {
244 #else
245  for (i = 0; i < 16; i++) {
246 #endif
247  *w = hex_digit(uuid->uuid[i] >> 4); w++;
248  *w = hex_digit(uuid->uuid[i] & 0xf); w++;
249 
250  if (i == 3 || i == 5 || i == 7 || i == 9) {
251  *w = L'-';
252  w++;
253  }
254  }
255 
256  *w = L'}';
257 
259  if (!NT_SUCCESS(Status)) {
260  ERR("IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION returned %08x\n", Status);
261  ExFreePool(mmtn);
262  return;
263  }
264 
265  ExFreePool(mmtn);
266 }
267 
268 /* If booting from Btrfs, Windows will pass the device object for the raw partition to
269  * mount_vol - which is no good to us, as we only use the \Device\Btrfs{} devices we
270  * create so that RAID works correctly.
271  * At the time check_system_root gets called, \SystemRoot is a symlink to the ARC device,
272  * e.g. \ArcName\multi(0)disk(0)rdisk(0)partition(1)\Windows. We can't change the symlink,
273  * as it gets clobbered by IopReassignSystemRoot shortly afterwards, and we can't touch
274  * the \ArcName symlinks as they haven't been created yet. Instead, we need to change the
275  * symlink \Device\HarddiskX\PartitionY, which is what the ArcName symlink will shortly
276  * point to.
277  */
279  uint32_t disk_num, partition_num;
280  LIST_ENTRY* le;
281  bool done = false;
282  PDEVICE_OBJECT pdo_to_add = NULL;
283 
284  TRACE("(%p, %p, %u)\n", DriverObject, Context, Count);
285 
286  // wait for any PNP notifications in progress to finish
289 
290  if (!get_system_root_partition(&disk_num, &partition_num))
291  return;
292 
293  TRACE("system boot partition is disk %u, partition %u\n", disk_num, partition_num);
294 
296 
297  le = pdo_list.Flink;
298  while (le != &pdo_list) {
299  LIST_ENTRY* le2;
301 
303 
304  le2 = pdode->children.Flink;
305 
306  while (le2 != &pdode->children) {
308 
309  if (vc->disk_num == disk_num && vc->part_num == partition_num) {
310  change_symlink(disk_num, partition_num, &pdode->uuid);
311  done = true;
312 
313  if (!pdode->vde)
314  pdo_to_add = pdode->pdo;
315 
316  break;
317  }
318 
319  le2 = le2->Flink;
320  }
321 
322  if (done) {
323  le2 = pdode->children.Flink;
324 
325  while (le2 != &pdode->children) {
327 
328  /* On Windows 7 we need to clear the DO_SYSTEM_BOOT_PARTITION flag of
329  * all of our underlying partition objects - otherwise IopMountVolume
330  * will bugcheck with UNMOUNTABLE_BOOT_VOLUME when it tries and fails
331  * to mount one. */
332  if (vc->devobj) {
333  PDEVICE_OBJECT dev = vc->devobj;
334 
336 
337  while (dev) {
339 
340  dev->Flags &= ~DO_SYSTEM_BOOT_PARTITION;
341 
343 
344  dev = dev2;
345  }
346  }
347 
348  le2 = le2->Flink;
349  }
350 
352 
353  break;
354  }
355 
357 
358  le = le->Flink;
359  }
360 
362 
363  // If our FS depends on volumes that aren't there when we do our IoRegisterPlugPlayNotification calls
364  // in DriverEntry, bus_query_device_relations won't get called until it's too late. We need to do our
365  // own call to AddDevice here as a result. We need to clear the DOE_START_PENDING bits, or NtOpenFile
366  // will return STATUS_NO_SUCH_DEVICE.
367  if (pdo_to_add) {
368  pdo_device_extension* pdode = pdo_to_add->DeviceExtension;
369 
370  AddDevice(drvobj, pdo_to_add);
371 
372  // To stop Windows sneakily setting DOE_START_PENDING
373  pdode->dont_report = true;
374 
375  if (pdo_to_add->DeviceObjectExtension) {
376  ((DEVOBJ_EXTENSION2*)pdo_to_add->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
377 
378  if (pdode && pdode->vde && pdode->vde->device)
379  ((DEVOBJ_EXTENSION2*)pdode->vde->device->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
380  }
381 
382  mountmgr_notification(&pdode->uuid);
383  }
384 }
#define hex_digit(c)
Definition: btrfs_drv.h:1725
WCHAR DeviceName[1]
Definition: imports.h:155
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
ULONG PowerFlags
Definition: boot.c:45
USHORT MaximumLength
Definition: env_spec_w32.h:370
static const BYTE us[]
Definition: encode.c:689
DRIVER_ADD_DEVICE AddDevice
Definition: parport.h:72
PDEVICE_OBJECT device
Definition: btrfs_drv.h:850
LONG NTSTATUS
Definition: precomp.h:26
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
CSHORT Type
Definition: boot.c:42
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1435
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
WCHAR DeviceName[]
Definition: adapter.cpp:21
ULONG part_num
Definition: btrfs_drv.h:841
ERESOURCE boot_lock
Definition: btrfs.c:113
#define MOUNTMGR_DEVICE_NAME
Definition: imports.h:76
#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION
Definition: imports.h:130
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
PDEVICE_OBJECT pdo
Definition: btrfs_drv.h:865
#define ALLOC_TAG
Definition: btrfs_drv.h:91
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
#define DOE_START_PENDING
Definition: boot.c:38
LIST_ENTRY pdo_list
Definition: btrfs.c:107
USHORT Size
Definition: boot.c:43
PVOID DeviceExtension
Definition: env_spec_w32.h:418
#define DO_SYSTEM_BOOT_PARTITION
Definition: env_spec_w32.h:400
_Out_ _Inout_ POEM_STRING DestinationString
Definition: rtlfuncs.h:1869
smooth NULL
Definition: ftsmooth.c:416
#define offsetof(TYPE, MEMBER)
PDEVICE_OBJECT devobj
Definition: btrfs_drv.h:833
static PDRIVER_OBJECT DriverObject
Definition: template.c:42
static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID *uuid)
Definition: boot.c:159
PDEVICE_OBJECT NTAPI IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
Definition: device.c:1507
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
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
void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULONG Count)
Definition: boot.c:278
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
#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:66
#define BTRFS_VOLUME_PREFIX
Definition: btrfs_drv.h:127
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:2813
NTSTATUS RtlUnicodeStringPrintf(PUNICODE_STRING DestinationString, const WCHAR *pszFormat,...)
GLint left
Definition: glext.h:7726
#define __stdcall
Definition: typedefs.h:25
ERESOURCE child_lock
Definition: btrfs_drv.h:871
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
* PFILE_OBJECT
Definition: iotypes.h:1955
static bool get_system_root_partition(uint32_t *disk_num, uint32_t *partition_num)
Definition: boot.c:50
ULONG disk_num
Definition: btrfs_drv.h:840
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static const WCHAR L[]
Definition: oid.c:1250
GLdouble s
Definition: gl.h:2039
#define GENERIC_READ
Definition: compat.h:124
Definition: typedefs.h:117
Status
Definition: gdiplustypes.h:24
#define ERR(fmt,...)
Definition: debug.h:109
USHORT DeviceNameLength
Definition: imports.h:154
static void mountmgr_notification(BTRFS_UUID *uuid)
Definition: boot.c:209
unsigned short USHORT
Definition: pedump.c:61
Definition: list.h:27
PDEVICE_OBJECT DeviceObject
Definition: boot.c:44
UINT32 uint32_t
Definition: types.h:75
BOOLEAN NTAPI ExAcquireResourceSharedLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:885
volume_device_extension * vde
Definition: btrfs_drv.h:864
#define ObReferenceObject
Definition: obfuncs.h:204
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:46
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
LIST_ENTRY children
Definition: btrfs_drv.h:872
short CSHORT
Definition: umtypes.h:127
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
ERESOURCE pdo_list_lock
Definition: btrfs.c:106
#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:47