1 /* 2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * By using this file, you agree to the terms and conditions set 11 * forth in the LICENSE file which can be found at the top level of 12 * the sendmail distribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include <sm/gen.h> 18 SM_RCSID("@(#)$Id: setvbuf.c,v 1.30 2001/02/28 20:25:18 rodney Exp $") 19 #include <stdlib.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <sm/io.h> 23 #include <sm/heap.h> 24 #include <sm/assert.h> 25 #include <sm/conf.h> 26 #include "local.h" 27 28 /* 29 ** SM_IO_SETVBUF -- set the buffering type for a file 30 ** 31 ** Set one of the different kinds of buffering, optionally including 32 ** a buffer. 33 ** If 'size' is == 0 then an "optimal" size will be selected. 34 ** If 'buf' is == NULL then space will be allocated at 'size'. 35 ** 36 ** Parameters: 37 ** fp -- the file that buffering is to be changed for 38 ** timeout -- time allowed for completing the function 39 ** buf -- buffer to use 40 ** mode -- buffering method to use 41 ** size -- size of 'buf' 42 ** 43 ** Returns: 44 ** Failure: SM_IO_EOF 45 ** Success: 0 (zero) 46 */ 47 48 int 49 sm_io_setvbuf(fp, timeout, buf, mode, size) 50 SM_FILE_T *fp; 51 int timeout; 52 char *buf; 53 int mode; 54 size_t size; 55 { 56 int ret, flags; 57 size_t iosize; 58 int ttyflag; 59 int fd; 60 struct timeval to; 61 62 SM_REQUIRE_ISA(fp, SmFileMagic); 63 64 /* 65 ** Verify arguments. The `int' limit on `size' is due to this 66 ** particular implementation. Note, buf and size are ignored 67 ** when setting SM_IO_NBF. 68 */ 69 70 if (mode != SM_IO_NBF) 71 if ((mode != SM_IO_FBF && mode != SM_IO_LBF && 72 mode != SM_IO_NOW) || (int) size < 0) 73 return SM_IO_EOF; 74 75 /* 76 ** Write current buffer, if any. Discard unread input (including 77 ** ungetc data), cancel line buffering, and free old buffer if 78 ** malloc()ed. We also clear any eof condition, as if this were 79 ** a seek. 80 */ 81 82 ret = 0; 83 SM_CONVERT_TIME(fp, fd, timeout, &to); 84 (void) sm_flush(fp, &timeout); 85 if (HASUB(fp)) 86 FREEUB(fp); 87 fp->f_r = fp->f_lbfsize = 0; 88 flags = fp->f_flags; 89 if (flags & SMMBF) 90 { 91 sm_free((void *) fp->f_bf.smb_base); 92 fp->f_bf.smb_base = NULL; 93 } 94 flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW | 95 SMFBF); 96 97 /* If setting unbuffered mode, skip all the hard work. */ 98 if (mode == SM_IO_NBF) 99 goto nbf; 100 101 /* 102 ** Find optimal I/O size for seek optimization. This also returns 103 ** a `tty flag' to suggest that we check isatty(fd), but we do not 104 ** care since our caller told us how to buffer. 105 */ 106 107 flags |= sm_whatbuf(fp, &iosize, &ttyflag); 108 if (size == 0) 109 { 110 buf = NULL; /* force local allocation */ 111 size = iosize; 112 } 113 114 /* Allocate buffer if needed. */ 115 if (buf == NULL) 116 { 117 if ((buf = sm_malloc(size)) == NULL) 118 { 119 /* 120 ** Unable to honor user's request. We will return 121 ** failure, but try again with file system size. 122 */ 123 124 ret = SM_IO_EOF; 125 if (size != iosize) 126 { 127 size = iosize; 128 buf = sm_malloc(size); 129 } 130 } 131 if (buf == NULL) 132 { 133 /* No luck; switch to unbuffered I/O. */ 134 nbf: 135 fp->f_flags = flags | SMNBF; 136 fp->f_w = 0; 137 fp->f_bf.smb_base = fp->f_p = fp->f_nbuf; 138 fp->f_bf.smb_size = 1; 139 return ret; 140 } 141 flags |= SMMBF; 142 } 143 144 /* 145 ** Kill any seek optimization if the buffer is not the 146 ** right size. 147 ** 148 ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? 149 */ 150 151 if (size != iosize) 152 flags |= SMNPT; 153 154 /* 155 ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on 156 ** exit (since we are buffered in some way). 157 */ 158 159 if (mode == SM_IO_LBF) 160 flags |= SMLBF; 161 else if (mode == SM_IO_NOW) 162 flags |= SMNOW; 163 else if (mode == SM_IO_FBF) 164 flags |= SMFBF; 165 fp->f_flags = flags; 166 fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf; 167 fp->f_bf.smb_size = size; 168 /* fp->f_lbfsize is still 0 */ 169 if (flags & SMWR) 170 { 171 /* 172 ** Begin or continue writing: see sm_wsetup(). Note 173 ** that SMNBF is impossible (it was handled earlier). 174 */ 175 176 if (flags & SMLBF) 177 { 178 fp->f_w = 0; 179 fp->f_lbfsize = -fp->f_bf.smb_size; 180 } 181 else 182 fp->f_w = size; 183 } 184 else 185 { 186 /* begin/continue reading, or stay in intermediate state */ 187 fp->f_w = 0; 188 } 189 190 atexit(sm_cleanup); 191 return ret; 192 } 193