source: trunk/third/sendmail/libsm/fvwrite.c @ 19204

Revision 19204, 6.2 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
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.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
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.
13 */
14
15#include <sm/gen.h>
16SM_RCSID("@(#)$Id: fvwrite.c,v 1.1.1.1 2003-04-08 15:06:04 zacheiss 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"
28
29/*
30**  SM_FVWRITE -- write memory regions and buffer for file pointer
31**
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
36**
37**      Returns:
38**              Failure: returns SM_IO_EOF and sets errno
39**              Success: returns 0 (zero)
40**
41**      This routine is large and unsightly, but most of the ugliness due
42**      to the different kinds of output buffering handled here.
43*/
44
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++;                  \
53        }
54
55int
56sm_fvwrite(fp, timeout, uio)
57        register SM_FILE_T *fp;
58        int timeout;
59        register struct sm_uio *uio;
60{
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;
69
70        if (uio->uio_resid == 0)
71                return 0;
72
73        /* make sure we can write */
74        if (cantwrite(fp))
75        {
76                errno = EBADF;
77                return SM_IO_EOF;
78        }
79
80        SM_CONVERT_TIME(fp, fd, timeout, &to);
81
82        iov = uio->uio_iov;
83        p = iov->iov_base;
84        len = iov->iov_len;
85        iov++;
86        if (fp->f_flags & SMNBF)
87        {
88                /* Unbuffered: write up to BUFSIZ bytes at a time. */
89                do
90                {
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)
95                        {
96                                if (w == 0 && errno == 0)
97                                        break; /* EOF found */
98                                if (IS_IO_ERROR(fd, w, timeout))
99                                        goto err; /* errno set */
100
101                                /* write would block */
102                                SM_IO_WR_TIMEOUT(fp, fd, timeout);
103                                w = 0;
104                        }
105                        else
106                        {
107                                p += w;
108                                len -= w;
109                        }
110                } while ((uio->uio_resid -= w) != 0);
111        }
112        else if ((fp->f_flags & SMLBF) == 0)
113        {
114                /*
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).
119                **
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).
125                */
126
127                do
128                {
129                        GETIOV(;);
130                        if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR))
131                            || ((fp->f_flags & SMNOW) != 0))
132                            && (size_t) fp->f_w < len)
133                        {
134                                size_t blen = fp->f_p - fp->f_bf.smb_base;
135                                unsigned char *tbase;
136                                int tsize;
137
138                                /* Allocate space exponentially. */
139                                tsize = fp->f_bf.smb_size;
140                                do
141                                {
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)
147                                {
148                                        errno = ENOMEM;
149                                        goto err; /* errno set */
150                                }
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;
155                        }
156                        w = fp->f_w;
157                        errno = 0; /* needed to ensure EOF correctly found */
158                        if (fp->f_flags & SMSTR)
159                        {
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 */
166                        }
167                        else if (fp->f_p > fp->f_bf.smb_base
168                                 && len > (size_t) w)
169                        {
170                                /* fill and flush */
171                                COPY(w);
172                                fp->f_p += w;
173                                if (sm_flush(fp, &timeout))
174                                        goto err; /* errno set */
175                        }
176                        else if (len >= (size_t) (w = fp->f_bf.smb_size))
177                        {
178                                /* write directly */
179                                w = (*fp->f_write)(fp, p, w);
180                                if (w <= 0)
181                                {
182                                        if (w == 0 && errno == 0)
183                                                break; /* EOF found */
184                                        if (IS_IO_ERROR(fd, w, timeout))
185                                                goto err; /* errno set */
186
187                                        /* write would block */
188                                        SM_IO_WR_TIMEOUT(fp, fd, timeout);
189                                        w = 0;
190                                }
191                        }
192                        else
193                        {
194                                /* fill and done */
195                                w = len;
196                                COPY(w);
197                                fp->f_w -= w;
198                                fp->f_p += w;
199                        }
200                        p += w;
201                        len -= w;
202                } while ((uio->uio_resid -= w) != 0);
203
204                if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout))
205                        goto err; /* errno set */
206        }
207        else
208        {
209                /*
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).
215                */
216
217                nlknown = 0;
218                nldist = 0;     /* XXX just to keep gcc happy */
219                do
220                {
221                        GETIOV(nlknown = 0);
222                        if (!nlknown)
223                        {
224                                nl = memchr((void *)p, '\n', len);
225                                nldist = nl != NULL ? nl + 1 - p : len + 1;
226                                nlknown = 1;
227                        }
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)
232                        {
233                                COPY(w);
234                                /* fp->f_w -= w; */
235                                fp->f_p += w;
236                                if (sm_flush(fp, &timeout))
237                                        goto err; /* errno set */
238                        }
239                        else if (s >= (w = fp->f_bf.smb_size))
240                        {
241                                w = (*fp->f_write)(fp, p, w);
242                                if (w <= 0)
243                                {
244                                        if (w == 0 && errno == 0)
245                                                break; /* EOF found */
246                                        if (IS_IO_ERROR(fd, w, timeout))
247                                                goto err; /* errno set */
248
249                                        /* write would block */
250                                        SM_IO_WR_TIMEOUT(fp, fd, timeout);
251                                        w = 0;
252                                }
253                        }
254                        else
255                        {
256                                w = s;
257                                COPY(w);
258                                fp->f_w -= w;
259                                fp->f_p += w;
260                        }
261                        if ((nldist -= w) == 0)
262                        {
263                                /* copied the newline: flush and forget */
264                                if (sm_flush(fp, &timeout))
265                                        goto err; /* errno set */
266                                nlknown = 0;
267                        }
268                        p += w;
269                        len -= w;
270                } while ((uio->uio_resid -= w) != 0);
271        }
272
273        return 0;
274
275err:
276        /* errno set before goto places us here */
277        fp->f_flags |= SMERR;
278        return SM_IO_EOF;
279}
Note: See TracBrowser for help on using the repository browser.