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 int fd; 58 struct timeval to; 59 60 SM_REQUIRE_ISA(fp, SmFileMagic); 61 62 /* 63 ** Verify arguments. The `int' limit on `size' is due to this 64 ** particular implementation. Note, buf and size are ignored 65 ** when setting SM_IO_NBF. 66 */ 67 68 if (mode != SM_IO_NBF) 69 if ((mode != SM_IO_FBF && mode != SM_IO_LBF && 70 mode != SM_IO_NOW) || (int) size < 0) 71 return SM_IO_EOF; 72 73 /* 74 ** Write current buffer, if any. Discard unread input (including 75 ** ungetc data), cancel line buffering, and free old buffer if 76 ** malloc()ed. We also clear any eof condition, as if this were 77 ** a seek. 78 */ 79 80 ret = 0; 81 SM_CONVERT_TIME(fp, fd, timeout, &to); 82 (void) sm_flush(fp, &timeout); 83 if (HASUB(fp)) 84 FREEUB(fp); 85 fp->f_r = fp->f_lbfsize = 0; 86 flags = fp->f_flags; 87 if (flags & SMMBF) 88 { 89 sm_free((void *) fp->f_bf.smb_base); 90 fp->f_bf.smb_base = NULL; 91 } 92 flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW | 93 SMFBF); 94 95 /* If setting unbuffered mode, skip all the hard work. */ 96 if (mode == SM_IO_NBF) 97 goto nbf; 98 99 /* 100 ** Find optimal I/O size for seek optimization. This also returns 101 ** a `tty flag' to suggest that we check isatty(fd), but we do not 102 ** care since our caller told us how to buffer. 103 */ 104 105 flags |= sm_whatbuf(fp, &iosize, &ttyflag); 106 if (size == 0) 107 { 108 buf = NULL; /* force local allocation */ 109 size = iosize; 110 } 111 112 /* Allocate buffer if needed. */ 113 if (buf == NULL) 114 { 115 if ((buf = sm_malloc(size)) == NULL) 116 { 117 /* 118 ** Unable to honor user's request. We will return 119 ** failure, but try again with file system size. 120 */ 121 122 ret = SM_IO_EOF; 123 if (size != iosize) 124 { 125 size = iosize; 126 buf = sm_malloc(size); 127 } 128 } 129 if (buf == NULL) 130 { 131 /* No luck; switch to unbuffered I/O. */ 132 nbf: 133 fp->f_flags = flags | SMNBF; 134 fp->f_w = 0; 135 fp->f_bf.smb_base = fp->f_p = fp->f_nbuf; 136 fp->f_bf.smb_size = 1; 137 return ret; 138 } 139 flags |= SMMBF; 140 } 141 142 /* 143 ** Kill any seek optimization if the buffer is not the 144 ** right size. 145 ** 146 ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? 147 */ 148 149 if (size != iosize) 150 flags |= SMNPT; 151 152 /* 153 ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on 154 ** exit (since we are buffered in some way). 155 */ 156 157 if (mode == SM_IO_LBF) 158 flags |= SMLBF; 159 else if (mode == SM_IO_NOW) 160 flags |= SMNOW; 161 else if (mode == SM_IO_FBF) 162 flags |= SMFBF; 163 fp->f_flags = flags; 164 fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf; 165 fp->f_bf.smb_size = size; 166 /* fp->f_lbfsize is still 0 */ 167 if (flags & SMWR) 168 { 169 /* 170 ** Begin or continue writing: see sm_wsetup(). Note 171 ** that SMNBF is impossible (it was handled earlier). 172 */ 173 174 if (flags & SMLBF) 175 { 176 fp->f_w = 0; 177 fp->f_lbfsize = -fp->f_bf.smb_size; 178 } 179 else 180 fp->f_w = size; 181 } 182 else 183 { 184 /* begin/continue reading, or stay in intermediate state */ 185 fp->f_w = 0; 186 } 187 188 atexit(sm_cleanup); 189 return ret; 190 } 191