140266059SGregory Neil Shapiro /* 240266059SGregory Neil Shapiro * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers. 340266059SGregory Neil Shapiro * All rights reserved. 440266059SGregory Neil Shapiro * Copyright (c) 1990, 1993 540266059SGregory Neil Shapiro * The Regents of the University of California. All rights reserved. 640266059SGregory Neil Shapiro * 740266059SGregory Neil Shapiro * This code is derived from software contributed to Berkeley by 840266059SGregory Neil Shapiro * Chris Torek. 940266059SGregory Neil Shapiro * 1040266059SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 1140266059SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 1240266059SGregory Neil Shapiro * the sendmail distribution. 1340266059SGregory Neil Shapiro */ 1440266059SGregory Neil Shapiro 1540266059SGregory Neil Shapiro #include <sm/gen.h> 1694c01205SGregory Neil Shapiro SM_RCSID("@(#)$Id: fvwrite.c,v 1.50 2013-11-22 20:51:42 ca Exp $") 1740266059SGregory Neil Shapiro #include <stdlib.h> 1840266059SGregory Neil Shapiro #include <unistd.h> 1940266059SGregory Neil Shapiro #include <string.h> 2040266059SGregory Neil Shapiro #include <errno.h> 2140266059SGregory Neil Shapiro #include <signal.h> 2240266059SGregory Neil Shapiro #include <fcntl.h> 2340266059SGregory Neil Shapiro #include <sm/io.h> 2440266059SGregory Neil Shapiro #include <sm/setjmp.h> 2540266059SGregory Neil Shapiro #include <sm/conf.h> 2640266059SGregory Neil Shapiro #include "local.h" 2740266059SGregory Neil Shapiro #include "fvwrite.h" 2840266059SGregory Neil Shapiro 2940266059SGregory Neil Shapiro /* 3040266059SGregory Neil Shapiro ** SM_FVWRITE -- write memory regions and buffer for file pointer 3140266059SGregory Neil Shapiro ** 3240266059SGregory Neil Shapiro ** Parameters: 3340266059SGregory Neil Shapiro ** fp -- the file pointer to write to 3440266059SGregory Neil Shapiro ** timeout -- time length for function to return by 3540266059SGregory Neil Shapiro ** uio -- the memory regions to write 3640266059SGregory Neil Shapiro ** 3740266059SGregory Neil Shapiro ** Returns: 3840266059SGregory Neil Shapiro ** Failure: returns SM_IO_EOF and sets errno 3940266059SGregory Neil Shapiro ** Success: returns 0 (zero) 4040266059SGregory Neil Shapiro ** 4140266059SGregory Neil Shapiro ** This routine is large and unsightly, but most of the ugliness due 4240266059SGregory Neil Shapiro ** to the different kinds of output buffering handled here. 4340266059SGregory Neil Shapiro */ 4440266059SGregory Neil Shapiro 4540266059SGregory Neil Shapiro #define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n)) 4640266059SGregory Neil Shapiro #define GETIOV(extra_work) \ 4740266059SGregory Neil Shapiro while (len == 0) \ 4840266059SGregory Neil Shapiro { \ 4940266059SGregory Neil Shapiro extra_work; \ 5040266059SGregory Neil Shapiro p = iov->iov_base; \ 5140266059SGregory Neil Shapiro len = iov->iov_len; \ 5240266059SGregory Neil Shapiro iov++; \ 5340266059SGregory Neil Shapiro } 5440266059SGregory Neil Shapiro 5540266059SGregory Neil Shapiro int 5640266059SGregory Neil Shapiro sm_fvwrite(fp, timeout, uio) 5740266059SGregory Neil Shapiro register SM_FILE_T *fp; 5840266059SGregory Neil Shapiro int timeout; 5940266059SGregory Neil Shapiro register struct sm_uio *uio; 6040266059SGregory Neil Shapiro { 6140266059SGregory Neil Shapiro register size_t len; 6240266059SGregory Neil Shapiro register char *p; 6340266059SGregory Neil Shapiro register struct sm_iov *iov; 6440266059SGregory Neil Shapiro register int w, s; 6540266059SGregory Neil Shapiro char *nl; 6640266059SGregory Neil Shapiro int nlknown, nldist; 6740266059SGregory Neil Shapiro int fd; 6840266059SGregory Neil Shapiro struct timeval to; 6940266059SGregory Neil Shapiro 7040266059SGregory Neil Shapiro if (uio->uio_resid == 0) 7140266059SGregory Neil Shapiro return 0; 7240266059SGregory Neil Shapiro 7340266059SGregory Neil Shapiro /* make sure we can write */ 7440266059SGregory Neil Shapiro if (cantwrite(fp)) 7540266059SGregory Neil Shapiro { 7640266059SGregory Neil Shapiro errno = EBADF; 7740266059SGregory Neil Shapiro return SM_IO_EOF; 7840266059SGregory Neil Shapiro } 7940266059SGregory Neil Shapiro 8040266059SGregory Neil Shapiro SM_CONVERT_TIME(fp, fd, timeout, &to); 8140266059SGregory Neil Shapiro 8240266059SGregory Neil Shapiro iov = uio->uio_iov; 8340266059SGregory Neil Shapiro p = iov->iov_base; 8440266059SGregory Neil Shapiro len = iov->iov_len; 8540266059SGregory Neil Shapiro iov++; 8640266059SGregory Neil Shapiro if (fp->f_flags & SMNBF) 8740266059SGregory Neil Shapiro { 8840266059SGregory Neil Shapiro /* Unbuffered: write up to BUFSIZ bytes at a time. */ 8940266059SGregory Neil Shapiro do 9040266059SGregory Neil Shapiro { 9140266059SGregory Neil Shapiro GETIOV(;); 9240266059SGregory Neil Shapiro errno = 0; /* needed to ensure EOF correctly found */ 9340266059SGregory Neil Shapiro w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ)); 9440266059SGregory Neil Shapiro if (w <= 0) 9540266059SGregory Neil Shapiro { 9640266059SGregory Neil Shapiro if (w == 0 && errno == 0) 9740266059SGregory Neil Shapiro break; /* EOF found */ 9840266059SGregory Neil Shapiro if (IS_IO_ERROR(fd, w, timeout)) 9940266059SGregory Neil Shapiro goto err; /* errno set */ 10040266059SGregory Neil Shapiro 10140266059SGregory Neil Shapiro /* write would block */ 10240266059SGregory Neil Shapiro SM_IO_WR_TIMEOUT(fp, fd, timeout); 10340266059SGregory Neil Shapiro w = 0; 10440266059SGregory Neil Shapiro } 10540266059SGregory Neil Shapiro else 10640266059SGregory Neil Shapiro { 10740266059SGregory Neil Shapiro p += w; 10840266059SGregory Neil Shapiro len -= w; 10940266059SGregory Neil Shapiro } 11040266059SGregory Neil Shapiro } while ((uio->uio_resid -= w) != 0); 11140266059SGregory Neil Shapiro } 11240266059SGregory Neil Shapiro else if ((fp->f_flags & SMLBF) == 0) 11340266059SGregory Neil Shapiro { 11440266059SGregory Neil Shapiro /* 11540266059SGregory Neil Shapiro ** Not SMLBF (line-buffered). Either SMFBF or SMNOW 11640266059SGregory Neil Shapiro ** buffered: fill partially full buffer, if any, 11740266059SGregory Neil Shapiro ** and then flush. If there is no partial buffer, write 11840266059SGregory Neil Shapiro ** one bf._size byte chunk directly (without copying). 11940266059SGregory Neil Shapiro ** 12040266059SGregory Neil Shapiro ** String output is a special case: write as many bytes 12140266059SGregory Neil Shapiro ** as fit, but pretend we wrote everything. This makes 12240266059SGregory Neil Shapiro ** snprintf() return the number of bytes needed, rather 12340266059SGregory Neil Shapiro ** than the number used, and avoids its write function 12440266059SGregory Neil Shapiro ** (so that the write function can be invalid). 12540266059SGregory Neil Shapiro */ 12640266059SGregory Neil Shapiro 12740266059SGregory Neil Shapiro do 12840266059SGregory Neil Shapiro { 12940266059SGregory Neil Shapiro GETIOV(;); 13040266059SGregory Neil Shapiro if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR)) 13140266059SGregory Neil Shapiro || ((fp->f_flags & SMNOW) != 0)) 13240266059SGregory Neil Shapiro && (size_t) fp->f_w < len) 13340266059SGregory Neil Shapiro { 13440266059SGregory Neil Shapiro size_t blen = fp->f_p - fp->f_bf.smb_base; 13540266059SGregory Neil Shapiro unsigned char *tbase; 13640266059SGregory Neil Shapiro int tsize; 13740266059SGregory Neil Shapiro 13840266059SGregory Neil Shapiro /* Allocate space exponentially. */ 13940266059SGregory Neil Shapiro tsize = fp->f_bf.smb_size; 14040266059SGregory Neil Shapiro do 14140266059SGregory Neil Shapiro { 14240266059SGregory Neil Shapiro tsize = (tsize << 1) + 1; 14340266059SGregory Neil Shapiro } while ((size_t) tsize < blen + len); 14440266059SGregory Neil Shapiro tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base, 14540266059SGregory Neil Shapiro tsize + 1); 14640266059SGregory Neil Shapiro if (tbase == NULL) 14740266059SGregory Neil Shapiro { 14840266059SGregory Neil Shapiro errno = ENOMEM; 14940266059SGregory Neil Shapiro goto err; /* errno set */ 15040266059SGregory Neil Shapiro } 15140266059SGregory Neil Shapiro fp->f_w += tsize - fp->f_bf.smb_size; 15240266059SGregory Neil Shapiro fp->f_bf.smb_base = tbase; 15340266059SGregory Neil Shapiro fp->f_bf.smb_size = tsize; 15440266059SGregory Neil Shapiro fp->f_p = tbase + blen; 15540266059SGregory Neil Shapiro } 15640266059SGregory Neil Shapiro w = fp->f_w; 15740266059SGregory Neil Shapiro errno = 0; /* needed to ensure EOF correctly found */ 15840266059SGregory Neil Shapiro if (fp->f_flags & SMSTR) 15940266059SGregory Neil Shapiro { 16040266059SGregory Neil Shapiro if (len < (size_t) w) 16140266059SGregory Neil Shapiro w = len; 16240266059SGregory Neil Shapiro COPY(w); /* copy SM_MIN(fp->f_w,len), */ 16340266059SGregory Neil Shapiro fp->f_w -= w; 16440266059SGregory Neil Shapiro fp->f_p += w; 16540266059SGregory Neil Shapiro w = len; /* but pretend copied all */ 16640266059SGregory Neil Shapiro } 16740266059SGregory Neil Shapiro else if (fp->f_p > fp->f_bf.smb_base 16840266059SGregory Neil Shapiro && len > (size_t) w) 16940266059SGregory Neil Shapiro { 17040266059SGregory Neil Shapiro /* fill and flush */ 17140266059SGregory Neil Shapiro COPY(w); 17240266059SGregory Neil Shapiro fp->f_p += w; 17340266059SGregory Neil Shapiro if (sm_flush(fp, &timeout)) 17440266059SGregory Neil Shapiro goto err; /* errno set */ 17540266059SGregory Neil Shapiro } 17640266059SGregory Neil Shapiro else if (len >= (size_t) (w = fp->f_bf.smb_size)) 17740266059SGregory Neil Shapiro { 17840266059SGregory Neil Shapiro /* write directly */ 17940266059SGregory Neil Shapiro w = (*fp->f_write)(fp, p, w); 18040266059SGregory Neil Shapiro if (w <= 0) 18140266059SGregory Neil Shapiro { 18240266059SGregory Neil Shapiro if (w == 0 && errno == 0) 18340266059SGregory Neil Shapiro break; /* EOF found */ 18440266059SGregory Neil Shapiro if (IS_IO_ERROR(fd, w, timeout)) 18540266059SGregory Neil Shapiro goto err; /* errno set */ 18640266059SGregory Neil Shapiro 18740266059SGregory Neil Shapiro /* write would block */ 18840266059SGregory Neil Shapiro SM_IO_WR_TIMEOUT(fp, fd, timeout); 18940266059SGregory Neil Shapiro w = 0; 19040266059SGregory Neil Shapiro } 19140266059SGregory Neil Shapiro } 19240266059SGregory Neil Shapiro else 19340266059SGregory Neil Shapiro { 19440266059SGregory Neil Shapiro /* fill and done */ 19540266059SGregory Neil Shapiro w = len; 19640266059SGregory Neil Shapiro COPY(w); 19740266059SGregory Neil Shapiro fp->f_w -= w; 19840266059SGregory Neil Shapiro fp->f_p += w; 19940266059SGregory Neil Shapiro } 20040266059SGregory Neil Shapiro p += w; 20140266059SGregory Neil Shapiro len -= w; 20240266059SGregory Neil Shapiro } while ((uio->uio_resid -= w) != 0); 20340266059SGregory Neil Shapiro 20440266059SGregory Neil Shapiro if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout)) 20540266059SGregory Neil Shapiro goto err; /* errno set */ 20640266059SGregory Neil Shapiro } 20740266059SGregory Neil Shapiro else 20840266059SGregory Neil Shapiro { 20940266059SGregory Neil Shapiro /* 21040266059SGregory Neil Shapiro ** Line buffered: like fully buffered, but we 21140266059SGregory Neil Shapiro ** must check for newlines. Compute the distance 21240266059SGregory Neil Shapiro ** to the first newline (including the newline), 21340266059SGregory Neil Shapiro ** or `infinity' if there is none, then pretend 21440266059SGregory Neil Shapiro ** that the amount to write is SM_MIN(len,nldist). 21540266059SGregory Neil Shapiro */ 21640266059SGregory Neil Shapiro 21740266059SGregory Neil Shapiro nlknown = 0; 21840266059SGregory Neil Shapiro nldist = 0; /* XXX just to keep gcc happy */ 21940266059SGregory Neil Shapiro do 22040266059SGregory Neil Shapiro { 22140266059SGregory Neil Shapiro GETIOV(nlknown = 0); 22240266059SGregory Neil Shapiro if (!nlknown) 22340266059SGregory Neil Shapiro { 22440266059SGregory Neil Shapiro nl = memchr((void *)p, '\n', len); 22540266059SGregory Neil Shapiro nldist = nl != NULL ? nl + 1 - p : len + 1; 22640266059SGregory Neil Shapiro nlknown = 1; 22740266059SGregory Neil Shapiro } 22840266059SGregory Neil Shapiro s = SM_MIN(len, ((size_t) nldist)); 22940266059SGregory Neil Shapiro w = fp->f_w + fp->f_bf.smb_size; 23040266059SGregory Neil Shapiro errno = 0; /* needed to ensure EOF correctly found */ 23140266059SGregory Neil Shapiro if (fp->f_p > fp->f_bf.smb_base && s > w) 23240266059SGregory Neil Shapiro { 23340266059SGregory Neil Shapiro COPY(w); 23440266059SGregory Neil Shapiro /* fp->f_w -= w; */ 23540266059SGregory Neil Shapiro fp->f_p += w; 23640266059SGregory Neil Shapiro if (sm_flush(fp, &timeout)) 23740266059SGregory Neil Shapiro goto err; /* errno set */ 23840266059SGregory Neil Shapiro } 23940266059SGregory Neil Shapiro else if (s >= (w = fp->f_bf.smb_size)) 24040266059SGregory Neil Shapiro { 24140266059SGregory Neil Shapiro w = (*fp->f_write)(fp, p, w); 24240266059SGregory Neil Shapiro if (w <= 0) 24340266059SGregory Neil Shapiro { 24440266059SGregory Neil Shapiro if (w == 0 && errno == 0) 24540266059SGregory Neil Shapiro break; /* EOF found */ 24640266059SGregory Neil Shapiro if (IS_IO_ERROR(fd, w, timeout)) 24740266059SGregory Neil Shapiro goto err; /* errno set */ 24840266059SGregory Neil Shapiro 24940266059SGregory Neil Shapiro /* write would block */ 25040266059SGregory Neil Shapiro SM_IO_WR_TIMEOUT(fp, fd, timeout); 25140266059SGregory Neil Shapiro w = 0; 25240266059SGregory Neil Shapiro } 25340266059SGregory Neil Shapiro } 25440266059SGregory Neil Shapiro else 25540266059SGregory Neil Shapiro { 25640266059SGregory Neil Shapiro w = s; 25740266059SGregory Neil Shapiro COPY(w); 25840266059SGregory Neil Shapiro fp->f_w -= w; 25940266059SGregory Neil Shapiro fp->f_p += w; 26040266059SGregory Neil Shapiro } 26140266059SGregory Neil Shapiro if ((nldist -= w) == 0) 26240266059SGregory Neil Shapiro { 26340266059SGregory Neil Shapiro /* copied the newline: flush and forget */ 26440266059SGregory Neil Shapiro if (sm_flush(fp, &timeout)) 26540266059SGregory Neil Shapiro goto err; /* errno set */ 26640266059SGregory Neil Shapiro nlknown = 0; 26740266059SGregory Neil Shapiro } 26840266059SGregory Neil Shapiro p += w; 26940266059SGregory Neil Shapiro len -= w; 27040266059SGregory Neil Shapiro } while ((uio->uio_resid -= w) != 0); 27140266059SGregory Neil Shapiro } 27240266059SGregory Neil Shapiro 27340266059SGregory Neil Shapiro return 0; 27440266059SGregory Neil Shapiro 27540266059SGregory Neil Shapiro err: 27640266059SGregory Neil Shapiro /* errno set before goto places us here */ 27740266059SGregory Neil Shapiro fp->f_flags |= SMERR; 27840266059SGregory Neil Shapiro return SM_IO_EOF; 27940266059SGregory Neil Shapiro } 280