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