new release
[gnupg.git] / util / iobuf.c
1 /* iobuf.c  -  file handling
2  *      Copyright (C) 1998 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
31 #include "memory.h"
32 #include "util.h"
33 #include "iobuf.h"
34
35 typedef struct {
36     FILE *fp;      /* open file handle */
37     char fname[1]; /* name of the file */
38 } file_filter_ctx_t ;
39
40 typedef struct {
41     int usage;
42     size_t size;
43     size_t count;
44     int partial;  /* 1 = partial header, 2 in last partial packet */
45     int eof;
46 } block_filter_ctx_t;
47
48 static int underflow(IOBUF a);
49
50 /****************
51  * Read data from a file into buf which has an allocated length of *LEN.
52  * return the number of read bytes in *LEN. OPAQUE is the FILE * of
53  * the stream. A is not used.
54  * control may be:
55  * IOBUFCTRL_INIT: called just before the function is linked into the
56  *                 list of function. This can be used to prepare internal
57  *                 data structures of the function.
58  * IOBUFCTRL_FREE: called just before the function is removed from the
59  *                  list of functions and can be used to release internal
60  *                  data structures or close a file etc.
61  * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer
62  *                  with new stuff. *RET_LEN is the available size of the
63  *                  buffer, and should be set to the number of bytes
64  *                  which were put into the buffer. The function
65  *                  returns 0 to indicate success, -1 on EOF and
66  *                  G10ERR_xxxxx for other errors.
67  *
68  * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff.
69  *                  *RET_LAN is the number of bytes in BUF.
70  *
71  */
72 static int
73 file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
74 {
75     file_filter_ctx_t *a = opaque;
76     FILE *fp = a->fp;
77     size_t size = *ret_len;
78     size_t nbytes = 0;
79     int c, rc = 0;
80     char *p;
81
82     if( control == IOBUFCTRL_UNDERFLOW ) {
83         assert( size ); /* need a buffer */
84         for(; size; size-- ) {
85             if( (c=getc(fp)) == EOF ) {
86                 if( ferror(fp) ) {
87                     log_error("%s: read error: %s\n",
88                                         a->fname, strerror(errno));
89                     rc = G10ERR_READ_FILE;
90                 }
91                 else if( !nbytes )
92                     rc = -1; /* okay: we can return EOF now. */
93                 break;
94             }
95             buf[nbytes++] = c & 0xff;
96         }
97         *ret_len = nbytes;
98     }
99     else if( control == IOBUFCTRL_FLUSH ) {
100         for(p=buf; nbytes < size; nbytes++, p++ ) {
101             if( putc(*p, fp) == EOF ) {
102                 log_error("%s: write error: %s\n",
103                                     a->fname, strerror(errno));
104                 rc = G10ERR_WRITE_FILE;
105                 break;
106             }
107         }
108         *ret_len = nbytes;
109     }
110     else if( control == IOBUFCTRL_INIT ) {
111     }
112     else if( control == IOBUFCTRL_DESC ) {
113         *(char**)buf = "file_filter";
114     }
115     else if( control == IOBUFCTRL_FREE ) {
116         if( fp != stdin && fp != stdout )
117             fclose(fp);
118         fp = NULL;
119         m_free(a); /* we can free our context now */
120     }
121
122     return rc;
123 }
124
125
126 /****************
127  * This is used to implement the block write mode.
128  * Block reading is done on a byte by byte basis in readbyte(),
129  * without a filter
130  */
131 static int
132 block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
133 {
134     block_filter_ctx_t *a = opaque;
135     size_t size = *ret_len;
136     int c, rc = 0;
137     char *p;
138
139     if( control == IOBUFCTRL_UNDERFLOW ) {
140         size_t n=0;
141
142         p = buf;
143         assert( size ); /* need a buffer */
144         if( a->eof ) /* don't read any further */
145             rc = -1;
146         while( !rc && size ) {
147             if( !a->size ) { /* get the length bytes */
148                 if( a->partial == 2 ) {
149                     a->eof = 1;
150                     if( !n )
151                         rc = -1;
152                     break;
153                 }
154                 else if( a->partial ) {
155                     if( (c = iobuf_get(chain)) == -1 ) {
156                         log_error("block_filter: 1st length byte missing\n");
157                         rc = G10ERR_READ_FILE;
158                         break;
159                     }
160                     if( c < 192 ) {
161                         a->size = c;
162                         a->partial = 2;
163                         if( !a->size ) {
164                             a->eof = 1;
165                             if( !n )
166                                 rc = -1;
167                             break;
168                         }
169                     }
170                     else if( c < 224 ) {
171                         a->size = (c - 192) * 256;
172                         if( (c = iobuf_get(chain)) == -1 ) {
173                             log_error("block_filter: 2nd length byte missing\n");
174                             rc = G10ERR_READ_FILE;
175                             break;
176                         }
177                         a->size += c + 192;
178                         a->partial = 2;
179                         if( !a->size ) {
180                             a->eof = 1;
181                             if( !n )
182                                 rc = -1;
183                             break;
184                         }
185                     }
186                     else { /* next partial body length */
187                         a->size = 1 << (c & 0x1f);
188                     }
189                 }
190                 else {
191                     c = iobuf_get(chain);
192                     a->size = c << 8;
193                     c = iobuf_get(chain);
194                     a->size |= c;
195                     if( c == -1 ) {
196                         log_error("block_filter: error reading length info\n");
197                         rc = G10ERR_READ_FILE;
198                     }
199                     if( !a->size ) {
200                         a->eof = 1;
201                         if( !n )
202                             rc = -1;
203                         break;
204                     }
205                 }
206             }
207
208             for(; !rc && size && a->size; size--, a->size-- ) {
209                 if( (c=iobuf_get(chain)) == -1 ) {
210                     log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n",
211                                 a,  (ulong)size, (ulong)a->size);
212                     rc = G10ERR_READ_FILE;
213                 }
214                 else {
215                     *p++ = c;
216                     n++;
217                 }
218             }
219         }
220         *ret_len = n;
221     }
222     else if( control == IOBUFCTRL_FLUSH ) {
223         size_t avail, n;
224
225         assert( !a->partial );
226         for(p=buf; !rc && size; ) {
227             n = size;
228             avail = a->size - a->count;
229             if( !avail ) {
230                 if( n > a->size ) {
231                     iobuf_put( chain, (a->size >> 8) & 0xff );
232                     iobuf_put( chain, a->size & 0xff );
233                     avail = a->size;
234                     a->count = 0;
235                 }
236                 else {
237                     iobuf_put( chain, (n >> 8) & 0xff );
238                     iobuf_put( chain, n & 0xff );
239                     avail = n;
240                     a->count = a->size - n;
241                 }
242             }
243             if( n > avail )
244                 n = avail;
245             if( iobuf_write(chain, p, n ) )
246                 rc = G10ERR_WRITE_FILE;
247             a->count += n;
248             p += n;
249             size -= n;
250         }
251     }
252     else if( control == IOBUFCTRL_INIT ) {
253         if( DBG_IOBUF )
254             log_debug("init block_filter %p\n", a );
255         if( a->partial )
256             a->count = 0;
257         else if( a->usage == 1 )
258             a->count = a->size = 0;
259         else
260             a->count = a->size; /* force first length bytes */
261         a->eof = 0;
262     }
263     else if( control == IOBUFCTRL_DESC ) {
264         *(char**)buf = "block_filter";
265     }
266     else if( control == IOBUFCTRL_FREE ) {
267         if( a->usage == 2 ) { /* write the end markers */
268             if( a->partial ) {
269             }
270             else {
271                 iobuf_writebyte(chain, 0);
272                 iobuf_writebyte(chain, 0);
273             }
274         }
275         else if( a->size ) {
276             log_error("block_filter: pending bytes!\n");
277         }
278         if( DBG_IOBUF )
279             log_debug("free block_filter %p\n", a );
280         m_free(a); /* we can free our context now */
281     }
282
283     return rc;
284 }
285
286
287
288 /****************
289  * Allocate a new io buffer, with no function assigned.
290  * Usage is the desired usage: 1 for input, 2 for output, 3 for temp buffer
291  * BUFSIZE is a suggested buffer size.
292  */
293 IOBUF
294 iobuf_alloc(int usage, size_t bufsize)
295 {
296     IOBUF a;
297     static int number=0;
298
299     a = m_alloc_clear(sizeof *a);
300     a->usage = usage;
301     a->d.buf = m_alloc( bufsize );
302     a->d.size = bufsize;
303     a->no = ++number;
304     a->subno = 0;
305     a->opaque = NULL;
306     return a;
307 }
308
309
310 int
311 iobuf_close( IOBUF a )
312 {
313     IOBUF a2;
314     size_t dummy_len;
315     int rc=0;
316
317     for( ; a && !rc ; a = a2 ) {
318         a2 = a->chain;
319         if( a->usage == 2 && (rc=iobuf_flush(a)) )
320             log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc));
321
322         if( DBG_IOBUF )
323             log_debug("iobuf-%d.%d: close '%s'\n", a->no, a->subno, a->desc );
324         if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE,
325                                          a->chain, NULL, &dummy_len)) )
326             log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) );
327         m_free(a->d.buf);
328         m_free(a);
329     }
330     return rc;
331 }
332
333 int
334 iobuf_cancel( IOBUF a )
335 {
336     const char *s;
337
338     if( a && a->usage == 2 ) {
339         s = iobuf_get_fname(a);
340         if( s && *s )
341             remove(s);  /* remove the file. Fixme: this will fail for MSDOZE*/
342     }                   /* because the file is still open */
343     return iobuf_close(a);
344 }
345
346
347 /****************
348  * create a temporary iobuf, which can be used to collect stuff
349  * in an iobuf and later be written by iobuf_write_temp() to another
350  * iobuf.
351  */
352 IOBUF
353 iobuf_temp()
354 {
355     IOBUF a;
356
357     a = iobuf_alloc(3, 8192 );
358
359     return a;
360 }
361
362
363 /****************
364  * Create a head iobuf for reading from a file
365  * returns: NULL if an error occures and sets errno
366  */
367 IOBUF
368 iobuf_open( const char *fname )
369 {
370     IOBUF a;
371     FILE *fp;
372     file_filter_ctx_t *fcx;
373     size_t len;
374
375     if( !fname || (*fname=='-' && !fname[1])  ) {
376         fp = stdin; /* fixme: set binary mode for msdoze */
377         fname = "[stdin]";
378     }
379     else if( !(fp = fopen(fname, "rb")) )
380         return NULL;
381     a = iobuf_alloc(1, 8192 );
382     fcx = m_alloc( sizeof *fcx + strlen(fname) );
383     fcx->fp = fp;
384     strcpy(fcx->fname, fname );
385     a->filter = file_filter;
386     a->filter_ov = fcx;
387     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
388     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
389     if( DBG_IOBUF )
390         log_debug("iobuf-%d.%d: open '%s'\n", a->no, a->subno, fname );
391
392     return a;
393 }
394
395 /****************
396  * create an iobuf for writing to a file; the file will be created.
397  */
398 IOBUF
399 iobuf_create( const char *fname )
400 {
401     IOBUF a;
402     FILE *fp;
403     file_filter_ctx_t *fcx;
404     size_t len;
405
406     if( !fname || (*fname=='-' && !fname[1]) ) {
407         fp = stdout;
408         fname = "[stdout]";
409     }
410     else if( !(fp = fopen(fname, "wb")) )
411         return NULL;
412     a = iobuf_alloc(2, 8192 );
413     fcx = m_alloc( sizeof *fcx + strlen(fname) );
414     fcx->fp = fp;
415     strcpy(fcx->fname, fname );
416     a->filter = file_filter;
417     a->filter_ov = fcx;
418     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
419     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
420     if( DBG_IOBUF )
421         log_debug("iobuf-%d.%d: create '%s'\n", a->no, a->subno, a->desc );
422
423     return a;
424 }
425
426 /****************
427  * append to an iobuf; if the file does not exist, create it.
428  * cannot be used for stdout.
429  */
430 IOBUF
431 iobuf_append( const char *fname )
432 {
433     IOBUF a;
434     FILE *fp;
435     file_filter_ctx_t *fcx;
436     size_t len;
437
438     if( !fname )
439         return NULL;
440     else if( !(fp = fopen(fname, "ab")) )
441         return NULL;
442     a = iobuf_alloc(2, 8192 );
443     fcx = m_alloc( sizeof *fcx + strlen(fname) );
444     fcx->fp = fp;
445     strcpy(fcx->fname, fname );
446     a->filter = file_filter;
447     a->filter_ov = fcx;
448     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
449     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
450     if( DBG_IOBUF )
451         log_debug("iobuf-%d.%d: append '%s'\n", a->no, a->subno, a->desc );
452
453     return a;
454 }
455
456 IOBUF
457 iobuf_openrw( const char *fname )
458 {
459     IOBUF a;
460     FILE *fp;
461     file_filter_ctx_t *fcx;
462     size_t len;
463
464     if( !fname )
465         return NULL;
466     else if( !(fp = fopen(fname, "r+b")) )
467         return NULL;
468     a = iobuf_alloc(2, 8192 );
469     fcx = m_alloc( sizeof *fcx + strlen(fname) );
470     fcx->fp = fp;
471     strcpy(fcx->fname, fname );
472     a->filter = file_filter;
473     a->filter_ov = fcx;
474     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
475     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
476     if( DBG_IOBUF )
477         log_debug("iobuf-%d.%d: openrw '%s'\n", a->no, a->subno, a->desc );
478
479     return a;
480 }
481
482 /****************
483  * Register an i/o filter.
484  */
485 int
486 iobuf_push_filter( IOBUF a,
487                    int (*f)(void *opaque, int control,
488                    IOBUF chain, byte *buf, size_t *len), void *ov )
489 {
490     IOBUF b;
491     size_t dummy_len=0;
492     int rc=0;
493
494     if( a->usage == 2 && (rc=iobuf_flush(a)) )
495         return rc;
496     /* make a copy of the current stream, so that
497      * A is the new stream and B the original one.
498      * The contents of the buffers are transferred to the
499      * new stream.
500      */
501     b = m_alloc(sizeof *b);
502     memcpy(b, a, sizeof *b );
503     /* remove the filter stuff from the new stream */
504     a->filter = NULL;
505     a->filter_ov = NULL;
506     a->filter_eof = 0;
507     if( a->usage == 2 ) { /* allocate a fresh buffer for the original stream */
508         b->d.buf = m_alloc( a->d.size );
509         b->d.len = 0;
510         b->d.start = 0;
511     }
512     else { /* allocate a fresh buffer for the new stream */
513         a->d.buf = m_alloc( a->d.size );
514         a->d.len = 0;
515         a->d.start = 0;
516     }
517     /* disable nlimit for the new stream */
518     a->ntotal = b->ntotal + b->nbytes;
519     a->nlimit = a->nbytes = 0;
520     /* make a link from the new stream to the original stream */
521     a->chain = b;
522     a->opaque = b->opaque;
523
524     /* setup the function on the new stream */
525     a->filter = f;
526     a->filter_ov = ov;
527
528     a->subno = b->subno + 1;
529     f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len );
530
531     if( DBG_IOBUF ) {
532         log_debug("iobuf-%d.%d: push '%s'\n", a->no, a->subno, a->desc );
533         for(b=a; b; b = b->chain )
534             log_debug("\tchain: %d.%d '%s'\n", b->no, b->subno, b->desc );
535     }
536
537     /* now we can initialize the new function if we have one */
538     if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain,
539                        NULL, &dummy_len)) )
540         log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) );
541     return rc;
542 }
543
544 /****************
545  * Remove an i/o filter.
546  */
547 int
548 iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control,
549                       IOBUF chain, byte *buf, size_t *len), void *ov )
550 {
551     IOBUF b;
552     size_t dummy_len=0;
553     int rc=0;
554
555     if( DBG_IOBUF )
556         log_debug("iobuf-%d.%d: pop '%s'\n", a->no, a->subno, a->desc );
557     if( !a->filter ) { /* this is simple */
558         b = a->chain;
559         assert(b);
560         m_free(a->d.buf);
561         memcpy(a,b, sizeof *a);
562         m_free(b);
563         return 0;
564     }
565     for(b=a ; b; b = b->chain )
566         if( b->filter == f && (!ov || b->filter_ov == ov) )
567             break;
568     if( !b )
569         log_bug("iobuf_pop_filter(): filter function not found\n");
570
571     /* flush this stream if it is an output stream */
572     if( a->usage == 2 && (rc=iobuf_flush(b)) ) {
573         log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc));
574         return rc;
575     }
576     /* and tell the filter to free it self */
577     if( (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain,
578                        NULL, &dummy_len)) ) {
579         log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
580         return rc;
581     }
582
583     /* and see how to remove it */
584     if( a == b && !b->chain )
585         log_bug("can't remove the last filter from the chain\n");
586     else if( a == b ) { /* remove the first iobuf from the chain */
587         /* everything from b is copied to a. This is save because
588          * a flush has been done on the to be removed entry
589          */
590         b = a->chain;
591         m_free(a->d.buf);
592         memcpy(a,b, sizeof *a);
593         m_free(b);
594     }
595     else if( !b->chain ) { /* remove the last iobuf from the chain */
596         log_bug("Ohh jeee, trying to remove a head filter\n");
597     }
598     else {  /* remove an intermediate iobuf from the chain */
599         log_bug("Ohh jeee, trying to remove an intermediate filter\n");
600     }
601
602     return rc;
603 }
604
605
606
607 /****************
608  * read underflow: read more bytes into the buffer and return
609  * the first byte or -1 on EOF.
610  */
611 static int
612 underflow(IOBUF a)
613 {
614     size_t len;
615     int rc;
616
617   /*log_debug("iobuf-%d.%d: underflow: start=%lu len=%lu\n",
618                 a->no, a->subno, (ulong)a->d.start, (ulong)a->d.len );*/
619     assert( a->d.start == a->d.len );
620     if( a->usage == 3 )
621         return -1; /* EOF because a temp buffer can't do an underflow */
622     if( a->filter_eof ) {
623         if( DBG_IOBUF )
624             log_debug("iobuf-%d.%d: filter eof\n", a->no, a->subno );
625         return -1;
626     }
627
628     if( a->filter ) {
629         len = a->d.size;
630         rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
631                         a->d.buf, &len );
632         if( a->usage == 1 && rc == -1 ) { /* EOF: we can remove the filter */
633             size_t dummy_len;
634
635             /* and tell the filter to free it self */
636             if( a->filter != file_filter ) {
637                 if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
638                                    NULL, &dummy_len)) )
639                     log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
640                 a->filter = NULL;
641                 a->desc = NULL;
642                 a->filter_ov = NULL;
643             }
644             a->filter_eof = 1;
645         }
646
647         if( !len )
648             return -1;
649         a->d.len = len;
650         a->d.start = 0;
651         return a->d.buf[a->d.start++];
652     }
653     else
654         return -1;  /* no filter; return EOF */
655 }
656
657
658 void
659 iobuf_clear_eof(IOBUF a)
660 {
661     assert(a->usage == 1);
662
663     if( a->filter )
664         log_info("iobuf-%d.%d: clear_eof '%s' with enabled filter\n", a->no, a->subno, a->desc );
665     if( !a->filter_eof )
666         log_info("iobuf-%d.%d: clear_eof '%s' with no EOF pending\n", a->no, a->subno, a->desc );
667     iobuf_pop_filter(a, NULL, NULL);
668 }
669
670
671 int
672 iobuf_flush(IOBUF a)
673 {
674     size_t len;
675     int rc;
676
677     /*log_debug("iobuf-%d.%d: flush\n", a->no, a->subno );*/
678     if( a->usage == 3 )
679         log_bug("temp buffer too short\n");
680     else if( a->usage != 2 )
681         log_bug("flush on non-output iobuf\n");
682     else if( !a->filter )
683         log_bug("iobuf_flush: no filter\n");
684     len = a->d.len;
685     rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len );
686     if( !rc && len != a->d.len ) {
687         log_info("iobuf_flush did not write all!\n");
688         rc = G10ERR_WRITE_FILE;
689     }
690     a->d.len = 0;
691
692     return rc;
693 }
694
695
696 /****************
697  * Read a byte from the iobuf; returns -1 on EOF
698  */
699 int
700 iobuf_readbyte(IOBUF a)
701 {
702     int c;
703
704     /* nlimit does not work together with unget */
705     /* nbytes is also not valid! */
706     if( a->unget.buf ) {
707         if( a->unget.start < a->unget.len )
708             return a->unget.buf[a->unget.start++];
709         m_free(a->unget.buf);
710         a->unget.buf = NULL;
711     }
712
713     if( a->nlimit && a->nbytes >= a->nlimit )
714         return -1; /* forced EOF */
715
716     if( a->d.start < a->d.len ) {
717         c = a->d.buf[a->d.start++];
718     }
719     else if( (c=underflow(a)) == -1 )
720         return -1; /* EOF */
721
722     a->nbytes++;
723     return c;
724 }
725
726
727 int
728 iobuf_read(IOBUF a, byte *buf, unsigned buflen )
729 {
730     int c, n;
731
732     if( a->unget.buf || a->nlimit ) {
733         /* handle special cases */
734         for(n=0 ; n < buflen; n++, buf++ ) {
735             if( (c = iobuf_readbyte(a)) == -1 ) {
736                 if( !n )
737                     return -1; /* eof */
738                 break;
739             }
740             else
741                 *buf = c;
742         }
743         return n;
744     }
745
746     n = 0;
747     do {
748         for( ; n < buflen && a->d.start < a->d.len; n++ )
749             *buf++ = a->d.buf[a->d.start++];
750         if( n < buflen ) {
751             if( (c=underflow(a)) == -1 ) {
752                 a->nbytes += n;
753                 return n? n : -1/*EOF*/;
754             }
755             *buf++ = c; n++;
756         }
757     } while( n < buflen );
758     a->nbytes += n;
759     return n;
760 }
761
762
763 /****************
764  * Have a look at the iobuf.
765  * NOTE: This only works in special cases.
766  */
767 int
768 iobuf_peek(IOBUF a, byte *buf, unsigned buflen )
769 {
770     int n=0;
771
772     if( !(a->d.start < a->d.len) ) {
773         if( underflow(a) == -1 )
774             return -1;
775         /* and unget this character */
776         assert(a->d.start == 1);
777         a->d.start = 0;
778     }
779
780     for(n=0 ; n < buflen && (a->d.start+n) < a->d.len ; n++, buf++ )
781         *buf = a->d.buf[n];
782     return n;
783 }
784
785
786
787
788 int
789 iobuf_writebyte(IOBUF a, unsigned c)
790 {
791     if( a->d.len == a->d.size )
792         if( iobuf_flush(a) )
793             return -1;
794
795     assert( a->d.len < a->d.size );
796     a->d.buf[a->d.len++] = c;
797     return 0;
798 }
799
800
801 int
802 iobuf_write(IOBUF a, byte *buf, unsigned buflen )
803 {
804     do {
805         for( ; buflen && a->d.len < a->d.size; buflen--, buf++ )
806             a->d.buf[a->d.len++] = *buf;
807         if( buflen ) {
808             if( iobuf_flush(a) )
809                 return -1;
810         }
811     } while( buflen );
812     return 0;
813 }
814
815
816 int
817 iobuf_writestr(IOBUF a, const char *buf )
818 {
819     for( ; *buf; buf++ )
820         if( iobuf_writebyte(a, *buf) )
821             return -1;
822     return 0;
823 }
824
825
826
827 /****************
828  * copy the contents of TEMP to A.
829  */
830 int
831 iobuf_write_temp( IOBUF a, IOBUF temp )
832 {
833     return iobuf_write(a, temp->d.buf, temp->d.len );
834 }
835
836 /****************
837  * copy the contents of the temp io stream to BUFFER.
838  */
839 size_t
840 iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
841 {
842     size_t n = a->d.len;
843
844     if( n > buflen )
845         n = buflen;
846     memcpy( buffer, a->d.buf, n );
847     return n;
848 }
849
850 /****************
851  * unget the contents of the temp io stream to A and close temp
852  * Could be optimized!!
853  */
854 void
855 iobuf_unget_and_close_temp( IOBUF a, IOBUF temp )
856 {
857     if( a->unget.buf ) {
858         if( a->unget.start < a->unget.len )
859             log_fatal("cannot do any more ungets on this buffer\n");
860         /* not yet cleaned up; do it now */
861         m_free(a->unget.buf);
862         a->unget.buf = NULL;
863     }
864     a->unget.size = temp->d.len;
865     a->unget.buf = m_alloc( a->unget.size );
866     a->unget.len = temp->d.len;
867     memcpy( a->unget.buf, temp->d.buf, a->unget.len );
868     iobuf_close(temp);
869 }
870
871
872 /****************
873  * Set a limit on how many bytes may be read from the input stream A.
874  * Setting the limit to 0 disables this feature.
875  */
876 void
877 iobuf_set_limit( IOBUF a, unsigned long nlimit )
878 {
879     a->nlimit = nlimit;
880     a->ntotal += a->nbytes;
881     a->nbytes = 0;
882 }
883
884
885
886 /****************
887  * Return the length of an open file
888  */
889 u32
890 iobuf_get_filelength( IOBUF a )
891 {
892     struct stat st;
893
894     for( ; a; a = a->chain )
895         if( !a->chain && a->filter == file_filter ) {
896             file_filter_ctx_t *b = a->filter_ov;
897             FILE *fp = b->fp;
898
899             if( !fstat(fileno(fp), &st) )
900                 return st.st_size;
901             log_error("fstat() failed: %s\n", strerror(errno) );
902             break;
903         }
904
905     return 0;
906 }
907
908 /****************
909  * Tell the file position, where the next read will take place
910  */
911 ulong
912 iobuf_tell( IOBUF a )
913 {
914     return a->ntotal + a->nbytes;
915 }
916
917
918
919 /****************
920  * This is a very limited implementation. It simply discards all internal
921  * buffering and removes all filters but the first one.
922  */
923 int
924 iobuf_seek( IOBUF a, ulong newpos )
925 {
926     file_filter_ctx_t *b = NULL;
927
928     for( ; a; a = a->chain ) {
929         if( !a->chain && a->filter == file_filter ) {
930             b = a->filter_ov;
931             break;
932         }
933     }
934     if( !a )
935         return -1;
936
937     if( fseek( b->fp, newpos, SEEK_SET ) ) {
938         log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
939         return -1;
940     }
941     a->d.len = 0;   /* discard buffer */
942     a->d.start = 0;
943     a->nbytes = 0;
944     a->nlimit = 0;
945     a->ntotal = newpos;
946     /* remove filters, but the last */
947     while( a->chain )
948         iobuf_pop_filter( a, a->filter, NULL );
949
950
951     return 0;
952 }
953
954
955
956
957
958
959 /****************
960  * Retrieve the filename
961  */
962 const char *
963 iobuf_get_fname( IOBUF a )
964 {
965     for( ; a; a = a->chain )
966         if( !a->chain && a->filter == file_filter ) {
967             file_filter_ctx_t *b = a->filter_ov;
968             return b->fname;
969         }
970
971     return NULL;
972 }
973
974 /****************
975  * Start the block write mode, see rfc1991.new for details.
976  * A value of 0 for N stops this mode (flushes and writes
977  * the end marker)
978  */
979 void
980 iobuf_set_block_mode( IOBUF a, size_t n )
981 {
982     block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
983
984     assert( a->usage == 1 || a->usage == 2 );
985     ctx->usage = a->usage;
986     if( !n ) {
987         iobuf_pop_filter(a, block_filter, NULL );
988     }
989     else {
990         ctx->size = n; /* only needed for usage 2 */
991         iobuf_push_filter(a, block_filter, ctx );
992     }
993 }
994
995 /****************
996  * enable partial block mode as described in the OpenPGP draft.
997  * LEN is the first length
998  */
999 void
1000 iobuf_set_partial_block_mode( IOBUF a, size_t len )
1001 {
1002     block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
1003
1004     assert( a->usage == 1 || a->usage == 2 );
1005     ctx->usage = a->usage;
1006     if( !len ) {
1007         iobuf_pop_filter(a, block_filter, NULL );
1008     }
1009     else {
1010         ctx->partial = 1;
1011         ctx->size = len;
1012         iobuf_push_filter(a, block_filter, ctx );
1013     }
1014 }
1015
1016
1017 /****************
1018  * Checks whether the stream is in block mode
1019  * Note: This does not work if other filters are pushed on the stream.
1020  */
1021 int
1022 iobuf_in_block_mode( IOBUF a )
1023 {
1024     if( a && a->filter == block_filter )
1025         return 1; /* yes */
1026     return 0; /* no */
1027 }
1028
1029
1030