Remove support for RISCOS from dotlock.c
[gnupg.git] / common / membuf.c
1 /* membuf.c - A simple implementation of a dynamic buffer.
2  * Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG 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 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <errno.h>
23
24 #include "membuf.h"
25
26 #include "util.h"
27
28
29 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
30    create a buffer, put_membuf to append bytes and get_membuf to
31    release and return the buffer.  Allocation errors are detected but
32    only returned at the final get_membuf(), this helps not to clutter
33    the code with out of core checks.  */
34
35 void
36 init_membuf (membuf_t *mb, int initiallen)
37 {
38   mb->len = 0;
39   mb->size = initiallen;
40   mb->out_of_core = 0;
41   mb->buf = xtrymalloc (initiallen);
42   if (!mb->buf)
43     mb->out_of_core = errno;
44 }
45
46 /* Same as init_membuf but allocates the buffer in secure memory.  */
47 void
48 init_membuf_secure (membuf_t *mb, int initiallen)
49 {
50   mb->len = 0;
51   mb->size = initiallen;
52   mb->out_of_core = 0;
53   mb->buf = xtrymalloc_secure (initiallen);
54   if (!mb->buf)
55     mb->out_of_core = errno;
56 }
57
58
59 /* Shift the the content of the membuf MB by AMOUNT bytes.  The next
60    operation will then behave as if AMOUNT bytes had not been put into
61    the buffer.  If AMOUNT is greater than the actual accumulated
62    bytes, the membuf is basically reset to its initial state.  */
63 void
64 clear_membuf (membuf_t *mb, size_t amount)
65 {
66   /* No need to clear if we are already out of core.  */
67   if (mb->out_of_core)
68     return;
69   if (amount >= mb->len)
70     mb->len = 0;
71   else
72     {
73       mb->len -= amount;
74       memmove (mb->buf, mb->buf+amount, mb->len);
75     }
76 }
77
78
79 void
80 put_membuf (membuf_t *mb, const void *buf, size_t len)
81 {
82   if (mb->out_of_core || !len)
83     return;
84
85   if (mb->len + len >= mb->size)
86     {
87       char *p;
88
89       mb->size += len + 1024;
90       p = xtryrealloc (mb->buf, mb->size);
91       if (!p)
92         {
93           mb->out_of_core = errno ? errno : ENOMEM;
94           /* Wipe out what we already accumulated.  This is required
95              in case we are storing sensitive data here.  The membuf
96              API does not provide another way to cleanup after an
97              error. */
98           wipememory (mb->buf, mb->len);
99           return;
100         }
101       mb->buf = p;
102     }
103   memcpy (mb->buf + mb->len, buf, len);
104   mb->len += len;
105 }
106
107
108 void
109 put_membuf_str (membuf_t *mb, const char *string)
110 {
111   put_membuf (mb, string, strlen (string));
112 }
113
114
115 void *
116 get_membuf (membuf_t *mb, size_t *len)
117 {
118   char *p;
119
120   if (mb->out_of_core)
121     {
122       if (mb->buf)
123         {
124           wipememory (mb->buf, mb->len);
125           xfree (mb->buf);
126           mb->buf = NULL;
127         }
128       gpg_err_set_errno (mb->out_of_core);
129       return NULL;
130     }
131
132   p = mb->buf;
133   if (len)
134     *len = mb->len;
135   mb->buf = NULL;
136   mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
137   return p;
138 }
139
140
141 /* Peek at the membuf MB.  On success a pointer to the buffer is
142    returned which is valid until the next operation on MB.  If LEN is
143    not NULL the current LEN of the buffer is stored there.  On error
144    NULL is returned and ERRNO is set.  */
145 const void *
146 peek_membuf (membuf_t *mb, size_t *len)
147 {
148   const char *p;
149
150   if (mb->out_of_core)
151     {
152       gpg_err_set_errno (mb->out_of_core);
153       return NULL;
154     }
155
156   p = mb->buf;
157   if (len)
158     *len = mb->len;
159   return p;
160 }