LCOV - code coverage report
Current view: top level - lib - randread.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 41 74 55.4 %
Date: 2018-01-30 Functions: 6 9 66.7 %

          Line data    Source code
       1             : /* Generate buffers of random data.
       2             : 
       3             :    Copyright (C) 2006, 2008 Free Software Foundation, Inc.
       4             : 
       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.
       9             : 
      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.
      14             : 
      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/>.  */
      17             : 
      18             : /* Written by Paul Eggert.  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include "randread.h"
      23             : 
      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>
      33             : 
      34             : #include "gettext.h"
      35             : #define _(msgid) gettext (msgid)
      36             : 
      37             : #include "rand-isaac.h"
      38             : #include "stdio-safer.h"
      39             : #include "unlocked-io.h"
      40             : #include "xalloc.h"
      41             : 
      42             : #ifndef MIN
      43             : # define MIN(a, b) ((a) < (b) ? (a) : (b))
      44             : #endif
      45             : 
      46             : #ifndef __attribute__
      47             : # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
      48             : #  define __attribute__(x)
      49             : # endif
      50             : #endif
      51             : 
      52             : #ifndef ATTRIBUTE_UNUSED
      53             : # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
      54             : #endif
      55             : 
      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
      62             : 
      63             : #ifndef DEFAULT_RANDOM_FILE
      64             : # define DEFAULT_RANDOM_FILE "/dev/urandom"
      65             : #endif
      66             : 
      67             : /* The maximum buffer size used for reads of random data.  Using the
      68             :    value 2 * ISAAC_BYTES makes this the largest power of two that
      69             :    would not otherwise cause struct randread_source to grow.  */
      70             : #define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES)
      71             : 
      72             : /* A source of random data for generating random buffers.  */
      73             : struct randread_source
      74             : {
      75             :   /* Stream to read random bytes from.  If null, the behavior is
      76             :      undefined; the current implementation uses ISAAC in this case,
      77             :      but this is for old-fashioned implementations that lack
      78             :      /dev/urandom and callers should not rely on this.  */
      79             :   FILE *source;
      80             : 
      81             :   /* Function to call, and its argument, if there is an input error or
      82             :      end of file when reading from the stream; errno is nonzero if
      83             :      there was an error.  If this function returns, it should fix the
      84             :      problem before returning.  The default handler assumes that
      85             :      handler_arg is the file name of the source.  */
      86             :   void (*handler) (void const *);
      87             :   void const *handler_arg;
      88             : 
      89             :   /* The buffer for SOURCE.  It's kept here to simplify storage
      90             :      allocation and to make it easier to clear out buffered random
      91             :      data.  */
      92             :   union
      93             :   {
      94             :     /* The stream buffer, if SOURCE is not null.  */
      95             :     char c[RANDREAD_BUFFER_SIZE];
      96             : 
      97             :     /* The buffered ISAAC pseudorandom buffer, if SOURCE is null.  */
      98             :     struct isaac
      99             :     {
     100             :       /* The number of bytes that are buffered at the end of data.b.  */
     101             :       size_t buffered;
     102             : 
     103             :       /* State of the ISAAC generator.  */
     104             :       struct isaac_state state;
     105             : 
     106             :       /* Up to a buffer's worth of pseudorandom data.  */
     107             :       union
     108             :       {
     109             :         uint32_t w[ISAAC_WORDS];
     110             :         unsigned char b[ISAAC_BYTES];
     111             :       } data;
     112             :     } isaac;
     113             :   } buf;
     114             : };
     115             : 
     116             : 
     117             : /* The default error handler.  */
     118             : 
     119             : static void
     120           1 : randread_error (void const *file_name)
     121             : {
     122           1 :   if (file_name)
     123           2 :     error (exit_failure, errno,
     124           1 :            _(errno == 0 ? "%s: end of file" : "%s: read error"),
     125             :            quotearg_colon (file_name));
     126           0 :   abort ();
     127             : }
     128             : 
     129             : /* Simply return a new randread_source object with the default error
     130             :    handler.  */
     131             : 
     132             : static struct randread_source *
     133         103 : simple_new (FILE *source, void const *handler_arg)
     134             : {
     135         103 :   struct randread_source *s = xmalloc (sizeof *s);
     136         103 :   s->source = source;
     137         103 :   s->handler = randread_error;
     138         103 :   s->handler_arg = handler_arg;
     139         103 :   return s;
     140             : }
     141             : 
     142             : /* Create and initialize a random data source from NAME, or use a
     143             :    reasonable default source if NAME is null.  BYTES_BOUND is an upper
     144             :    bound on the number of bytes that will be needed.  If zero, it is a
     145             :    hard bound; otherwise it is just an estimate.
     146             : 
     147             :    If NAME is not null, NAME is saved for use as the argument of the
     148             :    default handler.  Unless a non-default handler is used, NAME's
     149             :    lifetime should be at least that of the returned value.
     150             : 
     151             :    Return NULL (setting errno) on failure.  */
     152             : 
     153             : struct randread_source *
     154         105 : randread_new (char const *name, size_t bytes_bound)
     155             : {
     156         105 :   if (bytes_bound == 0)
     157          10 :     return simple_new (NULL, NULL);
     158             :   else
     159             :     {
     160          95 :       char const *file_name = (name ? name : DEFAULT_RANDOM_FILE);
     161          95 :       FILE *source = fopen_safer (file_name, "rb");
     162             :       struct randread_source *s;
     163             : 
     164          95 :       if (! source)
     165             :         {
     166           2 :           if (name)
     167           2 :             return NULL;
     168           0 :           file_name = NULL;
     169             :         }
     170             : 
     171          93 :       s = simple_new (source, file_name);
     172             : 
     173          93 :       if (source)
     174          93 :         setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound));
     175             :       else
     176             :         {
     177           0 :           s->buf.isaac.buffered = 0;
     178           0 :           isaac_seed (&s->buf.isaac.state);
     179             :         }
     180             : 
     181          93 :       return s;
     182             :     }
     183             : }
     184             : 
     185             : 
     186             : /* Set S's handler and its argument.  HANDLER (HANDLER_ARG) is called
     187             :    when there is a read error or end of file from the random data
     188             :    source; errno is nonzero if there was an error.  If HANDLER
     189             :    returns, it should fix the problem before returning.  The default
     190             :    handler assumes that handler_arg is the file name of the source; it
     191             :    does not return.  */
     192             : 
     193             : void
     194           0 : randread_set_handler (struct randread_source *s, void (*handler) (void const *))
     195             : {
     196           0 :   s->handler = handler;
     197           0 : }
     198             : 
     199             : void
     200           0 : randread_set_handler_arg (struct randread_source *s, void const *handler_arg)
     201             : {
     202           0 :   s->handler_arg = handler_arg;
     203           0 : }
     204             : 
     205             : 
     206             : /* Place SIZE random bytes into the buffer beginning at P, using
     207             :    the stream in S.  */
     208             : 
     209             : static void
     210         452 : readsource (struct randread_source *s, unsigned char *p, size_t size)
     211             : {
     212             :   for (;;)
     213           0 :     {
     214         452 :       size_t inbytes = fread (p, sizeof *p, size, s->source);
     215         452 :       int fread_errno = errno;
     216         452 :       p += inbytes;
     217         452 :       size -= inbytes;
     218         452 :       if (size == 0)
     219         451 :         break;
     220           1 :       errno = (ferror (s->source) ? fread_errno : 0);
     221           1 :       s->handler (s->handler_arg);
     222             :     }
     223         451 : }
     224             : 
     225             : 
     226             : /* Place SIZE pseudorandom bytes into the buffer beginning at P, using
     227             :    the buffered ISAAC generator in ISAAC.  */
     228             : 
     229             : static void
     230           0 : readisaac (struct isaac *isaac, unsigned char *p, size_t size)
     231             : {
     232           0 :   size_t inbytes = isaac->buffered;
     233             : 
     234             :   for (;;)
     235             :     {
     236           0 :       if (size <= inbytes)
     237             :         {
     238           0 :           memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size);
     239           0 :           isaac->buffered = inbytes - size;
     240           0 :           return;
     241             :         }
     242             : 
     243           0 :       memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes);
     244           0 :       p += inbytes;
     245           0 :       size -= inbytes;
     246             : 
     247             :       /* If P is aligned, write to *P directly to avoid the overhead
     248             :          of copying from the buffer.  */
     249           0 :       if (ALIGNED_POINTER (p, uint32_t))
     250             :         {
     251           0 :           uint32_t *wp = (uint32_t *) p;
     252           0 :           while (ISAAC_BYTES <= size)
     253             :             {
     254           0 :               isaac_refill (&isaac->state, wp);
     255           0 :               wp += ISAAC_WORDS;
     256           0 :               size -= ISAAC_BYTES;
     257           0 :               if (size == 0)
     258             :                 {
     259           0 :                   isaac->buffered = 0;
     260           0 :                   return;
     261             :                 }
     262             :             }
     263           0 :           p = (unsigned char *) wp;
     264             :         }
     265             : 
     266           0 :       isaac_refill (&isaac->state, isaac->data.w);
     267           0 :       inbytes = ISAAC_BYTES;
     268             :     }
     269             : }
     270             : 
     271             : 
     272             : /* Consume random data from *S to generate a random buffer BUF of size
     273             :    SIZE.  */
     274             : 
     275             : void
     276         452 : randread (struct randread_source *s, void *buf, size_t size)
     277             : {
     278         452 :   if (s->source)
     279         452 :     readsource (s, buf, size);
     280             :   else
     281           0 :     readisaac (&s->buf.isaac, buf, size);
     282         451 : }
     283             : 
     284             : 
     285             : /* Clear *S so that it no longer contains undelivered random data, and
     286             :    deallocate any system resources associated with *S.  Return 0 if
     287             :    successful, a negative number (setting errno) if not (this is rare,
     288             :    but can occur in theory if there is an input error).  */
     289             : 
     290             : int
     291          76 : randread_free (struct randread_source *s)
     292             : {
     293          76 :   FILE *source = s->source;
     294          76 :   memset (s, 0, sizeof *s);
     295          76 :   free (s);
     296          76 :   return (source ? fclose (source) : 0);
     297             : }

Generated by: LCOV version 1.10