X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/1f2f436a38f7ae2d39a943ad2898d8fed4ed2e58..23e20b0053d7317ce3facd3fd38db8c73c2c380a:/stdio/FreeBSD/fwrite.c diff --git a/stdio/FreeBSD/fwrite.c b/stdio/FreeBSD/fwrite.c index 0c40b93..09eae83 100644 --- a/stdio/FreeBSD/fwrite.c +++ b/stdio/FreeBSD/fwrite.c @@ -43,6 +43,13 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/fwrite.c,v 1.13 2009/07/12 13:09:43 ed Ex #include "fvwrite.h" #include "libc_private.h" +/* + * The maximum amount to write to avoid integer overflow (especially for + * uio_resid in struct __suio). INT_MAX is odd, so it make sense to make it + * even. We subtract (BUFSIZ - 1) to get a whole number of BUFSIZ chunks. + */ +#define MAXWRITE (INT_MAX - (BUFSIZ - 1)) + /* * Write `count' objects (each size `size') from memory to the given file. * Return the number of whole objects written. @@ -53,31 +60,40 @@ fwrite(buf, size, count, fp) size_t size, count; FILE * __restrict fp; { - size_t n; + size_t n, resid; struct __suio uio; struct __siov iov; + int s; /* * ANSI and SUSv2 require a return value of 0 if size or count are 0. */ n = count * size; +#if __DARWIN_UNIX03 if (n == 0) return (0); - - iov.iov_base = (void *)buf; - uio.uio_resid = iov.iov_len = n; +#endif uio.uio_iov = &iov; uio.uio_iovcnt = 1; FLOCKFILE(fp); ORIENT(fp, -1); - /* - * The usual case is success (__sfvwrite returns 0); - * skip the divide if this happens, since divides are - * generally slow and since this occurs whenever size==0. - */ - if (__sfvwrite(fp, &uio) != 0) - count = (n - uio.uio_resid) / size; + + for (resid = n; resid > 0; buf += s, resid -= s) { + s = resid > INT_MAX ? MAXWRITE : (int)resid; + iov.iov_base = (void *)buf; + uio.uio_resid = iov.iov_len = s; + + /* + * The usual case is success (__sfvwrite returns 0); + * skip the divide if this happens, since divides are + * generally slow and since this occurs whenever size==0. + */ + if (__sfvwrite(fp, &uio) != 0) { + count = (n - resid + s - uio.uio_resid) / size; + break; + } + } FUNLOCKFILE(fp); return (count); }