1 /* $OpenBSD: fread.c,v 1.12 2014/05/01 16:40:36 deraadt Exp $ */ 2 /*- 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Chris Torek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <stdint.h> 37 #include <errno.h> 38 #include <sys/param.h> 39 #include "local.h" 40 41 #define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) 42 43 size_t 44 fread(void *buf, size_t size, size_t count, FILE *fp) 45 { 46 /* 47 * Extension: Catch integer overflow. 48 */ 49 if ((size >= MUL_NO_OVERFLOW || count >= MUL_NO_OVERFLOW) && 50 size > 0 && SIZE_MAX / size < count) { 51 errno = EOVERFLOW; 52 fp->_flags |= __SERR; 53 return (0); 54 } 55 56 const size_t desired_total = count * size; 57 size_t total = desired_total; 58 59 /* 60 * ANSI and SUSv2 require a return value of 0 if size or count are 0. 61 */ 62 if (total == 0) { 63 return (0); 64 } 65 66 FLOCKFILE(fp); 67 _SET_ORIENTATION(fp, -1); 68 69 // TODO: how can this ever happen?! 70 if (fp->_r < 0) 71 fp->_r = 0; 72 73 /* 74 * Ensure _bf._size is valid. 75 */ 76 if (fp->_bf._base == NULL) { 77 __smakebuf(fp); 78 } 79 80 char* dst = buf; 81 82 while (total > 0) { 83 /* 84 * Copy data out of the buffer. 85 */ 86 size_t buffered_bytes = MIN((size_t) fp->_r, total); 87 memcpy(dst, fp->_p, buffered_bytes); 88 fp->_p += buffered_bytes; 89 fp->_r -= buffered_bytes; 90 dst += buffered_bytes; 91 total -= buffered_bytes; 92 93 /* 94 * Are we done? 95 */ 96 if (total == 0) { 97 goto out; 98 } 99 100 /* 101 * Do we have so much more to read that we should 102 * avoid copying it through the buffer? 103 */ 104 if (total > (size_t) fp->_bf._size) { 105 /* 106 * Make sure that fseek doesn't think it can 107 * reuse the buffer since we are going to read 108 * directly from the file descriptor. 109 */ 110 fp->_flags |= __SMOD; 111 break; 112 } 113 114 /* 115 * Less than a buffer to go, so refill the buffer and 116 * go around the loop again. 117 */ 118 if (__srefill(fp)) { 119 goto out; 120 } 121 } 122 123 /* 124 * Read directly into the caller's buffer. 125 */ 126 while (total > 0) { 127 ssize_t bytes_read = (*fp->_read)(fp->_cookie, dst, total); 128 if (bytes_read <= 0) { 129 fp->_flags |= (bytes_read == 0) ? __SEOF : __SERR; 130 break; 131 } 132 dst += bytes_read; 133 total -= bytes_read; 134 } 135 136 out: 137 FUNLOCKFILE(fp); 138 return ((desired_total - total) / size); 139 } 140