Reactos
at listview 255 lines 9.5 kB view raw
1// 2// fread.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines fread() and related functions, which read unformatted data from a 7// stdio stream. 8// 9#include <corecrt_internal_stdio.h> 10 11#ifdef _DEBUG 12 #define _BUFFER_FILL_PATTERN _SECURECRT_FILL_BUFFER_PATTERN 13#else 14 #define _BUFFER_FILL_PATTERN 0 15#endif 16 17 18 19// Reads data from a stream into the result buffer. The function reads elements 20// of size 'element_size' until it has read 'element_count' elements, until the 21// buffer is full, or until EOF is reached. 22// 23// Returns the number of "whole" elements that were read into the buffer. This 24// may be fewer than the requested number of elements if an error occurs or if 25// EOF is encountered. In this case, ferror() or feof() should be used to 26// distinguish between the two conditions. 27// 28// If the result buffer becomes full before the requested number of elements are 29// read, the buffer is zero-filled, zero is returned, and errno is set to ERANGE. 30extern "C" size_t __cdecl fread_s( 31 void* const buffer, 32 size_t const buffer_size, 33 size_t const element_size, 34 size_t const element_count, 35 FILE* const stream 36 ) 37{ 38 if (element_size == 0 || element_count == 0) 39 return 0; 40 41 // The rest of the argument validation is done in the _nolock function. Here 42 // we only need to validate that the stream is non-null before we lock it. 43 if (stream == nullptr) 44 { 45 if (buffer_size != _CRT_UNBOUNDED_BUFFER_SIZE) 46 memset(buffer, _BUFFER_FILL_PATTERN, buffer_size); 47 48 _VALIDATE_RETURN(stream != nullptr, EINVAL, 0); 49 } 50 51 size_t return_value = 0; 52 53 _lock_file(stream); 54 __try 55 { 56 return_value = _fread_nolock_s(buffer, buffer_size, element_size, element_count, stream); 57 } 58 __finally 59 { 60 _unlock_file(stream); 61 } 62 __endtry 63 64 return return_value; 65} 66 67 68 69extern "C" size_t __cdecl _fread_nolock_s( 70 void* const buffer, 71 size_t const buffer_size, 72 size_t const element_size, 73 size_t const element_count, 74 FILE* const public_stream 75 ) 76{ 77 __crt_stdio_stream const stream(public_stream); 78 79 if (element_size == 0 || element_count == 0) 80 return 0; 81 82 _VALIDATE_RETURN(buffer != nullptr, EINVAL, 0); 83 if (!stream.valid() || element_count > (SIZE_MAX / element_size)) 84 { 85 if (buffer_size != _CRT_UNBOUNDED_BUFFER_SIZE) 86 memset(buffer, _BUFFER_FILL_PATTERN, buffer_size); 87 88 _VALIDATE_RETURN(stream.valid(), EINVAL, 0); 89 _VALIDATE_RETURN(element_count <= (SIZE_MAX / element_size), EINVAL, 0); 90 } 91 92 // Figure out how big the buffer is; if the stream doesn't currently have a 93 // buffer, we assume that we'll get one with the usual internal buffer size: 94 unsigned stream_buffer_size = stream.has_any_buffer() 95 ? stream->_bufsiz 96 : _INTERNAL_BUFSIZ; 97 98 // The total number of bytes to be read into the buffer: 99 size_t const total_bytes = element_size * element_count; 100 101 char* data = static_cast<char*>(buffer); 102 103 // Read blocks of data from the stream until we have read the requested 104 // number of elements or we fill the buffer. 105 size_t remaining_bytes = total_bytes; 106 size_t remaining_buffer = buffer_size; 107 while (remaining_bytes != 0) 108 { 109 // If the stream is buffered and has characters, copy them into the 110 // result buffer: 111 if (stream.has_any_buffer() && stream->_cnt != 0) 112 { 113 if(stream->_cnt < 0) 114 { 115 _ASSERTE(("Inconsistent Stream Count. Flush between consecutive read and write", stream->_cnt >= 0)); 116 stream.set_flags(_IOERROR); 117 return (total_bytes - remaining_bytes) / element_size; 118 } 119 120 unsigned const bytes_to_read = remaining_bytes < static_cast<size_t>(stream->_cnt) 121 ? static_cast<unsigned>(remaining_bytes) 122 : static_cast<unsigned>(stream->_cnt); 123 124 if (bytes_to_read > remaining_buffer) 125 { 126 if (buffer_size != _CRT_UNBOUNDED_BUFFER_SIZE) 127 memset(buffer, _BUFFER_FILL_PATTERN, buffer_size); 128 129 _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0) 130 } 131 132 memcpy_s(data, remaining_buffer, stream->_ptr, bytes_to_read); 133 134 // Update the stream and local tracking variables to account for the 135 // read. Note that the number of bytes actually read is always equal 136 // to the number of bytes that we expected to read, because the data 137 // was already buffered in the stream. 138 remaining_bytes -= bytes_to_read; 139 stream->_cnt -= bytes_to_read; 140 stream->_ptr += bytes_to_read; 141 data += bytes_to_read; 142 remaining_buffer -= bytes_to_read; 143 } 144 // There is no data remaining in the stream buffer to be read, and we 145 // need to read more data than will fit in the buffer (or we need to read 146 // at least enough data to fill the buffer completely): 147 else if (remaining_bytes >= stream_buffer_size) 148 { 149 // We can read at most INT_MAX bytes at a time. This is a hard limit 150 // of the lowio _read() function. 151 unsigned const maximum_bytes_to_read = remaining_bytes > INT_MAX 152 ? static_cast<unsigned>(INT_MAX) 153 : static_cast<unsigned>(remaining_bytes); 154 155 // If the stream has a buffer, we want to read the largest chunk that 156 // is a multiple of the buffer size, to keep the stream buffer state 157 // consistent. If the stream is not buffered, we can read the maximum 158 // number of bytes that we can: 159 unsigned const bytes_to_read = stream_buffer_size != 0 160 ? static_cast<unsigned>(maximum_bytes_to_read - maximum_bytes_to_read % stream_buffer_size) 161 : maximum_bytes_to_read; 162 163 if (bytes_to_read > remaining_buffer) 164 { 165 if (buffer_size != _CRT_UNBOUNDED_BUFFER_SIZE) 166 memset(buffer, _BUFFER_FILL_PATTERN, buffer_size); 167 168 _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0) 169 } 170 171 // We are about to read data directly from the underlying file 172 // descriptor, bypassing the stream buffer. We reset the stream 173 // buffer state to ensure that future seeks do not incorrectly 174 // assume that the buffer contents are valid. 175 __acrt_stdio_reset_buffer(stream); 176 177 // Do the read. Note that if the stream is open in text mode, the 178 // bytes_read may not be the same as the bytes_to_read, due to 179 // newline translation. 180 int const bytes_read = _read_nolock(_fileno(stream.public_stream()), data, bytes_to_read); 181 if (bytes_read == 0) 182 { 183 // We encountered EOF: 184 stream.set_flags(_IOEOF); 185 return (total_bytes - remaining_bytes) / element_size; 186 } 187 else if (bytes_read < 0) 188 { 189 // The _read failed: 190 stream.set_flags(_IOERROR); 191 return (total_bytes - remaining_bytes) / element_size; 192 } 193 194 // Update the iteration state to reflect the read: 195 remaining_bytes -= bytes_read; 196 data += bytes_read; 197 remaining_buffer -= bytes_read; 198 } 199 // Otherwise, the stream does not have a buffer, or the stream buffer 200 // is full and there is insufficient space to do a direct read, so use 201 // __acrt_stdio_refill_and_read_narrow_nolock: 202 else 203 { 204 int const c = __acrt_stdio_refill_and_read_narrow_nolock(stream.public_stream()); 205 if (c == EOF) 206 return (total_bytes - remaining_bytes) / element_size; 207 208 // If we have filled the result buffer before we have read the 209 // requested number of elements or reached EOF, it is an error: 210 if (remaining_buffer == 0) 211 { 212 if (buffer_size != _CRT_UNBOUNDED_BUFFER_SIZE) 213 memset(buffer, _BUFFER_FILL_PATTERN, buffer_size); 214 215 _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0) 216 } 217 218 *data++ = static_cast<char>(c); 219 --remaining_bytes; 220 --remaining_buffer; 221 222 stream_buffer_size = stream->_bufsiz; 223 } 224 } 225 226 return element_count; // Success! 227} 228 229 230 231extern "C" size_t __cdecl fread( 232 void* const buffer, 233 size_t const element_size, 234 size_t const element_count, 235 FILE* const stream 236 ) 237{ 238 // Assume there is enough space in the destination buffer 239#pragma warning(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY) // 26015 - fread is unsafe 240 return fread_s(buffer, _CRT_UNBOUNDED_BUFFER_SIZE, element_size, element_count, stream); 241} 242 243 244 245extern "C" size_t __cdecl _fread_nolock( 246 void* const buffer, 247 size_t const element_size, 248 size_t const element_count, 249 FILE* const stream 250 ) 251{ 252 // Assume there is enough space in the destination buffer 253#pragma warning(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY) // 26015 - _fread_nolock is unsafe 254 return _fread_nolock_s(buffer, _CRT_UNBOUNDED_BUFFER_SIZE, element_size, element_count, stream); 255}