captive_shutdown(): Implemented proper unmount for ntfs.sys of NT-5.1sp1.
authorshort <>
Fri, 4 Jul 2003 05:05:49 +0000 (05:05 +0000)
committershort <>
Fri, 4 Jul 2003 05:05:49 +0000 (05:05 +0000)
+dismount_volume(): Invoke filesystem FSCTL_DISMOUNT_VOLUME.

src/libcaptive/client/init.c

index 5dd8a65..b30efa4 100644 (file)
@@ -46,6 +46,9 @@
 #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>
 
 
 struct captive_options *captive_options;
@@ -269,7 +272,8 @@ gboolean errbool;
                }
 
        if (captive_options->rwmode==CAPTIVE_OPTION_RWMODE_BLIND)
-               captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(captive_options->image_iochannel);
+               captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(captive_options->image_iochannel,
+                               TRUE);  /* writeable */
        else
                captive_image_iochannel=captive_options->image_iochannel;
 
@@ -285,6 +289,92 @@ gboolean errbool;
 }
 
 
+static void dismount_volume(void)
+{
+IO_STATUS_BLOCK IoStatusBlock;
+PIO_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;
+
+       errvfsresult=captive_ObjectAttributes_init("/!Captive!del",&dir_ObjectAttributes);
+       g_return_if_fail(errvfsresult==GNOME_VFS_OK);
+       
+       /* wanted: * IoCreateFile()->ObCreateObject(,,,IoFileObjectType)->
+        * ->(IoFileObjectType->Create==IopCreateFile)()->IoMountVolume()
+        */
+       err=IoCreateFile(
+                       &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 */
+                       (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_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, /* CreateOptions; FILE_DIRECTORY_FILE is forbidden */
+                       NULL,   /* EaBuffer */
+                       0,      /* EaLength */
+                       CreateFileTypeNone,     /* CreateFileType */
+                       NULL,   /* ExtraCreateParameters */
+                       0);     /* Options */
+       g_free(dir_ObjectAttributes.ObjectName);        /* left from captive_gnomevfs_uri_parent_init() */
+       g_return_if_fail(NT_SUCCESS(err)==NT_SUCCESS(dir_IoStatusBlock.Status));
+       g_return_if_fail(NT_SUCCESS(err));
+       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));
+
+       Irp=IoAllocateIrp(DeviceObject->StackSize,TRUE);
+       g_return_if_fail(Irp!=NULL);
+
+       Irp->UserIosb=&IoStatusBlock;
+       Irp->UserEvent=&FileObject->Event;
+       Irp->Tail.Overlay.Thread=PsGetCurrentThread();
+
+       StackPtr=IoGetNextIrpStackLocation(Irp);
+       StackPtr->MajorFunction=IRP_MJ_FILE_SYSTEM_CONTROL;
+       StackPtr->MinorFunction=IRP_MN_USER_FS_REQUEST;
+       StackPtr->Flags=0;
+       StackPtr->Control=0;
+       StackPtr->DeviceObject=DeviceObject;    /* FIXME: FileObject->Vpb->DeviceObject ? */
+       StackPtr->FileObject=FileObject;
+       StackPtr->CompletionRoutine=NULL;
+
+       StackPtr->Parameters.FileSystemControl.OutputBufferLength=0;
+       StackPtr->Parameters.FileSystemControl.InputBufferLength=0;
+       StackPtr->Parameters.FileSystemControl.FsControlCode=FSCTL_DISMOUNT_VOLUME;
+       StackPtr->Parameters.FileSystemControl.Type3InputBuffer=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;
+               }
+       g_assert(NT_SUCCESS(Status));
+
+       ObDereferenceObject(FileObject);
+}
+
+
 BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject);
 void captive_cc_flush(void);
 
@@ -311,28 +401,43 @@ GIOStatus erriostatus;
                        FALSE)) /* may_block */
                g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: g_main_context_iteration() proceeded",G_STRLOC);
 
+       captive_cc_flush();     /* based on captive_leave(), not g_main idle */
+
+       dismount_volume();
+
+       /* 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);
+
        captive_PoQueueShutdownWorkItem_hooklist_invoke();
-       captive_cc_flush();
-
-       /* 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().
+
+       /* 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(),
         */
-       captive_cc_unmounting=TRUE;
 
        /* FIXME: ntoskrnl/ex/power.c/NtShutdownSystem() does
         * IoShutdownRegistered{Devices,FileSystems} order; is it correct?
         */
        IoShutdownRegisteredFileSystems();
 
-       /* Just a sanity check as all the dirty data should
-        * get already flushed during 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.
         */
-       captive_cc_FileObject_delete(
-                       NULL);  /* FileObject */
 
        IoShutdownRegisteredDevices();