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