mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-02-14 11:21:58 +02:00
This modernizes the source code somewhat, to take advantage of advances in GCC over the years, and Gnulib’s ‘assure’ module. Include assure.h in files that now need it. Do not include assert.h directly; it’s no longer needed. * bootstrap.conf (gnulib_modules): Add ‘assure’. * gl/lib/randread.c (randread_error): * src/chmod.c (describe_change): * src/chown-core.c (describe_change): * src/cp.c (decode_preserve_arg): * src/head.c (diagnose_copy_fd_failure): * src/ls.c (parse_ls_color): * src/od.c (decode_one_format): * src/split.c (main): * src/test.c (binary_operator, posixtest): Prefer affirm to abort, since it has better diagnostics in the normal case and better performance with -DNDEBUG. * gl/lib/xdectoint.c, src/die.h: Include stddef.h, for unreachable. * gl/lib/xdectoint.c: Do not include verify.h; no longer needed. * gl/lib/xdectoint.c (__xnumtoint): * src/die.h (die): Prefer C23 unreachable () to assume (false). * gl/lib/xfts.c (xfts_open): * src/basenc.c (base32hex_encode): * src/copy.c (abandon_move, copy_internal, valid_options): * src/cut.c (cut_fields): * src/df.c (alloc_field, decode_output_arg, get_dev): * src/du.c (process_file, main): * src/echo.c (usage): * src/factor.c (udiv_qrnnd, mod2, gcd2_odd, factor_insert_large) (mulredc2, factor_using_pollard_rho, isqrt2, div_smallq) (factor_using_squfof): * src/iopoll.c (iopoll_internal, fwrite_wait): * src/join.c (add_field): * src/ls.c (dev_ino_pop, main, gobble_file, sort_files): * src/mv.c (do_move): * src/od.c (decode_format_string, read_block, dump, main): * src/remove.c (rm): * src/rm.c (main): * src/sort.c (stream_open): * src/split.c (next_file_name, lines_chunk_split): * src/stdbuf.c (main): * src/stty.c (set_speed): * src/tac-pipe.c (line_ptr_decrement, line_ptr_increment): * src/touch.c (touch): * src/tr.c (find_bracketed_repeat, get_next) (validate_case_classes, get_spec_stats, string2_extend, main): * src/tsort.c (search_item, tsort): * src/wc.c (main): Prefer affirm to assert, as it allows for better static checking when compiling with -DNDEBUG. * src/chown-core.c (change_file_owner): * src/df.c (get_field_list): * src/expr.c (printv, null, tostring, toarith, eval2): * src/ls.c (time_type_to_statx, calc_req_mask, get_funky_string) (print_long_format): * src/numfmt.c (simple_strtod_fatal): * src/od.c (decode_one_format): * src/stty.c (mode_type_flag): * src/tail.c (xlseek): * src/tr.c (is_char_class_member, get_next, get_spec_stats) (string2_extend): Prefer unreachable () to abort () or assert (false) when merely pacifying the compiler, e.g., in a switch statement on an enum where all cases are covered. * src/copy.c (valid_options): Now returns void; the bool was useless. Caller no longer needs to assert. * src/csplit.c (find_line): * src/expand-common.c (next_file): * src/shred.c (incname): * src/sort.c (main): * src/tr.c (append_normal_char, append_range, append_char_class) (append_repeated_char, append_equiv_class): * src/tsort.c (search_item): Omit assert, since the hardware will check for us. * src/df.c (header_mode): Now the enum type it should have been. * src/du.c (process_file): * src/ls.c (assert_matching_dev_ino): * src/tail.c (valid_file_spec): * src/tr.c (validate_case_classes): Mark defns with MAYBE_UNUSED if they’re not used when -DNDEBUG. * src/factor.c (prime_p, prime2_p, mp_prime_p): Now ATTRIBUTE_PURE. Prefer affirm to error+abort. No need to translate this diagnostic. * src/fmt.c (get_paragraph): * src/stty.c (display_changed, display_all, sane_mode): * src/who.c (idle_string): Prefer assume to assert, since the goal is merely pacification and assert doesn’t pacify anyway if -DNDEBUG is used. * src/join.c (decode_field_spec): Omit unreachable abort. * src/ls.c (assert_matching_dev_ino, main): * src/tr.c (get_next): Prefer assure to assert, since the check is relatively expensive and won’t help static analysis. * src/ls.c (main): Prefer static_assert to assert of a constant expression. (format_inode): Redo to make it clear that buflen doesn’t matter, and that buf must have a certain number of bytes. All callers changed. This pacifies -Wformat-overflow. * src/od.c (decode_one_format): Omit an assert that tested for obviously undefined behavior, as the compiler could optimize it away anyway. * src/od.c (decode_one_format, decode_format_string): Prefer ATTRIBUTE_NONNULL to runtime checking. * src/stat.c: Do not include <stddef.h> since system.h does that now. * src/sync.c (sync_arg): Prefer unreachable () to assert (true), which was a typo. * src/system.h: Include stddef.h, for unreachable. * src/tail.c (xlseek): Simplify by relying on ‘error’ to exit.
314 lines
8.4 KiB
C
314 lines
8.4 KiB
C
/* Generate buffers of random data.
|
|
|
|
Copyright (C) 2006-2023 Free Software Foundation, Inc.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
/* Written by Paul Eggert. */
|
|
|
|
/* FIXME: Improve performance by adding support for the RDRAND machine
|
|
instruction if available (e.g., Ivy Bridge processors). */
|
|
|
|
#include <config.h>
|
|
|
|
#include "randread.h"
|
|
|
|
#include <errno.h>
|
|
#include <error.h>
|
|
#include <exitfail.h>
|
|
#include <fcntl.h>
|
|
#include <quote.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/random.h>
|
|
|
|
#include "gettext.h"
|
|
#define _(msgid) gettext (msgid)
|
|
|
|
#include "assure.h"
|
|
#include "minmax.h"
|
|
#include "rand-isaac.h"
|
|
#include "stdio-safer.h"
|
|
#include "unlocked-io.h"
|
|
#include "xalloc.h"
|
|
|
|
#if _STRING_ARCH_unaligned || _STRING_INLINE_unaligned
|
|
# define ALIGNED_POINTER(ptr, type) true
|
|
#else
|
|
# define ALIGNED_POINTER(ptr, type) ((size_t) (ptr) % alignof (type) == 0)
|
|
#endif
|
|
|
|
/* The maximum buffer size used for reads of random data. Using the
|
|
value 2 * ISAAC_BYTES makes this the largest power of two that
|
|
would not otherwise cause struct randread_source to grow. */
|
|
#define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES)
|
|
|
|
/* A source of random data for generating random buffers. */
|
|
struct randread_source
|
|
{
|
|
/* Stream to read random bytes from. If null, the current
|
|
implementation uses an internal PRNG (ISAAC). */
|
|
FILE *source;
|
|
|
|
/* Function to call, and its argument, if there is an input error or
|
|
end of file when reading from the stream; errno is nonzero if
|
|
there was an error. If this function returns, it should fix the
|
|
problem before returning. The default handler assumes that
|
|
handler_arg is the file name of the source. */
|
|
void (*handler) (void const *);
|
|
void const *handler_arg;
|
|
|
|
/* The buffer for SOURCE. It's kept here to simplify storage
|
|
allocation and to make it easier to clear out buffered random
|
|
data. */
|
|
union
|
|
{
|
|
/* The stream buffer, if SOURCE is not null. */
|
|
char c[RANDREAD_BUFFER_SIZE];
|
|
|
|
/* The buffered ISAAC pseudorandom buffer, if SOURCE is null. */
|
|
struct isaac
|
|
{
|
|
/* The number of bytes that are buffered at the end of data.b. */
|
|
size_t buffered;
|
|
|
|
/* State of the ISAAC generator. */
|
|
struct isaac_state state;
|
|
|
|
/* Up to a buffer's worth of pseudorandom data. */
|
|
union
|
|
{
|
|
isaac_word w[ISAAC_WORDS];
|
|
unsigned char b[ISAAC_BYTES];
|
|
} data;
|
|
} isaac;
|
|
} buf;
|
|
};
|
|
|
|
|
|
/* The default error handler. */
|
|
|
|
static void
|
|
randread_error (void const *file_name)
|
|
{
|
|
affirm (exit_failure);
|
|
error (exit_failure, errno,
|
|
errno == 0 ? _("%s: end of file") : _("%s: read error"),
|
|
quote (file_name));
|
|
}
|
|
|
|
/* Simply return a new randread_source object with the default error
|
|
handler. */
|
|
|
|
static struct randread_source *
|
|
simple_new (FILE *source, void const *handler_arg)
|
|
{
|
|
struct randread_source *s = xmalloc (sizeof *s);
|
|
s->source = source;
|
|
s->handler = randread_error;
|
|
s->handler_arg = handler_arg;
|
|
return s;
|
|
}
|
|
|
|
/* Put a nonce value into BUFFER, with size BUFSIZE.
|
|
Return true on success, false (setting errno) on failure. */
|
|
|
|
static bool
|
|
get_nonce (void *buffer, size_t bufsize)
|
|
{
|
|
char *buf = buffer, *buflim = buf + bufsize;
|
|
while (buf < buflim)
|
|
{
|
|
ssize_t nbytes = getrandom (buf, buflim - buf, 0);
|
|
if (0 <= nbytes)
|
|
buf += nbytes;
|
|
else if (errno != EINTR)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* Body of randread_free, broken out to pacify gcc -Wmismatched-dealloc. */
|
|
|
|
static int
|
|
randread_free_body (struct randread_source *s)
|
|
{
|
|
FILE *source = s->source;
|
|
explicit_bzero (s, sizeof *s);
|
|
free (s);
|
|
return source ? fclose (source) : 0;
|
|
}
|
|
|
|
/* Create and initialize a random data source from NAME, or use a
|
|
reasonable default source if NAME is null. BYTES_BOUND is an upper
|
|
bound on the number of bytes that will be needed. If zero, it is a
|
|
hard bound; otherwise it is just an estimate.
|
|
|
|
If NAME is not null, NAME is saved for use as the argument of the
|
|
default handler. Unless a non-default handler is used, NAME's
|
|
lifetime should be at least that of the returned value.
|
|
|
|
Return nullptr (setting errno) on failure. */
|
|
|
|
struct randread_source *
|
|
randread_new (char const *name, size_t bytes_bound)
|
|
{
|
|
if (bytes_bound == 0)
|
|
return simple_new (nullptr, nullptr);
|
|
else
|
|
{
|
|
FILE *source = nullptr;
|
|
struct randread_source *s;
|
|
|
|
if (name)
|
|
if (! (source = fopen_safer (name, "rb")))
|
|
return nullptr;
|
|
|
|
s = simple_new (source, name);
|
|
|
|
if (source)
|
|
setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound));
|
|
else
|
|
{
|
|
s->buf.isaac.buffered = 0;
|
|
if (! get_nonce (s->buf.isaac.state.m,
|
|
MIN (sizeof s->buf.isaac.state.m, bytes_bound)))
|
|
{
|
|
int e = errno;
|
|
randread_free_body (s);
|
|
errno = e;
|
|
return nullptr;
|
|
}
|
|
isaac_seed (&s->buf.isaac.state);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
}
|
|
|
|
|
|
/* Set S's handler and its argument. HANDLER (HANDLER_ARG) is called
|
|
when there is a read error or end of file from the random data
|
|
source; errno is nonzero if there was an error. If HANDLER
|
|
returns, it should fix the problem before returning. The default
|
|
handler assumes that handler_arg is the file name of the source; it
|
|
does not return. */
|
|
|
|
void
|
|
randread_set_handler (struct randread_source *s, void (*handler) (void const *))
|
|
{
|
|
s->handler = handler;
|
|
}
|
|
|
|
void
|
|
randread_set_handler_arg (struct randread_source *s, void const *handler_arg)
|
|
{
|
|
s->handler_arg = handler_arg;
|
|
}
|
|
|
|
|
|
/* Place SIZE random bytes into the buffer beginning at P, using
|
|
the stream in S. */
|
|
|
|
static void
|
|
readsource (struct randread_source *s, unsigned char *p, size_t size)
|
|
{
|
|
while (true)
|
|
{
|
|
size_t inbytes = fread (p, sizeof *p, size, s->source);
|
|
int fread_errno = errno;
|
|
p += inbytes;
|
|
size -= inbytes;
|
|
if (size == 0)
|
|
break;
|
|
errno = (ferror (s->source) ? fread_errno : 0);
|
|
s->handler (s->handler_arg);
|
|
}
|
|
}
|
|
|
|
|
|
/* Place SIZE pseudorandom bytes into the buffer beginning at P, using
|
|
the buffered ISAAC generator in ISAAC. */
|
|
|
|
static void
|
|
readisaac (struct isaac *isaac, void *p, size_t size)
|
|
{
|
|
size_t inbytes = isaac->buffered;
|
|
|
|
while (true)
|
|
{
|
|
char *char_p = p;
|
|
|
|
if (size <= inbytes)
|
|
{
|
|
memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size);
|
|
isaac->buffered = inbytes - size;
|
|
return;
|
|
}
|
|
|
|
memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes);
|
|
p = char_p + inbytes;
|
|
size -= inbytes;
|
|
|
|
/* If P is aligned, write to *P directly to avoid the overhead
|
|
of copying from the buffer. */
|
|
if (ALIGNED_POINTER (p, isaac_word))
|
|
{
|
|
isaac_word *wp = p;
|
|
while (ISAAC_BYTES <= size)
|
|
{
|
|
isaac_refill (&isaac->state, wp);
|
|
wp += ISAAC_WORDS;
|
|
size -= ISAAC_BYTES;
|
|
if (size == 0)
|
|
{
|
|
isaac->buffered = 0;
|
|
return;
|
|
}
|
|
}
|
|
p = wp;
|
|
}
|
|
|
|
isaac_refill (&isaac->state, isaac->data.w);
|
|
inbytes = ISAAC_BYTES;
|
|
}
|
|
}
|
|
|
|
|
|
/* Consume random data from *S to generate a random buffer BUF of size
|
|
SIZE. */
|
|
|
|
void
|
|
randread (struct randread_source *s, void *buf, size_t size)
|
|
{
|
|
if (s->source)
|
|
readsource (s, buf, size);
|
|
else
|
|
readisaac (&s->buf.isaac, buf, size);
|
|
}
|
|
|
|
|
|
/* Clear *S so that it no longer contains undelivered random data, and
|
|
deallocate any system resources associated with *S. Return 0 if
|
|
successful, a negative number (setting errno) if not (this is rare,
|
|
but can occur in theory if there is an input error). */
|
|
|
|
int
|
|
randread_free (struct randread_source *s)
|
|
{
|
|
return randread_free_body (s);
|
|
}
|