+Workaround Linux kernel last device block inaccessibility.
[captive.git] / src / libcaptive / client / vfs-parent.c
index c2f1ef8..40801ef 100644 (file)
 #include "../sandbox/parent-Vfs.h"
 #include "directory-parent.h"
 #include "file-parent.h"
+#include "marshallers.h"
 
 
 static gpointer captive_vfs_parent_object_parent_class=NULL;
 
 
 static GnomeVFSResult captive_vfs_parent_init(CaptiveVfsObject *captive_vfs_object);
+static void captive_vfs_parent_object_dispose(CaptiveVfsParentObject *captive_vfs_parent_object);
+static void captive_vfs_parent_object_handler_detach(CaptiveVfsParentObject *captive_vfs_parent_object);
+static void captive_vfs_parent_object_handler_cease(CaptiveVfsParentObject *captive_vfs_parent_object);
+static void captive_vfs_parent_object_handler_abort(CaptiveVfsParentObject *captive_vfs_parent_object);
 static GnomeVFSResult captive_vfs_parent_close(CaptiveVfsObject *captive_vfs_object);
 static GnomeVFSResult captive_vfs_parent_commit(CaptiveVfsObject *captive_vfs_object);
 static GnomeVFSResult captive_vfs_parent_volume_info_get
                (CaptiveVfsObject *captive_vfs_object,CaptiveVfsVolumeInfo *volume_info);
+static GnomeVFSResult captive_vfs_parent_object_connect_silent(CaptiveVfsParentObject *captive_vfs_parent_object);
 
 
-static void captive_vfs_parent_object_finalize(CaptiveVfsParentObject *captive_vfs_parent_object)
+/* We need to close the filesystem during custom 'dispose'
+ * as the default GObject g_object_real_dispose() destroys all the signals
+ * first and we would not notify our Connectors during captive_vfs_parent_object_finalize().
+ */
+static void captive_vfs_parent_object_dispose(CaptiveVfsParentObject *captive_vfs_parent_object)
 {
        g_return_if_fail(captive_vfs_parent_object!=NULL);
 
        captive_vfs_parent_close(CAPTIVE_VFS_OBJECT(captive_vfs_parent_object));        /* errors ignored */
 
+       G_OBJECT_CLASS(captive_vfs_parent_object_parent_class)->dispose((GObject *)captive_vfs_parent_object);
+}
+
+
+static void captive_vfs_parent_object_finalize(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+       g_return_if_fail(captive_vfs_parent_object!=NULL);
+
        G_OBJECT_CLASS(captive_vfs_parent_object_parent_class)->finalize((GObject *)captive_vfs_parent_object);
 }
 
@@ -53,6 +71,7 @@ GObjectClass *gobject_class=G_OBJECT_CLASS(class);
 CaptiveVfsObjectClass *captive_vfs_object_class=CAPTIVE_VFS_OBJECT_CLASS(class);
 
        captive_vfs_parent_object_parent_class=g_type_class_ref(g_type_parent(G_TYPE_FROM_CLASS(class)));
+       gobject_class->dispose=(void (*)(GObject *object))captive_vfs_parent_object_dispose;
        gobject_class->finalize=(void (*)(GObject *object))captive_vfs_parent_object_finalize;
 
        captive_vfs_object_class->init=captive_vfs_parent_init;
@@ -64,6 +83,34 @@ CaptiveVfsObjectClass *captive_vfs_object_class=CAPTIVE_VFS_OBJECT_CLASS(class);
 
        captive_vfs_object_class->file_new_open=captive_file_parent_new_open;
        captive_vfs_object_class->file_new_create=captive_file_parent_new_create;
+
+       class->detach=captive_vfs_parent_object_handler_detach;
+       g_signal_new(
+                       "detach",       /* signal_name */
+                       G_TYPE_FROM_CLASS(class),       /* itype */
+                       G_SIGNAL_RUN_LAST,      /* signal_flags */
+                       G_STRUCT_OFFSET(CaptiveVfsParentObjectClass,detach),    /* class_offset */
+                       NULL,NULL,      /* accumulator,accu_data */
+                       captive_client_VOID__VOID,      /* c_marshaller */
+                       G_TYPE_NONE,0); /* return_type,n_params */
+       class->cease=captive_vfs_parent_object_handler_cease;
+       g_signal_new(
+                       "cease",        /* signal_name */
+                       G_TYPE_FROM_CLASS(class),       /* itype */
+                       G_SIGNAL_RUN_LAST,      /* signal_flags */
+                       G_STRUCT_OFFSET(CaptiveVfsParentObjectClass,cease),     /* class_offset */
+                       NULL,NULL,      /* accumulator,accu_data */
+                       captive_client_VOID__VOID,      /* c_marshaller */
+                       G_TYPE_NONE,0); /* return_type,n_params */
+       class->abort=captive_vfs_parent_object_handler_abort;
+       g_signal_new(
+                       "abort",        /* signal_name */
+                       G_TYPE_FROM_CLASS(class),       /* itype */
+                       G_SIGNAL_RUN_LAST,      /* signal_flags */
+                       G_STRUCT_OFFSET(CaptiveVfsParentObjectClass,abort),     /* class_offset */
+                       NULL,NULL,      /* accumulator,accu_data */
+                       captive_client_VOID__VOID,      /* c_marshaller */
+                       G_TYPE_NONE,0); /* return_type,n_params */
 }
 
 
@@ -72,6 +119,22 @@ static void captive_vfs_parent_object_init(CaptiveVfsParentObject *captive_vfs_p
        captive_vfs_parent_object->corba_parent_giochanel_blind=NULL;
 }
 
+       
+static void captive_vfs_parent_object_handler_detach(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+       g_return_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object));
+}
+
+static void captive_vfs_parent_object_handler_cease(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+       g_return_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object));
+}
+
+static void captive_vfs_parent_object_handler_abort(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+       g_return_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object));
+}
+
 
 GType captive_vfs_parent_object_get_type(void)
 {
@@ -113,24 +176,47 @@ CaptiveVfsParentObject *captive_vfs_parent_object;
 static GnomeVFSResult captive_vfs_parent_close(CaptiveVfsObject *captive_vfs_object)
 {
 CaptiveVfsParentObject *captive_vfs_parent_object;
+GnomeVFSResult r;
 
        g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
 
        captive_vfs_parent_object=CAPTIVE_VFS_PARENT_OBJECT(captive_vfs_object);
 
-       return captive_sandbox_parent_vfs_close(captive_vfs_parent_object);
+       if (captive_vfs_parent_object->corba_Vfs_object!=CORBA_OBJECT_NIL) {
+               r=captive_vfs_parent_object_disconnect(captive_vfs_parent_object);
+               g_assert(captive_vfs_parent_object->corba_Vfs_object==CORBA_OBJECT_NIL);
+               }
+       else
+               r=GNOME_VFS_OK;
+
+       if (captive_vfs_parent_object->corba_parent_giochanel_blind_source) {
+               g_io_channel_unref(captive_vfs_parent_object->corba_parent_giochanel_blind_source);
+               captive_vfs_parent_object->corba_parent_giochanel_blind_source=NULL;
+               }
+
+       return r;
 }
 
 
 static GnomeVFSResult captive_vfs_parent_commit(CaptiveVfsObject *captive_vfs_object)
 {
 CaptiveVfsParentObject *captive_vfs_parent_object;
+GnomeVFSResult r;
+gint retried=0;
 
        g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
 
        captive_vfs_parent_object=CAPTIVE_VFS_PARENT_OBJECT(captive_vfs_object);
 
-       return captive_sandbox_parent_vfs_commit(captive_vfs_parent_object);
+       do {
+               if (captive_vfs_parent_object->corba_Vfs_object==CORBA_OBJECT_NIL
+                               && GNOME_VFS_OK!=(r=captive_vfs_parent_object_connect_silent(captive_vfs_parent_object)))
+                       return r;
+               if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
+                               !=(r=captive_sandbox_parent_vfs_commit(captive_vfs_parent_object)))
+                       return r;
+               } while (!retried++);
+       return r;
 }
 
 
@@ -138,11 +224,99 @@ static GnomeVFSResult captive_vfs_parent_volume_info_get
                (CaptiveVfsObject *captive_vfs_object,CaptiveVfsVolumeInfo *volume_info)
 {
 CaptiveVfsParentObject *captive_vfs_parent_object;
+GnomeVFSResult r;
+gint retried=0;
 
        g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(volume_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
        captive_vfs_parent_object=CAPTIVE_VFS_PARENT_OBJECT(captive_vfs_object);
 
-       return captive_sandbox_parent_vfs_volume_info_get(captive_vfs_parent_object,volume_info);
+       do {
+               if (captive_vfs_parent_object->corba_Vfs_object==CORBA_OBJECT_NIL
+                               && GNOME_VFS_OK!=(r=captive_vfs_parent_object_connect(captive_vfs_parent_object)))
+                       return r;
+               if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
+                               !=(r=captive_sandbox_parent_vfs_volume_info_get(captive_vfs_parent_object,volume_info)))
+                       return r;
+               } while (!retried++);
+       return r;
+}
+
+
+GnomeVFSResult captive_vfs_parent_object_connect(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+       g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       g_return_val_if_fail(captive_vfs_parent_object->corba_Vfs_object==CORBA_OBJECT_NIL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       return captive_sandbox_parent_vfs_new(captive_vfs_parent_object);
+}
+
+
+static GnomeVFSResult captive_vfs_parent_object_connect_silent(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+       g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       g_return_val_if_fail(captive_vfs_parent_object->corba_Vfs_object==CORBA_OBJECT_NIL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       return captive_sandbox_parent_vfs_new_silent(captive_vfs_parent_object);
+}
+
+
+GnomeVFSResult captive_vfs_parent_object_disconnect(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+GnomeVFSResult r;
+
+       g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       g_return_val_if_fail(captive_vfs_parent_object->corba_Vfs_object!=CORBA_OBJECT_NIL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       /* Detach all connectors: */
+       g_signal_emit_by_name(captive_vfs_parent_object,"detach");
+
+       /* Some connector detaching broke the connection? */
+       if (captive_vfs_parent_object->corba_Vfs_object==CORBA_OBJECT_NIL) {
+               /* "abort" should have been emitted by captive_vfs_parent_object_aborted() */
+               return GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE;
+               }
+
+       if (GNOME_VFS_OK!=(r=captive_sandbox_parent_vfs_close(captive_vfs_parent_object))) {
+               /* Some non-ORBit shutdown error may have occured: */
+               g_signal_emit_by_name(captive_vfs_parent_object,"abort");
+               return r;
+               }
+
+       /* success: */
+       g_signal_emit_by_name(captive_vfs_parent_object,"cease");
+
+       return GNOME_VFS_OK;
+}
+
+
+GnomeVFSResult captive_vfs_parent_object_aborted(CaptiveVfsParentObject *captive_vfs_parent_object)
+{
+static gint inside=0;
+GnomeVFSResult r;
+
+       g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       g_return_val_if_fail(captive_vfs_parent_object->corba_Vfs_object!=CORBA_OBJECT_NIL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       /* Prevent looping by COMM_FAILURE of 'unmount' operation
+        * by captive_sandbox_parent_vfs_close().
+        */
+       g_assert(inside>=0);
+       if (inside)
+               return GNOME_VFS_OK;
+       inside++;
+
+       g_signal_emit_by_name(captive_vfs_parent_object,"abort");
+
+       r=captive_sandbox_parent_vfs_close(captive_vfs_parent_object);
+
+       g_assert(inside==1);
+       inside--;
+
+       return r;
 }