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