2 * Init and cleanup code of libcaptive to be called by client application
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "captive/ldr.h"
23 #include "captive/ldr_exports.h"
24 #include "captive/unicode.h"
25 #include "captive/rtl-file.h"
26 #include <glib/gtypes.h>
27 #include <glib/gmessages.h>
28 #include "reactos/internal/ldr.h"
29 #include "reactos/napi/types.h"
30 #include "reactos/internal/kd.h" /* for KDB_LOADDRIVER_HOOK */
32 #include <sys/mman.h> /* for PROT_READ, MAP_SHARED */
33 #include "reactos/ddk/kefuncs.h" /* for KeInitializeSpinLock() */
34 #include "reactos/internal/ntoskrnl.h" /* for RtlpInitNlsTables() and IoInit() */
35 #include "reactos/internal/ps.h" /* for PsInitProcessManagment() and PsInitThreadManagment() */
36 #include "reactos/ddk/iofuncs.h" /* for IoCreateFile() */
37 #include "captive/storage.h"
38 #include "captive/signal.h" /* for captive_signal_init() */
39 #include "reactos/ddk/psfuncs.h" /* for PsGetCurrentThread() */
42 #include <glib/gstrfuncs.h>
43 #include <glib/glist.h>
44 #include "giochannel-blind.h"
45 #include <glib-object.h>
46 #include "reactos/internal/se.h" /* for SeInit2() */
47 #include "captive/leave.h"
48 #include "captive/options.h"
49 #include <libgnomevfs/gnome-vfs-result.h>
51 #include <reactos/ddk/obfuncs.h>
54 struct captive_options *captive_options;
56 /* Are we initialized? */
57 static gboolean active;
59 /* Module of fs module itself loaded by captive_w32_init() */
60 static PMODULE_OBJECT ModuleObject;
62 /* Driver in fs module loaded by captive_w32_init() */
63 DRIVER_OBJECT captive_DriverObject;
64 PDRIVER_REINITIALIZE captive_DriverObject_ReinitRoutine;
65 PVOID captive_DriverObject_ReinitRoutine_Context;
67 /* Structure holding the pointer to the toplevel IRP */
68 static TOP_LEVEL_IRP TopLevelIrp; /* TODO:thread */
71 void *_local_unwind2_addr;
74 /* Acceleration hack for ntoskrnl/dbg/print.c/DbgPrint() */
75 gboolean captive_get_debug_messages(void)
77 g_return_val_if_fail(captive_options!=NULL,TRUE);
79 return captive_options->debug_messages;
83 static gboolean captive_w32_init(void)
87 GIOStatus erriostatus;
89 g_return_val_if_fail(captive_options!=NULL,FALSE);
90 g_return_val_if_fail(captive_options->filesystem.type!=CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY,FALSE);
92 erriostatus=g_io_channel_set_encoding(captive_image_iochannel,
93 NULL, /* encoding; force binary data */
95 g_assert(erriostatus==G_IO_STATUS_NORMAL);
97 /* captive_giochannel_size() only _after_ g_io_channel_set_encoding() ! */
98 captive_image_size=captive_giochannel_size(captive_image_iochannel);
99 g_return_val_if_fail(captive_image_size>0,FALSE);
101 /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() begins. */
102 /* ExpInitializeExecutive(); */
103 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() begins
104 * here as the rest of the function does a lot of hardware initializations.
107 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() begins. */
108 InitializeListHead(&ModuleTextListHead);
109 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() ends. */
110 KeLowerIrql(DISPATCH_LEVEL);
112 /* create default nls tables */
117 KeInitializeDispatcher();
119 KeLowerIrql(PASSIVE_LEVEL);
121 g_assert(errbool==TRUE);
124 g_assert(errbool==TRUE);
125 /* PiInitProcessManager(); */
126 /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() begins. */
127 PsInitProcessManagment();
128 PsInitThreadManagment();
129 /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() ends. */
133 /* LdrInitModuleManagement(); */
134 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement() begins
135 * here as the rest "Create module object for {NTOSKRNL,HAL}"
136 * is dependent on {NTOSKRNL,HAL} PE image headers not provided by libcaptive.
138 /* Initialize the module list and spinlock */
139 InitializeListHead(&ModuleListHead);
140 KeInitializeSpinLock(&ModuleListLock);
141 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement ends. */
144 NtInitializeEventImplementation();
146 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() ends. */
147 /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() ends. */
149 /* Simulate our PE headers and export the symbols of our complete libraries */
150 captive_kernel_exports();
152 errbool=captive_cdrom_init();
153 g_return_val_if_fail(errbool==TRUE,FALSE);
154 errbool=captive_disk_init();
155 g_return_val_if_fail(errbool==TRUE,FALSE);
157 while (captive_options->load_module) {
158 PMODULE_OBJECT ModuleObject_tmp;
161 /* load the module */
162 err=captive_LdrLoadModule(
163 captive_options->load_module->data,
164 &ModuleObject_tmp); /* ModuleObjectp */
165 g_return_val_if_fail(NT_SUCCESS(err),FALSE);
167 captive_options_module_free(captive_options->load_module->data);
168 /* also frees 'options->load_module->data' */
169 captive_options->load_module=g_list_delete_link(captive_options->load_module,captive_options->load_module);
172 /* Patch 'ntoskrnl.exe' loaded by 'captive_options->load_module' above. */
174 CHAR *KeNumberProcessorsp=captive_Module_GetExportAddress("ntoskrnl.exe","KeNumberProcessors");
176 g_assert(*KeNumberProcessorsp==0);
177 *KeNumberProcessorsp=KeNumberProcessors;
178 g_assert(*KeNumberProcessorsp==1);
180 /* Apply captive_kernel_patches() AFTER any symbols sanity checks above! */
181 captive_kernel_patches();
183 _local_unwind2_addr=captive_Module_GetExportAddress("ntoskrnl.exe","_local_unwind2");
185 /* Initialize 'FsRtlLegalAnsiCharacterArray'.
186 * It requires 'ntoskrnl.exe' loaded by 'captive_options->load_module' above;
187 * captive_kernel_patches() should not be needed.
189 captive_FsRtlLegalAnsiCharacterArray_init();
191 /* set TopLevelIrp() - FIXME: where is it set by native reactos? */
192 PsGetCurrentThread()->TopLevelIrp=&TopLevelIrp; /* otherwise Io{Get,Set}TopLevelIrp() would SIGSEGV */
194 /* Begin possible handling of foreign W32 binary code here */
195 /* If you want to disable SIGSEGV handler if not needed:
196 * if (ModuleObject->Flags & MODULE_FLAG_PE)
198 captive_signal_init();
200 /* You must have already captive_signal_init() passed here as the module may
201 * call some functions from W32 ntoskrnl.exe.
203 captive_DriverObject_ReinitRoutine=NULL;
204 err=captive_LdrpLoadAndCallImage(
205 &ModuleObject, /* ModuleObjectp */
206 &captive_options->filesystem, /* options_module */
207 &captive_DriverObject, /* DriverEntry_DriverObject */
208 captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
209 g_return_val_if_fail(NT_SUCCESS(err),FALSE);
210 if (captive_DriverObject_ReinitRoutine) {
211 (*captive_DriverObject_ReinitRoutine)(
212 &captive_DriverObject, /* DriverObject */
213 captive_DriverObject_ReinitRoutine_Context, /* Context */
214 1); /* Count: # of calls of ReinitRoutine incl. the current one */
221 static void log_discard_func(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
230 * Expects #captive_options: Parsed by captive_options_parse().
231 * %NULL value is forbidden. Field #image_iochannel %NULL value is forbidden.
233 * Initializes %libcaptive and loads the specified filesystem.
235 * Returns: %TRUE if successfuly initialized.
237 gboolean captive_init(void)
241 /* We are in sandbox child and we have the right to fail. */
242 g_log_set_always_fatal(~(0
248 g_return_val_if_fail(active==FALSE,FALSE);
250 g_return_val_if_fail(captive_options!=NULL,FALSE);
251 g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
253 /* Initialize GObject subsystem of GLib. */
256 if (!captive_options->debug_messages) {
258 G_LOG_DOMAIN, /* log_domain; "Captive" */
260 | G_LOG_FLAG_RECURSION
262 /* The same mask is in:
263 * libcaptive/sandbox/server-GLogFunc.c
264 * libcaptive/client/init.c
265 * libcaptive/client/vfs.c
267 | G_LOG_LEVEL_MESSAGE
270 log_discard_func, /* log_func */
271 NULL); /* user_data */
274 if (captive_options->rwmode==CAPTIVE_OPTION_RWMODE_BLIND)
275 captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(captive_options->image_iochannel,
276 TRUE); /* writeable */
278 captive_image_iochannel=captive_options->image_iochannel;
280 /* Do not initialize 'captive_image_size' by captive_giochannel_size() here
281 * as we yet need to do g_io_channel_set_encoding().
284 errbool=captive_w32_init();
285 g_return_val_if_fail(errbool==TRUE,FALSE);
292 static void dismount_volume(void)
294 IO_STATUS_BLOCK IoStatusBlock;
295 PIO_STACK_LOCATION StackPtr;
298 DEVICE_OBJECT *DeviceObject=captive_DriverObject.DeviceObject;
299 OBJECT_ATTRIBUTES dir_ObjectAttributes;
301 FILE_OBJECT *FileObject;
302 GnomeVFSResult errvfsresult;
304 IO_STATUS_BLOCK dir_IoStatusBlock;
306 errvfsresult=captive_ObjectAttributes_init("/!Captive!del",&dir_ObjectAttributes);
307 g_return_if_fail(errvfsresult==GNOME_VFS_OK);
309 /* wanted: * IoCreateFile()->ObCreateObject(,,,IoFileObjectType)->
310 * ->(IoFileObjectType->Create==IopCreateFile)()->IoMountVolume()
313 &dir_Handle, /* FileHandle */
314 GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE|0x80, /* DesiredAccess; 0xC0100080=GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE|0x80 */
315 &dir_ObjectAttributes, /* ObjectAttributes */
316 &dir_IoStatusBlock, /* IoStatusBlock */
317 NULL, /* AllocationSize; ignored for open */
318 FILE_ATTRIBUTE_NORMAL, /* FileAttributes; ignored for open */
319 (FILE_SHARE_READ | FILE_SHARE_WRITE), /* ShareAccess; 0 means exclusive */
320 FILE_OPEN, /* CreateDisposition */
321 /* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
322 * any waits to not to let it return STATUS_CANT_WAIT us.
323 * Alertability should have only effect on asynchronous events
324 * from KeWaitForSingleObject() by setting/clearing its parameter 'Alertable'.
326 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, /* CreateOptions; FILE_DIRECTORY_FILE is forbidden */
329 CreateFileTypeNone, /* CreateFileType */
330 NULL, /* ExtraCreateParameters */
332 g_free(dir_ObjectAttributes.ObjectName); /* left from captive_gnomevfs_uri_parent_init() */
333 g_return_if_fail(NT_SUCCESS(err)==NT_SUCCESS(dir_IoStatusBlock.Status));
334 g_return_if_fail(NT_SUCCESS(err));
335 g_return_if_fail(dir_IoStatusBlock.Information==FILE_OPENED);
337 Status=ObReferenceObjectByHandle(dir_Handle,FILE_LIST_DIRECTORY,IoFileObjectType,UserMode,(PVOID *)&FileObject,NULL);
338 g_assert(NT_SUCCESS(Status));
340 Irp=IoAllocateIrp(DeviceObject->StackSize,TRUE);
341 g_return_if_fail(Irp!=NULL);
343 Irp->UserIosb=&IoStatusBlock;
344 Irp->UserEvent=&FileObject->Event;
345 Irp->Tail.Overlay.Thread=PsGetCurrentThread();
347 StackPtr=IoGetNextIrpStackLocation(Irp);
348 StackPtr->MajorFunction=IRP_MJ_FILE_SYSTEM_CONTROL;
349 StackPtr->MinorFunction=IRP_MN_USER_FS_REQUEST;
352 StackPtr->DeviceObject=DeviceObject; /* FIXME: FileObject->Vpb->DeviceObject ? */
353 StackPtr->FileObject=FileObject;
354 StackPtr->CompletionRoutine=NULL;
356 StackPtr->Parameters.FileSystemControl.OutputBufferLength=0;
357 StackPtr->Parameters.FileSystemControl.InputBufferLength=0;
358 StackPtr->Parameters.FileSystemControl.FsControlCode=FSCTL_DISMOUNT_VOLUME;
359 StackPtr->Parameters.FileSystemControl.Type3InputBuffer=NULL;
361 /* IoCallDriver() will do one ObDereferenceObject(FileObject)
362 * in its IoSecondStageCompletion().
363 * Do not leave to dereference it itself as we need its 'FileObject->Event'.
365 ObReferenceObject(FileObject);
367 Status=IoCallDriver(DeviceObject,Irp);
368 if (Status==STATUS_PENDING) {
369 KeWaitForSingleObject(&FileObject->Event,Executive,KernelMode,FALSE,NULL);
370 Status=IoStatusBlock.Status;
372 g_assert(NT_SUCCESS(Status));
374 ObDereferenceObject(FileObject);
378 BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject);
379 void captive_cc_flush(void);
384 * Closes down %libcaptive. It should flush all pending buffers and successfuly
385 * close the filesystem. Variable #captive_options->image_iochannel will not be set to %NULL,
386 * you should close such channel yourself.
388 * Returns: %TRUE if successfuly shutdown.
390 gboolean captive_shutdown(void)
392 GIOStatus erriostatus;
394 g_return_val_if_fail(active==TRUE,FALSE);
395 g_return_val_if_fail(captive_image_iochannel!=NULL,FALSE);
396 g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
398 /* Invoke all pending idle functions just to not to forget for anything... */
399 while (g_main_context_iteration(
400 NULL, /* context; NULL means default one */
401 FALSE)) /* may_block */
402 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: g_main_context_iteration() proceeded",G_STRLOC);
404 captive_cc_flush(); /* based on captive_leave(), not g_main idle */
408 /* Invoke all pending idle functions just to not to forget for anything... */
409 while (g_main_context_iteration(
410 NULL, /* context; NULL means default one */
411 FALSE)) /* may_block */
412 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: g_main_context_iteration() proceeded",G_STRLOC);
414 captive_PoQueueShutdownWorkItem_hooklist_invoke();
416 /* Do not: captive_cc_flush();
417 * as the dirty blocks should have been already commited by dismount_volume(),
418 * any further commits would get us just STATUS_VOLUME_DISMOUNTED.
421 /* Do not: captive_cc_unmounting=TRUE;
422 * Without dismount_volume() it was:
423 * During IoShutdownRegisteredFileSystems() - IRP_MJ_SHUTDOWN to be specific
424 * some buffers will be written but after the IofCallDriver() it will be
425 * no longer possible to flush such buffers to their DeviceVolumeFile.
426 * Therefore we must flush such buffers on the fly although such behaviour
427 * would crash us in regular case as filesystems access BCBs even after their
429 * Currently the dirty blocks should have been already commited by dismount_volume(),
432 /* FIXME: ntoskrnl/ex/power.c/NtShutdownSystem() does
433 * IoShutdownRegistered{Devices,FileSystems} order; is it correct?
435 IoShutdownRegisteredFileSystems();
437 /* Do not: captive_cc_FileObject_delete(NULL);
438 * as the dirty blocks should have been already commited by dismount_volume(),
439 * any further commits would get us just STATUS_VOLUME_DISMOUNTED.
442 IoShutdownRegisteredDevices();
444 /* libcaptive is not authorized to shutdown 'captive_image_channel'. */
445 erriostatus=g_io_channel_flush(
446 captive_image_iochannel, /* channel */
448 g_assert(erriostatus==G_IO_STATUS_NORMAL);
450 /* 'captive_image_iochannel' may be blinded wrapper of 'captive_options->image_iochannel'. */
451 if (captive_image_iochannel!=captive_options->image_iochannel) {
452 erriostatus=g_io_channel_flush(
453 captive_options->image_iochannel, /* channel */
455 g_assert(erriostatus==G_IO_STATUS_NORMAL);
456 g_io_channel_unref(captive_image_iochannel);
459 captive_image_iochannel=NULL;