1f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes/*	$OpenBSD: fread.c,v 1.12 2014/05/01 16:40:36 deraadt Exp $ */
29d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes/*-
39d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * Copyright (c) 1990, 1993
49d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *	The Regents of the University of California.  All rights reserved.
59d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *
69d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * This code is derived from software contributed to Berkeley by
79d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * Chris Torek.
89d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *
99d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * Redistribution and use in source and binary forms, with or without
109d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * modification, are permitted provided that the following conditions
119d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * are met:
129d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * 1. Redistributions of source code must retain the above copyright
139d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *    notice, this list of conditions and the following disclaimer.
149d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * 2. Redistributions in binary form must reproduce the above copyright
159d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *    notice, this list of conditions and the following disclaimer in the
169d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *    documentation and/or other materials provided with the distribution.
179d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * 3. Neither the name of the University nor the names of its contributors
189d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *    may be used to endorse or promote products derived from this software
199d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *    without specific prior written permission.
209d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes *
219d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
229d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
259d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
279d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
289d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
299d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
309d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
319d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * SUCH DAMAGE.
329d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes */
339d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes
349d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes#include <stdio.h>
359d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes#include <string.h>
36f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes#include <stdint.h>
37f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes#include <errno.h>
389d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes#include "local.h"
399d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes
40f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes#define MUL_NO_OVERFLOW	(1UL << (sizeof(size_t) * 4))
41f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes
429d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughessize_t
439d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughesfread(void *buf, size_t size, size_t count, FILE *fp)
449d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes{
459d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	size_t resid;
469d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	char *p;
479d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	int r;
489d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	size_t total;
499d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes
509d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	/*
51f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes	 * Extension:  Catch integer overflow
52f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes	 */
53f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes	if ((size >= MUL_NO_OVERFLOW || count >= MUL_NO_OVERFLOW) &&
54f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes	    size > 0 && SIZE_MAX / size < count) {
55f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes		errno = EOVERFLOW;
56f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes		fp->_flags |= __SERR;
57f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes		return (0);
58f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes	}
59f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes
60f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes	/*
619d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	 * ANSI and SUSv2 require a return value of 0 if size or count are 0.
629d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	 */
639d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	if ((resid = count * size) == 0)
649d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		return (0);
659d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	FLOCKFILE(fp);
669d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	_SET_ORIENTATION(fp, -1);
679d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	if (fp->_r < 0)
689d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		fp->_r = 0;
699d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	total = resid;
709d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	p = buf;
719d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	while (resid > (r = fp->_r)) {
729d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		(void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
739d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		fp->_p += r;
749d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		/* fp->_r = 0 ... done in __srefill */
759d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		p += r;
769d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		resid -= r;
779d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		if (__srefill(fp)) {
789d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes			/* no more input: return partial result */
799d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes			FUNLOCKFILE(fp);
809d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes			return ((total - resid) / size);
819d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes		}
829d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	}
839d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	(void)memcpy((void *)p, (void *)fp->_p, resid);
849d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	fp->_r -= resid;
859d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	fp->_p += resid;
869d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	FUNLOCKFILE(fp);
879d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes	return (count);
889d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes}
89