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