Fix last change.
[gpgme.git] / gpgme / data-compat.c
1 /* data-compat.c - Compatibility interfaces for data objects.
2    Copyright (C) 2002, 2003 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 General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (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    General Public License for more details.
15  
16    You should have received a copy of the GNU General Public License
17    along with GPGME; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <errno.h>
25 #include <sys/stat.h>
26 #include <stdlib.h>
27
28 #include "data.h"
29 #include "util.h"
30
31 \f
32 /* Create a new data buffer filled with LENGTH bytes starting from
33    OFFSET within the file FNAME or stream STREAM (exactly one must be
34    non-zero).  */
35 gpgme_error_t
36 gpgme_data_new_from_filepart (gpgme_data_t *dh, const char *fname,
37                               FILE *stream, off_t offset, size_t length)
38 {
39   gpgme_error_t err;
40   char *buf = NULL;
41
42   if (stream && fname)
43     return gpg_error (GPG_ERR_INV_VALUE);
44
45   if (fname)
46     stream = fopen (fname, "rb");
47   if (!stream)
48     return gpg_error_from_errno (errno);
49
50   if (fseek (stream, offset, SEEK_SET))
51     {
52       int saved_errno = errno;
53       if (fname)
54         fclose (stream);
55       return gpg_error_from_errno (saved_errno);
56     }
57
58   buf = malloc (length);
59   if (!buf)
60     {
61       int saved_errno = errno;
62       if (fname)
63         fclose (stream);
64       return gpg_error_from_errno (saved_errno);
65     }
66
67   while (fread (buf, length, 1, stream) < 1
68          && ferror (stream) && errno == EINTR);
69   if (ferror (stream))
70     {
71       int saved_errno = errno;
72       if (buf)
73         free (buf);
74       if (fname)
75         fclose (stream);
76       return gpg_error_from_errno (saved_errno);
77     }
78
79   if (fname)
80     fclose (stream);
81
82   err = gpgme_data_new (dh);
83   if (err)
84     {
85       if (buf)
86         free (buf);
87       return err;
88     }
89
90   (*dh)->data.mem.buffer = buf;
91   (*dh)->data.mem.size = length;
92   (*dh)->data.mem.length = length;
93   return 0;
94 }
95
96 \f
97 /* Create a new data buffer filled with the content of file FNAME.
98    COPY must be non-zero (delayed reads are not supported yet).  */
99 gpgme_error_t
100 gpgme_data_new_from_file (gpgme_data_t *dh, const char *fname, int copy)
101 {
102   struct stat statbuf;
103
104   if (!fname || !copy)
105     return gpg_error (GPG_ERR_INV_VALUE);
106
107   if (stat (fname, &statbuf) < 0)
108     return gpg_error_from_errno (errno);
109
110   return gpgme_data_new_from_filepart (dh, fname, NULL, 0, statbuf.st_size);
111 }
112
113 \f
114 static int
115 gpgme_error_to_errno (gpgme_error_t err)
116 {
117   int no = gpg_err_code_to_errno (err);
118
119   if (no)
120     {
121       errno = no;
122       return -1;
123     }
124
125   switch (gpg_err_code (err))
126     {
127     case GPG_ERR_EOF:
128       return 0;
129     case GPG_ERR_INV_VALUE:
130       errno = EINVAL;
131       return -1;
132     case GPG_ERR_NOT_SUPPORTED:
133       errno = EOPNOTSUPP;
134       return -1;
135     default:
136       /* FIXME: Yeah, well.  */
137       errno = EINVAL;
138       return -1;
139     }
140 }
141
142
143 static ssize_t
144 old_user_read (gpgme_data_t dh, void *buffer, size_t size)
145 {
146   size_t amt;
147   gpgme_error_t err = (*dh->data.old_user.cb) (dh->data.old_user.handle,
148                                                buffer, size, &amt);
149   if (err)
150     return gpgme_error_to_errno (err);
151   return amt;
152 }
153
154
155 static off_t
156 old_user_seek (gpgme_data_t dh, off_t offset, int whence)
157 {
158   gpgme_error_t err;
159   if (whence != SEEK_SET || offset)
160     return EINVAL;
161   err = (*dh->data.old_user.cb) (dh->data.old_user.handle, NULL, 0, NULL);
162   if (err)
163     return gpgme_error_to_errno (err);
164   return 0;
165 }
166
167
168 static struct _gpgme_data_cbs old_user_cbs =
169   {
170     old_user_read,
171     NULL,
172     old_user_seek,
173     NULL
174   };
175
176
177 /* Create a new data buffer which retrieves the data from the callback
178    function READ_CB.  */
179 gpgme_error_t
180 gpgme_data_new_with_read_cb (gpgme_data_t *dh,
181                              int (*read_cb) (void *, char *, size_t, size_t *),
182                              void *read_cb_value)
183 {
184   gpgme_error_t err = _gpgme_data_new (dh, &old_user_cbs);
185   if (err)
186     return err;
187
188   (*dh)->data.old_user.cb = read_cb;
189   (*dh)->data.old_user.handle = read_cb_value;
190   return 0;
191 }
192
193 \f
194 gpgme_error_t
195 gpgme_data_rewind (gpgme_data_t dh)
196 {
197   return (gpgme_data_seek (dh, 0, SEEK_SET) == -1)
198     ? gpg_error_from_errno (errno) : 0;
199 }