[19203] | 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.1.1.1 2003-04-08 15:06:05 zacheiss 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 | } |
---|