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 :
32 : #include "gpgme.h"
33 : #include "data.h"
34 : #include "util.h"
35 : #include "ops.h"
36 : #include "priv-io.h"
37 : #include "debug.h"
38 :
39 :
40 : gpgme_error_t
41 684 : _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
42 : {
43 : gpgme_data_t dh;
44 :
45 684 : if (!r_dh)
46 1 : return gpg_error (GPG_ERR_INV_VALUE);
47 :
48 683 : *r_dh = NULL;
49 683 : dh = calloc (1, sizeof (*dh));
50 683 : if (!dh)
51 0 : return gpg_error_from_syserror ();
52 :
53 683 : dh->cbs = cbs;
54 :
55 683 : *r_dh = dh;
56 683 : return 0;
57 : }
58 :
59 :
60 : void
61 645 : _gpgme_data_release (gpgme_data_t dh)
62 : {
63 645 : if (!dh)
64 0 : return;
65 :
66 645 : if (dh->file_name)
67 5 : free (dh->file_name);
68 645 : free (dh);
69 : }
70 :
71 :
72 : /* Read up to SIZE bytes into buffer BUFFER from the data object with
73 : the handle DH. Return the number of characters read, 0 on EOF and
74 : -1 on error. If an error occurs, errno is set. */
75 : gpgme_ssize_t
76 1434 : gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
77 : {
78 : gpgme_ssize_t res;
79 1434 : TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh,
80 : "buffer=%p, size=%u", buffer, size);
81 :
82 1434 : if (!dh)
83 : {
84 0 : gpg_err_set_errno (EINVAL);
85 0 : return TRACE_SYSRES (-1);
86 : }
87 1434 : if (!dh->cbs->read)
88 : {
89 0 : gpg_err_set_errno (ENOSYS);
90 0 : return TRACE_SYSRES (-1);
91 : }
92 : do
93 1434 : res = (*dh->cbs->read) (dh, buffer, size);
94 1434 : while (res < 0 && errno == EINTR);
95 :
96 1434 : return TRACE_SYSRES (res);
97 : }
98 :
99 :
100 : /* Write up to SIZE bytes from buffer BUFFER to the data object with
101 : the handle DH. Return the number of characters written, or -1 on
102 : error. If an error occurs, errno is set. */
103 : gpgme_ssize_t
104 885 : gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
105 : {
106 : gpgme_ssize_t res;
107 885 : TRACE_BEG2 (DEBUG_DATA, "gpgme_data_write", dh,
108 : "buffer=%p, size=%u", buffer, size);
109 :
110 885 : if (!dh)
111 : {
112 0 : gpg_err_set_errno (EINVAL);
113 0 : return TRACE_SYSRES (-1);
114 : }
115 885 : if (!dh->cbs->write)
116 : {
117 0 : gpg_err_set_errno (ENOSYS);
118 0 : return TRACE_SYSRES (-1);
119 : }
120 : do
121 885 : res = (*dh->cbs->write) (dh, buffer, size);
122 885 : while (res < 0 && errno == EINTR);
123 :
124 885 : return TRACE_SYSRES (res);
125 : }
126 :
127 :
128 : /* Set the current position from where the next read or write starts
129 : in the data object with the handle DH to OFFSET, relativ to
130 : WHENCE. */
131 : gpgme_off_t
132 318 : gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
133 : {
134 318 : TRACE_BEG2 (DEBUG_DATA, "gpgme_data_seek", dh,
135 : "offset=%lli, whence=%i", offset, whence);
136 :
137 318 : if (!dh)
138 : {
139 0 : gpg_err_set_errno (EINVAL);
140 0 : return TRACE_SYSRES (-1);
141 : }
142 318 : if (!dh->cbs->seek)
143 : {
144 0 : gpg_err_set_errno (ENOSYS);
145 0 : return TRACE_SYSRES (-1);
146 : }
147 :
148 : /* For relative movement, we must take into account the actual
149 : position of the read counter. */
150 318 : if (whence == SEEK_CUR)
151 0 : offset -= dh->pending_len;
152 :
153 318 : offset = (*dh->cbs->seek) (dh, offset, whence);
154 318 : if (offset >= 0)
155 314 : dh->pending_len = 0;
156 :
157 318 : return TRACE_SYSRES (offset);
158 : }
159 :
160 :
161 : /* Convenience function to do a gpgme_data_seek (dh, 0, SEEK_SET). */
162 : gpgme_error_t
163 0 : gpgme_data_rewind (gpgme_data_t dh)
164 : {
165 : gpgme_error_t err;
166 0 : TRACE_BEG (DEBUG_DATA, "gpgme_data_rewind", dh);
167 :
168 0 : err = ((gpgme_data_seek (dh, 0, SEEK_SET) == -1)
169 0 : ? gpg_error_from_syserror () : 0);
170 :
171 0 : return TRACE_ERR (err);
172 : }
173 :
174 :
175 : /* Release the data object with the handle DH. */
176 : void
177 1289 : gpgme_data_release (gpgme_data_t dh)
178 : {
179 1289 : TRACE (DEBUG_DATA, "gpgme_data_release", dh);
180 :
181 1289 : if (!dh)
182 644 : return;
183 :
184 645 : if (dh->cbs->release)
185 625 : (*dh->cbs->release) (dh);
186 645 : _gpgme_data_release (dh);
187 : }
188 :
189 :
190 : /* Get the current encoding meta information for the data object with
191 : handle DH. */
192 : gpgme_data_encoding_t
193 135 : gpgme_data_get_encoding (gpgme_data_t dh)
194 : {
195 135 : TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh,
196 : "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
197 135 : return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
198 : }
199 :
200 :
201 : /* Set the encoding meta information for the data object with handle
202 : DH to ENC. */
203 : gpgme_error_t
204 0 : gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
205 : {
206 0 : TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_encoding", dh,
207 : "encoding=%i", enc);
208 0 : if (!dh)
209 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
210 0 : if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
211 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
212 0 : dh->encoding = enc;
213 0 : return TRACE_ERR (0);
214 : }
215 :
216 :
217 : /* Set the file name associated with the data object with handle DH to
218 : FILE_NAME. */
219 : gpgme_error_t
220 5 : gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
221 : {
222 5 : TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh,
223 : "file_name=%s", file_name);
224 :
225 5 : if (!dh)
226 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
227 :
228 5 : if (dh->file_name)
229 0 : free (dh->file_name);
230 :
231 5 : if (file_name)
232 : {
233 5 : dh->file_name = strdup (file_name);
234 5 : if (!dh->file_name)
235 0 : return TRACE_ERR (gpg_error_from_syserror ());
236 : }
237 : else
238 0 : dh->file_name = 0;
239 :
240 5 : return TRACE_ERR (0);
241 : }
242 :
243 :
244 : /* Get the file name associated with the data object with handle DH,
245 : or NULL if there is none. */
246 : char *
247 130 : gpgme_data_get_file_name (gpgme_data_t dh)
248 : {
249 130 : if (!dh)
250 : {
251 0 : TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh);
252 0 : return NULL;
253 : }
254 :
255 130 : TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh,
256 : "dh->file_name=%s", dh->file_name);
257 130 : return dh->file_name;
258 : }
259 :
260 :
261 : /* Set a flag for the data object DH. See the manual for details. */
262 : gpg_error_t
263 67 : gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
264 : {
265 67 : TRACE_BEG2 (DEBUG_DATA, "gpgme_data_set_flag", dh,
266 : "%s=%s", name, value);
267 :
268 67 : if (!dh)
269 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
270 :
271 67 : if (!strcmp (name, "size-hint"))
272 : {
273 67 : dh->size_hint= value? _gpgme_string_to_off (value) : 0;
274 : }
275 : else
276 0 : return gpg_error (GPG_ERR_UNKNOWN_NAME);
277 :
278 67 : return 0;
279 : }
280 :
281 :
282 :
283 : /* Functions to support the wait interface. */
284 :
285 : gpgme_error_t
286 537 : _gpgme_data_inbound_handler (void *opaque, int fd)
287 : {
288 537 : struct io_cb_data *data = (struct io_cb_data *) opaque;
289 537 : gpgme_data_t dh = (gpgme_data_t) data->handler_value;
290 : char buffer[BUFFER_SIZE];
291 537 : char *bufp = buffer;
292 : gpgme_ssize_t buflen;
293 537 : TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
294 : "fd=0x%x", fd);
295 :
296 537 : buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
297 537 : if (buflen < 0)
298 0 : return gpg_error_from_syserror ();
299 537 : if (buflen == 0)
300 : {
301 209 : _gpgme_io_close (fd);
302 209 : return TRACE_ERR (0);
303 : }
304 :
305 : do
306 : {
307 328 : gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
308 328 : if (amt == 0 || (amt < 0 && errno != EINTR))
309 0 : return TRACE_ERR (gpg_error_from_syserror ());
310 328 : bufp += amt;
311 328 : buflen -= amt;
312 : }
313 328 : while (buflen > 0);
314 328 : return TRACE_ERR (0);
315 : }
316 :
317 :
318 : gpgme_error_t
319 873 : _gpgme_data_outbound_handler (void *opaque, int fd)
320 : {
321 873 : struct io_cb_data *data = (struct io_cb_data *) opaque;
322 873 : gpgme_data_t dh = (gpgme_data_t) data->handler_value;
323 : gpgme_ssize_t nwritten;
324 873 : TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
325 : "fd=0x%x", fd);
326 :
327 873 : if (!dh->pending_len)
328 : {
329 873 : gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
330 873 : if (amt < 0)
331 0 : return TRACE_ERR (gpg_error_from_syserror ());
332 873 : if (amt == 0)
333 : {
334 277 : _gpgme_io_close (fd);
335 277 : return TRACE_ERR (0);
336 : }
337 596 : dh->pending_len = amt;
338 : }
339 :
340 596 : nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
341 596 : if (nwritten == -1 && errno == EAGAIN)
342 0 : return TRACE_ERR (0);
343 :
344 596 : if (nwritten == -1 && errno == EPIPE)
345 : {
346 : /* Not much we can do. The other end closed the pipe, but we
347 : still have data. This should only ever happen if the other
348 : end is going to tell us what happened on some other channel.
349 : Silently close our end. */
350 0 : _gpgme_io_close (fd);
351 0 : return TRACE_ERR (0);
352 : }
353 :
354 596 : if (nwritten <= 0)
355 0 : return TRACE_ERR (gpg_error_from_syserror ());
356 :
357 596 : if (nwritten < dh->pending_len)
358 0 : memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
359 596 : dh->pending_len -= nwritten;
360 596 : return TRACE_ERR (0);
361 : }
362 :
363 :
364 : /* Get the file descriptor associated with DH, if possible. Otherwise
365 : return -1. */
366 : int
367 18 : _gpgme_data_get_fd (gpgme_data_t dh)
368 : {
369 18 : if (!dh || !dh->cbs->get_fd)
370 18 : return -1;
371 0 : return (*dh->cbs->get_fd) (dh);
372 : }
373 :
374 :
375 : /* Get the size-hint value for DH or 0 if not available. */
376 : gpgme_off_t
377 229 : _gpgme_data_get_size_hint (gpgme_data_t dh)
378 : {
379 229 : return dh ? dh->size_hint : 0;
380 : }
|