core: Fix condition-always-true warning in trace macro.
[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 /* 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_MIME)
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
247 /* Set a flag for the data object DH.  See the manual for details.  */
248 gpg_error_t
249 gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
250 {
251   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_set_flag", dh,
252               "%s=%s", name, value);
253
254   if (!dh)
255     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
256
257   if (!strcmp (name, "size-hint"))
258     {
259       dh->size_hint= value? _gpgme_string_to_off (value) : 0;
260     }
261   else
262     return gpg_error (GPG_ERR_UNKNOWN_NAME);
263
264   return 0;
265 }
266
267
268 \f
269 /* Functions to support the wait interface.  */
270
271 gpgme_error_t
272 _gpgme_data_inbound_handler (void *opaque, int fd)
273 {
274   struct io_cb_data *data = (struct io_cb_data *) opaque;
275   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
276   char buffer[BUFFER_SIZE];
277   char *bufp = buffer;
278   gpgme_ssize_t buflen;
279   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
280               "fd=0x%x", fd);
281
282   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
283   if (buflen < 0)
284     return gpg_error_from_syserror ();
285   if (buflen == 0)
286     {
287       _gpgme_io_close (fd);
288       return TRACE_ERR (0);
289     }
290
291   do
292     {
293       gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
294       if (amt == 0 || (amt < 0 && errno != EINTR))
295         return TRACE_ERR (gpg_error_from_syserror ());
296       bufp += amt;
297       buflen -= amt;
298     }
299   while (buflen > 0);
300   return TRACE_ERR (0);
301 }
302
303
304 gpgme_error_t
305 _gpgme_data_outbound_handler (void *opaque, int fd)
306 {
307   struct io_cb_data *data = (struct io_cb_data *) opaque;
308   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
309   gpgme_ssize_t nwritten;
310   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
311               "fd=0x%x", fd);
312
313   if (!dh->pending_len)
314     {
315       gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
316       if (amt < 0)
317         return TRACE_ERR (gpg_error_from_syserror ());
318       if (amt == 0)
319         {
320           _gpgme_io_close (fd);
321           return TRACE_ERR (0);
322         }
323       dh->pending_len = amt;
324     }
325
326   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
327   if (nwritten == -1 && errno == EAGAIN)
328     return TRACE_ERR (0);
329
330   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       _gpgme_io_close (fd);
337       return TRACE_ERR (0);
338     }
339
340   if (nwritten <= 0)
341     return TRACE_ERR (gpg_error_from_syserror ());
342
343   if (nwritten < dh->pending_len)
344     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
345   dh->pending_len -= nwritten;
346   return TRACE_ERR (0);
347 }
348
349
350 /* Get the file descriptor associated with DH, if possible.  Otherwise
351    return -1.  */
352 int
353 _gpgme_data_get_fd (gpgme_data_t dh)
354 {
355   if (!dh || !dh->cbs->get_fd)
356     return -1;
357   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 _gpgme_data_get_size_hint (gpgme_data_t dh)
364 {
365   return dh ? dh->size_hint : 0;
366 }