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 #include <sm/gen.h> 16 SM_RCSID("@(#)$Id: setvbuf.c,v 1.32 2001/09/11 04:04:49 gshapiro Exp $") 17 #include <stdlib.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <sm/io.h> 21 #include <sm/heap.h> 22 #include <sm/assert.h> 23 #include <sm/conf.h> 24 #include "local.h" 25 26 /* 27 ** SM_IO_SETVBUF -- set the buffering type for a file 28 ** 29 ** Set one of the different kinds of buffering, optionally including 30 ** a buffer. 31 ** If 'size' is == 0 then an "optimal" size will be selected. 32 ** If 'buf' is == NULL then space will be allocated at 'size'. 33 ** 34 ** Parameters: 35 ** fp -- the file that buffering is to be changed for 36 ** timeout -- time allowed for completing the function 37 ** buf -- buffer to use 38 ** mode -- buffering method to use 39 ** size -- size of 'buf' 40 ** 41 ** Returns: 42 ** Failure: SM_IO_EOF 43 ** Success: 0 (zero) 44 */ 45 46 int 47 sm_io_setvbuf(fp, timeout, buf, mode, size) 48 SM_FILE_T *fp; 49 int timeout; 50 char *buf; 51 int mode; 52 size_t size; 53 { 54 int ret, flags; 55 size_t iosize; 56 int ttyflag; 57 #ifndef WIN32 58 int fd; 59 struct timeval to; 60 #endif /* WIN32 */ 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