__sfvwrite: allow writing buffers larger than BUFSIZ or st_blksize.
authormillert <millert@openbsd.org>
Sun, 28 Apr 2024 14:28:02 +0000 (14:28 +0000)
committermillert <millert@openbsd.org>
Sun, 28 Apr 2024 14:28:02 +0000 (14:28 +0000)
This can vastly improve write performance.  For unbuffered writes,
we now write up to INT_MAX instead of BUFSIZE.  For buffered writes,
write the largest multiple of the buffer size (which may be st_blksize).
From Apple via enh at google.  OK tb@

lib/libc/stdio/fvwrite.c

index d83de88..d615245 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: fvwrite.c,v 1.21 2023/10/06 16:41:02 millert Exp $ */
+/*     $OpenBSD: fvwrite.c,v 1.22 2024/04/28 14:28:02 millert Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -31,6 +31,7 @@
  * SUCH DAMAGE.
  */
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -76,11 +77,12 @@ __sfvwrite(FILE *fp, struct __suio *uio)
        }
        if (fp->_flags & __SNBF) {
                /*
-                * Unbuffered: write up to BUFSIZ bytes at a time.
+                * Unbuffered: write up to INT_MAX bytes at a time, to not
+                * truncate the value of len if it is greater than 2^31 bytes.
                 */
                do {
                        GETIOV(;);
-                       w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ));
+                       w = (*fp->_write)(fp->_cookie, p, MIN(len, INT_MAX));
                        if (w <= 0)
                                goto err;
                        p += w;
@@ -90,7 +92,8 @@ __sfvwrite(FILE *fp, struct __suio *uio)
                /*
                 * Fully buffered: fill partially full buffer, if any,
                 * and then flush.  If there is no partial buffer, write
-                * one _bf._size byte chunk directly (without copying).
+                * entire payload directly (without copying) up to a
+                * multiple of the buffer size.
                 *
                 * String output is a special case: write as many bytes
                 * as fit, but pretend we wrote everything.  This makes
@@ -134,7 +137,15 @@ __sfvwrite(FILE *fp, struct __suio *uio)
                                if (__sflush(fp))
                                        goto err;
                        } else if (len >= (w = fp->_bf._size)) {
-                               /* write directly */
+                               /*
+                                * Write directly up to INT_MAX or greatest
+                                * multiple of buffer size (whichever is
+                                * smaller), keeping in the memory buffer the
+                                * remaining part of payload that is smaller
+                                * than buffer size.
+                                */
+                               if (w != 0)
+                                       w = MIN(w * (len / w), INT_MAX);
                                w = (*fp->_write)(fp->_cookie, p, w);
                                if (w <= 0)
                                        goto err;