Import sendmail 8.13.7
[dragonfly.git] / contrib / sendmail-8.13.7 / libsm / fvwrite.c
bloba692781bab354271268aaade46a2be825d66faa9
1 /*
2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
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
8 * Chris Torek.
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.
15 #include <sm/gen.h>
16 SM_RCSID("@(#)$Id: fvwrite.c,v 1.49 2001/09/11 04:04:48 gshapiro Exp $")
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <signal.h>
22 #include <fcntl.h>
23 #include <sm/io.h>
24 #include <sm/setjmp.h>
25 #include <sm/conf.h>
26 #include "local.h"
27 #include "fvwrite.h"
30 ** SM_FVWRITE -- write memory regions and buffer for file pointer
32 ** Parameters:
33 ** fp -- the file pointer to write to
34 ** timeout -- time length for function to return by
35 ** uio -- the memory regions to write
37 ** Returns:
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) \
47 while (len == 0) \
48 { \
49 extra_work; \
50 p = iov->iov_base; \
51 len = iov->iov_len; \
52 iov++; \
55 int
56 sm_fvwrite(fp, timeout, uio)
57 register SM_FILE_T *fp;
58 int timeout;
59 register struct sm_uio *uio;
61 register size_t len;
62 register char *p;
63 register struct sm_iov *iov;
64 register int w, s;
65 char *nl;
66 int nlknown, nldist;
67 int fd;
68 struct timeval to;
70 if (uio->uio_resid == 0)
71 return 0;
73 /* make sure we can write */
74 if (cantwrite(fp))
76 errno = EBADF;
77 return SM_IO_EOF;
80 SM_CONVERT_TIME(fp, fd, timeout, &to);
82 iov = uio->uio_iov;
83 p = iov->iov_base;
84 len = iov->iov_len;
85 iov++;
86 if (fp->f_flags & SMNBF)
88 /* Unbuffered: write up to BUFSIZ bytes at a time. */
91 GETIOV(;);
92 errno = 0; /* needed to ensure EOF correctly found */
93 w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ));
94 if (w <= 0)
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);
103 w = 0;
105 else
107 p += w;
108 len -= w;
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).
129 GETIOV(;);
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;
136 int tsize;
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,
145 tsize + 1);
146 if (tbase == NULL)
148 errno = ENOMEM;
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;
156 w = fp->f_w;
157 errno = 0; /* needed to ensure EOF correctly found */
158 if (fp->f_flags & SMSTR)
160 if (len < (size_t) w)
161 w = len;
162 COPY(w); /* copy SM_MIN(fp->f_w,len), */
163 fp->f_w -= w;
164 fp->f_p += w;
165 w = len; /* but pretend copied all */
167 else if (fp->f_p > fp->f_bf.smb_base
168 && len > (size_t) w)
170 /* fill and flush */
171 COPY(w);
172 fp->f_p += w;
173 if (sm_flush(fp, &timeout))
174 goto err; /* errno set */
176 else if (len >= (size_t) (w = fp->f_bf.smb_size))
178 /* write directly */
179 w = (*fp->f_write)(fp, p, w);
180 if (w <= 0)
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);
189 w = 0;
192 else
194 /* fill and done */
195 w = len;
196 COPY(w);
197 fp->f_w -= w;
198 fp->f_p += w;
200 p += w;
201 len -= w;
202 } while ((uio->uio_resid -= w) != 0);
204 if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout))
205 goto err; /* errno set */
207 else
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).
217 nlknown = 0;
218 nldist = 0; /* XXX just to keep gcc happy */
221 GETIOV(nlknown = 0);
222 if (!nlknown)
224 nl = memchr((void *)p, '\n', len);
225 nldist = nl != NULL ? nl + 1 - p : len + 1;
226 nlknown = 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)
233 COPY(w);
234 /* fp->f_w -= w; */
235 fp->f_p += 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);
242 if (w <= 0)
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);
251 w = 0;
254 else
256 w = s;
257 COPY(w);
258 fp->f_w -= w;
259 fp->f_p += w;
261 if ((nldist -= w) == 0)
263 /* copied the newline: flush and forget */
264 if (sm_flush(fp, &timeout))
265 goto err; /* errno set */
266 nlknown = 0;
268 p += w;
269 len -= w;
270 } while ((uio->uio_resid -= w) != 0);
273 return 0;
275 err:
276 /* errno set before goto places us here */
277 fp->f_flags |= SMERR;
278 return SM_IO_EOF;