+Workaround Linux kernel last device block inaccessibility.
authorshort <>
Sat, 6 Dec 2003 14:04:54 +0000 (14:04 +0000)
committershort <>
Sat, 6 Dec 2003 14:04:54 +0000 (14:04 +0000)
 - It may be causing auto-chkdsk / W2000 BSOD, unconfirmed yet.

22 files changed:
src/client/gnomevfs/giognomevfs.c
src/libcaptive/client/Makefile.am
src/libcaptive/client/giochannel-blind.c
src/libcaptive/client/giochannel-blind.h
src/libcaptive/client/giochannel-subrange.c [new file with mode: 0644]
src/libcaptive/client/giochannel-subrange.h [new file with mode: 0644]
src/libcaptive/client/init.c
src/libcaptive/client/lib.c
src/libcaptive/client/lib.h
src/libcaptive/client/vfs-parent.c
src/libcaptive/client/vfs-parent.h
src/libcaptive/client/vfs.c
src/libcaptive/sandbox/client-CaptiveIOChannel.c
src/libcaptive/sandbox/split.c
src/libcaptive/storage/Makefile.am
src/libcaptive/storage/iounixchannel.c [new file with mode: 0644]
src/libcaptive/storage/iounixchannel.h [new file with mode: 0644]
src/libcaptive/storage/media.h
src/libcaptive/storage/relastblock.c [new file with mode: 0644]
src/libcaptive/storage/relastblock.h [new file with mode: 0644]
src/libcaptive/storage/size.c
src/libcaptive/storage/size.h [new file with mode: 0644]

index c6d66d6..23ba237 100644 (file)
@@ -25,7 +25,7 @@
 #include <glib/gmessages.h>
 #include "gnome-vfs-module.h"
 #include "captive/options.h"
-#include "../../libcaptive/client/giochannel-blind.h"  /* for captive_giochannel_setup(); FIXME: pathname */
+#include "../../libcaptive/client/lib.h"       /* for captive_giochannel_setup(); FIXME: pathname */
 
 
 /* FIXME: fill 'err' */
index 6eeba24..ea4f66c 100644 (file)
@@ -35,6 +35,8 @@ libclient_la_SOURCES= \
                file.h \
                giochannel-blind.c \
                giochannel-blind.h \
+               giochannel-subrange.c \
+               giochannel-subrange.h \
                init.c \
                init.h \
                leave.c \
index a766841..5590eb4 100644 (file)
@@ -33,6 +33,7 @@
 #ifdef HAVE_LIBXML_BUFFERING
 #include <libxml/xmlreader.h>
 #endif
+#include "lib.h"       /* for captive_giochannel_setup(); FIXME: pathname */
 
 
 /* CONFIG: */
@@ -45,7 +46,7 @@
 
 struct captive_giochannel_blind {
        GIOChannel iochannel;
-       GIOChannel *giochannel_orig;
+       GIOChannel *giochannel_orig;    /* reffed by us */
        guint64 offset; /* gint64 range */
        guint64 size;
        GHashTable *buffer_hash;        /* (guint64 *) -> (struct blind_block *)  (guint8[GIOCHANNEL_BLIND_BLOCK_SIZE]) */
@@ -356,11 +357,13 @@ GIOStatus erriostatus;
        g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
 
        if (giochannel_blind->giochannel_orig) {
-               /* We are not authorized to destroy 'giochannel_blind->giochannel_orig'. */
+               /* Just a sanity if 'giochannel_orig' is already falsely reffed a bit more... */
                erriostatus=g_io_channel_flush(
                                giochannel_blind->giochannel_orig,      /* channel */
                                NULL);  /* error */
                g_assert(erriostatus==G_IO_STATUS_NORMAL);
+
+               g_io_channel_unref(giochannel_blind->giochannel_orig);
                giochannel_blind->giochannel_orig=NULL;
                }
 
@@ -422,26 +425,6 @@ struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_bli
        return g_io_channel_get_flags(giochannel_blind->giochannel_orig) | G_IO_FLAG_IS_WRITEABLE;
 }
 
-void captive_giochannel_setup(GIOChannel *giochannel)
-{
-GIOStatus erriostatus;
-
-       g_return_if_fail(giochannel!=NULL);
-
-       if (g_io_channel_get_encoding(giochannel)) {
-               if (!g_io_channel_get_buffered(giochannel))     /* Prevent: Need to have NULL encoding to set the buffering state ... */
-                       g_io_channel_set_buffered(giochannel,TRUE);     /* Prevent: Need to set the channel buffered before setting the encoding. */
-               erriostatus=g_io_channel_set_encoding(giochannel,
-                               NULL,   /* encoding; force binary data */
-                               NULL);  /* error */
-               g_assert(erriostatus==G_IO_STATUS_NORMAL);
-               }
-       erriostatus=g_io_channel_flush(giochannel,
-                       NULL);  /* error */
-       g_assert(erriostatus==G_IO_STATUS_NORMAL);
-       g_io_channel_set_buffered(giochannel,FALSE);
-}
-
 
 struct captive_giochannel_blind *captive_giochannel_blind_new(GIOChannel *giochannel_orig,gboolean writeable)
 {
@@ -463,6 +446,8 @@ struct captive_giochannel_blind *giochannel_blind;
        if (giochannel_orig)
                captive_giochannel_setup(giochannel_orig);
 
+       g_io_channel_ref(giochannel_orig);
+
        captive_new(giochannel_blind);
        g_assert(G_STRUCT_OFFSET(struct captive_giochannel_blind,iochannel)==0);        /* safely re-type-able */
        g_io_channel_init(&giochannel_blind->iochannel);
index 6ae610d..b97ca7e 100644 (file)
@@ -36,7 +36,6 @@ struct captive_giochannel_blind *captive_giochannel_blind_new(GIOChannel *giocha
 gboolean captive_giochannel_blind_get_size(GIOChannel *giochannel,guint64 *size_return);
 GIOStatus captive_giochannel_blind_commit(GIOChannel *giochannel_blind);
 xmlNode *captive_giochannel_blind_readreport_to_xml(xmlNode *xml_parent,GIOChannel *giochannel);
-void captive_giochannel_setup(GIOChannel *giochannel);
 #ifdef HAVE_LIBXML_BUFFERING
 struct captive_giochannel_blind *captive_giochannel_blind_new_from_xml(xmlTextReader *xml_reader);
 #endif
diff --git a/src/libcaptive/client/giochannel-subrange.c b/src/libcaptive/client/giochannel-subrange.c
new file mode 100644 (file)
index 0000000..3f34516
--- /dev/null
@@ -0,0 +1,277 @@
+/* $Id$
+ * glib GIOChannel mapping subrange of parent GIOChannel for libcaptive
+ * Copyright (C) 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
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include "giochannel-subrange.h"
+#include <glib/gmessages.h>
+#include "captive/macros.h"
+#include "captive/storage.h"
+#include <ctype.h>
+#include "lib.h"       /* for captive_giochannel_setup() */
+
+
+/* FIXME: fill 'err' */
+
+struct captive_giochannel_subrange {
+       GIOChannel iochannel;
+       GIOChannel *giochannel_orig;    /* reffed by us */
+       guint64 offset; /* gint64 range; read start+offset from 'giochannel_orig' */
+       guint64 start,end;
+       };
+
+
+G_LOCK_DEFINE_STATIC(giochannel_subrange_funcs);
+static GIOFuncs giochannel_subrange_funcs;
+
+
+static gboolean validate_giochannel_subrange(struct captive_giochannel_subrange *giochannel_subrange)
+{
+       g_return_val_if_fail(giochannel_subrange->iochannel.funcs==&giochannel_subrange_funcs,FALSE);
+       g_return_val_if_fail(giochannel_subrange!=NULL,FALSE);
+       g_return_val_if_fail(giochannel_subrange->giochannel_orig!=NULL,FALSE);
+       g_return_val_if_fail((gint64)giochannel_subrange->offset>=0,FALSE);     /* gint64 overflow stored in guint64 */
+       g_return_val_if_fail(giochannel_subrange->start<=giochannel_subrange->end,FALSE);
+       g_return_val_if_fail(giochannel_subrange->offset<=(giochannel_subrange->end-giochannel_subrange->start),FALSE);
+
+       return TRUE;
+}
+
+
+static GIOStatus captive_giochannel_subrange_io_read
+               (GIOChannel *channel,gchar *buf,gsize count,gsize *bytes_read,GError **err)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+GIOStatus errgiostatus;
+
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),G_IO_STATUS_ERROR);
+       g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
+       g_return_val_if_fail(bytes_read!=NULL,G_IO_STATUS_ERROR);
+
+       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: read(offset=0x%llX,count=0x%lX)",G_STRLOC,
+                       giochannel_subrange->offset,(gulong)count);
+
+       errgiostatus=g_io_channel_seek_position(
+                       giochannel_subrange->giochannel_orig,   /* channel */
+                       giochannel_subrange->start+giochannel_subrange->offset, /* offset */
+                       G_SEEK_SET,     /* type */
+                       err);   /* error */
+       /* During seek in block device such as on URL file:///dev/hda1#captive-fastfat.sys-ro:/
+        * we will do llseek(2) on "/dev/hda1" device from captive_giochannel_size().
+        * Although we are allowed to seek behind EOF on regular files
+        * at least linux-kernel-2.4.19-ac4/fs/block_dev.c/block_llseek() will give
+        * EINVAL on seek behind EOF therefore it must be accepted without complaints by us.
+        */
+       if (errgiostatus!=G_IO_STATUS_NORMAL) {
+               errgiostatus=G_IO_STATUS_EOF;
+               *bytes_read=0;
+               }
+       else {
+               errgiostatus=g_io_channel_read_chars(
+                               giochannel_subrange->giochannel_orig,   /* channel */
+                               buf,    /* buf */
+                               count,  /* count */
+                               bytes_read,     /* bytes_read */
+                               err);   /* error */
+               }
+       g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL || errgiostatus==G_IO_STATUS_EOF,errgiostatus);
+       g_return_val_if_fail(*bytes_read<=count,G_IO_STATUS_ERROR);
+       g_return_val_if_fail((errgiostatus==G_IO_STATUS_EOF)==(bytes_read==0),G_IO_STATUS_ERROR);
+
+       giochannel_subrange->offset+=*bytes_read;
+       return (*bytes_read == 0 ? G_IO_STATUS_EOF : G_IO_STATUS_NORMAL);
+}
+
+
+static GIOStatus captive_giochannel_subrange_io_write
+               (GIOChannel *channel,const gchar *buf,gsize count,gsize *bytes_written,GError **err)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+GIOStatus errgiostatus;
+
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),G_IO_STATUS_ERROR);
+       g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
+       g_return_val_if_fail(bytes_written!=NULL,G_IO_STATUS_ERROR);
+
+       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: write(offset=0x%llX,count=0x%lX)",G_STRLOC,
+                       giochannel_subrange->offset,(gulong)count);
+
+       g_return_val_if_fail(giochannel_subrange->start+giochannel_subrange->offset+count<=giochannel_subrange->end,
+                       G_IO_STATUS_ERROR);
+
+       errgiostatus=g_io_channel_seek_position(
+                       giochannel_subrange->giochannel_orig,   /* channel */
+                       giochannel_subrange->start+giochannel_subrange->offset, /* offset */
+                       G_SEEK_SET,     /* type */
+                       err);   /* error */
+       g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
+       errgiostatus=g_io_channel_write_chars(
+                       giochannel_subrange->giochannel_orig,   /* channel */
+                       buf,    /* buf */
+                       count,  /* count */
+                       bytes_written,  /* bytes_written */
+                       err);   /* error */
+       g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
+       g_return_val_if_fail(*bytes_written==count,G_IO_STATUS_ERROR);
+
+       giochannel_subrange->offset+=(*bytes_written);
+       return G_IO_STATUS_NORMAL;
+}
+
+
+static GIOStatus captive_giochannel_subrange_io_seek(GIOChannel *channel,gint64 offset,GSeekType type,GError **err)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),G_IO_STATUS_ERROR);
+
+       switch (type) {
+               case G_SEEK_CUR: giochannel_subrange->offset+=offset; break;
+               case G_SEEK_SET: giochannel_subrange->offset =offset; break;
+               case G_SEEK_END: giochannel_subrange->offset =(giochannel_subrange->end-giochannel_subrange->start)+offset; break;
+               default: g_return_val_if_reached(G_IO_STATUS_ERROR);
+               }
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),G_IO_STATUS_ERROR);      /* 'offset' overflow? */
+
+       return G_IO_STATUS_NORMAL;
+}
+
+
+static GIOStatus captive_giochannel_subrange_io_close(GIOChannel *channel,GError **err)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+GIOStatus erriostatus;
+
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),G_IO_STATUS_ERROR);
+
+       if (giochannel_subrange->giochannel_orig) {
+               /* Just a sanity if 'giochannel_orig' is already falsely reffed a bit more... */
+               erriostatus=g_io_channel_flush(
+                               giochannel_subrange->giochannel_orig,   /* channel */
+                               NULL);  /* error */
+               g_assert(erriostatus==G_IO_STATUS_NORMAL);
+
+               g_io_channel_unref(giochannel_subrange->giochannel_orig);
+               giochannel_subrange->giochannel_orig=NULL;
+               }
+
+       return G_IO_STATUS_NORMAL;
+}
+
+
+static GSource* captive_giochannel_subrange_io_create_watch(GIOChannel *channel,GIOCondition condition)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),NULL);
+
+       g_return_val_if_reached(NULL);  /* FIXME: NOT IMPLEMENTED YET */
+}
+
+
+static void captive_giochannel_subrange_io_free(GIOChannel *channel)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+
+       /* After captive_giochannel_subrange_io_close() 'giochannel_subrange'
+        * may be no longer valid for validate_giochannel_subrange(giochannel_subrange).
+        */
+       g_return_if_fail(giochannel_subrange!=NULL);
+
+       g_assert(giochannel_subrange->giochannel_orig==NULL);
+
+       g_free(giochannel_subrange);
+}
+
+
+static GIOStatus captive_giochannel_subrange_io_set_flags(GIOChannel *channel,GIOFlags flags,GError **err)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),G_IO_STATUS_ERROR);
+
+       return g_io_channel_set_flags(giochannel_subrange->giochannel_orig,flags,err);
+}
+
+
+static GIOFlags captive_giochannel_subrange_io_get_flags(GIOChannel *channel)
+{
+struct captive_giochannel_subrange *giochannel_subrange=(struct captive_giochannel_subrange *)channel;
+
+       g_return_val_if_fail(validate_giochannel_subrange(giochannel_subrange),0);
+
+       return g_io_channel_get_flags(giochannel_subrange->giochannel_orig);
+}
+
+
+struct captive_giochannel_subrange *captive_giochannel_subrange_new(GIOChannel *giochannel_orig,guint64 start,guint64 end)
+{
+struct captive_giochannel_subrange *giochannel_subrange;
+
+       g_return_val_if_fail(giochannel_orig!=NULL,NULL);
+       g_return_val_if_fail(start<=end,NULL);
+
+       G_LOCK(giochannel_subrange_funcs);
+       giochannel_subrange_funcs.io_read        =captive_giochannel_subrange_io_read;
+       giochannel_subrange_funcs.io_write       =captive_giochannel_subrange_io_write;
+       giochannel_subrange_funcs.io_seek        =captive_giochannel_subrange_io_seek;
+       giochannel_subrange_funcs.io_close       =captive_giochannel_subrange_io_close;
+       giochannel_subrange_funcs.io_create_watch=captive_giochannel_subrange_io_create_watch;
+       giochannel_subrange_funcs.io_free        =captive_giochannel_subrange_io_free;
+       giochannel_subrange_funcs.io_set_flags   =captive_giochannel_subrange_io_set_flags;
+       giochannel_subrange_funcs.io_get_flags   =captive_giochannel_subrange_io_get_flags;
+       G_UNLOCK(giochannel_subrange_funcs);
+
+       captive_giochannel_setup(giochannel_orig);
+
+       g_io_channel_ref(giochannel_orig);
+
+       captive_new(giochannel_subrange);
+       g_assert(G_STRUCT_OFFSET(struct captive_giochannel_subrange,iochannel)==0);     /* safely re-type-able */
+       g_io_channel_init(&giochannel_subrange->iochannel);
+       giochannel_subrange->iochannel.funcs=&giochannel_subrange_funcs;
+       giochannel_subrange->iochannel.is_seekable =!!(g_io_channel_get_flags(giochannel_orig) & G_IO_FLAG_IS_SEEKABLE);
+       giochannel_subrange->iochannel.is_readable =!!(g_io_channel_get_flags(giochannel_orig) & G_IO_FLAG_IS_READABLE);
+       giochannel_subrange->iochannel.is_writeable=!!(g_io_channel_get_flags(giochannel_orig) & G_IO_FLAG_IS_WRITEABLE);
+       giochannel_subrange->iochannel.close_on_unref=TRUE;     /* run g_io_channel_shutdown() flush on last unref */
+       giochannel_subrange->giochannel_orig=giochannel_orig;
+       giochannel_subrange->offset=0;
+       giochannel_subrange->start=start;
+       giochannel_subrange->end=end;
+
+       captive_giochannel_setup(&giochannel_subrange->iochannel);
+
+       return giochannel_subrange;
+}
+
+
+gboolean captive_giochannel_subrange_get_size(GIOChannel *giochannel,guint64 *size_return)
+{
+struct captive_giochannel_subrange *giochannel_subrange;
+
+       g_return_val_if_fail(giochannel!=NULL,FALSE);
+       g_return_val_if_fail(size_return!=NULL,FALSE);
+
+       if (giochannel->funcs!=&giochannel_subrange_funcs)
+               return FALSE;
+       giochannel_subrange=(struct captive_giochannel_subrange *)giochannel;
+
+       *size_return=giochannel_subrange->end-giochannel_subrange->start;
+       return TRUE;
+}
diff --git a/src/libcaptive/client/giochannel-subrange.h b/src/libcaptive/client/giochannel-subrange.h
new file mode 100644 (file)
index 0000000..314fccf
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id$
+ * Include file for glib GIOChannel mapping subrange of parent GIOChannel for libcaptive
+ * Copyright (C) 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
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _CAPTIVE_GNOMEVFS_GIOCHANNEL_SUBRANGE_H
+#define _CAPTIVE_GNOMEVFS_GIOCHANNEL_SUBRANGE_H 1
+
+
+#include <glib/giochannel.h>
+
+
+G_BEGIN_DECLS
+
+struct captive_giochannel_subrange;
+
+struct captive_giochannel_subrange *captive_giochannel_subrange_new(GIOChannel *giochannel_orig,guint64 start,guint64 end);
+gboolean captive_giochannel_subrange_get_size(GIOChannel *giochannel,guint64 *size_return);
+
+G_END_DECLS
+
+
+#endif /* _CAPTIVE_GNOMEVFS_GIOCHANNEL_SUBRANGE_H */
index e20eda6..7a963a0 100644 (file)
@@ -52,6 +52,7 @@
 #include <reactos/ddk/obfuncs.h>
 #include <syslog.h>
 #include "captive/macros.h"
+#include "../storage/relastblock.h"    /* for captive_storage_relastblock() */
 
 
 struct captive_options *captive_options;
@@ -335,11 +336,19 @@ gboolean errbool;
 
        captive_log_init(captive_options);
 
-       if (captive_options->rwmode==CAPTIVE_OPTION_RWMODE_BLIND)
-               captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(captive_options->image_iochannel,
+       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 */
-       else
-               captive_image_iochannel=captive_options->image_iochannel;
+               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().
@@ -534,21 +543,13 @@ GIOStatus erriostatus;
 
        IoShutdownRegisteredDevices();
 
-       /* libcaptive is not authorized to shutdown 'captive_image_channel'. */
+       /* 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_image_iochannel' may be blinded wrapper of 'captive_options->image_iochannel'. */
-       if (captive_image_iochannel!=captive_options->image_iochannel) {
-               erriostatus=g_io_channel_flush(
-                               captive_options->image_iochannel,       /* channel */
-                               NULL);  /* error */
-               g_assert(erriostatus==G_IO_STATUS_NORMAL);
-               g_io_channel_unref(captive_image_iochannel);
-               }
-
+       g_io_channel_unref(captive_image_iochannel);
        captive_image_iochannel=NULL;
 
        active=FALSE;
index 83aab0b..01bc7bf 100644 (file)
@@ -134,3 +134,24 @@ gchar *pathname_normalized;
 
        return GNOME_VFS_OK;
 }
+
+
+void captive_giochannel_setup(GIOChannel *giochannel)
+{
+GIOStatus erriostatus;
+
+       g_return_if_fail(giochannel!=NULL);
+
+       if (g_io_channel_get_encoding(giochannel)) {
+               if (!g_io_channel_get_buffered(giochannel))     /* Prevent: Need to have NULL encoding to set the buffering state ... */
+                       g_io_channel_set_buffered(giochannel,TRUE);     /* Prevent: Need to set the channel buffered before setting the encoding. */
+               erriostatus=g_io_channel_set_encoding(giochannel,
+                               NULL,   /* encoding; force binary data */
+                               NULL);  /* error */
+               g_assert(erriostatus==G_IO_STATUS_NORMAL);
+               }
+       erriostatus=g_io_channel_flush(giochannel,
+                       NULL);  /* error */
+       g_assert(erriostatus==G_IO_STATUS_NORMAL);
+       g_io_channel_set_buffered(giochannel,FALSE);
+}
index 1f8ec36..fa1fe6d 100644 (file)
 #include <glib/gmacros.h>
 #include "reactos/ntos/obtypes.h"      /* for OBJECT_ATTRIBUTES */
 #include <libgnomevfs/gnome-vfs-result.h>
+#include <glib/giochannel.h>
 
 
 G_BEGIN_DECLS
 
 GnomeVFSResult captive_ObjectAttributes_init(const gchar *pathname,OBJECT_ATTRIBUTES *ObjectAttributes);
+void captive_giochannel_setup(GIOChannel *giochannel);
 
 G_END_DECLS
 
index 5f400c1..40801ef 100644 (file)
@@ -189,6 +189,11 @@ GnomeVFSResult r;
        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;
 }
 
index 92c2405..1ec1f38 100644 (file)
@@ -53,7 +53,8 @@ struct _CaptiveVfsParentObject {
        /* It may corba_parent_giochanel_blind_source==options.image_iochannel !
         * 1st stage           : corba_parent_giochanel_blind
         * 2nd stage (optional): corba_parent_giochanel_blind_source
-        * 3rd stage           : options.image_iochannel
+        * 3rd stage (optional): captive_storage_relastblock(options.image_iochannel)
+        * 4rd stage           : options.image_iochannel
         */
        GIOChannel *corba_parent_giochanel_blind;
        GIOChannel *corba_parent_giochanel_blind_source;
index f29d37c..4f607aa 100644 (file)
@@ -25,7 +25,7 @@
 #include "vfs-parent.h"
 #include "vfs-slave.h"
 #include "init.h"
-#include "giochannel-blind.h"  /* for captive_giochannel_setup() */
+#include "lib.h"       /* for captive_giochannel_setup() */
 #include <unistd.h>
 #include <string.h>
 
@@ -101,7 +101,7 @@ int fd;
                /* Shameless advertisement: */
                for (fd=2 /* STDERR */;fd>=1 /* STDOUT */;fd--) {
                        if (isatty(fd)) {
-const gchar *msg="Captive NTFS v" VERSION ".  Check new version: http://www.jankratochvil.net/\n";
+const gchar *msg="Captive NTFS v" VERSION ".  Check a new version at: http://www.jankratochvil.net/\n";
 
                                write(fd,msg,strlen(msg));
                                break;
index a18c0eb..17faf8d 100644 (file)
@@ -24,7 +24,7 @@
 #include "split.h"
 #include <string.h>
 #include "captive/macros.h"
-#include "../client/giochannel-blind.h"        /* for captive_giochannel_setup() */
+#include "../client/lib.h"     /* for captive_giochannel_setup() */
 
 
 struct captive_io_channel {
index f9da17a..d58c8ee 100644 (file)
@@ -37,6 +37,7 @@
 #include <errno.h>
 #include "../client/giochannel-blind.h"        /* for captive_giochannel_blind_new() */
 #include <signal.h>
+#include "../storage/relastblock.h"    /* for captive_storage_relastblock() */
 
 #ifdef HAVE_ORBIT_LINK
 void link_set_tmpdir(const char *dir);
@@ -652,19 +653,32 @@ int errint;
        g_assert(validate_CORBA_Environment(&captive_corba_ev));
 
        /* Init 'CaptiveIOChannel_object' */
-       if (!captive_vfs_parent_object->corba_parent_giochanel_blind_source)
+       if (!captive_vfs_parent_object->corba_parent_giochanel_blind_source) {
+GIOChannel *giochannel;
+
+               giochannel=CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.image_iochannel;
+               g_io_channel_ref(giochannel);
+
+               giochannel=captive_storage_relastblock(giochannel);
+
                switch (CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.rwmode) {
                        case CAPTIVE_OPTION_RWMODE_RO:
                        case CAPTIVE_OPTION_RWMODE_RW:
-                               captive_vfs_parent_object->corba_parent_giochanel_blind_source=CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.image_iochannel;
                                break;
-                       case CAPTIVE_OPTION_RWMODE_BLIND:
-                               captive_vfs_parent_object->corba_parent_giochanel_blind_source=(GIOChannel *)captive_giochannel_blind_new(
-                                               CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.image_iochannel, /* giochannel_orig */
+                       case CAPTIVE_OPTION_RWMODE_BLIND: {
+GIOChannel *giochannel_orig;
+
+                               giochannel_orig=giochannel;
+                               giochannel=(GIOChannel *)captive_giochannel_blind_new(
+                                               giochannel,     /* giochannel_orig */
                                                TRUE); /* writeable */
-                               break;
+                               g_io_channel_unref(giochannel_orig);    /* reffed by captive_giochannel_blind_new() */
+                               } break;
                        default: g_assert_not_reached();
                        }
+               captive_vfs_parent_object->corba_parent_giochanel_blind_source=giochannel;
+               }
+
        if (!captive_vfs_parent_object->corba_parent_giochanel_blind)
                captive_vfs_parent_object->corba_parent_giochanel_blind=(GIOChannel *)captive_giochannel_blind_new(
                                captive_vfs_parent_object->corba_parent_giochanel_blind_source,  /* giochannel_orig */
index 2205af3..555f698 100644 (file)
@@ -23,8 +23,12 @@ noinst_LTLIBRARIES=libstorage.la
 libstorage_la_SOURCES= \
                cdrom.c \
                disk.c \
+               iounixchannel.c \
+               iounixchannel.h \
+               relastblock.c \
+               relastblock.h \
                media.c \
                media.h \
                size.c
-libstorage_la_CFLAGS= \
-               $(LIBXML_CFLAGS)
+libstorage_la_CFLAGS=$(GNOME_VFS_MODULE_CFLAGS) $(LIBXML_CFLAGS)
+libstorage_la_LIBADD=$(GNOME_VFS_MODULE_LIBS)
diff --git a/src/libcaptive/storage/iounixchannel.c b/src/libcaptive/storage/iounixchannel.c
new file mode 100644 (file)
index 0000000..1bf3f6a
--- /dev/null
@@ -0,0 +1,59 @@
+/* $Id$
+ * Detect file descriptor of a given GIOUnixChannel for libcaptive
+ * Copyright (C) 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
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include "iounixchannel.h"     /* self */
+#include <glib/gmessages.h>
+#include <glib/giochannel.h>
+#include <glib/gtypes.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+static GIOChannel *iochannel_null;
+
+int captive_iounixchannel_get_fd(GIOChannel *iochannel)
+{
+int r;
+
+       g_return_val_if_fail(iochannel!=NULL,-1);
+
+       if (!iochannel_null) {
+int fd;
+
+               fd=open("/dev/null",O_RDONLY);
+               g_return_val_if_fail(fd!=-1,-1);
+               iochannel_null=g_io_channel_unix_new(fd);
+               g_return_val_if_fail(iochannel_null!=NULL,-1);
+               }
+
+       if (iochannel->funcs!=iochannel_null->funcs) {
+               /* Not a UNIX file descriptor */
+               return -1;
+               }
+
+       /* It is forbidden to callg_io_channel_unix_get_fd()
+        * if you are not sure it is a 'GIOUnixChannel'.
+        */
+       r=g_io_channel_unix_get_fd(iochannel);
+       g_return_val_if_fail(r!=-1,-1);
+
+       return r;
+}
diff --git a/src/libcaptive/storage/iounixchannel.h b/src/libcaptive/storage/iounixchannel.h
new file mode 100644 (file)
index 0000000..c88eb9f
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Id$
+ * Include file to detect file descriptor of a given GIOUnixChannel for libcaptive
+ * Copyright (C) 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
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _CAPTIVE_STORAGE_IOUNIXCHANNEL_H
+#define _CAPTIVE_STORAGE_IOUNIXCHANNEL_H 1
+
+
+#include <glib/giochannel.h>
+#include "reactos/ddk/iotypes.h"       /* for DRIVER_OBJECT */
+#include "reactos/ddk/ntddscsi.h"      /* for IO_SCSI_CAPABILITIES */
+
+
+G_BEGIN_DECLS
+
+int captive_iounixchannel_get_fd(GIOChannel *iochannel);
+
+G_END_DECLS
+
+
+#endif /* _CAPTIVE_STORAGE_IOUNIXCHANNEL_H */
index f3210d3..67d8d75 100644 (file)
@@ -17,8 +17,8 @@
  */
 
 
-#ifndef _CAPTIVE_CLIENT_MEDIA_H
-#define _CAPTIVE_CLIENT_MEDIA_H 1
+#ifndef _CAPTIVE_STORAGE_MEDIA_H
+#define _CAPTIVE_STORAGE_MEDIA_H 1
 
 
 #include <glib/gmacros.h>
@@ -48,4 +48,4 @@ NTSTATUS captive_media_DriverEntry(struct captive_DriverObject *captive_DriverOb
 G_END_DECLS
 
 
-#endif /* _CAPTIVE_CLIENT_MEDIA_H */
+#endif /* _CAPTIVE_STORAGE_MEDIA_H */
diff --git a/src/libcaptive/storage/relastblock.c b/src/libcaptive/storage/relastblock.c
new file mode 100644 (file)
index 0000000..903d838
--- /dev/null
@@ -0,0 +1,200 @@
+/* $Id$
+ * Workaround Linux kernel bug wrt accessing last device block for libcaptive
+ * Copyright (C) 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
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include "iounixchannel.h"     /* self */
+#include <glib/gmessages.h>
+#include <glib/giochannel.h>
+#include <glib/gtypes.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "size.h"
+#include <linux/hdreg.h>
+#include <sys/ioctl.h>
+#include "captive/macros.h"
+#include <ctype.h>
+#include "../client/lib.h"     /* for captive_giochannel_setup(); FIXME: pathname */
+#include "../client/giochannel-subrange.h"
+#include "captive/storage.h"   /* for captive_giochannel_size() */
+
+
+/* Config */
+#define ENSURE_BLOCK_SIZE 0x200        /* size of the NTFS 'superblock backup' */
+
+
+
+gboolean start_bytes_ioctl_detect(int fd,guint64 *start_bytes_ioctlp)
+{
+struct hd_geometry hd_geometry;
+#ifdef HDIO_GETGEO_BIG
+struct hd_big_geometry hd_big_geometry;
+#endif
+unsigned long start_sectors_ioctl;
+
+       /* 'start' field is always 'unsigned long'.
+        * 'HDIO_GETGEO_BIG' is supported if 'HDIO_GETGEO' gets deprecated.
+        */
+       if (0)
+               /* nop */;
+#ifdef HDIO_GETGEO_BIG
+       else if (!ioctl(fd,HDIO_GETGEO_BIG,&hd_big_geometry))
+               start_sectors_ioctl=hd_big_geometry.start;
+#endif
+       else if (!ioctl(fd,HDIO_GETGEO,&hd_geometry))
+               start_sectors_ioctl=hd_geometry.start;
+       else
+               return FALSE;
+
+       *start_bytes_ioctlp=((guint64)start_sectors_ioctl)*0x200;
+       return TRUE;
+}
+
+static gboolean check_last_block(GIOChannel *iochannel,guint64 iochannel_size)
+{
+GIOStatus erriostatus;
+gchar buf[ENSURE_BLOCK_SIZE];
+gsize bufgot;
+
+       g_return_val_if_fail(iochannel!=NULL,FALSE);
+       g_return_val_if_fail(iochannel_size>0,FALSE);
+
+       erriostatus=g_io_channel_seek_position(iochannel,iochannel_size-ENSURE_BLOCK_SIZE,G_SEEK_SET,
+                       NULL);  /* error */
+       g_assert(erriostatus==G_IO_STATUS_NORMAL);
+
+       erriostatus=g_io_channel_read_chars(iochannel,
+                       buf, /* buf */
+                       ENSURE_BLOCK_SIZE,      /* count */
+                       &bufgot,        /* bytes_read */
+                       NULL);  /* error */
+       /* During read on the end boundary of Linux kernel block device we will
+        * get GNOME_VFS_ERROR_IO at least from linux-kernel-2.4.19-ac4
+        * which will get mapped to G_IO_STATUS_ERROR by captive_gnomevfs_giognomevfs_io_read().
+        */
+       g_assert(0
+                       || (bufgot==ENSURE_BLOCK_SIZE && erriostatus==G_IO_STATUS_NORMAL)
+                       || (bufgot==0                 && erriostatus==G_IO_STATUS_EOF)
+                       || (bufgot==0                 && erriostatus==G_IO_STATUS_ERROR));
+
+       return (erriostatus==G_IO_STATUS_NORMAL);
+}
+
+/* No new reference is created; unref the result the same way as the input. */
+GIOChannel *captive_storage_relastblock(GIOChannel *iochannel)
+{
+int fd;
+guint64 size_bytes_ioctl;
+guint64 start_bytes_ioctl;
+char linkbuf[0x1000],*linknum;
+int linkgot;
+const gchar *iochannel_unix_new_mode;
+const gchar *linkread_pathname;
+const gchar *slashpart_prefix;
+gboolean errbool;
+GIOFlags iochannel_flags;
+GIOChannel *iochannel_unix_new;
+int iochannel_unix_new_fd;
+guint64 unix_new_start_bytes_ioctl,unix_new_size_bytes_ioctl;
+GIOChannel *iochannel_subrange_new;
+
+       g_return_val_if_fail(iochannel!=NULL,NULL);
+
+       if (-1==(fd=captive_iounixchannel_get_fd(iochannel)))
+               return iochannel;
+
+       if (ENSURE_BLOCK_SIZE>(size_bytes_ioctl=captive_giochannel_size_ioctl(iochannel)))
+               return iochannel;
+
+       g_return_val_if_fail(g_io_channel_get_encoding(iochannel)==NULL,0);
+
+       if (!start_bytes_ioctl_detect(fd,&start_bytes_ioctl))
+               return iochannel;
+
+       if (check_last_block(iochannel,size_bytes_ioctl))
+               return iochannel;
+
+       linkread_pathname=captive_printf_alloca("/proc/self/fd/%d",fd);
+       linkgot=readlink(
+                       linkread_pathname,      /* path */
+                       linkbuf,        /* buf */
+                       sizeof(linkbuf));       /* bufsiz */
+       if (!(linkgot>=1 && linkgot<=(int)sizeof(linkbuf)-1))
+               g_error(_("Unable to read: %s"),linkread_pathname);
+       linkbuf[linkgot]=0;     /* readlink(2) does not '\0'-terminate it */
+
+       for (linknum=linkbuf+linkgot;linknum>linkbuf && isdigit(linknum[-1]);linknum--);
+       if (linknum>=linkbuf+linkgot)
+               g_error(_("Last block not readable although the link read has no trailing number: %s"),linkbuf);
+       *linknum='\0';
+
+       /* /dev/ide/host0/bus0/target0/lun0/part1 -> /dev/ide/host0/bus0/target0/lun0/disc */
+       slashpart_prefix="/part";
+       if (!strcmp(linknum-strlen(slashpart_prefix),slashpart_prefix))
+               strcpy(linknum-strlen(slashpart_prefix),"/disc");
+
+       iochannel_flags=g_io_channel_get_flags(iochannel);
+       switch (iochannel_flags & (G_IO_FLAG_IS_READABLE|G_IO_FLAG_IS_WRITEABLE)) {
+               case G_IO_FLAG_IS_READABLE:
+                       iochannel_unix_new_mode="r";
+                       break;
+               case G_IO_FLAG_IS_READABLE|G_IO_FLAG_IS_WRITEABLE:
+                       iochannel_unix_new_mode="r+";
+                       break;
+               default: g_assert_not_reached();
+               }
+
+       iochannel_unix_new=g_io_channel_new_file(
+                       linkbuf,        /* filename */
+                       iochannel_unix_new_mode,        /* mode */
+                       NULL);  /* error */
+       g_assert(iochannel_unix_new!=NULL);
+
+       /* 'iochannel_unix_new' sanity checks: */
+       iochannel_unix_new_fd=captive_iounixchannel_get_fd(iochannel_unix_new);
+       g_assert(iochannel_unix_new_fd>=0);
+       errbool=start_bytes_ioctl_detect(iochannel_unix_new_fd,&unix_new_start_bytes_ioctl);
+       g_assert(errbool==TRUE);
+       g_assert(unix_new_start_bytes_ioctl==0);
+       unix_new_size_bytes_ioctl=captive_giochannel_size_ioctl(iochannel_unix_new);
+       g_assert(unix_new_size_bytes_ioctl>0);
+       if (!(unix_new_size_bytes_ioctl>=start_bytes_ioctl+size_bytes_ioctl))
+               g_error(_("Partition last block inaccessible and partition table incorrect: disc size %llu < part start %llu + part size %llu"),
+               (unsigned long long)unix_new_size_bytes_ioctl,
+               (unsigned long long)start_bytes_ioctl,
+               (unsigned long long)size_bytes_ioctl);
+
+       iochannel_subrange_new=(GIOChannel *)captive_giochannel_subrange_new(iochannel_unix_new,
+                       start_bytes_ioctl,      /* start */
+                       start_bytes_ioctl+size_bytes_ioctl);    /* end */
+       g_assert(iochannel_subrange_new!=NULL);
+
+       g_io_channel_unref(iochannel_unix_new); /* now reffed by 'iochannel_subrange_new' */
+
+       captive_giochannel_setup(iochannel_subrange_new);
+       g_io_channel_unref(iochannel);
+
+       if (!check_last_block(iochannel_subrange_new,size_bytes_ioctl))
+               g_error(_("Last block still not readable for the subrange of: %s"),linkbuf);
+
+       if (size_bytes_ioctl!=captive_giochannel_size(iochannel_subrange_new))
+               g_error(_("Invalid size of the subranged GIOChannel of: %s"),linkbuf);
+
+       return iochannel_subrange_new;
+}
diff --git a/src/libcaptive/storage/relastblock.h b/src/libcaptive/storage/relastblock.h
new file mode 100644 (file)
index 0000000..9867d0a
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Id$
+ * Include file for workarounding Linux kernel bug wrt accessing last device block for libcaptive
+ * Copyright (C) 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
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _CAPTIVE_STORAGE_RELASTBLOCK_H
+#define _CAPTIVE_STORAGE_RELASTBLOCK_H 1
+
+
+#include <glib/giochannel.h>
+#include "reactos/ddk/iotypes.h"       /* for DRIVER_OBJECT */
+#include "reactos/ddk/ntddscsi.h"      /* for IO_SCSI_CAPABILITIES */
+
+
+G_BEGIN_DECLS
+
+GIOChannel *captive_storage_relastblock(GIOChannel *iochannel);
+
+G_END_DECLS
+
+
+#endif /* _CAPTIVE_STORAGE_RELASTBLOCK_H */
index b70af55..cab7f76 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "captive/storage.h"   /* self */
 #include "../client/giochannel-blind.h"        /* for captive_giochannel_blind_get_size() */
+#include "../client/giochannel-subrange.h"     /* for captive_giochannel_subrange_get_size() */
 #include "../sandbox/client-CaptiveIOChannel.h"        /* for captive_io_channel_get_size() */
 #include <glib/gmessages.h>
 #include <glib/gtypes.h>
  * as including any Linux kernel include files is too much incompatible.
  */
 #include <sys/mount.h> /* for 'BLKGETSIZE' */
+#include "iounixchannel.h"
 
 
-static guint64 size_blind(GIOChannel *iochannel)
+static guint64 size_subrange(GIOChannel *iochannel)
 {
 guint64 r;
 
        g_return_val_if_fail(iochannel!=NULL,0);
 
-       if (!captive_giochannel_blind_get_size(iochannel,&r))
+       if (!captive_giochannel_subrange_get_size(iochannel,&r))
                return 0;
 
        return r;
 }
 
 
-static guint64 size_sandbox(GIOChannel *iochannel)
+static guint64 size_blind(GIOChannel *iochannel)
 {
 guint64 r;
 
        g_return_val_if_fail(iochannel!=NULL,0);
 
-       if (!captive_io_channel_get_size(iochannel,&r))
+       if (!captive_giochannel_blind_get_size(iochannel,&r))
                return 0;
 
        return r;
 }
 
 
-static GIOChannel *iochannel_null;
-
-static int iounixchannel_get_fd(GIOChannel *iochannel)
+static guint64 size_sandbox(GIOChannel *iochannel)
 {
-int r;
-
-       g_return_val_if_fail(iochannel!=NULL,-1);
-
-       if (!iochannel_null) {
-int fd;
-
-               fd=open("/dev/null",O_RDONLY);
-               g_return_val_if_fail(fd!=-1,-1);
-               iochannel_null=g_io_channel_unix_new(fd);
-               g_return_val_if_fail(iochannel_null!=NULL,-1);
-               }
+guint64 r;
 
-       if (iochannel->funcs!=iochannel_null->funcs) {
-               /* Not a UNIX file descriptor */
-               return -1;
-               }
+       g_return_val_if_fail(iochannel!=NULL,0);
 
-       /* It is forbidden to callg_io_channel_unix_get_fd()
-        * if you are not sure it is a 'GIOUnixChannel'.
-        */
-       r=g_io_channel_unix_get_fd(iochannel);
-       g_return_val_if_fail(r!=-1,-1);
+       if (!captive_io_channel_get_size(iochannel,&r))
+               return 0;
 
        return r;
 }
 
 
-static guint64 size_ioctl(GIOChannel *iochannel)
+guint64 captive_giochannel_size_ioctl(GIOChannel *iochannel)
 {
 int fd;
 guint64 r;
@@ -99,7 +82,7 @@ long r_long;
 
        g_return_val_if_fail(iochannel!=NULL,0);
 
-       if (-1==(fd=iounixchannel_get_fd(iochannel)))
+       if (-1==(fd=captive_iounixchannel_get_fd(iochannel)))
                return 0;
 
 #ifdef BLKGETSIZE64
@@ -129,7 +112,7 @@ off_t offset_orig,offset;
         */
        g_return_val_if_fail(sizeof(offset)==sizeof(guint64),0);
 
-       if (-1==(fd=iounixchannel_get_fd(iochannel)))
+       if (-1==(fd=captive_iounixchannel_get_fd(iochannel)))
                return 0;
 
        if (-1==(offset_orig=lseek(fd,0,SEEK_CUR)))
@@ -217,11 +200,13 @@ guint64 captive_giochannel_size(GIOChannel *iochannel)
 {
 guint64 r;
 
+       if ((r=size_subrange(iochannel)))
+               return r;
        if ((r=size_blind(iochannel)))
                return r;
        if ((r=size_sandbox(iochannel)))
                return r;
-       if ((r=size_ioctl(iochannel)))
+       if ((r=captive_giochannel_size_ioctl(iochannel)))
                return r;
        if ((r=size_seek(iochannel)))
                return r;
diff --git a/src/libcaptive/storage/size.h b/src/libcaptive/storage/size.h
new file mode 100644 (file)
index 0000000..55f4c58
--- /dev/null
@@ -0,0 +1,34 @@
+/* $Id$
+ * Include file to detect media size of given GIOChannel for libcaptive
+ * Copyright (C) 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
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _CAPTIVE_STORAGE_SIZE_H
+#define _CAPTIVE_STORAGE_SIZE_H 1
+
+
+#include <glib/giochannel.h>
+
+
+G_BEGIN_DECLS
+
+guint64 captive_giochannel_size_ioctl(GIOChannel *iochannel);
+
+G_END_DECLS
+
+
+#endif /* _CAPTIVE_STORAGE_SIZE_H */