From 831cd76256290541a102bc660442918c95a65e6c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 25 Jun 2007 11:54:43 +0000 Subject: [PATCH] Fixed a problem in estream-printf.c. Changes for Windows (gpgsm -k does now work). Minor cleanups. --- autogen.sh | 2 +- common/ChangeLog | 42 +++++ common/estream-printf.c | 35 ++-- common/estream.c | 375 +++++++++++++++++++++++++++++++--------- common/estream.h | 16 +- common/homedir.c | 107 ++++++++---- common/iobuf.c | 28 +-- common/iobuf.h | 2 - common/sysutils.c | 29 ++++ common/sysutils.h | 1 + doc/ChangeLog | 5 + doc/gpg.texi | 8 + g10/ChangeLog | 6 + g10/gpg.c | 10 +- g10/gpgv.c | 2 +- sm/ChangeLog | 10 ++ sm/certreqgen.c | 8 +- sm/gpgsm.c | 16 +- 18 files changed, 520 insertions(+), 182 deletions(-) diff --git a/autogen.sh b/autogen.sh index 70b2eabb7..ad1464ce1 100755 --- a/autogen.sh +++ b/autogen.sh @@ -93,7 +93,7 @@ if test "$1" = "--build-w32"; then --with-zlib=${w32root} \ --with-pth-prefix=${w32root} \ --without-included-gettext \ - --disable-regex + --disable-regex "$@" rc=$? exit $rc fi diff --git a/common/ChangeLog b/common/ChangeLog index e80e70359..c5fc79d92 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,45 @@ +2007-06-25 Werner Koch + + * sysutils.c (translate_sys2libc_fd): New using the code from iobuf.c. + * iobuf.c: Include sysutils.h. + (iobuf_translate_file_handle): Remove. + (translate_file_handle): Use new function. + + * estream-printf.c [TEST]: Header including fixes. + (do_format): Do not append a trailing Nul. This avoids spurious + Nuls in the es_printf output. + (estream_vsnprintf, estream_vasprintf): Take this in account. + + * estream.h (struct es__stream): Change FLAGS to a bit structure. + (ES__FLAG_WRITING): Replace by a bit from FLAGS. * estream.c + (struct estream_internal): Rename FLAGS to MODEFLAGS so that they + are not confused with the estream flags. + (es_initialize, es_create): Add arg MODEFLAGS so that we can setup + the intial writemode. Changed all callers to pass them. + (es_convert_mode): Set O_BINARY. + (es_func_fd_create, es_func_fp_create, es_func_file_create) [W32]: + Call setmode if requested. + +2007-06-24 Werner Koch + + * estream.c (do_fpopen, es_fpopen, es_fpopen_nc): New. + (es_func_fp_create, es_func_fp_read, es_func_fp_write) + (es_func_fp_seek, es_func_fp_destroy): New. + +2007-06-22 Werner Koch + + * estream.c (es_fdopen): Factored code out to.. + (do_fdopen): .. new. + (es_fdopen_nc): New. + (estream_cookie_fd): Add field NO_CLOSE. + (es_func_fd_create): Add arg NO_CLOSE and changed all callers. + (es_func_fd_destroy): Handle the new flag. + + * homedir.c (gnupg_libexecdir) [W32]: Factor code out to .. + (w32_rootdir): .. new. + (gnupg_sysconfdir, gnupg_libdir, gnupg_datadir) [W32]: Return + name based on w32_rootdir(). + 2007-06-21 Werner Koch * membuf.h (get_membuf_len): New. diff --git a/common/estream-printf.c b/common/estream-printf.c index fce56867c..76d346953 100644 --- a/common/estream-printf.c +++ b/common/estream-printf.c @@ -60,19 +60,20 @@ #endif #ifdef TEST # include -#endif -#ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE -#include _ESTREAM_PRINTF_EXTRA_INCLUDE +#else +# ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE +# include _ESTREAM_PRINTF_EXTRA_INCLUDE +# endif #endif #include "estream-printf.h" /* Allow redefinition of asprintf used malloc functions. */ -#ifdef _ESTREAM_PRINTF_MALLOC +#if defined(_ESTREAM_PRINTF_MALLOC) && !defined(TEST) #define my_printf_malloc(a) _ESTREAM_PRINTF_MALLOC((a)) #else #define my_printf_malloc(a) malloc((a)) #endif -#ifdef _ESTREAM_PRINTF_FREE +#if defined(_ESTREAM_PRINTF_FREE) && !defined(TEST) #define my_printf_free(a) _ESTREAM_PRINTF_FREE((a)) #else #define my_printf_free(a) free((a)) @@ -1329,7 +1330,7 @@ pr_bytes_so_far (estream_printf_out_t outfnc, void *outfncarg, /* Run the actual formatting. OUTFNC and OUTFNCARG are the output functions. FORMAT is format string ARGSPECS is the parsed format string, ARGSPECS_LEN the number of items in ARGSPECS. VALUETABLE - holds the values and may be directly addressed using the poistion + holds the values and may be directly addressed using the position arguments given by ARGSPECS. MYERRNO is used for the "%m" conversion. NBYTES well be updated to reflect the number of bytes send to the output function. */ @@ -1449,8 +1450,8 @@ do_format (estream_printf_out_t outfnc, void *outfncarg, } /* Print out any trailing stuff. */ - s++; /* Need to output a terminating nul; take it from format. */ - rc = outfnc (outfncarg, format, (n=s - format)); + n = s - format; + rc = n? outfnc (outfncarg, format, n) : 0; if (!rc) *nbytes += n; @@ -1619,10 +1620,8 @@ plain_stdio_out (void *outfncarg, const char *buf, size_t buflen) { FILE *fp = (FILE*)outfncarg; - fputs ("OUT->", fp); if ( fwrite (buf, buflen, 1, fp) != 1 ) return -1; - fputs ("<-\n", fp); return 0; } @@ -1715,6 +1714,8 @@ estream_vsnprintf (char *buf, size_t bufsize, parm.used = 0; parm.buffer = bufsize?buf:NULL; rc = estream_format (fixed_buffer_out, &parm, format, arg_ptr); + if (!rc) + rc = fixed_buffer_out (&parm, "", 1); /* Print terminating Nul. */ if (rc == -1) return -1; if (bufsize && buf && parm.count >= parm.size) @@ -1807,7 +1808,9 @@ estream_vasprintf (char **bufp, const char *format, va_list arg_ptr) } rc = estream_format (dynamic_buffer_out, &parm, format, arg_ptr); - + if (!rc) + rc = dynamic_buffer_out (&parm, "", 1); /* Print terminating Nul. */ + /* Fixme: Should we shrink the resulting buffer? */ if (rc != -1 && parm.error_flag) { rc = -1; @@ -1820,9 +1823,9 @@ estream_vasprintf (char **bufp, const char *format, va_list arg_ptr) *bufp = NULL; return -1; } - + assert (parm.used); /* We have at least the terminating Nul. */ *bufp = parm.buffer; - return parm.used - 1; /* Do not include the nul. */ + return parm.used - 1; /* Do not include that Nul. */ } /* A replacement for asprintf. As with the BSD of asprintf version -1 @@ -1891,8 +1894,7 @@ one_test (const char *format, ...) static void run_tests (void) { -#if 0 - one_test ("%d %% %'d", 17, 19681977); + /*one_test ("%d %% %'d", 17, 19681977);*/ one_test ("%d %% %d", 17, 768114563); one_test ("%d %% %d", 17, -768114563); @@ -2011,7 +2013,8 @@ run_tests (void) one_test ("%50s", "the quick brown fox jumps over the lazy dogs back"); one_test ("%51s", "the quick brown fox jumps over the lazy dogs back"); one_test ("%-51s", "the quick brown fox jumps over the lazy dogs back"); -#endif + + one_test ("/%s=", "CN"); one_test ("%f", 3.1415926535); one_test ("%f", -3.1415926535); diff --git a/common/estream.c b/common/estream.c index 131ddc232..5b953b5d2 100644 --- a/common/estream.c +++ b/common/estream.c @@ -67,6 +67,10 @@ void *memrchr (const void *block, int c, size_t size); +#ifndef O_BINARY +#define O_BINARY 0 +#endif + /* Generally used types. */ typedef void *(*func_realloc_t) (void *mem, size_t size); @@ -139,8 +143,6 @@ typedef void *estream_mutex_t; #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR) -#define ES_FLAG_WRITING ES__FLAG_WRITING - /* An internal stream object. */ struct estream_internal @@ -148,9 +150,9 @@ struct estream_internal unsigned char buffer[BUFFER_BLOCK_SIZE]; unsigned char unread_buffer[BUFFER_UNREAD_SIZE]; estream_mutex_t lock; /* Lock. */ - void *cookie; /* Cookie. */ - void *opaque; /* Opaque data. */ - unsigned int flags; /* Flags. */ + void *cookie; /* Cookie. */ + void *opaque; /* Opaque data. */ + unsigned int modeflags; /* Flags for the backend. */ off_t offset; es_cookie_read_function_t func_read; es_cookie_write_function_t func_write; @@ -325,7 +327,7 @@ es_init_do (void) /* Cookie for memory objects. */ typedef struct estream_cookie_mem { - unsigned int flags; /* Open flags. */ + unsigned int modeflags; /* Open flags. */ unsigned char *memory; /* Data. */ size_t memory_size; /* Size of MEMORY. */ size_t offset; /* Current offset in MEMORY. */ @@ -349,7 +351,7 @@ es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie, unsigned int append_zero, unsigned int dont_free, char **ptr, size_t *size, func_realloc_t func_realloc, func_free_t func_free, - unsigned int flags) + unsigned int modeflags) { estream_cookie_mem_t mem_cookie; int err; @@ -359,7 +361,7 @@ es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie, err = -1; else { - mem_cookie->flags = flags; + mem_cookie->modeflags = modeflags; mem_cookie->memory = data; mem_cookie->memory_size = data_n; mem_cookie->offset = 0; @@ -416,7 +418,7 @@ es_func_mem_write (void *cookie, const void *buffer, size_t size) { /* Regular write. */ - if (mem_cookie->flags & O_APPEND) + if (mem_cookie->modeflags & O_APPEND) /* Append to data. */ mem_cookie->offset = mem_cookie->data_len; @@ -593,17 +595,20 @@ static es_cookie_io_functions_t estream_functions_mem = es_func_mem_destroy }; + + /* Implementation of fd I/O. */ /* Cookie for fd objects. */ typedef struct estream_cookie_fd { - int fd; + int fd; /* The file descriptor we are using for actual output. */ + int no_close; /* If set we won't close the file descriptor. */ } *estream_cookie_fd_t; /* Create function for fd objects. */ static int -es_func_fd_create (void **cookie, int fd, unsigned int flags) +es_func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close) { estream_cookie_fd_t fd_cookie; int err; @@ -613,7 +618,13 @@ es_func_fd_create (void **cookie, int fd, unsigned int flags) err = -1; else { +#ifdef HAVE_DOSISH_SYSTEM + /* Make sure it is in binary mode if requested. */ + if ( (modeflags & O_BINARY) ) + setmode (fd, O_BINARY); +#endif fd_cookie->fd = fd; + fd_cookie->no_close = no_close; *cookie = fd_cookie; err = 0; } @@ -680,7 +691,7 @@ es_func_fd_destroy (void *cookie) if (fd_cookie) { - err = close (fd_cookie->fd); + err = fd_cookie->no_close? 0 : close (fd_cookie->fd); ES_MEM_FREE (fd_cookie); } else @@ -689,6 +700,7 @@ es_func_fd_destroy (void *cookie) return err; } + static es_cookie_io_functions_t estream_functions_fd = { es_func_fd_read, @@ -697,12 +709,132 @@ static es_cookie_io_functions_t estream_functions_fd = es_func_fd_destroy }; + + + +/* Implementation of FILE* I/O. */ + +/* Cookie for fp objects. */ +typedef struct estream_cookie_fp +{ + FILE *fp; /* The file pointer we are using for actual output. */ + int no_close; /* If set we won't close the file pointer. */ +} *estream_cookie_fp_t; + +/* Create function for fd objects. */ +static int +es_func_fp_create (void **cookie, FILE *fp, unsigned int modeflags, int no_close) +{ + estream_cookie_fp_t fp_cookie; + int err; + + fp_cookie = ES_MEM_ALLOC (sizeof *fp_cookie); + if (!fp_cookie) + err = -1; + else + { +#ifdef HAVE_DOSISH_SYSTEM + /* Make sure it is in binary mode if requested. */ + if ( (modeflags & O_BINARY) ) + setmode (fileno (fp), O_BINARY); +#endif + fp_cookie->fp = fp; + fp_cookie->no_close = no_close; + *cookie = fp_cookie; + err = 0; + } + + return err; +} + +/* Read function for FILE* objects. */ +static ssize_t +es_func_fp_read (void *cookie, void *buffer, size_t size) + +{ + estream_cookie_fp_t file_cookie = cookie; + ssize_t bytes_read; + + bytes_read = fread (buffer, 1, size, file_cookie->fp); + if (!bytes_read && ferror (file_cookie->fp)) + return -1; + return bytes_read; +} + +/* Write function for FILE* objects. */ +static ssize_t +es_func_fp_write (void *cookie, const void *buffer, size_t size) + +{ + estream_cookie_fp_t file_cookie = cookie; + size_t bytes_written; + + bytes_written = fwrite (buffer, 1, size, file_cookie->fp); + if (bytes_written != size) + return -1; + return bytes_written; +} + +/* Seek function for FILE* objects. */ +static int +es_func_fp_seek (void *cookie, off_t *offset, int whence) +{ + estream_cookie_fp_t file_cookie = cookie; + long int offset_new; + + if ( fseek (file_cookie->fp, (long int)*offset, whence) ) + { + fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno)); + return -1; + } + + offset_new = ftell (file_cookie->fp); + if (offset_new == -1) + { + fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno)); + return -1; + } + *offset = offset_new; + return 0; +} + +/* Destroy function for fd objects. */ +static int +es_func_fp_destroy (void *cookie) +{ + estream_cookie_fp_t fp_cookie = cookie; + int err; + + if (fp_cookie) + { + fflush (fp_cookie->fp); + err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp); + ES_MEM_FREE (fp_cookie); + } + else + err = 0; + + return err; +} + + +static es_cookie_io_functions_t estream_functions_fp = + { + es_func_fp_read, + es_func_fp_write, + es_func_fp_seek, + es_func_fp_destroy + }; + + + + /* Implementation of file I/O. */ /* Create function for file objects. */ static int es_func_file_create (void **cookie, int *filedes, - const char *path, unsigned int flags) + const char *path, unsigned int modeflags) { estream_cookie_fd_t file_cookie; int err; @@ -718,12 +850,17 @@ es_func_file_create (void **cookie, int *filedes, goto out; } - fd = open (path, flags, ES_DEFAULT_OPEN_MODE); + fd = open (path, modeflags, ES_DEFAULT_OPEN_MODE); if (fd == -1) { err = -1; goto out; } +#ifdef HAVE_DOSISH_SYSTEM + /* Make sure it is in binary mode if requested. */ + if ( (modeflags & O_BINARY) ) + setmode (fd, O_BINARY); +#endif file_cookie->fd = fd; *cookie = file_cookie; @@ -750,16 +887,10 @@ static es_cookie_io_functions_t estream_functions_file = /* Stream primitives. */ static int -es_convert_mode (const char *mode, unsigned int *flags) +es_convert_mode (const char *mode, unsigned int *modeflags) { - /* FIXME: We need to allow all mode flags permutations and for - binary mode we need to do a - - #ifdef HAVE_DOSISH_SYSTEM - setmode (fd, O_BINARY); - #endif - */ + /* FIXME: We need to allow all mode flags permutations. */ struct { const char *mode; @@ -767,33 +898,34 @@ es_convert_mode (const char *mode, unsigned int *flags) } mode_flags[] = { { "r", O_RDONLY }, { "rb", - O_RDONLY }, + O_RDONLY | O_BINARY }, { "w", O_WRONLY | O_TRUNC | O_CREAT }, { "wb", - O_WRONLY | O_TRUNC | O_CREAT }, + O_WRONLY | O_TRUNC | O_CREAT | O_BINARY }, { "a", O_WRONLY | O_APPEND | O_CREAT }, { "ab", - O_WRONLY | O_APPEND | O_CREAT }, + O_WRONLY | O_APPEND | O_CREAT | O_BINARY }, { "r+", O_RDWR }, { "rb+", - O_RDWR }, + O_RDWR | O_BINARY }, { "r+b", - O_RDONLY | O_WRONLY }, + O_RDONLY | O_WRONLY | O_BINARY }, { "w+", O_RDWR | O_TRUNC | O_CREAT }, { "wb+", - O_RDWR | O_TRUNC | O_CREAT }, + O_RDWR | O_TRUNC | O_CREAT | O_BINARY }, { "w+b", - O_RDWR | O_TRUNC | O_CREAT }, + O_RDWR | O_TRUNC | O_CREAT | O_BINARY }, { "a+", O_RDWR | O_CREAT | O_APPEND }, { "ab+", - O_RDWR | O_CREAT | O_APPEND }, + O_RDWR | O_CREAT | O_APPEND | O_BINARY }, { "a+b", - O_RDWR | O_CREAT | O_APPEND } }; + O_RDWR | O_CREAT | O_APPEND | O_BINARY } + }; unsigned int i; int err; @@ -808,7 +940,7 @@ es_convert_mode (const char *mode, unsigned int *flags) else { err = 0; - *flags = mode_flags[i].flags; + *modeflags = mode_flags[i].flags; } return err; @@ -868,7 +1000,7 @@ es_flush (estream_t stream) es_cookie_write_function_t func_write = stream->intern->func_write; int err; - assert (stream->flags & ES_FLAG_WRITING); + assert (stream->flags.writing); if (stream->data_offset) { @@ -935,7 +1067,7 @@ es_flush (estream_t stream) static void es_empty (estream_t stream) { - assert (! (stream->flags & ES_FLAG_WRITING)); + assert (!stream->flags.writing); stream->data_len = 0; stream->data_offset = 0; stream->unread_data_len = 0; @@ -944,7 +1076,8 @@ es_empty (estream_t stream) /* Initialize STREAM. */ static void es_initialize (estream_t stream, - void *cookie, int fd, es_cookie_io_functions_t functions) + void *cookie, int fd, es_cookie_io_functions_t functions, + unsigned int modeflags) { stream->intern->cookie = cookie; stream->intern->opaque = NULL; @@ -967,7 +1100,15 @@ es_initialize (estream_t stream, stream->data_offset = 0; stream->data_flushed = 0; stream->unread_data_len = 0; - stream->flags = 0; + /* Depending on the modeflags we set whether we start in writing or + reading mode. This is required in case we are working on a + wronly stream which is not seeekable (like stdout). Without this + pre-initialization we would do a seek at the first write call and + as this will fail no utput will be delivered. */ + if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) ) + stream->flags.writing = 1; + else + stream->flags.writing = 0; } /* Deinitialize STREAM. */ @@ -988,7 +1129,7 @@ es_deinitialize (estream_t stream) func_close = stream->intern->func_close; err = 0; - if (stream->flags & ES_FLAG_WRITING) + if (stream->flags.writing) SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream)); if (func_close) SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie)); @@ -1000,7 +1141,7 @@ es_deinitialize (estream_t stream) /* Create a new stream object, initialize it. */ static int es_create (estream_t *stream, void *cookie, int fd, - es_cookie_io_functions_t functions) + es_cookie_io_functions_t functions, unsigned int modeflags) { estream_internal_t stream_internal_new; estream_t stream_new; @@ -1030,7 +1171,7 @@ es_create (estream_t *stream, void *cookie, int fd, stream_new->intern = stream_internal_new; ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock); - es_initialize (stream_new, cookie, fd, functions); + es_initialize (stream_new, cookie, fd, functions, modeflags); err = es_list_add (stream_new); if (err) @@ -1186,13 +1327,13 @@ es_readn (estream_t ES__RESTRICT stream, data_read = 0; err = 0; - if (stream->flags & ES_FLAG_WRITING) + if (stream->flags.writing) { /* Switching to reading mode -> flush output. */ err = es_flush (stream); if (err) goto out; - stream->flags &= ~ES_FLAG_WRITING; + stream->flags.writing = 0; } /* Read unread data first. */ @@ -1274,14 +1415,14 @@ es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence, goto out; } - if (stream->flags & ES_FLAG_WRITING) + if (stream->flags.writing) { /* Flush data first in order to prevent flushing it to the wrong offset. */ err = es_flush (stream); if (err) goto out; - stream->flags &= ~ES_FLAG_WRITING; + stream->flags.writing = 0; } off = offset; @@ -1451,7 +1592,7 @@ es_writen (estream_t ES__RESTRICT stream, data_written = 0; err = 0; - if (! (stream->flags & ES_FLAG_WRITING)) + if (!stream->flags.writing) { /* Switching to writing mode -> discard input data and seek to position at which reading has stopped. We can do this only @@ -1489,8 +1630,8 @@ es_writen (estream_t ES__RESTRICT stream, if (bytes_written) *bytes_written = data_written; if (data_written) - if (! (stream->flags & ES_FLAG_WRITING)) - stream->flags |= ES_FLAG_WRITING; + if (!stream->flags.writing) + stream->flags.writing = 1; return err; } @@ -1502,13 +1643,13 @@ es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data, { int err; - if (stream->flags & ES_FLAG_WRITING) + if (stream->flags.writing) { /* Switching to reading mode -> flush output. */ err = es_flush (stream); if (err) goto out; - stream->flags &= ~ES_FLAG_WRITING; + stream->flags.writing = 0; } if (stream->data_offset == stream->data_len) @@ -1572,12 +1713,13 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length, line_stream_cookie = NULL; err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE, - 1, 0, 0, NULL, 0, ES_MEM_REALLOC, ES_MEM_FREE, O_RDWR); + 1, 0, 0, NULL, 0, ES_MEM_REALLOC, ES_MEM_FREE, + O_RDWR); if (err) goto out; err = es_create (&line_stream, line_stream_cookie, -1, - estream_functions_mem); + estream_functions_mem, O_RDWR); if (err) goto out; @@ -1738,7 +1880,7 @@ es_set_buffering (estream_t ES__RESTRICT stream, int err; /* Flush or empty buffer depending on mode. */ - if (stream->flags & ES_FLAG_WRITING) + if (stream->flags.writing) { err = es_flush (stream); if (err) @@ -1839,7 +1981,7 @@ es_init (void) estream_t es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode) { - unsigned int flags; + unsigned int modeflags; int create_called; estream_t stream; void *cookie; @@ -1850,16 +1992,16 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode) cookie = NULL; create_called = 0; - err = es_convert_mode (mode, &flags); + err = es_convert_mode (mode, &modeflags); if (err) goto out; - err = es_func_file_create (&cookie, &fd, path, flags); + err = es_func_file_create (&cookie, &fd, path, modeflags); if (err) goto out; create_called = 1; - err = es_create (&stream, cookie, fd, estream_functions_file); + err = es_create (&stream, cookie, fd, estream_functions_file, modeflags); if (err) goto out; @@ -1878,7 +2020,7 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len, func_realloc_t func_realloc, func_free_t func_free, const char *ES__RESTRICT mode) { - unsigned int flags; + unsigned int modeflags; int create_called; estream_t stream; void *cookie; @@ -1888,18 +2030,18 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len, stream = NULL; create_called = 0; - err = es_convert_mode (mode, &flags); + err = es_convert_mode (mode, &modeflags); if (err) goto out; err = es_func_mem_create (&cookie, data, data_n, data_len, BUFFER_BLOCK_SIZE, grow, 0, 0, - NULL, 0, func_realloc, func_free, flags); + NULL, 0, func_realloc, func_free, modeflags); if (err) goto out; create_called = 1; - err = es_create (&stream, cookie, -1, estream_functions_mem); + err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags); out: @@ -1913,25 +2055,25 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len, estream_t es_open_memstream (char **ptr, size_t *size) { - unsigned int flags; + unsigned int modeflags; int create_called; estream_t stream; void *cookie; int err; - flags = O_RDWR; + modeflags = O_RDWR; create_called = 0; stream = NULL; cookie = 0; err = es_func_mem_create (&cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE, 1, 1, 1, - ptr, size, ES_MEM_REALLOC, ES_MEM_FREE, flags); + ptr, size, ES_MEM_REALLOC, ES_MEM_FREE, modeflags); if (err) goto out; create_called = 1; - err = es_create (&stream, cookie, -1, estream_functions_mem); + err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags); out: @@ -1947,18 +2089,18 @@ es_fopencookie (void *ES__RESTRICT cookie, const char *ES__RESTRICT mode, es_cookie_io_functions_t functions) { - unsigned int flags; + unsigned int modeflags; estream_t stream; int err; stream = NULL; - flags = 0; + modeflags = 0; - err = es_convert_mode (mode, &flags); + err = es_convert_mode (mode, &modeflags); if (err) goto out; - err = es_create (&stream, cookie, -1, functions); + err = es_create (&stream, cookie, -1, functions, modeflags); if (err) goto out; @@ -1969,9 +2111,9 @@ es_fopencookie (void *ES__RESTRICT cookie, estream_t -es_fdopen (int filedes, const char *mode) +do_fdopen (int filedes, const char *mode, int no_close) { - unsigned int flags; + unsigned int modeflags; int create_called; estream_t stream; void *cookie; @@ -1981,16 +2123,16 @@ es_fdopen (int filedes, const char *mode) cookie = NULL; create_called = 0; - err = es_convert_mode (mode, &flags); + err = es_convert_mode (mode, &modeflags); if (err) goto out; - err = es_func_fd_create (&cookie, filedes, flags); + err = es_func_fd_create (&cookie, filedes, modeflags, no_close); if (err) goto out; create_called = 1; - err = es_create (&stream, cookie, filedes, estream_functions_fd); + err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags); out: @@ -1999,7 +2141,78 @@ es_fdopen (int filedes, const char *mode) return stream; } + +estream_t +es_fdopen (int filedes, const char *mode) +{ + return do_fdopen (filedes, mode, 0); +} + +/* A variant of es_fdopen which does not close FILEDES at the end. */ +estream_t +es_fdopen_nc (int filedes, const char *mode) +{ + return do_fdopen (filedes, mode, 1); +} + + +estream_t +do_fpopen (FILE *fp, const char *mode, int no_close) +{ + unsigned int modeflags; + int create_called; + estream_t stream; + void *cookie; + int err; + + stream = NULL; + cookie = NULL; + create_called = 0; + + err = es_convert_mode (mode, &modeflags); + if (err) + goto out; + + fflush (fp); + err = es_func_fp_create (&cookie, fp, modeflags, no_close); + if (err) + goto out; + + create_called = 1; + err = es_create (&stream, cookie, fileno (fp), estream_functions_fp, + modeflags); + + out: + + if (err && create_called) + (*estream_functions_fp.func_close) (cookie); + + return stream; +} + +/* Create an estream from the stdio stream FP. This mechanism is + useful in case the stdio streams have special properties and may + not be mixed with fd based functions. This is for example the case + under Windows where the 3 standard streams are associated with the + console whereas a duped and fd-opened stream of one of this stream + won't be associated with the console. As this messes things up it + is easier to keep on using the standard I/O stream as a backend for + estream. */ +estream_t +es_fpopen (FILE *fp, const char *mode) +{ + return do_fpopen (fp, mode, 0); +} + + +/* Same as es_fpopen but does not close FP at the end. */ +estream_t +es_fpopen_nc (FILE *fp, const char *mode) +{ + return do_fpopen (fp, mode, 1); +} + estream_t es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode, @@ -2009,7 +2222,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode, if (path) { - unsigned int flags; + unsigned int modeflags; int create_called; void *cookie; int fd; @@ -2021,16 +2234,16 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode, es_deinitialize (stream); - err = es_convert_mode (mode, &flags); + err = es_convert_mode (mode, &modeflags); if (err) goto leave; - err = es_func_file_create (&cookie, &fd, path, flags); + err = es_func_file_create (&cookie, &fd, path, modeflags); if (err) goto leave; create_called = 1; - es_initialize (stream, cookie, fd, estream_functions_file); + es_initialize (stream, cookie, fd, estream_functions_file, modeflags); leave: @@ -2173,7 +2386,7 @@ es_fflush (estream_t stream) if (stream) { ESTREAM_LOCK (stream); - if (stream->flags & ES_FLAG_WRITING) + if (stream->flags.writing) err = es_flush (stream); else { @@ -2686,7 +2899,7 @@ tmpfd (void) estream_t es_tmpfile (void) { - unsigned int flags; + unsigned int modeflags; int create_called; estream_t stream; void *cookie; @@ -2695,7 +2908,7 @@ es_tmpfile (void) create_called = 0; stream = NULL; - flags = O_RDWR | O_TRUNC | O_CREAT; + modeflags = O_RDWR | O_TRUNC | O_CREAT; cookie = NULL; fd = tmpfd (); @@ -2705,12 +2918,12 @@ es_tmpfile (void) goto out; } - err = es_func_fd_create (&cookie, fd, flags); + err = es_func_fd_create (&cookie, fd, modeflags, 0); if (err) goto out; create_called = 1; - err = es_create (&stream, cookie, fd, estream_functions_fd); + err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags); out: diff --git a/common/estream.h b/common/estream.h index b5694370e..79bfbb71b 100644 --- a/common/estream.h +++ b/common/estream.h @@ -45,6 +45,9 @@ #define es_mopen _ESTREAM_PREFIX(es_mopen) #define es_open_memstream _ESTREAM_PREFIX(es_open_memstream) #define es_fdopen _ESTREAM_PREFIX(es_fdopen) +#define es_fdopen_nc _ESTREAM_PREFIX(es_fdopen_nc) +#define es_fpopen _ESTREAM_PREFIX(es_fpopen) +#define es_fpopen_nc _ESTREAM_PREFIX(es_fpopen_nc) #define es_freopen _ESTREAM_PREFIX(es_freopen) #define es_fopencookie _ESTREAM_PREFIX(es_fopencookie) #define es_fclose _ESTREAM_PREFIX(es_fclose) @@ -136,8 +139,10 @@ struct es__stream size_t unread_data_len; /* Various flags. */ -#define ES__FLAG_WRITING (1 << 0) - unsigned int flags; + struct { + unsigned int writing: 1; + unsigned int reserved: 7; + } flags; /* A pointer to our internal data for this stream. */ struct estream_internal *intern; @@ -197,6 +202,9 @@ estream_t es_mopen (unsigned char *ES__RESTRICT data, const char *ES__RESTRICT mode); estream_t es_open_memstream (char **ptr, size_t *size); estream_t es_fdopen (int filedes, const char *mode); +estream_t es_fdopen_nc (int filedes, const char *mode); +estream_t es_fpopen (FILE *fp, const char *mode); +estream_t es_fpopen_nc (FILE *fp, const char *mode); estream_t es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode, estream_t ES__RESTRICT stream); @@ -232,14 +240,14 @@ int _es_getc_underflow (estream_t stream); int _es_putc_overflow (int c, estream_t stream); #define es_getc_unlocked(stream) \ - (((! ((stream)->flags & 1)) \ + (((!(stream)->flags.writing) \ && ((stream)->data_offset < (stream)->data_len) \ && (! (stream)->unread_data_len)) \ ? ((int) (stream)->buffer[((stream)->data_offset)++]) \ : _es_getc_underflow ((stream))) #define es_putc_unlocked(c, stream) \ - ((((stream)->flags & 1) \ + (((stream)->flags.writing \ && ((stream)->data_offset < (stream)->buffer_size) \ && (c != '\n')) \ ? ((int) ((stream)->buffer[((stream)->data_offset)++] = (c))) \ diff --git a/common/homedir.c b/common/homedir.c index 654c96bec..e0c511cc9 100644 --- a/common/homedir.c +++ b/common/homedir.c @@ -126,38 +126,10 @@ default_homedir (void) } -/* Return the name of the sysconfdir. This is a static string. This - function is required because under Windows we can't simply compile - it in. */ -const char * -gnupg_sysconfdir (void) -{ #ifdef HAVE_W32_SYSTEM -#warning get the sysconfdir from somewhere else - return GNUPG_SYSCONFDIR; -#else /*!HAVE_W32_SYSTEM*/ - return GNUPG_SYSCONFDIR; -#endif /*!HAVE_W32_SYSTEM*/ -} - - -const char * -gnupg_bindir (void) +static const char * +w32_rootdir (void) { -#ifdef HAVE_W32_SYSTEM - return gnupg_libexecdir (); -#else /*!HAVE_W32_SYSTEM*/ - return GNUPG_BINDIR; -#endif /*!HAVE_W32_SYSTEM*/ -} - - -/* Return the name of the libexec directory. The name is allocated in - a static area on the first use. This function won't fail. */ -const char * -gnupg_libexecdir (void) -{ -#ifdef HAVE_W32_SYSTEM static int got_dir; static char dir[MAX_PATH+5]; @@ -184,17 +156,75 @@ gnupg_libexecdir (void) if (*dir) return dir; /* Fallback to the hardwired value. */ + return GNUPG_LIBEXECDIR; +} #endif /*HAVE_W32_SYSTEM*/ + + + +/* Return the name of the sysconfdir. This is a static string. This + function is required because under Windows we can't simply compile + it in. */ +const char * +gnupg_sysconfdir (void) +{ +#ifdef HAVE_W32_SYSTEM + static char *name; + + if (!name) + { + const char *s1, *s2; + s1 = w32_rootdir (); + s2 = DIRSEP_S "etc" DIRSEP_S "gnupg"; + name = xmalloc (strlen (s1) + strlen (s2) + 1); + strcpy (stpcpy (name, s1), s2); + } + return name; +#else /*!HAVE_W32_SYSTEM*/ + return GNUPG_SYSCONFDIR; +#endif /*!HAVE_W32_SYSTEM*/ +} + + +const char * +gnupg_bindir (void) +{ +#ifdef HAVE_W32_SYSTEM + return w32_rootdir (); +#else /*!HAVE_W32_SYSTEM*/ + return GNUPG_BINDIR; +#endif /*!HAVE_W32_SYSTEM*/ +} + + +/* Return the name of the libexec directory. The name is allocated in + a static area on the first use. This function won't fail. */ +const char * +gnupg_libexecdir (void) +{ +#ifdef HAVE_W32_SYSTEM + return w32_rootdir (); +#else /*!HAVE_W32_SYSTEM*/ return GNUPG_LIBEXECDIR; +#endif /*!HAVE_W32_SYSTEM*/ } const char * gnupg_libdir (void) { #ifdef HAVE_W32_SYSTEM -#warning get the libdir from somewhere else - return GNUPG_LIBDIR; + static char *name; + + if (!name) + { + const char *s1, *s2; + s1 = w32_rootdir (); + s2 = DIRSEP_S "lib" DIRSEP_S "gnupg"; + name = xmalloc (strlen (s1) + strlen (s2) + 1); + strcpy (stpcpy (name, s1), s2); + } + return name; #else /*!HAVE_W32_SYSTEM*/ return GNUPG_LIBDIR; #endif /*!HAVE_W32_SYSTEM*/ @@ -204,8 +234,17 @@ const char * gnupg_datadir (void) { #ifdef HAVE_W32_SYSTEM -#warning get the datadir from somewhere else - return GNUPG_DATADIR; + static char *name; + + if (!name) + { + const char *s1, *s2; + s1 = w32_rootdir (); + s2 = DIRSEP_S "share" DIRSEP_S "gnupg"; + name = xmalloc (strlen (s1) + strlen (s2) + 1); + strcpy (stpcpy (name, s1), s2); + } + return name; #else /*!HAVE_W32_SYSTEM*/ return GNUPG_DATADIR; #endif /*!HAVE_W32_SYSTEM*/ diff --git a/common/iobuf.c b/common/iobuf.c index 40af196da..f395405f6 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -40,6 +40,7 @@ #endif /* __riscos__ */ #include "util.h" +#include "sysutils.h" #include "iobuf.h" /* The size of the internal buffers. @@ -2350,37 +2351,12 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer, return nbytes; } -/* This is the non iobuf specific function */ -int -iobuf_translate_file_handle (int fd, int for_write) -{ -#ifdef _WIN32 - { - int x; - - if (fd <= 2) - return fd; /* do not do this for error, stdin, stdout, stderr */ - - x = _open_osfhandle (fd, for_write ? 1 : 0); - if (x == -1) - log_error ("failed to translate osfhandle %p\n", (void *) fd); - else - { - /*log_info ("_open_osfhandle %p yields %d%s\n", - (void*)fd, x, for_write? " for writing":"" ); */ - fd = x; - } - } -#endif - return fd; -} - static int translate_file_handle (int fd, int for_write) { #ifdef _WIN32 #ifdef FILE_FILTER_USES_STDIO - fd = iobuf_translate_file_handle (fd, for_write); + fd = translate_sys2libc_fd (fd, for_write); #else { int x; diff --git a/common/iobuf.h b/common/iobuf.h index fa11f3905..f20ea28fa 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -136,8 +136,6 @@ const char *iobuf_get_fname (iobuf_t a); void iobuf_set_partial_block_mode (iobuf_t a, size_t len); -int iobuf_translate_file_handle (int fd, int for_write); - void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial); diff --git a/common/sysutils.c b/common/sysutils.c index ff1fe1ba4..a3fc8cb07 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -272,3 +272,32 @@ gnupg_sleep (unsigned int seconds) # endif #endif } + + +/* This function is a NOP for POSIX systems but required under Windows + as the file handles as returned by OS calls (like CreateFile) are + different from the libc file descriptors (like open). This function + translates system file handles to libc file handles. FOR_WRITE + gives the direction of the handle. */ +int +translate_sys2libc_fd (int fd, int for_write) +{ +#ifdef HAVE_W32_SYSTEM + int x; + + if (fd <= 2) + return fd; /* Do not do this for error, stdin, stdout, stderr. + (This also ignores an fd of -1.) */ + + x = _open_osfhandle (fd, for_write ? 1 : 0); + if (x == -1) + log_error ("failed to translate osfhandle %p\n", (void *) fd); + else + { +/* log_info ("_open_osfhandle %p yields %d%s\n", */ +/* (void*)fd, x, for_write? " for writing":"" ); */ + fd = x; + } +#endif /* HAVE_W32_SYSTEM */ + return fd; +} diff --git a/common/sysutils.h b/common/sysutils.h index 0e295f5d1..3ed702aa7 100644 --- a/common/sysutils.h +++ b/common/sysutils.h @@ -28,6 +28,7 @@ int enable_core_dumps (void); const unsigned char *get_session_marker (size_t *rlen); int check_permissions (const char *path,int extension,int checkonly); void gnupg_sleep (unsigned int seconds); +int translate_sys2libc_fd (int fd, int for_write); #ifdef HAVE_W32_SYSTEM diff --git a/doc/ChangeLog b/doc/ChangeLog index 27546e08f..7123c5d71 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2007-06-22 Werner Koch + + * gpg.texi (Operational GPG Commands): Describe the flags used by + --check-sigs. + 2007-06-21 Werner Koch * gpgsm.texi (Certificate Management): Changed description of diff --git a/doc/gpg.texi b/doc/gpg.texi index b46036e41..409320a7c 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -309,6 +309,14 @@ command "tsign"). @opindex check-sigs Same as @option{--list-sigs}, but the signatures are verified. +The status of the verification is indicated by a flag directly following +the "sig" tag (and thus before the flags described above for +@option{--list-sigs}). A "!" indicates that the signature has been +successfully verified, a "-" denotes a bad signature and a "%" is used +if an error occured while checking the signature (e.g. a non supported +algorithm). + + @item --fingerprint @opindex fingerprint List all keys (or the specified ones) along with their diff --git a/g10/ChangeLog b/g10/ChangeLog index e3db0f80f..2958c9fff 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,9 @@ +2007-06-25 Werner Koch + + * gpg.c (main): Replace iobuf_translate_file_handle by + translate_sys2libc_fd. + * gpgv.c (main): Ditto. + 2007-06-21 Werner Koch * main.h: Include util.h. diff --git a/g10/gpg.c b/g10/gpg.c index 44ea8048e..d1d79ea19 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -2161,19 +2161,19 @@ main (int argc, char **argv ) case oDebugLevel: debug_level = pargs.r.ret_str; break; case oStatusFD: - set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) ); + set_status_fd( translate_sys2libc_fd (pargs.r.ret_int, 1) ); break; case oStatusFile: set_status_fd ( open_info_file (pargs.r.ret_str, 1) ); break; case oAttributeFD: - set_attrib_fd(iobuf_translate_file_handle (pargs.r.ret_int, 1)); + set_attrib_fd(translate_sys2libc_fd (pargs.r.ret_int, 1)); break; case oAttributeFile: set_attrib_fd ( open_info_file (pargs.r.ret_str, 1) ); break; case oLoggerFD: - log_set_fd (iobuf_translate_file_handle (pargs.r.ret_int, 1)); + log_set_fd (translate_sys2libc_fd (pargs.r.ret_int, 1)); break; case oLoggerFile: logfile = pargs.r.ret_str; @@ -2437,14 +2437,14 @@ main (int argc, char **argv ) set_passphrase_from_string(pargs.r.ret_str); break; case oPasswdFD: - pwfd = iobuf_translate_file_handle (pargs.r.ret_int, 0); + pwfd = translate_sys2libc_fd (pargs.r.ret_int, 0); break; case oPasswdFile: pwfd = open_info_file (pargs.r.ret_str, 0); break; case oPasswdRepeat: opt.passwd_repeat=pargs.r.ret_int; break; case oCommandFD: - opt.command_fd = iobuf_translate_file_handle (pargs.r.ret_int, 0); + opt.command_fd = translate_sys2libc_fd (pargs.r.ret_int, 0); break; case oCommandFile: opt.command_fd = open_info_file (pargs.r.ret_str, 0); diff --git a/g10/gpgv.c b/g10/gpgv.c index 73f3be09b..f7cac3457 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -155,7 +155,7 @@ main( int argc, char **argv ) case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break; case oStatusFD: set_status_fd( pargs.r.ret_int ); break; case oLoggerFD: - log_set_fd (iobuf_translate_file_handle (pargs.r.ret_int, 1)); + log_set_fd (translate_sys2libc_fd (pargs.r.ret_int, 1)); break; case oHomedir: opt.homedir = pargs.r.ret_str; break; case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break; diff --git a/sm/ChangeLog b/sm/ChangeLog index 737a57d0c..a57af3cfb 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,13 @@ +2007-06-25 Werner Koch + + * gpgsm.c (check_special_filename): Use translate_sys2libc_fd and + add new arg FOR_WRITE. Change callers to pass new arg. + +2007-06-24 Werner Koch + + * gpgsm.c (open_es_fwrite): Avoid the dup by using the new + es_fdopen_nc(). + 2007-06-21 Werner Koch * certreqgen-ui.c: New. diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 4ffd8363e..bb30a63ec 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -573,8 +573,8 @@ proc_parameters (ctrl_t ctrl, if (rc) { r = get_parameter (para, pKEYTYPE, 0); - log_error (_("line %d: key generation failed: %s\n"), - r->lnr, gpg_strerror (rc)); + log_error (_("line %d: key generation failed: %s <%s>\n"), + r->lnr, gpg_strerror (rc), gpg_strsource (rc)); xfree (cardkeyid); return rc; } @@ -863,8 +863,8 @@ gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *in_stream, FILE *out_fp) rc = read_parameters (ctrl, in_fp, writer); if (rc) { - log_error ("error creating certificate request: %s\n", - gpg_strerror (rc)); + log_error ("error creating certificate request: %s <%s>\n", + gpg_strerror (rc), gpg_strsource (rc)); goto leave; } diff --git a/sm/gpgsm.c b/sm/gpgsm.c index ee6cf08cd..d3be015c7 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -481,7 +481,7 @@ static void set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ); static void emergency_cleanup (void); -static int check_special_filename (const char *fname); +static int check_special_filename (const char *fname, int for_write); static int open_read (const char *filename); static FILE *open_fwrite (const char *filename); static estream_t open_es_fwrite (const char *filename); @@ -1732,7 +1732,7 @@ gpgsm_init_default_ctrl (struct server_control_s *ctrl) /* Check whether the filename has the form "-&nnnn", where n is a non-zero number. Returns this number or -1 if it is not the case. */ static int -check_special_filename (const char *fname) +check_special_filename (const char *fname, int for_write) { if (allow_special_filenames && fname && *fname == '-' && fname[1] == '&' ) { @@ -1742,7 +1742,7 @@ check_special_filename (const char *fname) for (i=0; isdigit (fname[i]); i++ ) ; if ( !fname[i] ) - return atoi (fname); + return translate_sys2libc_fd (atoi (fname), for_write); } return -1; } @@ -1762,7 +1762,7 @@ open_read (const char *filename) set_binary (stdin); return 0; /* stdin */ } - fd = check_special_filename (filename); + fd = check_special_filename (filename, 0); if (fd != -1) return fd; fd = open (filename, O_RDONLY | O_BINARY); @@ -1790,7 +1790,7 @@ open_fwrite (const char *filename) return stdout; } - fd = check_special_filename (filename); + fd = check_special_filename (filename, 1); if (fd != -1) { fp = fdopen (dup (fd), "wb"); @@ -1825,14 +1825,14 @@ open_es_fwrite (const char *filename) if (filename[0] == '-' && !filename[1]) { fflush (stdout); - fp = es_fdopen (dup (fileno(stdout)), "wb"); + fp = es_fdopen_nc (fileno(stdout), "wb"); return fp; } - fd = check_special_filename (filename); + fd = check_special_filename (filename, 1); if (fd != -1) { - fp = es_fdopen (dup (fd), "wb"); + fp = es_fdopen_nc (fd, "wb"); if (!fp) { log_error ("es_fdopen(%d) failed: %s\n", fd, strerror (errno));