LCOV - code coverage report
Current view: top level - src - data.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 176 270 65.2 %
Date: 2018-11-15 08:49:49 Functions: 19 21 90.5 %

          Line data    Source code
       1             : /* data.c - An abstraction for data objects.
       2             :    Copyright (C) 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
       3             : 
       4             :    This file is part of GPGME.
       5             : 
       6             :    GPGME is free software; you can redistribute it and/or modify it
       7             :    under the terms of the GNU Lesser General Public License as
       8             :    published by the Free Software Foundation; either version 2.1 of
       9             :    the License, or (at your option) any later version.
      10             : 
      11             :    GPGME is distributed in the hope that it will be useful, but
      12             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :    Lesser General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU Lesser General Public
      17             :    License along with this program; if not, write to the Free Software
      18             :    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      19             :    02111-1307, USA.  */
      20             : 
      21             : #if HAVE_CONFIG_H
      22             : #include <config.h>
      23             : #endif
      24             : 
      25             : #include <stdlib.h>
      26             : #ifdef HAVE_UNISTD_H
      27             : # include <unistd.h>
      28             : #endif
      29             : #include <errno.h>
      30             : #include <string.h>
      31             : #include <assert.h>
      32             : 
      33             : #include "gpgme.h"
      34             : #include "data.h"
      35             : #include "util.h"
      36             : #include "ops.h"
      37             : #include "priv-io.h"
      38             : #include "debug.h"
      39             : 
      40             : 
      41             : /* The property table which has an entry for each active data object.
      42             :  * The data object itself uses an index into this table and the table
      43             :  * has a pointer back to the data object.  All access to that table is
      44             :  * controlled by the property_table_lock.
      45             :  *
      46             :  * We use a separate table instead of linking all data objects
      47             :  * together for faster locating properties of the data object using
      48             :  * the data objects serial number.  We use 64 bit for the serial
      49             :  * number which is good enough to create a new data object every
      50             :  * nanosecond for more than 500 years.  Thus no wrap around will ever
      51             :  * happen.
      52             :  */
      53             : struct property_s
      54             : {
      55             :   gpgme_data_t dh;   /* The data objcet or NULL if the slot is not used.  */
      56             :   uint64_t dserial;  /* The serial number of the data object.  */
      57             :   struct {
      58             :     unsigned int blankout : 1;  /* Void the held data.  */
      59             :   } flags;
      60             : };
      61             : typedef struct property_s *property_t;
      62             : 
      63             : static property_t property_table;
      64             : static unsigned int property_table_size;
      65             : DEFINE_STATIC_LOCK (property_table_lock);
      66             : #define PROPERTY_TABLE_ALLOCATION_CHUNK 32
      67             : 
      68             : 
      69             : 
      70             : /* Insert the newly created data object DH into the property table and
      71             :  * store the index of it at R_IDX.  An error code is returned on error
      72             :  * and the table is not changed.  */
      73             : static gpg_error_t
      74        1551 : insert_into_property_table (gpgme_data_t dh, unsigned int *r_idx)
      75             : {
      76             :   static uint64_t last_dserial;
      77             :   gpg_error_t err;
      78             :   unsigned int idx;
      79             : 
      80        1551 :   LOCK (property_table_lock);
      81        1551 :   if (!property_table)
      82             :     {
      83         109 :       property_table_size = PROPERTY_TABLE_ALLOCATION_CHUNK;
      84         109 :       property_table = calloc (property_table_size, sizeof *property_table);
      85         109 :       if (!property_table)
      86             :         {
      87           0 :           err = gpg_error_from_syserror ();
      88           0 :           goto leave;
      89             :         }
      90             :     }
      91             : 
      92             :   /* Find an empty slot.  */
      93        4513 :   for (idx = 0; idx < property_table_size; idx++)
      94        4512 :     if (!property_table[idx].dh)
      95        1550 :       break;
      96        1551 :   if (!(idx < property_table_size))
      97             :     {
      98             :       /* No empty slot found.  Enlarge the table.  */
      99             :       property_t newtbl;
     100             :       unsigned int newsize;
     101             : 
     102           1 :       newsize = property_table_size + PROPERTY_TABLE_ALLOCATION_CHUNK;;
     103           2 :       if ((newsize * sizeof *property_table)
     104           1 :           < (property_table_size * sizeof *property_table))
     105             :         {
     106           0 :           err = gpg_error (GPG_ERR_ENOMEM);
     107           0 :           goto leave;
     108             :         }
     109           1 :       newtbl = realloc (property_table, newsize * sizeof *property_table);
     110           1 :       if (!newtbl)
     111             :         {
     112           0 :           err = gpg_error_from_syserror ();
     113           0 :           goto leave;
     114             :         }
     115           1 :       property_table = newtbl;
     116          33 :       for (idx = property_table_size; idx < newsize; idx++)
     117          32 :         property_table[idx].dh = NULL;
     118           1 :       idx = property_table_size;
     119           1 :       property_table_size = newsize;
     120             :     }
     121             : 
     122             :   /* Slot found. */
     123        1551 :   property_table[idx].dh = dh;
     124        1551 :   property_table[idx].dserial = ++last_dserial;
     125        1551 :   memset (&property_table[idx].flags, 0, sizeof property_table[idx].flags);
     126        1551 :   *r_idx = idx;
     127        1551 :   err = 0;
     128             : 
     129             :  leave:
     130        1551 :   UNLOCK (property_table_lock);
     131        1551 :   return err;
     132             : }
     133             : 
     134             : 
     135             : /* Remove the data object at PROPIDX from the table.  DH is only used
     136             :  * for cross checking.  */
     137             : static void
     138        1489 : remove_from_property_table (gpgme_data_t dh, unsigned int propidx)
     139             : {
     140        1489 :   LOCK (property_table_lock);
     141        1490 :   assert (property_table);
     142        1490 :   assert (propidx < property_table_size);
     143        1490 :   assert (property_table[propidx].dh == dh);
     144        1490 :   property_table[propidx].dh = NULL;
     145        1490 :   UNLOCK (property_table_lock);
     146        1490 : }
     147             : 
     148             : 
     149             : /* Return the data object's serial number for handle DH.  This is a
     150             :  * unique serial number for each created data object.  */
     151             : uint64_t
     152          55 : _gpgme_data_get_dserial (gpgme_data_t dh)
     153             : {
     154             :   uint64_t dserial;
     155             :   unsigned int idx;
     156             : 
     157          55 :   if (!dh)
     158           0 :     return 0;
     159             : 
     160          55 :   idx = dh->propidx;
     161          55 :   LOCK (property_table_lock);
     162          55 :   assert (property_table);
     163          55 :   assert (idx < property_table_size);
     164          55 :   assert (property_table[idx].dh == dh);
     165          55 :   dserial = property_table[idx].dserial;
     166          55 :   UNLOCK (property_table_lock);
     167             : 
     168          55 :   return dserial;
     169             : }
     170             : 
     171             : 
     172             : /* Set an internal property of a data object.  The data object may
     173             :  * either be identified by the usual DH or by using the data serial
     174             :  * number DSERIAL.  */
     175             : gpg_error_t
     176           0 : _gpgme_data_set_prop (gpgme_data_t dh, uint64_t dserial,
     177             :                       data_prop_t name, int value)
     178             : {
     179           0 :   gpg_error_t err = 0;
     180             :   int idx;
     181           0 :   TRACE_BEG3 (DEBUG_DATA, "gpgme_data_set_prop", dh,
     182             :               "dserial=%llu %lu=%d",
     183             :               (unsigned long long)dserial,
     184             :               (unsigned long)name, value);
     185             : 
     186           0 :   LOCK (property_table_lock);
     187           0 :   if ((!dh && !dserial) || (dh && dserial))
     188             :     {
     189           0 :       err = gpg_error (GPG_ERR_INV_VALUE);
     190           0 :       goto leave;
     191             :     }
     192           0 :   if (dh) /* Lookup via handle.  */
     193             :     {
     194           0 :       idx = dh->propidx;
     195           0 :       assert (property_table);
     196           0 :       assert (idx < property_table_size);
     197           0 :       assert (property_table[idx].dh == dh);
     198             :     }
     199             :   else /* Lookup via DSERIAL.  */
     200             :     {
     201           0 :       if (!property_table)
     202             :         {
     203           0 :           err = gpg_error (GPG_ERR_NOT_FOUND);
     204           0 :           goto leave;
     205             :         }
     206           0 :       for (idx = 0; idx < property_table_size; idx++)
     207           0 :         if (property_table[idx].dh && property_table[idx].dserial == dserial)
     208           0 :           break;
     209           0 :       if (!(idx < property_table_size))
     210             :         {
     211           0 :           err = gpg_error (GPG_ERR_NOT_FOUND);
     212           0 :           goto leave;
     213             :         }
     214             :     }
     215             : 
     216           0 :   switch (name)
     217             :     {
     218             :     case DATA_PROP_NONE: /* Nothing to to do.  */
     219           0 :       break;
     220             :     case DATA_PROP_BLANKOUT:
     221           0 :       property_table[idx].flags.blankout = !!value;
     222           0 :       break;
     223             : 
     224             :     default:
     225           0 :       err = gpg_error (GPG_ERR_UNKNOWN_NAME);
     226           0 :       break;
     227             :     }
     228             : 
     229             :  leave:
     230           0 :   UNLOCK (property_table_lock);
     231           0 :   return TRACE_ERR (err);
     232             : }
     233             : 
     234             : 
     235             : /* Get an internal property of a data object.  This is the counter
     236             :  * part to _gpgme_data_set_property.  The value of the property is
     237             :  * stored at R_VALUE.  On error 0 is stored at R_VALUE.  */
     238             : gpg_error_t
     239        1646 : _gpgme_data_get_prop (gpgme_data_t dh, uint64_t dserial,
     240             :                       data_prop_t name, int *r_value)
     241             : {
     242        1646 :   gpg_error_t err = 0;
     243             :   int idx;
     244        1646 :   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_get_prop", dh,
     245             :               "dserial=%llu %lu",
     246             :               (unsigned long long)dserial,
     247             :               (unsigned long)name);
     248             : 
     249        1646 :   *r_value = 0;
     250             : 
     251        1646 :   LOCK (property_table_lock);
     252        1646 :   if ((!dh && !dserial) || (dh && dserial))
     253             :     {
     254           0 :       err = gpg_error (GPG_ERR_INV_VALUE);
     255           0 :       goto leave;
     256             :     }
     257        1646 :   if (dh) /* Lookup via handle.  */
     258             :     {
     259        1646 :       idx = dh->propidx;
     260        1646 :       assert (property_table);
     261        1646 :       assert (idx < property_table_size);
     262        1646 :       assert (property_table[idx].dh == dh);
     263             :     }
     264             :   else /* Lookup via DSERIAL.  */
     265             :     {
     266           0 :       if (!property_table)
     267             :         {
     268           0 :           err = gpg_error (GPG_ERR_NOT_FOUND);
     269           0 :           goto leave;
     270             :         }
     271           0 :       for (idx = 0; idx < property_table_size; idx++)
     272           0 :         if (property_table[idx].dh && property_table[idx].dserial == dserial)
     273           0 :           break;
     274           0 :       if (!(idx < property_table_size))
     275             :         {
     276           0 :           err = gpg_error (GPG_ERR_NOT_FOUND);
     277           0 :           goto leave;
     278             :         }
     279             :     }
     280             : 
     281        1646 :   switch (name)
     282             :     {
     283             :     case DATA_PROP_NONE: /* Nothing to to do.  */
     284           0 :       break;
     285             :     case DATA_PROP_BLANKOUT:
     286        1646 :       *r_value = property_table[idx].flags.blankout;
     287        1646 :       break;
     288             : 
     289             :     default:
     290           0 :       err = gpg_error (GPG_ERR_UNKNOWN_NAME);
     291           0 :       break;
     292             :     }
     293             : 
     294             :  leave:
     295        1646 :   UNLOCK (property_table_lock);
     296        1646 :   return TRACE_ERR (err);
     297             : }
     298             : 
     299             : 
     300             : 
     301             : gpgme_error_t
     302        1552 : _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
     303             : {
     304             :   gpgme_error_t err;
     305             :   gpgme_data_t dh;
     306             : 
     307        1552 :   if (!r_dh)
     308           1 :     return gpg_error (GPG_ERR_INV_VALUE);
     309             : 
     310        1551 :   *r_dh = NULL;
     311             : 
     312        1551 :   if (_gpgme_selftest)
     313           0 :     return _gpgme_selftest;
     314             : 
     315        1551 :   dh = calloc (1, sizeof (*dh));
     316        1551 :   if (!dh)
     317           0 :     return gpg_error_from_syserror ();
     318             : 
     319        1551 :   dh->cbs = cbs;
     320             : 
     321        1551 :   err = insert_into_property_table (dh, &dh->propidx);
     322        1551 :   if (err)
     323             :     {
     324           0 :       free (dh);
     325           0 :       return err;
     326             :     }
     327             : 
     328        1551 :   *r_dh = dh;
     329        1551 :   return 0;
     330             : }
     331             : 
     332             : 
     333             : void
     334        1489 : _gpgme_data_release (gpgme_data_t dh)
     335             : {
     336        1489 :   if (!dh)
     337           0 :     return;
     338             : 
     339        1489 :   remove_from_property_table (dh, dh->propidx);
     340        1490 :   if (dh->file_name)
     341           6 :     free (dh->file_name);
     342        1490 :   free (dh);
     343             : }
     344             : 
     345             : 
     346             : 
     347             : /* Read up to SIZE bytes into buffer BUFFER from the data object with
     348             :    the handle DH.  Return the number of characters read, 0 on EOF and
     349             :    -1 on error.  If an error occurs, errno is set.  */
     350             : gpgme_ssize_t
     351        1617 : gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
     352             : {
     353             :   gpgme_ssize_t res;
     354             :   int blankout;
     355        1617 :   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh,
     356             :               "buffer=%p, size=%u", buffer, size);
     357             : 
     358        1617 :   if (!dh)
     359             :     {
     360           0 :       gpg_err_set_errno (EINVAL);
     361           0 :       return TRACE_SYSRES (-1);
     362             :     }
     363        1617 :   if (!dh->cbs->read)
     364             :     {
     365           0 :       gpg_err_set_errno (ENOSYS);
     366           0 :       return TRACE_SYSRES (-1);
     367             :     }
     368             : 
     369        1617 :   if (_gpgme_data_get_prop (dh, 0, DATA_PROP_BLANKOUT, &blankout)
     370        1617 :       || blankout)
     371           0 :     res = 0;
     372             :   else
     373             :     {
     374             :       do
     375        1617 :         res = (*dh->cbs->read) (dh, buffer, size);
     376        1617 :       while (res < 0 && errno == EINTR);
     377             :     }
     378             : 
     379        1617 :   return TRACE_SYSRES (res);
     380             : }
     381             : 
     382             : 
     383             : /* Write up to SIZE bytes from buffer BUFFER to the data object with
     384             :    the handle DH.  Return the number of characters written, or -1 on
     385             :    error.  If an error occurs, errno is set.  */
     386             : gpgme_ssize_t
     387        1934 : gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
     388             : {
     389             :   gpgme_ssize_t res;
     390        1934 :   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_write", dh,
     391             :               "buffer=%p, size=%u", buffer, size);
     392             : 
     393        1933 :   if (!dh)
     394             :     {
     395           0 :       gpg_err_set_errno (EINVAL);
     396           0 :       return TRACE_SYSRES (-1);
     397             :     }
     398        1933 :   if (!dh->cbs->write)
     399             :     {
     400           0 :       gpg_err_set_errno (ENOSYS);
     401           0 :       return TRACE_SYSRES (-1);
     402             :     }
     403             :   do
     404        1933 :     res = (*dh->cbs->write) (dh, buffer, size);
     405        1933 :   while (res < 0 && errno == EINTR);
     406             : 
     407        1933 :   return TRACE_SYSRES (res);
     408             : }
     409             : 
     410             : 
     411             : /* Set the current position from where the next read or write starts
     412             :    in the data object with the handle DH to OFFSET, relative to
     413             :    WHENCE.  */
     414             : gpgme_off_t
     415         435 : gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
     416             : {
     417         435 :   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_seek", dh,
     418             :               "offset=%lli, whence=%i", offset, whence);
     419             : 
     420         435 :   if (!dh)
     421             :     {
     422           0 :       gpg_err_set_errno (EINVAL);
     423           0 :       return TRACE_SYSRES (-1);
     424             :     }
     425         435 :   if (!dh->cbs->seek)
     426             :     {
     427           0 :       gpg_err_set_errno (ENOSYS);
     428           0 :       return TRACE_SYSRES (-1);
     429             :     }
     430             : 
     431             :   /* For relative movement, we must take into account the actual
     432             :      position of the read counter.  */
     433         435 :   if (whence == SEEK_CUR)
     434           0 :     offset -= dh->pending_len;
     435             : 
     436         435 :   offset = (*dh->cbs->seek) (dh, offset, whence);
     437         435 :   if (offset >= 0)
     438         431 :     dh->pending_len = 0;
     439             : 
     440         435 :   return TRACE_SYSRES (offset);
     441             : }
     442             : 
     443             : 
     444             : /* Convenience function to do a gpgme_data_seek (dh, 0, SEEK_SET).  */
     445             : gpgme_error_t
     446          61 : gpgme_data_rewind (gpgme_data_t dh)
     447             : {
     448             :   gpgme_error_t err;
     449          61 :   TRACE_BEG (DEBUG_DATA, "gpgme_data_rewind", dh);
     450             : 
     451         122 :   err = ((gpgme_data_seek (dh, 0, SEEK_SET) == -1)
     452          61 :          ? gpg_error_from_syserror () : 0);
     453             : 
     454          61 :   return TRACE_ERR (err);
     455             : }
     456             : 
     457             : 
     458             : /* Release the data object with the handle DH.  */
     459             : void
     460        2240 : gpgme_data_release (gpgme_data_t dh)
     461             : {
     462        2240 :   TRACE (DEBUG_DATA, "gpgme_data_release", dh);
     463             : 
     464        2241 :   if (!dh)
     465         751 :     return;
     466             : 
     467        1490 :   if (dh->cbs->release)
     468        1470 :     (*dh->cbs->release) (dh);
     469        1490 :   _gpgme_data_release (dh);
     470             : }
     471             : 
     472             : 
     473             : /* Get the current encoding meta information for the data object with
     474             :    handle DH.  */
     475             : gpgme_data_encoding_t
     476         144 : gpgme_data_get_encoding (gpgme_data_t dh)
     477             : {
     478         144 :   TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh,
     479             :           "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
     480         144 :   return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
     481             : }
     482             : 
     483             : 
     484             : /* Set the encoding meta information for the data object with handle
     485             :    DH to ENC.  */
     486             : gpgme_error_t
     487           0 : gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
     488             : {
     489           0 :   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_encoding", dh,
     490             :               "encoding=%i", enc);
     491           0 :   if (!dh)
     492           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     493           0 :   if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
     494           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     495           0 :   dh->encoding = enc;
     496           0 :   return TRACE_ERR (0);
     497             : }
     498             : 
     499             : 
     500             : /* Set the file name associated with the data object with handle DH to
     501             :    FILE_NAME.  */
     502             : gpgme_error_t
     503           6 : gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
     504             : {
     505           6 :   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh,
     506             :               "file_name=%s", file_name);
     507             : 
     508           6 :   if (!dh)
     509           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     510             : 
     511           6 :   if (dh->file_name)
     512           0 :     free (dh->file_name);
     513             : 
     514           6 :   if (file_name)
     515             :     {
     516           6 :       dh->file_name = strdup (file_name);
     517           6 :       if (!dh->file_name)
     518           0 :         return TRACE_ERR (gpg_error_from_syserror ());
     519             :     }
     520             :   else
     521           0 :     dh->file_name = 0;
     522             : 
     523           6 :   return TRACE_ERR (0);
     524             : }
     525             : 
     526             : 
     527             : /* Get the file name associated with the data object with handle DH,
     528             :    or NULL if there is none.  */
     529             : char *
     530         135 : gpgme_data_get_file_name (gpgme_data_t dh)
     531             : {
     532         135 :   if (!dh)
     533             :     {
     534           0 :       TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh);
     535           0 :       return NULL;
     536             :     }
     537             : 
     538         135 :   TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh,
     539             :           "dh->file_name=%s", dh->file_name);
     540         135 :   return dh->file_name;
     541             : }
     542             : 
     543             : 
     544             : /* Set a flag for the data object DH.  See the manual for details.  */
     545             : gpg_error_t
     546          88 : gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
     547             : {
     548          88 :   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_set_flag", dh,
     549             :               "%s=%s", name, value);
     550             : 
     551          88 :   if (!dh)
     552           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     553             : 
     554          88 :   if (!strcmp (name, "size-hint"))
     555             :     {
     556          88 :       dh->size_hint= value? _gpgme_string_to_off (value) : 0;
     557             :     }
     558             :   else
     559           0 :     return gpg_error (GPG_ERR_UNKNOWN_NAME);
     560             : 
     561          88 :   return 0;
     562             : }
     563             : 
     564             : 
     565             : 
     566             : /* Functions to support the wait interface.  */
     567             : 
     568             : gpgme_error_t
     569        2307 : _gpgme_data_inbound_handler (void *opaque, int fd)
     570             : {
     571        2307 :   struct io_cb_data *data = (struct io_cb_data *) opaque;
     572        2307 :   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
     573             :   char buffer[BUFFER_SIZE];
     574        2307 :   char *bufp = buffer;
     575             :   gpgme_ssize_t buflen;
     576        2307 :   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
     577             :               "fd=0x%x", fd);
     578             : 
     579        2307 :   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
     580        2307 :   if (buflen < 0)
     581           0 :     return gpg_error_from_syserror ();
     582        2307 :   if (buflen == 0)
     583             :     {
     584         983 :       _gpgme_io_close (fd);
     585         983 :       return TRACE_ERR (0);
     586             :     }
     587             : 
     588             :   do
     589             :     {
     590        1324 :       gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
     591        1320 :       if (amt == 0 || (amt < 0 && errno != EINTR))
     592           0 :         return TRACE_ERR (gpg_error_from_syserror ());
     593        1322 :       bufp += amt;
     594        1322 :       buflen -= amt;
     595             :     }
     596        1322 :   while (buflen > 0);
     597        1322 :   return TRACE_ERR (0);
     598             : }
     599             : 
     600             : 
     601             : gpgme_error_t
     602         975 : _gpgme_data_outbound_handler (void *opaque, int fd)
     603             : {
     604         975 :   struct io_cb_data *data = (struct io_cb_data *) opaque;
     605         975 :   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
     606             :   gpgme_ssize_t nwritten;
     607         975 :   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
     608             :               "fd=0x%x", fd);
     609             : 
     610         975 :   if (!dh->pending_len)
     611             :     {
     612         975 :       gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
     613         975 :       if (amt < 0)
     614           0 :         return TRACE_ERR (gpg_error_from_syserror ());
     615         975 :       if (amt == 0)
     616             :         {
     617         322 :           _gpgme_io_close (fd);
     618         322 :           return TRACE_ERR (0);
     619             :         }
     620         653 :       dh->pending_len = amt;
     621             :     }
     622             : 
     623         653 :   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
     624         653 :   if (nwritten == -1 && errno == EAGAIN)
     625           0 :     return TRACE_ERR (0);
     626             : 
     627         653 :   if (nwritten == -1 && errno == EPIPE)
     628             :     {
     629             :       /* Not much we can do.  The other end closed the pipe, but we
     630             :          still have data.  This should only ever happen if the other
     631             :          end is going to tell us what happened on some other channel.
     632             :          Silently close our end.  */
     633           0 :       _gpgme_io_close (fd);
     634           0 :       return TRACE_ERR (0);
     635             :     }
     636             : 
     637         653 :   if (nwritten <= 0)
     638           0 :     return TRACE_ERR (gpg_error_from_syserror ());
     639             : 
     640         653 :   if (nwritten < dh->pending_len)
     641           0 :     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
     642         653 :   dh->pending_len -= nwritten;
     643         653 :   return TRACE_ERR (0);
     644             : }
     645             : 
     646             : 
     647             : /* Get the file descriptor associated with DH, if possible.  Otherwise
     648             :    return -1.  */
     649             : int
     650          18 : _gpgme_data_get_fd (gpgme_data_t dh)
     651             : {
     652          18 :   if (!dh || !dh->cbs->get_fd)
     653          18 :     return -1;
     654           0 :   return (*dh->cbs->get_fd) (dh);
     655             : }
     656             : 
     657             : 
     658             : /* Get the size-hint value for DH or 0 if not available.  */
     659             : gpgme_off_t
     660         242 : _gpgme_data_get_size_hint (gpgme_data_t dh)
     661             : {
     662         242 :   return dh ? dh->size_hint : 0;
     663             : }

Generated by: LCOV version 1.13