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 | } |
---|