--- fread.c.bsdnew 2009-11-11 13:33:09.000000000 -0800 +++ fread.c 2009-11-11 14:14:22.000000000 -0800 @@ -63,7 +63,7 @@ __fread(void * __restrict buf, size_t si { size_t resid; char *p; - int r; + int r, ret; size_t total; /* @@ -76,19 +76,66 @@ __fread(void * __restrict buf, size_t si fp->_r = 0; total = resid; p = buf; + /* first deal with anything left in buffer, plus any ungetc buffers */ while (resid > (r = fp->_r)) { (void)memcpy((void *)p, (void *)fp->_p, (size_t)r); fp->_p += r; /* fp->_r = 0 ... done in __srefill */ p += r; resid -= r; - if (__srefill(fp)) { + if ((ret = __srefill0(fp)) > 0) + break; + else if (ret) { /* no more input: return partial result */ return ((total - resid) / size); } } - (void)memcpy((void *)p, (void *)fp->_p, resid); - fp->_r -= resid; - fp->_p += resid; + /* + * 5980080: don't use optimization if __SMBF not set (meaning setvbuf + * was called, and the buffer belongs to the user). + * 6180417: but for unbuffered (__SMBF is not set), so specifically + * test for it. + */ + if ((fp->_flags & (__SMBF | __SNBF)) && resid > fp->_bf._size) { + struct __sbuf save; + size_t n; + + save = fp->_bf; + fp->_bf._base = p; + fp->_bf._size = resid; + while (fp->_bf._size > 0) { + if ((ret = __srefill1(fp)) != 0) { + /* no more input: return partial result */ + resid = fp->_bf._size; + fp->_bf = save; + fp->_p = fp->_bf._base; + /* fp->_r = 0; already set in __srefill1 */ + return ((total - resid) / size); + } + fp->_bf._base += fp->_r; + fp->_bf._size -= fp->_r; + } + fp->_bf = save; + n = fp->_bf._size * ((resid - 1) / fp->_bf._size); + r = resid - n; + (void)memcpy((void *)fp->_bf._base, (void *)(p + n), (size_t)r); + fp->_p = fp->_bf._base + r; + fp->_r = 0; + } else { + while (resid > (r = fp->_r)) { + (void)memcpy((void *)p, (void *)fp->_p, (size_t)r); + fp->_p += r; + /* fp->_r = 0 ... done in __srefill */ + p += r; + resid -= r; + if (__srefill1(fp)) { + /* no more input: return partial result */ + return ((total - resid) / size); + } + } + (void)memcpy((void *)p, (void *)fp->_p, resid); + fp->_r -= resid; + fp->_p += resid; + } return (count); }