summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/libsm/fvwrite.c
diff options
context:
space:
mode:
authorgshapiro <gshapiro@FreeBSD.org>2002-02-17 21:56:45 +0000
committergshapiro <gshapiro@FreeBSD.org>2002-02-17 21:56:45 +0000
commit8449595fe97f4474b9b9a7e4edee1ef35dcff393 (patch)
treee7a33b132264d449a512ddf4a8685df097669c1d /contrib/sendmail/libsm/fvwrite.c
parent289b381b31415647269c7520d881017e2dcb27f1 (diff)
downloadFreeBSD-src-8449595fe97f4474b9b9a7e4edee1ef35dcff393.zip
FreeBSD-src-8449595fe97f4474b9b9a7e4edee1ef35dcff393.tar.gz
Import sendmail 8.12.2
Diffstat (limited to 'contrib/sendmail/libsm/fvwrite.c')
-rw-r--r--contrib/sendmail/libsm/fvwrite.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/contrib/sendmail/libsm/fvwrite.c b/contrib/sendmail/libsm/fvwrite.c
new file mode 100644
index 0000000..a692781
--- /dev/null
+++ b/contrib/sendmail/libsm/fvwrite.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fvwrite.c,v 1.49 2001/09/11 04:04:48 gshapiro Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sm/io.h>
+#include <sm/setjmp.h>
+#include <sm/conf.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_FVWRITE -- write memory regions and buffer for file pointer
+**
+** Parameters:
+** fp -- the file pointer to write to
+** timeout -- time length for function to return by
+** uio -- the memory regions to write
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns 0 (zero)
+**
+** This routine is large and unsightly, but most of the ugliness due
+** to the different kinds of output buffering handled here.
+*/
+
+#define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n))
+#define GETIOV(extra_work) \
+ while (len == 0) \
+ { \
+ extra_work; \
+ p = iov->iov_base; \
+ len = iov->iov_len; \
+ iov++; \
+ }
+
+int
+sm_fvwrite(fp, timeout, uio)
+ register SM_FILE_T *fp;
+ int timeout;
+ register struct sm_uio *uio;
+{
+ register size_t len;
+ register char *p;
+ register struct sm_iov *iov;
+ register int w, s;
+ char *nl;
+ int nlknown, nldist;
+ int fd;
+ struct timeval to;
+
+ if (uio->uio_resid == 0)
+ return 0;
+
+ /* make sure we can write */
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+
+ iov = uio->uio_iov;
+ p = iov->iov_base;
+ len = iov->iov_len;
+ iov++;
+ if (fp->f_flags & SMNBF)
+ {
+ /* Unbuffered: write up to BUFSIZ bytes at a time. */
+ do
+ {
+ GETIOV(;);
+ errno = 0; /* needed to ensure EOF correctly found */
+ w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ));
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ else
+ {
+ p += w;
+ len -= w;
+ }
+ } while ((uio->uio_resid -= w) != 0);
+ }
+ else if ((fp->f_flags & SMLBF) == 0)
+ {
+ /*
+ ** Not SMLBF (line-buffered). Either SMFBF or SMNOW
+ ** 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).
+ **
+ ** String output is a special case: write as many bytes
+ ** as fit, but pretend we wrote everything. This makes
+ ** snprintf() return the number of bytes needed, rather
+ ** than the number used, and avoids its write function
+ ** (so that the write function can be invalid).
+ */
+
+ do
+ {
+ GETIOV(;);
+ if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR))
+ || ((fp->f_flags & SMNOW) != 0))
+ && (size_t) fp->f_w < len)
+ {
+ size_t blen = fp->f_p - fp->f_bf.smb_base;
+ unsigned char *tbase;
+ int tsize;
+
+ /* Allocate space exponentially. */
+ tsize = fp->f_bf.smb_size;
+ do
+ {
+ tsize = (tsize << 1) + 1;
+ } while ((size_t) tsize < blen + len);
+ tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base,
+ tsize + 1);
+ if (tbase == NULL)
+ {
+ errno = ENOMEM;
+ goto err; /* errno set */
+ }
+ fp->f_w += tsize - fp->f_bf.smb_size;
+ fp->f_bf.smb_base = tbase;
+ fp->f_bf.smb_size = tsize;
+ fp->f_p = tbase + blen;
+ }
+ w = fp->f_w;
+ errno = 0; /* needed to ensure EOF correctly found */
+ if (fp->f_flags & SMSTR)
+ {
+ if (len < (size_t) w)
+ w = len;
+ COPY(w); /* copy SM_MIN(fp->f_w,len), */
+ fp->f_w -= w;
+ fp->f_p += w;
+ w = len; /* but pretend copied all */
+ }
+ else if (fp->f_p > fp->f_bf.smb_base
+ && len > (size_t) w)
+ {
+ /* fill and flush */
+ COPY(w);
+ fp->f_p += w;
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else if (len >= (size_t) (w = fp->f_bf.smb_size))
+ {
+ /* write directly */
+ w = (*fp->f_write)(fp, p, w);
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ }
+ else
+ {
+ /* fill and done */
+ w = len;
+ COPY(w);
+ fp->f_w -= w;
+ fp->f_p += w;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+
+ if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else
+ {
+ /*
+ ** Line buffered: like fully buffered, but we
+ ** must check for newlines. Compute the distance
+ ** to the first newline (including the newline),
+ ** or `infinity' if there is none, then pretend
+ ** that the amount to write is SM_MIN(len,nldist).
+ */
+
+ nlknown = 0;
+ nldist = 0; /* XXX just to keep gcc happy */
+ do
+ {
+ GETIOV(nlknown = 0);
+ if (!nlknown)
+ {
+ nl = memchr((void *)p, '\n', len);
+ nldist = nl != NULL ? nl + 1 - p : len + 1;
+ nlknown = 1;
+ }
+ s = SM_MIN(len, ((size_t) nldist));
+ w = fp->f_w + fp->f_bf.smb_size;
+ errno = 0; /* needed to ensure EOF correctly found */
+ if (fp->f_p > fp->f_bf.smb_base && s > w)
+ {
+ COPY(w);
+ /* fp->f_w -= w; */
+ fp->f_p += w;
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else if (s >= (w = fp->f_bf.smb_size))
+ {
+ w = (*fp->f_write)(fp, p, w);
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ }
+ else
+ {
+ w = s;
+ COPY(w);
+ fp->f_w -= w;
+ fp->f_p += w;
+ }
+ if ((nldist -= w) == 0)
+ {
+ /* copied the newline: flush and forget */
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ nlknown = 0;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ }
+
+ return 0;
+
+err:
+ /* errno set before goto places us here */
+ fp->f_flags |= SMERR;
+ return SM_IO_EOF;
+}
OpenPOWER on IntegriCloud