fvwrite.c revision 266527
190792Sgshapiro/* 2261194Sgshapiro * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * Copyright (c) 1990, 1993 590792Sgshapiro * The Regents of the University of California. All rights reserved. 690792Sgshapiro * 790792Sgshapiro * This code is derived from software contributed to Berkeley by 890792Sgshapiro * Chris Torek. 990792Sgshapiro * 1090792Sgshapiro * By using this file, you agree to the terms and conditions set 1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of 1290792Sgshapiro * the sendmail distribution. 1390792Sgshapiro */ 1490792Sgshapiro 1590792Sgshapiro#include <sm/gen.h> 16266527SgshapiroSM_RCSID("@(#)$Id: fvwrite.c,v 1.50 2013-11-22 20:51:42 ca Exp $") 1790792Sgshapiro#include <stdlib.h> 1890792Sgshapiro#include <unistd.h> 1990792Sgshapiro#include <string.h> 2090792Sgshapiro#include <errno.h> 2190792Sgshapiro#include <signal.h> 2290792Sgshapiro#include <fcntl.h> 2390792Sgshapiro#include <sm/io.h> 2490792Sgshapiro#include <sm/setjmp.h> 2590792Sgshapiro#include <sm/conf.h> 2690792Sgshapiro#include "local.h" 2790792Sgshapiro#include "fvwrite.h" 2890792Sgshapiro 2990792Sgshapiro/* 3090792Sgshapiro** SM_FVWRITE -- write memory regions and buffer for file pointer 3190792Sgshapiro** 3290792Sgshapiro** Parameters: 3390792Sgshapiro** fp -- the file pointer to write to 3490792Sgshapiro** timeout -- time length for function to return by 3590792Sgshapiro** uio -- the memory regions to write 3690792Sgshapiro** 3790792Sgshapiro** Returns: 3890792Sgshapiro** Failure: returns SM_IO_EOF and sets errno 3990792Sgshapiro** Success: returns 0 (zero) 4090792Sgshapiro** 4190792Sgshapiro** This routine is large and unsightly, but most of the ugliness due 4290792Sgshapiro** to the different kinds of output buffering handled here. 4390792Sgshapiro*/ 4490792Sgshapiro 4590792Sgshapiro#define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n)) 4690792Sgshapiro#define GETIOV(extra_work) \ 4790792Sgshapiro while (len == 0) \ 4890792Sgshapiro { \ 4990792Sgshapiro extra_work; \ 5090792Sgshapiro p = iov->iov_base; \ 5190792Sgshapiro len = iov->iov_len; \ 5290792Sgshapiro iov++; \ 5390792Sgshapiro } 5490792Sgshapiro 5590792Sgshapiroint 5690792Sgshapirosm_fvwrite(fp, timeout, uio) 5790792Sgshapiro register SM_FILE_T *fp; 5890792Sgshapiro int timeout; 5990792Sgshapiro register struct sm_uio *uio; 6090792Sgshapiro{ 6190792Sgshapiro register size_t len; 6290792Sgshapiro register char *p; 6390792Sgshapiro register struct sm_iov *iov; 6490792Sgshapiro register int w, s; 6590792Sgshapiro char *nl; 6690792Sgshapiro int nlknown, nldist; 6790792Sgshapiro int fd; 6890792Sgshapiro struct timeval to; 6990792Sgshapiro 7090792Sgshapiro if (uio->uio_resid == 0) 7190792Sgshapiro return 0; 7290792Sgshapiro 7390792Sgshapiro /* make sure we can write */ 7490792Sgshapiro if (cantwrite(fp)) 7590792Sgshapiro { 7690792Sgshapiro errno = EBADF; 7790792Sgshapiro return SM_IO_EOF; 7890792Sgshapiro } 7990792Sgshapiro 8090792Sgshapiro SM_CONVERT_TIME(fp, fd, timeout, &to); 8190792Sgshapiro 8290792Sgshapiro iov = uio->uio_iov; 8390792Sgshapiro p = iov->iov_base; 8490792Sgshapiro len = iov->iov_len; 8590792Sgshapiro iov++; 8690792Sgshapiro if (fp->f_flags & SMNBF) 8790792Sgshapiro { 8890792Sgshapiro /* Unbuffered: write up to BUFSIZ bytes at a time. */ 8990792Sgshapiro do 9090792Sgshapiro { 9190792Sgshapiro GETIOV(;); 9290792Sgshapiro errno = 0; /* needed to ensure EOF correctly found */ 9390792Sgshapiro w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ)); 9490792Sgshapiro if (w <= 0) 9590792Sgshapiro { 9690792Sgshapiro if (w == 0 && errno == 0) 9790792Sgshapiro break; /* EOF found */ 9890792Sgshapiro if (IS_IO_ERROR(fd, w, timeout)) 9990792Sgshapiro goto err; /* errno set */ 10090792Sgshapiro 10190792Sgshapiro /* write would block */ 10290792Sgshapiro SM_IO_WR_TIMEOUT(fp, fd, timeout); 10390792Sgshapiro w = 0; 10490792Sgshapiro } 10590792Sgshapiro else 10690792Sgshapiro { 10790792Sgshapiro p += w; 10890792Sgshapiro len -= w; 10990792Sgshapiro } 11090792Sgshapiro } while ((uio->uio_resid -= w) != 0); 11190792Sgshapiro } 11290792Sgshapiro else if ((fp->f_flags & SMLBF) == 0) 11390792Sgshapiro { 11490792Sgshapiro /* 11590792Sgshapiro ** Not SMLBF (line-buffered). Either SMFBF or SMNOW 11690792Sgshapiro ** buffered: fill partially full buffer, if any, 11790792Sgshapiro ** and then flush. If there is no partial buffer, write 11890792Sgshapiro ** one bf._size byte chunk directly (without copying). 11990792Sgshapiro ** 12090792Sgshapiro ** String output is a special case: write as many bytes 12190792Sgshapiro ** as fit, but pretend we wrote everything. This makes 12290792Sgshapiro ** snprintf() return the number of bytes needed, rather 12390792Sgshapiro ** than the number used, and avoids its write function 12490792Sgshapiro ** (so that the write function can be invalid). 12590792Sgshapiro */ 12690792Sgshapiro 12790792Sgshapiro do 12890792Sgshapiro { 12990792Sgshapiro GETIOV(;); 13090792Sgshapiro if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR)) 13190792Sgshapiro || ((fp->f_flags & SMNOW) != 0)) 13290792Sgshapiro && (size_t) fp->f_w < len) 13390792Sgshapiro { 13490792Sgshapiro size_t blen = fp->f_p - fp->f_bf.smb_base; 13590792Sgshapiro unsigned char *tbase; 13690792Sgshapiro int tsize; 13790792Sgshapiro 13890792Sgshapiro /* Allocate space exponentially. */ 13990792Sgshapiro tsize = fp->f_bf.smb_size; 14090792Sgshapiro do 14190792Sgshapiro { 14290792Sgshapiro tsize = (tsize << 1) + 1; 14390792Sgshapiro } while ((size_t) tsize < blen + len); 14490792Sgshapiro tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base, 14590792Sgshapiro tsize + 1); 14690792Sgshapiro if (tbase == NULL) 14790792Sgshapiro { 14890792Sgshapiro errno = ENOMEM; 14990792Sgshapiro goto err; /* errno set */ 15090792Sgshapiro } 15190792Sgshapiro fp->f_w += tsize - fp->f_bf.smb_size; 15290792Sgshapiro fp->f_bf.smb_base = tbase; 15390792Sgshapiro fp->f_bf.smb_size = tsize; 15490792Sgshapiro fp->f_p = tbase + blen; 15590792Sgshapiro } 15690792Sgshapiro w = fp->f_w; 15790792Sgshapiro errno = 0; /* needed to ensure EOF correctly found */ 15890792Sgshapiro if (fp->f_flags & SMSTR) 15990792Sgshapiro { 16090792Sgshapiro if (len < (size_t) w) 16190792Sgshapiro w = len; 16290792Sgshapiro COPY(w); /* copy SM_MIN(fp->f_w,len), */ 16390792Sgshapiro fp->f_w -= w; 16490792Sgshapiro fp->f_p += w; 16590792Sgshapiro w = len; /* but pretend copied all */ 16690792Sgshapiro } 16790792Sgshapiro else if (fp->f_p > fp->f_bf.smb_base 16890792Sgshapiro && len > (size_t) w) 16990792Sgshapiro { 17090792Sgshapiro /* fill and flush */ 17190792Sgshapiro COPY(w); 17290792Sgshapiro fp->f_p += w; 17390792Sgshapiro if (sm_flush(fp, &timeout)) 17490792Sgshapiro goto err; /* errno set */ 17590792Sgshapiro } 17690792Sgshapiro else if (len >= (size_t) (w = fp->f_bf.smb_size)) 17790792Sgshapiro { 17890792Sgshapiro /* write directly */ 17990792Sgshapiro w = (*fp->f_write)(fp, p, w); 18090792Sgshapiro if (w <= 0) 18190792Sgshapiro { 18290792Sgshapiro if (w == 0 && errno == 0) 18390792Sgshapiro break; /* EOF found */ 18490792Sgshapiro if (IS_IO_ERROR(fd, w, timeout)) 18590792Sgshapiro goto err; /* errno set */ 18690792Sgshapiro 18790792Sgshapiro /* write would block */ 18890792Sgshapiro SM_IO_WR_TIMEOUT(fp, fd, timeout); 18990792Sgshapiro w = 0; 19090792Sgshapiro } 19190792Sgshapiro } 19290792Sgshapiro else 19390792Sgshapiro { 19490792Sgshapiro /* fill and done */ 19590792Sgshapiro w = len; 19690792Sgshapiro COPY(w); 19790792Sgshapiro fp->f_w -= w; 19890792Sgshapiro fp->f_p += w; 19990792Sgshapiro } 20090792Sgshapiro p += w; 20190792Sgshapiro len -= w; 20290792Sgshapiro } while ((uio->uio_resid -= w) != 0); 20390792Sgshapiro 20490792Sgshapiro if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout)) 20590792Sgshapiro goto err; /* errno set */ 20690792Sgshapiro } 20790792Sgshapiro else 20890792Sgshapiro { 20990792Sgshapiro /* 21090792Sgshapiro ** Line buffered: like fully buffered, but we 21190792Sgshapiro ** must check for newlines. Compute the distance 21290792Sgshapiro ** to the first newline (including the newline), 21390792Sgshapiro ** or `infinity' if there is none, then pretend 21490792Sgshapiro ** that the amount to write is SM_MIN(len,nldist). 21590792Sgshapiro */ 21690792Sgshapiro 21790792Sgshapiro nlknown = 0; 21890792Sgshapiro nldist = 0; /* XXX just to keep gcc happy */ 21990792Sgshapiro do 22090792Sgshapiro { 22190792Sgshapiro GETIOV(nlknown = 0); 22290792Sgshapiro if (!nlknown) 22390792Sgshapiro { 22490792Sgshapiro nl = memchr((void *)p, '\n', len); 22590792Sgshapiro nldist = nl != NULL ? nl + 1 - p : len + 1; 22690792Sgshapiro nlknown = 1; 22790792Sgshapiro } 22890792Sgshapiro s = SM_MIN(len, ((size_t) nldist)); 22990792Sgshapiro w = fp->f_w + fp->f_bf.smb_size; 23090792Sgshapiro errno = 0; /* needed to ensure EOF correctly found */ 23190792Sgshapiro if (fp->f_p > fp->f_bf.smb_base && s > w) 23290792Sgshapiro { 23390792Sgshapiro COPY(w); 23490792Sgshapiro /* fp->f_w -= w; */ 23590792Sgshapiro fp->f_p += w; 23690792Sgshapiro if (sm_flush(fp, &timeout)) 23790792Sgshapiro goto err; /* errno set */ 23890792Sgshapiro } 23990792Sgshapiro else if (s >= (w = fp->f_bf.smb_size)) 24090792Sgshapiro { 24190792Sgshapiro w = (*fp->f_write)(fp, p, w); 24290792Sgshapiro if (w <= 0) 24390792Sgshapiro { 24490792Sgshapiro if (w == 0 && errno == 0) 24590792Sgshapiro break; /* EOF found */ 24690792Sgshapiro if (IS_IO_ERROR(fd, w, timeout)) 24790792Sgshapiro goto err; /* errno set */ 24890792Sgshapiro 24990792Sgshapiro /* write would block */ 25090792Sgshapiro SM_IO_WR_TIMEOUT(fp, fd, timeout); 25190792Sgshapiro w = 0; 25290792Sgshapiro } 25390792Sgshapiro } 25490792Sgshapiro else 25590792Sgshapiro { 25690792Sgshapiro w = s; 25790792Sgshapiro COPY(w); 25890792Sgshapiro fp->f_w -= w; 25990792Sgshapiro fp->f_p += w; 26090792Sgshapiro } 26190792Sgshapiro if ((nldist -= w) == 0) 26290792Sgshapiro { 26390792Sgshapiro /* copied the newline: flush and forget */ 26490792Sgshapiro if (sm_flush(fp, &timeout)) 26590792Sgshapiro goto err; /* errno set */ 26690792Sgshapiro nlknown = 0; 26790792Sgshapiro } 26890792Sgshapiro p += w; 26990792Sgshapiro len -= w; 27090792Sgshapiro } while ((uio->uio_resid -= w) != 0); 27190792Sgshapiro } 27290792Sgshapiro 27390792Sgshapiro return 0; 27490792Sgshapiro 27590792Sgshapiroerr: 27690792Sgshapiro /* errno set before goto places us here */ 27790792Sgshapiro fp->f_flags |= SMERR; 27890792Sgshapiro return SM_IO_EOF; 27990792Sgshapiro} 280