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