/* $Id$
* Init and cleanup code of libcaptive to be called by client application
- * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
+ * Copyright (C) 2002-2003 Jan Kratochvil <project-captive@jankratochvil.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "config.h"
-#include "captive/client.h" /* self */
+#include "init.h" /* self */
#include "captive/ldr.h"
#include "captive/ldr_exports.h"
#include "captive/unicode.h"
-#include "captive/file.h"
+#include "captive/rtl-file.h"
#include <glib/gtypes.h>
#include <glib/gmessages.h>
#include "reactos/internal/ldr.h"
#include <fcntl.h>
#include <sys/mman.h> /* for PROT_READ, MAP_SHARED */
#include "reactos/ddk/kefuncs.h" /* for KeInitializeSpinLock() */
-#include "reactos/internal/ntoskrnl.h" /* for RtlpInitNlsTables() and IoInit() */
+#include "reactos/internal/ntoskrnl.h" /* for IoInit() */
#include "reactos/internal/ps.h" /* for PsInitProcessManagment() and PsInitThreadManagment() */
#include "reactos/ddk/iofuncs.h" /* for IoCreateFile() */
#include "captive/storage.h"
#include "captive/signal.h" /* for captive_signal_init() */
#include "reactos/ddk/psfuncs.h" /* for PsGetCurrentThread() */
#include <stdio.h>
-
+#include <popt.h>
+#include <glib/gstrfuncs.h>
+#include <glib/glist.h>
+#include "giochannel-blind.h"
+#include <glib-object.h>
+#include "reactos/internal/se.h" /* for SeInit2() */
+#include "captive/leave.h"
+#include "captive/options.h"
+#include <libgnomevfs/gnome-vfs-result.h>
+#include "lib.h"
+#include <reactos/ddk/obfuncs.h>
+#include <syslog.h>
+#include "captive/macros.h"
+#include "../storage/relastblock.h" /* for captive_storage_relastblock() */
+#include "../cc/sharedcachemap.h" /* for captive_shared_cache_map_flush_all() */
+
+
+struct captive_options *captive_options;
/* Are we initialized? */
static gboolean active;
-/* Module of fs module itself loaded by captive_init(fs_path) */
+/* Module of fs module itself loaded by captive_w32_init() */
static PMODULE_OBJECT ModuleObject;
-/* Driver in fs module loaded by captive_init(fs_path) */
-static DRIVER_OBJECT DriverObject;
-
-/* Handle for the root directory of the mounted volume */
-static HANDLE root_Handle;
+/* Driver in fs module loaded by captive_w32_init() */
+DRIVER_OBJECT captive_DriverObject;
+PDRIVER_REINITIALIZE captive_DriverObject_ReinitRoutine;
+PVOID captive_DriverObject_ReinitRoutine_Context;
/* Structure holding the pointer to the toplevel IRP */
static TOP_LEVEL_IRP TopLevelIrp; /* TODO:thread */
-/**
- * captive_init:
- * @fs_path: Host OS file #utf8 pathname of the filesystem module to load.
- * %NULL value is forbidden.
- * @image_pathname: Host OS file #utf8 pathname of the disk image to mount.
- * %NULL value is forbidden.
- *
- * Initializes %libcaptive and loads the specified filesystem.
- *
- * Returns: %TRUE if successfuly loaded.
- */
-gboolean captive_init(const gchar *fs_path,const gchar *image_pathname)
+void *_local_unwind2_addr;
+
+
+gboolean captive_debug_messages_disabled=FALSE;
+
+static gboolean captive_w32_init(void)
{
NTSTATUS err;
gboolean errbool;
-OBJECT_ATTRIBUTES root_ObjectAttributes;
-IO_STATUS_BLOCK root_IoStatusBlock;
-FILE_ID_BOTH_DIR_INFORMATION *FileIdBothDirInformation,*FileIdBothDirInformation_next;
-char QueryDirectory_buf[0x10000];
-#ifdef MAINTAINER_MODE
- g_log_set_always_fatal(~(0
- |G_LOG_LEVEL_MESSAGE
- |G_LOG_LEVEL_INFO
- |G_LOG_LEVEL_DEBUG
- ));
-#endif
+ g_return_val_if_fail(captive_options!=NULL,FALSE);
+ g_return_val_if_fail(captive_options->filesystem.type!=CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY,FALSE);
- g_return_val_if_fail(fs_path!=NULL,FALSE);
- g_return_val_if_fail(image_pathname!=NULL,FALSE);
- g_return_val_if_fail(active==FALSE,FALSE);
+ /* captive_giochannel_size() only _after_ g_io_channel_set_encoding() ! */
+ captive_image_size=captive_giochannel_size(captive_image_iochannel);
+ g_return_val_if_fail(captive_image_size>0,FALSE);
/* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() begins. */
/* ExpInitializeExecutive(); */
/* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() begins. */
InitializeListHead(&ModuleTextListHead);
/* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() ends. */
+ KeLowerIrql(DISPATCH_LEVEL);
/*...*/
- /* create default nls tables */
- RtlpInitNlsTables();
+ /* FIXME: create default nls tables? Really still needed? */
+ /* Obsolete: RtlpInitNlsTables(); */
/*...*/
+ /* KeInit2() */
+ /*...*/
+ KeInitializeDispatcher();
+ /*...*/
+ KeLowerIrql(PASSIVE_LEVEL);
+ errbool=SeInit1();
+ g_assert(errbool==TRUE);
ObInit();
- /*...*/
+ errbool=SeInit2();
+ g_assert(errbool==TRUE);
/* PiInitProcessManager(); */
/* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() begins. */
PsInitProcessManagment();
InitializeListHead(&ModuleListHead);
KeInitializeSpinLock(&ModuleListLock);
/* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement ends. */
+ /*...*/
+ /* Ntinit(); */
+ NtInitializeEventImplementation();
+ /*...*/
/* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() ends. */
/* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() ends. */
- /* Simulate our PE headers and export the symbols of {NTOSKRNL,HAL} */
+ /* Simulate our PE headers and export the symbols of our complete libraries */
captive_kernel_exports();
- errbool=captive_cdrom_init(image_pathname);
+ errbool=captive_cdrom_init();
+ g_return_val_if_fail(errbool==TRUE,FALSE);
+ errbool=captive_disk_init();
g_return_val_if_fail(errbool==TRUE,FALSE);
- err=captive_LdrpLoadAndCallImage(
- &ModuleObject, /* ModuleObjectp */
- captive_utf8_to_UnicodeString_alloca(fs_path), /* ModuleName */
- &DriverObject, /* DriverEntry_DriverObject */
- captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
- g_return_val_if_fail(NT_SUCCESS(err),FALSE);
+ while (captive_options->load_module) {
+PMODULE_OBJECT ModuleObject_tmp;
+NTSTATUS err;
+
+ /* load the module */
+ err=captive_LdrLoadModule(
+ captive_options->load_module->data,
+ &ModuleObject_tmp); /* ModuleObjectp */
+ g_return_val_if_fail(NT_SUCCESS(err),FALSE);
+
+ captive_options_module_free(captive_options->load_module->data);
+ /* also frees 'options->load_module->data' */
+ captive_options->load_module=g_list_delete_link(captive_options->load_module,captive_options->load_module);
+ }
+
+ /* Patch 'ntoskrnl.exe' loaded by 'captive_options->load_module' above. */
+ {
+ CHAR *KeNumberProcessorsp=captive_Module_GetExportAddress("ntoskrnl.exe","KeNumberProcessors");
+
+ g_assert(*KeNumberProcessorsp==0);
+ *KeNumberProcessorsp=KeNumberProcessors;
+ g_assert(*KeNumberProcessorsp==1);
+ }
+ /* Apply AFTER any symbols sanity checks above! */
+ if (captive_options->debug_messages)
+ captive_kernel_patches_debug();
+ else
+ captive_kernel_patches_nondebug();
+
+ _local_unwind2_addr=captive_Module_GetExportAddress("ntoskrnl.exe","_local_unwind2");
+
+ /* Initialize 'FsRtlLegalAnsiCharacterArray'.
+ * It requires 'ntoskrnl.exe' loaded by 'captive_options->load_module' above;
+ * captive_kernel_patches_debug()/captive_kernel_patches_nondebug() should not be needed.
+ */
+ captive_FsRtlLegalAnsiCharacterArray_init();
/* set TopLevelIrp() - FIXME: where is it set by native reactos? */
PsGetCurrentThread()->TopLevelIrp=&TopLevelIrp; /* otherwise Io{Get,Set}TopLevelIrp() would SIGSEGV */
*/
captive_signal_init();
- /* Do not open "\Cdfs"(anything) as it is just the filesystem implementation.
- * ntoskrnl/io/fs.c/IoMountVolume() will map
- * FILE_DEVICE_CD_ROM -> FILE_DEVICE_CD_ROM_FILE_SYSTEM
- * for us automatically when opening the device itself.
- * Also you must put some trailing content there as otherwise
- * IoCreateFile()->ObCreateObject()->ObFindObject()
- * would leave 'ObCreateObject::RemainingPath' as NULL
- * and later IopCreateFile() would consider it FO_DIRECT_DEVICE_OPEN (e.g. w/o any mount!)
+ /* You must have already captive_signal_init() passed here as the module may
+ * call some functions from W32 ntoskrnl.exe.
+ */
+ captive_DriverObject_ReinitRoutine=NULL;
+ err=captive_LdrpLoadAndCallImage(
+ &ModuleObject, /* ModuleObjectp */
+ &captive_options->filesystem, /* options_module */
+ &captive_DriverObject, /* DriverEntry_DriverObject */
+ captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
+ g_return_val_if_fail(NT_SUCCESS(err),FALSE);
+ if (captive_DriverObject_ReinitRoutine) {
+ captive_stdcall_call_12((CaptiveStdCallFunc12)captive_DriverObject_ReinitRoutine,
+ &captive_DriverObject, /* DriverObject */
+ captive_DriverObject_ReinitRoutine_Context, /* Context */
+ (gpointer)1); /* Count: # of calls of ReinitRoutine incl. the current one */
+ }
+
+ return TRUE;
+}
+
+
+static void captive_log_init_g_log_func_discard
+ (const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
+{
+ g_return_if_fail(message!=NULL);
+
+ /* NOP */
+}
+
+static void captive_log_init_g_log_func
+ (const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data /* unused */)
+{
+int priority;
+
+ g_return_if_fail(message!=NULL);
+
+ /* unused: LOG_EMERG */
+ /* unused: LOG_ALERT */
+ /**/ if (log_level&G_LOG_LEVEL_ERROR)
+ priority=LOG_CRIT;
+ else if (log_level&G_LOG_LEVEL_CRITICAL)
+ priority=LOG_ERR;
+ else if (log_level&G_LOG_LEVEL_WARNING)
+ priority=LOG_WARNING;
+ else if (log_level&G_LOG_LEVEL_MESSAGE)
+ priority=LOG_NOTICE;
+ else if (log_level&G_LOG_LEVEL_INFO)
+ priority=LOG_INFO;
+ else if (log_level&G_LOG_LEVEL_DEBUG)
+ priority=LOG_DEBUG;
+ else /* bogus? */
+ priority=LOG_WARNING;
+
+ syslog(priority,"%s%s%s",
+ (!(log_level&G_LOG_FLAG_RECURSION) ? "" : "RECURSION: "),
+ (!(log_level&G_LOG_FLAG_FATAL ) ? "" : "FATAL: "),
+ message);
+}
+
+void captive_log_init(const struct captive_options *captive_options)
+{
+ g_return_if_fail(captive_options!=NULL);
+
+ /* FIXME: Fix sharing of different 'debug_messages' for various sandboxes. */
+ captive_debug_messages_disabled=!captive_options->debug_messages;
+
+ /* FIXME: Fix sharing of different 'debug_messages' for various sandboxes. */
+ if (!captive_options->debug_messages) {
+ /* FIXME: Save handler_id and destroy it in captive_vfs_close(). */
+ g_log_set_handler(
+ G_LOG_DOMAIN, /* log_domain; "Captive" */
+ 0 /* log_levels */
+ | G_LOG_FLAG_RECURSION
+ | G_LOG_FLAG_FATAL
+ /* The same mask is in:
+ * libcaptive/sandbox/server-GLogFunc.c
+ * libcaptive/client/init.c
+ */
+ | G_LOG_LEVEL_MESSAGE
+ | G_LOG_LEVEL_INFO
+ | G_LOG_LEVEL_DEBUG,
+ captive_log_init_g_log_func_discard, /* log_func */
+ NULL); /* user_data */
+ }
+ /* We are not the sandboxed slave;
+ * 'syslog_facility' would be '-1' in slave anyway as it is not transferred through CORBA.
+ */
+ if (!captive_options->sandbox || (captive_options->sandbox_server_argv || captive_options->sandbox_server_ior)) {
+ if (captive_options->syslog_facility!=-1) {
+ openlog(
+ /* FIXME: Prefix 'ident' by device/mountpoint. */
+ G_LOG_DOMAIN, /* ident; "Captive"; FIXME: lowercase it for syslog(3)? */
+ LOG_CONS|LOG_PID, /* options */
+ captive_options->syslog_facility); /* facility */
+ /* FIXME: Save handler_id and destroy it in captive_vfs_close(). */
+ g_log_set_handler(
+ G_LOG_DOMAIN, /* log_domain; "Captive" */
+ 0 /* log_levels */
+ | 0 /* !G_LOG_FLAG_RECURSION */
+ | G_LOG_FLAG_FATAL
+ | (G_LOG_LEVEL_MASK & ~(captive_options->debug_messages ? 0 : 0
+ /* The same mask is in:
+ * libcaptive/sandbox/server-GLogFunc.c
+ * libcaptive/client/init.c
+ */
+ | G_LOG_LEVEL_MESSAGE
+ | G_LOG_LEVEL_INFO
+ | G_LOG_LEVEL_DEBUG)),
+ (GLogFunc)captive_log_init_g_log_func, /* log_func */
+ NULL); /* user_data */
+ }
+ }
+}
+
+/**
+ * captive_init:
+ *
+ * Expects #captive_options: Parsed by captive_options_parse().
+ * %NULL value is forbidden. Field #image_iochannel %NULL value is forbidden.
+ *
+ * Initializes %libcaptive and loads the specified filesystem.
+ *
+ * Returns: %TRUE if successfuly initialized.
+ */
+gboolean captive_init(void)
+{
+gboolean errbool;
+
+ /* We are in sandbox child and we have the right to fail. */
+ g_log_set_always_fatal(~(0
+ |G_LOG_LEVEL_MESSAGE
+ |G_LOG_LEVEL_INFO
+ |G_LOG_LEVEL_DEBUG
+ ));
+
+ g_return_val_if_fail(active==FALSE,FALSE);
+
+ g_return_val_if_fail(captive_options!=NULL,FALSE);
+ g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
+
+ /* Initialize GObject subsystem of GLib. */
+ g_type_init();
+
+ captive_log_init(captive_options);
+
+ captive_image_iochannel=captive_options->image_iochannel;
+ g_io_channel_ref(captive_image_iochannel);
+
+ captive_image_iochannel=captive_storage_relastblock(captive_image_iochannel);
+
+ if (captive_options->rwmode==CAPTIVE_OPTION_RWMODE_BLIND) {
+ GIOChannel *captive_image_iochannel_orig;
+
+ captive_image_iochannel_orig=captive_image_iochannel;
+ captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(captive_image_iochannel,
+ TRUE); /* writeable */
+ g_io_channel_unref(captive_image_iochannel_orig); /* reffed by captive_giochannel_blind_new() */
+ }
+
+ /* Do not initialize 'captive_image_size' by captive_giochannel_size() here
+ * as we yet need to do g_io_channel_set_encoding().
*/
- InitializeObjectAttributes(
- &root_ObjectAttributes, /* InitializedAttributes */
- captive_utf8_to_UnicodeString_alloca("\\Device\\CdRom0\\."), /* ObjectName */
- 0, /* Attributes; I hope no OBJ_KERNEL_HANDLE as we are 'system process' */
- NULL, /* RootDirectory */
- NULL); /* SecurityDescriptor; ignored */
+ errbool=captive_w32_init();
+ g_return_val_if_fail(errbool==TRUE,FALSE);
+
+ active=TRUE;
+ return TRUE;
+}
+
+
+static void dismount_volume(void)
+{
+IO_STATUS_BLOCK IoStatusBlock;
+PEXTENDED_IO_STACK_LOCATION StackPtr;
+PIRP Irp;
+NTSTATUS Status;
+DEVICE_OBJECT *DeviceObject=captive_DriverObject.DeviceObject;
+OBJECT_ATTRIBUTES dir_ObjectAttributes;
+HANDLE dir_Handle;
+FILE_OBJECT *FileObject;
+GnomeVFSResult errvfsresult;
+NTSTATUS err;
+IO_STATUS_BLOCK dir_IoStatusBlock;
+/*
+ * TraceFS reported only IRP_MJ_FLUSH_BUFFERS
+ * and IRP_MJ_SHUTDOWN.
+ * Apparently it is not enough, FSCTL_DISMOUNT_VOLUME is needed,
+ * otherwise NT-5.1 autochkdsks the disk and W2000 may give BSOD during boot.
+ */
+enum step {
+ /* First item value assumed to be 0. */
+ STEP_IRP_MJ_FLUSH_BUFFERS_PRE,
+#if 0
+ /* DISABLED: STATUS_ACCESS_DENIED; FIXME: Why?
+ * The official way of device modification is: LOCK,DISMOUNT
+ * but LOCK fails for Captive if any file was written (and closed).
+ */
+ STEP_FSCTL_LOCK_VOLUME,
+#endif
+ STEP_FSCTL_DISMOUNT_VOLUME,
+ STEP_IRP_MJ_FLUSH_BUFFERS_POST,
+ STEP_MAX=3,
+ } stepi;
+WCHAR wzero;
+
+ errvfsresult=captive_ObjectAttributes_init("/!Captive!del",&dir_ObjectAttributes);
+ g_return_if_fail(errvfsresult==GNOME_VFS_OK);
+
/* wanted: * IoCreateFile()->ObCreateObject(,,,IoFileObjectType)->
* ->(IoFileObjectType->Create==IopCreateFile)()->IoMountVolume()
*/
+ CAPTIVE_MEMZERO(&dir_IoStatusBlock); /* FIXME: Try to pre-clear it - uninitialized otherwise? */
+ dir_IoStatusBlock.Information=FILE_OPENED; /* FIXME: Try to pre-set it - uninitialized otherwise? */
err=IoCreateFile(
- &root_Handle, /* FileHandle */
- FILE_LIST_DIRECTORY, /* DesiredAccess */
- &root_ObjectAttributes, /* ObjectAttributes */
- &root_IoStatusBlock, /* IoStatusBlock */
+ &dir_Handle, /* FileHandle */
+ GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE|0x80, /* DesiredAccess; 0xC0100080=GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE|0x80 */
+ &dir_ObjectAttributes, /* ObjectAttributes */
+ &dir_IoStatusBlock, /* IoStatusBlock */
NULL, /* AllocationSize; ignored for open */
FILE_ATTRIBUTE_NORMAL, /* FileAttributes; ignored for open */
- 0, /* ShareAccess; 0 means exclusive */
+ (FILE_SHARE_READ | FILE_SHARE_WRITE), /* ShareAccess; 0 means exclusive */
FILE_OPEN, /* CreateDisposition */
/* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
* any waits to not to let it return STATUS_CANT_WAIT us.
* Alertability should have only effect on asynchronous events
* from KeWaitForSingleObject() by setting/clearing its parameter 'Alertable'.
*/
- FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_ALERT, /* CreateOptions */
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, /* CreateOptions; FILE_DIRECTORY_FILE is forbidden */
NULL, /* EaBuffer */
0, /* EaLength */
CreateFileTypeNone, /* CreateFileType */
NULL, /* ExtraCreateParameters */
0); /* Options */
- g_return_val_if_fail(NT_SUCCESS(err),FALSE);
- g_return_val_if_fail(NT_SUCCESS(root_IoStatusBlock.Status),FALSE);
- g_return_val_if_fail(root_IoStatusBlock.Information==FILE_OPENED,FALSE);
-
-
- err=NtQueryDirectoryFile(
- root_Handle, /* FileHandle */
- NULL, /* PEvent; completion signalling; optional */
- NULL, /* ApcRoutine; optional */
- NULL, /* ApcContext; optional */
- &root_IoStatusBlock, /* IoStatusBlock */
- (gpointer)QueryDirectory_buf, /* FileInformation */
- sizeof(QueryDirectory_buf), /* Length */
- FileIdBothDirectoryInformation, /* FileInformationClass; =>FILE_ID_BOTH_DIR_INFORMATION */
- FALSE, /* ReturnSingleEntry */
- NULL, /* FileName; wildcards possible; optional */
- TRUE); /* RestartScan */
- g_return_val_if_fail(NT_SUCCESS(err),FALSE);
- g_return_val_if_fail(NT_SUCCESS(root_IoStatusBlock.Status),FALSE);
-
- for (FileIdBothDirInformation=(gpointer)QueryDirectory_buf;
- (gpointer)FileIdBothDirInformation < (gpointer)(QueryDirectory_buf+root_IoStatusBlock.Information);
- FileIdBothDirInformation=FileIdBothDirInformation_next) {
-gint i;
-
- FileIdBothDirInformation_next=(gpointer)(((char *)FileIdBothDirInformation)+FileIdBothDirInformation->NextEntryOffset);
- /* do not exceed the returned buffer by this record */
- g_assert((gpointer)FileIdBothDirInformation_next<=(gpointer)(QueryDirectory_buf+root_IoStatusBlock.Information));
-
- printf("@%ld: FileIndex=%lu,EndOfFile=%lld,AllocationSize=%lld,FileId=0x%llX,",
- (long)(((char *)FileIdBothDirInformation)-((char *)QueryDirectory_buf)), /* @%ld */
- FileIdBothDirInformation->FileIndex,
- FileIdBothDirInformation->EndOfFile.QuadPart,
- FileIdBothDirInformation->AllocationSize.QuadPart,
- (unsigned long long)FileIdBothDirInformation->FileId.QuadPart);
- printf("ShortName=\"");
- g_assert((FileIdBothDirInformation->ShortNameLength%sizeof(*FileIdBothDirInformation->ShortName))==0);
- for (i=0;(unsigned)i<FileIdBothDirInformation->ShortNameLength/sizeof(*FileIdBothDirInformation->ShortName);i++) {
-gunichar uc=FileIdBothDirInformation->ShortName[i];
-
- if (g_unichar_isprint(uc) && uc<=0xFF)
- putchar(uc);
- else
- printf("[0x%X]",(unsigned)uc);
+ g_free(dir_ObjectAttributes.ObjectName); /* left from captive_gnomevfs_uri_parent_init() */
+ g_return_if_fail(NT_SUCCESS(err));
+ g_return_if_fail(NT_SUCCESS(err)==NT_SUCCESS(dir_IoStatusBlock.Status));
+ g_return_if_fail(dir_IoStatusBlock.Information==FILE_OPENED);
+
+ Status=ObReferenceObjectByHandle(dir_Handle,FILE_LIST_DIRECTORY,IoFileObjectType,UserMode,(PVOID *)&FileObject,NULL);
+ g_assert(NT_SUCCESS(Status));
+
+ g_assert(FileObject->FileName.Length==0);
+ /* 'FileObject->FileName.MaximumLength' is not reset by IoCreateFile(). */
+ g_assert(FileObject->FileName.Buffer==NULL);
+ FileObject->FileName.MaximumLength=2;
+ FileObject->FileName.Buffer=&wzero;
+
+ for (stepi=0;stepi<STEP_MAX;stepi++) {
+ Irp=IoAllocateIrp(DeviceObject->StackSize,TRUE);
+ g_return_if_fail(Irp!=NULL);
+
+ Irp->UserIosb=&IoStatusBlock;
+ Irp->UserEvent=&FileObject->Event;
+ Irp->Tail.Overlay.Thread=PsGetCurrentThread();
+
+ StackPtr=(EXTENDED_IO_STACK_LOCATION *)IoGetNextIrpStackLocation(Irp);
+ switch (stepi) {
+ case STEP_IRP_MJ_FLUSH_BUFFERS_PRE:
+ StackPtr->MajorFunction=IRP_MJ_FLUSH_BUFFERS;
+ break;
+#if 0 /* Disabled, see 'STEP_FSCTL_LOCK_VOLUME'. */
+ case STEP_FSCTL_LOCK_VOLUME:
+ StackPtr->MajorFunction=IRP_MJ_FILE_SYSTEM_CONTROL;
+ StackPtr->MinorFunction=IRP_MN_USER_FS_REQUEST;
+ StackPtr->Parameters.FileSystemControl.OutputBufferLength=0;
+ StackPtr->Parameters.FileSystemControl.InputBufferLength=0;
+ StackPtr->Parameters.FileSystemControl.FsControlCode=FSCTL_LOCK_VOLUME;
+ StackPtr->Parameters.FileSystemControl.Type3InputBuffer=NULL;
+ break;
+#endif
+ case STEP_FSCTL_DISMOUNT_VOLUME:
+ StackPtr->MajorFunction=IRP_MJ_FILE_SYSTEM_CONTROL;
+ StackPtr->MinorFunction=IRP_MN_USER_FS_REQUEST;
+ StackPtr->Parameters.FileSystemControl.OutputBufferLength=0;
+ StackPtr->Parameters.FileSystemControl.InputBufferLength=0;
+ StackPtr->Parameters.FileSystemControl.FsControlCode=FSCTL_DISMOUNT_VOLUME;
+ StackPtr->Parameters.FileSystemControl.Type3InputBuffer=NULL;
+ break;
+ case STEP_IRP_MJ_FLUSH_BUFFERS_POST:
+ StackPtr->MajorFunction=IRP_MJ_FLUSH_BUFFERS;
+ break;
+ default: g_assert_not_reached();
}
- printf("\",");
- printf("FileName: ");
- g_assert((FileIdBothDirInformation->FileNameLength)%sizeof(*FileIdBothDirInformation->FileName)==0);
- for (i=0;(unsigned)i<FileIdBothDirInformation->FileNameLength/sizeof(*FileIdBothDirInformation->FileName);i++) {
-gunichar uc=FileIdBothDirInformation->FileName[i];
-
- if (g_unichar_isprint(uc) && uc<=0xFF)
- putchar(uc);
- else
- printf("[0x%X]",(unsigned)uc);
+ StackPtr->Flags=0;
+ StackPtr->Control=0;
+ StackPtr->DeviceObject=DeviceObject; /* FIXME: FileObject->Vpb->DeviceObject ? */
+ StackPtr->FileObject=FileObject;
+ StackPtr->CompletionRoutine=NULL;
+
+ /* IoCallDriver() will do one ObDereferenceObject(FileObject)
+ * in its IoSecondStageCompletion().
+ * Do not leave to dereference it itself as we need its 'FileObject->Event'.
+ */
+ ObReferenceObject(FileObject);
+
+ Status=IoCallDriver(DeviceObject,Irp);
+ if (Status==STATUS_PENDING) {
+ KeWaitForSingleObject(&FileObject->Event,Executive,KernelMode,FALSE,NULL);
+ Status=IoStatusBlock.Status;
}
- printf("\n");
- /* Last entry may be also marked by: 0==FileIdBothDirInformation->NextEntryOffset */
- if (FileIdBothDirInformation_next==FileIdBothDirInformation)
- break;
+ g_assert(NT_SUCCESS(Status)
+ || (Status==STATUS_MEDIA_WRITE_PROTECTED && captive_options->rwmode==CAPTIVE_OPTION_RWMODE_RO));
}
-
- active=TRUE;
- return TRUE;
+ ObDereferenceObject(FileObject);
}
+BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject);
+void captive_cc_flush(void);
+
/**
- * captive_cleanup:
+ * captive_shutdown:
*
- * Closes #libcaptive. Frees any used system resources. You are forbidden
- * to touch any #libcaptive data or funtions before a new captive_init()
- * is done. Forbidden to call it before successful captive_init() is done.
+ * Closes down %libcaptive. It should flush all pending buffers and successfuly
+ * close the filesystem. Variable #captive_options->image_iochannel will not be set to %NULL,
+ * you should close such channel yourself.
*
- * Currently this function IS NOT IMPLEMENTED.
- *
- * Returns: %TRUE if the successful resource cleanup was done during the call.
+ * Returns: %TRUE if successfuly shutdown.
*/
-gboolean captive_cleanup(void)
+gboolean captive_shutdown(void)
{
-NTSTATUS err;
+GIOStatus erriostatus;
g_return_val_if_fail(active==TRUE,FALSE);
+ g_return_val_if_fail(captive_image_iochannel!=NULL,FALSE);
+ g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
+
+ /* Invoke all pending idle functions just to not to forget for anything... */
+ while (g_main_context_iteration(
+ NULL, /* context; NULL means default one */
+ FALSE)) /* may_block */
+ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: g_main_context_iteration() proceeded",G_STRLOC);
+
+ /* Do not: captive_cc_flush(); * based on captive_leave(), not g_main idle *
+ * replaced by IRP_MJ_FLUSH_BUFFERS.
+ */
+
+ /* Probably not needed: captive_shared_cache_map_flush_all();
+ */
+
+ dismount_volume();
+
+ /* Probably not needed: captive_shared_cache_map_flush_all();
+ */
+
+ /* Invoke all pending idle functions just to not to forget for anything... */
+ while (g_main_context_iteration(
+ NULL, /* context; NULL means default one */
+ FALSE)) /* may_block */
+ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: g_main_context_iteration() proceeded",G_STRLOC);
+
+#if 0
+ captive_PoQueueShutdownWorkItem_hooklist_invoke();
+#endif
+
+ /* Do not: captive_cc_flush();
+ * as the dirty blocks should have been already commited by dismount_volume(),
+ * any further commits would get us just STATUS_VOLUME_DISMOUNTED.
+ */
+
+ /* Do not: captive_cc_unmounting=TRUE;
+ * Without dismount_volume() it was:
+ * During IoShutdownRegisteredFileSystems() - IRP_MJ_SHUTDOWN to be specific
+ * some buffers will be written but after the IofCallDriver() it will be
+ * no longer possible to flush such buffers to their DeviceVolumeFile.
+ * Therefore we must flush such buffers on the fly although such behaviour
+ * would crash us in regular case as filesystems access BCBs even after their
+ * CcUnpinData().
+ * Currently the dirty blocks should have been already commited by dismount_volume(),
+ */
+
+ /* FIXME: ntoskrnl/ex/power.c/NtShutdownSystem() does
+ * IoShutdownRegistered{Devices,FileSystems} order; is it correct?
+ */
+ IoShutdownRegisteredFileSystems();
+
+ /* Do not: captive_cc_FileObject_delete(NULL);
+ * as the dirty blocks should have been already commited by dismount_volume(),
+ * any further commits would get us just STATUS_VOLUME_DISMOUNTED.
+ */
+
+ IoShutdownRegisteredDevices();
- err=LdrUnloadModule(ModuleObject);
- g_assert(NT_SUCCESS(err));
+ /* Just a sanity if 'captive_image_iochannel' is already reffed a bit more... */
+ erriostatus=g_io_channel_flush(
+ captive_image_iochannel, /* channel */
+ NULL); /* error */
+ g_assert(erriostatus==G_IO_STATUS_NORMAL);
- /* captive_cleanup() NOT IMPLEMENTED */
- g_return_val_if_reached(FALSE);
+ g_io_channel_unref(captive_image_iochannel);
+ captive_image_iochannel=NULL;
active=FALSE;
return TRUE;