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