2005-10-01 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / data.c
1 /* data.c - An abstraction for data objects.
2    Copyright (C) 2002, 2003, 2004, 2005 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
36 \f
37 gpgme_error_t
38 _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
39 {
40   gpgme_data_t dh;
41
42   if (!r_dh)
43     return gpg_error (GPG_ERR_INV_VALUE);
44
45   *r_dh = NULL;
46   dh = calloc (1, sizeof (*dh));
47   if (!dh)
48     return gpg_error_from_errno (errno);
49
50   dh->cbs = cbs;
51
52   *r_dh = dh;
53   return 0;
54 }
55
56
57 void
58 _gpgme_data_release (gpgme_data_t dh)
59 {
60   if (!dh)
61     return;
62
63   if (dh->file_name)
64     free (dh->file_name);
65   free (dh);
66 }
67
68 \f
69 /* Read up to SIZE bytes into buffer BUFFER from the data object with
70    the handle DH.  Return the number of characters read, 0 on EOF and
71    -1 on error.  If an error occurs, errno is set.  */
72 ssize_t
73 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
74 {
75   if (!dh)
76     {
77       errno = EINVAL;
78       return -1;
79     }
80   if (!dh->cbs->read)
81     {
82       errno = ENOSYS;
83       return -1;
84     }
85   return (*dh->cbs->read) (dh, buffer, size);
86 }
87
88
89 /* Write up to SIZE bytes from buffer BUFFER to the data object with
90    the handle DH.  Return the number of characters written, or -1 on
91    error.  If an error occurs, errno is set.  */
92 ssize_t
93 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
94 {
95   if (!dh)
96     {
97       errno = EINVAL;
98       return -1;
99     }
100   if (!dh->cbs->write)
101     {
102       errno = ENOSYS;
103       return -1;
104     }
105   return (*dh->cbs->write) (dh, buffer, size);
106 }
107
108
109 /* Set the current position from where the next read or write starts
110    in the data object with the handle DH to OFFSET, relativ to
111    WHENCE.  */
112 off_t
113 gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence)
114 {
115   if (!dh)
116     {
117       errno = EINVAL;
118       return -1;
119     }
120   if (!dh->cbs->seek)
121     {
122       errno = ENOSYS;
123       return -1;
124     }
125
126   /* For relative movement, we must take into account the actual
127      position of the read counter.  */
128   if (whence == SEEK_CUR)
129     offset -= dh->pending_len;
130
131   offset = (*dh->cbs->seek) (dh, offset, whence);
132   if (offset >= 0)
133     dh->pending_len = 0;
134
135   return offset;
136 }
137
138
139 /* Release the data object with the handle DH.  */
140 void
141 gpgme_data_release (gpgme_data_t dh)
142 {
143   if (!dh)
144     return;
145
146   if (dh->cbs->release)
147     (*dh->cbs->release) (dh);
148   _gpgme_data_release (dh);
149 }
150
151
152 /* Get the current encoding meta information for the data object with
153    handle DH.  */
154 gpgme_data_encoding_t
155 gpgme_data_get_encoding (gpgme_data_t dh)
156 {
157   return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
158 }
159
160
161 /* Set the encoding meta information for the data object with handle
162    DH to ENC.  */
163 gpgme_error_t
164 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
165 {
166   if (!dh)
167     return gpg_error (GPG_ERR_INV_VALUE);
168   if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR)
169     return gpg_error (GPG_ERR_INV_VALUE);
170   dh->encoding = enc;
171   return 0;
172 }
173
174
175 /* Set the file name associated with the data object with handle DH to
176    FILE_NAME.  */
177 gpgme_error_t
178 gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
179 {
180   if (!dh)
181     return gpg_error (GPG_ERR_INV_VALUE);
182
183   if (dh->file_name)
184     free (dh->file_name);
185
186   dh->file_name = strdup (file_name);
187   if (!dh->file_name)
188     return gpg_error_from_errno (errno);
189
190   return 0;
191 }
192
193 /* Get the file name associated with the data object with handle DH,
194    or NULL if there is none.  */
195 char *
196 gpgme_data_get_file_name (gpgme_data_t dh)
197 {
198   if (!dh)
199     return NULL;
200
201   return dh->file_name;
202 }
203
204 \f
205 /* Functions to support the wait interface.  */
206
207 gpgme_error_t
208 _gpgme_data_inbound_handler (void *opaque, int fd)
209 {
210   gpgme_data_t dh = (gpgme_data_t) opaque;
211   char buffer[BUFFER_SIZE];
212   char *bufp = buffer;
213   ssize_t buflen;
214
215   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
216   if (buflen < 0)
217     return gpg_error_from_errno (errno);
218   if (buflen == 0)
219     {
220       _gpgme_io_close (fd);
221       return 0;
222     }
223
224   do
225     {
226       ssize_t amt = gpgme_data_write (dh, bufp, buflen);
227       if (amt == 0 || (amt < 0 && errno != EINTR))
228         return gpg_error_from_errno (errno);
229       bufp += amt;
230       buflen -= amt;
231     }
232   while (buflen > 0);
233   return 0;
234 }
235
236
237 gpgme_error_t
238 _gpgme_data_outbound_handler (void *opaque, int fd)
239 {
240   gpgme_data_t dh = (gpgme_data_t) opaque;
241   ssize_t nwritten;
242
243   if (!dh->pending_len)
244     {
245       ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
246       if (amt < 0)
247         return gpg_error_from_errno (errno);
248       if (amt == 0)
249         {
250           _gpgme_io_close (fd);
251           return 0;
252         }
253       dh->pending_len = amt;
254     }
255
256   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
257   if (nwritten == -1 && errno == EAGAIN)
258     return 0;
259
260   if (nwritten == -1 && errno == EPIPE)
261     {
262       /* Not much we can do.  The other end closed the pipe, but we
263          still have data.  This should only ever happen if the other
264          end is going to tell us what happened on some other channel.
265          Silently close our end.  */
266       _gpgme_io_close (fd);
267       return 0;
268     }
269
270   if (nwritten <= 0)
271     return gpg_error_from_errno (errno);
272
273   if (nwritten < dh->pending_len)
274     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
275   dh->pending_len -= nwritten;
276   return 0;
277 }