* iobuf.c (block_filter): Properly handle a partial body stream that ends
[gnupg.git] / util / iobuf.c
1 /* iobuf.c  -  file handling
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <assert.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h> 
32 #include <unistd.h>
33 #ifdef HAVE_DOSISH_SYSTEM
34 #include <windows.h>
35 #endif
36 #ifdef __riscos__
37 #include <kernel.h>
38 #include <swis.h>
39 #endif /* __riscos__ */
40
41 #include "memory.h"
42 #include "util.h"
43 #include "iobuf.h"
44
45 #undef FILE_FILTER_USES_STDIO
46
47 #ifdef HAVE_DOSISH_SYSTEM
48 #define USE_SETMODE 1
49 #endif
50
51 #ifdef FILE_FILTER_USES_STDIO
52 #define my_fileno(a)  fileno ((a))
53 #define my_fopen_ro(a,b) fopen ((a),(b))
54 #define my_fopen(a,b)    fopen ((a),(b))
55 typedef FILE *FILEP_OR_FD;
56 #define INVALID_FP    NULL
57 #define FILEP_OR_FD_FOR_STDIN  (stdin)
58 #define FILEP_OR_FD_FOR_STDOUT  (stdout)
59 typedef struct {
60      FILE *fp;     /* open file handle */
61      int keep_open;
62      int no_cache;
63      int  print_only_name; /* flags indicating that fname is not a real file*/
64      char fname[1]; /* name of the file */
65  } file_filter_ctx_t ;
66 #else
67 #define my_fileno(a)  (a)
68 #define my_fopen_ro(a,b) fd_cache_open ((a),(b)) 
69 #define my_fopen(a,b) direct_open ((a),(b)) 
70 #ifdef HAVE_DOSISH_SYSTEM
71 typedef HANDLE FILEP_OR_FD;
72 #define INVALID_FP  ((HANDLE)-1)
73 #define FILEP_OR_FD_FOR_STDIN  (GetStdHandle (STD_INPUT_HANDLE))
74 #define FILEP_OR_FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE))
75 #undef USE_SETMODE
76 #else
77 typedef int FILEP_OR_FD;
78 #define INVALID_FP  (-1)
79 #define FILEP_OR_FD_FOR_STDIN  (0)
80 #define FILEP_OR_FD_FOR_STDOUT (1)
81 #endif
82 typedef struct {
83      FILEP_OR_FD  fp;      /* open file handle */
84      int keep_open;
85      int no_cache;
86      int eof_seen;
87      int  print_only_name; /* flags indicating that fname is not a real file*/
88      char fname[1]; /* name of the file */
89  } file_filter_ctx_t ;
90
91  struct close_cache_s { 
92     struct close_cache_s *next;
93     FILEP_OR_FD fp;
94     char fname[1];
95  };
96  typedef struct close_cache_s *CLOSE_CACHE;
97  static CLOSE_CACHE close_cache;
98 #endif
99
100 #ifdef _WIN32
101 typedef struct {
102     int sock;
103     int keep_open;
104     int no_cache;
105     int eof_seen;
106     int  print_only_name; /* flags indicating that fname is not a real file*/
107     char fname[1]; /* name of the file */
108 } sock_filter_ctx_t ;
109 #endif /*_WIN32*/
110
111 /* The first partial length header block must be of size 512
112  * to make it easier (and efficienter) we use a min. block size of 512
113  * for all chunks (but the last one) */
114 #define OP_MIN_PARTIAL_CHUNK      512
115 #define OP_MIN_PARTIAL_CHUNK_2POW 9
116
117 typedef struct {
118     int use;
119     size_t size;
120     size_t count;
121     int partial;  /* 1 = partial header, 2 in last partial packet */
122     char *buffer;    /* used for partial header */
123     size_t buflen;   /* used size of buffer */
124     int first_c;     /* of partial header (which is > 0)*/
125     int eof;
126 } block_filter_ctx_t;
127
128 static int special_names_enabled;
129
130 static int underflow(IOBUF a);
131 static int translate_file_handle ( int fd, int for_write );
132
133 #ifndef FILE_FILTER_USES_STDIO
134
135 /*
136  * Invalidate (i.e. close) a cached iobuf
137  */
138 static void
139 fd_cache_invalidate (const char *fname)
140 {
141     CLOSE_CACHE cc;
142
143     assert (fname);
144     if( DBG_IOBUF )
145         log_debug ("fd_cache_invalidate (%s)\n", fname);
146
147     for (cc=close_cache; cc; cc = cc->next ) {
148         if ( cc->fp != INVALID_FP && !strcmp (cc->fname, fname) ) {
149             if( DBG_IOBUF )
150                 log_debug ("                did (%s)\n", cc->fname);
151 #ifdef HAVE_DOSISH_SYSTEM
152             CloseHandle (cc->fp);
153 #else
154             close(cc->fp);
155 #endif
156             cc->fp = INVALID_FP;
157         }
158     }
159 }
160
161
162
163 static FILEP_OR_FD
164 direct_open (const char *fname, const char *mode)
165 {
166 #ifdef HAVE_DOSISH_SYSTEM
167     unsigned long da, cd, sm;
168     HANDLE hfile;
169
170     /* Note, that we do not handle all mode combinations */
171
172     /* According to the ReactOS source it seems that open() of the
173      * standard MSW32 crt does open the file in share mode which is
174      * something new for MS applications ;-)
175      */
176     if ( strchr (mode, '+') ) {
177         fd_cache_invalidate (fname);
178         da = GENERIC_READ|GENERIC_WRITE;
179         cd = OPEN_EXISTING;
180         sm = FILE_SHARE_READ | FILE_SHARE_WRITE;
181     }
182     else if ( strchr (mode, 'w') ) {
183         fd_cache_invalidate (fname);
184         da = GENERIC_WRITE;
185         cd = CREATE_ALWAYS;
186         sm = FILE_SHARE_WRITE;
187     }
188     else {
189         da = GENERIC_READ;
190         cd = OPEN_EXISTING;
191         sm = FILE_SHARE_READ;
192     }
193
194     hfile = CreateFile (fname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL);
195     return hfile;
196 #else
197     int oflag;
198     int cflag = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
199
200     /* Note, that we do not handle all mode combinations */
201     if ( strchr (mode, '+') ) {
202         fd_cache_invalidate (fname);
203         oflag = O_RDWR;
204     }
205     else if ( strchr (mode, 'w') ) {
206         fd_cache_invalidate (fname);
207         oflag = O_WRONLY | O_CREAT | O_TRUNC;
208     }
209     else {
210         oflag = O_RDONLY;
211     }
212 #ifdef O_BINARY
213     if (strchr (mode, 'b'))
214       oflag |= O_BINARY;
215 #endif
216 #ifndef __riscos__
217     return open (fname, oflag, cflag );
218 #else
219     {
220         struct stat buf;
221         int rc = stat( fname, &buf );
222         
223         /* Don't allow iobufs on directories */
224         if( !rc && S_ISDIR(buf.st_mode) && !S_ISREG(buf.st_mode) )
225             return __set_errno( EISDIR );
226         else
227             return open( fname, oflag, cflag );
228     }
229 #endif
230 #endif
231 }
232
233
234 /*
235  * Instead of closing an FD we keep it open and cache it for later reuse 
236  * Note that this caching strategy only works if the process does not chdir.
237  */
238 static void
239 fd_cache_close (const char *fname, FILEP_OR_FD fp)
240 {
241     CLOSE_CACHE cc;
242
243     assert (fp);
244     if ( !fname || !*fname ) {
245 #ifdef HAVE_DOSISH_SYSTEM
246         CloseHandle (fp);
247 #else
248         close(fp);
249 #endif
250         if( DBG_IOBUF )
251             log_debug ("fd_cache_close (%p) real\n", (void*)fp);
252         return;
253     }
254     /* try to reuse a slot */
255     for (cc=close_cache; cc; cc = cc->next ) {
256         if ( cc->fp == INVALID_FP && !strcmp (cc->fname, fname) ) {
257             cc->fp = fp;
258             if( DBG_IOBUF )
259                 log_debug ("fd_cache_close (%s) used existing slot\n", fname);
260             return;
261         }
262     }
263     /* add a new one */
264     if( DBG_IOBUF )
265         log_debug ("fd_cache_close (%s) new slot created\n", fname);
266     cc = m_alloc_clear (sizeof *cc + strlen (fname));
267     strcpy (cc->fname, fname);
268     cc->fp = fp;
269     cc->next = close_cache;
270     close_cache = cc;
271 }
272
273 /*
274  * Do an direct_open on FNAME but first try to reuse one from the fd_cache
275  */
276 static FILEP_OR_FD
277 fd_cache_open (const char *fname, const char *mode)
278 {
279     CLOSE_CACHE cc;
280
281     assert (fname);
282     for (cc=close_cache; cc; cc = cc->next ) {
283         if ( cc->fp != INVALID_FP && !strcmp (cc->fname, fname) ) {
284             FILEP_OR_FD fp = cc->fp;
285             cc->fp = INVALID_FP;
286             if( DBG_IOBUF )
287                 log_debug ("fd_cache_open (%s) using cached fp\n", fname);
288 #ifdef HAVE_DOSISH_SYSTEM
289             if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff ) {
290                 log_error ("rewind file failed on handle %p: ec=%d\n",
291                            fp, (int)GetLastError () );
292                 fp = INVALID_FP;
293             }
294 #else
295             if ( lseek (fp, 0, SEEK_SET) == (off_t)-1 ) {
296                 log_error("can't rewind fd %d: %s\n", fp, strerror(errno) );
297                 fp = INVALID_FP;
298             }
299 #endif
300             return fp;
301         }
302     }
303     if( DBG_IOBUF )
304         log_debug ("fd_cache_open (%s) not cached\n", fname);
305     return direct_open (fname, mode);
306 }
307
308
309 #endif /*FILE_FILTER_USES_STDIO*/
310
311
312 /****************
313  * Read data from a file into buf which has an allocated length of *LEN.
314  * return the number of read bytes in *LEN. OPAQUE is the FILE * of
315  * the stream. A is not used.
316  * control may be:
317  * IOBUFCTRL_INIT: called just before the function is linked into the
318  *                 list of function. This can be used to prepare internal
319  *                 data structures of the function.
320  * IOBUFCTRL_FREE: called just before the function is removed from the
321  *                  list of functions and can be used to release internal
322  *                  data structures or close a file etc.
323  * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer
324  *                  with new stuff. *RET_LEN is the available size of the
325  *                  buffer, and should be set to the number of bytes
326  *                  which were put into the buffer. The function
327  *                  returns 0 to indicate success, -1 on EOF and
328  *                  G10ERR_xxxxx for other errors.
329  *
330  * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff.
331  *                  *RET_LAN is the number of bytes in BUF.
332  *
333  * IOBUFCTRL_CANCEL: send to all filters on behalf of iobuf_cancel.  The
334  *                  filter may take appropriate action on this message.
335  */
336 static int
337 file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
338 {
339     file_filter_ctx_t *a = opaque;
340     FILEP_OR_FD f = a->fp;
341     size_t size = *ret_len;
342     size_t nbytes = 0;
343     int rc = 0;
344
345 #ifdef FILE_FILTER_USES_STDIO
346     if( control == IOBUFCTRL_UNDERFLOW ) {
347         assert( size ); /* need a buffer */
348         if ( feof(f)) { /* On terminals you could easiely read as many EOFs as you call         */
349             rc = -1;            /* fread() or fgetc() repeatly. Every call will block until you press   */
350             *ret_len = 0;       /* CTRL-D. So we catch this case before we call fread() again.          */
351         }
352         else {
353             clearerr( f );
354             nbytes = fread( buf, 1, size, f );
355             if( feof(f) && !nbytes ) {
356                 rc = -1; /* okay: we can return EOF now. */
357             }
358             else if( ferror(f) && errno != EPIPE  ) {
359                 log_error("%s: read error: %s\n",
360                           a->fname, strerror(errno));
361                 rc = G10ERR_READ_FILE;
362             }
363             *ret_len = nbytes;
364         }
365     }
366     else if( control == IOBUFCTRL_FLUSH ) {
367         if( size ) {
368             clearerr( f );
369             nbytes = fwrite( buf, 1, size, f );
370             if( ferror(f) ) {
371                 log_error("%s: write error: %s\n", a->fname, strerror(errno));
372                 rc = G10ERR_WRITE_FILE;
373             }
374         }
375         *ret_len = nbytes;
376     }
377     else if( control == IOBUFCTRL_INIT ) {
378         a->keep_open = a->no_cache = 0;
379     }
380     else if( control == IOBUFCTRL_DESC ) {
381         *(char**)buf = "file_filter";
382     }
383     else if( control == IOBUFCTRL_FREE ) {
384         if( f != stdin && f != stdout ) {
385             if( DBG_IOBUF )
386                 log_debug("%s: close fd %d\n", a->fname, fileno(f) );
387             if (!a->keep_open)
388                 fclose(f);
389         }
390         f = NULL;
391         m_free(a); /* we can free our context now */
392     }
393 #else /* !stdio implementation */
394
395     if( control == IOBUFCTRL_UNDERFLOW ) {
396         assert( size ); /* need a buffer */
397         if ( a->eof_seen) {
398             rc = -1;            
399             *ret_len = 0;       
400         }
401         else {
402 #ifdef HAVE_DOSISH_SYSTEM
403             unsigned long nread;
404
405             nbytes = 0;
406             if ( !ReadFile ( f, buf, size, &nread, NULL ) ) {
407                 int ec = (int)GetLastError ();
408                 if ( ec != ERROR_BROKEN_PIPE ) {
409                     log_error("%s: read error: ec=%d\n", a->fname, ec);
410                     rc = G10ERR_READ_FILE;
411                 }
412             }
413             else if ( !nread ) {
414                 a->eof_seen = 1;
415                 rc = -1;
416             }
417             else {
418                 nbytes = nread;
419             }
420
421 #else
422
423             int n;
424
425             nbytes = 0;
426             do {
427                 n = read ( f, buf, size );
428             } while (n == -1 && errno == EINTR );
429             if ( n == -1 ) { /* error */
430                 if (errno != EPIPE) {
431                     log_error("%s: read error: %s\n",
432                               a->fname, strerror(errno));
433                     rc = G10ERR_READ_FILE;
434                 }
435             }
436             else if ( !n ) { /* eof */
437                 a->eof_seen = 1;
438                 rc = -1;
439             }
440             else {
441                 nbytes = n;
442             }
443 #endif
444             *ret_len = nbytes;
445         }
446     }
447     else if( control == IOBUFCTRL_FLUSH ) {
448         if( size ) {
449 #ifdef HAVE_DOSISH_SYSTEM
450             byte *p = buf;
451             unsigned long n;
452
453             nbytes = size;
454             do {
455                 if ( size && !WriteFile ( f,  p, nbytes, &n, NULL) ) {
456                     int ec = (int)GetLastError ();
457                     log_error("%s: write error: ec=%d\n", a->fname, ec);
458                     rc = G10ERR_WRITE_FILE;
459                     break;
460                 }
461                 p += n;
462                 nbytes -= n;
463             } while ( nbytes );
464             nbytes = p - buf;
465 #else
466             byte *p = buf;
467             int n;
468
469             nbytes = size;
470             do {
471                 do {
472                     n = write ( f, p, nbytes );
473                 } while ( n == -1 && errno == EINTR );
474                 if ( n > 0 ) {
475                     p += n;
476                     nbytes -= n;
477                 }
478             } while ( n != -1 && nbytes );
479             if( n == -1 ) {
480                 log_error("%s: write error: %s\n", a->fname, strerror(errno));
481                 rc = G10ERR_WRITE_FILE;
482             }
483             nbytes = p - buf;
484 #endif
485         }
486         *ret_len = nbytes;
487     }
488     else if ( control == IOBUFCTRL_INIT ) {
489         a->eof_seen = 0;
490         a->keep_open = 0;
491         a->no_cache = 0;
492     }
493     else if ( control == IOBUFCTRL_DESC ) {
494         *(char**)buf = "file_filter(fd)";
495     }
496     else if ( control == IOBUFCTRL_FREE ) {
497 #ifdef HAVE_DOSISH_SYSTEM
498         if ( f != FILEP_OR_FD_FOR_STDIN && f != FILEP_OR_FD_FOR_STDOUT ) {
499             if( DBG_IOBUF )
500                 log_debug("%s: close handle %p\n", a->fname, f );
501             if (!a->keep_open)
502                 fd_cache_close (a->no_cache?NULL:a->fname, f);
503         }
504 #else
505         if ( (int)f != 0 && (int)f != 1 ) {
506             if( DBG_IOBUF )
507                 log_debug("%s: close fd %d\n", a->fname, f );
508             if (!a->keep_open)
509                 fd_cache_close (a->no_cache?NULL:a->fname, f);
510         }
511         f = INVALID_FP;
512 #endif
513         m_free (a); /* we can free our context now */
514     }
515 #endif /* !stdio implementation */
516     return rc;
517 }
518
519 #ifdef _WIN32
520 /* Becuase sockets are an special object under Lose32 we have to
521  * use a special filter */
522 static int
523 sock_filter (void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
524 {
525     sock_filter_ctx_t *a = opaque;
526     size_t size = *ret_len;
527     size_t nbytes = 0;
528     int rc = 0;
529
530     if( control == IOBUFCTRL_UNDERFLOW ) {
531         assert( size ); /* need a buffer */
532         if ( a->eof_seen) {
533             rc = -1;            
534             *ret_len = 0;       
535         }
536         else {
537             int nread;
538
539             nread = recv ( a->sock, buf, size, 0 );
540             if ( nread == SOCKET_ERROR ) {
541                 int ec = (int)WSAGetLastError ();
542                 log_error("socket read error: ec=%d\n", ec);
543                 rc = G10ERR_READ_FILE;
544             }
545             else if ( !nread ) {
546                 a->eof_seen = 1;
547                 rc = -1;
548             }
549             else {
550                 nbytes = nread;
551             }
552             *ret_len = nbytes;
553         }
554     }
555     else if( control == IOBUFCTRL_FLUSH ) {
556         if( size ) {
557             byte *p = buf;
558             int n;
559
560             nbytes = size;
561             do {
562                 n = send (a->sock, p, nbytes, 0);
563                 if ( n == SOCKET_ERROR ) {
564                     int ec = (int)WSAGetLastError ();
565                     log_error("socket write error: ec=%d\n", ec);
566                     rc = G10ERR_WRITE_FILE;
567                     break;
568                 }
569                 p += n;
570                 nbytes -= n;
571             } while ( nbytes );
572             nbytes = p - buf;
573         }
574         *ret_len = nbytes;
575     }
576     else if ( control == IOBUFCTRL_INIT ) {
577         a->eof_seen = 0;
578         a->keep_open = 0;
579         a->no_cache = 0;
580     }
581     else if ( control == IOBUFCTRL_DESC ) {
582         *(char**)buf = "sock_filter";
583     }
584     else if ( control == IOBUFCTRL_FREE ) {
585         if (!a->keep_open)
586             closesocket (a->sock);
587         m_free (a); /* we can free our context now */
588     }
589     return rc;
590 }
591 #endif /*_WIN32*/
592
593 /****************
594  * This is used to implement the block write mode.
595  * Block reading is done on a byte by byte basis in readbyte(),
596  * without a filter
597  */
598 static int
599 block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
600 {
601     block_filter_ctx_t *a = opaque;
602     size_t size = *ret_len;
603     int c, needed, rc = 0;
604     char *p;
605
606     if( control == IOBUFCTRL_UNDERFLOW ) {
607         size_t n=0;
608
609         p = buf;
610         assert( size ); /* need a buffer */
611         if( a->eof ) /* don't read any further */
612             rc = -1;
613         while( !rc && size ) {
614             if( !a->size ) { /* get the length bytes */
615                 if( a->partial == 2 ) {
616                     a->eof = 1;
617                     if( !n )
618                         rc = -1;
619                     break;
620                 }
621                 else if( a->partial ) {
622                     /* These OpenPGP introduced huffman like encoded length
623                      * bytes are really a mess :-( */
624                     if( a->first_c ) {
625                         c = a->first_c;
626                         a->first_c = 0;
627                     }
628                     else if( (c = iobuf_get(chain)) == -1 ) {
629                         log_error("block_filter: 1st length byte missing\n");
630                         rc = G10ERR_READ_FILE;
631                         break;
632                     }
633                     if( c < 192 ) {
634                         a->size = c;
635                         a->partial = 2;
636                         if( !a->size ) {
637                             a->eof = 1;
638                             if( !n )
639                                 rc = -1;
640                             break;
641                         }
642                     }
643                     else if( c < 224 ) {
644                         a->size = (c - 192) * 256;
645                         if( (c = iobuf_get(chain)) == -1 ) {
646                             log_error("block_filter: 2nd length byte missing\n");
647                             rc = G10ERR_READ_FILE;
648                             break;
649                         }
650                         a->size += c + 192;
651                         a->partial = 2;
652                         if( !a->size ) {
653                             a->eof = 1;
654                             if( !n )
655                                 rc = -1;
656                             break;
657                         }
658                     }
659                     else if( c == 255 ) {
660                         a->size  = iobuf_get(chain) << 24;
661                         a->size |= iobuf_get(chain) << 16;
662                         a->size |= iobuf_get(chain) << 8;
663                         if( (c = iobuf_get(chain)) == -1 ) {
664                             log_error("block_filter: invalid 4 byte length\n");
665                             rc = G10ERR_READ_FILE;
666                             break;
667                         }
668                         a->size |= c;
669                         a->partial = 2;
670                         if( !a->size ) {
671                             a->eof = 1;
672                             if( !n )
673                                 rc = -1;
674                             break;
675                         }
676                     }
677                     else { /* next partial body length */
678                         a->size = 1 << (c & 0x1f);
679                     }
680             /*  log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size);*/
681                 }
682                 else { /* the gnupg partial length scheme - much better :-) */
683                     c = iobuf_get(chain);
684                     a->size = c << 8;
685                     c = iobuf_get(chain);
686                     a->size |= c;
687                     if( c == -1 ) {
688                         log_error("block_filter: error reading length info\n");
689                         rc = G10ERR_READ_FILE;
690                     }
691                     if( !a->size ) {
692                         a->eof = 1;
693                         if( !n )
694                             rc = -1;
695                         break;
696                     }
697                 }
698             }
699
700             while( !rc && size && a->size ) {
701                 needed = size < a->size ? size : a->size;
702                 c = iobuf_read( chain, p, needed );
703                 if( c < needed ) {
704                     if( c == -1 ) c = 0;
705                     log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n",
706                               a,  (ulong)size+c, (ulong)a->size+c);
707                     rc = G10ERR_READ_FILE;
708                 }
709                 else {
710                     size -= c;
711                     a->size -= c;
712                     p += c;
713                     n += c;
714                 }
715             }
716         }
717         *ret_len = n;
718     }
719     else if( control == IOBUFCTRL_FLUSH ) {
720         if( a->partial ) { /* the complicated openpgp scheme */
721             size_t blen, n, nbytes = size + a->buflen;
722
723             assert( a->buflen <= OP_MIN_PARTIAL_CHUNK );
724             if( nbytes < OP_MIN_PARTIAL_CHUNK ) {
725                 /* not enough to write a partial block out; so we store it*/
726                 if( !a->buffer )
727                     a->buffer = m_alloc( OP_MIN_PARTIAL_CHUNK );
728                 memcpy( a->buffer + a->buflen, buf, size );
729                 a->buflen += size;
730             }
731             else { /* okay, we can write out something */
732                 /* do this in a loop to use the most efficient block lengths */
733                 p = buf;
734                 do {
735                     /* find the best matching block length - this is limited
736                      * by the size of the internal buffering */
737                     for( blen=OP_MIN_PARTIAL_CHUNK*2,
738                             c=OP_MIN_PARTIAL_CHUNK_2POW+1; blen <= nbytes;
739                                                             blen *=2, c++ )
740                         ;
741                     blen /= 2; c--;
742                     /* write the partial length header */
743                     assert( c <= 0x1f ); /*;-)*/
744                     c |= 0xe0;
745                     iobuf_put( chain, c );
746                     if( (n=a->buflen) ) { /* write stuff from the buffer */
747                         assert( n == OP_MIN_PARTIAL_CHUNK);
748                         if( iobuf_write(chain, a->buffer, n ) )
749                             rc = G10ERR_WRITE_FILE;
750                         a->buflen = 0;
751                         nbytes -= n;
752                     }
753                     if( (n = nbytes) > blen )
754                         n = blen;
755                     if( n && iobuf_write(chain, p, n ) )
756                         rc = G10ERR_WRITE_FILE;
757                     p += n;
758                     nbytes -= n;
759                 } while( !rc && nbytes >= OP_MIN_PARTIAL_CHUNK );
760                 /* store the rest in the buffer */
761                 if( !rc && nbytes ) {
762                     assert( !a->buflen );
763                     assert( nbytes < OP_MIN_PARTIAL_CHUNK );
764                     if( !a->buffer )
765                         a->buffer = m_alloc( OP_MIN_PARTIAL_CHUNK );
766                     memcpy( a->buffer, p, nbytes );
767                     a->buflen = nbytes;
768                 }
769             }
770         }
771         else { /* the gnupg scheme (which is not openpgp compliant) */
772             size_t avail, n;
773
774             for(p=buf; !rc && size; ) {
775                 n = size;
776                 avail = a->size - a->count;
777                 if( !avail ) {
778                     if( n > a->size ) {
779                         iobuf_put( chain, (a->size >> 8) & 0xff );
780                         iobuf_put( chain, a->size & 0xff );
781                         avail = a->size;
782                         a->count = 0;
783                     }
784                     else {
785                         iobuf_put( chain, (n >> 8) & 0xff );
786                         iobuf_put( chain, n & 0xff );
787                         avail = n;
788                         a->count = a->size - n;
789                     }
790                 }
791                 if( n > avail )
792                     n = avail;
793                 if( iobuf_write(chain, p, n ) )
794                     rc = G10ERR_WRITE_FILE;
795                 a->count += n;
796                 p += n;
797                 size -= n;
798             }
799         }
800     }
801     else if( control == IOBUFCTRL_INIT ) {
802         if( DBG_IOBUF )
803             log_debug("init block_filter %p\n", a );
804         if( a->partial )
805             a->count = 0;
806         else if( a->use == 1 )
807             a->count = a->size = 0;
808         else
809             a->count = a->size; /* force first length bytes */
810         a->eof = 0;
811         a->buffer = NULL;
812         a->buflen = 0;
813     }
814     else if( control == IOBUFCTRL_DESC ) {
815         *(char**)buf = "block_filter";
816     }
817     else if( control == IOBUFCTRL_FREE ) {
818         if( a->use == 2 ) { /* write the end markers */
819             if( a->partial ) {
820                 u32 len;
821                 /* write out the remaining bytes without a partial header
822                  * the length of this header may be 0 - but if it is
823                  * the first block we are not allowed to use a partial header
824                  * and frankly we can't do so, because this length must be
825                  * a power of 2. This is _really_ complicated because we
826                  * have to check the possible length of a packet prior
827                  * to it's creation: a chain of filters becomes complicated
828                  * and we need a lot of code to handle compressed packets etc.
829                  *   :-(((((((
830                  */
831                 /* construct header */
832                 len = a->buflen;
833                 /*log_debug("partial: remaining length=%u\n", len );*/
834                 if( len < 192 )
835                     rc = iobuf_put(chain, len );
836                 else if( len < 8384 ) {
837                     if( !(rc=iobuf_put( chain, ((len-192) / 256) + 192)) )
838                         rc = iobuf_put( chain, ((len-192) % 256));
839                 }
840                 else { /* use a 4 byte header */
841                     if( !(rc=iobuf_put( chain, 0xff )) )
842                         if( !(rc=iobuf_put( chain, (len >> 24)&0xff )) )
843                             if( !(rc=iobuf_put( chain, (len >> 16)&0xff )) )
844                                 if( !(rc=iobuf_put( chain, (len >> 8)&0xff )))
845                                     rc=iobuf_put( chain, len & 0xff );
846                 }
847                 if( !rc && len )
848                     rc = iobuf_write(chain, a->buffer, len );
849                 if( rc ) {
850                     log_error("block_filter: write error: %s\n",strerror(errno));
851                     rc = G10ERR_WRITE_FILE;
852                 }
853                 m_free( a->buffer ); a->buffer = NULL; a->buflen = 0;
854             }
855             else {
856                 iobuf_writebyte(chain, 0);
857                 iobuf_writebyte(chain, 0);
858             }
859         }
860         else if( a->size ) {
861             log_error("block_filter: pending bytes!\n");
862         }
863         if( DBG_IOBUF )
864             log_debug("free block_filter %p\n", a );
865         m_free(a); /* we can free our context now */
866     }
867
868     return rc;
869 }
870
871
872 static void
873 print_chain( IOBUF a )
874 {
875     if( !DBG_IOBUF )
876         return;
877     for(; a; a = a->chain ) {
878         size_t dummy_len = 0;
879         const char *desc = "[none]";
880
881         if( a->filter )
882             a->filter( a->filter_ov, IOBUFCTRL_DESC, NULL,
883                                                 (byte*)&desc, &dummy_len );
884
885         log_debug("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n",
886                    a->no, a->subno, desc, a->filter_eof,
887                    (int)a->d.start, (int)a->d.len );
888     }
889 }
890
891 int
892 iobuf_print_chain( IOBUF a )
893 {
894     print_chain(a);
895     return 0;
896 }
897
898 /****************
899  * Allocate a new io buffer, with no function assigned.
900  * Use is the desired usage: 1 for input, 2 for output, 3 for temp buffer
901  * BUFSIZE is a suggested buffer size.
902  */
903 IOBUF
904 iobuf_alloc(int use, size_t bufsize)
905 {
906     IOBUF a;
907     static int number=0;
908
909     a = m_alloc_clear(sizeof *a);
910     a->use = use;
911     a->d.buf = m_alloc( bufsize );
912     a->d.size = bufsize;
913     a->no = ++number;
914     a->subno = 0;
915     a->opaque = NULL;
916     a->real_fname = NULL;
917     return a;
918 }
919
920 int
921 iobuf_close ( IOBUF a )
922 {
923     IOBUF a2;
924     size_t dummy_len=0;
925     int rc=0;
926
927     if( a && a->directfp ) {
928         fclose( a->directfp );
929         m_free( a->real_fname );
930         if( DBG_IOBUF )
931             log_debug("iobuf_close -> %p\n", a->directfp );
932         return 0;
933     }
934
935     for( ; a && !rc ; a = a2 ) {
936         a2 = a->chain;
937         if( a->use == 2 && (rc=iobuf_flush(a)) )
938             log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc));
939
940         if( DBG_IOBUF )
941             log_debug("iobuf-%d.%d: close `%s'\n", a->no, a->subno, a->desc );
942         if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE,
943                                          a->chain, NULL, &dummy_len)) )
944             log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) );
945         m_free(a->real_fname);
946         if (a->d.buf) {
947             memset (a->d.buf, 0, a->d.size); /* erase the buffer */
948             m_free(a->d.buf);
949         }
950         m_free(a);
951     }
952     return rc;
953 }
954
955 int
956 iobuf_cancel( IOBUF a )
957 {
958     const char *s;
959     IOBUF a2;
960     int rc;
961 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
962     char *remove_name = NULL;
963 #endif
964
965     if( a && a->use == 2 ) {
966         s = iobuf_get_real_fname(a);
967         if( s && *s ) {
968 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
969             remove_name = m_strdup ( s );
970 #else
971             remove(s);
972 #endif
973         }
974     }
975
976     /* send a cancel message to all filters */
977     for( a2 = a; a2 ; a2 = a2->chain ) {
978         size_t dummy;
979         if( a2->filter )
980             a2->filter( a2->filter_ov, IOBUFCTRL_CANCEL, a2->chain,
981                                                          NULL, &dummy );
982     }
983
984     rc = iobuf_close(a);
985 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
986     if ( remove_name ) {
987         /* Argg, MSDOS does not allow to remove open files.  So
988          * we have to do it here */
989         remove ( remove_name );
990         m_free ( remove_name );
991     }
992 #endif
993     return rc;
994 }
995
996
997 /****************
998  * create a temporary iobuf, which can be used to collect stuff
999  * in an iobuf and later be written by iobuf_write_temp() to another
1000  * iobuf.
1001  */
1002 IOBUF
1003 iobuf_temp()
1004 {
1005     IOBUF a;
1006
1007     a = iobuf_alloc(3, 8192 );
1008
1009     return a;
1010 }
1011
1012 IOBUF
1013 iobuf_temp_with_content( const char *buffer, size_t length )
1014 {
1015     IOBUF a;
1016
1017     a = iobuf_alloc(3, length );
1018     memcpy( a->d.buf, buffer, length );
1019     a->d.len = length;
1020
1021     return a;
1022 }
1023
1024 void
1025 iobuf_enable_special_filenames ( int yes )
1026 {
1027     special_names_enabled = yes;
1028 }
1029
1030 /*
1031  * see whether the filename has the for "-&nnnn", where n is a
1032  * non-zero number.
1033  * Returns this number or -1 if it is not the case.
1034  */
1035 static int
1036 check_special_filename ( const char *fname )
1037 {
1038     if ( special_names_enabled
1039          && fname && *fname == '-' && fname[1] == '&' ) {
1040         int i;
1041
1042         fname += 2;
1043         for (i=0; digitp (fname+i); i++ )
1044             ;
1045         if ( !fname[i] ) 
1046             return atoi (fname);
1047     }
1048     return -1;
1049 }
1050
1051 /****************
1052  * Create a head iobuf for reading from a file
1053  * returns: NULL if an error occures and sets errno
1054  */
1055 IOBUF
1056 iobuf_open( const char *fname )
1057 {
1058     IOBUF a;
1059     FILEP_OR_FD fp;
1060     file_filter_ctx_t *fcx;
1061     size_t len;
1062     int print_only = 0;
1063     int fd;
1064
1065     if( !fname || (*fname=='-' && !fname[1])  ) {
1066         fp = FILEP_OR_FD_FOR_STDIN;
1067 #ifdef USE_SETMODE
1068         setmode ( my_fileno(fp) , O_BINARY );
1069 #endif
1070         fname = "[stdin]";
1071         print_only = 1;
1072     }
1073     else if ( (fd = check_special_filename ( fname )) != -1 )
1074         return iobuf_fdopen ( translate_file_handle (fd,0), "rb" );
1075     else if( (fp = my_fopen_ro(fname, "rb")) == INVALID_FP )
1076         return NULL;
1077     a = iobuf_alloc(1, 8192 );
1078     fcx = m_alloc( sizeof *fcx + strlen(fname) );
1079     fcx->fp = fp;
1080     fcx->print_only_name = print_only;
1081     strcpy(fcx->fname, fname );
1082     if( !print_only )
1083         a->real_fname = m_strdup( fname );
1084     a->filter = file_filter;
1085     a->filter_ov = fcx;
1086     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
1087     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
1088     if( DBG_IOBUF )
1089         log_debug("iobuf-%d.%d: open `%s' fd=%d\n",
1090                    a->no, a->subno, fname, (int)my_fileno(fcx->fp) );
1091
1092     return a;
1093 }
1094
1095 /****************
1096  * Create a head iobuf for reading from a file
1097  * returns: NULL if an error occures and sets errno
1098  */
1099 IOBUF
1100 iobuf_fdopen( int fd, const char *mode )
1101 {
1102     IOBUF a;
1103     FILEP_OR_FD fp;
1104     file_filter_ctx_t *fcx;
1105     size_t len;
1106
1107 #ifdef FILE_FILTER_USES_STDIO
1108     if( !(fp = fdopen(fd, mode)) )
1109         return NULL;
1110 #else
1111     fp = (FILEP_OR_FD)fd;
1112 #endif
1113     a = iobuf_alloc( strchr( mode, 'w')? 2:1, 8192 );
1114     fcx = m_alloc( sizeof *fcx + 20 );
1115     fcx->fp = fp;
1116     fcx->print_only_name = 1;
1117     sprintf(fcx->fname, "[fd %d]", fd );
1118     a->filter = file_filter;
1119     a->filter_ov = fcx;
1120     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
1121     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
1122     if( DBG_IOBUF )
1123         log_debug("iobuf-%d.%d: fdopen `%s'\n", a->no, a->subno, fcx->fname );
1124     iobuf_ioctl (a,3,1,NULL); /* disable fd caching */
1125     return a;
1126 }
1127
1128
1129 IOBUF
1130 iobuf_sockopen ( int fd, const char *mode )
1131 {
1132     IOBUF a;
1133 #ifdef _WIN32
1134     sock_filter_ctx_t *scx;
1135     size_t len;
1136
1137     a = iobuf_alloc( strchr( mode, 'w')? 2:1, 8192 );
1138     scx = m_alloc( sizeof *scx + 25 );
1139     scx->sock = fd;
1140     scx->print_only_name = 1;
1141     sprintf(scx->fname, "[sock %d]", fd );
1142     a->filter = sock_filter;
1143     a->filter_ov = scx;
1144     sock_filter( scx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
1145     sock_filter( scx, IOBUFCTRL_INIT, NULL, NULL, &len );
1146     if( DBG_IOBUF )
1147         log_debug("iobuf-%d.%d: sockopen `%s'\n", a->no, a->subno, scx->fname);
1148     iobuf_ioctl (a,3,1,NULL); /* disable fd caching */ 
1149 #else
1150     a = iobuf_fdopen (fd, mode);
1151 #endif
1152     return a;
1153 }
1154
1155 /****************
1156  * create an iobuf for writing to a file; the file will be created.
1157  */
1158 IOBUF
1159 iobuf_create( const char *fname )
1160 {
1161     IOBUF a;
1162     FILEP_OR_FD fp;
1163     file_filter_ctx_t *fcx;
1164     size_t len;
1165     int print_only = 0;
1166     int fd;
1167
1168     if( !fname || (*fname=='-' && !fname[1]) ) {
1169         fp = FILEP_OR_FD_FOR_STDOUT;
1170 #ifdef USE_SETMODE
1171         setmode ( my_fileno(fp) , O_BINARY );
1172 #endif
1173         fname = "[stdout]";
1174         print_only = 1;
1175     }
1176     else if ( (fd = check_special_filename ( fname )) != -1 )
1177         return iobuf_fdopen ( translate_file_handle (fd, 1), "wb" );
1178     else if( (fp = my_fopen(fname, "wb")) == INVALID_FP )
1179         return NULL;
1180     a = iobuf_alloc(2, 8192 );
1181     fcx = m_alloc( sizeof *fcx + strlen(fname) );
1182     fcx->fp = fp;
1183     fcx->print_only_name = print_only;
1184     strcpy(fcx->fname, fname );
1185     if( !print_only )
1186         a->real_fname = m_strdup( fname );
1187     a->filter = file_filter;
1188     a->filter_ov = fcx;
1189     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
1190     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
1191     if( DBG_IOBUF )
1192         log_debug("iobuf-%d.%d: create `%s'\n", a->no, a->subno, a->desc );
1193
1194     return a;
1195 }
1196
1197 /****************
1198  * append to an iobuf; if the file does not exist, create it.
1199  * cannot be used for stdout.
1200  * Note: This is not used.
1201  */
1202 #if 0 /* not used */
1203 IOBUF
1204 iobuf_append( const char *fname )
1205 {
1206     IOBUF a;
1207     FILE *fp;
1208     file_filter_ctx_t *fcx;
1209     size_t len;
1210
1211     if( !fname )
1212         return NULL;
1213     else if( !(fp = my_fopen(fname, "ab")) )
1214         return NULL;
1215     a = iobuf_alloc(2, 8192 );
1216     fcx = m_alloc( sizeof *fcx + strlen(fname) );
1217     fcx->fp = fp;
1218     strcpy(fcx->fname, fname );
1219     a->real_fname = m_strdup( fname );
1220     a->filter = file_filter;
1221     a->filter_ov = fcx;
1222     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
1223     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
1224     if( DBG_IOBUF )
1225         log_debug("iobuf-%d.%d: append `%s'\n", a->no, a->subno, a->desc );
1226
1227     return a;
1228 }
1229 #endif
1230
1231 IOBUF
1232 iobuf_openrw( const char *fname )
1233 {
1234     IOBUF a;
1235     FILEP_OR_FD fp;
1236     file_filter_ctx_t *fcx;
1237     size_t len;
1238
1239     if( !fname )
1240         return NULL;
1241     else if( (fp = my_fopen(fname, "r+b")) == INVALID_FP )
1242         return NULL;
1243     a = iobuf_alloc(2, 8192 );
1244     fcx = m_alloc( sizeof *fcx + strlen(fname) );
1245     fcx->fp = fp;
1246     strcpy(fcx->fname, fname );
1247     a->real_fname = m_strdup( fname );
1248     a->filter = file_filter;
1249     a->filter_ov = fcx;
1250     file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
1251     file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
1252     if( DBG_IOBUF )
1253         log_debug("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno, a->desc );
1254
1255     return a;
1256 }
1257
1258
1259 int
1260 iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval )
1261 {
1262     if ( cmd == 1 ) {  /* keep system filepointer/descriptor open */
1263         if( DBG_IOBUF )
1264             log_debug("iobuf-%d.%d: ioctl `%s' keep=%d\n",
1265                       a? a->no:-1, a?a->subno:-1, a?a->desc:"?", intval );
1266         for( ; a; a = a->chain )
1267             if( !a->chain && a->filter == file_filter ) {
1268                 file_filter_ctx_t *b = a->filter_ov;
1269                 b->keep_open = intval;
1270                 return 0;
1271             }
1272 #ifdef _WIN32
1273             else if( !a->chain && a->filter == sock_filter ) {
1274                 sock_filter_ctx_t *b = a->filter_ov;
1275                 b->keep_open = intval;
1276                 return 0;
1277             }
1278 #endif
1279     }
1280     else if ( cmd == 2 ) {  /* invalidate cache */
1281         if( DBG_IOBUF )
1282             log_debug("iobuf-*.*: ioctl `%s' invalidate\n",
1283                       ptrval? (char*)ptrval:"?");
1284         if ( !a && !intval && ptrval ) {
1285 #ifndef FILE_FILTER_USES_STDIO
1286             fd_cache_invalidate (ptrval);
1287 #endif
1288             return 0;
1289         }
1290     }
1291     else if ( cmd == 3 ) {  /* disallow/allow caching */
1292         if( DBG_IOBUF )
1293             log_debug("iobuf-%d.%d: ioctl `%s' no_cache=%d\n",
1294                       a? a->no:-1, a?a->subno:-1, a?a->desc:"?", intval );
1295         for( ; a; a = a->chain )
1296             if( !a->chain && a->filter == file_filter ) {
1297                 file_filter_ctx_t *b = a->filter_ov;
1298                 b->no_cache = intval;
1299                 return 0;
1300             }
1301 #ifdef _WIN32
1302             else if( !a->chain && a->filter == sock_filter ) {
1303                 sock_filter_ctx_t *b = a->filter_ov;
1304                 b->no_cache = intval;
1305                 return 0;
1306             }
1307 #endif
1308     }
1309
1310     return -1;
1311 }
1312
1313
1314 /****************
1315  * Register an i/o filter.
1316  */
1317 int
1318 iobuf_push_filter( IOBUF a,
1319                    int (*f)(void *opaque, int control,
1320                    IOBUF chain, byte *buf, size_t *len), void *ov )
1321 {
1322     return iobuf_push_filter2( a, f, ov, 0 );
1323 }
1324
1325 int
1326 iobuf_push_filter2( IOBUF a,
1327                     int (*f)(void *opaque, int control,
1328                     IOBUF chain, byte *buf, size_t *len),
1329                     void *ov, int rel_ov )
1330 {
1331     IOBUF b;
1332     size_t dummy_len=0;
1333     int rc=0;
1334
1335     if( a->directfp )
1336         BUG();
1337
1338     if( a->use == 2 && (rc=iobuf_flush(a)) )
1339         return rc;
1340     /* make a copy of the current stream, so that
1341      * A is the new stream and B the original one.
1342      * The contents of the buffers are transferred to the
1343      * new stream.
1344      */
1345     b = m_alloc(sizeof *b);
1346     memcpy(b, a, sizeof *b );
1347     /* fixme: it is stupid to keep a copy of the name at every level
1348      * but we need the name somewhere because the name known by file_filter
1349      * may have been released when we need the name of the file */
1350     b->real_fname = a->real_fname? m_strdup(a->real_fname):NULL;
1351     /* remove the filter stuff from the new stream */
1352     a->filter = NULL;
1353     a->filter_ov = NULL;
1354     a->filter_ov_owner = 0;
1355     a->filter_eof = 0;
1356     if( a->use == 3 )
1357         a->use = 2;  /* make a write stream from a temp stream */
1358
1359     if( a->use == 2 ) { /* allocate a fresh buffer for the original stream */
1360         b->d.buf = m_alloc( a->d.size );
1361         b->d.len = 0;
1362         b->d.start = 0;
1363     }
1364     else { /* allocate a fresh buffer for the new stream */
1365         a->d.buf = m_alloc( a->d.size );
1366         a->d.len = 0;
1367         a->d.start = 0;
1368     }
1369     /* disable nlimit for the new stream */
1370     a->ntotal = b->ntotal + b->nbytes;
1371     a->nlimit = a->nbytes = 0;
1372     a->nofast &= ~1;
1373     /* make a link from the new stream to the original stream */
1374     a->chain = b;
1375     a->opaque = b->opaque;
1376
1377     /* setup the function on the new stream */
1378     a->filter = f;
1379     a->filter_ov = ov;
1380     a->filter_ov_owner = rel_ov;
1381
1382     a->subno = b->subno + 1;
1383     f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len );
1384
1385     if( DBG_IOBUF ) {
1386         log_debug("iobuf-%d.%d: push `%s'\n", a->no, a->subno, a->desc );
1387         print_chain( a );
1388     }
1389
1390     /* now we can initialize the new function if we have one */
1391     if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain,
1392                        NULL, &dummy_len)) )
1393         log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) );
1394     return rc;
1395 }
1396
1397 /****************
1398  * Remove an i/o filter.
1399  */
1400 int
1401 pop_filter( IOBUF a, int (*f)(void *opaque, int control,
1402                       IOBUF chain, byte *buf, size_t *len), void *ov )
1403 {
1404     IOBUF b;
1405     size_t dummy_len=0;
1406     int rc=0;
1407
1408     if( a->directfp )
1409         BUG();
1410
1411     if( DBG_IOBUF )
1412         log_debug("iobuf-%d.%d: pop `%s'\n", a->no, a->subno, a->desc );
1413     if( !a->filter ) { /* this is simple */
1414         b = a->chain;
1415         assert(b);
1416         m_free(a->d.buf);
1417         m_free(a->real_fname);
1418         memcpy(a,b, sizeof *a);
1419         m_free(b);
1420         return 0;
1421     }
1422     for(b=a ; b; b = b->chain )
1423         if( b->filter == f && (!ov || b->filter_ov == ov) )
1424             break;
1425     if( !b )
1426         log_bug("pop_filter(): filter function not found\n");
1427
1428     /* flush this stream if it is an output stream */
1429     if( a->use == 2 && (rc=iobuf_flush(b)) ) {
1430         log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc));
1431         return rc;
1432     }
1433     /* and tell the filter to free it self */
1434     if( b->filter && (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain,
1435                        NULL, &dummy_len)) ) {
1436         log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
1437         return rc;
1438     }
1439     if( b->filter_ov && b->filter_ov_owner ) {
1440         m_free( b->filter_ov );
1441         b->filter_ov = NULL;
1442     }
1443
1444
1445     /* and see how to remove it */
1446     if( a == b && !b->chain )
1447         log_bug("can't remove the last filter from the chain\n");
1448     else if( a == b ) { /* remove the first iobuf from the chain */
1449         /* everything from b is copied to a. This is save because
1450          * a flush has been done on the to be removed entry
1451          */
1452         b = a->chain;
1453         m_free(a->d.buf);
1454         m_free(a->real_fname);
1455         memcpy(a,b, sizeof *a);
1456         m_free(b);
1457         if( DBG_IOBUF )
1458            log_debug("iobuf-%d.%d: popped filter\n", a->no, a->subno );
1459     }
1460     else if( !b->chain ) { /* remove the last iobuf from the chain */
1461         log_bug("Ohh jeee, trying to remove a head filter\n");
1462     }
1463     else {  /* remove an intermediate iobuf from the chain */
1464         log_bug("Ohh jeee, trying to remove an intermediate filter\n");
1465     }
1466
1467     return rc;
1468 }
1469
1470
1471 /****************
1472  * read underflow: read more bytes into the buffer and return
1473  * the first byte or -1 on EOF.
1474  */
1475 static int
1476 underflow(IOBUF a)
1477 {
1478     size_t len;
1479     int rc;
1480
1481     assert( a->d.start == a->d.len );
1482     if( a->use == 3 )
1483         return -1; /* EOF because a temp buffer can't do an underflow */
1484
1485     if( a->filter_eof ) {
1486         if( a->chain ) {
1487             IOBUF b = a->chain;
1488             if( DBG_IOBUF )
1489                 log_debug("iobuf-%d.%d: pop `%s' in underflow\n",
1490                                         a->no, a->subno, a->desc );
1491             m_free(a->d.buf);
1492             m_free(a->real_fname);
1493             memcpy(a, b, sizeof *a);
1494             m_free(b);
1495             print_chain(a);
1496         }
1497         else
1498              a->filter_eof = 0;  /* for the top level filter */
1499         if( DBG_IOBUF )
1500             log_debug("iobuf-%d.%d: underflow: eof (due to filter eof)\n",
1501                                                     a->no, a->subno );
1502         return -1; /* return one(!) EOF */
1503     }
1504     if( a->error ) {
1505         if( DBG_IOBUF )
1506             log_debug("iobuf-%d.%d: error\n", a->no, a->subno );
1507         return -1;
1508     }
1509
1510     if( a->directfp ) {
1511         FILE *fp = a->directfp;
1512
1513         len = fread( a->d.buf, 1, a->d.size, fp);
1514         if( len < a->d.size ) {
1515             if( ferror(fp) )
1516                 a->error = 1;
1517         }
1518         a->d.len = len;
1519         a->d.start = 0;
1520         return len? a->d.buf[a->d.start++] : -1;
1521     }
1522
1523
1524     if( a->filter ) {
1525         len = a->d.size;
1526         if( DBG_IOBUF )
1527             log_debug("iobuf-%d.%d: underflow: req=%lu\n",
1528                       a->no, a->subno, (ulong)len );
1529         rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
1530                         a->d.buf, &len );
1531         if( DBG_IOBUF ) {
1532             log_debug("iobuf-%d.%d: underflow: got=%lu rc=%d\n",
1533                     a->no, a->subno, (ulong)len, rc );
1534 /*          if( a->no == 1 ) */
1535 /*                   log_hexdump ("     data:", a->d.buf, len); */
1536         }
1537         if( a->use == 1 && rc == -1 ) { /* EOF: we can remove the filter */
1538             size_t dummy_len=0;
1539
1540             /* and tell the filter to free itself */
1541             if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
1542                                NULL, &dummy_len)) )
1543                 log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
1544             if( a->filter_ov && a->filter_ov_owner ) {
1545                 m_free( a->filter_ov );
1546                 a->filter_ov = NULL;
1547             }
1548             a->filter = NULL;
1549             a->desc = NULL;
1550             a->filter_ov = NULL;
1551             a->filter_eof = 1;
1552             if( !len && a->chain ) {
1553                 IOBUF b = a->chain;
1554                 if( DBG_IOBUF )
1555                     log_debug("iobuf-%d.%d: pop `%s' in underflow (!len)\n",
1556                                                a->no, a->subno, a->desc );
1557                 m_free(a->d.buf);
1558                 m_free(a->real_fname);
1559                 memcpy(a,b, sizeof *a);
1560                 m_free(b);
1561                 print_chain(a);
1562             }
1563         }
1564         else if( rc )
1565             a->error = 1;
1566
1567         if( !len ) {
1568             if( DBG_IOBUF )
1569                 log_debug("iobuf-%d.%d: underflow: eof\n", a->no, a->subno );
1570             return -1;
1571         }
1572         a->d.len = len;
1573         a->d.start = 0;
1574         return a->d.buf[a->d.start++];
1575     }
1576     else {
1577         if( DBG_IOBUF )
1578             log_debug("iobuf-%d.%d: underflow: eof (no filter)\n",
1579                                                     a->no, a->subno );
1580         return -1;  /* no filter; return EOF */
1581     }
1582 }
1583
1584
1585 int
1586 iobuf_flush(IOBUF a)
1587 {
1588     size_t len;
1589     int rc;
1590
1591     if( a->directfp )
1592         return 0;
1593
1594     if( a->use == 3 ) { /* increase the temp buffer */
1595         char *newbuf;
1596         size_t newsize = a->d.size + 8192;
1597
1598         if( DBG_IOBUF )
1599           log_debug("increasing temp iobuf from %lu to %lu\n",
1600                     (ulong)a->d.size, (ulong)newsize );
1601         newbuf = m_alloc( newsize );
1602         memcpy( newbuf, a->d.buf, a->d.len );
1603         m_free(a->d.buf);
1604         a->d.buf = newbuf;
1605         a->d.size = newsize;
1606         return 0;
1607     }
1608     else if( a->use != 2 )
1609         log_bug("flush on non-output iobuf\n");
1610     else if( !a->filter )
1611         log_bug("iobuf_flush: no filter\n");
1612     len = a->d.len;
1613     rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len );
1614     if( !rc && len != a->d.len ) {
1615         log_info("iobuf_flush did not write all!\n");
1616         rc = G10ERR_WRITE_FILE;
1617     }
1618     else if( rc )
1619         a->error = 1;
1620     a->d.len = 0;
1621
1622     return rc;
1623 }
1624
1625
1626 /****************
1627  * Read a byte from the iobuf; returns -1 on EOF
1628  */
1629 int
1630 iobuf_readbyte(IOBUF a)
1631 {
1632     int c;
1633
1634     /* nlimit does not work together with unget */
1635     /* nbytes is also not valid! */
1636     if( a->unget.buf ) {
1637         if( a->unget.start < a->unget.len )
1638             return a->unget.buf[a->unget.start++];
1639         m_free(a->unget.buf);
1640         a->unget.buf = NULL;
1641         a->nofast &= ~2;
1642     }
1643
1644     if( a->nlimit && a->nbytes >= a->nlimit )
1645         return -1; /* forced EOF */
1646
1647     if( a->d.start < a->d.len ) {
1648         c = a->d.buf[a->d.start++];
1649     }
1650     else if( (c=underflow(a)) == -1 )
1651         return -1; /* EOF */
1652
1653     a->nbytes++;
1654     return c;
1655 }
1656
1657
1658 int
1659 iobuf_read(IOBUF a, byte *buf, unsigned buflen )
1660 {
1661     int c, n;
1662
1663     if( a->unget.buf || a->nlimit ) {
1664         /* handle special cases */
1665         for(n=0 ; n < buflen; n++ ) {
1666             if( (c = iobuf_readbyte(a)) == -1 ) {
1667                 if( !n )
1668                     return -1; /* eof */
1669                 break;
1670             }
1671             else
1672                 if( buf ) *buf = c;
1673             if( buf ) buf++;
1674         }
1675         return n;
1676     }
1677
1678     n = 0;
1679     do {
1680         if( n < buflen && a->d.start < a->d.len ) {
1681             unsigned size = a->d.len - a->d.start;
1682             if( size > buflen - n )
1683                 size = buflen - n;
1684             if( buf )
1685                 memcpy( buf, a->d.buf + a->d.start, size );
1686             n += size;
1687             a->d.start += size;
1688             if( buf )
1689                 buf += size;
1690         }
1691         if( n < buflen ) {
1692             if( (c=underflow(a)) == -1 ) {
1693                 a->nbytes += n;
1694                 return n? n : -1/*EOF*/;
1695             }
1696             if( buf )
1697                 *buf++ = c;
1698             n++;
1699         }
1700     } while( n < buflen );
1701     a->nbytes += n;
1702     return n;
1703 }
1704
1705
1706 /****************
1707  * Have a look at the iobuf.
1708  * NOTE: This only works in special cases.
1709  */
1710 int
1711 iobuf_peek(IOBUF a, byte *buf, unsigned buflen )
1712 {
1713     int n=0;
1714
1715     if( a->filter_eof )
1716         return -1;
1717
1718     if( !(a->d.start < a->d.len) ) {
1719         if( underflow(a) == -1 )
1720             return -1;
1721         /* and unget this character */
1722         assert(a->d.start == 1);
1723         a->d.start = 0;
1724     }
1725
1726     for(n=0 ; n < buflen && (a->d.start+n) < a->d.len ; n++, buf++ )
1727         *buf = a->d.buf[n];
1728     return n;
1729 }
1730
1731
1732
1733
1734 int
1735 iobuf_writebyte(IOBUF a, unsigned c)
1736 {
1737
1738     if( a->directfp )
1739         BUG();
1740
1741     if( a->d.len == a->d.size )
1742         if( iobuf_flush(a) )
1743             return -1;
1744
1745     assert( a->d.len < a->d.size );
1746     a->d.buf[a->d.len++] = c;
1747     return 0;
1748 }
1749
1750
1751 int
1752 iobuf_write(IOBUF a, byte *buf, unsigned buflen )
1753 {
1754
1755     if( a->directfp )
1756         BUG();
1757
1758     do {
1759         if( buflen && a->d.len < a->d.size ) {
1760             unsigned size = a->d.size - a->d.len;
1761             if( size > buflen ) size = buflen;
1762             memcpy( a->d.buf + a->d.len, buf, size );
1763             buflen -= size;
1764             buf += size;
1765             a->d.len += size;
1766         }
1767         if( buflen ) {
1768             if( iobuf_flush(a) )
1769                 return -1;
1770         }
1771     } while( buflen );
1772     return 0;
1773 }
1774
1775
1776 int
1777 iobuf_writestr(IOBUF a, const char *buf )
1778 {
1779     for( ; *buf; buf++ )
1780         if( iobuf_writebyte(a, *buf) )
1781             return -1;
1782     return 0;
1783 }
1784
1785
1786
1787 /****************
1788  * copy the contents of TEMP to A.
1789  */
1790 int
1791 iobuf_write_temp( IOBUF a, IOBUF temp )
1792 {
1793     while( temp->chain )
1794         pop_filter( temp, temp->filter, NULL );
1795     return iobuf_write(a, temp->d.buf, temp->d.len );
1796 }
1797
1798 /****************
1799  * copy the contents of the temp io stream to BUFFER.
1800  */
1801 size_t
1802 iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
1803 {
1804     size_t n = a->d.len;
1805
1806     if( n > buflen )
1807         n = buflen;
1808     memcpy( buffer, a->d.buf, n );
1809     return n;
1810 }
1811
1812
1813 /****************
1814  * Call this function to terminate processing of the temp stream
1815  * without closing it.  This removes all filters from the stream
1816  * makes sure that iobuf_get_temp_{buffer,length}() returns correct
1817  * values.
1818  */
1819 void
1820 iobuf_flush_temp( IOBUF temp )
1821 {
1822     while( temp->chain )
1823         pop_filter( temp, temp->filter, NULL );
1824 }
1825
1826
1827 /****************
1828  * Set a limit on how many bytes may be read from the input stream A.
1829  * Setting the limit to 0 disables this feature.
1830  */
1831 void
1832 iobuf_set_limit( IOBUF a, off_t nlimit )
1833 {
1834     if( nlimit )
1835         a->nofast |= 1;
1836     else
1837         a->nofast &= ~1;
1838     a->nlimit = nlimit;
1839     a->ntotal += a->nbytes;
1840     a->nbytes = 0;
1841 }
1842
1843
1844
1845 /****************
1846  * Return the length of an open file
1847  */
1848 off_t
1849 iobuf_get_filelength( IOBUF a )
1850 {
1851     struct stat st;
1852
1853     if( a->directfp )  {
1854         FILE *fp = a->directfp;
1855
1856        if( !fstat(fileno(fp), &st) )
1857            return st.st_size;
1858         log_error("fstat() failed: %s\n", strerror(errno) );
1859         return 0;
1860     }
1861
1862     /* Hmmm: file_filter may have already been removed */
1863     for( ; a; a = a->chain )
1864         if( !a->chain && a->filter == file_filter ) {
1865             file_filter_ctx_t *b = a->filter_ov;
1866             FILEP_OR_FD fp = b->fp;
1867
1868 #if defined(HAVE_DOSISH_SYSTEM) && !defined(FILE_FILTER_USES_STDIO)
1869             ulong size;
1870
1871             if ( (size=GetFileSize (fp, NULL)) != 0xffffffff ) 
1872                 return size;
1873             log_error ("GetFileSize for handle %p failed: ec=%d\n",
1874                        fp, (int)GetLastError () );
1875 #else
1876             if( !fstat(my_fileno(fp), &st) )
1877                 return st.st_size;
1878             log_error("fstat() failed: %s\n", strerror(errno) );
1879 #endif
1880             break;
1881         }
1882
1883     return 0;
1884 }
1885
1886 /****************
1887  * Tell the file position, where the next read will take place
1888  */
1889 off_t
1890 iobuf_tell( IOBUF a )
1891 {
1892     return a->ntotal + a->nbytes;
1893 }
1894
1895
1896 #if !defined(HAVE_FSEEKO) && !defined(fseeko)
1897
1898 #ifdef HAVE_LIMITS_H
1899 # include <limits.h>
1900 #endif
1901 #ifndef LONG_MAX
1902 # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
1903 #endif
1904 #ifndef LONG_MIN
1905 # define LONG_MIN (-1 - LONG_MAX)
1906 #endif
1907
1908 /****************
1909  * A substitute for fseeko, for hosts that don't have it.
1910  */
1911 static int
1912 fseeko( FILE *stream, off_t newpos, int whence )
1913 {
1914     while( newpos != (long) newpos ) {
1915        long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
1916        if( fseek( stream, pos, whence ) != 0 )
1917            return -1;
1918        newpos -= pos;
1919        whence = SEEK_CUR;
1920     }
1921     return fseek( stream, (long)newpos, whence );
1922 }
1923 #endif
1924
1925 /****************
1926  * This is a very limited implementation. It simply discards all internal
1927  * buffering and removes all filters but the first one.
1928  */
1929 int
1930 iobuf_seek( IOBUF a, off_t newpos )
1931 {
1932     file_filter_ctx_t *b = NULL;
1933
1934     if( a->directfp ) {
1935         FILE *fp = a->directfp;
1936         if( fseeko( fp, newpos, SEEK_SET ) ) {
1937             log_error("can't seek: %s\n", strerror(errno) );
1938             return -1;
1939         }
1940         clearerr(fp);
1941     }
1942     else {
1943         for( ; a; a = a->chain ) {
1944             if( !a->chain && a->filter == file_filter ) {
1945                 b = a->filter_ov;
1946                 break;
1947             }
1948         }
1949         if( !a )
1950             return -1;
1951 #ifdef FILE_FILTER_USES_STDIO
1952        if( fseeko( b->fp, newpos, SEEK_SET ) ) {
1953            log_error("can't fseek: %s\n", strerror(errno) );
1954            return -1;
1955        }
1956 #else
1957 #ifdef HAVE_DOSISH_SYSTEM
1958        if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff ) {
1959            log_error ("SetFilePointer failed on handle %p: ec=%d\n",
1960                       b->fp, (int)GetLastError () );
1961            return -1;
1962        }
1963 #else
1964        if ( lseek (b->fp, newpos, SEEK_SET) == (off_t)-1 ) {
1965            log_error("can't lseek: %s\n", strerror(errno) );
1966            return -1;
1967        }
1968 #endif
1969 #endif
1970     }
1971     a->d.len = 0;   /* discard buffer */
1972     a->d.start = 0;
1973     a->nbytes = 0;
1974     a->nlimit = 0;
1975     a->nofast &= ~1;
1976     a->ntotal = newpos;
1977     a->error = 0;
1978     /* remove filters, but the last */
1979     if( a->chain )
1980         log_debug("pop_filter called in iobuf_seek - please report\n");
1981     while( a->chain )
1982        pop_filter( a, a->filter, NULL );
1983
1984     return 0;
1985 }
1986
1987
1988
1989
1990
1991
1992 /****************
1993  * Retrieve the real filename
1994  */
1995 const char *
1996 iobuf_get_real_fname( IOBUF a )
1997 {
1998     if( a->real_fname )
1999         return a->real_fname;
2000
2001     /* the old solution */
2002     for( ; a; a = a->chain )
2003         if( !a->chain && a->filter == file_filter ) {
2004             file_filter_ctx_t *b = a->filter_ov;
2005             return b->print_only_name? NULL : b->fname;
2006         }
2007
2008     return NULL;
2009 }
2010
2011
2012 /****************
2013  * Retrieve the filename
2014  */
2015 const char *
2016 iobuf_get_fname( IOBUF a )
2017 {
2018     for( ; a; a = a->chain )
2019         if( !a->chain && a->filter == file_filter ) {
2020             file_filter_ctx_t *b = a->filter_ov;
2021             return b->fname;
2022         }
2023
2024     return NULL;
2025 }
2026
2027 /****************
2028  * Start the block write mode, see rfc1991.new for details.
2029  * A value of 0 for N stops this mode (flushes and writes
2030  * the end marker)
2031  */
2032 void
2033 iobuf_set_block_mode( IOBUF a, size_t n )
2034 {
2035     block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
2036
2037     assert( a->use == 1 || a->use == 2 );
2038     ctx->use = a->use;
2039     if( !n ) {
2040         if( a->use == 1 )
2041             log_debug("pop_filter called in set_block_mode - please report\n");
2042         pop_filter(a, block_filter, NULL );
2043     }
2044     else {
2045         ctx->size = n; /* only needed for use 2 */
2046         iobuf_push_filter(a, block_filter, ctx );
2047     }
2048 }
2049
2050 /****************
2051  * enable partial block mode as described in the OpenPGP draft.
2052  * LEN is the first length byte on read, but ignored on writes.
2053  */
2054 void
2055 iobuf_set_partial_block_mode( IOBUF a, size_t len )
2056 {
2057     block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
2058
2059     assert( a->use == 1 || a->use == 2 );
2060     ctx->use = a->use;
2061     if( !len ) {
2062         if( a->use == 1 )
2063             log_debug("pop_filter called in set_partial_block_mode"
2064                                                     " - please report\n");
2065         pop_filter(a, block_filter, NULL );
2066     }
2067     else {
2068         ctx->partial = 1;
2069         ctx->size = 0;
2070         ctx->first_c = len;
2071         iobuf_push_filter(a, block_filter, ctx );
2072     }
2073 }
2074
2075
2076 /****************
2077  * Checks whether the stream is in block mode
2078  * Note: This does not work if other filters are pushed on the stream.
2079  */
2080 int
2081 iobuf_in_block_mode( IOBUF a )
2082 {
2083     if( a && a->filter == block_filter )
2084         return 1; /* yes */
2085     return 0; /* no */
2086 }
2087
2088
2089 /****************
2090  * Same as fgets() but if the buffer is too short a larger one will
2091  * be allocated up to some limit *max_length.
2092  * A line is considered a byte stream ending in a LF.
2093  * Returns the length of the line. EOF is indicated by a line of
2094  * length zero. The last LF may be missing due to an EOF.
2095  * is max_length is zero on return, the line has been truncated.
2096  *
2097  * Note: The buffer is allocated with enough space to append a CR,LF,EOL
2098  */
2099 unsigned
2100 iobuf_read_line( IOBUF a, byte **addr_of_buffer,
2101                           unsigned *length_of_buffer, unsigned *max_length )
2102 {
2103     int c;
2104     char *buffer = *addr_of_buffer;
2105     unsigned length = *length_of_buffer;
2106     unsigned nbytes = 0;
2107     unsigned maxlen = *max_length;
2108     char *p;
2109
2110     if( !buffer ) { /* must allocate a new buffer */
2111         length = 256;
2112         buffer = m_alloc( length );
2113         *addr_of_buffer = buffer;
2114         *length_of_buffer = length;
2115     }
2116
2117     length -= 3; /* reserve 3 bytes (cr,lf,eol) */
2118     p = buffer;
2119     while( (c=iobuf_get(a)) != -1 ) {
2120         if( nbytes == length ) { /* increase the buffer */
2121             if( length > maxlen  ) { /* this is out limit */
2122                 /* skip the rest of the line */
2123                 while( c != '\n' && (c=iobuf_get(a)) != -1 )
2124                     ;
2125                 *p++ = '\n'; /* always append a LF (we have reserved space) */
2126                 nbytes++;
2127                 *max_length = 0; /* indicate truncation */
2128                 break;
2129             }
2130             length += 3; /* correct for the reserved byte */
2131             length += length < 1024? 256 : 1024;
2132             buffer = m_realloc( buffer, length );
2133             *addr_of_buffer = buffer;
2134             *length_of_buffer = length;
2135             length -= 3; /* and reserve again */
2136             p = buffer + nbytes;
2137         }
2138         *p++ = c;
2139         nbytes++;
2140         if( c == '\n' )
2141             break;
2142     }
2143     *p = 0; /* make sure the line is a string */
2144
2145     return nbytes;
2146 }
2147
2148 /* This is the non iobuf specific function */
2149 int
2150 iobuf_translate_file_handle ( int fd, int for_write )
2151 {
2152 #ifdef _WIN32
2153     {
2154         int x;
2155             
2156         if  ( fd <= 2 )
2157             return fd; /* do not do this for error, stdin, stdout, stderr */
2158
2159         x = _open_osfhandle ( fd, for_write? 1:0 );
2160         if (x==-1 )
2161             log_error ("failed to translate osfhandle %p\n", (void*)fd );
2162         else {
2163             /*log_info ("_open_osfhandle %p yields %d%s\n",
2164               (void*)fd, x, for_write? " for writing":"" );*/
2165             fd = x;
2166         }
2167     }
2168 #endif
2169     return fd;
2170 }
2171
2172 static int
2173 translate_file_handle ( int fd, int for_write )
2174 {
2175 #ifdef _WIN32
2176 #ifdef FILE_FILTER_USES_STDIO  
2177     fd = iobuf_translate_file_handle (fd, for_write);
2178 #else
2179     {
2180         int x;
2181
2182         if  ( fd == 0 ) 
2183             x = (int)GetStdHandle (STD_INPUT_HANDLE);
2184         else if (fd == 1)    
2185             x = (int)GetStdHandle (STD_OUTPUT_HANDLE);
2186         else if (fd == 2)    
2187             x = (int)GetStdHandle (STD_ERROR_HANDLE);
2188         else
2189             x = fd;
2190
2191         if (x == -1)
2192             log_debug ("GetStdHandle(%d) failed: ec=%d\n",
2193                        fd, (int)GetLastError () );
2194
2195         fd = x;
2196     }
2197 #endif
2198 #endif
2199     return fd;
2200 }