Loading...
stdio/FreeBSD/fwrite.c Libc-763.13 Libc-1583.60.2
--- Libc/Libc-763.13/stdio/FreeBSD/fwrite.c
+++ Libc/Libc-1583.60.2/stdio/FreeBSD/fwrite.c
@@ -44,40 +44,54 @@
 #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.
  */
 size_t
-fwrite(buf, size, count, fp)
-	const void * __restrict buf;
-	size_t size, count;
-	FILE * __restrict fp;
+fwrite(const void * __restrict buf, size_t size, size_t 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);
 }