http: Allow overriding of the Host header.
[gnupg.git] / common / estream.c
1 /* estream.c - Extended Stream I/O Library
2  * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011,
3  *               2014 g10 Code GmbH
4  *
5  * This file is part of Libestream.
6  *
7  * Libestream is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; either version 2 of the License,
10  * or (at your option) any later version.
11  *
12  * Libestream is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Libestream; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * ALTERNATIVELY, Libestream may be distributed under the terms of the
21  * following license, in which case the provisions of this license are
22  * required INSTEAD OF the GNU General Public License. If you wish to
23  * allow use of your version of this file only under the terms of the
24  * GNU General Public License, and not to allow others to use your
25  * version of this file under the terms of the following license,
26  * indicate your decision by deleting this paragraph and the license
27  * below.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  * 1. Redistributions of source code must retain the above copyright
33  *    notice, and the entire permission notice in its entirety,
34  *    including the disclaimer of warranties.
35  * 2. Redistributions in binary form must reproduce the above copyright
36  *    notice, this list of conditions and the following disclaimer in the
37  *    documentation and/or other materials provided with the distribution.
38  * 3. The name of the author may not be used to endorse or promote
39  *    products derived from this software without specific prior
40  *    written permission.
41  *
42  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
43  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
45  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
46  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52  * OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54
55 #ifdef USE_ESTREAM_SUPPORT_H
56 # include <estream-support.h>
57 #endif
58
59 #ifdef HAVE_CONFIG_H
60 # include <config.h>
61 #endif
62
63 #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
64 # define HAVE_W32_SYSTEM 1
65 # if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM)
66 #  define HAVE_W32CE_SYSTEM
67 # endif
68 #endif
69
70 #include <sys/types.h>
71 #include <sys/file.h>
72 #include <sys/stat.h>
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <unistd.h>
77 #include <stdarg.h>
78 #include <fcntl.h>
79 #include <errno.h>
80 #include <stddef.h>
81 #include <assert.h>
82 #ifdef HAVE_W32_SYSTEM
83 # ifdef HAVE_WINSOCK2_H
84 #  include <winsock2.h>
85 # endif
86 # include <windows.h>
87 #endif
88 #ifdef HAVE_W32CE_SYSTEM
89 # include <gpg-error.h> /* ERRNO replacement.  */
90 #endif
91
92 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
93 # undef HAVE_NPTH
94 # undef USE_NPTH
95 #endif
96
97 #ifdef HAVE_NPTH
98 # include <npth.h>
99 #endif
100
101 /* This is for the special hack to use estream.c in GnuPG.  */
102 #ifdef GNUPG_MAJOR_VERSION
103 # include "../common/util.h"
104 #endif
105
106 #ifndef HAVE_MKSTEMP
107 int mkstemp (char *template);
108 #endif
109
110 #ifndef HAVE_MEMRCHR
111 void *memrchr (const void *block, int c, size_t size);
112 #endif
113
114 #include <estream.h>
115 #include <estream-printf.h>
116
117 \f
118
119 #ifndef O_BINARY
120 #define O_BINARY 0
121 #endif
122
123 #ifdef HAVE_W32_SYSTEM
124 # define S_IRGRP S_IRUSR
125 # define S_IROTH S_IRUSR
126 # define S_IWGRP S_IWUSR
127 # define S_IWOTH S_IWUSR
128 # define S_IXGRP S_IXUSR
129 # define S_IXOTH S_IXUSR
130 #endif
131
132
133 #ifdef HAVE_W32CE_SYSTEM
134 # define _set_errno(a)  gpg_err_set_errno ((a))
135 /* Setmode is missing in cegcc but available since CE 5.0.  */
136 int _setmode (int handle, int mode);
137 # define setmode(a,b)   _setmode ((a),(b))
138 #else
139 # define _set_errno(a)  do { errno = (a); } while (0)
140 #endif
141
142 #ifdef HAVE_W32_SYSTEM
143 # define IS_INVALID_FD(a)    ((void*)(a) == (void*)(-1)) /* ?? FIXME.  */
144 #else
145 # define IS_INVALID_FD(a)    ((a) == -1)
146 #endif
147
148
149 /* Generally used types.  */
150
151 typedef void *(*func_realloc_t) (void *mem, size_t size);
152 typedef void (*func_free_t) (void *mem);
153
154
155 \f
156
157 /* Buffer management layer.  */
158
159 #define BUFFER_BLOCK_SIZE  BUFSIZ
160 #define BUFFER_UNREAD_SIZE 16
161
162 \f
163 /* Primitive system I/O.  */
164
165 #ifdef USE_NPTH
166 # define ESTREAM_SYS_READ  do_npth_read
167 # define ESTREAM_SYS_WRITE do_npth_write
168 # define ESTREAM_SYS_YIELD() npth_usleep (0)
169 #else
170 # define ESTREAM_SYS_READ  read
171 # define ESTREAM_SYS_WRITE write
172 # define ESTREAM_SYS_YIELD() do { } while (0)
173 #endif
174
175
176 /* A linked list to hold notification functions. */
177 struct notify_list_s
178 {
179   struct notify_list_s *next;
180   void (*fnc) (estream_t, void*); /* The notification function.  */
181   void *fnc_value;                /* The value to be passed to FNC.  */
182 };
183 typedef struct notify_list_s *notify_list_t;
184
185
186 /* A private cookie function to implement an internal IOCTL
187    service.  */
188 typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd,
189                                         void *ptr, size_t *len);
190 /* IOCTL commands for the private cookie function.  */
191 #define COOKIE_IOCTL_SNATCH_BUFFER 1
192
193
194 /* The internal stream object.  */
195 struct estream_internal
196 {
197   unsigned char buffer[BUFFER_BLOCK_SIZE];
198   unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
199
200 #ifdef USE_NPTH
201   npth_mutex_t lock;             /* Lock. */
202 #endif
203
204   void *cookie;                  /* Cookie.                */
205   void *opaque;                  /* Opaque data.           */
206   unsigned int modeflags;        /* Flags for the backend. */
207   char *printable_fname;         /* Malloced filename for es_fname_get.  */
208   off_t offset;
209   es_cookie_read_function_t func_read;
210   es_cookie_write_function_t func_write;
211   es_cookie_seek_function_t func_seek;
212   cookie_ioctl_function_t func_ioctl;
213   es_cookie_close_function_t func_close;
214   int strategy;
215   es_syshd_t syshd;              /* A copy of the sytem handle.  */
216   struct
217   {
218     unsigned int err: 1;
219     unsigned int eof: 1;
220   } indicators;
221   unsigned int deallocate_buffer: 1;
222   unsigned int is_stdstream:1;   /* This is a standard stream.  */
223   unsigned int stdstream_fd:2;   /* 0, 1 or 2 for a standard stream.  */
224   unsigned int printable_fname_inuse: 1;  /* es_fname_get has been used.  */
225   unsigned int samethread: 1;    /* The "samethread" mode keyword.  */
226   size_t print_ntotal;           /* Bytes written from in print_writer. */
227   notify_list_t onclose;         /* On close notify function list.  */
228 };
229 typedef struct estream_internal *estream_internal_t;
230
231 /* A linked list to hold active stream objects.   */
232 struct estream_list_s
233 {
234   struct estream_list_s *next;
235   estream_t stream;  /* Entry is not used if NULL.  */
236 };
237 typedef struct estream_list_s *estream_list_t;
238 static estream_list_t estream_list;
239
240 /* File descriptors registered to be used as the standard file handles. */
241 static int custom_std_fds[3];
242 static unsigned char custom_std_fds_valid[3];
243
244 /* A lock object for the estream list and the custom_std_fds array.  */
245 #ifdef USE_NPTH
246 static npth_mutex_t estream_list_lock;
247 #endif
248
249
250 /* Error code replacements.  */
251 #ifndef EOPNOTSUPP
252 # define EOPNOTSUPP ENOSYS
253 #endif
254
255
256 /* Local prototypes.  */
257 static void fname_set_internal (estream_t stream, const char *fname, int quote);
258
259
260
261 \f
262 /* Macros.  */
263
264 /* Calculate array dimension.  */
265 #ifndef DIM
266 #define DIM(array) (sizeof (array) / sizeof (*array))
267 #endif
268
269 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
270
271
272 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
273    VARIABLE is zero.  */
274 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
275   do                                                           \
276     {                                                          \
277       tmp_variable = expression;                               \
278       if ((! variable) && tmp_variable)                        \
279         variable = tmp_variable;                               \
280     }                                                          \
281   while (0)
282
283
284 \f
285 /* Malloc wrappers to overcome problems on some older OSes.  */
286 static void *
287 mem_alloc (size_t n)
288 {
289   if (!n)
290     n++;
291   return malloc (n);
292 }
293
294 static void *
295 mem_realloc (void *p, size_t n)
296 {
297   if (!p)
298     return mem_alloc (n);
299   return realloc (p, n);
300 }
301
302 static void
303 mem_free (void *p)
304 {
305   if (p)
306     free (p);
307 }
308
309 #ifdef HAVE_W32_SYSTEM
310 static int
311 map_w32_to_errno (DWORD w32_err)
312 {
313   switch (w32_err)
314     {
315     case 0:
316       return 0;
317
318     case ERROR_FILE_NOT_FOUND:
319       return ENOENT;
320
321     case ERROR_PATH_NOT_FOUND:
322       return ENOENT;
323
324     case ERROR_ACCESS_DENIED:
325       return EPERM;
326
327     case ERROR_INVALID_HANDLE:
328     case ERROR_INVALID_BLOCK:
329       return EINVAL;
330
331     case ERROR_NOT_ENOUGH_MEMORY:
332       return ENOMEM;
333
334     case ERROR_NO_DATA:
335       return EPIPE;
336
337     default:
338       return EIO;
339     }
340 }
341 #endif /*HAVE_W32_SYSTEM*/
342
343
344 \f
345 /*
346  * Lock wrappers
347  */
348 #if 0
349 # define dbg_lock_0(f)        fprintf (stderr, "estream: " f);
350 # define dbg_lock_1(f, a)     fprintf (stderr, "estream: " f, (a));
351 # define dbg_lock_2(f, a, b)  fprintf (stderr, "estream: " f, (a), (b));
352 #else
353 # define dbg_lock_0(f)
354 # define dbg_lock_1(f, a)
355 # define dbg_lock_2(f, a, b)
356 #endif
357
358 static int
359 init_stream_lock (estream_t ES__RESTRICT stream)
360 {
361 #ifdef USE_NPTH
362   int rc;
363
364   if (!stream->intern->samethread)
365     {
366       dbg_lock_1 ("enter init_stream_lock for %p\n", stream);
367       rc = npth_mutex_init (&stream->intern->lock, NULL);
368       dbg_lock_2 ("leave init_stream_lock for %p: rc=%d\n", stream, rc);
369     }
370   else
371     rc = 0;
372   return rc;
373 #else
374   (void)stream;
375   return 0;
376 #endif
377 }
378
379
380 static void
381 lock_stream (estream_t ES__RESTRICT stream)
382 {
383 #ifdef USE_NPTH
384   if (!stream->intern->samethread)
385     {
386       dbg_lock_1 ("enter lock_stream for %p\n", stream);
387       npth_mutex_lock (&stream->intern->lock);
388       dbg_lock_1 ("leave lock_stream for %p\n", stream);
389     }
390 #else
391   (void)stream;
392 #endif
393 }
394
395
396 static int
397 trylock_stream (estream_t ES__RESTRICT stream)
398 {
399 #ifdef USE_NPTH
400   int rc;
401
402   if (!stream->intern->samethread)
403     {
404       dbg_lock_1 ("enter trylock_stream for %p\n", stream);
405       rc = npth_mutex_trylock (&stream->intern->lock)? 0 : -1;
406       dbg_lock_2 ("leave trylock_stream for %p: rc=%d\n", stream, rc);
407     }
408   else
409     rc = 0;
410   return rc;
411 #else
412   (void)stream;
413   return 0;
414 #endif
415 }
416
417
418 static void
419 unlock_stream (estream_t ES__RESTRICT stream)
420 {
421 #ifdef USE_NPTH
422   if (!stream->intern->samethread)
423     {
424       dbg_lock_1 ("enter unlock_stream for %p\n", stream);
425       npth_mutex_unlock (&stream->intern->lock);
426       dbg_lock_1 ("leave unlock_stream for %p\n", stream);
427     }
428 #else
429   (void)stream;
430 #endif
431 }
432
433
434 static int
435 init_list_lock (void)
436 {
437 #ifdef USE_NPTH
438   int rc;
439
440   dbg_lock_0 ("enter init_list_lock\n");
441   rc = npth_mutex_init (&estream_list_lock, NULL);
442   dbg_lock_1 ("leave init_list_lock: rc=%d\n", rc);
443   return rc;
444 #else
445   return 0;
446 #endif
447 }
448
449
450 static void
451 lock_list (void)
452 {
453 #ifdef USE_NPTH
454   dbg_lock_0 ("enter lock_list\n");
455   npth_mutex_lock (&estream_list_lock);
456   dbg_lock_0 ("leave lock_list\n");
457 #endif
458 }
459
460
461 static void
462 unlock_list (void)
463 {
464 #ifdef USE_NPTH
465   dbg_lock_0 ("enter unlock_list\n");
466   npth_mutex_unlock (&estream_list_lock);
467   dbg_lock_0 ("leave unlock_list\n");
468 #endif
469 }
470
471
472 #undef dbg_lock_0
473 #undef dbg_lock_1
474 #undef dbg_lock_2
475
476
477 \f
478 /*
479  * List manipulation.
480  */
481
482 /* Add STREAM to the list of registered stream objects.  If
483    WITH_LOCKED_LIST is true it is assumed that the list of streams is
484    already locked.  The implementation is straightforward: We first
485    look for an unused entry in the list and use that; if none is
486    available we put a new item at the head.  We drawback of the
487    strategy never to shorten the list is that a one time allocation of
488    many streams will lead to scanning unused entries later.  If that
489    turns out to be a problem, we may either free some items from the
490    list or append new entries at the end; or use a table.  Returns 0
491    on success; on error or non-zero is returned and ERRNO set.  */
492 static int
493 do_list_add (estream_t stream, int with_locked_list)
494 {
495   estream_list_t item;
496
497   if (!with_locked_list)
498     lock_list ();
499
500   for (item = estream_list; item && item->stream; item = item->next)
501     ;
502   if (!item)
503     {
504       item = mem_alloc (sizeof *item);
505       if (item)
506         {
507           item->next = estream_list;
508           estream_list = item;
509         }
510     }
511   if (item)
512     item->stream = stream;
513
514   if (!with_locked_list)
515     unlock_list ();
516
517   return item? 0 : -1;
518 }
519
520 /* Remove STREAM from the list of registered stream objects.  */
521 static void
522 do_list_remove (estream_t stream, int with_locked_list)
523 {
524   estream_list_t item;
525
526   if (!with_locked_list)
527     lock_list ();
528
529   for (item = estream_list; item; item = item->next)
530     if (item->stream == stream)
531       {
532         item->stream = NULL;
533         break;
534       }
535
536   if (!with_locked_list)
537     unlock_list ();
538 }
539
540
541 \f
542 /*
543  * I/O Helper
544  *
545  * Unfortunately our Pth emulation for Windows expects system handles
546  * for npth_read and npth_write.  We use a simple approach to fix this:
547  * If the function returns an error we fall back to a vanilla read or
548  * write, assuming that we do I/O on a plain file where the operation
549  * can't block.  FIXME:  Is this still needed for npth?
550  */
551 #ifdef USE_NPTH
552 static int
553 do_npth_read (int fd, void *buffer, size_t size)
554 {
555 # ifdef HAVE_W32_SYSTEM
556   int rc = npth_read (fd, buffer, size);
557   if (rc == -1 && errno == EINVAL)
558     rc = read (fd, buffer, size);
559   return rc;
560 # else /*!HAVE_W32_SYSTEM*/
561   return npth_read (fd, buffer, size);
562 # endif /* !HAVE_W32_SYSTEM*/
563 }
564
565 static int
566 do_npth_write (int fd, const void *buffer, size_t size)
567 {
568 # ifdef HAVE_W32_SYSTEM
569   int rc = npth_write (fd, buffer, size);
570   if (rc == -1 && errno == EINVAL)
571     rc = write (fd, buffer, size);
572   return rc;
573 # else /*!HAVE_W32_SYSTEM*/
574   return npth_write (fd, buffer, size);
575 # endif /* !HAVE_W32_SYSTEM*/
576 }
577 #endif /*USE_NPTH*/
578
579 \f
580
581 static void
582 do_deinit (void)
583 {
584   /* Flush all streams. */
585   es_fflush (NULL);
586
587   /* We should release the estream_list.  However there is one
588      problem: That list is also used to search for the standard
589      estream file descriptors.  If we would remove the entire list,
590      any use of es_foo in another atexit function may re-create the
591      list and the streams with possible undesirable effects.  Given
592      that we don't close the stream either, it should not matter that
593      we keep the list and let the OS clean it up at process end.  */
594 }
595
596
597 /*
598  * Initialization.
599  */
600
601 static int
602 do_init (void)
603 {
604   static int initialized;
605
606   if (!initialized)
607     {
608       if (!init_list_lock ())
609         initialized = 1;
610       atexit (do_deinit);
611     }
612   return 0;
613 }
614
615 \f
616
617 /*
618  * I/O methods.
619  */
620
621 /* Implementation of Memory I/O.  */
622
623 /* Cookie for memory objects.  */
624 typedef struct estream_cookie_mem
625 {
626   unsigned int modeflags;       /* Open flags.  */
627   unsigned char *memory;        /* Allocated data buffer.  */
628   size_t memory_size;           /* Allocated size of MEMORY.  */
629   size_t memory_limit;          /* Caller supplied maximum allowed
630                                    allocation size or 0 for no limit.  */
631   size_t offset;                /* Current offset in MEMORY.  */
632   size_t data_len;              /* Used length of data in MEMORY.  */
633   size_t block_size;            /* Block size.  */
634   struct {
635     unsigned int grow: 1;       /* MEMORY is allowed to grow.  */
636   } flags;
637   func_realloc_t func_realloc;
638   func_free_t func_free;
639 } *estream_cookie_mem_t;
640
641
642 /* Create function for memory objects.  DATA is either NULL or a user
643    supplied buffer with the initial conetnt of the memory buffer.  If
644    DATA is NULL, DATA_N and DATA_LEN need to be 0 as well.  If DATA is
645    not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the
646    used length in DATA.  If this fucntion succeeds DATA is now owned
647    by this function.  If GROW is false FUNC_REALLOC is not
648    required. */
649 static int
650 func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
651                  unsigned char *ES__RESTRICT data, size_t data_n,
652                  size_t data_len,
653                  size_t block_size, unsigned int grow,
654                  func_realloc_t func_realloc, func_free_t func_free,
655                  unsigned int modeflags,
656                  size_t memory_limit)
657 {
658   estream_cookie_mem_t mem_cookie;
659   int err;
660
661   if (!data && (data_n || data_len))
662     {
663       _set_errno (EINVAL);
664       return -1;
665     }
666   if (grow && func_free && !func_realloc)
667     {
668       _set_errno (EINVAL);
669       return -1;
670     }
671
672   mem_cookie = mem_alloc (sizeof (*mem_cookie));
673   if (!mem_cookie)
674     err = -1;
675   else
676     {
677       mem_cookie->modeflags = modeflags;
678       mem_cookie->memory = data;
679       mem_cookie->memory_size = data_n;
680       mem_cookie->memory_limit = memory_limit;
681       mem_cookie->offset = 0;
682       mem_cookie->data_len = data_len;
683       mem_cookie->block_size = block_size;
684       mem_cookie->flags.grow = !!grow;
685       mem_cookie->func_realloc
686         = grow? (func_realloc ? func_realloc : mem_realloc) : NULL;
687       mem_cookie->func_free = func_free ? func_free : mem_free;
688       *cookie = mem_cookie;
689       err = 0;
690     }
691
692   return err;
693 }
694
695
696 /* Read function for memory objects.  */
697 static ssize_t
698 es_func_mem_read (void *cookie, void *buffer, size_t size)
699 {
700   estream_cookie_mem_t mem_cookie = cookie;
701   ssize_t ret;
702
703   if (size > mem_cookie->data_len - mem_cookie->offset)
704     size = mem_cookie->data_len - mem_cookie->offset;
705
706   if (size)
707     {
708       memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
709       mem_cookie->offset += size;
710     }
711
712   ret = size;
713   return ret;
714 }
715
716
717 /* Write function for memory objects.  */
718 static ssize_t
719 es_func_mem_write (void *cookie, const void *buffer, size_t size)
720 {
721   estream_cookie_mem_t mem_cookie = cookie;
722   ssize_t ret;
723   size_t nleft;
724
725   if (!size)
726     return 0;  /* A flush is a NOP for memory objects.  */
727
728   if (mem_cookie->modeflags & O_APPEND)
729     {
730       /* Append to data.  */
731       mem_cookie->offset = mem_cookie->data_len;
732     }
733
734   assert (mem_cookie->memory_size >= mem_cookie->offset);
735   nleft = mem_cookie->memory_size - mem_cookie->offset;
736
737   /* If we are not allowed to grow the buffer, limit the size to the
738      left space.  */
739   if (!mem_cookie->flags.grow && size > nleft)
740     size = nleft;
741
742   /* Enlarge the memory buffer if needed.  */
743   if (size > nleft)
744     {
745       unsigned char *newbuf;
746       size_t newsize;
747
748       if (!mem_cookie->memory_size)
749         newsize = size;  /* Not yet allocated.  */
750       else
751         newsize = mem_cookie->memory_size + (size - nleft);
752       if (newsize < mem_cookie->offset)
753         {
754           _set_errno (EINVAL);
755           return -1;
756         }
757
758       /* Round up to the next block length.  BLOCK_SIZE should always
759          be set; we check anyway.  */
760       if (mem_cookie->block_size)
761         {
762           newsize += mem_cookie->block_size - 1;
763           if (newsize < mem_cookie->offset)
764             {
765               _set_errno (EINVAL);
766               return -1;
767             }
768           newsize /= mem_cookie->block_size;
769           newsize *= mem_cookie->block_size;
770         }
771
772       /* Check for a total limit.  */
773       if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
774         {
775           _set_errno (ENOSPC);
776           return -1;
777         }
778
779       assert (mem_cookie->func_realloc);
780       newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
781       if (!newbuf)
782         return -1;
783
784       mem_cookie->memory = newbuf;
785       mem_cookie->memory_size = newsize;
786
787       assert (mem_cookie->memory_size >= mem_cookie->offset);
788       nleft = mem_cookie->memory_size - mem_cookie->offset;
789
790       assert (size <= nleft);
791     }
792
793   memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
794   if (mem_cookie->offset + size > mem_cookie->data_len)
795     mem_cookie->data_len = mem_cookie->offset + size;
796   mem_cookie->offset += size;
797
798   ret = size;
799   return ret;
800 }
801
802
803 /* Seek function for memory objects.  */
804 static int
805 es_func_mem_seek (void *cookie, off_t *offset, int whence)
806 {
807   estream_cookie_mem_t mem_cookie = cookie;
808   off_t pos_new;
809
810   switch (whence)
811     {
812     case SEEK_SET:
813       pos_new = *offset;
814       break;
815
816     case SEEK_CUR:
817       pos_new = mem_cookie->offset += *offset;
818       break;
819
820     case SEEK_END:
821       pos_new = mem_cookie->data_len += *offset;
822       break;
823
824     default:
825       _set_errno (EINVAL);
826       return -1;
827     }
828
829   if (pos_new > mem_cookie->memory_size)
830     {
831       size_t newsize;
832       void *newbuf;
833
834       if (!mem_cookie->flags.grow)
835         {
836           _set_errno (ENOSPC);
837           return -1;
838         }
839
840       newsize = pos_new + mem_cookie->block_size - 1;
841       if (newsize < pos_new)
842         {
843           _set_errno (EINVAL);
844           return -1;
845         }
846       newsize /= mem_cookie->block_size;
847       newsize *= mem_cookie->block_size;
848
849       if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
850         {
851           _set_errno (ENOSPC);
852           return -1;
853         }
854
855       assert (mem_cookie->func_realloc);
856       newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
857       if (!newbuf)
858         return -1;
859
860       mem_cookie->memory = newbuf;
861       mem_cookie->memory_size = newsize;
862     }
863
864   if (pos_new > mem_cookie->data_len)
865     {
866       /* Fill spare space with zeroes.  */
867       memset (mem_cookie->memory + mem_cookie->data_len,
868               0, pos_new - mem_cookie->data_len);
869       mem_cookie->data_len = pos_new;
870     }
871
872   mem_cookie->offset = pos_new;
873   *offset = pos_new;
874
875   return 0;
876 }
877
878 /* An IOCTL function for memory objects.  */
879 static int
880 es_func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
881 {
882   estream_cookie_mem_t mem_cookie = cookie;
883   int ret;
884
885   if (cmd == COOKIE_IOCTL_SNATCH_BUFFER)
886     {
887       /* Return the internal buffer of the stream to the caller and
888          invalidate it for the stream.  */
889       *(void**)ptr = mem_cookie->memory;
890       *len = mem_cookie->offset;
891       mem_cookie->memory = NULL;
892       mem_cookie->memory_size = 0;
893       mem_cookie->offset = 0;
894       ret = 0;
895     }
896   else
897     {
898       _set_errno (EINVAL);
899       ret = -1;
900     }
901
902   return ret;
903 }
904
905
906 /* Destroy function for memory objects.  */
907 static int
908 es_func_mem_destroy (void *cookie)
909 {
910   estream_cookie_mem_t mem_cookie = cookie;
911
912   if (cookie)
913     {
914       mem_cookie->func_free (mem_cookie->memory);
915       mem_free (mem_cookie);
916     }
917   return 0;
918 }
919
920
921 static es_cookie_io_functions_t estream_functions_mem =
922   {
923     es_func_mem_read,
924     es_func_mem_write,
925     es_func_mem_seek,
926     es_func_mem_destroy
927   };
928
929
930 \f
931 /* Implementation of file descriptor based I/O.  */
932
933 /* Cookie for fd objects.  */
934 typedef struct estream_cookie_fd
935 {
936   int fd;        /* The file descriptor we are using for actual output.  */
937   int no_close;  /* If set we won't close the file descriptor.  */
938 } *estream_cookie_fd_t;
939
940 /* Create function for objects indentified by a libc file descriptor.  */
941 static int
942 func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
943 {
944   estream_cookie_fd_t fd_cookie;
945   int err;
946
947   fd_cookie = mem_alloc (sizeof (*fd_cookie));
948   if (! fd_cookie)
949     err = -1;
950   else
951     {
952 #ifdef HAVE_DOSISH_SYSTEM
953       /* Make sure it is in binary mode if requested.  */
954       if ( (modeflags & O_BINARY) )
955         setmode (fd, O_BINARY);
956 #else
957       (void)modeflags;
958 #endif
959       fd_cookie->fd = fd;
960       fd_cookie->no_close = no_close;
961       *cookie = fd_cookie;
962       err = 0;
963     }
964
965   return err;
966 }
967
968 /* Read function for fd objects.  */
969 static ssize_t
970 es_func_fd_read (void *cookie, void *buffer, size_t size)
971
972 {
973   estream_cookie_fd_t file_cookie = cookie;
974   ssize_t bytes_read;
975
976   if (IS_INVALID_FD (file_cookie->fd))
977     {
978       ESTREAM_SYS_YIELD ();
979       bytes_read = 0;
980     }
981   else
982     {
983       do
984         bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
985       while (bytes_read == -1 && errno == EINTR);
986     }
987
988   return bytes_read;
989 }
990
991 /* Write function for fd objects.  */
992 static ssize_t
993 es_func_fd_write (void *cookie, const void *buffer, size_t size)
994 {
995   estream_cookie_fd_t file_cookie = cookie;
996   ssize_t bytes_written;
997
998   if (IS_INVALID_FD (file_cookie->fd))
999     {
1000       ESTREAM_SYS_YIELD ();
1001       bytes_written = size; /* Yeah:  Success writing to the bit bucket.  */
1002     }
1003   else
1004     {
1005       do
1006         bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
1007       while (bytes_written == -1 && errno == EINTR);
1008     }
1009
1010   return bytes_written;
1011 }
1012
1013 /* Seek function for fd objects.  */
1014 static int
1015 es_func_fd_seek (void *cookie, off_t *offset, int whence)
1016 {
1017   estream_cookie_fd_t file_cookie = cookie;
1018   off_t offset_new;
1019   int err;
1020
1021   if (IS_INVALID_FD (file_cookie->fd))
1022     {
1023       _set_errno (ESPIPE);
1024       err = -1;
1025     }
1026   else
1027     {
1028       offset_new = lseek (file_cookie->fd, *offset, whence);
1029       if (offset_new == -1)
1030         err = -1;
1031       else
1032         {
1033           *offset = offset_new;
1034           err = 0;
1035         }
1036     }
1037
1038   return err;
1039 }
1040
1041 /* Destroy function for fd objects.  */
1042 static int
1043 es_func_fd_destroy (void *cookie)
1044 {
1045   estream_cookie_fd_t fd_cookie = cookie;
1046   int err;
1047
1048   if (fd_cookie)
1049     {
1050       if (IS_INVALID_FD (fd_cookie->fd))
1051         err = 0;
1052       else
1053         err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
1054       mem_free (fd_cookie);
1055     }
1056   else
1057     err = 0;
1058
1059   return err;
1060 }
1061
1062
1063 static es_cookie_io_functions_t estream_functions_fd =
1064   {
1065     es_func_fd_read,
1066     es_func_fd_write,
1067     es_func_fd_seek,
1068     es_func_fd_destroy
1069   };
1070
1071
1072
1073 \f
1074 #ifdef HAVE_W32_SYSTEM
1075 /* Implementation of W32 handle based I/O.  */
1076
1077 /* Cookie for fd objects.  */
1078 typedef struct estream_cookie_w32
1079 {
1080   HANDLE hd;     /* The handle we are using for actual output.  */
1081   int no_close;  /* If set we won't close the handle.  */
1082 } *estream_cookie_w32_t;
1083
1084
1085 /* Create function for w32 handle objects.  */
1086 static int
1087 es_func_w32_create (void **cookie, HANDLE hd,
1088                     unsigned int modeflags, int no_close)
1089 {
1090   estream_cookie_w32_t w32_cookie;
1091   int err;
1092
1093   w32_cookie = mem_alloc (sizeof (*w32_cookie));
1094   if (!w32_cookie)
1095     err = -1;
1096   else
1097     {
1098       /* CR/LF translations are not supported when using the bare W32
1099          API.  If that is really required we need to implemented that
1100          in the upper layer.  */
1101       (void)modeflags;
1102
1103       w32_cookie->hd = hd;
1104       w32_cookie->no_close = no_close;
1105       *cookie = w32_cookie;
1106       err = 0;
1107     }
1108
1109   return err;
1110 }
1111
1112 /* Read function for W32 handle objects.  */
1113 static ssize_t
1114 es_func_w32_read (void *cookie, void *buffer, size_t size)
1115 {
1116   estream_cookie_w32_t w32_cookie = cookie;
1117   ssize_t bytes_read;
1118
1119   if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1120     {
1121       ESTREAM_SYS_YIELD ();
1122       bytes_read = 0;
1123     }
1124   else
1125     {
1126       do
1127         {
1128 #ifdef USE_NPTH
1129           /* Note: Our pth_read actually uses HANDLE!
1130              FIXME: Check  whether this is the case for npth. */
1131           bytes_read = npth_read ((int)w32_cookie->hd, buffer, size);
1132 #else
1133           DWORD nread, ec;
1134
1135           if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL))
1136             {
1137               ec = GetLastError ();
1138               if (ec == ERROR_BROKEN_PIPE)
1139                 bytes_read = 0; /* Like our pth_read we handle this as EOF.  */
1140               else
1141                 {
1142                   _set_errno (map_w32_to_errno (ec));
1143                   log_debug ("estream: ReadFile returned %d\n",
1144                              (int)GetLastError ());
1145                   bytes_read = -1;
1146                 }
1147             }
1148           else
1149             bytes_read = (int)nread;
1150 #endif
1151         }
1152       while (bytes_read == -1 && errno == EINTR);
1153     }
1154
1155   return bytes_read;
1156 }
1157
1158 /* Write function for W32 handle objects.  */
1159 static ssize_t
1160 es_func_w32_write (void *cookie, const void *buffer, size_t size)
1161 {
1162   estream_cookie_w32_t w32_cookie = cookie;
1163   ssize_t bytes_written;
1164
1165   if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1166     {
1167       ESTREAM_SYS_YIELD ();
1168       bytes_written = size; /* Yeah:  Success writing to the bit bucket.  */
1169     }
1170   else
1171     {
1172       do
1173         {
1174 #ifdef USE_NPTH
1175           /* Note: Our pth_write actually uses HANDLE! */
1176           bytes_written = npth_write ((int)w32_cookie->hd, buffer, size);
1177 #else
1178           DWORD nwritten;
1179
1180           if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL))
1181             {
1182               _set_errno (map_w32_to_errno (GetLastError ()));
1183               bytes_written = -1;
1184             }
1185           else
1186             bytes_written = (int)nwritten;
1187 #endif
1188         }
1189       while (bytes_written == -1 && errno == EINTR);
1190     }
1191
1192   return bytes_written;
1193 }
1194
1195 /* Seek function for W32 handle objects.  */
1196 static int
1197 es_func_w32_seek (void *cookie, off_t *offset, int whence)
1198 {
1199   estream_cookie_w32_t w32_cookie = cookie;
1200   DWORD method;
1201   LARGE_INTEGER distance, newoff;
1202
1203   if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1204     {
1205       _set_errno (ESPIPE);
1206       return -1;
1207     }
1208
1209   if (whence == SEEK_SET)
1210     {
1211       method = FILE_BEGIN;
1212       distance.QuadPart = (unsigned long long)(*offset);
1213     }
1214   else if (whence == SEEK_CUR)
1215     {
1216       method = FILE_CURRENT;
1217       distance.QuadPart = (long long)(*offset);
1218     }
1219   else if (whence == SEEK_END)
1220     {
1221       method = FILE_END;
1222       distance.QuadPart = (long long)(*offset);
1223     }
1224   else
1225     {
1226       _set_errno (EINVAL);
1227       return -1;
1228     }
1229 #ifdef HAVE_W32CE_SYSTEM
1230 # warning need to use SetFilePointer
1231 #else
1232   if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method))
1233     {
1234       _set_errno (map_w32_to_errno (GetLastError ()));
1235       return -1;
1236     }
1237 #endif
1238   *offset = (unsigned long long)newoff.QuadPart;
1239   return 0;
1240 }
1241
1242 /* Destroy function for W32 handle objects.  */
1243 static int
1244 es_func_w32_destroy (void *cookie)
1245 {
1246   estream_cookie_w32_t w32_cookie = cookie;
1247   int err;
1248
1249   if (w32_cookie)
1250     {
1251       if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1252         err = 0;
1253       else if (w32_cookie->no_close)
1254         err = 0;
1255       else
1256         {
1257           if (!CloseHandle (w32_cookie->hd))
1258             {
1259               _set_errno (map_w32_to_errno (GetLastError ()));
1260               err = -1;
1261             }
1262           else
1263             err = 0;
1264         }
1265       mem_free (w32_cookie);
1266     }
1267   else
1268     err = 0;
1269
1270   return err;
1271 }
1272
1273
1274 static es_cookie_io_functions_t estream_functions_w32 =
1275   {
1276     es_func_w32_read,
1277     es_func_w32_write,
1278     es_func_w32_seek,
1279     es_func_w32_destroy
1280   };
1281 #endif /*HAVE_W32_SYSTEM*/
1282
1283
1284
1285 \f
1286 /* Implementation of FILE* I/O.  */
1287
1288 /* Cookie for fp objects.  */
1289 typedef struct estream_cookie_fp
1290 {
1291   FILE *fp;      /* The file pointer we are using for actual output.  */
1292   int no_close;  /* If set we won't close the file pointer.  */
1293 } *estream_cookie_fp_t;
1294
1295
1296 /* Create function for FILE objects.  */
1297 static int
1298 func_fp_create (void **cookie, FILE *fp,
1299                 unsigned int modeflags, int no_close)
1300 {
1301   estream_cookie_fp_t fp_cookie;
1302   int err;
1303
1304   fp_cookie = mem_alloc (sizeof *fp_cookie);
1305   if (!fp_cookie)
1306     err = -1;
1307   else
1308     {
1309 #ifdef HAVE_DOSISH_SYSTEM
1310       /* Make sure it is in binary mode if requested.  */
1311       if ( (modeflags & O_BINARY) )
1312         setmode (fileno (fp), O_BINARY);
1313 #else
1314       (void)modeflags;
1315 #endif
1316       fp_cookie->fp = fp;
1317       fp_cookie->no_close = no_close;
1318       *cookie = fp_cookie;
1319       err = 0;
1320     }
1321
1322   return err;
1323 }
1324
1325 /* Read function for FILE* objects.  */
1326 static ssize_t
1327 es_func_fp_read (void *cookie, void *buffer, size_t size)
1328
1329 {
1330   estream_cookie_fp_t file_cookie = cookie;
1331   ssize_t bytes_read;
1332
1333   if (file_cookie->fp)
1334     bytes_read = fread (buffer, 1, size, file_cookie->fp);
1335   else
1336     bytes_read = 0;
1337   if (!bytes_read && ferror (file_cookie->fp))
1338     return -1;
1339   return bytes_read;
1340 }
1341
1342 /* Write function for FILE* objects.  */
1343 static ssize_t
1344 es_func_fp_write (void *cookie, const void *buffer, size_t size)
1345 {
1346   estream_cookie_fp_t file_cookie = cookie;
1347   size_t bytes_written;
1348
1349   if (file_cookie->fp)
1350     {
1351 #ifdef HAVE_W32_SYSTEM
1352       /* Using an fwrite to stdout connected to the console fails with
1353          the error "Not enough space" for an fwrite size of >= 52KB
1354          (tested on Windows XP SP2).  To solve this we always chunk
1355          the writes up into smaller blocks.  */
1356       bytes_written = 0;
1357       while (bytes_written < size)
1358         {
1359           size_t cnt = size - bytes_written;
1360
1361           if (cnt > 32*1024)
1362             cnt = 32*1024;
1363           if (fwrite ((const char*)buffer + bytes_written,
1364                       cnt, 1, file_cookie->fp) != 1)
1365             break; /* Write error.  */
1366           bytes_written += cnt;
1367         }
1368 #else
1369       bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
1370 #endif
1371       fflush (file_cookie->fp);
1372     }
1373   else
1374     bytes_written = size; /* Successfully written to the bit bucket.  */
1375   if (bytes_written != size)
1376     return -1;
1377   return bytes_written;
1378 }
1379
1380 /* Seek function for FILE* objects.  */
1381 static int
1382 es_func_fp_seek (void *cookie, off_t *offset, int whence)
1383 {
1384   estream_cookie_fp_t file_cookie = cookie;
1385   long int offset_new;
1386
1387   if (!file_cookie->fp)
1388     {
1389       _set_errno (ESPIPE);
1390       return -1;
1391     }
1392
1393   if ( fseek (file_cookie->fp, (long int)*offset, whence) )
1394     {
1395       /* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */
1396       /*          errno,strerror (errno)); */
1397       return -1;
1398     }
1399
1400   offset_new = ftell (file_cookie->fp);
1401   if (offset_new == -1)
1402     {
1403       /* fprintf (stderr, "\nftell failed: errno=%d (%s)\n",  */
1404       /*          errno,strerror (errno)); */
1405       return -1;
1406     }
1407   *offset = offset_new;
1408   return 0;
1409 }
1410
1411 /* Destroy function for FILE* objects.  */
1412 static int
1413 es_func_fp_destroy (void *cookie)
1414 {
1415   estream_cookie_fp_t fp_cookie = cookie;
1416   int err;
1417
1418   if (fp_cookie)
1419     {
1420       if (fp_cookie->fp)
1421         {
1422           fflush (fp_cookie->fp);
1423           err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
1424         }
1425       else
1426         err = 0;
1427       mem_free (fp_cookie);
1428     }
1429   else
1430     err = 0;
1431
1432   return err;
1433 }
1434
1435
1436 static es_cookie_io_functions_t estream_functions_fp =
1437   {
1438     es_func_fp_read,
1439     es_func_fp_write,
1440     es_func_fp_seek,
1441     es_func_fp_destroy
1442   };
1443
1444
1445
1446 \f
1447 /* Implementation of file I/O.  */
1448
1449 /* Create function for objects identified by a file name.  */
1450 static int
1451 func_file_create (void **cookie, int *filedes,
1452                   const char *path, unsigned int modeflags, unsigned int cmode)
1453 {
1454   estream_cookie_fd_t file_cookie;
1455   int err;
1456   int fd;
1457
1458   err = 0;
1459   fd = -1;
1460
1461   file_cookie = mem_alloc (sizeof (*file_cookie));
1462   if (! file_cookie)
1463     {
1464       err = -1;
1465       goto out;
1466     }
1467
1468   fd = open (path, modeflags, cmode);
1469   if (fd == -1)
1470     {
1471       err = -1;
1472       goto out;
1473     }
1474 #ifdef HAVE_DOSISH_SYSTEM
1475   /* Make sure it is in binary mode if requested.  */
1476   if ( (modeflags & O_BINARY) )
1477     setmode (fd, O_BINARY);
1478 #endif
1479
1480   file_cookie->fd = fd;
1481   file_cookie->no_close = 0;
1482   *cookie = file_cookie;
1483   *filedes = fd;
1484
1485  out:
1486
1487   if (err)
1488     mem_free (file_cookie);
1489
1490   return err;
1491 }
1492
1493
1494 \f
1495 /* Parse the mode flags of fopen et al.  In addition to the POSIX
1496    defined mode flags keyword parameters are supported.  These are
1497    key/value pairs delimited by comma and optional white spaces.
1498    Keywords and values may not contain a comma or white space; unknown
1499    keywords are skipped. Supported keywords are:
1500
1501    mode=<string>
1502
1503       Creates a file and gives the new file read and write permissions
1504       for the user and read permission for the group.  The format of
1505       the string is the same as shown by the -l option of the ls(1)
1506       command.  However the first letter must be a dash and it is
1507       allowed to leave out trailing dashes.  If this keyword parameter
1508       is not given the default mode for creating files is "-rw-rw-r--"
1509       (664).  Note that the system still applies the current umask to
1510       the mode when crating a file.  Example:
1511
1512          "wb,mode=-rw-r--"
1513
1514    samethread
1515
1516       Assumes that the object is only used by the creating thread and
1517       disables any internal locking.  This keyword is also found on
1518       IBM systems.
1519
1520
1521    Note: R_CMODE is optional because is only required by functions
1522    which are able to creat a file.  */
1523 static int
1524 parse_mode (const char *modestr,
1525             unsigned int *modeflags, int *samethread,
1526             unsigned int *r_cmode)
1527 {
1528   unsigned int omode, oflags, cmode;
1529   int got_cmode = 0;
1530
1531   *samethread = 0;
1532
1533   switch (*modestr)
1534     {
1535     case 'r':
1536       omode = O_RDONLY;
1537       oflags = 0;
1538       break;
1539     case 'w':
1540       omode = O_WRONLY;
1541       oflags = O_TRUNC | O_CREAT;
1542       break;
1543     case 'a':
1544       omode = O_WRONLY;
1545       oflags = O_APPEND | O_CREAT;
1546       break;
1547     default:
1548       _set_errno (EINVAL);
1549       return -1;
1550     }
1551   for (modestr++; *modestr; modestr++)
1552     {
1553       switch (*modestr)
1554         {
1555         case '+':
1556           omode = O_RDWR;
1557           break;
1558         case 'b':
1559           oflags |= O_BINARY;
1560           break;
1561         case 'x':
1562           oflags |= O_EXCL;
1563           break;
1564         case ',':
1565           goto keyvalue;
1566         default: /* Ignore unknown flags.  */
1567           break;
1568         }
1569     }
1570
1571  keyvalue:
1572   /* Parse key/value pairs (similar to fopen on mainframes).  */
1573   for (cmode=0; *modestr == ','; modestr += strcspn (modestr, ","))
1574     {
1575       modestr++;
1576       modestr += strspn (modestr, " \t");
1577       if (!strncmp (modestr, "mode=", 5))
1578         {
1579           static struct {
1580             char letter;
1581             unsigned int value;
1582           } table[] = { { '-', 0 },
1583                         { 'r', S_IRUSR }, { 'w', S_IWUSR }, { 'x', S_IXUSR },
1584                         { 'r', S_IRGRP }, { 'w', S_IWGRP }, { 'x', S_IXGRP },
1585                         { 'r', S_IROTH }, { 'w', S_IWOTH }, { 'x', S_IXOTH }};
1586           int idx;
1587
1588           got_cmode = 1;
1589           modestr += 5;
1590           /* For now we only support a string as used by ls(1) and no
1591              octal numbers.  The first character must be a dash.  */
1592           for (idx=0; idx < 10 && *modestr; idx++, modestr++)
1593             {
1594               if (*modestr == table[idx].letter)
1595                 cmode |= table[idx].value;
1596               else if (*modestr != '-')
1597                 break;
1598             }
1599           if (*modestr && !strchr (" \t,", *modestr))
1600             {
1601               _set_errno (EINVAL);
1602               return -1;
1603             }
1604         }
1605       else if (!strncmp (modestr, "samethread", 10))
1606         {
1607           modestr += 10;
1608           if (*modestr && !strchr (" \t,", *modestr))
1609             {
1610               _set_errno (EINVAL);
1611               return -1;
1612             }
1613           *samethread = 1;
1614         }
1615     }
1616   if (!got_cmode)
1617     cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
1618
1619   *modeflags = (omode | oflags);
1620   if (r_cmode)
1621     *r_cmode = cmode;
1622   return 0;
1623 }
1624
1625 \f
1626
1627 /*
1628  * Low level stream functionality.
1629  */
1630
1631 static int
1632 es_fill (estream_t stream)
1633 {
1634   size_t bytes_read = 0;
1635   int err;
1636
1637   if (!stream->intern->func_read)
1638     {
1639       _set_errno (EOPNOTSUPP);
1640       err = -1;
1641     }
1642   else
1643     {
1644       es_cookie_read_function_t func_read = stream->intern->func_read;
1645       ssize_t ret;
1646
1647       ret = (*func_read) (stream->intern->cookie,
1648                           stream->buffer, stream->buffer_size);
1649       if (ret == -1)
1650         {
1651           bytes_read = 0;
1652           err = -1;
1653         }
1654       else
1655         {
1656           bytes_read = ret;
1657           err = 0;
1658         }
1659     }
1660
1661   if (err)
1662     stream->intern->indicators.err = 1;
1663   else if (!bytes_read)
1664     stream->intern->indicators.eof = 1;
1665
1666   stream->intern->offset += stream->data_len;
1667   stream->data_len = bytes_read;
1668   stream->data_offset = 0;
1669
1670   return err;
1671 }
1672
1673 static int
1674 es_flush (estream_t stream)
1675 {
1676   es_cookie_write_function_t func_write = stream->intern->func_write;
1677   int err;
1678
1679   assert (stream->flags.writing);
1680
1681   if (stream->data_offset)
1682     {
1683       size_t bytes_written;
1684       size_t data_flushed;
1685       ssize_t ret;
1686
1687       if (! func_write)
1688         {
1689           err = EOPNOTSUPP;
1690           goto out;
1691         }
1692
1693       /* Note: to prevent an endless loop caused by user-provided
1694          write-functions that pretend to have written more bytes than
1695          they were asked to write, we have to check for
1696          "(stream->data_offset - data_flushed) > 0" instead of
1697          "stream->data_offset - data_flushed".  */
1698
1699       data_flushed = 0;
1700       err = 0;
1701
1702       while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1703         {
1704           ret = (*func_write) (stream->intern->cookie,
1705                                stream->buffer + data_flushed,
1706                                stream->data_offset - data_flushed);
1707           if (ret == -1)
1708             {
1709               bytes_written = 0;
1710               err = -1;
1711             }
1712           else
1713             bytes_written = ret;
1714
1715           data_flushed += bytes_written;
1716           if (err)
1717             break;
1718         }
1719
1720       stream->data_flushed += data_flushed;
1721       if (stream->data_offset == data_flushed)
1722         {
1723           stream->intern->offset += stream->data_offset;
1724           stream->data_offset = 0;
1725           stream->data_flushed = 0;
1726
1727           /* Propagate flush event.  */
1728           (*func_write) (stream->intern->cookie, NULL, 0);
1729         }
1730     }
1731   else
1732     err = 0;
1733
1734  out:
1735
1736   if (err)
1737     stream->intern->indicators.err = 1;
1738
1739   return err;
1740 }
1741
1742 /* Discard buffered data for STREAM.  */
1743 static void
1744 es_empty (estream_t stream)
1745 {
1746   assert (!stream->flags.writing);
1747   stream->data_len = 0;
1748   stream->data_offset = 0;
1749   stream->unread_data_len = 0;
1750 }
1751
1752 /* Initialize STREAM.  */
1753 static void
1754 init_stream_obj (estream_t stream,
1755                  void *cookie, es_syshd_t *syshd,
1756                  es_cookie_io_functions_t functions,
1757                  unsigned int modeflags, int samethread)
1758 {
1759   stream->intern->cookie = cookie;
1760   stream->intern->opaque = NULL;
1761   stream->intern->offset = 0;
1762   stream->intern->func_read = functions.func_read;
1763   stream->intern->func_write = functions.func_write;
1764   stream->intern->func_seek = functions.func_seek;
1765   stream->intern->func_ioctl = NULL;
1766   stream->intern->func_close = functions.func_close;
1767   stream->intern->strategy = _IOFBF;
1768   stream->intern->syshd = *syshd;
1769   stream->intern->print_ntotal = 0;
1770   stream->intern->indicators.err = 0;
1771   stream->intern->indicators.eof = 0;
1772   stream->intern->is_stdstream = 0;
1773   stream->intern->stdstream_fd = 0;
1774   stream->intern->deallocate_buffer = 0;
1775   stream->intern->printable_fname = NULL;
1776   stream->intern->printable_fname_inuse = 0;
1777   stream->intern->samethread = !!samethread;
1778   stream->intern->onclose = NULL;
1779
1780   stream->data_len = 0;
1781   stream->data_offset = 0;
1782   stream->data_flushed = 0;
1783   stream->unread_data_len = 0;
1784   /* Depending on the modeflags we set whether we start in writing or
1785      reading mode.  This is required in case we are working on a
1786      stream which is not seeekable (like stdout).  Without this
1787      pre-initialization we would do a seek at the first write call and
1788      as this will fail no utput will be delivered. */
1789   if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1790     stream->flags.writing = 1;
1791   else
1792     stream->flags.writing = 0;
1793 }
1794
1795 /* Deinitialize STREAM.  */
1796 static int
1797 es_deinitialize (estream_t stream)
1798 {
1799   es_cookie_close_function_t func_close;
1800   int err, tmp_err;
1801
1802   func_close = stream->intern->func_close;
1803
1804   err = 0;
1805   if (stream->flags.writing)
1806     SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1807   if (func_close)
1808     SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1809
1810   mem_free (stream->intern->printable_fname);
1811   stream->intern->printable_fname = NULL;
1812   stream->intern->printable_fname_inuse = 0;
1813   while (stream->intern->onclose)
1814     {
1815       notify_list_t tmp = stream->intern->onclose->next;
1816       mem_free (stream->intern->onclose);
1817       stream->intern->onclose = tmp;
1818     }
1819
1820   return err;
1821 }
1822
1823 /* Create a new stream object, initialize it.  */
1824 static int
1825 es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
1826            es_cookie_io_functions_t functions, unsigned int modeflags,
1827            int samethread, int with_locked_list)
1828 {
1829   estream_internal_t stream_internal_new;
1830   estream_t stream_new;
1831   int err;
1832
1833   stream_new = NULL;
1834   stream_internal_new = NULL;
1835
1836   stream_new = mem_alloc (sizeof (*stream_new));
1837   if (! stream_new)
1838     {
1839       err = -1;
1840       goto out;
1841     }
1842
1843   stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1844   if (! stream_internal_new)
1845     {
1846       err = -1;
1847       goto out;
1848     }
1849
1850   stream_new->buffer = stream_internal_new->buffer;
1851   stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1852   stream_new->unread_buffer = stream_internal_new->unread_buffer;
1853   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1854   stream_new->intern = stream_internal_new;
1855
1856   init_stream_obj (stream_new, cookie, syshd, functions, modeflags, samethread);
1857   init_stream_lock (stream_new);
1858
1859   err = do_list_add (stream_new, with_locked_list);
1860   if (err)
1861     goto out;
1862
1863   *stream = stream_new;
1864
1865  out:
1866
1867   if (err)
1868     {
1869       if (stream_new)
1870         {
1871           es_deinitialize (stream_new);
1872           mem_free (stream_new);
1873         }
1874     }
1875
1876   return err;
1877 }
1878
1879 /* Deinitialize a stream object and destroy it.  */
1880 static int
1881 do_close (estream_t stream, int with_locked_list)
1882 {
1883   int err;
1884
1885   if (stream)
1886     {
1887       do_list_remove (stream, with_locked_list);
1888       while (stream->intern->onclose)
1889         {
1890           notify_list_t tmp = stream->intern->onclose->next;
1891
1892           if (stream->intern->onclose->fnc)
1893             stream->intern->onclose->fnc (stream,
1894                                           stream->intern->onclose->fnc_value);
1895           mem_free (stream->intern->onclose);
1896           stream->intern->onclose = tmp;
1897         }
1898       err = es_deinitialize (stream);
1899       mem_free (stream->intern);
1900       mem_free (stream);
1901     }
1902   else
1903     err = 0;
1904
1905   return err;
1906 }
1907
1908
1909 /* This worker function is called with a locked stream.  */
1910 static int
1911 do_onclose (estream_t stream, int mode,
1912             void (*fnc) (estream_t, void*), void *fnc_value)
1913 {
1914   notify_list_t item;
1915
1916   if (!mode)
1917     {
1918       for (item = stream->intern->onclose; item; item = item->next)
1919         if (item->fnc && item->fnc == fnc && item->fnc_value == fnc_value)
1920           item->fnc = NULL; /* Disable this notification.  */
1921     }
1922   else
1923     {
1924       item = mem_alloc (sizeof *item);
1925       if (!item)
1926         return -1;
1927       item->fnc = fnc;
1928       item->fnc_value = fnc_value;
1929       item->next = stream->intern->onclose;
1930       stream->intern->onclose = item;
1931     }
1932   return 0;
1933 }
1934
1935
1936 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1937    unbuffered-mode, storing the amount of bytes read in
1938    *BYTES_READ.  */
1939 static int
1940 es_read_nbf (estream_t ES__RESTRICT stream,
1941              unsigned char *ES__RESTRICT buffer,
1942              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1943 {
1944   es_cookie_read_function_t func_read = stream->intern->func_read;
1945   size_t data_read;
1946   ssize_t ret;
1947   int err;
1948
1949   data_read = 0;
1950   err = 0;
1951
1952   while (bytes_to_read - data_read)
1953     {
1954       ret = (*func_read) (stream->intern->cookie,
1955                           buffer + data_read, bytes_to_read - data_read);
1956       if (ret == -1)
1957         {
1958           err = -1;
1959           break;
1960         }
1961       else if (ret)
1962         data_read += ret;
1963       else
1964         break;
1965     }
1966
1967   stream->intern->offset += data_read;
1968   *bytes_read = data_read;
1969
1970   return err;
1971 }
1972
1973 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1974    fully-buffered-mode, storing the amount of bytes read in
1975    *BYTES_READ.  */
1976 static int
1977 es_read_fbf (estream_t ES__RESTRICT stream,
1978              unsigned char *ES__RESTRICT buffer,
1979              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1980 {
1981   size_t data_available;
1982   size_t data_to_read;
1983   size_t data_read;
1984   int err;
1985
1986   data_read = 0;
1987   err = 0;
1988
1989   while ((bytes_to_read - data_read) && (! err))
1990     {
1991       if (stream->data_offset == stream->data_len)
1992         {
1993           /* Nothing more to read in current container, try to
1994              fill container with new data.  */
1995           err = es_fill (stream);
1996           if (! err)
1997             if (! stream->data_len)
1998               /* Filling did not result in any data read.  */
1999               break;
2000         }
2001
2002       if (! err)
2003         {
2004           /* Filling resulted in some new data.  */
2005
2006           data_to_read = bytes_to_read - data_read;
2007           data_available = stream->data_len - stream->data_offset;
2008           if (data_to_read > data_available)
2009             data_to_read = data_available;
2010
2011           memcpy (buffer + data_read,
2012                   stream->buffer + stream->data_offset, data_to_read);
2013           stream->data_offset += data_to_read;
2014           data_read += data_to_read;
2015         }
2016     }
2017
2018   *bytes_read = data_read;
2019
2020   return err;
2021 }
2022
2023 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
2024    line-buffered-mode, storing the amount of bytes read in
2025    *BYTES_READ.  */
2026 static int
2027 es_read_lbf (estream_t ES__RESTRICT stream,
2028              unsigned char *ES__RESTRICT buffer,
2029              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
2030 {
2031   int err;
2032
2033   err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
2034
2035   return err;
2036 }
2037
2038 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
2039    *the amount of bytes read in BYTES_READ.  */
2040 static int
2041 es_readn (estream_t ES__RESTRICT stream,
2042           void *ES__RESTRICT buffer_arg,
2043           size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
2044 {
2045   unsigned char *buffer = (unsigned char *)buffer_arg;
2046   size_t data_read_unread, data_read;
2047   int err;
2048
2049   data_read_unread = 0;
2050   data_read = 0;
2051   err = 0;
2052
2053   if (stream->flags.writing)
2054     {
2055       /* Switching to reading mode -> flush output.  */
2056       err = es_flush (stream);
2057       if (err)
2058         goto out;
2059       stream->flags.writing = 0;
2060     }
2061
2062   /* Read unread data first.  */
2063   while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
2064     {
2065       buffer[data_read_unread]
2066         = stream->unread_buffer[stream->unread_data_len - 1];
2067       stream->unread_data_len--;
2068       data_read_unread++;
2069     }
2070
2071   switch (stream->intern->strategy)
2072     {
2073     case _IONBF:
2074       err = es_read_nbf (stream,
2075                          buffer + data_read_unread,
2076                          bytes_to_read - data_read_unread, &data_read);
2077       break;
2078     case _IOLBF:
2079       err = es_read_lbf (stream,
2080                          buffer + data_read_unread,
2081                          bytes_to_read - data_read_unread, &data_read);
2082       break;
2083     case _IOFBF:
2084       err = es_read_fbf (stream,
2085                          buffer + data_read_unread,
2086                          bytes_to_read - data_read_unread, &data_read);
2087       break;
2088     }
2089
2090  out:
2091
2092   if (bytes_read)
2093     *bytes_read = data_read_unread + data_read;
2094
2095   return err;
2096 }
2097
2098 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
2099    amount of bytes successfully unread in *BYTES_UNREAD.  */
2100 static void
2101 es_unreadn (estream_t ES__RESTRICT stream,
2102             const unsigned char *ES__RESTRICT data, size_t data_n,
2103             size_t *ES__RESTRICT bytes_unread)
2104 {
2105   size_t space_left;
2106
2107   space_left = stream->unread_buffer_size - stream->unread_data_len;
2108
2109   if (data_n > space_left)
2110     data_n = space_left;
2111
2112   if (! data_n)
2113     goto out;
2114
2115   memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
2116   stream->unread_data_len += data_n;
2117   stream->intern->indicators.eof = 0;
2118
2119  out:
2120
2121   if (bytes_unread)
2122     *bytes_unread = data_n;
2123 }
2124
2125 /* Seek in STREAM.  */
2126 static int
2127 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
2128          off_t *ES__RESTRICT offset_new)
2129 {
2130   es_cookie_seek_function_t func_seek = stream->intern->func_seek;
2131   int err, ret;
2132   off_t off;
2133
2134   if (! func_seek)
2135     {
2136       _set_errno (EOPNOTSUPP);
2137       err = -1;
2138       goto out;
2139     }
2140
2141   if (stream->flags.writing)
2142     {
2143       /* Flush data first in order to prevent flushing it to the wrong
2144          offset.  */
2145       err = es_flush (stream);
2146       if (err)
2147         goto out;
2148       stream->flags.writing = 0;
2149     }
2150
2151   off = offset;
2152   if (whence == SEEK_CUR)
2153     {
2154       off = off - stream->data_len + stream->data_offset;
2155       off -= stream->unread_data_len;
2156     }
2157
2158   ret = (*func_seek) (stream->intern->cookie, &off, whence);
2159   if (ret == -1)
2160     {
2161       err = -1;
2162       goto out;
2163     }
2164
2165   err = 0;
2166   es_empty (stream);
2167
2168   if (offset_new)
2169     *offset_new = off;
2170
2171   stream->intern->indicators.eof = 0;
2172   stream->intern->offset = off;
2173
2174  out:
2175
2176   if (err)
2177     stream->intern->indicators.err = 1;
2178
2179   return err;
2180 }
2181
2182 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
2183    unbuffered-mode, storing the amount of bytes written in
2184    *BYTES_WRITTEN.  */
2185 static int
2186 es_write_nbf (estream_t ES__RESTRICT stream,
2187               const unsigned char *ES__RESTRICT buffer,
2188               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
2189 {
2190   es_cookie_write_function_t func_write = stream->intern->func_write;
2191   size_t data_written;
2192   ssize_t ret;
2193   int err;
2194
2195   if (bytes_to_write && (! func_write))
2196     {
2197       err = EOPNOTSUPP;
2198       goto out;
2199     }
2200
2201   data_written = 0;
2202   err = 0;
2203
2204   while (bytes_to_write - data_written)
2205     {
2206       ret = (*func_write) (stream->intern->cookie,
2207                            buffer + data_written,
2208                            bytes_to_write - data_written);
2209       if (ret == -1)
2210         {
2211           err = -1;
2212           break;
2213         }
2214       else
2215         data_written += ret;
2216     }
2217
2218   stream->intern->offset += data_written;
2219   *bytes_written = data_written;
2220
2221  out:
2222
2223   return err;
2224 }
2225
2226 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
2227    fully-buffered-mode, storing the amount of bytes written in
2228    *BYTES_WRITTEN.  */
2229 static int
2230 es_write_fbf (estream_t ES__RESTRICT stream,
2231               const unsigned char *ES__RESTRICT buffer,
2232               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
2233 {
2234   size_t space_available;
2235   size_t data_to_write;
2236   size_t data_written;
2237   int err;
2238
2239   data_written = 0;
2240   err = 0;
2241
2242   while ((bytes_to_write - data_written) && (! err))
2243     {
2244       if (stream->data_offset == stream->buffer_size)
2245         /* Container full, flush buffer.  */
2246         err = es_flush (stream);
2247
2248       if (! err)
2249         {
2250           /* Flushing resulted in empty container.  */
2251
2252           data_to_write = bytes_to_write - data_written;
2253           space_available = stream->buffer_size - stream->data_offset;
2254           if (data_to_write > space_available)
2255             data_to_write = space_available;
2256
2257           memcpy (stream->buffer + stream->data_offset,
2258                   buffer + data_written, data_to_write);
2259           stream->data_offset += data_to_write;
2260           data_written += data_to_write;
2261         }
2262     }
2263
2264   *bytes_written = data_written;
2265
2266   return err;
2267 }
2268
2269
2270 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
2271    line-buffered-mode, storing the amount of bytes written in
2272    *BYTES_WRITTEN.  */
2273 static int
2274 es_write_lbf (estream_t ES__RESTRICT stream,
2275               const unsigned char *ES__RESTRICT buffer,
2276               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
2277 {
2278   size_t data_flushed = 0;
2279   size_t data_buffered = 0;
2280   unsigned char *nlp;
2281   int err = 0;
2282
2283   nlp = memrchr (buffer, '\n', bytes_to_write);
2284   if (nlp)
2285     {
2286       /* Found a newline, directly write up to (including) this
2287          character.  */
2288       err = es_flush (stream);
2289       if (!err)
2290         err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
2291     }
2292
2293   if (!err)
2294     {
2295       /* Write remaining data fully buffered.  */
2296       err = es_write_fbf (stream, buffer + data_flushed,
2297                           bytes_to_write - data_flushed, &data_buffered);
2298     }
2299
2300   *bytes_written = data_flushed + data_buffered;
2301   return err;
2302 }
2303
2304
2305 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
2306    amount of bytes written in BYTES_WRITTEN.  */
2307 static int
2308 es_writen (estream_t ES__RESTRICT stream,
2309            const void *ES__RESTRICT buffer,
2310            size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
2311 {
2312   size_t data_written;
2313   int err;
2314
2315   data_written = 0;
2316   err = 0;
2317
2318   if (!stream->flags.writing)
2319     {
2320       /* Switching to writing mode -> discard input data and seek to
2321          position at which reading has stopped.  We can do this only
2322          if a seek function has been registered. */
2323       if (stream->intern->func_seek)
2324         {
2325           err = es_seek (stream, 0, SEEK_CUR, NULL);
2326           if (err)
2327             {
2328               if (errno == ESPIPE)
2329                 err = 0;
2330               else
2331                 goto out;
2332             }
2333         }
2334     }
2335
2336   switch (stream->intern->strategy)
2337     {
2338     case _IONBF:
2339       err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
2340       break;
2341
2342     case _IOLBF:
2343       err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
2344       break;
2345
2346     case _IOFBF:
2347       err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
2348       break;
2349     }
2350
2351  out:
2352
2353   if (bytes_written)
2354     *bytes_written = data_written;
2355   if (data_written)
2356     if (!stream->flags.writing)
2357       stream->flags.writing = 1;
2358
2359   return err;
2360 }
2361
2362
2363 static int
2364 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
2365          size_t *ES__RESTRICT data_len)
2366 {
2367   int err;
2368
2369   if (stream->flags.writing)
2370     {
2371       /* Switching to reading mode -> flush output.  */
2372       err = es_flush (stream);
2373       if (err)
2374         goto out;
2375       stream->flags.writing = 0;
2376     }
2377
2378   if (stream->data_offset == stream->data_len)
2379     {
2380       /* Refill container.  */
2381       err = es_fill (stream);
2382       if (err)
2383         goto out;
2384     }
2385
2386   if (data)
2387     *data = stream->buffer + stream->data_offset;
2388   if (data_len)
2389     *data_len = stream->data_len - stream->data_offset;
2390   err = 0;
2391
2392  out:
2393
2394   return err;
2395 }
2396
2397
2398 /* Skip SIZE bytes of input data contained in buffer.  */
2399 static int
2400 es_skip (estream_t stream, size_t size)
2401 {
2402   int err;
2403
2404   if (stream->data_offset + size > stream->data_len)
2405     {
2406       _set_errno (EINVAL);
2407       err = -1;
2408     }
2409   else
2410     {
2411       stream->data_offset += size;
2412       err = 0;
2413     }
2414
2415   return err;
2416 }
2417
2418
2419 static int
2420 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
2421             char *ES__RESTRICT *ES__RESTRICT line,
2422             size_t *ES__RESTRICT line_length)
2423 {
2424   size_t space_left;
2425   size_t line_size;
2426   estream_t line_stream;
2427   char *line_new;
2428   void *line_stream_cookie;
2429   char *newline;
2430   unsigned char *data;
2431   size_t data_len;
2432   int err;
2433   es_syshd_t syshd;
2434
2435   line_new = NULL;
2436   line_stream = NULL;
2437   line_stream_cookie = NULL;
2438
2439   err = func_mem_create (&line_stream_cookie, NULL, 0, 0,
2440                          BUFFER_BLOCK_SIZE, 1,
2441                          mem_realloc, mem_free,
2442                          O_RDWR,
2443                          0);
2444   if (err)
2445     goto out;
2446
2447   memset (&syshd, 0, sizeof syshd);
2448   err = es_create (&line_stream, line_stream_cookie, &syshd,
2449                    estream_functions_mem, O_RDWR, 1, 0);
2450   if (err)
2451     goto out;
2452
2453   space_left = max_length;
2454   line_size = 0;
2455   while (1)
2456     {
2457       if (max_length && (space_left == 1))
2458         break;
2459
2460       err = es_peek (stream, &data, &data_len);
2461       if (err || (! data_len))
2462         break;
2463
2464       if (data_len > (space_left - 1))
2465         data_len = space_left - 1;
2466
2467       newline = memchr (data, '\n', data_len);
2468       if (newline)
2469         {
2470           data_len = (newline - (char *) data) + 1;
2471           err = es_write (line_stream, data, data_len, NULL);
2472           if (! err)
2473             {
2474               space_left -= data_len;
2475               line_size += data_len;
2476               es_skip (stream, data_len);
2477               break;
2478             }
2479         }
2480       else
2481         {
2482           err = es_write (line_stream, data, data_len, NULL);
2483           if (! err)
2484             {
2485               space_left -= data_len;
2486               line_size += data_len;
2487               es_skip (stream, data_len);
2488             }
2489         }
2490       if (err)
2491         break;
2492     }
2493   if (err)
2494     goto out;
2495
2496   /* Complete line has been written to line_stream.  */
2497
2498   if ((max_length > 1) && (! line_size))
2499     {
2500       stream->intern->indicators.eof = 1;
2501       goto out;
2502     }
2503
2504   err = es_seek (line_stream, 0, SEEK_SET, NULL);
2505   if (err)
2506     goto out;
2507
2508   if (! *line)
2509     {
2510       line_new = mem_alloc (line_size + 1);
2511       if (! line_new)
2512         {
2513           err = -1;
2514           goto out;
2515         }
2516     }
2517   else
2518     line_new = *line;
2519
2520   err = es_read (line_stream, line_new, line_size, NULL);
2521   if (err)
2522     goto out;
2523
2524   line_new[line_size] = '\0';
2525
2526   if (! *line)
2527     *line = line_new;
2528   if (line_length)
2529     *line_length = line_size;
2530
2531  out:
2532
2533   if (line_stream)
2534     do_close (line_stream, 0);
2535   else if (line_stream_cookie)
2536     es_func_mem_destroy (line_stream_cookie);
2537
2538   if (err)
2539     {
2540       if (! *line)
2541         mem_free (line_new);
2542       stream->intern->indicators.err = 1;
2543     }
2544
2545   return err;
2546 }
2547
2548
2549 /* Output fucntion used for estream_format.  */
2550 static int
2551 print_writer (void *outfncarg, const char *buf, size_t buflen)
2552 {
2553   estream_t stream = outfncarg;
2554   size_t nwritten;
2555   int rc;
2556
2557   nwritten = 0;
2558   rc = es_writen (stream, buf, buflen, &nwritten);
2559   stream->intern->print_ntotal += nwritten;
2560   return rc;
2561 }
2562
2563
2564 /* The core of our printf function.  This is called in locked state. */
2565 static int
2566 es_print (estream_t ES__RESTRICT stream,
2567           const char *ES__RESTRICT format, va_list ap)
2568 {
2569   int rc;
2570
2571   stream->intern->print_ntotal = 0;
2572   rc = estream_format (print_writer, stream, format, ap);
2573   if (rc)
2574     return -1;
2575   return (int)stream->intern->print_ntotal;
2576 }
2577
2578
2579 static void
2580 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
2581 {
2582   if (ind_err != -1)
2583     stream->intern->indicators.err = ind_err ? 1 : 0;
2584   if (ind_eof != -1)
2585     stream->intern->indicators.eof = ind_eof ? 1 : 0;
2586 }
2587
2588
2589 static int
2590 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
2591 {
2592   int ret = 0;
2593
2594   if (ind_err)
2595     ret = stream->intern->indicators.err;
2596   else if (ind_eof)
2597     ret = stream->intern->indicators.eof;
2598
2599   return ret;
2600 }
2601
2602
2603 static int
2604 es_set_buffering (estream_t ES__RESTRICT stream,
2605                   char *ES__RESTRICT buffer, int mode, size_t size)
2606 {
2607   int err;
2608
2609   /* Flush or empty buffer depending on mode.  */
2610   if (stream->flags.writing)
2611     {
2612       err = es_flush (stream);
2613       if (err)
2614         goto out;
2615     }
2616   else
2617     es_empty (stream);
2618
2619   es_set_indicators (stream, -1, 0);
2620
2621   /* Free old buffer in case that was allocated by this function.  */
2622   if (stream->intern->deallocate_buffer)
2623     {
2624       stream->intern->deallocate_buffer = 0;
2625       mem_free (stream->buffer);
2626       stream->buffer = NULL;
2627     }
2628
2629   if (mode == _IONBF)
2630     stream->buffer_size = 0;
2631   else
2632     {
2633       void *buffer_new;
2634
2635       if (buffer)
2636         buffer_new = buffer;
2637       else
2638         {
2639           if (!size)
2640             size = BUFSIZ;
2641           buffer_new = mem_alloc (size);
2642           if (! buffer_new)
2643             {
2644               err = -1;
2645               goto out;
2646             }
2647         }
2648
2649       stream->buffer = buffer_new;
2650       stream->buffer_size = size;
2651       if (! buffer)
2652         stream->intern->deallocate_buffer = 1;
2653     }
2654   stream->intern->strategy = mode;
2655   err = 0;
2656
2657  out:
2658
2659   return err;
2660 }
2661
2662
2663 static off_t
2664 es_offset_calculate (estream_t stream)
2665 {
2666   off_t offset;
2667
2668   offset = stream->intern->offset + stream->data_offset;
2669   if (offset < stream->unread_data_len)
2670     /* Offset undefined.  */
2671     offset = 0;
2672   else
2673     offset -= stream->unread_data_len;
2674
2675   return offset;
2676 }
2677
2678
2679 static void
2680 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
2681                 void **ES__RESTRICT opaque_old)
2682 {
2683   if (opaque_old)
2684     *opaque_old = stream->intern->opaque;
2685   if (opaque_new)
2686     stream->intern->opaque = opaque_new;
2687 }
2688
2689
2690 \f
2691
2692 /* API.  */
2693
2694 int
2695 es_init (void)
2696 {
2697   int err;
2698
2699   err = do_init ();
2700
2701   return err;
2702 }
2703
2704
2705 \f
2706 estream_t
2707 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
2708 {
2709   unsigned int modeflags, cmode;
2710   int samethread, create_called;
2711   estream_t stream;
2712   void *cookie;
2713   int err;
2714   int fd;
2715   es_syshd_t syshd;
2716
2717   stream = NULL;
2718   cookie = NULL;
2719   create_called = 0;
2720
2721   err = parse_mode (mode, &modeflags, &samethread, &cmode);
2722   if (err)
2723     goto out;
2724
2725   err = func_file_create (&cookie, &fd, path, modeflags, cmode);
2726   if (err)
2727     goto out;
2728
2729   syshd.type = ES_SYSHD_FD;
2730   syshd.u.fd = fd;
2731
2732   create_called = 1;
2733   err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags,
2734                    samethread, 0);
2735   if (err)
2736     goto out;
2737
2738   if (stream && path)
2739     fname_set_internal (stream, path, 1);
2740
2741  out:
2742
2743   if (err && create_called)
2744     (*estream_functions_fd.func_close) (cookie);
2745
2746   return stream;
2747 }
2748
2749
2750 \f
2751 /* Create a new estream object in memory.  If DATA is not NULL this
2752    buffer will be used as the memory buffer; thus after this functions
2753    returns with the success the the memory at DATA belongs to the new
2754    estream.  The allocated length of DATA is given by DATA_LEN and its
2755    used length by DATA_N.  Usually this is malloced buffer; if a
2756    static buffer is provided, the caller must pass false for GROW and
2757    provide a dummy function for FUNC_FREE.  FUNC_FREE and FUNC_REALLOC
2758    allow the caller to provide custom functions for realloc and free
2759    to be used by the new estream object.  Note that the realloc
2760    function is also used for initial allocation.  If DATA is NULL a
2761    buffer is internally allocated; either using internal function or
2762    those provide by the caller.  It is an error to provide a realloc
2763    function but no free function.  Providing only a free function is
2764    allowed as long as GROW is false.  */
2765 estream_t
2766 es_mopen (void *ES__RESTRICT data, size_t data_n, size_t data_len,
2767           unsigned int grow,
2768           func_realloc_t func_realloc, func_free_t func_free,
2769           const char *ES__RESTRICT mode)
2770 {
2771   int create_called = 0;
2772   estream_t stream = NULL;
2773   void *cookie = NULL;
2774   unsigned int modeflags;
2775   int samethread;
2776   int err;
2777   es_syshd_t syshd;
2778
2779   err = parse_mode (mode, &modeflags, &samethread, NULL);
2780   if (err)
2781     goto out;
2782
2783   err = func_mem_create (&cookie, data, data_n, data_len,
2784                          BUFFER_BLOCK_SIZE, grow,
2785                          func_realloc, func_free, modeflags, 0);
2786   if (err)
2787     goto out;
2788
2789   memset (&syshd, 0, sizeof syshd);
2790   create_called = 1;
2791   err = es_create (&stream, cookie, &syshd,
2792                    estream_functions_mem, modeflags, samethread, 0);
2793
2794  out:
2795
2796   if (err && create_called)
2797     (*estream_functions_mem.func_close) (cookie);
2798
2799   return stream;
2800 }
2801
2802
2803 \f
2804 estream_t
2805 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
2806 {
2807   unsigned int modeflags;
2808   int samethread;
2809   estream_t stream = NULL;
2810   void *cookie = NULL;
2811   es_syshd_t syshd;
2812
2813   /* Memory streams are always read/write.  We use MODE only to get
2814      the append flag.  */
2815   if (parse_mode (mode, &modeflags, &samethread, NULL))
2816     return NULL;
2817   modeflags |= O_RDWR;
2818
2819   if (func_mem_create (&cookie, NULL, 0, 0,
2820                        BUFFER_BLOCK_SIZE, 1,
2821                        mem_realloc, mem_free, modeflags,
2822                        memlimit))
2823     return NULL;
2824
2825   memset (&syshd, 0, sizeof syshd);
2826   if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags,
2827                  samethread, 0))
2828     (*estream_functions_mem.func_close) (cookie);
2829
2830   if (stream)
2831     stream->intern->func_ioctl = es_func_mem_ioctl;
2832
2833   return stream;
2834 }
2835
2836 \f
2837 /* This is the same as es_fopenmem but intializes the memory with a
2838    copy of (DATA,DATALEN).  The stream is initally set to the
2839    beginning.  If MEMLIMIT is not 0 but shorter than DATALEN it
2840    DATALEN will be used as the value for MEMLIMIT.  */
2841 estream_t
2842 es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode,
2843                   const void *data, size_t datalen)
2844 {
2845   estream_t stream;
2846
2847   if (memlimit && memlimit < datalen)
2848     memlimit = datalen;
2849
2850   stream = es_fopenmem (memlimit, mode);
2851   if (stream && data && datalen)
2852     {
2853       if (es_writen (stream, data, datalen, NULL))
2854         {
2855           int saveerrno = errno;
2856           es_fclose (stream);
2857           stream = NULL;
2858           _set_errno (saveerrno);
2859         }
2860       else
2861         {
2862           es_seek (stream, 0L, SEEK_SET, NULL);
2863           es_set_indicators (stream, 0, 0);
2864         }
2865     }
2866   return stream;
2867 }
2868
2869
2870 \f
2871 estream_t
2872 es_fopencookie (void *ES__RESTRICT cookie,
2873                 const char *ES__RESTRICT mode,
2874                 es_cookie_io_functions_t functions)
2875 {
2876   unsigned int modeflags;
2877   int samethread;
2878   estream_t stream;
2879   int err;
2880   es_syshd_t syshd;
2881
2882   stream = NULL;
2883   modeflags = 0;
2884
2885   err = parse_mode (mode, &modeflags, &samethread, NULL);
2886   if (err)
2887     goto out;
2888
2889   memset (&syshd, 0, sizeof syshd);
2890   err = es_create (&stream, cookie, &syshd, functions, modeflags,
2891                    samethread, 0);
2892   if (err)
2893     goto out;
2894
2895  out:
2896   return stream;
2897 }
2898
2899
2900 \f
2901 estream_t
2902 do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
2903 {
2904   unsigned int modeflags;
2905   int samethread, create_called;
2906   estream_t stream;
2907   void *cookie;
2908   int err;
2909   es_syshd_t syshd;
2910
2911   stream = NULL;
2912   cookie = NULL;
2913   create_called = 0;
2914
2915   err = parse_mode (mode, &modeflags, &samethread, NULL);
2916   if (err)
2917     goto out;
2918
2919   err = func_fd_create (&cookie, filedes, modeflags, no_close);
2920   if (err)
2921     goto out;
2922
2923   syshd.type = ES_SYSHD_FD;
2924   syshd.u.fd = filedes;
2925   create_called = 1;
2926   err = es_create (&stream, cookie, &syshd, estream_functions_fd,
2927                    modeflags, samethread, with_locked_list);
2928
2929  out:
2930   if (err && create_called)
2931     (*estream_functions_fd.func_close) (cookie);
2932
2933   return stream;
2934 }
2935
2936 estream_t
2937 es_fdopen (int filedes, const char *mode)
2938 {
2939   return do_fdopen (filedes, mode, 0, 0);
2940 }
2941
2942 /* A variant of es_fdopen which does not close FILEDES at the end.  */
2943 estream_t
2944 es_fdopen_nc (int filedes, const char *mode)
2945 {
2946   return do_fdopen (filedes, mode, 1, 0);
2947 }
2948
2949
2950 \f
2951 estream_t
2952 do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
2953 {
2954   unsigned int modeflags, cmode;
2955   int samethread, create_called;
2956   estream_t stream;
2957   void *cookie;
2958   int err;
2959   es_syshd_t syshd;
2960
2961   stream = NULL;
2962   cookie = NULL;
2963   create_called = 0;
2964
2965   err = parse_mode (mode, &modeflags, &samethread, &cmode);
2966   if (err)
2967     goto out;
2968
2969   if (fp)
2970     fflush (fp);
2971   err = func_fp_create (&cookie, fp, modeflags, no_close);
2972   if (err)
2973     goto out;
2974
2975   syshd.type = ES_SYSHD_FD;
2976   syshd.u.fd = fp? fileno (fp): -1;
2977   create_called = 1;
2978   err = es_create (&stream, cookie, &syshd, estream_functions_fp,
2979                    modeflags, samethread, with_locked_list);
2980
2981  out:
2982
2983   if (err && create_called)
2984     (*estream_functions_fp.func_close) (cookie);
2985
2986   return stream;
2987 }
2988
2989
2990 /* Create an estream from the stdio stream FP.  This mechanism is
2991    useful in case the stdio streams have special properties and may
2992    not be mixed with fd based functions.  This is for example the case
2993    under Windows where the 3 standard streams are associated with the
2994    console whereas a duped and fd-opened stream of one of this stream
2995    won't be associated with the console.  As this messes things up it
2996    is easier to keep on using the standard I/O stream as a backend for
2997    estream. */
2998 estream_t
2999 es_fpopen (FILE *fp, const char *mode)
3000 {
3001   return do_fpopen (fp, mode, 0, 0);
3002 }
3003
3004
3005 /* Same as es_fpopen but does not close  FP at the end.  */
3006 estream_t
3007 es_fpopen_nc (FILE *fp, const char *mode)
3008 {
3009   return do_fpopen (fp, mode, 1, 0);
3010 }
3011
3012
3013 \f
3014 #ifdef HAVE_W32_SYSTEM
3015 estream_t
3016 do_w32open (HANDLE hd, const char *mode,
3017             int no_close, int with_locked_list)
3018 {
3019   unsigned int modeflags, cmode;
3020   int samethread;
3021   int create_called = 0;
3022   estream_t stream = NULL;
3023   void *cookie = NULL;
3024   int err;
3025   es_syshd_t syshd;
3026
3027   err = parse_mode (mode, &modeflags, &samethread, &cmode);
3028   if (err)
3029     goto leave;
3030
3031   err = es_func_w32_create (&cookie, hd, modeflags, no_close);
3032   if (err)
3033     goto leave;
3034
3035   syshd.type = ES_SYSHD_HANDLE;
3036   syshd.u.handle = hd;
3037   create_called = 1;
3038   err = es_create (&stream, cookie, &syshd, estream_functions_w32,
3039                    modeflags, samethread, with_locked_list);
3040
3041  leave:
3042   if (err && create_called)
3043     (*estream_functions_w32.func_close) (cookie);
3044
3045   return stream;
3046 }
3047 #endif /*HAVE_W32_SYSTEM*/
3048
3049 static estream_t
3050 do_sysopen (es_syshd_t *syshd, const char *mode, int no_close)
3051 {
3052   estream_t stream;
3053
3054   switch (syshd->type)
3055     {
3056     case ES_SYSHD_FD:
3057     case ES_SYSHD_SOCK:
3058       stream = do_fdopen (syshd->u.fd, mode, no_close, 0);
3059       break;
3060
3061 #ifdef HAVE_W32_SYSTEM
3062     case ES_SYSHD_HANDLE:
3063       stream = do_w32open (syshd->u.handle, mode, no_close, 0);
3064       break;
3065 #endif
3066
3067     /* FIXME: Support RVIDs under Wince?  */
3068
3069     default:
3070       _set_errno (EINVAL);
3071       stream = NULL;
3072     }
3073   return stream;
3074 }
3075
3076 /* On POSIX systems this function is an alias for es_fdopen.  Under
3077    Windows it uses the bare W32 API and thus a HANDLE instead of a
3078    file descriptor.  */
3079 estream_t
3080 es_sysopen (es_syshd_t *syshd, const char *mode)
3081 {
3082   return do_sysopen (syshd, mode, 0);
3083 }
3084
3085 /* Same as es_sysopen but the handle/fd will not be closed by
3086    es_fclose.  */
3087 estream_t
3088 es_sysopen_nc (es_syshd_t *syshd, const char *mode)
3089 {
3090   return do_sysopen (syshd, mode, 1);
3091 }
3092
3093
3094
3095 /* Set custom standard descriptors to be used for stdin, stdout and
3096    stderr.  This function needs to be called before any of the
3097    standard streams are accessed.  */
3098 void
3099 _es_set_std_fd (int no, int fd)
3100 {
3101   /* fprintf (stderr, "es_set_std_fd(%d, %d)\n", no, fd); */
3102   lock_list ();
3103   if (no >= 0 && no < 3 && !custom_std_fds_valid[no])
3104     {
3105       custom_std_fds[no] = fd;
3106       custom_std_fds_valid[no] = 1;
3107     }
3108   unlock_list ();
3109 }
3110
3111
3112 /* Return the stream used for stdin, stdout or stderr.  */
3113 estream_t
3114 _es_get_std_stream (int fd)
3115 {
3116   estream_list_t list_obj;
3117   estream_t stream = NULL;
3118
3119   fd %= 3; /* We only allow 0, 1 or 2 but we don't want to return an error. */
3120
3121   lock_list ();
3122
3123   for (list_obj = estream_list; list_obj; list_obj = list_obj->next)
3124     if (list_obj->stream && list_obj->stream->intern->is_stdstream
3125         && list_obj->stream->intern->stdstream_fd == fd)
3126       {
3127         stream = list_obj->stream;
3128         break;
3129       }
3130   if (!stream)
3131     {
3132       /* Standard stream not yet created.  We first try to create them
3133          from registered file descriptors.  */
3134       if (!fd && custom_std_fds_valid[0])
3135         stream = do_fdopen (custom_std_fds[0], "r", 1, 1);
3136       else if (fd == 1 && custom_std_fds_valid[1])
3137         stream = do_fdopen (custom_std_fds[1], "a", 1, 1);
3138       else if (custom_std_fds_valid[2])
3139         stream = do_fdopen (custom_std_fds[2], "a", 1, 1);
3140
3141       if (!stream)
3142         {
3143           /* Second try is to use the standard C streams.  */
3144           if (!fd)
3145             stream = do_fpopen (stdin, "r", 1, 1);
3146           else if (fd == 1)
3147             stream = do_fpopen (stdout, "a", 1, 1);
3148           else
3149             stream = do_fpopen (stderr, "a", 1, 1);
3150         }
3151
3152       if (!stream)
3153         {
3154           /* Last try: Create a bit bucket.  */
3155           stream = do_fpopen (NULL, fd? "a":"r", 0, 1);
3156           if (!stream)
3157             {
3158               fprintf (stderr, "fatal: error creating a dummy estream"
3159                        " for %d: %s\n", fd, strerror (errno));
3160               abort();
3161             }
3162         }
3163
3164       stream->intern->is_stdstream = 1;
3165       stream->intern->stdstream_fd = fd;
3166       if (fd == 2)
3167         es_set_buffering (stream, NULL, _IOLBF, 0);
3168       fname_set_internal (stream,
3169                           fd == 0? "[stdin]" :
3170                           fd == 1? "[stdout]" : "[stderr]", 0);
3171     }
3172
3173   unlock_list ();
3174   return stream;
3175 }
3176
3177 /* Note: A "samethread" keyword given in "mode" is ignored and the
3178    value used by STREAM is used instead. */
3179 estream_t
3180 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
3181             estream_t ES__RESTRICT stream)
3182 {
3183   int err;
3184
3185   if (path)
3186     {
3187       unsigned int modeflags, cmode;
3188       int dummy, samethread, create_called;
3189       void *cookie;
3190       int fd;
3191       es_syshd_t syshd;
3192
3193       cookie = NULL;
3194       create_called = 0;
3195
3196       samethread = stream->intern->samethread;
3197
3198       lock_stream (stream);
3199
3200       es_deinitialize (stream);
3201
3202       err = parse_mode (mode, &modeflags, &dummy, &cmode);
3203       if (err)
3204         goto leave;
3205       (void)dummy;
3206
3207       err = func_file_create (&cookie, &fd, path, modeflags, cmode);
3208       if (err)
3209         goto leave;
3210
3211       syshd.type = ES_SYSHD_FD;
3212       syshd.u.fd = fd;
3213       create_called = 1;
3214       init_stream_obj (stream, cookie, &syshd, estream_functions_fd,
3215                        modeflags, samethread);
3216
3217     leave:
3218
3219       if (err)
3220         {
3221           if (create_called)
3222             es_func_fd_destroy (cookie);
3223
3224           do_close (stream, 0);
3225           stream = NULL;
3226         }
3227       else
3228         {
3229           if (path)
3230             fname_set_internal (stream, path, 1);
3231           unlock_stream (stream);
3232         }
3233     }
3234   else
3235     {
3236       /* FIXME?  We don't support re-opening at the moment.  */
3237       _set_errno (EINVAL);
3238       es_deinitialize (stream);
3239       do_close (stream, 0);
3240       stream = NULL;
3241     }
3242
3243   return stream;
3244 }
3245
3246
3247 int
3248 es_fclose (estream_t stream)
3249 {
3250   int err;
3251
3252   err = do_close (stream, 0);
3253
3254   return err;
3255 }
3256
3257
3258 /* This is a special version of es_fclose which can be used with
3259    es_fopenmem to return the memory buffer.  This is feature is useful
3260    to write to a memory buffer using estream.  Note that the function
3261    does not close the stream if the stream does not support snatching
3262    the buffer.  On error NULL is stored at R_BUFFER.  Note that if no
3263    write operation has happened, NULL may also be stored at BUFFER on
3264    success.  The caller needs to release the returned memory using
3265    es_free.  */
3266 int
3267 es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen)
3268 {
3269   int err;
3270
3271   /* Note: There is no need to lock the stream in a close call.  The
3272      object will be destroyed after the close and thus any other
3273      contender for the lock would work on a closed stream.  */
3274
3275   if (r_buffer)
3276     {
3277       cookie_ioctl_function_t func_ioctl = stream->intern->func_ioctl;
3278       size_t buflen;
3279
3280       *r_buffer = NULL;
3281
3282       if (!func_ioctl)
3283         {
3284           _set_errno (EOPNOTSUPP);
3285           err = -1;
3286           goto leave;
3287         }
3288
3289       if (stream->flags.writing)
3290         {
3291           err = es_flush (stream);
3292           if (err)
3293             goto leave;
3294           stream->flags.writing = 0;
3295         }
3296
3297       err = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_SNATCH_BUFFER,
3298                         r_buffer, &buflen);
3299       if (err)
3300         goto leave;
3301       if (r_buflen)
3302         *r_buflen = buflen;
3303     }
3304
3305   err = do_close (stream, 0);
3306
3307  leave:
3308   if (err && r_buffer)
3309     {
3310       mem_free (*r_buffer);
3311       *r_buffer = NULL;
3312     }
3313   return err;
3314 }
3315
3316
3317 /* Register or unregister a close notification function for STREAM.
3318    FNC is the function to call and FNC_VALUE the value passed as
3319    second argument.  To register the notification the value for MODE
3320    must be 1.  If mode is 0 the function tries to remove or disable an
3321    already registered notification; for this to work the value of FNC
3322    and FNC_VALUE must be the same as with the registration and
3323    FNC_VALUE must be a unique value.  No error will be returned if
3324    MODE is 0.
3325
3326    FIXME: I think the next comment is not anymore correct:
3327    Unregister should only be used in the error case because it may not
3328    be able to remove memory internally allocated for the onclose
3329    handler.
3330
3331    FIXME: Unregister is not thread safe.
3332
3333    The notification will be called right before the stream is closed.
3334    It may not call any estream function for STREAM, neither direct nor
3335    indirectly. */
3336 int
3337 es_onclose (estream_t stream, int mode,
3338             void (*fnc) (estream_t, void*), void *fnc_value)
3339 {
3340   int err;
3341
3342   lock_stream (stream);
3343   err = do_onclose (stream, mode, fnc, fnc_value);
3344   unlock_stream (stream);
3345
3346   return err;
3347 }
3348
3349
3350 int
3351 es_fileno_unlocked (estream_t stream)
3352 {
3353   es_syshd_t syshd;
3354
3355   if (es_syshd_unlocked (stream, &syshd))
3356     return -1;
3357   switch (syshd.type)
3358     {
3359     case ES_SYSHD_FD:   return syshd.u.fd;
3360     case ES_SYSHD_SOCK: return syshd.u.sock;
3361     default:
3362       _set_errno (EINVAL);
3363       return -1;
3364     }
3365 }
3366
3367
3368 /* Return the handle of a stream which has been opened by es_sysopen.
3369    The caller needs to pass a structure which will be filled with the
3370    sys handle.  Return 0 on success or true on error and sets errno.
3371    This is the unlocked version.  */
3372 int
3373 es_syshd_unlocked (estream_t stream, es_syshd_t *syshd)
3374 {
3375   if (!stream || !syshd || stream->intern->syshd.type == ES_SYSHD_NONE)
3376     {
3377       if (syshd)
3378         syshd->type = ES_SYSHD_NONE;
3379       _set_errno (EINVAL);
3380       return -1;
3381     }
3382
3383   *syshd = stream->intern->syshd;
3384   return 0;
3385 }
3386
3387
3388 void
3389 es_flockfile (estream_t stream)
3390 {
3391   lock_stream (stream);
3392 }
3393
3394
3395 int
3396 es_ftrylockfile (estream_t stream)
3397 {
3398   return trylock_stream (stream);
3399 }
3400
3401
3402 void
3403 es_funlockfile (estream_t stream)
3404 {
3405   unlock_stream (stream);
3406 }
3407
3408
3409 int
3410 es_fileno (estream_t stream)
3411 {
3412   int ret;
3413
3414   lock_stream (stream);
3415   ret = es_fileno_unlocked (stream);
3416   unlock_stream (stream);
3417
3418   return ret;
3419 }
3420
3421
3422 /* Return the handle of a stream which has been opened by es_sysopen.
3423    The caller needs to pass a structure which will be filled with the
3424    sys handle.  Return 0 on success or true on error and sets errno.
3425    This is the unlocked version.  */
3426 int
3427 es_syshd (estream_t stream, es_syshd_t *syshd)
3428 {
3429   int ret;
3430
3431   lock_stream (stream);
3432   ret = es_syshd_unlocked (stream, syshd);
3433   unlock_stream (stream);
3434
3435   return ret;
3436 }
3437
3438
3439 int
3440 es_feof_unlocked (estream_t stream)
3441 {
3442   return es_get_indicator (stream, 0, 1);
3443 }
3444
3445
3446 int
3447 es_feof (estream_t stream)
3448 {
3449   int ret;
3450
3451   lock_stream (stream);
3452   ret = es_feof_unlocked (stream);
3453   unlock_stream (stream);
3454
3455   return ret;
3456 }
3457
3458
3459 int
3460 es_ferror_unlocked (estream_t stream)
3461 {
3462   return es_get_indicator (stream, 1, 0);
3463 }
3464
3465
3466 int
3467 es_ferror (estream_t stream)
3468 {
3469   int ret;
3470
3471   lock_stream (stream);
3472   ret = es_ferror_unlocked (stream);
3473   unlock_stream (stream);
3474
3475   return ret;
3476 }
3477
3478
3479 void
3480 es_clearerr_unlocked (estream_t stream)
3481 {
3482   es_set_indicators (stream, 0, 0);
3483 }
3484
3485
3486 void
3487 es_clearerr (estream_t stream)
3488 {
3489   lock_stream (stream);
3490   es_clearerr_unlocked (stream);
3491   unlock_stream (stream);
3492 }
3493
3494
3495 static int
3496 do_fflush (estream_t stream)
3497 {
3498   int err;
3499
3500   if (stream->flags.writing)
3501     err = es_flush (stream);
3502   else
3503     {
3504       es_empty (stream);
3505       err = 0;
3506     }
3507
3508   return err;
3509 }
3510
3511
3512 int
3513 es_fflush (estream_t stream)
3514 {
3515   int err;
3516
3517   if (stream)
3518     {
3519       lock_stream (stream);
3520       err = do_fflush (stream);
3521       unlock_stream (stream);
3522     }
3523   else
3524     {
3525       estream_list_t item;
3526
3527       err = 0;
3528       lock_list ();
3529       for (item = estream_list; item; item = item->next)
3530         if (item->stream)
3531           {
3532             lock_stream (item->stream);
3533             err |= do_fflush (item->stream);
3534             unlock_stream (item->stream);
3535           }
3536       unlock_list ();
3537     }
3538   return err ? EOF : 0;
3539 }
3540
3541
3542 int
3543 es_fseek (estream_t stream, long int offset, int whence)
3544 {
3545   int err;
3546
3547   lock_stream (stream);
3548   err = es_seek (stream, offset, whence, NULL);
3549   unlock_stream (stream);
3550
3551   return err;
3552 }
3553
3554
3555 int
3556 es_fseeko (estream_t stream, off_t offset, int whence)
3557 {
3558   int err;
3559
3560   lock_stream (stream);
3561   err = es_seek (stream, offset, whence, NULL);
3562   unlock_stream (stream);
3563
3564   return err;
3565 }
3566
3567
3568 long int
3569 es_ftell (estream_t stream)
3570 {
3571   long int ret;
3572
3573   lock_stream (stream);
3574   ret = es_offset_calculate (stream);
3575   unlock_stream (stream);
3576
3577   return ret;
3578 }
3579
3580
3581 off_t
3582 es_ftello (estream_t stream)
3583 {
3584   off_t ret = -1;
3585
3586   lock_stream (stream);
3587   ret = es_offset_calculate (stream);
3588   unlock_stream (stream);
3589
3590   return ret;
3591 }
3592
3593
3594 void
3595 es_rewind (estream_t stream)
3596 {
3597   lock_stream (stream);
3598   es_seek (stream, 0L, SEEK_SET, NULL);
3599   es_set_indicators (stream, 0, -1);
3600   unlock_stream (stream);
3601 }
3602
3603
3604 int
3605 _es_getc_underflow (estream_t stream)
3606 {
3607   int err;
3608   unsigned char c;
3609   size_t bytes_read;
3610
3611   err = es_readn (stream, &c, 1, &bytes_read);
3612
3613   return (err || (! bytes_read)) ? EOF : c;
3614 }
3615
3616
3617 int
3618 _es_putc_overflow (int c, estream_t stream)
3619 {
3620   unsigned char d = c;
3621   int err;
3622
3623   err = es_writen (stream, &d, 1, NULL);
3624
3625   return err ? EOF : c;
3626 }
3627
3628
3629 int
3630 es_fgetc (estream_t stream)
3631 {
3632   int ret;
3633
3634   lock_stream (stream);
3635   ret = es_getc_unlocked (stream);
3636   unlock_stream (stream);
3637
3638   return ret;
3639 }
3640
3641
3642 int
3643 es_fputc (int c, estream_t stream)
3644 {
3645   int ret;
3646
3647   lock_stream (stream);
3648   ret = es_putc_unlocked (c, stream);
3649   unlock_stream (stream);
3650
3651   return ret;
3652 }
3653
3654
3655 int
3656 es_ungetc (int c, estream_t stream)
3657 {
3658   unsigned char data = (unsigned char) c;
3659   size_t data_unread;
3660
3661   lock_stream (stream);
3662   es_unreadn (stream, &data, 1, &data_unread);
3663   unlock_stream (stream);
3664
3665   return data_unread ? c : EOF;
3666 }
3667
3668
3669 int
3670 es_read (estream_t ES__RESTRICT stream,
3671          void *ES__RESTRICT buffer, size_t bytes_to_read,
3672          size_t *ES__RESTRICT bytes_read)
3673 {
3674   int err;
3675
3676   if (bytes_to_read)
3677     {
3678       lock_stream (stream);
3679       err = es_readn (stream, buffer, bytes_to_read, bytes_read);
3680       unlock_stream (stream);
3681     }
3682   else
3683     err = 0;
3684
3685   return err;
3686 }
3687
3688
3689 int
3690 es_write (estream_t ES__RESTRICT stream,
3691           const void *ES__RESTRICT buffer, size_t bytes_to_write,
3692           size_t *ES__RESTRICT bytes_written)
3693 {
3694   int err;
3695
3696   if (bytes_to_write)
3697     {
3698       lock_stream (stream);
3699       err = es_writen (stream, buffer, bytes_to_write, bytes_written);
3700       unlock_stream (stream);
3701     }
3702   else
3703     err = 0;
3704
3705   return err;
3706 }
3707
3708
3709 size_t
3710 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
3711           estream_t ES__RESTRICT stream)
3712 {
3713   size_t ret, bytes;
3714
3715   if (size * nitems)
3716     {
3717       lock_stream (stream);
3718       es_readn (stream, ptr, size * nitems, &bytes);
3719       unlock_stream (stream);
3720
3721       ret = bytes / size;
3722     }
3723   else
3724     ret = 0;
3725
3726   return ret;
3727 }
3728
3729
3730 size_t
3731 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
3732            estream_t ES__RESTRICT stream)
3733 {
3734   size_t ret, bytes;
3735
3736   if (size * nitems)
3737     {
3738       lock_stream (stream);
3739       es_writen (stream, ptr, size * nitems, &bytes);
3740       unlock_stream (stream);
3741
3742       ret = bytes / size;
3743     }
3744   else
3745     ret = 0;
3746
3747   return ret;
3748 }
3749
3750
3751 char *
3752 es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
3753 {
3754   unsigned char *s = (unsigned char*)buffer;
3755   int c;
3756
3757   if (!length)
3758     return NULL;
3759
3760   c = EOF;
3761   lock_stream (stream);
3762   while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
3763     {
3764       *s++ = c;
3765       length--;
3766     }
3767   unlock_stream (stream);
3768
3769   if (c == EOF && s == (unsigned char*)buffer)
3770     return NULL; /* Nothing read.  */
3771
3772   if (c != EOF && length > 1)
3773     *s++ = c;
3774
3775   *s = 0;
3776   return buffer;
3777 }
3778
3779
3780 int
3781 es_fputs_unlocked (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
3782 {
3783   size_t length;
3784   int err;
3785
3786   length = strlen (s);
3787   err = es_writen (stream, s, length, NULL);
3788   return err ? EOF : 0;
3789 }
3790
3791 int
3792 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
3793 {
3794   size_t length;
3795   int err;
3796
3797   length = strlen (s);
3798   lock_stream (stream);
3799   err = es_writen (stream, s, length, NULL);
3800   unlock_stream (stream);
3801
3802   return err ? EOF : 0;
3803 }
3804
3805
3806 ssize_t
3807 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
3808             estream_t ES__RESTRICT stream)
3809 {
3810   char *line = NULL;
3811   size_t line_n = 0;
3812   int err;
3813
3814   lock_stream (stream);
3815   err = doreadline (stream, 0, &line, &line_n);
3816   unlock_stream (stream);
3817   if (err)
3818     goto out;
3819
3820   if (*n)
3821     {
3822       /* Caller wants us to use his buffer.  */
3823
3824       if (*n < (line_n + 1))
3825         {
3826           /* Provided buffer is too small -> resize.  */
3827
3828           void *p;
3829
3830           p = mem_realloc (*lineptr, line_n + 1);
3831           if (! p)
3832             err = -1;
3833           else
3834             {
3835               if (*lineptr != p)
3836                 *lineptr = p;
3837             }
3838         }
3839
3840       if (! err)
3841         {
3842           memcpy (*lineptr, line, line_n + 1);
3843           if (*n != line_n)
3844             *n = line_n;
3845         }
3846       mem_free (line);
3847     }
3848   else
3849     {
3850       /* Caller wants new buffers.  */
3851       *lineptr = line;
3852       *n = line_n;
3853     }
3854
3855  out:
3856
3857   return err ? err : (ssize_t)line_n;
3858 }
3859
3860
3861
3862 /* Same as fgets() but if the provided buffer is too short a larger
3863    one will be allocated.  This is similar to getline. A line is
3864    considered a byte stream ending in a LF.
3865
3866    If MAX_LENGTH is not NULL, it shall point to a value with the
3867    maximum allowed allocation.
3868
3869    Returns the length of the line. EOF is indicated by a line of
3870    length zero. A truncated line is indicated my setting the value at
3871    MAX_LENGTH to 0.  If the returned value is less then 0 not enough
3872    memory was enable or another error occurred; ERRNO is then set
3873    accordingly.
3874
3875    If a line has been truncated, the file pointer is moved forward to
3876    the end of the line so that the next read starts with the next
3877    line.  Note that MAX_LENGTH must be re-initialzied in this case.
3878