- It may be causing auto-chkdsk / W2000 BSOD, unconfirmed yet.
#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' */
file.h \
giochannel-blind.c \
giochannel-blind.h \
+ giochannel-subrange.c \
+ giochannel-subrange.h \
init.c \
init.h \
leave.c \
#ifdef HAVE_LIBXML_BUFFERING
#include <libxml/xmlreader.h>
#endif
+#include "lib.h" /* for captive_giochannel_setup(); FIXME: pathname */
/* CONFIG: */
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]) */
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;
}
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)
{
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);
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
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
#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;
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().
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;
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);
+}
#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
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;
}
/* 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;
#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>
/* 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;
#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 {
#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);
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 */
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)
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
*/
-#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>
G_END_DECLS
-#endif /* _CAPTIVE_CLIENT_MEDIA_H */
+#endif /* _CAPTIVE_STORAGE_MEDIA_H */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
#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;
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
*/
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)))
{
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;
--- /dev/null
+/* $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 */