70595907db3bad1b1c6ba2abdffc582753d1bd7f
[platform/upstream/gpgme.git] / src / data.c
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, see <https://gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1-or-later
19  */
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 \f
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 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   LOCK (property_table_lock);
81   if (!property_table)
82     {
83       property_table_size = PROPERTY_TABLE_ALLOCATION_CHUNK;
84       property_table = calloc (property_table_size, sizeof *property_table);
85       if (!property_table)
86         {
87           err = gpg_error_from_syserror ();
88           goto leave;
89         }
90     }
91
92   /* Find an empty slot.  */
93   for (idx = 0; idx < property_table_size; idx++)
94     if (!property_table[idx].dh)
95       break;
96   if (!(idx < property_table_size))
97     {
98       /* No empty slot found.  Enlarge the table.  */
99       property_t newtbl;
100       unsigned int newsize;
101
102       newsize = property_table_size + PROPERTY_TABLE_ALLOCATION_CHUNK;;
103       if ((newsize * sizeof *property_table)
104           < (property_table_size * sizeof *property_table))
105         {
106           err = gpg_error (GPG_ERR_ENOMEM);
107           goto leave;
108         }
109       newtbl = realloc (property_table, newsize * sizeof *property_table);
110       if (!newtbl)
111         {
112           err = gpg_error_from_syserror ();
113           goto leave;
114         }
115       property_table = newtbl;
116       for (idx = property_table_size; idx < newsize; idx++)
117         property_table[idx].dh = NULL;
118       idx = property_table_size;
119       property_table_size = newsize;
120     }
121
122   /* Slot found. */
123   property_table[idx].dh = dh;
124   property_table[idx].dserial = ++last_dserial;
125   memset (&property_table[idx].flags, 0, sizeof property_table[idx].flags);
126   *r_idx = idx;
127   err = 0;
128
129  leave:
130   UNLOCK (property_table_lock);
131   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 remove_from_property_table (gpgme_data_t dh, unsigned int propidx)
139 {
140   LOCK (property_table_lock);
141   assert (property_table);
142   assert (propidx < property_table_size);
143   assert (property_table[propidx].dh == dh);
144   property_table[propidx].dh = NULL;
145   UNLOCK (property_table_lock);
146 }
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 _gpgme_data_get_dserial (gpgme_data_t dh)
153 {
154   uint64_t dserial;
155   unsigned int idx;
156
157   if (!dh)
158     return 0;
159
160   idx = dh->propidx;
161   LOCK (property_table_lock);
162   assert (property_table);
163   assert (idx < property_table_size);
164   assert (property_table[idx].dh == dh);
165   dserial = property_table[idx].dserial;
166   UNLOCK (property_table_lock);
167
168   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 _gpgme_data_set_prop (gpgme_data_t dh, uint64_t dserial,
177                       data_prop_t name, int value)
178 {
179   gpg_error_t err = 0;
180   int idx;
181   TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_prop", dh,
182               "dserial=%llu %lu=%d",
183               (unsigned long long)dserial,
184               (unsigned long)name, value);
185
186   LOCK (property_table_lock);
187   if ((!dh && !dserial) || (dh && dserial))
188     {
189       err = gpg_error (GPG_ERR_INV_VALUE);
190       goto leave;
191     }
192   if (dh) /* Lookup via handle.  */
193     {
194       idx = dh->propidx;
195       assert (property_table);
196       assert (idx < property_table_size);
197       assert (property_table[idx].dh == dh);
198     }
199   else /* Lookup via DSERIAL.  */
200     {
201       if (!property_table)
202         {
203           err = gpg_error (GPG_ERR_NOT_FOUND);
204           goto leave;
205         }
206       for (idx = 0; idx < property_table_size; idx++)
207         if (property_table[idx].dh && property_table[idx].dserial == dserial)
208           break;
209       if (!(idx < property_table_size))
210         {
211           err = gpg_error (GPG_ERR_NOT_FOUND);
212           goto leave;
213         }
214     }
215
216   switch (name)
217     {
218     case DATA_PROP_NONE: /* Nothing to to do.  */
219       break;
220     case DATA_PROP_BLANKOUT:
221       property_table[idx].flags.blankout = !!value;
222       break;
223
224     default:
225       err = gpg_error (GPG_ERR_UNKNOWN_NAME);
226       break;
227     }
228
229  leave:
230   UNLOCK (property_table_lock);
231   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 _gpgme_data_get_prop (gpgme_data_t dh, uint64_t dserial,
240                       data_prop_t name, int *r_value)
241 {
242   gpg_error_t err = 0;
243   int idx;
244   TRACE_BEG  (DEBUG_DATA, "gpgme_data_get_prop", dh,
245               "dserial=%llu %lu",
246               (unsigned long long)dserial,
247               (unsigned long)name);
248
249   *r_value = 0;
250
251   LOCK (property_table_lock);
252   if ((!dh && !dserial) || (dh && dserial))
253     {
254       err = gpg_error (GPG_ERR_INV_VALUE);
255       goto leave;
256     }
257   if (dh) /* Lookup via handle.  */
258     {
259       idx = dh->propidx;
260       assert (property_table);
261       assert (idx < property_table_size);
262       assert (property_table[idx].dh == dh);
263     }
264   else /* Lookup via DSERIAL.  */
265     {
266       if (!property_table)
267         {
268           err = gpg_error (GPG_ERR_NOT_FOUND);
269           goto leave;
270         }
271       for (idx = 0; idx < property_table_size; idx++)
272         if (property_table[idx].dh && property_table[idx].dserial == dserial)
273           break;
274       if (!(idx < property_table_size))
275         {
276           err = gpg_error (GPG_ERR_NOT_FOUND);
277           goto leave;
278         }
279     }
280
281   switch (name)
282     {
283     case DATA_PROP_NONE: /* Nothing to to do.  */
284       break;
285     case DATA_PROP_BLANKOUT:
286       *r_value = property_table[idx].flags.blankout;
287       break;
288
289     default:
290       err = gpg_error (GPG_ERR_UNKNOWN_NAME);
291       break;
292     }
293
294  leave:
295   UNLOCK (property_table_lock);
296   return TRACE_ERR (err);
297 }
298
299
300 \f
301 gpgme_error_t
302 _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   if (!r_dh)
308     return gpg_error (GPG_ERR_INV_VALUE);
309
310   *r_dh = NULL;
311
312   if (_gpgme_selftest)
313     return _gpgme_selftest;
314
315   dh = calloc (1, sizeof (*dh));
316   if (!dh)
317     return gpg_error_from_syserror ();
318
319   dh->cbs = cbs;
320
321   err = insert_into_property_table (dh, &dh->propidx);
322   if (err)
323     {
324       free (dh);
325       return err;
326     }
327
328   *r_dh = dh;
329   return 0;
330 }
331
332
333 void
334 _gpgme_data_release (gpgme_data_t dh)
335 {
336   if (!dh)
337     return;
338
339   remove_from_property_table (dh, dh->propidx);
340   if (dh->file_name)
341     free (dh->file_name);
342   free (dh);
343 }
344
345
346 \f
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 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
352 {
353   gpgme_ssize_t res;
354   int blankout;
355   TRACE_BEG  (DEBUG_DATA, "gpgme_data_read", dh,
356               "buffer=%p, size=%zu", buffer, size);
357
358   if (!dh)
359     {
360       gpg_err_set_errno (EINVAL);
361       return TRACE_SYSRES (-1);
362     }
363   if (!dh->cbs->read)
364     {
365       gpg_err_set_errno (ENOSYS);
366       return TRACE_SYSRES (-1);
367     }
368
369   if (_gpgme_data_get_prop (dh, 0, DATA_PROP_BLANKOUT, &blankout)
370       || blankout)
371     res = 0;
372   else
373     {
374       do
375         res = (*dh->cbs->read) (dh, buffer, size);
376       while (res < 0 && errno == EINTR);
377     }
378
379   return TRACE_SYSRES ((int)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 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
388 {
389   gpgme_ssize_t res;
390   TRACE_BEG  (DEBUG_DATA, "gpgme_data_write", dh,
391               "buffer=%p, size=%zu", buffer, size);
392
393   if (!dh)
394     {
395       gpg_err_set_errno (EINVAL);
396       return TRACE_SYSRES (-1);
397     }
398   if (!dh->cbs->write)
399     {
400       gpg_err_set_errno (ENOSYS);
401       return TRACE_SYSRES (-1);
402     }
403   do
404     res = (*dh->cbs->write) (dh, buffer, size);
405   while (res < 0 && errno == EINTR);
406
407   return TRACE_SYSRES ((int)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 gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
416 {
417   TRACE_BEG  (DEBUG_DATA, "gpgme_data_seek", dh,
418               "offset=%lli, whence=%i", (long long int)offset, whence);
419
420   if (!dh)
421     {
422       gpg_err_set_errno (EINVAL);
423       return TRACE_SYSRES (-1);
424     }
425   if (!dh->cbs->seek)
426     {
427       gpg_err_set_errno (ENOSYS);
428       return TRACE_SYSRES (-1);
429     }
430
431   /* For relative movement, we must take into account the actual
432      position of the read counter.  */
433   if (whence == SEEK_CUR)
434     offset -= dh->pending_len;
435
436   offset = (*dh->cbs->seek) (dh, offset, whence);
437   if (offset >= 0)
438     dh->pending_len = 0;
439
440   return TRACE_SYSRES ((int)offset);
441 }
442
443
444 /* Convenience function to do a gpgme_data_seek (dh, 0, SEEK_SET).  */
445 gpgme_error_t
446 gpgme_data_rewind (gpgme_data_t dh)
447 {
448   gpgme_error_t err;
449   TRACE_BEG  (DEBUG_DATA, "gpgme_data_rewind", dh, "");
450
451   err = ((gpgme_data_seek (dh, 0, SEEK_SET) == -1)
452          ? gpg_error_from_syserror () : 0);
453
454   return TRACE_ERR (err);
455 }
456
457
458 /* Release the data object with the handle DH.  */
459 void
460 gpgme_data_release (gpgme_data_t dh)
461 {
462   TRACE (DEBUG_DATA, "gpgme_data_release", dh, "");
463
464   if (!dh)
465     return;
466
467   if (dh->cbs->release)
468     (*dh->cbs->release) (dh);
469   _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 gpgme_data_get_encoding (gpgme_data_t dh)
477 {
478   TRACE (DEBUG_DATA, "gpgme_data_get_encoding", dh,
479          "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
480   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 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
488 {
489   TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_encoding", dh,
490               "encoding=%i", enc);
491   if (!dh)
492     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
493   if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
494     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
495   dh->encoding = enc;
496   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 gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
504 {
505   TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_file_name", dh,
506               "file_name=%s", file_name);
507
508   if (!dh)
509     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
510
511   if (dh->file_name)
512     free (dh->file_name);
513
514   if (file_name)
515     {
516       dh->file_name = strdup (file_name);
517       if (!dh->file_name)
518         return TRACE_ERR (gpg_error_from_syserror ());
519     }
520   else
521     dh->file_name = 0;
522
523   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 gpgme_data_get_file_name (gpgme_data_t dh)
531 {
532   if (!dh)
533     {
534       TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh, "");
535       return NULL;
536     }
537
538   TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh,
539          "dh->file_name=%s", dh->file_name);
540   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 gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
547 {
548   TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_flag", dh,
549               "%s=%s", name, value);
550
551   if (!dh)
552     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
553
554   if (!strcmp (name, "size-hint"))
555     {
556       dh->size_hint= value? _gpgme_string_to_off (value) : 0;
557     }
558   else
559     return gpg_error (GPG_ERR_UNKNOWN_NAME);
560
561   return 0;
562 }
563
564
565 \f
566 /* Functions to support the wait interface.  */
567
568 gpgme_error_t
569 _gpgme_data_inbound_handler (void *opaque, int fd)
570 {
571   struct io_cb_data *data = (struct io_cb_data *) opaque;
572   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
573   char buffer[BUFFER_SIZE];
574   char *bufp = buffer;
575   gpgme_ssize_t buflen;
576   TRACE_BEG  (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
577               "fd=%d", fd);
578
579   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
580   if (buflen < 0)
581     return gpg_error_from_syserror ();
582   if (buflen == 0)
583     {
584       _gpgme_io_close (fd);
585       return TRACE_ERR (0);
586     }
587
588   do
589     {
590       gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
591       if (amt == 0 || (amt < 0 && errno != EINTR))
592         return TRACE_ERR (gpg_error_from_syserror ());
593       bufp += amt;
594       buflen -= amt;
595     }
596   while (buflen > 0);
597   return TRACE_ERR (0);
598 }
599
600
601 gpgme_error_t
602 _gpgme_data_outbound_handler (void *opaque, int fd)
603 {
604   struct io_cb_data *data = (struct io_cb_data *) opaque;
605   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
606   gpgme_ssize_t nwritten;
607   TRACE_BEG  (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
608               "fd=%d", fd);
609
610   if (!dh->pending_len)
611     {
612       gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
613       if (amt < 0)
614         return TRACE_ERR (gpg_error_from_syserror ());
615       if (amt == 0)
616         {
617           _gpgme_io_close (fd);
618           return TRACE_ERR (0);
619         }
620       dh->pending_len = amt;
621     }
622
623   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
624   if (nwritten == -1 && errno == EAGAIN)
625     return TRACE_ERR (0);
626
627   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       _gpgme_io_close (fd);
634       return TRACE_ERR (0);
635     }
636
637   if (nwritten <= 0)
638     return TRACE_ERR (gpg_error_from_syserror ());
639
640   if (nwritten < dh->pending_len)
641     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
642   dh->pending_len -= nwritten;
643   return TRACE_ERR (0);
644 }
645
646
647 /* Get the file descriptor associated with DH, if possible.  Otherwise
648    return -1.  */
649 int
650 _gpgme_data_get_fd (gpgme_data_t dh)
651 {
652   if (!dh || !dh->cbs->get_fd)
653     return -1;
654   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 _gpgme_data_get_size_hint (gpgme_data_t dh)
661 {
662   return dh ? dh->size_hint : 0;
663 }