2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENSE file which can be found at the top level of
12 * the sendmail distribution.
16 SM_RCSID("@(#)$Id: fvwrite.c,v 1.49 2001/09/11 04:04:48 gshapiro Exp $")
24 #include <sm/setjmp.h>
30 ** SM_FVWRITE -- write memory regions and buffer for file pointer
33 ** fp -- the file pointer to write to
34 ** timeout -- time length for function to return by
35 ** uio -- the memory regions to write
38 ** Failure: returns SM_IO_EOF and sets errno
39 ** Success: returns 0 (zero)
41 ** This routine is large and unsightly, but most of the ugliness due
42 ** to the different kinds of output buffering handled here.
45 #define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n))
46 #define GETIOV(extra_work) \
56 sm_fvwrite(fp, timeout, uio)
57 register SM_FILE_T *fp;
59 register struct sm_uio *uio;
63 register struct sm_iov *iov;
70 if (uio->uio_resid == 0)
73 /* make sure we can write */
80 SM_CONVERT_TIME(fp, fd, timeout, &to);
86 if (fp->f_flags & SMNBF)
88 /* Unbuffered: write up to BUFSIZ bytes at a time. */
92 errno = 0; /* needed to ensure EOF correctly found */
93 w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ));
96 if (w == 0 && errno == 0)
97 break; /* EOF found */
98 if (IS_IO_ERROR(fd, w, timeout))
99 goto err; /* errno set */
101 /* write would block */
102 SM_IO_WR_TIMEOUT(fp, fd, timeout);
110 } while ((uio->uio_resid -= w) != 0);
112 else if ((fp->f_flags & SMLBF) == 0)
115 ** Not SMLBF (line-buffered). Either SMFBF or SMNOW
116 ** buffered: fill partially full buffer, if any,
117 ** and then flush. If there is no partial buffer, write
118 ** one bf._size byte chunk directly (without copying).
120 ** String output is a special case: write as many bytes
121 ** as fit, but pretend we wrote everything. This makes
122 ** snprintf() return the number of bytes needed, rather
123 ** than the number used, and avoids its write function
124 ** (so that the write function can be invalid).
130 if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR))
131 || ((fp->f_flags & SMNOW) != 0))
132 && (size_t) fp->f_w < len)
134 size_t blen = fp->f_p - fp->f_bf.smb_base;
135 unsigned char *tbase;
138 /* Allocate space exponentially. */
139 tsize = fp->f_bf.smb_size;
142 tsize = (tsize << 1) + 1;
143 } while ((size_t) tsize < blen + len);
144 tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base,
149 goto err; /* errno set */
151 fp->f_w += tsize - fp->f_bf.smb_size;
152 fp->f_bf.smb_base = tbase;
153 fp->f_bf.smb_size = tsize;
154 fp->f_p = tbase + blen;
157 errno = 0; /* needed to ensure EOF correctly found */
158 if (fp->f_flags & SMSTR)
160 if (len < (size_t) w)
162 COPY(w); /* copy SM_MIN(fp->f_w,len), */
165 w = len; /* but pretend copied all */
167 else if (fp->f_p > fp->f_bf.smb_base
173 if (sm_flush(fp, &timeout))
174 goto err; /* errno set */
176 else if (len >= (size_t) (w = fp->f_bf.smb_size))
179 w = (*fp->f_write)(fp, p, w);
182 if (w == 0 && errno == 0)
183 break; /* EOF found */
184 if (IS_IO_ERROR(fd, w, timeout))
185 goto err; /* errno set */
187 /* write would block */
188 SM_IO_WR_TIMEOUT(fp, fd, timeout);
202 } while ((uio->uio_resid -= w) != 0);
204 if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout))
205 goto err; /* errno set */
210 ** Line buffered: like fully buffered, but we
211 ** must check for newlines. Compute the distance
212 ** to the first newline (including the newline),
213 ** or `infinity' if there is none, then pretend
214 ** that the amount to write is SM_MIN(len,nldist).
218 nldist = 0; /* XXX just to keep gcc happy */
224 nl = memchr((void *)p, '\n', len);
225 nldist = nl != NULL ? nl + 1 - p : len + 1;
228 s = SM_MIN(len, ((size_t) nldist));
229 w = fp->f_w + fp->f_bf.smb_size;
230 errno = 0; /* needed to ensure EOF correctly found */
231 if (fp->f_p > fp->f_bf.smb_base && s > w)
236 if (sm_flush(fp, &timeout))
237 goto err; /* errno set */
239 else if (s >= (w = fp->f_bf.smb_size))
241 w = (*fp->f_write)(fp, p, w);
244 if (w == 0 && errno == 0)
245 break; /* EOF found */
246 if (IS_IO_ERROR(fd, w, timeout))
247 goto err; /* errno set */
249 /* write would block */
250 SM_IO_WR_TIMEOUT(fp, fd, timeout);
261 if ((nldist -= w) == 0)
263 /* copied the newline: flush and forget */
264 if (sm_flush(fp, &timeout))
265 goto err; /* errno set */
270 } while ((uio->uio_resid -= w) != 0);
276 /* errno set before goto places us here */
277 fp->f_flags |= SMERR;