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> 3875b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes#include <sys/param.h> 399d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes#include "local.h" 409d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes 41f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) 42f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes 439d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughessize_t 447cc779f15c524e1622f7d5b1c7e82e6ffc6677fdGeorge Burgess IVfread(void *buf, size_t size, size_t count, FILE *fp) __overloadable 459d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes{ 469d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes /* 4775b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * Extension: Catch integer overflow. 48f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes */ 49f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes if ((size >= MUL_NO_OVERFLOW || count >= MUL_NO_OVERFLOW) && 50f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes size > 0 && SIZE_MAX / size < count) { 51f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes errno = EOVERFLOW; 52f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes fp->_flags |= __SERR; 53f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes return (0); 54f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes } 55f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes 5675b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes const size_t desired_total = count * size; 5775b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes size_t total = desired_total; 5875b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 59f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughes /* 609d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes * ANSI and SUSv2 require a return value of 0 if size or count are 0. 619d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes */ 6275b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes if (total == 0) { 639d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes return (0); 6475b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes } 6575b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 669d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes FLOCKFILE(fp); 679d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes _SET_ORIENTATION(fp, -1); 6875b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 6975b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes // TODO: how can this ever happen?! 709d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes if (fp->_r < 0) 719d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes fp->_r = 0; 7220841a137beac5caa824e3586c7bd91d879ff92eElliott Hughes 7375b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes /* 7475b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * Ensure _bf._size is valid. 7575b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes */ 7675b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes if (fp->_bf._base == NULL) { 7775b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes __smakebuf(fp); 7820841a137beac5caa824e3586c7bd91d879ff92eElliott Hughes } 7920841a137beac5caa824e3586c7bd91d879ff92eElliott Hughes 8075b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes char* dst = buf; 8175b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 8275b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes while (total > 0) { 8375b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes /* 8475b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * Copy data out of the buffer. 8575b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes */ 86e69e6458cca9adb9669850ac4055df38a20a70d1Elliott Hughes size_t buffered_bytes = MIN((size_t) fp->_r, total); 8775b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes memcpy(dst, fp->_p, buffered_bytes); 8875b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes fp->_p += buffered_bytes; 8975b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes fp->_r -= buffered_bytes; 9075b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes dst += buffered_bytes; 9175b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes total -= buffered_bytes; 9275b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 9375b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes /* 9475b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * Are we done? 9575b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes */ 9675b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes if (total == 0) { 9775b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes goto out; 9875b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes } 9975b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 10075b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes /* 10175b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * Do we have so much more to read that we should 10275b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * avoid copying it through the buffer? 10375b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes */ 10475b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes if (total > (size_t) fp->_bf._size) { 105cc9ca1051dbf5bd2af1b801de13d43a399521cf9Christopher Ferris /* 106cc9ca1051dbf5bd2af1b801de13d43a399521cf9Christopher Ferris * Make sure that fseek doesn't think it can 107cc9ca1051dbf5bd2af1b801de13d43a399521cf9Christopher Ferris * reuse the buffer since we are going to read 108cc9ca1051dbf5bd2af1b801de13d43a399521cf9Christopher Ferris * directly from the file descriptor. 109cc9ca1051dbf5bd2af1b801de13d43a399521cf9Christopher Ferris */ 110cc9ca1051dbf5bd2af1b801de13d43a399521cf9Christopher Ferris fp->_flags |= __SMOD; 11175b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes break; 11275b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes } 11375b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 11475b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes /* 11575b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * Less than a buffer to go, so refill the buffer and 11675b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * go around the loop again. 11775b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes */ 1189d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes if (__srefill(fp)) { 11975b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes goto out; 12075b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes } 12175b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes } 12275b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 12375b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes /* 12475b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes * Read directly into the caller's buffer. 12575b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes */ 12675b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes while (total > 0) { 12775b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes ssize_t bytes_read = (*fp->_read)(fp->_cookie, dst, total); 12875b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes if (bytes_read <= 0) { 129e6bb5a27769cc974c4c6c1bfc96dcd07f0c0f5efElliott Hughes fp->_flags |= (bytes_read == 0) ? __SEOF : __SERR; 13075b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes break; 1319d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes } 13275b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes dst += bytes_read; 13375b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes total -= bytes_read; 1349d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes } 13575b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes 13675b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughesout: 1379d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes FUNLOCKFILE(fp); 13875b99387dd3a8833f09e2139e7062be5d38c5511Elliott Hughes return ((desired_total - total) / size); 1399d3c2dd11f5e796cd814cddc5b907494f859058eElliott Hughes} 140