2 * glib r/w GIOChannel buffered-over r/o GIOChannel for libcaptive
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "giochannel-blind.h"
23 #include "reactos/internal/mm.h" /* for PAGE_SIZE */
24 #include <glib/ghash.h>
25 #include <glib/gmessages.h>
26 #include "captive/macros.h"
27 #include "captive/storage.h"
28 #include <openssl/bn.h>
29 #include <openssl/crypto.h>
30 #include <libxml/tree.h>
34 #define GIOCHANNEL_BLIND_BLOCK_SIZE (PAGE_SIZE)
37 /* FIXME: fill 'err' */
39 struct captive_giochannel_blind {
41 GIOChannel *giochannel_orig;
42 guint64 offset; /* gint64 range */
44 GHashTable *buffer_hash; /* (guint64 *) -> (struct blind_block *) (guint8[GIOCHANNEL_BLIND_BLOCK_SIZE]) */
49 gboolean was_read,was_written;
50 guint8 *data_written; /* [GIOCHANNEL_BLIND_BLOCK_SIZE] */
54 G_LOCK_DEFINE_STATIC(giochannel_blind_funcs);
55 static GIOFuncs giochannel_blind_funcs;
58 static guint captive_giochannel_blind_hash_func(const guint64 *keyp)
60 g_return_val_if_fail(keyp!=NULL,0);
62 return (*keyp)^((*keyp)>>23);
65 static gboolean captive_giochannel_blind_equal_func(const guint64 *ap,const guint64 *bp)
67 g_return_val_if_fail(ap!=NULL,FALSE);
68 g_return_val_if_fail(bp!=NULL,FALSE);
73 static void captive_giochannel_blind_key_destroy_func(guint64 *keyp)
75 g_return_if_fail(keyp!=NULL);
80 static void captive_giochannel_blind_value_destroy_func(struct blind_block *blind_block)
82 g_return_if_fail(blind_block!=NULL);
84 g_free(blind_block->data_written);
89 static gboolean validate_giochannel_blind(struct captive_giochannel_blind *giochannel_blind)
91 g_return_val_if_fail(giochannel_blind->iochannel.funcs==&giochannel_blind_funcs,FALSE);
92 g_return_val_if_fail(giochannel_blind!=NULL,FALSE);
93 g_return_val_if_fail(giochannel_blind->giochannel_orig!=NULL,FALSE);
94 g_return_val_if_fail((gint64)giochannel_blind->offset>=0,FALSE); /* gint64 overflow stored in guint64 */
95 g_return_val_if_fail(giochannel_blind->buffer_hash!=NULL,FALSE);
101 static GIOStatus captive_giochannel_blind_io_read
102 (GIOChannel *channel,gchar *buf,gsize count,gsize *bytes_read,GError **err)
104 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
105 guint64 window_bottom,window_top,window_now;
106 guint64 transfer_bottom,transfer_top;
107 GIOStatus errgiostatus;
108 guint64 maxread; /* maximum offset of end of data we successfuly read */
109 struct blind_block *blind_block;
111 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
112 g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
113 g_return_val_if_fail(bytes_read!=NULL,G_IO_STATUS_ERROR);
115 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: read(offset=0x%llX,count=0x%lX)",G_STRLOC,
116 giochannel_blind->offset,(gulong)count);
118 window_bottom=CAPTIVE_ROUND_DOWN64(giochannel_blind->offset,GIOCHANNEL_BLIND_BLOCK_SIZE);
119 window_top=CAPTIVE_ROUND_UP64(giochannel_blind->offset+count,GIOCHANNEL_BLIND_BLOCK_SIZE);
120 maxread=giochannel_blind->offset;
122 for (window_now=window_bottom;window_now<window_top;window_now+=GIOCHANNEL_BLIND_BLOCK_SIZE) {
125 transfer_bottom=MAX(window_now,giochannel_blind->offset);
126 transfer_top=MIN(window_now+GIOCHANNEL_BLIND_BLOCK_SIZE,giochannel_blind->offset+count);
127 if ((blind_block=g_hash_table_lookup(giochannel_blind->buffer_hash,&window_now)) && blind_block->data_written) {
128 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: read-from-memcpy(window_now=0x%llX,dest=buf+0x%lX,src=data+0x%lX,n=0x%lX)",
130 (guint64)window_now,(gulong)(transfer_bottom-giochannel_blind->offset),(gulong)(transfer_bottom-window_now),
131 (gulong)(transfer_top-transfer_bottom));
133 buf+transfer_bottom-giochannel_blind->offset, /* dest */
134 blind_block->data_written+transfer_bottom-window_now, /* src */
135 transfer_top-transfer_bottom); /* n */
136 blind_block->was_read=TRUE;
137 maxread=transfer_top;
140 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: read-from-io(window_now=0x%llX,buf=buf+0x%lX,seek=0x%llX,count=0x%lX)",G_STRLOC,
141 (guint64)window_now,(gulong)(transfer_bottom-giochannel_blind->offset),(guint64)transfer_bottom,
142 (gulong)(transfer_top-transfer_bottom));
143 errgiostatus=g_io_channel_seek_position(
144 giochannel_blind->giochannel_orig, /* channel */
145 transfer_bottom, /* offset */
146 G_SEEK_SET, /* type */
148 /* During seek in block device such as on URL file:///dev/hda1#captive-fastfat.sys-ro:/
149 * we will do llseek(2) on "/dev/hda1" device from captive_giochannel_size().
150 * Although we are allowed to seek behind EOF on regular files
151 * at least linux-kernel-2.4.19-ac4/fs/block_dev.c/block_llseek() will give
152 * EINVAL on seek behind EOF therefore it must be accepted without complaints by us.
154 if (errgiostatus!=G_IO_STATUS_NORMAL) {
155 errgiostatus=G_IO_STATUS_EOF;
159 errgiostatus=g_io_channel_read_chars(
160 giochannel_blind->giochannel_orig, /* channel */
161 buf+transfer_bottom-giochannel_blind->offset, /* buf */
162 transfer_top-transfer_bottom, /* count */
163 &bytes_read, /* bytes_read */
166 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL || errgiostatus==G_IO_STATUS_EOF,errgiostatus);
167 g_return_val_if_fail(bytes_read<=(transfer_top-transfer_bottom),G_IO_STATUS_ERROR);
168 g_return_val_if_fail((errgiostatus==G_IO_STATUS_EOF)==(bytes_read==0),G_IO_STATUS_ERROR);
173 captive_new(blind_block);
174 blind_block->offset=window_now;
175 blind_block->was_read=FALSE;
176 blind_block->was_written=FALSE;
177 blind_block->data_written=NULL;
181 giochannel_blind->buffer_hash, /* hash_table */
183 blind_block); /* value */
185 blind_block->was_read=TRUE;
187 maxread=transfer_bottom+bytes_read;
188 if (bytes_read==transfer_top-transfer_bottom)
189 g_return_val_if_fail(transfer_bottom+bytes_read<=giochannel_blind->size,G_IO_STATUS_ERROR);
194 *bytes_read=maxread-giochannel_blind->offset;
195 giochannel_blind->offset=maxread;
196 return (*bytes_read == 0 ? G_IO_STATUS_EOF : G_IO_STATUS_NORMAL);
200 static GIOStatus captive_giochannel_blind_io_write
201 (GIOChannel *channel,const gchar *buf,gsize count,gsize *bytes_written,GError **err)
203 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
204 guint64 window_bottom,window_top,window_now;
205 guint64 transfer_bottom,transfer_top;
206 GIOStatus errgiostatus;
207 struct blind_block *blind_block;
209 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
210 g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
211 g_return_val_if_fail(bytes_written!=NULL,G_IO_STATUS_ERROR);
213 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: write(offset=0x%llX,count=0x%lX)",G_STRLOC,
214 giochannel_blind->offset,(gulong)count);
216 g_return_val_if_fail(giochannel_blind->offset+count<=giochannel_blind->size,G_IO_STATUS_ERROR);
218 g_return_val_if_fail(giochannel_blind->iochannel.is_writeable==TRUE,G_IO_STATUS_ERROR);
220 window_bottom=CAPTIVE_ROUND_DOWN64(giochannel_blind->offset,GIOCHANNEL_BLIND_BLOCK_SIZE);
221 window_top=CAPTIVE_ROUND_UP64(giochannel_blind->offset+count,GIOCHANNEL_BLIND_BLOCK_SIZE);
223 for (window_now=window_bottom;window_now<window_top;window_now+=GIOCHANNEL_BLIND_BLOCK_SIZE) {
226 transfer_bottom=MAX(window_now,giochannel_blind->offset);
227 transfer_top=MIN(window_now+GIOCHANNEL_BLIND_BLOCK_SIZE,giochannel_blind->offset+count);
228 if (!(blind_block=g_hash_table_lookup(giochannel_blind->buffer_hash,&window_now)) || !blind_block->data_written) {
232 captive_new(blind_block);
233 blind_block->offset=window_now;
234 blind_block->was_read=FALSE;
235 blind_block->was_written=FALSE;
239 giochannel_blind->buffer_hash, /* hash_table */
241 blind_block); /* value */
243 blind_block->data_written=g_malloc(GIOCHANNEL_BLIND_BLOCK_SIZE);
244 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: write-new-mem(window_now=0x%llX)",G_STRLOC,
245 (guint64)window_now);
247 /* Missing lower part of buffer? */
248 if (transfer_bottom>window_now) {
249 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: write-mem-read-lower(seek=0x%llX,count=0x%lX)",G_STRLOC,
250 (guint64)window_now,(gulong)(transfer_bottom-window_now));
251 errgiostatus=g_io_channel_seek_position(
252 giochannel_blind->giochannel_orig, /* channel */
253 window_now, /* offset */
254 G_SEEK_SET, /* type */
256 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
257 errgiostatus=g_io_channel_read_chars(
258 giochannel_blind->giochannel_orig, /* channel */
259 blind_block->data_written, /* buf */
260 transfer_bottom-window_now, /* count */
261 &bytes_read, /* bytes_read */
263 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
264 g_return_val_if_fail(bytes_read==(transfer_bottom-window_now),G_IO_STATUS_ERROR);
267 /* Missing upper part of buffer? */
268 if (transfer_top<window_now+GIOCHANNEL_BLIND_BLOCK_SIZE) {
269 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: write-mem-read-upper(buf=buf+0x%lX,seek=0x%llX,count=0x%lX)",G_STRLOC,
270 (gulong)(transfer_top-window_now),(guint64)transfer_top,
271 (gulong)(window_now+GIOCHANNEL_BLIND_BLOCK_SIZE-transfer_top));
272 errgiostatus=g_io_channel_seek_position(
273 giochannel_blind->giochannel_orig, /* channel */
274 transfer_top, /* offset */
275 G_SEEK_SET, /* type */
277 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
278 errgiostatus=g_io_channel_read_chars(
279 giochannel_blind->giochannel_orig, /* channel */
280 blind_block->data_written+transfer_top-window_now, /* buf */
281 window_now+GIOCHANNEL_BLIND_BLOCK_SIZE-transfer_top, /* count */
282 &bytes_read, /* bytes_read */
284 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL || errgiostatus==G_IO_STATUS_EOF,errgiostatus);
285 g_return_val_if_fail(bytes_read<=(window_now+GIOCHANNEL_BLIND_BLOCK_SIZE-transfer_top),G_IO_STATUS_ERROR);
286 g_return_val_if_fail((errgiostatus==G_IO_STATUS_EOF)==(bytes_read==0),G_IO_STATUS_ERROR);
287 if (bytes_read==window_now+GIOCHANNEL_BLIND_BLOCK_SIZE-transfer_top)
288 g_return_val_if_fail(transfer_top+bytes_read<=giochannel_blind->size,G_IO_STATUS_ERROR);
290 g_return_val_if_fail(transfer_top+bytes_read==giochannel_blind->size,G_IO_STATUS_ERROR); /* EOF hit */
294 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: write-by-memcpy(window_now=0x%llX,dest=data+0x%lX,src=buf+0x%lX,n=0x%lX)",
296 (guint64)window_now,(gulong)(transfer_bottom-window_now),(gulong)(transfer_bottom-giochannel_blind->offset),
297 (gulong)(transfer_top-transfer_bottom));
298 g_assert(blind_block); g_assert(blind_block->data_written);
300 ((char *)blind_block->data_written)+transfer_bottom-window_now, /* dest */
301 buf+transfer_bottom-giochannel_blind->offset, /* src */
302 transfer_top-transfer_bottom); /* n */
303 blind_block->was_written=TRUE;
306 *bytes_written=count;
307 giochannel_blind->offset+=(*bytes_written);
308 return G_IO_STATUS_NORMAL;
312 static GIOStatus captive_giochannel_blind_io_seek(GIOChannel *channel,gint64 offset,GSeekType type,GError **err)
314 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
316 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
319 case G_SEEK_CUR: giochannel_blind->offset+= offset; break;
320 case G_SEEK_SET: giochannel_blind->offset = offset; break;
321 case G_SEEK_END: giochannel_blind->offset =giochannel_blind->size+offset; break;
322 default: g_return_val_if_reached(G_IO_STATUS_ERROR);
324 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR); /* 'offset' overflow? */
326 return G_IO_STATUS_NORMAL;
330 static GIOStatus captive_giochannel_blind_io_close(GIOChannel *channel,GError **err)
332 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
333 GIOStatus erriostatus;
335 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
337 /* We are not authorized to destroy 'giochannel_blind->giochannel_orig'. */
338 erriostatus=g_io_channel_flush(
339 giochannel_blind->giochannel_orig, /* channel */
341 g_assert(erriostatus==G_IO_STATUS_NORMAL);
342 giochannel_blind->giochannel_orig=NULL;
344 g_hash_table_destroy(giochannel_blind->buffer_hash);
345 giochannel_blind->buffer_hash=NULL;
347 return G_IO_STATUS_NORMAL;
351 static GSource* captive_giochannel_blind_io_create_watch(GIOChannel *channel,GIOCondition condition)
353 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
355 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),NULL);
357 g_return_val_if_reached(NULL); /* FIXME: NOT IMPLEMENTED YET */
361 static void captive_giochannel_blind_io_free(GIOChannel *channel)
363 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
365 /* After captive_giochannel_blind_io_close() 'giochannel_blind'
366 * may be no longer valid for validate_giochannel_blind(giochannel_blind).
368 g_return_if_fail(giochannel_blind!=NULL);
370 g_assert(giochannel_blind->giochannel_orig==NULL);
371 g_assert(giochannel_blind->buffer_hash==NULL);
373 g_free(giochannel_blind);
377 static GIOStatus captive_giochannel_blind_io_set_flags(GIOChannel *channel,GIOFlags flags,GError **err)
379 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
381 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
383 return g_io_channel_set_flags(giochannel_blind->giochannel_orig,(flags&~G_IO_FLAG_IS_WRITEABLE),err);
387 static GIOFlags captive_giochannel_blind_io_get_flags(GIOChannel *channel)
389 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)channel;
391 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),0);
393 return g_io_channel_get_flags(giochannel_blind->giochannel_orig) | G_IO_FLAG_IS_WRITEABLE;
397 struct captive_giochannel_blind *captive_giochannel_blind_new(GIOChannel *giochannel_orig,gboolean writeable)
399 struct captive_giochannel_blind *giochannel_blind;
400 GIOStatus erriostatus;
402 g_return_val_if_fail(giochannel_orig!=NULL,NULL);
404 G_LOCK(giochannel_blind_funcs);
405 giochannel_blind_funcs.io_read =captive_giochannel_blind_io_read;
406 giochannel_blind_funcs.io_write =captive_giochannel_blind_io_write;
407 giochannel_blind_funcs.io_seek =captive_giochannel_blind_io_seek;
408 giochannel_blind_funcs.io_close =captive_giochannel_blind_io_close;
409 giochannel_blind_funcs.io_create_watch=captive_giochannel_blind_io_create_watch;
410 giochannel_blind_funcs.io_free =captive_giochannel_blind_io_free;
411 giochannel_blind_funcs.io_set_flags =captive_giochannel_blind_io_set_flags;
412 giochannel_blind_funcs.io_get_flags =captive_giochannel_blind_io_get_flags;
413 G_UNLOCK(giochannel_blind_funcs);
415 erriostatus=g_io_channel_set_encoding(giochannel_orig,
416 NULL, /* encoding; force binary data */
418 g_assert(erriostatus==G_IO_STATUS_NORMAL);
420 captive_new(giochannel_blind);
421 g_assert(G_STRUCT_OFFSET(struct captive_giochannel_blind,iochannel)==0); /* safely re-type-able */
422 g_io_channel_init(&giochannel_blind->iochannel);
423 giochannel_blind->iochannel.funcs=&giochannel_blind_funcs;
424 giochannel_blind->iochannel.is_seekable=TRUE;
425 giochannel_blind->iochannel.is_readable=TRUE;
426 /* readonly captive_giochannel_blind can be used to track read access. */
427 giochannel_blind->iochannel.is_writeable=writeable;
428 giochannel_blind->iochannel.close_on_unref=TRUE; /* run g_io_channel_shutdown() flush on last unref */
429 giochannel_blind->giochannel_orig=giochannel_orig;
430 giochannel_blind->offset=0;
431 giochannel_blind->size=captive_giochannel_size(giochannel_orig);
432 giochannel_blind->buffer_hash=g_hash_table_new_full(
433 (GHashFunc)captive_giochannel_blind_hash_func, /* hash_func */
434 (GEqualFunc)captive_giochannel_blind_equal_func, /* key_equal_func */
435 (GDestroyNotify)captive_giochannel_blind_key_destroy_func, /* key_destroy_func */
436 (GDestroyNotify)captive_giochannel_blind_value_destroy_func); /* value_destroy_func */
438 return giochannel_blind;
442 gboolean captive_giochannel_blind_get_size(GIOChannel *giochannel,guint64 *size_return)
444 struct captive_giochannel_blind *giochannel_blind;
446 g_return_val_if_fail(giochannel!=NULL,FALSE);
447 g_return_val_if_fail(size_return!=NULL,FALSE);
449 if (giochannel->funcs!=&giochannel_blind_funcs)
451 giochannel_blind=(struct captive_giochannel_blind *)giochannel;
453 *size_return=giochannel_blind->size;
458 typedef void (*sorted_array_filter)
459 (const guint64 *keyp,const struct blind_block *blind_block,const struct blind_block ***rpp /* user_data */);
461 static void captive_giochannel_blind_written_as_sorted_array_foreach
462 (const guint64 *keyp,const struct blind_block *blind_block,const struct blind_block ***rpp /* user_data */)
464 g_return_if_fail(keyp!=NULL);
465 g_return_if_fail(blind_block!=NULL);
466 g_return_if_fail(rpp!=NULL);
468 if (!blind_block->data_written)
471 *((*rpp)++)=blind_block;
474 static void captive_giochannel_blind_read_as_sorted_array_foreach
475 (const guint64 *keyp,const struct blind_block *blind_block,const struct blind_block ***rpp /* user_data */)
477 g_return_if_fail(keyp!=NULL);
478 g_return_if_fail(blind_block!=NULL);
479 g_return_if_fail(rpp!=NULL);
481 if (!blind_block->was_read)
484 *((*rpp)++)=blind_block;
487 static int captive_giochannel_blind_as_sorted_array_compat
488 (const struct blind_block *const *ap,const struct blind_block *const *bp)
490 g_return_val_if_fail(ap!=NULL,0);
491 g_return_val_if_fail(*ap!=NULL,0);
492 g_return_val_if_fail(bp!=NULL,0);
493 g_return_val_if_fail(*bp!=NULL,0);
495 return ((*ap)->offset>(*bp)->offset) - ((*bp)->offset>(*ap)->offset);
498 static struct blind_block **captive_giochannel_blind_as_sorted_array
499 (struct captive_giochannel_blind *giochannel_blind,sorted_array_filter filter_func)
502 struct blind_block **r,**rp;
504 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
506 hash_size=g_hash_table_size(giochannel_blind->buffer_hash);
507 captive_newn(r,hash_size+1);
509 g_hash_table_foreach(giochannel_blind->buffer_hash,(GHFunc)filter_func,&rp);
510 g_assert(rp<=r+hash_size);
512 qsort(r,rp-r,sizeof(*r),(int (*)(const void *,const void *))captive_giochannel_blind_as_sorted_array_compat);
517 GIOStatus captive_giochannel_blind_commit(GIOChannel *giochannel)
519 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)giochannel;
520 struct blind_block **blind_block_array,**blind_blockp;
521 GIOStatus errgiostatus;
523 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),G_IO_STATUS_ERROR);
525 errgiostatus=g_io_channel_flush(
526 giochannel, /* channel */
528 g_assert(errgiostatus==G_IO_STATUS_NORMAL);
530 blind_block_array=captive_giochannel_blind_as_sorted_array
531 (giochannel_blind,captive_giochannel_blind_written_as_sorted_array_foreach);
533 for (blind_blockp=blind_block_array;*blind_blockp;blind_blockp++) {
534 struct blind_block *blind_block=*blind_blockp;
537 g_assert(blind_block->data_written!=NULL);
539 errgiostatus=g_io_channel_seek_position(
540 giochannel_blind->giochannel_orig, /* channel */
541 blind_block->offset, /* offset */
542 G_SEEK_SET, /* type */
544 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
545 errgiostatus=g_io_channel_write_chars(
546 giochannel_blind->giochannel_orig, /* channel */
547 blind_block->data_written, /* buf */
548 GIOCHANNEL_BLIND_BLOCK_SIZE, /* count */
549 &bytes_written, /* bytes_written */
551 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,errgiostatus);
552 g_return_val_if_fail(bytes_written==GIOCHANNEL_BLIND_BLOCK_SIZE,G_IO_STATUS_ERROR);
554 g_free(blind_block->data_written);
555 blind_block->data_written=NULL;
558 g_free(blind_block_array);
560 errgiostatus=g_io_channel_flush(
561 giochannel_blind->giochannel_orig, /* channel */
563 g_assert(errgiostatus==G_IO_STATUS_NORMAL);
565 return G_IO_STATUS_NORMAL;
569 xmlNode *captive_giochannel_blind_readreport_to_xml(xmlNode *xml_parent,GIOChannel *giochannel)
571 struct captive_giochannel_blind *giochannel_blind=(struct captive_giochannel_blind *)giochannel;
572 struct blind_block **blind_block_array,**blind_blockp;
573 GIOStatus errgiostatus;
574 guint8 data_read[1+GIOCHANNEL_BLIND_BLOCK_SIZE]; /* '1+' for leading stub to prevent shorter output of BN_bn2hex() */
577 g_return_val_if_fail(validate_giochannel_blind(giochannel_blind),NULL);
579 errgiostatus=g_io_channel_flush(
580 giochannel, /* channel */
582 g_assert(errgiostatus==G_IO_STATUS_NORMAL);
584 xml_media=xmlNewTextChild(xml_parent,NULL,"media",NULL);
585 xmlNewProp(xml_media,"size",captive_printf_alloca("%" G_GUINT64_FORMAT,giochannel_blind->size));
587 blind_block_array=captive_giochannel_blind_as_sorted_array
588 (giochannel_blind,captive_giochannel_blind_read_as_sorted_array_foreach);
590 for (blind_blockp=blind_block_array;*blind_blockp;blind_blockp++) {
591 struct blind_block *blind_block=*blind_blockp;
593 xmlNode *xml_media_read;
594 gchar offset_string[64];
598 +1 /* leading '\n' */
599 +GIOCHANNEL_BLIND_BLOCK_SIZE*2/64*(64+1) /* each line of 64 characters has EOL '\n' */
600 +1],*gd; /* terminating '\0' */
602 errgiostatus=g_io_channel_seek_position(
603 giochannel_blind->giochannel_orig, /* channel */
604 blind_block->offset, /* offset */
605 G_SEEK_SET, /* type */
607 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,NULL);
608 errgiostatus=g_io_channel_read_chars(
609 giochannel_blind->giochannel_orig, /* channel */
610 data_read+1, /* buf */
611 GIOCHANNEL_BLIND_BLOCK_SIZE, /* count */
612 &bytes_read, /* bytes_read */
614 g_return_val_if_fail(errgiostatus==G_IO_STATUS_NORMAL,NULL);
615 g_return_val_if_fail(bytes_read==GIOCHANNEL_BLIND_BLOCK_SIZE,NULL);
617 /* Convert binary block to 'hex' and reformat line-wrap it to 'hex_out'. */
618 data_read[0]=0xFF; /* stub to prevent shorter output of BN_bn2hex() */
619 bignum=BN_bin2bn(data_read,1+GIOCHANNEL_BLIND_BLOCK_SIZE,NULL);
620 hex=BN_bn2hex(bignum);
622 g_assert(strlen(hex)==2*(1+GIOCHANNEL_BLIND_BLOCK_SIZE));
625 for (s=hex+2;s<hex+2+2*GIOCHANNEL_BLIND_BLOCK_SIZE;s+=64,gd+=64+1) {
631 g_assert(s==hex+2+2*GIOCHANNEL_BLIND_BLOCK_SIZE);
632 g_assert(gd==hex_out+sizeof(hex_out));
633 xml_media_read=xmlNewTextChild(xml_media,NULL,"block",hex_out);
635 g_snprintf(offset_string,sizeof(offset_string),"%" G_GUINT64_FORMAT,blind_block->offset);
636 xmlNewProp(xml_media_read,"offset",offset_string);
640 g_free(blind_block_array);