See ChangeLog: Fri Jul 28 18:19:11 CEST 2000 Werner Koch
[gnupg.git] / util / iobuf.c
1 /* iobuf.c  -  file handling
2  *      Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <gcrypt.h>
31 #ifdef HAVE_DOSISH_SYSTEM
32   #include <fcntl.h> /* for setmode() */
33 #endif
34
35 #include "memory.h"
36 #include "util.h"
37 #include "iobuf.h"
38
39 typedef struct {
40     FILE *fp;      /* open file handle */
41     int  print_only_name; /* flags indicating that fname is not a real file*/
42     char fname[1]; /* name of the file */
43 } file_filter_ctx_t ;
44
45
46 /* The first partial length header block must be of size 512
47  * to make it easier (and efficienter) we use a min. block size of 512
48  * for all chunks (but the last one) */
49 #define OP_MIN_PARTIAL_CHUNK      512
50 #define OP_MIN_PARTIAL_CHUNK_2POW 9
51
52 typedef struct {
53     int use;
54     size_t size;
55     size_t count;
56     int partial;  /* 1 = partial header, 2 in last partial packet */
57     char *buffer;    /* used for partial header */
58     size_t buflen;   /* used size of buffer */
59     int first_c;     /* of partial header (which is > 0)*/
60     int eof;
61 } block_filter_ctx_t;
62
63
64 static int underflow(IOBUF a);
65
66 /****************
67  * Read data from a file into buf which has an allocated length of *LEN.
68  * return the number of read bytes in *LEN. OPAQUE is the FILE * of
69  * the stream. A is not used.
70  * control may be:
71  * IOBUFCTRL_INIT: called just before the function is linked into the
72  *                 list of function. This can be used to prepare internal
73  *                 data structures of the function.
74  * IOBUFCTRL_FREE: called just before the function is removed from the
75  *                  list of functions and can be used to release internal
76  *                  data structures or close a file etc.
77  * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer
78  *                  with new stuff. *RET_LEN is the available size of the
79  *                  buffer, and should be set to the number of bytes
80  *                  which were put into the buffer. The function
81  *                  returns 0 to indicate success, -1 on EOF and
82  *                  GPGERR_xxxxx for other errors.
83  *
84  * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff.
85  *                  *RET_LAN is the number of bytes in BUF.
86  *
87  * IOBUFCTRL_CANCEL: send to all filters on behalf of iobuf_cancel.  The
88  *                  filter may take appropriate action on this message.
89  */
90 static int
91 file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
92 {
93     file_filter_ctx_t *a = opaque;
94     FILE *fp = a->fp;
95     size_t size = *ret_len;
96     size_t nbytes = 0;
97     int rc = 0;
98
99     if( control == IOBUFCTRL_UNDERFLOW ) {
100         assert( size ); /* need a buffer */
101         if ( feof(fp)) {        /* On terminals you could easiely read as many EOFs as you call         */
102             rc = -1;            /* fread() or fgetc() repeatly. Every call will block until you press   */
103             *ret_len = 0;       /* CTRL-D. So we catch this case before we call fread() again.          */
104         }
105         else {
106             clearerr( fp );
107             nbytes = fread( buf, 1, size, fp );
108             if( feof(fp) && !nbytes )
109                 rc = -1; /* okay: we can return EOF now. */
110             else if( ferror(fp) && errno != EPIPE  ) {
111                 log_error("%s: read error: %s\n",
112                           a->fname, strerror(errno));
113                 rc = GPGERR_READ_FILE;
114             }
115             *ret_len = nbytes;
116         }
117     }
118     else if( control == IOBUFCTRL_FLUSH ) {
119         if( size ) {
120             clearerr( fp );
121             nbytes = fwrite( buf, 1, size, fp );
122             if( ferror(fp) ) {
123                 log_error("%s: write error: %s\n", a->fname, strerror(errno));
124                 rc = GPGERR_WRITE_FILE;
125             }
126         }
127         *ret_len = nbytes;
128     }
129     else if( control == IOBUFCTRL_INIT ) {
130     }
131     else if( control == IOBUFCTRL_DESC ) {
132         *(char**)buf = "file_filter";
133     }
134     else if( control == IOBUFCTRL_FREE ) {
135         if( fp != stdin && fp != stdout ) {
136             if( DBG_IOBUF )
137                 log_debug("%s: close fd %d\n", a->fname, fileno(fp) );
138             fclose(fp);
139         }
140         fp = NULL;
141         gcry_free(a); /* we can free our context now */
142     }
143
144     return rc;
145 }
146
147
148 /****************
149  * This is used to implement the block write mode.
150  * Block reading is done on a byte by byte basis in readbyte(),
151  * without a filter
152  */
153 static int
154 block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
155 {
156     block_filter_ctx_t *a = opaque;
157     size_t size = *ret_len;
158     int c, needed, rc = 0;
159     char *p;
160
161     if( control == IOBUFCTRL_UNDERFLOW ) {
162         size_t n=0;
163
164         p = buf;
165         assert( size ); /* need a buffer */
166         if( a->eof ) /* don't read any further */
167             rc = -1;
168         while( !rc && size ) {
169             if( !a->size ) { /* get the length bytes */
170                 if( a->partial == 2 ) {
171                     a->eof = 1;
172                     if( !n )
173                         rc = -1;
174                     break;
175                 }
176                 else if( a->partial ) {
177                     /* These OpenPGP introduced huffman like encoded length
178                      * bytes are really a mess :-( */
179                     if( a->first_c ) {
180                         c = a->first_c;
181                         a->first_c = 0;
182                         assert( c >= 224 && c < 255 );
183                     }
184                     else if( (c = iobuf_get(chain)) == -1 ) {
185                         log_error("block_filter: 1st length byte missing\n");
186                         rc = GPGERR_READ_FILE;
187                         break;
188                     }
189                     if( c < 192 ) {
190                         a->size = c;
191                         a->partial = 2;
192                         if( !a->size ) {
193                             a->eof = 1;
194                             if( !n )
195                                 rc = -1;
196                             break;
197                         }
198                     }
199                     else if( c < 224 ) {
200                         a->size = (c - 192) * 256;
201                         if( (c = iobuf_get(chain)) == -1 ) {
202                             log_error("block_filter: 2nd length byte missing\n");
203                             rc = GPGERR_READ_FILE;
204                             break;
205                         }
206                         a->size += c + 192;
207                         a->partial = 2;
208                         if( !a->size ) {
209                             a->eof = 1;
210                             if( !n )
211                                 rc = -1;
212                             break;
213                         }
214                     }
215                     else if( c == 255 ) {
216                         a->size  = iobuf_get(chain) << 24;
217                         a->size |= iobuf_get(chain) << 16;
218                         a->size |= iobuf_get(chain) << 8;
219                         if( (c = iobuf_get(chain)) == -1 ) {
220                             log_error("block_filter: invalid 4 byte length\n");
221                             rc = GPGERR_READ_FILE;
222                             break;
223                         }
224                         a->size |= c;
225                     }
226                     else { /* next partial body length */
227                         a->size = 1 << (c & 0x1f);
228                     }
229             /*  log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size);*/
230                 }
231                 else { /* the gnupg partial length scheme - much better :-) */
232                     c = iobuf_get(chain);
233                     a->size = c << 8;
234                     c = iobuf_get(chain);
235                     a->size |= c;
236                     if( c == -1 ) {
237                         log_error("block_filter: error reading length info\n");
238                         rc = GPGERR_READ_FILE;
239                     }
240                     if( !a->size ) {
241                         a->eof = 1;
242                         if( !n )
243                             rc = -1;
244                         break;
245                     }
246                 }
247             }
248
249             while( !rc && size && a->size ) {
250                 needed = size < a->size ? size : a->size;
251                 c = iobuf_read( chain, p, needed );
252                 if( c < needed ) {
253                     if( c == -1 ) c = 0;
254                     log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n",
255                               a,  (ulong)size+c, (ulong)a->size+c);
256                     rc = GPGERR_READ_FILE;
257                 }
258                 else {
259                     size -= c;
260                     a->size -= c;
261                     p += c;
262                     n += c;
263                 }
264             }
265         }
266         *ret_len = n;
267     }
268     else if( control == IOBUFCTRL_FLUSH ) {
269         if( a->partial ) { /* the complicated openpgp scheme */
270             size_t blen, n, nbytes = size + a->buflen;
271
272             assert( a->buflen <= OP_MIN_PARTIAL_CHUNK );
273             if( nbytes < OP_MIN_PARTIAL_CHUNK ) {
274                 /* not enough to write a partial block out; so we store it*/
275                 if( !a->buffer )
276                     a->buffer = gcry_xmalloc( OP_MIN_PARTIAL_CHUNK );
277                 memcpy( a->buffer + a->buflen, buf, size );
278                 a->buflen += size;
279             }
280             else { /* okay, we can write out something */
281                 /* do this in a loop to use the most efficient block lengths */
282                 p = buf;
283                 do {
284                     /* find the best matching block length - this is limited
285                      * by the size of the internal buffering */
286                     for( blen=OP_MIN_PARTIAL_CHUNK*2,
287                             c=OP_MIN_PARTIAL_CHUNK_2POW+1; blen <= nbytes;
288                                                             blen *=2, c++ )
289                         ;
290                     blen /= 2; c--;
291                     /* write the partial length header */
292                     assert( c <= 0x1f ); /*;-)*/
293                     c |= 0xe0;
294                     iobuf_put( chain, c );
295                     if( (n=a->buflen) ) { /* write stuff from the buffer */
296                         assert( n == OP_MIN_PARTIAL_CHUNK);
297                         if( iobuf_write(chain, a->buffer, n ) )
298                             rc = GPGERR_WRITE_FILE;
299                         a->buflen = 0;
300                         nbytes -= n;
301                     }
302                     if( (n = nbytes) > blen )
303                         n = blen;
304                     if( n && iobuf_write(chain, p, n ) )
305                         rc = GPGERR_WRITE_FILE;
306                     p += n;
307                     nbytes -= n;
308                 } while( !rc && nbytes >= OP_MIN_PARTIAL_CHUNK );
309                 /* store the rest in the buffer */
310                 if( !rc && nbytes ) {
311                     assert( !a->buflen );
312                     assert( nbytes < OP_MIN_PARTIAL_CHUNK );
313                     if( !a->buffer )
314                         a->buffer = gcry_xmalloc( OP_MIN_PARTIAL_CHUNK );
315                     memcpy( a->buffer, p, nbytes );
316                     a->buflen = nbytes;
317                 }
318             }
319         }
320         else { /* the gnupg scheme (which is not openpgp compliant) */
321             size_t avail, n;
322
323             for(p=buf; !rc && size; ) {
324                 n = size;
325                 avail = a->size - a->count;
326                 if( !avail ) {
327                     if( n > a->size ) {
328                         iobuf_put( chain, (a->size >> 8) & 0xff );
329                         iobuf_put( chain, a->size & 0xff );
330                         avail = a->size;
331                         a->count = 0;
332                     }
333                     else {
334                         iobuf_put( chain, (n >> 8) & 0xff );
335                         iobuf_put( chain, n & 0xff );
336                         avail = n;
337                         a->count = a->size - n;
338                     }
339                 }
340                 if( n > avail )
341                     n = avail;
342                 if( iobuf_write(chain, p, n ) )
343                     rc = GPGERR_WRITE_FILE;
344                 a->count += n;
345                 p += n;
346                 size -= n;
347             }
348         }
349     }
350     else if( control == IOBUFCTRL_INIT ) {
351         if( DBG_IOBUF )
352             log_debug("init block_filter %p\n", a );
353         if( a->partial )
354             a->count = 0;
355         else if( a->use == 1 )
356             a->count = a->size = 0;
357         else
358             a->count = a->size; /* force first length bytes */
359         a->eof = 0;
360         a->buffer = NULL;
361         a->buflen = 0;
362     }
363     else if( control == IOBUFCTRL_DESC ) {
364         *(char**)buf = "block_filter";
365     }
366     else if( control == IOBUFCTRL_FREE ) {
367         if( a->use == 2 ) { /* write the end markers */
368             if( a->partial ) {
369                 u32 len;
370                 /* write out the remaining bytes without a partial header
371                  * the length of this header may be 0 - but if it is
372                  * the first block we are not allowed to use a partial header
373                  * and frankly we can't do so, because this length must be
374                  * a power of 2. This is _really_ complicated because we
375                  * have to check the possible length of a packet prior
376                  * to it's creation: a chain of filters becomes complicated
377                  * and we need a lot of code to handle compressed packets etc.
378                  *   :-(((((((
379                  */
380                 /* construct header */
381                 len = a->buflen;
382                 /*log_debug("partial: remaining length=%u\n", len );*/
383                 if( len < 192 )
384                     rc = iobuf_put(chain, len );
385                 else if( len < 8384 ) {
386                     if( !(rc=iobuf_put( chain, ((len-192) / 256) + 192)) )
387                         rc = iobuf_put( chain, ((len-192) % 256));
388                 }
389                 else { /* use a 4 byte header */
390                     if( !(rc=iobuf_put( chain, 0xff )) )
391                         if( !(rc=iobuf_put( chain, (len >> 24)&0xff )) )
392                             if( !(rc=iobuf_put( chain, (len >> 16)&0xff )) )
393                                 if( !(rc=iobuf_put( chain, (len >> 8)&0xff )))
394                                     rc=iobuf_put( chain, len & 0xff );
395                 }
396                 if( !rc && len )
397                     rc = iobuf_write(chain, a->buffer, len );
398                 if( rc ) {
399                     log_error("block_filter: write error: %s\n",strerror(errno));
400                     rc = GPGERR_WRITE_FILE;
401                 }
402                 gcry_free( a->buffer ); a->buffer = NULL; a->buflen = 0;
403             }
404             else {
405                 iobuf_writebyte(chain, 0);
406                 iobuf_writebyte(chain, 0);
407             }
408         }
409         else if( a->size ) {
410             log_error("block_filter: pending bytes!\n");
411         }
412         if( DBG_IOBUF )
413             log_debug("free block_filter %p\n", a );
414         gcry_free(a); /* we can free our context now */
415     }
416
417     return rc;
418 }
419
420
421 static void
422 print_chain( IOBUF a )
423 {
424     if( !DBG_IOBUF )
425         return;
426     for(; a; a = a->chain ) {
427         size_t dummy_len = 0;
428         const char *desc = "[none]";
429
430         if( a->filter )
431             a->filter( a->filter_ov, IOBUFCTRL_DESC, NULL,
432                                                 (byte*)&desc, &dummy_len );
433
434         log_debug("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n",
435                    a->no, a->subno, desc, a->filter_eof,
436                    (int)a->d.start, (int)a->d.len );
437     }
438 }
439
440 int
441 iobuf_print_chain( IOBUF a )
442 {
443     print_chain(a);
444     return 0;
445 }
446
447 /****************
448  * Allocate a new io buffer, with no function assigned.
449  * Use is the desired usage: 1 for input, 2 for output, 3 for temp buffer
450  * BUFSIZE is a suggested buffer size.
451  */
452 IOBUF
453 iobuf_alloc(int use, size_t bufsize)
454 {
455     IOBUF a;
456     static int number=0;
457
458     a = gcry_xcalloc( 1,sizeof *a);
459     a->use = use;
460     a->d.buf = gcry_xmalloc( bufsize );
461     a->d.size = bufsize;
462     a->no = ++number;
463     a->subno = 0;
464     a->opaque = NULL;
465     a->real_fname = NULL;
466     return a;
467 }
468
469
470 int
471 iobuf_close( IOBUF a )
472 {
473     IOBUF a2;
474     size_t dummy_len = 0;
475     int rc=0;
476
477     if( a && a->directfp ) {
478         fclose( a->directfp );
479         gcry_free( a->real_fname );
480         if( DBG_IOBUF )
481             log_debug("iobuf_close -> %p\n", a->directfp );
482         return 0;
483     }
484
485     for( ; a && !rc ; a = a2 ) {
486         a2 = a->chain;
487         if( a->use == 2 && (rc=iobuf_flush(a)) )
488             log_error("iobuf_flush failed on close: %s\n", gpg_errstr(rc));
489
490         if( DBG_IOBUF )
491             log_debug("iobuf-%d.%d: close `%s'\n", a->no, a->subno, a->desc );
492         if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE,
493                                          a->chain, NULL, &dummy_len)) )
494             log_error("IOBUFCTRL_FREE failed on close: %s\n", gpg_errstr(rc) );
495         gcry_free(a->real_fname);
496         gcry_free(a->d.buf);
497         gcry_free(a);
498     }
499     return rc;
500 }
501
502
503 int
504 iobuf_cancel( IOBUF a )
505 {
506     const char *s;
507     IOBUF a2;
508     int rc;
509   #ifdef HAVE_DOSISH_SYSTEM
510     char *remove_name = NULL;
511   #endif
512
513     if( a && a->use == 2 ) {
514         s = iobuf_get_real_fname(a);
515         if( s && *s ) {
516           #ifdef HAVE_DOSISH_SYSTEM
517             remove_name = m_strdup ( s );
518           #else
519             remove(s);
520           #endif
521         }
522     }
523
524     /* send a cancel message to all filters */
525     for( a2 = a; a2 ; a2 = a2->chain ) {
526         size_t dummy;
527         if( a2->filter )
528             a2->filter( a2->filter_ov, IOBUFCTRL_CANCEL, a2->chain,
529                                                          NULL, &dummy );
530     }
531
532     rc = iobuf_close(a);
533   #ifdef HAVE_DOSISH_SYSTEM
534     if ( remove_name ) {
535         /* Argg, MSDOS does not allow to remove open files.  So
536          * we have to do it here */
537         remove ( remove_name );
538         m_free ( remove_name );
539     }
540   #endif
541     return rc;
542 }
543
544 /****************
545  * create a temporary iobuf, which can be used to collect stuff
546  * in an iobuf and later be written by iobuf_write_temp() to another
547  * iobuf.
548  */
549 IOBUF
550 iobuf_temp()
551 {
552     IOBUF a;
553
554     a = iobuf_alloc(3, 8192 );
555
556     return a;
557 }
558
559 IOBUF
560 iobuf_temp_with_content( const char *buffer, size_t length )
561 {
562     IOBUF a;
563
564     a = iobuf_alloc(3, length );
565     memcpy( a->d.buf, buffer, length );
566     a->d.len = length;
567
568     return a;
569 }
570
571
572 /****************
573  * Create a head iobuf for reading from a file
574  * returns: NULL if an error occures and sets errno
575  */
576 IOBUF
577 iobuf_open( const char *fname )
578 {
579     IOBUF a;
580     FILE *fp;
581     file_filter_ctx_t *fcx;
582     size_t len;
583     int print_only = 0;
584
585     if( !fname || (*fname=='-' && !fname[1])  ) {
586         fp = stdin;
587       #ifdef HAVE_DOSISH_SYSTEM
588         setmode ( fileno(fp) , O_BINARY );
589       #endif
590         fname = "[stdin]";
591         print_only = 1;
592     }
593     else if( !(fp = fopen(fname, "rb")) )
594         return NULL;
595     a = iobuf_alloc(1, 8192 );
596     fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) );
597     fcx->fp = fp;
598     fcx->print_only_name = print_only;
599     strcpy(fcx->fname, fname );
600     if( !print_only )
601         a->real_fname = gcry_xstrdup( fname );
602     a->filter = file_filter;
603     a->filter_ov = fcx;
604     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
605     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
606     if( DBG_IOBUF )
607         log_debug("iobuf-%d.%d: open `%s' fd=%d\n",
608                    a->no, a->subno, fname, fileno(fcx->fp) );
609
610     return a;
611 }
612
613 /****************
614  * Create a head iobuf for reading from a file
615  * returns: NULL if an error occures and sets errno
616  */
617 IOBUF
618 iobuf_fdopen( int fd, const char *mode )
619 {
620     IOBUF a;
621     FILE *fp;
622     file_filter_ctx_t *fcx;
623     size_t len;
624
625     if( !(fp = fdopen(fd, mode)) )
626         return NULL;
627     a = iobuf_alloc( strchr( mode, 'w')? 2:1, 8192 );
628     fcx = gcry_xmalloc( sizeof *fcx + 20 );
629     fcx->fp = fp;
630     fcx->print_only_name = 1;
631     sprintf(fcx->fname, "[fd %d]", fd );
632     a->filter = file_filter;
633     a->filter_ov = fcx;
634     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
635     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
636     if( DBG_IOBUF )
637         log_debug("iobuf-%d.%d: fdopen `%s'\n", a->no, a->subno, fcx->fname );
638
639     return a;
640 }
641
642 /****************
643  * create an iobuf for writing to a file; the file will be created.
644  */
645 IOBUF
646 iobuf_create( const char *fname )
647 {
648     IOBUF a;
649     FILE *fp;
650     file_filter_ctx_t *fcx;
651     size_t len;
652     int print_only = 0;
653
654     if( !fname || (*fname=='-' && !fname[1]) ) {
655         fp = stdout;
656       #ifdef HAVE_DOSISH_SYSTEM
657         setmode ( fileno(fp) , O_BINARY );
658       #endif
659         fname = "[stdout]";
660         print_only = 1;
661     }
662     else if( !(fp = fopen(fname, "wb")) )
663         return NULL;
664     a = iobuf_alloc(2, 8192 );
665     fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) );
666     fcx->fp = fp;
667     fcx->print_only_name = print_only;
668     strcpy(fcx->fname, fname );
669     if( !print_only )
670         a->real_fname = gcry_xstrdup( fname );
671     a->filter = file_filter;
672     a->filter_ov = fcx;
673     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
674     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
675     if( DBG_IOBUF )
676         log_debug("iobuf-%d.%d: create `%s'\n", a->no, a->subno, a->desc );
677
678     return a;
679 }
680
681 /****************
682  * append to an iobuf; if the file does not exist, create it.
683  * cannot be used for stdout.
684  */
685 IOBUF
686 iobuf_append( const char *fname )
687 {
688     IOBUF a;
689     FILE *fp;
690     file_filter_ctx_t *fcx;
691     size_t len;
692
693     if( !fname )
694         return NULL;
695     else if( !(fp = fopen(fname, "ab")) )
696         return NULL;
697     a = iobuf_alloc(2, 8192 );
698     fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) );
699     fcx->fp = fp;
700     strcpy(fcx->fname, fname );
701     a->real_fname = gcry_xstrdup( fname );
702     a->filter = file_filter;
703     a->filter_ov = fcx;
704     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
705     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
706     if( DBG_IOBUF )
707         log_debug("iobuf-%d.%d: append `%s'\n", a->no, a->subno, a->desc );
708
709     return a;
710 }
711
712 IOBUF
713 iobuf_openrw( const char *fname )
714 {
715     IOBUF a;
716     FILE *fp;
717     file_filter_ctx_t *fcx;
718     size_t len;
719
720     if( !fname )
721         return NULL;
722     else if( !(fp = fopen(fname, "r+b")) )
723         return NULL;
724     a = iobuf_alloc(2, 8192 );
725     fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) );
726     fcx->fp = fp;
727     strcpy(fcx->fname, fname );
728     a->real_fname = gcry_xstrdup( fname );
729     a->filter = file_filter;
730     a->filter_ov = fcx;
731     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
732     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
733     if( DBG_IOBUF )
734         log_debug("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno, a->desc );
735
736     return a;
737 }
738
739
740
741 /****************
742  * You can overwrite the normal iobuf behaviour by using this function.
743  * If used the iobuf is a simple wrapper around stdio.
744  * NULL if an error occures and sets errno
745  */
746 IOBUF
747 iobuf_fopen( const char *fname, const char *mode )
748 {
749     IOBUF a;
750     FILE *fp;
751     int print_only = 0;
752
753     if( !fname || (*fname=='-' && !fname[1])  ) {
754         fp = stdin;
755       #ifdef HAVE_DOSISH_SYSTEM
756         setmode ( fileno(fp) , O_BINARY );
757       #endif
758         fname = "[stdin]";
759         print_only = 1;
760     }
761     else if( !(fp = fopen(fname, mode) ) )
762         return NULL;
763     a = iobuf_alloc(1, 8192 );
764     a->directfp = fp;
765     a->real_fname = gcry_xstrdup( fname );
766
767     if( DBG_IOBUF )
768         log_debug("iobuf_fopen -> %p\n", a->directfp );
769
770     return a;
771 }
772
773
774
775 /****************
776  * Register an i/o filter.
777  */
778 int
779 iobuf_push_filter( IOBUF a,
780                    int (*f)(void *opaque, int control,
781                    IOBUF chain, byte *buf, size_t *len), void *ov )
782 {
783     return iobuf_push_filter2( a, f, ov, 0 );
784 }
785
786 int
787 iobuf_push_filter2( IOBUF a,
788                     int (*f)(void *opaque, int control,
789                     IOBUF chain, byte *buf, size_t *len),
790                     void *ov, int rel_ov )
791 {
792     IOBUF b;
793     size_t dummy_len=0;
794     int rc=0;
795
796     if( a->directfp )
797         BUG();
798
799     if( a->use == 2 && (rc=iobuf_flush(a)) )
800         return rc;
801     /* make a copy of the current stream, so that
802      * A is the new stream and B the original one.
803      * The contents of the buffers are transferred to the
804      * new stream.
805      */
806     b = gcry_xmalloc(sizeof *b);
807     memcpy(b, a, sizeof *b );
808     /* fixme: it is stupid to keep a copy of the name at every level
809      * but we need the name somewhere because the name known by file_filter
810      * may have been released when we need the name of the file */
811     b->real_fname = a->real_fname? gcry_xstrdup(a->real_fname):NULL;
812     /* remove the filter stuff from the new stream */
813     a->filter = NULL;
814     a->filter_ov = NULL;
815     a->filter_ov_owner = 0;
816     a->filter_eof = 0;
817     if( a->use == 3 )
818         a->use = 2;  /* make a write stream from a temp stream */
819
820     if( a->use == 2 ) { /* allocate a fresh buffer for the original stream */
821         b->d.buf = gcry_xmalloc( a->d.size );
822         b->d.len = 0;
823         b->d.start = 0;
824     }
825     else { /* allocate a fresh buffer for the new stream */
826         a->d.buf = gcry_xmalloc( a->d.size );
827         a->d.len = 0;
828         a->d.start = 0;
829     }
830     /* disable nlimit for the new stream */
831     a->ntotal = b->ntotal + b->nbytes;
832     a->nlimit = a->nbytes = 0;
833     a->nofast &= ~1;
834     /* make a link from the new stream to the original stream */
835     a->chain = b;
836     a->opaque = b->opaque;
837
838     /* setup the function on the new stream */
839     a->filter = f;
840     a->filter_ov = ov;
841     a->filter_ov_owner = rel_ov;
842
843     a->subno = b->subno + 1;
844     f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len );
845
846     if( DBG_IOBUF ) {
847         log_debug("iobuf-%d.%d: push `%s'\n", a->no, a->subno, a->desc );
848         print_chain( a );
849     }
850
851     /* now we can initialize the new function if we have one */
852     if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain,
853                        NULL, &dummy_len)) )
854         log_error("IOBUFCTRL_INIT failed: %s\n", gpg_errstr(rc) );
855     return rc;
856 }
857
858 /****************
859  * Remove an i/o filter.
860  */
861 int
862 pop_filter( IOBUF a, int (*f)(void *opaque, int control,
863                       IOBUF chain, byte *buf, size_t *len), void *ov )
864 {
865     IOBUF b;
866     size_t dummy_len=0;
867     int rc=0;
868
869     if( a->directfp )
870         BUG();
871
872     if( DBG_IOBUF )
873         log_debug("iobuf-%d.%d: pop `%s'\n", a->no, a->subno, a->desc );
874     if( !a->filter ) { /* this is simple */
875         b = a->chain;
876         assert(b);
877         gcry_free(a->d.buf);
878         gcry_free(a->real_fname);
879         memcpy(a,b, sizeof *a);
880         gcry_free(b);
881         return 0;
882     }
883     for(b=a ; b; b = b->chain )
884         if( b->filter == f && (!ov || b->filter_ov == ov) )
885             break;
886     if( !b )
887         log_bug("pop_filter(): filter function not found\n");
888
889     /* flush this stream if it is an output stream */
890     if( a->use == 2 && (rc=iobuf_flush(b)) ) {
891         log_error("iobuf_flush failed in pop_filter: %s\n", gpg_errstr(rc));
892         return rc;
893     }
894     /* and tell the filter to free it self */
895     if( b->filter && (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain,
896                        NULL, &dummy_len)) ) {
897         log_error("IOBUFCTRL_FREE failed: %s\n", gpg_errstr(rc) );
898         return rc;
899     }
900     if( b->filter_ov && b->filter_ov_owner ) {
901         gcry_free( b->filter_ov );
902         b->filter_ov = NULL;
903     }
904
905
906     /* and see how to remove it */
907     if( a == b && !b->chain )
908         log_bug("can't remove the last filter from the chain\n");
909     else if( a == b ) { /* remove the first iobuf from the chain */
910         /* everything from b is copied to a. This is save because
911          * a flush has been done on the to be removed entry
912          */
913         b = a->chain;
914         gcry_free(a->d.buf);
915         gcry_free(a->real_fname);
916         memcpy(a,b, sizeof *a);
917         gcry_free(b);
918         if( DBG_IOBUF )
919            log_debug("iobuf-%d.%d: popped filter\n", a->no, a->subno );
920     }
921     else if( !b->chain ) { /* remove the last iobuf from the chain */
922         log_bug("Ohh jeee, trying to remove a head filter\n");
923     }
924     else {  /* remove an intermediate iobuf from the chain */
925         log_bug("Ohh jeee, trying to remove an intermediate filter\n");
926     }
927
928     return rc;
929 }
930
931
932 /****************
933  * read underflow: read more bytes into the buffer and return
934  * the first byte or -1 on EOF.
935  */
936 static int
937 underflow(IOBUF a)
938 {
939     size_t len;
940     int rc;
941
942     assert( a->d.start == a->d.len );
943     if( a->use == 3 )
944         return -1; /* EOF because a temp buffer can't do an underflow */
945
946     if( a->filter_eof ) {
947         if( a->chain && a->filter_eof == 1 ) {
948             IOBUF b = a->chain;
949             if( DBG_IOBUF )
950                 log_debug("iobuf-%d.%d: pop `%s' in underflow\n",
951                                         a->no, a->subno, a->desc );
952             gcry_free(a->d.buf);
953             gcry_free(a->real_fname);
954             memcpy(a, b, sizeof *a);
955             gcry_free(b);
956             print_chain(a);
957         }
958         else
959             a->filter_eof = 0;
960         if( DBG_IOBUF )
961             log_debug("iobuf-%d.%d: underflow: eof (due to filter eof)\n",
962                                                     a->no, a->subno );
963         return -1; /* return one(!) EOF */
964     }
965     if( a->error ) {
966         if( DBG_IOBUF )
967             log_debug("iobuf-%d.%d: error\n", a->no, a->subno );
968         return -1;
969     }
970
971     if( a->directfp ) {
972         FILE *fp = a->directfp;
973
974         len = fread( a->d.buf, 1, a->d.size, fp);
975         if( len < a->d.size ) {
976             if( ferror(fp) )
977                 a->error = 1;
978         }
979         a->d.len = len;
980         a->d.start = 0;
981         return len? a->d.buf[a->d.start++] : -1;
982     }
983
984
985     if( a->filter ) {
986         len = a->d.size;
987         rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
988                         a->d.buf, &len );
989         if( DBG_IOBUF ) {
990             log_debug("iobuf-%d.%d: underflow: req=%lu got=%lu rc=%d\n",
991                     a->no, a->subno, (ulong)a->d.size, (ulong)len, rc );
992           #if 0
993             if( a->no == 7 ) {
994                 print_string(stderr, a->d.buf, len, 0 );
995                 putc('\n', stderr );
996             }
997           #endif
998
999         }
1000         if( a->use == 1 && rc == -1 ) { /* EOF: we can remove the filter */
1001             size_t dummy_len=0;
1002
1003             /* and tell the filter to free itself */
1004             if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
1005                                NULL, &dummy_len)) )
1006                 log_error("IOBUFCTRL_FREE failed: %s\n", gpg_errstr(rc) );
1007             if( a->filter_ov && a->filter_ov_owner ) {
1008                 gcry_free( a->filter_ov );
1009                 a->filter_ov = NULL;
1010             }
1011             a->filter = NULL;
1012             a->desc = NULL;
1013             a->filter_ov = NULL;
1014             a->filter_eof = 1;
1015             if( !len && a->chain ) {
1016                 IOBUF b = a->chain;
1017                 if( DBG_IOBUF )
1018                     log_debug("iobuf-%d.%d: pop `%s' in underflow (!len)\n",
1019                                                a->no, a->subno, a->desc );
1020                 print_chain(a);
1021                 gcry_free(a->d.buf);
1022                 gcry_free(a->real_fname);
1023                 memcpy(a,b, sizeof *a);
1024                 gcry_free(b);
1025                 print_chain(a);
1026             }
1027         }
1028         else if( rc )
1029             a->error = 1;
1030
1031         if( !len ) {
1032             if( DBG_IOBUF )
1033                 log_debug("iobuf-%d.%d: underflow: eof\n", a->no, a->subno );
1034             return -1;
1035         }
1036         a->d.len = len;
1037         a->d.start = 0;
1038         return a->d.buf[a->d.start++];
1039     }
1040     else {
1041         if( DBG_IOBUF )
1042             log_debug("iobuf-%d.%d: underflow: eof (no filter)\n",
1043                                                     a->no, a->subno );
1044         return -1;  /* no filter; return EOF */
1045     }
1046 }
1047
1048
1049 int
1050 iobuf_flush(IOBUF a)
1051 {
1052     size_t len;
1053     int rc;
1054
1055     if( a->directfp )
1056         return 0;
1057
1058     /*log_debug("iobuf-%d.%d: flush\n", a->no, a->subno );*/
1059     if( a->use == 3 ) { /* increase the temp buffer */
1060         char *newbuf;
1061         size_t newsize = a->d.size + 8192;
1062
1063         log_debug("increasing temp iobuf from %lu to %lu\n",
1064                     (ulong)a->d.size, (ulong)newsize );
1065         newbuf = gcry_xmalloc( newsize );
1066         memcpy( newbuf, a->d.buf, a->d.len );
1067         gcry_free(a->d.buf);
1068         a->d.buf = newbuf;
1069         a->d.size = newsize;
1070         return 0;
1071     }
1072     else if( a->use != 2 )
1073         log_bug("flush on non-output iobuf\n");
1074     else if( !a->filter )
1075         log_bug("iobuf_flush: no filter\n");
1076     len = a->d.len;
1077     rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len );
1078     if( !rc && len != a->d.len ) {
1079         log_info("iobuf_flush did not write all!\n");
1080         rc = GPGERR_WRITE_FILE;
1081     }
1082     else if( rc )
1083         a->error = 1;
1084     a->d.len = 0;
1085
1086     return rc;
1087 }
1088
1089
1090 /****************
1091  * Read a byte from the iobuf; returns -1 on EOF
1092  */
1093 int
1094 iobuf_readbyte(IOBUF a)
1095 {
1096     int c;
1097
1098     /* nlimit does not work together with unget */
1099     /* nbytes is also not valid! */
1100     if( a->unget.buf ) {
1101         if( a->unget.start < a->unget.len )
1102             return a->unget.buf[a->unget.start++];
1103         gcry_free(a->unget.buf);
1104         a->unget.buf = NULL;
1105         a->nofast &= ~2;
1106     }
1107
1108     if( a->nlimit && a->nbytes >= a->nlimit )
1109         return -1; /* forced EOF */
1110
1111     if( a->d.start < a->d.len ) {
1112         c = a->d.buf[a->d.start++];
1113     }
1114     else if( (c=underflow(a)) == -1 )
1115         return -1; /* EOF */
1116
1117     a->nbytes++;
1118     return c;
1119 }
1120
1121
1122 int
1123 iobuf_read(IOBUF a, byte *buf, unsigned buflen )
1124 {
1125     int c, n;
1126
1127     if( a->unget.buf || a->nlimit ) {
1128         /* handle special cases */
1129         for(n=0 ; n < buflen; n++ ) {
1130             if( (c = iobuf_readbyte(a)) == -1 ) {
1131                 if( !n )
1132                     return -1; /* eof */
1133                 break;
1134             }
1135             else
1136                 if( buf ) *buf = c;
1137             if( buf ) buf++;
1138         }
1139         return n;
1140     }
1141
1142     n = 0;
1143     do {
1144         if( n < buflen && a->d.start < a->d.len ) {
1145             unsigned size = a->d.len - a->d.start;
1146             if( size > buflen - n )
1147                 size = buflen - n;
1148             if( buf )
1149                 memcpy( buf, a->d.buf + a->d.start, size );
1150             n += size;
1151             a->d.start += size;
1152             if( buf )
1153                 buf += size;
1154         }
1155         if( n < buflen ) {
1156             if( (c=underflow(a)) == -1 ) {
1157                 a->nbytes += n;
1158                 return n? n : -1/*EOF*/;
1159             }
1160             if( buf )
1161                 *buf++ = c;
1162             n++;
1163         }
1164     } while( n < buflen );
1165     a->nbytes += n;
1166     return n;
1167 }
1168
1169
1170 /****************
1171  * Have a look at the iobuf.
1172  * NOTE: This only works in special cases.
1173  */
1174 int
1175 iobuf_peek(IOBUF a, byte *buf, unsigned buflen )
1176 {
1177     int n=0;
1178
1179     if( a->filter_eof )
1180         return -1;
1181
1182     if( !(a->d.start < a->d.len) ) {
1183         if( underflow(a) == -1 )
1184             return -1;
1185         /* and unget this character */
1186         assert(a->d.start == 1);
1187         a->d.start = 0;
1188     }
1189
1190     for(n=0 ; n < buflen && (a->d.start+n) < a->d.len ; n++, buf++ )
1191         *buf = a->d.buf[n];
1192     return n;
1193 }
1194
1195
1196
1197
1198 int
1199 iobuf_writebyte(IOBUF a, unsigned c)
1200 {
1201
1202     if( a->directfp )
1203         BUG();
1204
1205     if( a->d.len == a->d.size )
1206         if( iobuf_flush(a) )
1207             return -1;
1208
1209     assert( a->d.len < a->d.size );
1210     a->d.buf[a->d.len++] = c;
1211     return 0;
1212 }
1213
1214
1215 int
1216 iobuf_write(IOBUF a, byte *buf, unsigned buflen )
1217 {
1218
1219     if( a->directfp )
1220         BUG();
1221
1222     do {
1223         if( buflen && a->d.len < a->d.size ) {
1224             unsigned size = a->d.size - a->d.len;
1225             if( size > buflen ) size = buflen;
1226             memcpy( a->d.buf + a->d.len, buf, size );
1227             buflen -= size;
1228             buf += size;
1229             a->d.len += size;
1230         }
1231         if( buflen ) {
1232             if( iobuf_flush(a) )
1233                 return -1;
1234         }
1235     } while( buflen );
1236     return 0;
1237 }
1238
1239
1240 int
1241 iobuf_writestr(IOBUF a, const char *buf )
1242 {
1243     for( ; *buf; buf++ )
1244         if( iobuf_writebyte(a, *buf) )
1245             return -1;
1246     return 0;
1247 }
1248
1249
1250
1251 /****************
1252  * copy the contents of TEMP to A.
1253  */
1254 int
1255 iobuf_write_temp( IOBUF a, IOBUF temp )
1256 {
1257     while( temp->chain )
1258         pop_filter( temp, temp->filter, NULL );
1259     return iobuf_write(a, temp->d.buf, temp->d.len );
1260 }
1261
1262 /****************
1263  * copy the contents of the temp io stream to BUFFER.
1264  */
1265 size_t
1266 iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
1267 {
1268     size_t n = a->d.len;
1269
1270     if( n > buflen )
1271         n = buflen;
1272     memcpy( buffer, a->d.buf, n );
1273     return n;
1274 }
1275
1276
1277 /****************
1278  * Call this function to terminate processing of the temp stream
1279  * without closing it.  This removes all filters from the stream
1280  * makes sure that iobuf_get_temp_{buffer,length}() returns correct
1281  * values.
1282  */
1283 void
1284 iobuf_flush_temp( IOBUF temp )
1285 {
1286     while( temp->chain )
1287         pop_filter( temp, temp->filter, NULL );
1288 }
1289
1290
1291 /****************
1292  * Set a limit on how many bytes may be read from the input stream A.
1293  * Setting the limit to 0 disables this feature.
1294  */
1295 void
1296 iobuf_set_limit( IOBUF a, unsigned long nlimit )
1297 {
1298     if( nlimit )
1299         a->nofast |= 1;
1300     else
1301         a->nofast &= ~1;
1302     a->nlimit = nlimit;
1303     a->ntotal += a->nbytes;
1304     a->nbytes = 0;
1305 }
1306
1307
1308
1309 /****************
1310  * Return the length of an open file
1311  */
1312 u32
1313 iobuf_get_filelength( IOBUF a )
1314 {
1315     struct stat st;
1316
1317     if( a->directfp )  {
1318         FILE *fp = a->directfp;
1319
1320         if( !fstat(fileno(fp), &st) )
1321             return st.st_size;
1322         log_error("fstat() failed: %s\n", strerror(errno) );
1323         return 0;
1324     }
1325
1326     /* Hmmm: file_filter may have already been removed */
1327     for( ; a; a = a->chain )
1328         if( !a->chain && a->filter == file_filter ) {
1329             file_filter_ctx_t *b = a->filter_ov;
1330             FILE *fp = b->fp;
1331
1332             if( !fstat(fileno(fp), &st) )
1333                 return st.st_size;
1334             log_error("fstat() failed: %s\n", strerror(errno) );
1335             break;
1336         }
1337
1338     return 0;
1339 }
1340
1341 /****************
1342  * Tell the file position, where the next read will take place
1343  */
1344 ulong
1345 iobuf_tell( IOBUF a )
1346 {
1347     return a->ntotal + a->nbytes;
1348 }
1349
1350
1351
1352 /****************
1353  * This is a very limited implementation. It simply discards all internal
1354  * buffering and removes all filters but the first one.
1355  */
1356 int
1357 iobuf_seek( IOBUF a, ulong newpos )
1358 {
1359     file_filter_ctx_t *b = NULL;
1360
1361     if( a->directfp ) {
1362         FILE *fp = a->directfp;
1363         if( fseek( fp, newpos, SEEK_SET ) ) {
1364             log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
1365             return -1;
1366         }
1367         clearerr(fp);
1368     }
1369     else {
1370         for( ; a; a = a->chain ) {
1371             if( !a->chain && a->filter == file_filter ) {
1372                 b = a->filter_ov;
1373                 break;
1374             }
1375         }
1376         if( !a )
1377             return -1;
1378         if( fseek( b->fp, newpos, SEEK_SET ) ) {
1379             log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
1380             return -1;
1381         }
1382     }
1383     a->d.len = 0;   /* discard buffer */
1384     a->d.start = 0;
1385     a->nbytes = 0;
1386     a->nlimit = 0;
1387     a->nofast &= ~1;
1388     a->ntotal = newpos;
1389     a->error = 0;
1390     /* remove filters, but the last */
1391     if( a->chain )
1392         log_debug("pop_filter called in iobuf_seek - please report\n");
1393     while( a->chain )
1394        pop_filter( a, a->filter, NULL );
1395
1396     return 0;
1397 }
1398
1399
1400
1401
1402
1403
1404 /****************
1405  * Retrieve the real filename
1406  */
1407 const char *
1408 iobuf_get_real_fname( IOBUF a )
1409 {
1410     if( a->real_fname )
1411         return a->real_fname;
1412
1413     /* the old solution */
1414     for( ; a; a = a->chain )
1415         if( !a->chain && a->filter == file_filter ) {
1416             file_filter_ctx_t *b = a->filter_ov;
1417             return b->print_only_name? NULL : b->fname;
1418         }
1419
1420     return NULL;
1421 }
1422
1423
1424 /****************
1425  * Retrieve the filename
1426  */
1427 const char *
1428 iobuf_get_fname( IOBUF a )
1429 {
1430     for( ; a; a = a->chain )
1431         if( !a->chain && a->filter == file_filter ) {
1432             file_filter_ctx_t *b = a->filter_ov;
1433             return b->fname;
1434         }
1435
1436     return NULL;
1437 }
1438
1439 /****************
1440  * Start the block write mode, see rfc1991.new for details.
1441  * A value of 0 for N stops this mode (flushes and writes
1442  * the end marker)
1443  */
1444 void
1445 iobuf_set_block_mode( IOBUF a, size_t n )
1446 {
1447     block_filter_ctx_t *ctx = gcry_xcalloc( 1, sizeof *ctx );
1448
1449     assert( a->use == 1 || a->use == 2 );
1450     ctx->use = a->use;
1451     if( !n ) {
1452         if( a->use == 1 )
1453             log_debug("pop_filter called in set_block_mode - please report\n");
1454         pop_filter(a, block_filter, NULL );
1455     }
1456     else {
1457         ctx->size = n; /* only needed for use 2 */
1458         iobuf_push_filter(a, block_filter, ctx );
1459     }
1460 }
1461
1462 /****************
1463  * enable partial block mode as described in the OpenPGP draft.
1464  * LEN is the first length byte on read, but ignored on writes.
1465  */
1466 void
1467 iobuf_set_partial_block_mode( IOBUF a, size_t len )
1468 {
1469     block_filter_ctx_t *ctx = gcry_xcalloc( 1, sizeof *ctx );
1470
1471     assert( a->use == 1 || a->use == 2 );
1472     ctx->use = a->use;
1473     if( !len ) {
1474         if( a->use == 1 )
1475             log_debug("pop_filter called in set_partial_block_mode"
1476                                                     " - please report\n");
1477         pop_filter(a, block_filter, NULL );
1478     }
1479     else {
1480         ctx->partial = 1;
1481         ctx->size = 0;
1482         ctx->first_c = len;
1483         iobuf_push_filter(a, block_filter, ctx );
1484     }
1485 }
1486
1487
1488 /****************
1489  * Checks whether the stream is in block mode
1490  * Note: This does not work if other filters are pushed on the stream.
1491  */
1492 int
1493 iobuf_in_block_mode( IOBUF a )
1494 {
1495     if( a && a->filter == block_filter )
1496         return 1; /* yes */
1497     return 0; /* no */
1498 }
1499
1500
1501 /****************
1502  * Same as fgets() but if the buffer is too short a larger one will
1503  * be allocated up to some limit *max_length.
1504  * A line is considered a byte stream ending in a LF.
1505  * Returns the length of the line. EOF is indicated by a line of
1506  * length zero. The last LF may be missing due to an EOF.
1507  * is max_length is zero on return, the line has been truncated.
1508  *
1509  * Note: The buffer is allocated with enough space to append a CR,LF,EOL
1510  */
1511 unsigned
1512 iobuf_read_line( IOBUF a, byte **addr_of_buffer,
1513                           unsigned *length_of_buffer, unsigned *max_length )
1514 {
1515     int c;
1516     char *buffer = *addr_of_buffer;
1517     unsigned length = *length_of_buffer;
1518     unsigned nbytes = 0;
1519     unsigned maxlen = *max_length;
1520     char *p;
1521
1522     if( !buffer ) { /* must allocate a new buffer */
1523         length = 256;
1524         buffer = gcry_xmalloc( length );
1525         *addr_of_buffer = buffer;
1526         *length_of_buffer = length;
1527     }
1528
1529     length -= 3; /* reserve 3 bytes (cr,lf,eol) */
1530     p = buffer;
1531     while( (c=iobuf_get(a)) != -1 ) {
1532         if( nbytes == length ) { /* increase the buffer */
1533             if( length > maxlen  ) { /* this is out limit */
1534                 /* skip the rest of the line */
1535                 while( c != '\n' && (c=iobuf_get(a)) != -1 )
1536                     ;
1537                 *p++ = '\n'; /* always append a LF (we have reserved space) */
1538                 nbytes++;
1539                 *max_length = 0; /* indicate truncation */
1540                 break;
1541             }
1542             length += 3; /* correct for the reserved byte */
1543             length += length < 1024? 256 : 1024;
1544             buffer = gcry_xrealloc( buffer, length );
1545             *addr_of_buffer = buffer;
1546             *length_of_buffer = length;
1547             length -= 3; /* and reserve again */
1548             p = buffer + nbytes;
1549         }
1550         *p++ = c;
1551         nbytes++;
1552         if( c == '\n' )
1553             break;
1554     }
1555     *p = 0; /* make sure the line is a string */
1556
1557     return nbytes;
1558 }
1559