72a14f5036f715131b369224e7f3118b0ce7f4f3
[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; 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     if( a->nlimit && a->nbytes >= a->nlimit )
704         return -1; /* forced EOF */
705
706     if( a->d.start < a->d.len ) {
707         c = a->d.buf[a->d.start++];
708     }
709     else if( (c=underflow(a)) == -1 )
710         return -1; /* EOF */
711
712     a->nbytes++;
713     return c;
714 }
715
716
717 int
718 iobuf_writebyte(IOBUF a, unsigned c)
719 {
720     if( a->d.len == a->d.size )
721         if( iobuf_flush(a) )
722             return -1;
723
724     assert( a->d.len < a->d.size );
725     a->d.buf[a->d.len++] = c;
726     return 0;
727 }
728
729
730 int
731 iobuf_write(IOBUF a, byte *buf, unsigned buflen )
732 {
733     for( ; buflen; buflen--, buf++ )
734         if( iobuf_writebyte(a, *buf) )
735             return -1;
736     return 0;
737 }
738
739 int
740 iobuf_writestr(IOBUF a, const char *buf )
741 {
742     for( ; *buf; buf++ )
743         if( iobuf_writebyte(a, *buf) )
744             return -1;
745     return 0;
746 }
747
748
749
750 /****************
751  * copy the contents of TEMP to A.
752  */
753 int
754 iobuf_write_temp( IOBUF a, IOBUF temp )
755 {
756     return iobuf_write(a, temp->d.buf, temp->d.len );
757 }
758
759 /****************
760  * copy the contents of the temp io stream to BUFFER.
761  */
762 size_t
763 iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
764 {
765     size_t n = a->d.len;
766
767     if( n > buflen )
768         n = buflen;
769     memcpy( buffer, a->d.buf, n );
770     return n;
771 }
772
773
774 /****************
775  * Set a limit, how much bytes may be read from the input stream A.
776  * Setting the limit to 0 disables this feature.
777  */
778 void
779 iobuf_set_limit( IOBUF a, unsigned long nlimit )
780 {
781     a->nlimit = nlimit;
782     a->ntotal += a->nbytes;
783     a->nbytes = 0;
784 }
785
786
787
788 /****************
789  * Return the length of an open file
790  */
791 u32
792 iobuf_get_filelength( IOBUF a )
793 {
794     struct stat st;
795
796     for( ; a; a = a->chain )
797         if( !a->chain && a->filter == file_filter ) {
798             file_filter_ctx_t *b = a->filter_ov;
799             FILE *fp = b->fp;
800
801             if( !fstat(fileno(fp), &st) )
802                 return st.st_size;
803             log_error("fstat() failed: %s\n", strerror(errno) );
804             break;
805         }
806
807     return 0;
808 }
809
810 /****************
811  * Tell the file position, where the next read will take place
812  */
813 ulong
814 iobuf_tell( IOBUF a )
815 {
816     return a->ntotal + a->nbytes;
817 }
818
819
820 int
821 iobuf_seek( IOBUF a, ulong newpos )
822 {
823     file_filter_ctx_t *b = NULL;
824
825     for( ; a; a = a->chain ) {
826         if( !a->chain && a->filter == file_filter ) {
827             b = a->filter_ov;
828             break;
829         }
830     }
831     if( !a )
832         return -1;
833
834     if( fseek( b->fp, newpos, SEEK_SET ) ) {
835         log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
836         return -1;
837     }
838     a->ntotal = newpos;
839     /* remove filters, but the last */
840     while( a->chain )
841         iobuf_pop_filter( a, a->filter, NULL );
842
843
844     return 0;
845 }
846
847
848
849
850
851
852 /****************
853  * Retrieve the filename
854  */
855 const char *
856 iobuf_get_fname( IOBUF a )
857 {
858     for( ; a; a = a->chain )
859         if( !a->chain && a->filter == file_filter ) {
860             file_filter_ctx_t *b = a->filter_ov;
861             return b->fname;
862         }
863
864     return NULL;
865 }
866
867 /****************
868  * Start the block write mode, see rfc1991.new for details.
869  * A value of 0 for N stops this mode (flushes and writes
870  * the end marker)
871  */
872 void
873 iobuf_set_block_mode( IOBUF a, size_t n )
874 {
875     block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
876
877     assert( a->usage == 1 || a->usage == 2 );
878     ctx->usage = a->usage;
879     if( !n ) {
880         iobuf_pop_filter(a, block_filter, NULL );
881     }
882     else {
883         ctx->size = n; /* only needed for usage 2 */
884         iobuf_push_filter(a, block_filter, ctx );
885     }
886 }
887
888 /****************
889  * enable patial block mode as descriped in the OpenPGP draft.
890  * LEN is the first length
891  */
892 void
893 iobuf_set_partial_block_mode( IOBUF a, size_t len )
894 {
895     block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
896
897     assert( a->usage == 1 || a->usage == 2 );
898     ctx->usage = a->usage;
899     if( !len ) {
900         iobuf_pop_filter(a, block_filter, NULL );
901     }
902     else {
903         ctx->partial = 1;
904         ctx->size = len;
905         iobuf_push_filter(a, block_filter, ctx );
906     }
907 }
908
909
910 /****************
911  * Checks wether the stream is in block mode
912  * Note: This does not work if other filters are pushed on the stream.
913  */
914 int
915 iobuf_in_block_mode( IOBUF a )
916 {
917     if( a && a->filter == block_filter )
918         return 1; /* yes */
919     return 0; /* no */
920 }
921
922
923