2002-10-10 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / data-compat.c
1 /* data-mem.c - A memory based data object.
2  *      Copyright (C) 2002 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it 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,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28
29 #include "data.h"
30 #include "util.h"
31
32 \f
33 /* Create a new data buffer filled with LENGTH bytes starting from
34    OFFSET within the file FNAME or stream STREAM (exactly one must be
35    non-zero).  */
36 GpgmeError
37 gpgme_data_new_from_filepart (GpgmeData *dh, const char *fname, FILE *stream,
38                               off_t offset, size_t length)
39 {
40   GpgmeError err;
41   char *buf = NULL;
42
43   if (stream && fname)
44     return mk_error (Invalid_Value);
45
46   if (fname)
47     stream = fopen (fname, "rb");
48   if (!stream)
49     return mk_error (File_Error);
50
51   if (fseek (stream, offset, SEEK_SET))
52     goto ferr;
53
54   buf = malloc (length);
55   if (!buf)
56     goto ferr;
57
58   while (fread (buf, length, 1, stream) < 1
59          && ferror (stream) && errno == EINTR);
60   if (ferror (stream))
61     {
62       if (buf)
63         free (buf);
64       goto ferr;
65     }
66
67   if (fname)
68     fclose (stream);
69
70   err = gpgme_data_new (dh);
71   if (err)
72     {
73       if (buf)
74         free (buf);
75       return err;
76     }
77
78   (*dh)->data.mem.buffer = buf;
79   (*dh)->data.mem.size = length;
80   (*dh)->data.mem.length = length;
81   return 0;
82
83  ferr:
84   {
85     int saved_errno = errno;
86     if (fname)
87       fclose (stream);
88     errno = saved_errno;
89     return mk_error (File_Error);
90   }
91 }
92
93 \f
94 /* Create a new data buffer filled with the content of file FNAME.
95    COPY must be non-zero (delayed reads are not supported yet).  */
96 GpgmeError
97 gpgme_data_new_from_file (GpgmeData *dh, const char *fname, int copy)
98 {
99   struct stat statbuf;
100
101   if (!fname || !copy)
102     return mk_error (Invalid_Value);
103
104   if (stat (fname, &statbuf) < 0)
105     return mk_error (File_Error);
106
107   return gpgme_data_new_from_filepart (dh, fname, NULL, 0, statbuf.st_size);
108 }
109
110 \f
111 static int
112 gpgme_error_to_errno (GpgmeError err)
113 {
114   switch (err)
115     {
116     case mk_error (EOF):
117       return 0;
118     case mk_error (Out_Of_Core):
119       errno = ENOMEM;
120       return -1;
121     case mk_error (Invalid_Value):
122       errno = EINVAL;
123       return -1;
124     case mk_error (Busy):
125       errno = EBUSY;
126       return -1;
127     case mk_error (Not_Implemented):
128       errno = EOPNOTSUPP;
129       return -1;
130     default:
131       /* XXX Yeah, well.  */
132       errno = EINVAL;
133       return -1;
134     }
135 }
136
137 static int
138 old_user_read (GpgmeData dh, void *buffer, size_t size)
139 {
140   size_t amt;
141   GpgmeError err = (*dh->data.old_user.cb) (dh->data.old_user.handle,
142                                             buffer, size, &amt);
143   if (err)
144     return gpgme_error_to_errno (err);
145   return amt;
146 }
147
148
149 static off_t
150 old_user_seek (GpgmeData dh, off_t offset, int whence)
151 {
152   GpgmeError err;
153   if (whence != SEEK_SET || offset)
154     return EINVAL;
155   err = (*dh->data.old_user.cb) (dh->data.old_user.handle, NULL, 0, NULL);
156   if (err)
157     return gpgme_error_to_errno (err);
158   return 0;
159 }
160
161
162 static struct gpgme_data_cbs old_user_cbs =
163   {
164     old_user_read,
165     NULL,
166     old_user_seek,
167     NULL
168   };
169
170
171 /* Create a new data buffer which retrieves the data from the callback
172    function READ_CB.  */
173 GpgmeError
174 gpgme_data_new_with_read_cb (GpgmeData *dh,
175                              int (*read_cb) (void *, char *, size_t, size_t *),
176                              void *read_cb_value)
177 {
178   GpgmeError err = _gpgme_data_new (dh, &old_user_cbs);
179   if (err)
180     return err;
181
182   (*dh)->data.old_user.cb = read_cb;
183   (*dh)->data.old_user.handle = read_cb_value;
184   return 0;
185 }
186
187 \f
188 GpgmeError
189 gpgme_data_rewind (GpgmeData dh)
190 {
191   return (gpgme_data_seek (dh, 0, SEEK_SET) == -1)
192     ? mk_error (File_Error) : 0;
193 }