#include #include #include "fileutil.h" size_t fread(void *data, size_t membsize, size_t nmemb, FILE *fp) { if(!fp->readable) { fp->error = 1; return 0; } size_t request_size; if(__builtin_umul_overflow(membsize, nmemb, &request_size)) { fp->error = 1; return 0; } /* If the stream if unbuffered, we might have no buffer for the reads. If it's buffered, we always have one. It's also possible that fp is unbuffered (_IONBF) but has a buffer temporarily because ungetc() has been used, in which case we have to transition from buffered reads into direct reads midway. We use __fp_buffered_read() to handle this. */ size_t read_size = 0; __fp_buffer_mode_read(fp); while(read_size < request_size) { int remaining = request_size - read_size; int chunk = __fp_buffered_read(fp, data+read_size, remaining); /* Stream is not/no longer buffered, finish unbuffered */ if(chunk < 0) { ssize_t rc = __fp_read(fp, data+read_size, remaining); return read_size + (rc == EOF ? 0 : rc); } read_size += chunk; if(read_size >= request_size) break; /* Get more data from the file descriptor into the buffer */ if(fp->buf) { ssize_t rc = __fp_read(fp, fp->buf, fp->bufsize); if(rc <= 0) /* EOF or error */ break; fp->bufread = rc; } } return read_size; }