setvbuf.c revision 90792
1186690Sobrien/* 2186690Sobrien * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3186690Sobrien * All rights reserved. 4186690Sobrien * Copyright (c) 1990, 1993 5234449Sobrien * The Regents of the University of California. All rights reserved. 6186690Sobrien * 7234449Sobrien * This code is derived from software contributed to Berkeley by 8234449Sobrien * Chris Torek. 9234449Sobrien * 10234449Sobrien * By using this file, you agree to the terms and conditions set 11186690Sobrien * forth in the LICENSE file which can be found at the top level of 12186690Sobrien * the sendmail distribution. 13186690Sobrien */ 14186690Sobrien 15234449Sobrien#include <sm/gen.h> 16186690SobrienSM_RCSID("@(#)$Id: setvbuf.c,v 1.32 2001/09/11 04:04:49 gshapiro Exp $") 17186690Sobrien#include <stdlib.h> 18234449Sobrien#include <errno.h> 19234449Sobrien#include <fcntl.h> 20234449Sobrien#include <sm/io.h> 21234449Sobrien#include <sm/heap.h> 22234449Sobrien#include <sm/assert.h> 23186690Sobrien#include <sm/conf.h> 24186690Sobrien#include "local.h" 25186690Sobrien 26186690Sobrien/* 27186690Sobrien** SM_IO_SETVBUF -- set the buffering type for a file 28186690Sobrien** 29186690Sobrien** Set one of the different kinds of buffering, optionally including 30186690Sobrien** a buffer. 31186690Sobrien** If 'size' is == 0 then an "optimal" size will be selected. 32186690Sobrien** If 'buf' is == NULL then space will be allocated at 'size'. 33186690Sobrien** 34186690Sobrien** Parameters: 35186690Sobrien** fp -- the file that buffering is to be changed for 36186690Sobrien** timeout -- time allowed for completing the function 37186690Sobrien** buf -- buffer to use 38186690Sobrien** mode -- buffering method to use 39186690Sobrien** size -- size of 'buf' 40186690Sobrien** 41186690Sobrien** Returns: 42186690Sobrien** Failure: SM_IO_EOF 43186690Sobrien** Success: 0 (zero) 44186690Sobrien*/ 45186690Sobrien 46186690Sobrienint 47186690Sobriensm_io_setvbuf(fp, timeout, buf, mode, size) 48186690Sobrien SM_FILE_T *fp; 49186690Sobrien int timeout; 50186690Sobrien char *buf; 51234449Sobrien int mode; 52186690Sobrien size_t size; 53186690Sobrien{ 54186690Sobrien int ret, flags; 55186690Sobrien size_t iosize; 56186690Sobrien int ttyflag; 57186690Sobrien int fd; 58186690Sobrien struct timeval to; 59186690Sobrien 60186690Sobrien SM_REQUIRE_ISA(fp, SmFileMagic); 61186690Sobrien 62234449Sobrien /* 63186690Sobrien ** Verify arguments. The `int' limit on `size' is due to this 64186690Sobrien ** particular implementation. Note, buf and size are ignored 65234449Sobrien ** when setting SM_IO_NBF. 66234449Sobrien */ 67234449Sobrien 68234449Sobrien if (mode != SM_IO_NBF) 69186690Sobrien if ((mode != SM_IO_FBF && mode != SM_IO_LBF && 70234449Sobrien mode != SM_IO_NOW) || (int) size < 0) 71234449Sobrien return SM_IO_EOF; 72234449Sobrien 73234449Sobrien /* 74234449Sobrien ** Write current buffer, if any. Discard unread input (including 75234449Sobrien ** ungetc data), cancel line buffering, and free old buffer if 76234449Sobrien ** malloc()ed. We also clear any eof condition, as if this were 77234449Sobrien ** a seek. 78186690Sobrien */ 79186690Sobrien 80186690Sobrien ret = 0; 81186690Sobrien SM_CONVERT_TIME(fp, fd, timeout, &to); 82186690Sobrien (void) sm_flush(fp, &timeout); 83186690Sobrien if (HASUB(fp)) 84186690Sobrien FREEUB(fp); 85186690Sobrien fp->f_r = fp->f_lbfsize = 0; 86234449Sobrien flags = fp->f_flags; 87234449Sobrien if (flags & SMMBF) 88234449Sobrien { 89234449Sobrien sm_free((void *) fp->f_bf.smb_base); 90234449Sobrien fp->f_bf.smb_base = NULL; 91234449Sobrien } 92234449Sobrien flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW | 93234449Sobrien SMFBF); 94234449Sobrien 95234449Sobrien /* If setting unbuffered mode, skip all the hard work. */ 96186690Sobrien if (mode == SM_IO_NBF) 97186690Sobrien goto nbf; 98186690Sobrien 99234449Sobrien /* 100234449Sobrien ** Find optimal I/O size for seek optimization. This also returns 101234449Sobrien ** a `tty flag' to suggest that we check isatty(fd), but we do not 102186690Sobrien ** care since our caller told us how to buffer. 103186690Sobrien */ 104186690Sobrien 105186690Sobrien flags |= sm_whatbuf(fp, &iosize, &ttyflag); 106186690Sobrien if (size == 0) 107186690Sobrien { 108186690Sobrien buf = NULL; /* force local allocation */ 109186690Sobrien size = iosize; 110186690Sobrien } 111186690Sobrien 112186690Sobrien /* Allocate buffer if needed. */ 113186690Sobrien if (buf == NULL) 114234449Sobrien { 115186690Sobrien if ((buf = sm_malloc(size)) == NULL) 116186690Sobrien { 117186690Sobrien /* 118186690Sobrien ** Unable to honor user's request. We will return 119234449Sobrien ** failure, but try again with file system size. 120234449Sobrien */ 121186690Sobrien 122186690Sobrien ret = SM_IO_EOF; 123186690Sobrien if (size != iosize) 124186690Sobrien { 125186690Sobrien size = iosize; 126186690Sobrien buf = sm_malloc(size); 127234449Sobrien } 128234449Sobrien } 129234449Sobrien if (buf == NULL) 130234449Sobrien { 131234449Sobrien /* No luck; switch to unbuffered I/O. */ 132234449Sobriennbf: 133234449Sobrien fp->f_flags = flags | SMNBF; 134234449Sobrien fp->f_w = 0; 135234449Sobrien fp->f_bf.smb_base = fp->f_p = fp->f_nbuf; 136234449Sobrien fp->f_bf.smb_size = 1; 137234449Sobrien return ret; 138234449Sobrien } 139234449Sobrien flags |= SMMBF; 140234449Sobrien } 141186690Sobrien 142186690Sobrien /* 143186690Sobrien ** Kill any seek optimization if the buffer is not the 144234449Sobrien ** right size. 145186690Sobrien ** 146186690Sobrien ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? 147234449Sobrien */ 148234449Sobrien 149186690Sobrien if (size != iosize) 150186690Sobrien flags |= SMNPT; 151186690Sobrien 152186690Sobrien /* 153186690Sobrien ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on 154186690Sobrien ** exit (since we are buffered in some way). 155186690Sobrien */ 156186690Sobrien 157186690Sobrien if (mode == SM_IO_LBF) 158186690Sobrien flags |= SMLBF; 159234449Sobrien else if (mode == SM_IO_NOW) 160234449Sobrien flags |= SMNOW; 161234449Sobrien else if (mode == SM_IO_FBF) 162234449Sobrien flags |= SMFBF; 163186690Sobrien fp->f_flags = flags; 164234449Sobrien fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf; 165234449Sobrien fp->f_bf.smb_size = size; 166234449Sobrien /* fp->f_lbfsize is still 0 */ 167234449Sobrien if (flags & SMWR) 168234449Sobrien { 169234449Sobrien /* 170234449Sobrien ** Begin or continue writing: see sm_wsetup(). Note 171234449Sobrien ** that SMNBF is impossible (it was handled earlier). 172234449Sobrien */ 173234449Sobrien 174234449Sobrien if (flags & SMLBF) 175234449Sobrien { 176234449Sobrien fp->f_w = 0; 177234449Sobrien fp->f_lbfsize = -fp->f_bf.smb_size; 178234449Sobrien } 179234449Sobrien else 180234449Sobrien fp->f_w = size; 181234449Sobrien } 182234449Sobrien else 183234449Sobrien { 184234449Sobrien /* begin/continue reading, or stay in intermediate state */ 185234449Sobrien fp->f_w = 0; 186234449Sobrien } 187234449Sobrien 188234449Sobrien atexit(sm_cleanup); 189234449Sobrien return ret; 190234449Sobrien} 191234449Sobrien