Blame lib/cmpbuf.c

Packit Service fdd496
/* Buffer primitives for comparison operations.
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1993, 1995, 1998, 2001-2002, 2006, 2009-2013, 2015-2017 Free
Packit Service fdd496
   Software Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation, either version 3 of the License, or
Packit Service fdd496
   (at your option) any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
#include <config.h>
Packit Service fdd496
Packit Service fdd496
#include <errno.h>
Packit Service fdd496
#include <limits.h>
Packit Service fdd496
#include <signal.h>
Packit Service fdd496
#include <unistd.h>
Packit Service fdd496
#include <stdint.h>
Packit Service fdd496
#include <inttypes.h>
Packit Service fdd496
#include <sys/types.h>
Packit Service fdd496
#include "cmpbuf.h"
Packit Service fdd496
#include "intprops.h"
Packit Service fdd496
Packit Service fdd496
#ifndef SSIZE_MAX
Packit Service fdd496
# define SSIZE_MAX TYPE_MAXIMUM (ssize_t)
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#undef MIN
Packit Service fdd496
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
Packit Service fdd496
Packit Service fdd496
/* Read NBYTES bytes from descriptor FD into BUF.
Packit Service fdd496
   NBYTES must not be SIZE_MAX.
Packit Service fdd496
   Return the number of characters successfully read.
Packit Service fdd496
   On error, return SIZE_MAX, setting errno.
Packit Service fdd496
   The number returned is always NBYTES unless end-of-file or error.  */
Packit Service fdd496
Packit Service fdd496
size_t
Packit Service fdd496
block_read (int fd, char *buf, size_t nbytes)
Packit Service fdd496
{
Packit Service fdd496
  char *bp = buf;
Packit Service fdd496
  char const *buflim = buf + nbytes;
Packit Service fdd496
  size_t readlim = MIN (SSIZE_MAX, SIZE_MAX);
Packit Service fdd496
Packit Service fdd496
  do
Packit Service fdd496
    {
Packit Service fdd496
      size_t bytes_remaining = buflim - bp;
Packit Service fdd496
      size_t bytes_to_read = MIN (bytes_remaining, readlim);
Packit Service fdd496
      ssize_t nread = read (fd, bp, bytes_to_read);
Packit Service fdd496
      if (nread <= 0)
Packit Service fdd496
	{
Packit Service fdd496
	  if (nread == 0)
Packit Service fdd496
	    break;
Packit Service fdd496
Packit Service fdd496
	  /* Accommodate Tru64 5.1, which can't read more than INT_MAX
Packit Service fdd496
	     bytes at a time.  They call that a 64-bit OS?  */
Packit Service fdd496
	  if (errno == EINVAL && INT_MAX < bytes_to_read)
Packit Service fdd496
	    {
Packit Service fdd496
	      readlim = INT_MAX;
Packit Service fdd496
	      continue;
Packit Service fdd496
	    }
Packit Service fdd496
Packit Service fdd496
	  /* This is needed for programs that have signal handlers on
Packit Service fdd496
	     older hosts without SA_RESTART.  It also accommodates
Packit Service fdd496
	     ancient AIX hosts that set errno to EINTR after uncaught
Packit Service fdd496
	     SIGCONT.  See <news:1r77ojINN85n@ftp.UU.NET>
Packit Service fdd496
	     (1993-04-22).  */
Packit Service fdd496
	  if (! SA_RESTART && errno == EINTR)
Packit Service fdd496
	    continue;
Packit Service fdd496
Packit Service fdd496
	  return SIZE_MAX;
Packit Service fdd496
	}
Packit Service fdd496
      bp += nread;
Packit Service fdd496
    }
Packit Service fdd496
  while (bp < buflim);
Packit Service fdd496
Packit Service fdd496
  return bp - buf;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Least common multiple of two buffer sizes A and B.  However, if
Packit Service fdd496
   either A or B is zero, or if the multiple is greater than LCM_MAX,
Packit Service fdd496
   return a reasonable buffer size.  */
Packit Service fdd496
Packit Service fdd496
size_t
Packit Service fdd496
buffer_lcm (size_t a, size_t b, size_t lcm_max)
Packit Service fdd496
{
Packit Service fdd496
  size_t lcm, m, n, q, r;
Packit Service fdd496
Packit Service fdd496
  /* Yield reasonable values if buffer sizes are zero.  */
Packit Service fdd496
  if (!a)
Packit Service fdd496
    return b ? b : 8 * 1024;
Packit Service fdd496
  if (!b)
Packit Service fdd496
    return a;
Packit Service fdd496
Packit Service fdd496
  /* n = gcd (a, b) */
Packit Service fdd496
  for (m = a, n = b;  (r = m % n) != 0;  m = n, n = r)
Packit Service fdd496
    continue;
Packit Service fdd496
Packit Service fdd496
  /* Yield a if there is an overflow.  */
Packit Service fdd496
  q = a / n;
Packit Service fdd496
  lcm = q * b;
Packit Service fdd496
  return lcm <= lcm_max && lcm / b == q ? lcm : a;
Packit Service fdd496
}