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