setvbuf.c revision 261363
190792Sgshapiro/* 2261363Sgshapiro * 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> 16261363SgshapiroSM_RCSID("@(#)$Id: setvbuf.c,v 1.33 2013/11/22 20:51:43 ca Exp $") 1790792Sgshapiro#include <stdlib.h> 1890792Sgshapiro#include <errno.h> 1990792Sgshapiro#include <fcntl.h> 2090792Sgshapiro#include <sm/io.h> 2190792Sgshapiro#include <sm/heap.h> 2290792Sgshapiro#include <sm/assert.h> 2390792Sgshapiro#include <sm/conf.h> 2490792Sgshapiro#include "local.h" 2590792Sgshapiro 2690792Sgshapiro/* 2790792Sgshapiro** SM_IO_SETVBUF -- set the buffering type for a file 2890792Sgshapiro** 2990792Sgshapiro** Set one of the different kinds of buffering, optionally including 3090792Sgshapiro** a buffer. 3190792Sgshapiro** If 'size' is == 0 then an "optimal" size will be selected. 3290792Sgshapiro** If 'buf' is == NULL then space will be allocated at 'size'. 3390792Sgshapiro** 3490792Sgshapiro** Parameters: 3590792Sgshapiro** fp -- the file that buffering is to be changed for 3690792Sgshapiro** timeout -- time allowed for completing the function 3790792Sgshapiro** buf -- buffer to use 3890792Sgshapiro** mode -- buffering method to use 3990792Sgshapiro** size -- size of 'buf' 4090792Sgshapiro** 4190792Sgshapiro** Returns: 4290792Sgshapiro** Failure: SM_IO_EOF 4390792Sgshapiro** Success: 0 (zero) 4490792Sgshapiro*/ 4590792Sgshapiro 4690792Sgshapiroint 4790792Sgshapirosm_io_setvbuf(fp, timeout, buf, mode, size) 4890792Sgshapiro SM_FILE_T *fp; 4990792Sgshapiro int timeout; 5090792Sgshapiro char *buf; 5190792Sgshapiro int mode; 5290792Sgshapiro size_t size; 5390792Sgshapiro{ 5490792Sgshapiro int ret, flags; 5590792Sgshapiro size_t iosize; 5690792Sgshapiro int ttyflag; 5790792Sgshapiro int fd; 5890792Sgshapiro struct timeval to; 5990792Sgshapiro 6090792Sgshapiro SM_REQUIRE_ISA(fp, SmFileMagic); 6190792Sgshapiro 6290792Sgshapiro /* 6390792Sgshapiro ** Verify arguments. The `int' limit on `size' is due to this 6490792Sgshapiro ** particular implementation. Note, buf and size are ignored 6590792Sgshapiro ** when setting SM_IO_NBF. 6690792Sgshapiro */ 6790792Sgshapiro 6890792Sgshapiro if (mode != SM_IO_NBF) 6990792Sgshapiro if ((mode != SM_IO_FBF && mode != SM_IO_LBF && 7090792Sgshapiro mode != SM_IO_NOW) || (int) size < 0) 7190792Sgshapiro return SM_IO_EOF; 7290792Sgshapiro 7390792Sgshapiro /* 7490792Sgshapiro ** Write current buffer, if any. Discard unread input (including 7590792Sgshapiro ** ungetc data), cancel line buffering, and free old buffer if 7690792Sgshapiro ** malloc()ed. We also clear any eof condition, as if this were 7790792Sgshapiro ** a seek. 7890792Sgshapiro */ 7990792Sgshapiro 8090792Sgshapiro ret = 0; 8190792Sgshapiro SM_CONVERT_TIME(fp, fd, timeout, &to); 8290792Sgshapiro (void) sm_flush(fp, &timeout); 8390792Sgshapiro if (HASUB(fp)) 8490792Sgshapiro FREEUB(fp); 8590792Sgshapiro fp->f_r = fp->f_lbfsize = 0; 8690792Sgshapiro flags = fp->f_flags; 8790792Sgshapiro if (flags & SMMBF) 8890792Sgshapiro { 8990792Sgshapiro sm_free((void *) fp->f_bf.smb_base); 9090792Sgshapiro fp->f_bf.smb_base = NULL; 9190792Sgshapiro } 9290792Sgshapiro flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW | 9390792Sgshapiro SMFBF); 9490792Sgshapiro 9590792Sgshapiro /* If setting unbuffered mode, skip all the hard work. */ 9690792Sgshapiro if (mode == SM_IO_NBF) 9790792Sgshapiro goto nbf; 9890792Sgshapiro 9990792Sgshapiro /* 10090792Sgshapiro ** Find optimal I/O size for seek optimization. This also returns 10190792Sgshapiro ** a `tty flag' to suggest that we check isatty(fd), but we do not 10290792Sgshapiro ** care since our caller told us how to buffer. 10390792Sgshapiro */ 10490792Sgshapiro 10590792Sgshapiro flags |= sm_whatbuf(fp, &iosize, &ttyflag); 10690792Sgshapiro if (size == 0) 10790792Sgshapiro { 10890792Sgshapiro buf = NULL; /* force local allocation */ 10990792Sgshapiro size = iosize; 11090792Sgshapiro } 11190792Sgshapiro 11290792Sgshapiro /* Allocate buffer if needed. */ 11390792Sgshapiro if (buf == NULL) 11490792Sgshapiro { 11590792Sgshapiro if ((buf = sm_malloc(size)) == NULL) 11690792Sgshapiro { 11790792Sgshapiro /* 11890792Sgshapiro ** Unable to honor user's request. We will return 11990792Sgshapiro ** failure, but try again with file system size. 12090792Sgshapiro */ 12190792Sgshapiro 12290792Sgshapiro ret = SM_IO_EOF; 12390792Sgshapiro if (size != iosize) 12490792Sgshapiro { 12590792Sgshapiro size = iosize; 12690792Sgshapiro buf = sm_malloc(size); 12790792Sgshapiro } 12890792Sgshapiro } 12990792Sgshapiro if (buf == NULL) 13090792Sgshapiro { 13190792Sgshapiro /* No luck; switch to unbuffered I/O. */ 13290792Sgshapironbf: 13390792Sgshapiro fp->f_flags = flags | SMNBF; 13490792Sgshapiro fp->f_w = 0; 13590792Sgshapiro fp->f_bf.smb_base = fp->f_p = fp->f_nbuf; 13690792Sgshapiro fp->f_bf.smb_size = 1; 13790792Sgshapiro return ret; 13890792Sgshapiro } 13990792Sgshapiro flags |= SMMBF; 14090792Sgshapiro } 14190792Sgshapiro 14290792Sgshapiro /* 14390792Sgshapiro ** Kill any seek optimization if the buffer is not the 14490792Sgshapiro ** right size. 14590792Sgshapiro ** 14690792Sgshapiro ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? 14790792Sgshapiro */ 14890792Sgshapiro 14990792Sgshapiro if (size != iosize) 15090792Sgshapiro flags |= SMNPT; 15190792Sgshapiro 15290792Sgshapiro /* 15390792Sgshapiro ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on 15490792Sgshapiro ** exit (since we are buffered in some way). 15590792Sgshapiro */ 15690792Sgshapiro 15790792Sgshapiro if (mode == SM_IO_LBF) 15890792Sgshapiro flags |= SMLBF; 15990792Sgshapiro else if (mode == SM_IO_NOW) 16090792Sgshapiro flags |= SMNOW; 16190792Sgshapiro else if (mode == SM_IO_FBF) 16290792Sgshapiro flags |= SMFBF; 16390792Sgshapiro fp->f_flags = flags; 16490792Sgshapiro fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf; 16590792Sgshapiro fp->f_bf.smb_size = size; 16690792Sgshapiro /* fp->f_lbfsize is still 0 */ 16790792Sgshapiro if (flags & SMWR) 16890792Sgshapiro { 16990792Sgshapiro /* 17090792Sgshapiro ** Begin or continue writing: see sm_wsetup(). Note 17190792Sgshapiro ** that SMNBF is impossible (it was handled earlier). 17290792Sgshapiro */ 17390792Sgshapiro 17490792Sgshapiro if (flags & SMLBF) 17590792Sgshapiro { 17690792Sgshapiro fp->f_w = 0; 17790792Sgshapiro fp->f_lbfsize = -fp->f_bf.smb_size; 17890792Sgshapiro } 17990792Sgshapiro else 18090792Sgshapiro fp->f_w = size; 18190792Sgshapiro } 18290792Sgshapiro else 18390792Sgshapiro { 18490792Sgshapiro /* begin/continue reading, or stay in intermediate state */ 18590792Sgshapiro fp->f_w = 0; 18690792Sgshapiro } 18790792Sgshapiro 18890792Sgshapiro atexit(sm_cleanup); 18990792Sgshapiro return ret; 19090792Sgshapiro} 191