1155192Srwatson/* 2155192Srwatson * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3155192Srwatson * All rights reserved. 4155192Srwatson * Copyright (c) 1990, 1993 5155192Srwatson * The Regents of the University of California. All rights reserved. 6155192Srwatson * 7155192Srwatson * This code is derived from software contributed to Berkeley by 8155192Srwatson * Chris Torek. 9155192Srwatson * 10155192Srwatson * By using this file, you agree to the terms and conditions set 11155192Srwatson * forth in the LICENSE file which can be found at the top level of 12155192Srwatson * the sendmail distribution. 13155192Srwatson */ 14155192Srwatson 15155192Srwatson#include <sm/gen.h> 16155192SrwatsonSM_RCSID("@(#)$Id: fvwrite.c,v 1.49 2001/09/11 04:04:48 gshapiro Exp $") 17155192Srwatson#include <stdlib.h> 18155192Srwatson#include <unistd.h> 19155192Srwatson#include <string.h> 20155192Srwatson#include <errno.h> 21155192Srwatson#include <signal.h> 22155192Srwatson#include <fcntl.h> 23155192Srwatson#include <sm/io.h> 24155192Srwatson#include <sm/setjmp.h> 25155192Srwatson#include <sm/conf.h> 26155192Srwatson#include "local.h" 27155192Srwatson#include "fvwrite.h" 28155192Srwatson 29155192Srwatson/* 30178186Srwatson** SM_FVWRITE -- write memory regions and buffer for file pointer 31178186Srwatson** 32178186Srwatson** Parameters: 33155192Srwatson** fp -- the file pointer to write to 34155192Srwatson** timeout -- time length for function to return by 35155192Srwatson** uio -- the memory regions to write 36155192Srwatson** 37155192Srwatson** Returns: 38155192Srwatson** Failure: returns SM_IO_EOF and sets errno 39155192Srwatson** Success: returns 0 (zero) 40155192Srwatson** 41155192Srwatson** This routine is large and unsightly, but most of the ugliness due 42159277Srwatson** to the different kinds of output buffering handled here. 43155192Srwatson*/ 44155192Srwatson 45155192Srwatson#define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n)) 46155192Srwatson#define GETIOV(extra_work) \ 47155192Srwatson while (len == 0) \ 48155192Srwatson { \ 49155192Srwatson extra_work; \ 50155192Srwatson p = iov->iov_base; \ 51155192Srwatson len = iov->iov_len; \ 52155192Srwatson iov++; \ 53155192Srwatson } 54155192Srwatson 55170196Srwatsonint 56170196Srwatsonsm_fvwrite(fp, timeout, uio) 57170196Srwatson register SM_FILE_T *fp; 58170196Srwatson int timeout; 59155192Srwatson register struct sm_uio *uio; 60155192Srwatson{ 61155192Srwatson register size_t len; 62155192Srwatson register char *p; 63155192Srwatson register struct sm_iov *iov; 64170585Srwatson register int w, s; 65155192Srwatson char *nl; 66155192Srwatson int nlknown, nldist; 67155192Srwatson int fd; 68155192Srwatson struct timeval to; 69155192Srwatson 70155192Srwatson if (uio->uio_resid == 0) 71155192Srwatson return 0; 72155192Srwatson 73155192Srwatson /* make sure we can write */ 74155192Srwatson if (cantwrite(fp)) 75155192Srwatson { 76155192Srwatson errno = EBADF; 77155192Srwatson return SM_IO_EOF; 78155192Srwatson } 79155192Srwatson 80155192Srwatson SM_CONVERT_TIME(fp, fd, timeout, &to); 81155192Srwatson 82155192Srwatson iov = uio->uio_iov; 83155192Srwatson p = iov->iov_base; 84155192Srwatson len = iov->iov_len; 85155192Srwatson iov++; 86155192Srwatson if (fp->f_flags & SMNBF) 87155192Srwatson { 88155192Srwatson /* Unbuffered: write up to BUFSIZ bytes at a time. */ 89155192Srwatson do 90155192Srwatson { 91155192Srwatson GETIOV(;); 92155192Srwatson errno = 0; /* needed to ensure EOF correctly found */ 93155192Srwatson w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ)); 94155192Srwatson if (w <= 0) 95155192Srwatson { 96155192Srwatson if (w == 0 && errno == 0) 97155192Srwatson break; /* EOF found */ 98155192Srwatson if (IS_IO_ERROR(fd, w, timeout)) 99155192Srwatson goto err; /* errno set */ 100155192Srwatson 101155192Srwatson /* write would block */ 102155192Srwatson SM_IO_WR_TIMEOUT(fp, fd, timeout); 103155192Srwatson w = 0; 104155192Srwatson } 105155192Srwatson else 106155192Srwatson { 107155192Srwatson p += w; 108155192Srwatson len -= w; 109155192Srwatson } 110155192Srwatson } while ((uio->uio_resid -= w) != 0); 111155192Srwatson } 112155192Srwatson else if ((fp->f_flags & SMLBF) == 0) 113155192Srwatson { 114155192Srwatson /* 115155192Srwatson ** Not SMLBF (line-buffered). Either SMFBF or SMNOW 116155192Srwatson ** buffered: fill partially full buffer, if any, 117155192Srwatson ** and then flush. If there is no partial buffer, write 118155192Srwatson ** one bf._size byte chunk directly (without copying). 119155192Srwatson ** 120155192Srwatson ** String output is a special case: write as many bytes 121155192Srwatson ** as fit, but pretend we wrote everything. This makes 122155192Srwatson ** snprintf() return the number of bytes needed, rather 123155192Srwatson ** than the number used, and avoids its write function 124155192Srwatson ** (so that the write function can be invalid). 125155192Srwatson */ 126155192Srwatson 127155192Srwatson do 128155192Srwatson { 129155192Srwatson GETIOV(;); 130155192Srwatson if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR)) 131155192Srwatson || ((fp->f_flags & SMNOW) != 0)) 132155192Srwatson && (size_t) fp->f_w < len) 133155192Srwatson { 134155192Srwatson size_t blen = fp->f_p - fp->f_bf.smb_base; 135155192Srwatson unsigned char *tbase; 136155192Srwatson int tsize; 137155192Srwatson 138155192Srwatson /* Allocate space exponentially. */ 139155192Srwatson tsize = fp->f_bf.smb_size; 140155192Srwatson do 141155192Srwatson { 142155192Srwatson tsize = (tsize << 1) + 1; 143155192Srwatson } while ((size_t) tsize < blen + len); 144155192Srwatson tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base, 145155192Srwatson tsize + 1); 146155192Srwatson if (tbase == NULL) 147155192Srwatson { 148155192Srwatson errno = ENOMEM; 149155192Srwatson goto err; /* errno set */ 150155192Srwatson } 151155192Srwatson fp->f_w += tsize - fp->f_bf.smb_size; 152155192Srwatson fp->f_bf.smb_base = tbase; 153155192Srwatson fp->f_bf.smb_size = tsize; 154155192Srwatson fp->f_p = tbase + blen; 155155192Srwatson } 156155192Srwatson w = fp->f_w; 157155192Srwatson errno = 0; /* needed to ensure EOF correctly found */ 158155192Srwatson if (fp->f_flags & SMSTR) 159155192Srwatson { 160155192Srwatson if (len < (size_t) w) 161155192Srwatson w = len; 162155192Srwatson COPY(w); /* copy SM_MIN(fp->f_w,len), */ 163155192Srwatson fp->f_w -= w; 164155192Srwatson fp->f_p += w; 165155192Srwatson w = len; /* but pretend copied all */ 166155192Srwatson } 167155192Srwatson else if (fp->f_p > fp->f_bf.smb_base 168155192Srwatson && len > (size_t) w) 169155192Srwatson { 170155192Srwatson /* fill and flush */ 171155192Srwatson COPY(w); 172155192Srwatson fp->f_p += w; 173155192Srwatson if (sm_flush(fp, &timeout)) 174155192Srwatson goto err; /* errno set */ 175155192Srwatson } 176155192Srwatson else if (len >= (size_t) (w = fp->f_bf.smb_size)) 177155192Srwatson { 178155192Srwatson /* write directly */ 179155192Srwatson w = (*fp->f_write)(fp, p, w); 180155192Srwatson if (w <= 0) 181155192Srwatson { 182155192Srwatson if (w == 0 && errno == 0) 183155192Srwatson break; /* EOF found */ 184155192Srwatson if (IS_IO_ERROR(fd, w, timeout)) 185155192Srwatson goto err; /* errno set */ 186155192Srwatson 187155192Srwatson /* write would block */ 188155192Srwatson SM_IO_WR_TIMEOUT(fp, fd, timeout); 189155192Srwatson w = 0; 190155192Srwatson } 191155192Srwatson } 192155192Srwatson else 193155192Srwatson { 194155192Srwatson /* fill and done */ 195155192Srwatson w = len; 196155192Srwatson COPY(w); 197155192Srwatson fp->f_w -= w; 198155192Srwatson fp->f_p += w; 199155192Srwatson } 200155192Srwatson p += w; 201155192Srwatson len -= w; 202155192Srwatson } while ((uio->uio_resid -= w) != 0); 203155192Srwatson 204155192Srwatson if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout)) 205155192Srwatson goto err; /* errno set */ 206155192Srwatson } 207155192Srwatson else 208155192Srwatson { 209155192Srwatson /* 210155192Srwatson ** Line buffered: like fully buffered, but we 211155192Srwatson ** must check for newlines. Compute the distance 212155192Srwatson ** to the first newline (including the newline), 213155192Srwatson ** or `infinity' if there is none, then pretend 214155192Srwatson ** that the amount to write is SM_MIN(len,nldist). 215155192Srwatson */ 216155192Srwatson 217155192Srwatson nlknown = 0; 218155192Srwatson nldist = 0; /* XXX just to keep gcc happy */ 219155192Srwatson do 220155192Srwatson { 221155192Srwatson GETIOV(nlknown = 0); 222155192Srwatson if (!nlknown) 223155192Srwatson { 224155192Srwatson nl = memchr((void *)p, '\n', len); 225155192Srwatson nldist = nl != NULL ? nl + 1 - p : len + 1; 226155192Srwatson nlknown = 1; 227155192Srwatson } 228155192Srwatson s = SM_MIN(len, ((size_t) nldist)); 229155192Srwatson w = fp->f_w + fp->f_bf.smb_size; 230155192Srwatson errno = 0; /* needed to ensure EOF correctly found */ 231155192Srwatson if (fp->f_p > fp->f_bf.smb_base && s > w) 232155192Srwatson { 233155192Srwatson COPY(w); 234155192Srwatson /* fp->f_w -= w; */ 235155192Srwatson fp->f_p += w; 236155192Srwatson if (sm_flush(fp, &timeout)) 237155192Srwatson goto err; /* errno set */ 238155192Srwatson } 239155192Srwatson else if (s >= (w = fp->f_bf.smb_size)) 240155192Srwatson { 241155192Srwatson w = (*fp->f_write)(fp, p, w); 242155192Srwatson if (w <= 0) 243155192Srwatson { 244155192Srwatson if (w == 0 && errno == 0) 245155192Srwatson break; /* EOF found */ 246155192Srwatson if (IS_IO_ERROR(fd, w, timeout)) 247155192Srwatson goto err; /* errno set */ 248155192Srwatson 249155192Srwatson /* write would block */ 250155192Srwatson SM_IO_WR_TIMEOUT(fp, fd, timeout); 251155192Srwatson w = 0; 252155192Srwatson } 253155192Srwatson } 254155192Srwatson else 255155192Srwatson { 256155192Srwatson w = s; 257155192Srwatson COPY(w); 258155192Srwatson fp->f_w -= w; 259155192Srwatson fp->f_p += w; 260155192Srwatson } 261155192Srwatson if ((nldist -= w) == 0) 262155192Srwatson { 263155192Srwatson /* copied the newline: flush and forget */ 264155192Srwatson if (sm_flush(fp, &timeout)) 265155192Srwatson goto err; /* errno set */ 266155192Srwatson nlknown = 0; 267155192Srwatson } 268155192Srwatson p += w; 269155192Srwatson len -= w; 270155192Srwatson } while ((uio->uio_resid -= w) != 0); 271155192Srwatson } 272155192Srwatson 273155192Srwatson return 0; 274155192Srwatson 275155192Srwatsonerr: 276155192Srwatson /* errno set before goto places us here */ 277155192Srwatson fp->f_flags |= SMERR; 278155192Srwatson return SM_IO_EOF; 279155192Srwatson} 280155192Srwatson