core: Fix error types.
[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 gpgme_ssize_t
76 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
77 {
78   gpgme_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 gpgme_ssize_t
104 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
105 {
106   gpgme_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 gpgme_off_t
132 gpgme_data_seek (gpgme_data_t dh, gpgme_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 /* Convenience function to do a gpgme_data_seek (dh, 0, SEEK_SET).  */
162 gpgme_error_t
163 gpgme_data_rewind (gpgme_data_t dh)
164 {
165   gpgme_error_t err;
166   TRACE_BEG (DEBUG_DATA, "gpgme_data_rewind", dh);
167
168   err = ((gpgme_data_seek (dh, 0, SEEK_SET) == -1)
169          ? gpg_error_from_syserror () : 0);
170
171   return TRACE_ERR (err);
172 }
173
174
175 /* Release the data object with the handle DH.  */
176 void
177 gpgme_data_release (gpgme_data_t dh)
178 {
179   TRACE (DEBUG_DATA, "gpgme_data_release", dh);
180
181   if (!dh)
182     return;
183
184   if (dh->cbs->release)
185     (*dh->cbs->release) (dh);
186   _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 gpgme_data_get_encoding (gpgme_data_t dh)
194 {
195   TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh,
196           "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
197   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 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
205 {
206   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_encoding", dh,
207               "encoding=%i", enc);
208   if (!dh)
209     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
210   if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
211     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
212   dh->encoding = enc;
213   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 gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
221 {
222   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh,
223               "file_name=%s", file_name);
224
225   if (!dh)
226     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
227
228   if (dh->file_name)
229     free (dh->file_name);
230
231   if (file_name)
232     {
233       dh->file_name = strdup (file_name);
234       if (!dh->file_name)
235         return TRACE_ERR (gpg_error_from_syserror ());
236     }
237   else
238     dh->file_name = 0;
239
240   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 gpgme_data_get_file_name (gpgme_data_t dh)
248 {
249   if (!dh)
250     {
251       TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh);
252       return NULL;
253     }
254
255   TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh,
256           "dh->file_name=%s", dh->file_name);
257   return dh->file_name;
258 }
259
260
261 /* Set a flag for the data object DH.  See the manual for details.  */
262 gpgme_error_t
263 gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
264 {
265   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_set_flag", dh,
266               "%s=%s", name, value);
267
268   if (!dh)
269     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
270
271   if (!strcmp (name, "size-hint"))
272     {
273       dh->size_hint= value? _gpgme_string_to_off (value) : 0;
274     }
275   else
276     return gpg_error (GPG_ERR_UNKNOWN_NAME);
277
278   return 0;
279 }
280
281
282 \f
283 /* Functions to support the wait interface.  */
284
285 gpgme_error_t
286 _gpgme_data_inbound_handler (void *opaque, int fd)
287 {
288   struct io_cb_data *data = (struct io_cb_data *) opaque;
289   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
290   char buffer[BUFFER_SIZE];
291   char *bufp = buffer;
292   gpgme_ssize_t buflen;
293   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
294               "fd=0x%x", fd);
295
296   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
297   if (buflen < 0)
298     return gpg_error_from_syserror ();
299   if (buflen == 0)
300     {
301       _gpgme_io_close (fd);
302       return TRACE_ERR (0);
303     }
304
305   do
306     {
307       gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
308       if (amt == 0 || (amt < 0 && errno != EINTR))
309         return TRACE_ERR (gpg_error_from_syserror ());
310       bufp += amt;
311       buflen -= amt;
312     }
313   while (buflen > 0);
314   return TRACE_ERR (0);
315 }
316
317
318 gpgme_error_t
319 _gpgme_data_outbound_handler (void *opaque, int fd)
320 {
321   struct io_cb_data *data = (struct io_cb_data *) opaque;
322   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
323   gpgme_ssize_t nwritten;
324   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
325               "fd=0x%x", fd);
326
327   if (!dh->pending_len)
328     {
329       gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
330       if (amt < 0)
331         return TRACE_ERR (gpg_error_from_syserror ());
332       if (amt == 0)
333         {
334           _gpgme_io_close (fd);
335           return TRACE_ERR (0);
336         }
337       dh->pending_len = amt;
338     }
339
340   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
341   if (nwritten == -1 && errno == EAGAIN)
342     return TRACE_ERR (0);
343
344   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       _gpgme_io_close (fd);
351       return TRACE_ERR (0);
352     }
353
354   if (nwritten <= 0)
355     return TRACE_ERR (gpg_error_from_syserror ());
356
357   if (nwritten < dh->pending_len)
358     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
359   dh->pending_len -= nwritten;
360   return TRACE_ERR (0);
361 }
362
363
364 /* Get the file descriptor associated with DH, if possible.  Otherwise
365    return -1.  */
366 int
367 _gpgme_data_get_fd (gpgme_data_t dh)
368 {
369   if (!dh || !dh->cbs->get_fd)
370     return -1;
371   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 _gpgme_data_get_size_hint (gpgme_data_t dh)
378 {
379   return dh ? dh->size_hint : 0;
380 }