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 148 : _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
42 : {
43 : gpgme_data_t dh;
44 :
45 148 : if (!r_dh)
46 1 : return gpg_error (GPG_ERR_INV_VALUE);
47 :
48 147 : *r_dh = NULL;
49 147 : dh = calloc (1, sizeof (*dh));
50 147 : if (!dh)
51 0 : return gpg_error_from_syserror ();
52 :
53 147 : dh->cbs = cbs;
54 :
55 147 : *r_dh = dh;
56 147 : return 0;
57 : }
58 :
59 :
60 : void
61 147 : _gpgme_data_release (gpgme_data_t dh)
62 : {
63 147 : if (!dh)
64 147 : return;
65 :
66 147 : if (dh->file_name)
67 1 : free (dh->file_name);
68 147 : 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 499 : gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
77 : {
78 : gpgme_ssize_t res;
79 499 : TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh,
80 : "buffer=%p, size=%u", buffer, size);
81 :
82 499 : if (!dh)
83 : {
84 0 : gpg_err_set_errno (EINVAL);
85 0 : return TRACE_SYSRES (-1);
86 : }
87 499 : if (!dh->cbs->read)
88 : {
89 0 : gpg_err_set_errno (ENOSYS);
90 0 : return TRACE_SYSRES (-1);
91 : }
92 : do
93 499 : res = (*dh->cbs->read) (dh, buffer, size);
94 499 : while (res < 0 && errno == EINTR);
95 :
96 499 : 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 108 : gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
105 : {
106 : gpgme_ssize_t res;
107 108 : TRACE_BEG2 (DEBUG_DATA, "gpgme_data_write", dh,
108 : "buffer=%p, size=%u", buffer, size);
109 :
110 108 : if (!dh)
111 : {
112 0 : gpg_err_set_errno (EINVAL);
113 0 : return TRACE_SYSRES (-1);
114 : }
115 108 : if (!dh->cbs->write)
116 : {
117 0 : gpg_err_set_errno (ENOSYS);
118 0 : return TRACE_SYSRES (-1);
119 : }
120 : do
121 108 : res = (*dh->cbs->write) (dh, buffer, size);
122 108 : while (res < 0 && errno == EINTR);
123 :
124 108 : 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 62 : gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
133 : {
134 62 : TRACE_BEG2 (DEBUG_DATA, "gpgme_data_seek", dh,
135 : "offset=%lli, whence=%i", offset, whence);
136 :
137 62 : if (!dh)
138 : {
139 0 : gpg_err_set_errno (EINVAL);
140 0 : return TRACE_SYSRES (-1);
141 : }
142 62 : 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 62 : if (whence == SEEK_CUR)
151 0 : offset -= dh->pending_len;
152 :
153 62 : offset = (*dh->cbs->seek) (dh, offset, whence);
154 62 : if (offset >= 0)
155 62 : dh->pending_len = 0;
156 :
157 62 : return TRACE_SYSRES (offset);
158 : }
159 :
160 :
161 : /* Release the data object with the handle DH. */
162 : void
163 147 : gpgme_data_release (gpgme_data_t dh)
164 : {
165 147 : TRACE (DEBUG_DATA, "gpgme_data_release", dh);
166 :
167 147 : if (!dh)
168 147 : return;
169 :
170 147 : if (dh->cbs->release)
171 147 : (*dh->cbs->release) (dh);
172 147 : _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 12 : gpgme_data_get_encoding (gpgme_data_t dh)
180 : {
181 12 : TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh,
182 : "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
183 12 : 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_URL0)
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 1 : gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
207 : {
208 1 : TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh,
209 : "file_name=%s", file_name);
210 :
211 1 : if (!dh)
212 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
213 :
214 1 : if (dh->file_name)
215 0 : free (dh->file_name);
216 :
217 1 : if (file_name)
218 : {
219 1 : dh->file_name = strdup (file_name);
220 1 : if (!dh->file_name)
221 0 : return TRACE_ERR (gpg_error_from_syserror ());
222 : }
223 : else
224 0 : dh->file_name = 0;
225 :
226 1 : 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 35 : gpgme_data_get_file_name (gpgme_data_t dh)
234 : {
235 35 : if (!dh)
236 : {
237 0 : TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh);
238 0 : return NULL;
239 : }
240 :
241 35 : TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh,
242 : "dh->file_name=%s", dh->file_name);
243 35 : return dh->file_name;
244 : }
245 :
246 :
247 : /* Functions to support the wait interface. */
248 :
249 : gpgme_error_t
250 173 : _gpgme_data_inbound_handler (void *opaque, int fd)
251 : {
252 173 : struct io_cb_data *data = (struct io_cb_data *) opaque;
253 173 : gpgme_data_t dh = (gpgme_data_t) data->handler_value;
254 : char buffer[BUFFER_SIZE];
255 173 : char *bufp = buffer;
256 : gpgme_ssize_t buflen;
257 173 : TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
258 : "fd=0x%x", fd);
259 :
260 173 : buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
261 173 : if (buflen < 0)
262 0 : return gpg_error_from_syserror ();
263 173 : if (buflen == 0)
264 : {
265 71 : _gpgme_io_close (fd);
266 71 : return TRACE_ERR (0);
267 : }
268 :
269 : do
270 : {
271 102 : gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
272 102 : if (amt == 0 || (amt < 0 && errno != EINTR))
273 0 : return TRACE_ERR (gpg_error_from_syserror ());
274 102 : bufp += amt;
275 102 : buflen -= amt;
276 : }
277 102 : while (buflen > 0);
278 102 : return TRACE_ERR (0);
279 : }
280 :
281 :
282 : gpgme_error_t
283 180 : _gpgme_data_outbound_handler (void *opaque, int fd)
284 : {
285 180 : struct io_cb_data *data = (struct io_cb_data *) opaque;
286 180 : gpgme_data_t dh = (gpgme_data_t) data->handler_value;
287 : gpgme_ssize_t nwritten;
288 180 : TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
289 : "fd=0x%x", fd);
290 :
291 180 : if (!dh->pending_len)
292 : {
293 180 : gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
294 180 : if (amt < 0)
295 0 : return TRACE_ERR (gpg_error_from_syserror ());
296 180 : if (amt == 0)
297 : {
298 78 : _gpgme_io_close (fd);
299 78 : return TRACE_ERR (0);
300 : }
301 102 : dh->pending_len = amt;
302 : }
303 :
304 102 : nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
305 102 : if (nwritten == -1 && errno == EAGAIN)
306 0 : return TRACE_ERR (0);
307 :
308 102 : if (nwritten == -1 && errno == EPIPE)
309 : {
310 : /* Not much we can do. The other end closed the pipe, but we
311 : still have data. This should only ever happen if the other
312 : end is going to tell us what happened on some other channel.
313 : Silently close our end. */
314 0 : _gpgme_io_close (fd);
315 0 : return TRACE_ERR (0);
316 : }
317 :
318 102 : if (nwritten <= 0)
319 0 : return TRACE_ERR (gpg_error_from_syserror ());
320 :
321 102 : if (nwritten < dh->pending_len)
322 0 : memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
323 102 : dh->pending_len -= nwritten;
324 102 : return TRACE_ERR (0);
325 : }
326 :
327 :
328 : /* Get the file descriptor associated with DH, if possible. Otherwise
329 : return -1. */
330 : int
331 18 : _gpgme_data_get_fd (gpgme_data_t dh)
332 : {
333 18 : if (!dh || !dh->cbs->get_fd)
334 18 : return -1;
335 0 : return (*dh->cbs->get_fd) (dh);
336 : }
|