Mon Jul 19 10:00:33 2021 UTC ()
There's no need to adjust `iov' in the error path.
Returning the amount written is all that's needed.
from RVP


(christos)
diff -r1.28 -r1.29 src/lib/libc/stdio/fvwrite.c

cvs diff -r1.28 -r1.29 src/lib/libc/stdio/fvwrite.c (switch to unified diff)

--- src/lib/libc/stdio/fvwrite.c 2021/07/16 12:34:10 1.28
+++ src/lib/libc/stdio/fvwrite.c 2021/07/19 10:00:32 1.29
@@ -1,259 +1,258 @@ @@ -1,259 +1,258 @@
1/* $NetBSD: fvwrite.c,v 1.28 2021/07/16 12:34:10 christos Exp $ */ 1/* $NetBSD: fvwrite.c,v 1.29 2021/07/19 10:00:32 christos Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1990, 1993 4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek. 8 * Chris Torek.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#if defined(LIBC_SCCS) && !defined(lint) 36#if defined(LIBC_SCCS) && !defined(lint)
37#if 0 37#if 0
38static char sccsid[] = "@(#)fvwrite.c 8.1 (Berkeley) 6/4/93"; 38static char sccsid[] = "@(#)fvwrite.c 8.1 (Berkeley) 6/4/93";
39#else 39#else
40__RCSID("$NetBSD: fvwrite.c,v 1.28 2021/07/16 12:34:10 christos Exp $"); 40__RCSID("$NetBSD: fvwrite.c,v 1.29 2021/07/19 10:00:32 christos Exp $");
41#endif 41#endif
42#endif /* LIBC_SCCS and not lint */ 42#endif /* LIBC_SCCS and not lint */
43 43
44#include <assert.h> 44#include <assert.h>
45#include <stddef.h> 45#include <stddef.h>
46#include <errno.h> 46#include <errno.h>
47#include <stdio.h> 47#include <stdio.h>
48#include <stdlib.h> 48#include <stdlib.h>
49#include <string.h> 49#include <string.h>
50#include "reentrant.h" 50#include "reentrant.h"
51#include "local.h" 51#include "local.h"
52#include "fvwrite.h" 52#include "fvwrite.h"
53 53
54static int 54static int
55flush_adj(FILE *fp, struct __suio *uio, struct __siov *iov, ssize_t w) 55flush_adj(FILE *fp, struct __suio *uio, ssize_t w)
56{ 56{
57 int rc; 57 int rc;
58 58
59 _DIAGASSERT(w >= 0); 59 _DIAGASSERT(w >= 0);
60 _DIAGASSERT(fp->_w >= 0); 60 _DIAGASSERT(fp->_w >= 0);
61 61
62 if ((rc = fflush(fp)) == 0) 62 if ((rc = fflush(fp)) == 0)
63 return 0; 63 return 0;
64 64
65 /* 65 /*
66 * If we have to return without writing the whole buffer, 66 * If we have to return without writing the whole buffer,
67 * adjust for how much fflush() has written for us. 67 * adjust for how much fflush() has written for us.
68 * `w' is the amt. of new user data just copied into our 68 * `w' is the amt. of new user data just copied into our
69 * internal buffer in _this_ fwrite() call. 69 * internal buffer in _this_ fwrite() call.
70 */ 70 */
71 if (fp->_w < w) { 71 if (fp->_w < w) {
72 /* some new data was also written */ 72 /* some new data was also written */
73 ssize_t i = w - fp->_w; 73 ssize_t i = w - fp->_w;
74 74
75 /* adjust amt. written */ 75 /* adjust amt. written */
76 uio->uio_resid -= i; 76 uio->uio_resid -= i;
77 iov->iov_len -= i; 
78 } else { 77 } else {
79 /* only old stuff was written */ 78 /* only old stuff was written */
80 79
81 /* adjust _p and _w so user can retry */ 80 /* adjust _p and _w so user can retry */
82 fp->_p -= w; 81 fp->_p -= w;
83 fp->_w += w; 82 fp->_w += w;
84 } 83 }
85 return rc; 84 return rc;
86} 85}
87 86
88/* 87/*
89 * Write some memory regions. Return zero on success, EOF on error. 88 * Write some memory regions. Return zero on success, EOF on error.
90 * 89 *
91 * This routine is large and unsightly, but most of the ugliness due 90 * This routine is large and unsightly, but most of the ugliness due
92 * to the three different kinds of output buffering is handled here. 91 * to the three different kinds of output buffering is handled here.
93 */ 92 */
94int 93int
95__sfvwrite(FILE *fp, struct __suio *uio) 94__sfvwrite(FILE *fp, struct __suio *uio)
96{ 95{
97 size_t len; 96 size_t len;
98 char *p; 97 char *p;
99 struct __siov *iov; 98 struct __siov *iov;
100 int s; 99 int s;
101 ssize_t w; 100 ssize_t w;
102 char *nl; 101 char *nl;
103 size_t nlknown, nldist; 102 size_t nlknown, nldist;
104 103
105 _DIAGASSERT(fp != NULL); 104 _DIAGASSERT(fp != NULL);
106 _DIAGASSERT(uio != NULL); 105 _DIAGASSERT(uio != NULL);
107 106
108 if ((ssize_t)uio->uio_resid < 0) { 107 if ((ssize_t)uio->uio_resid < 0) {
109 errno = EINVAL; 108 errno = EINVAL;
110 return EOF; 109 return EOF;
111 } 110 }
112 if (uio->uio_resid == 0) 111 if (uio->uio_resid == 0)
113 return 0; 112 return 0;
114 /* make sure we can write */ 113 /* make sure we can write */
115 if (cantwrite(fp)) { 114 if (cantwrite(fp)) {
116 errno = EBADF; 115 errno = EBADF;
117 return EOF; 116 return EOF;
118 } 117 }
119 118
120#define MIN(a, b) ((a) < (b) ? (a) : (b)) 119#define MIN(a, b) ((a) < (b) ? (a) : (b))
121#define COPY(n) (void)memcpy(fp->_p, p, (size_t)(n)) 120#define COPY(n) (void)memcpy(fp->_p, p, (size_t)(n))
122 121
123 iov = uio->uio_iov; 122 iov = uio->uio_iov;
124 p = iov->iov_base; 123 p = iov->iov_base;
125 len = iov->iov_len; 124 len = iov->iov_len;
126 iov++; 125 iov++;
127#define GETIOV(extra_work) \ 126#define GETIOV(extra_work) \
128 while (len == 0) { \ 127 while (len == 0) { \
129 extra_work; \ 128 extra_work; \
130 p = iov->iov_base; \ 129 p = iov->iov_base; \
131 len = iov->iov_len; \ 130 len = iov->iov_len; \
132 iov++; \ 131 iov++; \
133 } 132 }
134#define WRITE(nw) \ 133#define WRITE(nw) \
135 w = (*fp->_write)(fp->_cookie, p, nw); \ 134 w = (*fp->_write)(fp->_cookie, p, nw); \
136 if (w <= 0) \ 135 if (w <= 0) \
137 goto err 136 goto err
138#define FLUSH(nw) \ 137#define FLUSH(nw) \
139 if (flush_adj(fp, uio, iov - 1, nw)) \ 138 if (flush_adj(fp, uio, nw)) \
140 goto err 139 goto err
141 140
142 if (fp->_flags & __SNBF) { 141 if (fp->_flags & __SNBF) {
143 /* 142 /*
144 * Unbuffered: write up to BUFSIZ bytes at a time. 143 * Unbuffered: write up to BUFSIZ bytes at a time.
145 */ 144 */
146 do { 145 do {
147 GETIOV(;); 146 GETIOV(;);
148 WRITE(MIN(len, BUFSIZ)); 147 WRITE(MIN(len, BUFSIZ));
149 p += w; 148 p += w;
150 len -= w; 149 len -= w;
151 } while ((uio->uio_resid -= w) != 0); 150 } while ((uio->uio_resid -= w) != 0);
152 } else if ((fp->_flags & __SLBF) == 0) { 151 } else if ((fp->_flags & __SLBF) == 0) {
153 /* 152 /*
154 * Fully buffered: fill partially full buffer, if any, 153 * Fully buffered: fill partially full buffer, if any,
155 * and then flush. If there is no partial buffer, write 154 * and then flush. If there is no partial buffer, write
156 * one _bf._size byte chunk directly (without copying). 155 * one _bf._size byte chunk directly (without copying).
157 * 156 *
158 * String output is a special case: write as many bytes 157 * String output is a special case: write as many bytes
159 * as fit, but pretend we wrote everything. This makes 158 * as fit, but pretend we wrote everything. This makes
160 * snprintf() return the number of bytes needed, rather 159 * snprintf() return the number of bytes needed, rather
161 * than the number used, and avoids its write function 160 * than the number used, and avoids its write function
162 * (so that the write function can be invalid). 161 * (so that the write function can be invalid).
163 */ 162 */
164 do { 163 do {
165 GETIOV(;); 164 GETIOV(;);
166 if ((fp->_flags & (__SALC | __SSTR)) == 165 if ((fp->_flags & (__SALC | __SSTR)) ==
167 (__SALC | __SSTR) && (size_t)fp->_w < len) { 166 (__SALC | __SSTR) && (size_t)fp->_w < len) {
168 ptrdiff_t blen = fp->_p - fp->_bf._base; 167 ptrdiff_t blen = fp->_p - fp->_bf._base;
169 unsigned char *_base; 168 unsigned char *_base;
170 int _size; 169 int _size;
171 170
172 /* Allocate space exponentially. */ 171 /* Allocate space exponentially. */
173 _size = fp->_bf._size; 172 _size = fp->_bf._size;
174 do { 173 do {
175 _size = (_size << 1) + 1; 174 _size = (_size << 1) + 1;
176 } while ((size_t)_size < blen + len); 175 } while ((size_t)_size < blen + len);
177 _base = realloc(fp->_bf._base, 176 _base = realloc(fp->_bf._base,
178 (size_t)(_size + 1)); 177 (size_t)(_size + 1));
179 if (_base == NULL) 178 if (_base == NULL)
180 goto err; 179 goto err;
181 fp->_w += _size - fp->_bf._size; 180 fp->_w += _size - fp->_bf._size;
182 fp->_bf._base = _base; 181 fp->_bf._base = _base;
183 fp->_bf._size = _size; 182 fp->_bf._size = _size;
184 fp->_p = _base + blen; 183 fp->_p = _base + blen;
185 } 184 }
186 w = fp->_w; 185 w = fp->_w;
187 if (fp->_flags & __SSTR) { 186 if (fp->_flags & __SSTR) {
188 if (len < (size_t)w) 187 if (len < (size_t)w)
189 w = len; 188 w = len;
190 COPY(w); /* copy MIN(fp->_w,len), */ 189 COPY(w); /* copy MIN(fp->_w,len), */
191 fp->_w -= (int)w; 190 fp->_w -= (int)w;
192 fp->_p += w; 191 fp->_p += w;
193 w = len; /* but pretend copied all */ 192 w = len; /* but pretend copied all */
194 } else if (fp->_p > fp->_bf._base && len > (size_t)w) { 193 } else if (fp->_p > fp->_bf._base && len > (size_t)w) {
195 /* fill and flush */ 194 /* fill and flush */
196 COPY(w); 195 COPY(w);
197 /* fp->_w -= w; */ /* unneeded */ 196 /* fp->_w -= w; */ /* unneeded */
198 fp->_p += w; 197 fp->_p += w;
199 FLUSH(w); 198 FLUSH(w);
200 } else if (len >= (size_t)(w = fp->_bf._size)) { 199 } else if (len >= (size_t)(w = fp->_bf._size)) {
201 /* write directly */ 200 /* write directly */
202 WRITE((size_t)w); 201 WRITE((size_t)w);
203 } else { 202 } else {
204 /* fill and done */ 203 /* fill and done */
205 w = len; 204 w = len;
206 COPY(w); 205 COPY(w);
207 fp->_w -= (int)w; 206 fp->_w -= (int)w;
208 fp->_p += w; 207 fp->_p += w;
209 } 208 }
210 p += w; 209 p += w;
211 len -= w; 210 len -= w;
212 } while ((uio->uio_resid -= w) != 0); 211 } while ((uio->uio_resid -= w) != 0);
213 } else { 212 } else {
214 /* 213 /*
215 * Line buffered: like fully buffered, but we 214 * Line buffered: like fully buffered, but we
216 * must check for newlines. Compute the distance 215 * must check for newlines. Compute the distance
217 * to the first newline (including the newline), 216 * to the first newline (including the newline),
218 * or `infinity' if there is none, then pretend 217 * or `infinity' if there is none, then pretend
219 * that the amount to write is MIN(len,nldist). 218 * that the amount to write is MIN(len,nldist).
220 */ 219 */
221 nlknown = 0; 220 nlknown = 0;
222 nldist = 0; /* XXX just to keep gcc happy */ 221 nldist = 0; /* XXX just to keep gcc happy */
223 do { 222 do {
224 GETIOV(nlknown = 0); 223 GETIOV(nlknown = 0);
225 if (!nlknown) { 224 if (!nlknown) {
226 nl = memchr(p, '\n', len); 225 nl = memchr(p, '\n', len);
227 nldist = nl ? (size_t)(nl + 1 - p) : len + 1; 226 nldist = nl ? (size_t)(nl + 1 - p) : len + 1;
228 nlknown = 1; 227 nlknown = 1;
229 } 228 }
230 s = (int)MIN(len, nldist); 229 s = (int)MIN(len, nldist);
231 w = fp->_w + fp->_bf._size; 230 w = fp->_w + fp->_bf._size;
232 if (fp->_p > fp->_bf._base && s > w) { 231 if (fp->_p > fp->_bf._base && s > w) {
233 COPY(w); 232 COPY(w);
234 /* fp->_w -= w; */ 233 /* fp->_w -= w; */
235 fp->_p += w; 234 fp->_p += w;
236 FLUSH(w); 235 FLUSH(w);
237 } else if (s >= (w = fp->_bf._size)) { 236 } else if (s >= (w = fp->_bf._size)) {
238 WRITE((size_t)w); 237 WRITE((size_t)w);
239 } else { 238 } else {
240 w = s; 239 w = s;
241 COPY(w); 240 COPY(w);
242 fp->_w -= (int)w; 241 fp->_w -= (int)w;
243 fp->_p += w; 242 fp->_p += w;
244 } 243 }
245 if ((nldist -= w) == 0) { 244 if ((nldist -= w) == 0) {
246 /* copied the newline: flush and forget */ 245 /* copied the newline: flush and forget */
247 FLUSH(w); 246 FLUSH(w);
248 nlknown = 0; 247 nlknown = 0;
249 } 248 }
250 p += w; 249 p += w;
251 len -= w; 250 len -= w;
252 } while ((uio->uio_resid -= w) != 0); 251 } while ((uio->uio_resid -= w) != 0);
253 } 252 }
254 return 0; 253 return 0;
255 254
256err: 255err:
257 fp->_flags |= __SERR; 256 fp->_flags |= __SERR;
258 return EOF; 257 return EOF;
259} 258}