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 : }
|