+captive_giochannel_blind_commit()
authorshort <>
Fri, 4 Jul 2003 04:16:09 +0000 (04:16 +0000)
committershort <>
Fri, 4 Jul 2003 04:16:09 +0000 (04:16 +0000)
src/libcaptive/client/giochannel-blind.c
src/libcaptive/client/giochannel-blind.h

index 1615dd9..ff2518b 100644 (file)
 
 struct captive_giochannel_blind {
        GIOChannel iochannel;
-       GIOChannel *giochannel_ro;
+       GIOChannel *giochannel_orig;
        guint64 offset; /* gint64 range */
        guint64 size;
        GHashTable *buffer_hash;        /* (guint64 *) -> (struct blind_block *)  (guint8[GIOCHANNEL_BLIND_BLOCK_SIZE]) */
        };
 
 struct blind_block {
+       guint64 offset;
        gboolean was_read,was_written;
        guint8 *data_written;   /* [GIOCHANNEL_BLIND_BLOCK_SIZE] */
        };
@@ -51,11 +52,11 @@ G_LOCK_DEFINE_STATIC(giochannel_blind_funcs);
 static GIOFuncs giochannel_blind_funcs;
 
 
-static guint captive_giochannel_blind_hash_func(const guint64 *key)
+static guint captive_giochannel_blind_hash_func(const guint64 *keyp)
 {
-       g_return_val_if_fail(key!=NULL,0);
+       g_return_val_if_fail(keyp!=NULL,0);
 
-       return (*key)^((*key)>>23);
+       return (*keyp)^((*keyp)>>23);
 }
 
 static gboolean captive_giochannel_blind_equal_func(const guint64 *ap,const guint64 *bp)
@@ -66,11 +67,11 @@ static gboolean captive_giochannel_blind_equal_func(const guint64 *ap,const guin
        return (*ap)==(*bp);
 }
 
-static void captive_giochannel_blind_key_destroy_func(guint64 *key)
+static void captive_giochannel_blind_key_destroy_func(guint64 *keyp)
 {
-       g_return_if_fail(key!=NULL);
+       g_return_if_fail(keyp!=NULL);
 
-       g_free(key);
+       g_free(keyp);
 }
 
 static void captive_giochannel_blind_value_destroy_func(struct blind_block *blind_block)
@@ -84,8 +85,9 @@ static void captive_giochannel_blind_value_destroy_func(struct blind_block *blin
 
 static gboolean validate_giochannel_blind(struct captive_giochannel_blind *giochannel_blind)
 {
+       g_return_val_if_fail(giochannel_blind->iochannel.funcs==&giochannel_blind_funcs,FALSE);
        g_return_val_if_fail(giochannel_blind!=NULL,FALSE);
-       g_return_val_if_fail(giochannel_blind->giochannel_ro!=NULL,FALSE);
+       g_return_val_if_fail(giochannel_blind->giochannel_orig!=NULL,FALSE);
        g_return_val_if_fail((gint64)giochannel_blind->offset>=0,FALSE);        /* gint64 overflow stored in guint64 */
        g_return_val_if_fail(giochannel_blind->buffer_hash!=NULL,FALSE);
 
@@ -136,7 +138,7 @@ gsize bytes_read;
                                (guint64)window_now,(gulong)(transfer_bottom-giochannel_blind->offset),(guint64)transfer_bottom,
                                (gulong)(transfer_top-transfer_bottom));
                errgiostatus=g_io_channel_seek_position(
-                               giochannel_blind->giochannel_ro,        /* channel */
+                               giochannel_blind->giochannel_orig,      /* channel */
                                transfer_bottom,        /* offset */
                                G_SEEK_SET,     /* type */
                                err);   /* error */
@@ -152,7 +154,7 @@ gsize bytes_read;
                        }
                else {
                        errgiostatus=g_io_channel_read_chars(
-                                       giochannel_blind->giochannel_ro,        /* channel */
+                                       giochannel_blind->giochannel_orig,      /* channel */
                                        buf+transfer_bottom-giochannel_blind->offset,   /* buf */
                                        transfer_top-transfer_bottom,   /* count */
                                        &bytes_read,    /* bytes_read */
@@ -166,6 +168,7 @@ gsize bytes_read;
 guint64 *keyp;
 
                                captive_new(blind_block);
+                               blind_block->offset=window_now;
                                blind_block->was_read=FALSE;
                                blind_block->was_written=FALSE;
                                blind_block->data_written=NULL;
@@ -209,6 +212,8 @@ struct blind_block *blind_block;
 
        g_return_val_if_fail(giochannel_blind->offset+count<=giochannel_blind->size,G_IO_STATUS_ERROR);
 
+       g_return_val_if_fail(giochannel_blind->iochannel.is_writeable==TRUE,G_IO_STATUS_ERROR);
+
        window_bottom=CAPTIVE_ROUND_DOWN64(giochannel_blind->offset,GIOCHANNEL_BLIND_BLOCK_SIZE);
        window_top=CAPTIVE_ROUND_UP64(giochannel_blind->offset+count,GIOCHANNEL_BLIND_BLOCK_SIZE);
 
@@ -222,6 +227,7 @@ gsize bytes_read;
 guint64 *keyp;
 
                                captive_new(blind_block);
+                               blind_block->offset=window_now;
                                blind_block->was_read=FALSE;
                                blind_block->was_written=FALSE;
                                captive_new(keyp);
@@ -240,13 +246,13 @@ guint64 *keyp;
                                g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: write-mem-read-lower(seek=0x%llX,count=0x%lX)",G_STRLOC,
                                                (guint64)window_now,(gulong)(transfer_bottom-window_now));
                                errgiostatus=g_io_channel_seek_position(
-                                               giochannel_blind->giochannel_ro,        /* channel */
+                                               giochannel_blind->giochannel_orig,      /* channel */
                                                window_now,     /* offset */
                                                G_SEEK_SET,     /* type */
                                                err);   /* error */
                                g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
                                errgiostatus=g_io_channel_read_chars(
-                                               giochannel_blind->giochannel_ro,        /* channel */
+                                               giochannel_blind->giochannel_orig,      /* channel */
                                                blind_block->data_written,      /* buf */
                                                transfer_bottom-window_now,     /* count */
                                                &bytes_read,    /* bytes_read */
@@ -261,13 +267,13 @@ guint64 *keyp;
                                                (gulong)(transfer_top-window_now),(guint64)transfer_top,
                                                (gulong)(window_now+GIOCHANNEL_BLIND_BLOCK_SIZE-transfer_top));
                                errgiostatus=g_io_channel_seek_position(
-                                               giochannel_blind->giochannel_ro,        /* channel */
+                                               giochannel_blind->giochannel_orig,      /* channel */
                                                transfer_top,   /* offset */
                                                G_SEEK_SET,     /* type */
                                                err);   /* error */
                                g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
                                errgiostatus=g_io_channel_read_chars(
-                                               giochannel_blind->giochannel_ro,        /* channel */
+                                               giochannel_blind->giochannel_orig,      /* channel */
                                                blind_block->data_written+transfer_top-window_now,      /* buf */
                                                window_now+GIOCHANNEL_BLIND_BLOCK_SIZE-transfer_top,    /* count */
                                                &bytes_read,    /* bytes_read */
@@ -325,12 +331,12 @@ GIOStatus erriostatus;
 
        g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
 
-       /* We are not authorized to destroy 'giochannel_blind->giochannel_ro'. */
+       /* We are not authorized to destroy 'giochannel_blind->giochannel_orig'. */
        erriostatus=g_io_channel_flush(
-                       giochannel_blind->giochannel_ro,        /* channel */
+                       giochannel_blind->giochannel_orig,      /* channel */
                        NULL);  /* error */
        g_assert(erriostatus==G_IO_STATUS_NORMAL);
-       giochannel_blind->giochannel_ro=NULL;
+       giochannel_blind->giochannel_orig=NULL;
 
        g_hash_table_destroy(giochannel_blind->buffer_hash);
        giochannel_blind->buffer_hash=NULL;
@@ -358,7 +364,7 @@ struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_bli
         */
        g_return_if_fail(giochannel_blind!=NULL);
 
-       g_assert(giochannel_blind->giochannel_ro==NULL);
+       g_assert(giochannel_blind->giochannel_orig==NULL);
        g_assert(giochannel_blind->buffer_hash==NULL);
 
        g_free(giochannel_blind);
@@ -371,7 +377,7 @@ struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_bli
 
        g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
 
-       return g_io_channel_set_flags(giochannel_blind->giochannel_ro,(flags&~G_IO_FLAG_IS_WRITEABLE),err);
+       return g_io_channel_set_flags(giochannel_blind->giochannel_orig,(flags&~G_IO_FLAG_IS_WRITEABLE),err);
 }
 
 
@@ -381,16 +387,16 @@ struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_bli
 
        g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),0);
 
-       return g_io_channel_get_flags(giochannel_blind->giochannel_ro) | G_IO_FLAG_IS_WRITEABLE;
+       return g_io_channel_get_flags(giochannel_blind->giochannel_orig) | G_IO_FLAG_IS_WRITEABLE;
 }
 
 
-struct captive_giochannel_blind *captive_giochannel_blind_new(GIOChannel *giochannel_ro)
+struct captive_giochannel_blind *captive_giochannel_blind_new(GIOChannel *giochannel_orig,gboolean writeable)
 {
 struct captive_giochannel_blind *giochannel_blind;
 GIOStatus erriostatus;
 
-       g_return_val_if_fail(giochannel_ro!=NULL,NULL);
+       g_return_val_if_fail(giochannel_orig!=NULL,NULL);
 
        G_LOCK(giochannel_blind_funcs);
        giochannel_blind_funcs.io_read        =captive_giochannel_blind_io_read;
@@ -403,7 +409,7 @@ GIOStatus erriostatus;
        giochannel_blind_funcs.io_get_flags   =captive_giochannel_blind_io_get_flags;
        G_UNLOCK(giochannel_blind_funcs);
 
-       erriostatus=g_io_channel_set_encoding(giochannel_ro,
+       erriostatus=g_io_channel_set_encoding(giochannel_orig,
                        NULL,   /* encoding; force binary data */
                        NULL);  /* error */
        g_assert(erriostatus==G_IO_STATUS_NORMAL);
@@ -414,11 +420,12 @@ GIOStatus erriostatus;
        giochannel_blind->iochannel.funcs=&giochannel_blind_funcs;
        giochannel_blind->iochannel.is_seekable=TRUE;
        giochannel_blind->iochannel.is_readable=TRUE;
-       giochannel_blind->iochannel.is_writeable=TRUE;
+       /* readonly captive_giochannel_blind can be used to track read access. */
+       giochannel_blind->iochannel.is_writeable=writeable;
        giochannel_blind->iochannel.close_on_unref=TRUE;        /* run g_io_channel_shutdown() flush on last unref */
-       giochannel_blind->giochannel_ro=giochannel_ro;
+       giochannel_blind->giochannel_orig=giochannel_orig;
        giochannel_blind->offset=0;
-       giochannel_blind->size=captive_giochannel_size(giochannel_ro);
+       giochannel_blind->size=captive_giochannel_size(giochannel_orig);
        giochannel_blind->buffer_hash=g_hash_table_new_full(
                        (GHashFunc)captive_giochannel_blind_hash_func,  /* hash_func */
                        (GEqualFunc)captive_giochannel_blind_equal_func,        /* key_equal_func */
@@ -443,3 +450,96 @@ struct captive_giochannel_blind *giochannel_blind;
        *size_return=giochannel_blind->size;
        return TRUE;
 }
+
+
+static void captive_giochannel_blind_as_sorted_array_foreach
+               (const guint64 *keyp,const struct blind_block *blind_block,const struct blind_block ***rpp /* user_data */)
+{
+       g_return_if_fail(keyp!=NULL);
+       g_return_if_fail(blind_block!=NULL);
+       g_return_if_fail(rpp!=NULL);
+
+       if (!blind_block->data_written)
+               return;
+
+       *((*rpp)++)=blind_block;
+}
+
+static int captive_giochannel_blind_as_sorted_array_compat
+               (const struct blind_block *const *ap,const struct blind_block *const *bp)
+{
+       g_return_val_if_fail(ap!=NULL,0);
+       g_return_val_if_fail(*ap!=NULL,0);
+       g_return_val_if_fail(bp!=NULL,0);
+       g_return_val_if_fail(*bp!=NULL,0);
+
+       return ((*ap)->offset>(*bp)->offset) - ((*bp)->offset>(*ap)->offset);
+}
+
+static struct blind_block **captive_giochannel_blind_as_sorted_array(struct captive_giochannel_blind *giochannel_blind)
+{
+guint hash_size;
+struct blind_block **r,**rp;
+
+       g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
+
+       hash_size=g_hash_table_size(giochannel_blind->buffer_hash);
+       captive_newn(r,hash_size+1);
+       rp=r;
+       g_hash_table_foreach(giochannel_blind->buffer_hash,(GHFunc)captive_giochannel_blind_as_sorted_array_foreach,&rp);
+       g_assert(rp<=r+hash_size);
+       *rp=NULL;
+       qsort(r,rp-r,sizeof(*r),(int (*)(const void *,const void *))captive_giochannel_blind_as_sorted_array_compat);
+
+       return r;
+}
+
+GIOStatus captive_giochannel_blind_commit(GIOChannel *giochannel)
+{
+struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)giochannel;
+struct blind_block **blind_block_array,**blind_blockp;
+GIOStatus errgiostatus;
+
+       g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
+
+       errgiostatus=g_io_channel_flush(
+                       giochannel,     /* channel */
+                       NULL);  /* error */
+       g_assert(errgiostatus==G_IO_STATUS_NORMAL);
+
+       blind_block_array=captive_giochannel_blind_as_sorted_array(giochannel_blind);
+
+       for (blind_blockp=blind_block_array;*blind_blockp;blind_blockp++) {
+struct blind_block *blind_block=*blind_blockp;
+gsize bytes_written;
+
+               g_assert(blind_block->data_written!=NULL);
+
+               errgiostatus=g_io_channel_seek_position(
+                               giochannel_blind->giochannel_orig,      /* channel */
+                               blind_block->offset,    /* offset */
+                               G_SEEK_SET,     /* type */
+                               NULL);  /* error */
+               g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
+               errgiostatus=g_io_channel_write_chars(
+                               giochannel_blind->giochannel_orig,      /* channel */
+                               blind_block->data_written,      /* buf */
+                               GIOCHANNEL_BLIND_BLOCK_SIZE,    /* count */
+                               &bytes_written, /* bytes_written */
+                               NULL);  /* error */
+               g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
+               g_return_val_if_fail(bytes_written==GIOCHANNEL_BLIND_BLOCK_SIZE,G_IO_STATUS_ERROR);
+
+               g_free(blind_block->data_written);
+               blind_block->data_written=NULL;
+               }
+
+       g_free(blind_block_array);
+
+       errgiostatus=g_io_channel_flush(
+                       giochannel_blind->giochannel_orig,      /* channel */
+                       NULL);  /* error */
+       g_assert(errgiostatus==G_IO_STATUS_NORMAL);
+
+       return G_IO_STATUS_NORMAL;
+}
index f9eaaa7..6ce16f7 100644 (file)
@@ -28,8 +28,9 @@ G_BEGIN_DECLS
 
 struct captive_giochannel_blind;
 
-struct captive_giochannel_blind *captive_giochannel_blind_new(GIOChannel *giochannel_ro);
+struct captive_giochannel_blind *captive_giochannel_blind_new(GIOChannel *giochannel_ro,gboolean writeable);
 gboolean captive_giochannel_blind_get_size(GIOChannel *giochannel,guint64 *size_return);
+GIOStatus captive_giochannel_blind_commit(GIOChannel *giochannel_blind);
 
 G_END_DECLS