maint: replace each "for (;;)" with "while (true)"
[coreutils.git] / gl / lib / randread.c
blob94b9928b2a394a5a3254d2602c26605927ad5377
1 /* Generate buffers of random data.
3 Copyright (C) 2006, 2008-2010 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* Written by Paul Eggert. */
20 #include <config.h>
22 #include "randread.h"
24 #include <errno.h>
25 #include <error.h>
26 #include <exitfail.h>
27 #include <quotearg.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
37 #include "rand-isaac.h"
38 #include "stdio-safer.h"
39 #include "unlocked-io.h"
40 #include "xalloc.h"
42 #ifndef __attribute__
43 # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
44 # define __attribute__(x) /* empty */
45 # endif
46 #endif
48 #ifndef ATTRIBUTE_NORETURN
49 # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
50 #endif
52 #ifndef MIN
53 # define MIN(a, b) ((a) < (b) ? (a) : (b))
54 #endif
56 #if _STRING_ARCH_unaligned
57 # define ALIGNED_POINTER(ptr, type) true
58 #else
59 # define alignof(type) offsetof (struct { char c; type x; }, x)
60 # define ALIGNED_POINTER(ptr, type) ((size_t) (ptr) % alignof (type) == 0)
61 #endif
63 /* The maximum buffer size used for reads of random data. Using the
64 value 2 * ISAAC_BYTES makes this the largest power of two that
65 would not otherwise cause struct randread_source to grow. */
66 #define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES)
68 /* A source of random data for generating random buffers. */
69 struct randread_source
71 /* Stream to read random bytes from. If null, the current
72 implementation uses an internal PRNG (ISAAC). */
73 FILE *source;
75 /* Function to call, and its argument, if there is an input error or
76 end of file when reading from the stream; errno is nonzero if
77 there was an error. If this function returns, it should fix the
78 problem before returning. The default handler assumes that
79 handler_arg is the file name of the source. */
80 void (*handler) (void const *);
81 void const *handler_arg;
83 /* The buffer for SOURCE. It's kept here to simplify storage
84 allocation and to make it easier to clear out buffered random
85 data. */
86 union
88 /* The stream buffer, if SOURCE is not null. */
89 char c[RANDREAD_BUFFER_SIZE];
91 /* The buffered ISAAC pseudorandom buffer, if SOURCE is null. */
92 struct isaac
94 /* The number of bytes that are buffered at the end of data.b. */
95 size_t buffered;
97 /* State of the ISAAC generator. */
98 struct isaac_state state;
100 /* Up to a buffer's worth of pseudorandom data. */
101 union
103 uint32_t w[ISAAC_WORDS];
104 unsigned char b[ISAAC_BYTES];
105 } data;
106 } isaac;
107 } buf;
111 /* The default error handler. */
113 static void ATTRIBUTE_NORETURN
114 randread_error (void const *file_name)
116 if (file_name)
117 error (exit_failure, errno,
118 _(errno == 0 ? "%s: end of file" : "%s: read error"),
119 quotearg_colon (file_name));
120 abort ();
123 /* Simply return a new randread_source object with the default error
124 handler. */
126 static struct randread_source *
127 simple_new (FILE *source, void const *handler_arg)
129 struct randread_source *s = xmalloc (sizeof *s);
130 s->source = source;
131 s->handler = randread_error;
132 s->handler_arg = handler_arg;
133 return s;
136 /* Create and initialize a random data source from NAME, or use a
137 reasonable default source if NAME is null. BYTES_BOUND is an upper
138 bound on the number of bytes that will be needed. If zero, it is a
139 hard bound; otherwise it is just an estimate.
141 If NAME is not null, NAME is saved for use as the argument of the
142 default handler. Unless a non-default handler is used, NAME's
143 lifetime should be at least that of the returned value.
145 Return NULL (setting errno) on failure. */
147 struct randread_source *
148 randread_new (char const *name, size_t bytes_bound)
150 if (bytes_bound == 0)
151 return simple_new (NULL, NULL);
152 else
154 FILE *source = NULL;
155 struct randread_source *s;
157 if (name)
158 if (! (source = fopen_safer (name, "rb")))
159 return NULL;
161 s = simple_new (source, name);
163 if (source)
164 setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound));
165 else
167 s->buf.isaac.buffered = 0;
168 isaac_seed (&s->buf.isaac.state);
171 return s;
176 /* Set S's handler and its argument. HANDLER (HANDLER_ARG) is called
177 when there is a read error or end of file from the random data
178 source; errno is nonzero if there was an error. If HANDLER
179 returns, it should fix the problem before returning. The default
180 handler assumes that handler_arg is the file name of the source; it
181 does not return. */
183 void
184 randread_set_handler (struct randread_source *s, void (*handler) (void const *))
186 s->handler = handler;
189 void
190 randread_set_handler_arg (struct randread_source *s, void const *handler_arg)
192 s->handler_arg = handler_arg;
196 /* Place SIZE random bytes into the buffer beginning at P, using
197 the stream in S. */
199 static void
200 readsource (struct randread_source *s, unsigned char *p, size_t size)
202 while (true)
204 size_t inbytes = fread (p, sizeof *p, size, s->source);
205 int fread_errno = errno;
206 p += inbytes;
207 size -= inbytes;
208 if (size == 0)
209 break;
210 errno = (ferror (s->source) ? fread_errno : 0);
211 s->handler (s->handler_arg);
216 /* Place SIZE pseudorandom bytes into the buffer beginning at P, using
217 the buffered ISAAC generator in ISAAC. */
219 static void
220 readisaac (struct isaac *isaac, unsigned char *p, size_t size)
222 size_t inbytes = isaac->buffered;
224 while (true)
226 if (size <= inbytes)
228 memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size);
229 isaac->buffered = inbytes - size;
230 return;
233 memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes);
234 p += inbytes;
235 size -= inbytes;
237 /* If P is aligned, write to *P directly to avoid the overhead
238 of copying from the buffer. */
239 if (ALIGNED_POINTER (p, uint32_t))
241 uint32_t *wp = (uint32_t *) p;
242 while (ISAAC_BYTES <= size)
244 isaac_refill (&isaac->state, wp);
245 wp += ISAAC_WORDS;
246 size -= ISAAC_BYTES;
247 if (size == 0)
249 isaac->buffered = 0;
250 return;
253 p = (unsigned char *) wp;
256 isaac_refill (&isaac->state, isaac->data.w);
257 inbytes = ISAAC_BYTES;
262 /* Consume random data from *S to generate a random buffer BUF of size
263 SIZE. */
265 void
266 randread (struct randread_source *s, void *buf, size_t size)
268 if (s->source)
269 readsource (s, buf, size);
270 else
271 readisaac (&s->buf.isaac, buf, size);
275 /* Clear *S so that it no longer contains undelivered random data, and
276 deallocate any system resources associated with *S. Return 0 if
277 successful, a negative number (setting errno) if not (this is rare,
278 but can occur in theory if there is an input error). */
281 randread_free (struct randread_source *s)
283 FILE *source = s->source;
284 memset (s, 0, sizeof *s);
285 free (s);
286 return (source ? fclose (source) : 0);