1 /*
2 * Copyright (c) 2000-2002, 2004, 2005 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_IDSTR(id, "@(#)$Id: strio.c,v 1.44 2005/06/09 21:40:19 ca Exp $")
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sm/rpool.h>
25 #include <sm/io.h>
26 #include <sm/heap.h>
27 #include <sm/conf.h>
28 #include "local.h"
29
30 static int sm_strsetmode __P((SM_FILE_T*, const int *));
31 static int sm_strgetmode __P((SM_FILE_T*, int *));
32
33 /*
34 ** Cookie structure for the "strio" file type
35 */
36
37 struct sm_str_obj
38 {
39 char *strio_base;
40 char *strio_end;
41 size_t strio_size;
42 size_t strio_offset;
43 int strio_flags;
44 const void *strio_rpool;
45 };
46
47 typedef struct sm_str_obj SM_STR_OBJ_T;
48
49 /*
50 ** SM_STRGROW -- increase storage space for string
51 **
52 ** Parameters:
53 ** s -- current cookie
54 ** size -- new storage size request
55 **
56 ** Returns:
57 ** true iff successful.
58 */
59
60 static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t));
61
62 static bool
sm_strgrow(s,size)63 sm_strgrow(s, size)
64 SM_STR_OBJ_T *s;
65 size_t size;
66 {
67 register void *p;
68
69 if (s->strio_size >= size)
70 return true;
71 p = sm_realloc(s->strio_base, size);
72 if (p == NULL)
73 return false;
74 s->strio_base = p;
75 s->strio_end = s->strio_base + size;
76 s->strio_size = size;
77 return true;
78 }
79
80 /*
81 ** SM_STRREAD -- read a portion of the string
82 **
83 ** Parameters:
84 ** fp -- the file pointer
85 ** buf -- location to place read data
86 ** n -- number of bytes to read
87 **
88 ** Returns:
89 ** Failure: -1 and sets errno
90 ** Success: >=0, number of bytes read
91 */
92
93 ssize_t
sm_strread(fp,buf,n)94 sm_strread(fp, buf, n)
95 SM_FILE_T *fp;
96 char *buf;
97 size_t n;
98 {
99 register SM_STR_OBJ_T *s = fp->f_cookie;
100 int len;
101
102 if (!(s->strio_flags & SMRD) && !(s->strio_flags & SMRW))
103 {
104 errno = EBADF;
105 return -1;
106 }
107 len = SM_MIN(s->strio_size - s->strio_offset, n);
108 (void) memmove(buf, s->strio_base + s->strio_offset, len);
109 s->strio_offset += len;
110 return len;
111 }
112
113 /*
114 ** SM_STRWRITE -- write a portion of the string
115 **
116 ** Parameters:
117 ** fp -- the file pointer
118 ** buf -- location of data for writing
119 ** n -- number of bytes to write
120 **
121 ** Returns:
122 ** Failure: -1 and sets errno
123 ** Success: >=0, number of bytes written
124 */
125
126 ssize_t
sm_strwrite(fp,buf,n)127 sm_strwrite(fp, buf, n)
128 SM_FILE_T *fp;
129 char const *buf;
130 size_t n;
131 {
132 register SM_STR_OBJ_T *s = fp->f_cookie;
133
134 if (!(s->strio_flags & SMWR) && !(s->strio_flags & SMRW))
135 {
136 errno = EBADF;
137 return -1;
138 }
139 if (n + s->strio_offset > s->strio_size)
140 {
141 if (!sm_strgrow(s, n + s->strio_offset))
142 return 0;
143 }
144 (void) memmove(s->strio_base + s->strio_offset, buf, n);
145 s->strio_offset += n;
146 return n;
147 }
148
149 /*
150 ** SM_STRSEEK -- position the offset pointer for the string
151 **
152 ** Only SM_IO_SEEK_SET, SM_IO_SEEK_CUR and SM_IO_SEEK_END are valid
153 ** values for whence.
154 **
155 ** Parameters:
156 ** fp -- the file pointer
157 ** offset -- number of bytes offset from "base"
158 ** whence -- determines "base" for 'offset'
159 **
160 ** Returns:
161 ** Failure: -1 and sets errno
162 ** Success: >=0, number of bytes read
163 */
164
165 off_t
sm_strseek(fp,offset,whence)166 sm_strseek(fp, offset, whence)
167 SM_FILE_T *fp;
168 off_t offset;
169 int whence;
170 {
171 register off_t ret;
172 register SM_STR_OBJ_T *s = fp->f_cookie;
173
174 reseek:
175 switch (whence)
176 {
177 case SM_IO_SEEK_SET:
178 ret = offset;
179 break;
180 case SM_IO_SEEK_CUR:
181 ret = s->strio_offset + offset;
182 break;
183 case SM_IO_SEEK_END:
184 ret = s->strio_size;
185 break;
186 default:
187 errno = EINVAL;
188 return -1;
189 }
190 if (ret < 0 || ret > (off_t)(size_t)(-1)) /* XXX ugly */
191 return -1;
192 if ((size_t) ret > s->strio_size)
193 {
194 if (sm_strgrow(s, (size_t)ret))
195 goto reseek;
196
197 /* errno set by sm_strgrow */
198 return -1;
199 }
200 s->strio_offset = (size_t) ret;
201 return ret;
202 }
203
204 /*
205 ** SM_STROPEN -- open a string file type
206 **
207 ** Parameters:
208 ** fp -- file pointer open to be associated with
209 ** info -- initial contents (NULL for none)
210 ** flags -- flags for methods of access (was mode)
211 ** rpool -- resource pool to use memory from (if applicable)
212 **
213 ** Results:
214 ** Success: 0 (zero)
215 ** Failure: -1 and sets errno
216 */
217
218 int
sm_stropen(fp,info,flags,rpool)219 sm_stropen(fp, info, flags, rpool)
220 SM_FILE_T *fp;
221 const void *info;
222 int flags;
223 const void *rpool;
224 {
225 register SM_STR_OBJ_T *s;
226
227 #if SM_RPOOL
228 s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T));
229 #else /* SM_RPOOL */
230 s = sm_malloc(sizeof(SM_STR_OBJ_T));
231 if (s == NULL)
232 return -1;
233 #endif /* SM_RPOOL */
234
235 fp->f_cookie = s;
236 s->strio_rpool = rpool;
237 s->strio_offset = 0;
238 s->strio_size = 0;
239 s->strio_base = NULL;
240 s->strio_end = 0;
241
242 switch (flags)
243 {
244 case SM_IO_RDWR:
245 s->strio_flags = SMRW;
246 break;
247 case SM_IO_RDONLY:
248 s->strio_flags = SMRD;
249 break;
250 case SM_IO_WRONLY:
251 s->strio_flags = SMWR;
252 break;
253 case SM_IO_APPEND:
254 if (s->strio_rpool == NULL)
255 sm_free(s);
256 errno = EINVAL;
257 return -1;
258 default:
259 if (s->strio_rpool == NULL)
260 sm_free(s);
261 errno = EINVAL;
262 return -1;
263 }
264
265 if (info != NULL)
266 {
267 s->strio_base = sm_strdup_x(info);
268 if (s->strio_base == NULL)
269 {
270 int save_errno = errno;
271
272 if (s->strio_rpool == NULL)
273 sm_free(s);
274 errno = save_errno;
275 return -1;
276 }
277 s->strio_size = strlen(info);
278 s->strio_end = s->strio_base + s->strio_size;
279 }
280 return 0;
281 }
282
283 /*
284 ** SM_STRCLOSE -- close the string file type and free resources
285 **
286 ** Parameters:
287 ** fp -- file pointer
288 **
289 ** Results:
290 ** Success: 0 (zero)
291 */
292
293 int
sm_strclose(fp)294 sm_strclose(fp)
295 SM_FILE_T *fp;
296 {
297 SM_STR_OBJ_T *s = fp->f_cookie;
298
299 #if !SM_RPOOL
300 sm_free(s->strio_base);
301 s->strio_base = NULL;
302 #endif /* !SM_RPOOL */
303 return 0;
304 }
305
306 /*
307 ** SM_STRSETMODE -- set mode info for the file
308 **
309 ** Note: changing the mode can be a safe way to have the "parent"
310 ** set up a string that the "child" is not to modify
311 **
312 ** Parameters:
313 ** fp -- the file pointer
314 ** mode -- location of new mode to set
315 **
316 ** Results:
317 ** Success: 0 (zero)
318 ** Failure: -1 and sets errno
319 */
320
321 static int
sm_strsetmode(fp,mode)322 sm_strsetmode(fp, mode)
323 SM_FILE_T *fp;
324 const int *mode;
325 {
326 register SM_STR_OBJ_T *s = fp->f_cookie;
327 int flags;
328
329 switch (*mode)
330 {
331 case SM_IO_RDWR:
332 flags = SMRW;
333 break;
334 case SM_IO_RDONLY:
335 flags = SMRD;
336 break;
337 case SM_IO_WRONLY:
338 flags = SMWR;
339 break;
340 case SM_IO_APPEND:
341 errno = EINVAL;
342 return -1;
343 default:
344 errno = EINVAL;
345 return -1;
346 }
347 s->strio_flags &= ~SMMODEMASK;
348 s->strio_flags |= flags;
349 return 0;
350 }
351
352 /*
353 ** SM_STRGETMODE -- get mode info for the file
354 **
355 ** Parameters:
356 ** fp -- the file pointer
357 ** mode -- location to store current mode
358 **
359 ** Results:
360 ** Success: 0 (zero)
361 ** Failure: -1 and sets errno
362 */
363
364 static int
sm_strgetmode(fp,mode)365 sm_strgetmode(fp, mode)
366 SM_FILE_T *fp;
367 int *mode;
368 {
369 register SM_STR_OBJ_T *s = fp->f_cookie;
370
371 switch (s->strio_flags & SMMODEMASK)
372 {
373 case SMRW:
374 *mode = SM_IO_RDWR;
375 break;
376 case SMRD:
377 *mode = SM_IO_RDONLY;
378 break;
379 case SMWR:
380 *mode = SM_IO_WRONLY;
381 break;
382 default:
383 errno = EINVAL;
384 return -1;
385 }
386 return 0;
387 }
388
389 /*
390 ** SM_STRSETINFO -- set info for the file
391 **
392 ** Currently only SM_IO_WHAT_MODE is supported for 'what'.
393 **
394 ** Parameters:
395 ** fp -- the file pointer
396 ** what -- type of information to set
397 ** valp -- location to data for doing set
398 **
399 ** Results:
400 ** Failure: -1 and sets errno
401 ** Success: sm_strsetmode() return [0 (zero)]
402 */
403
404 int
sm_strsetinfo(fp,what,valp)405 sm_strsetinfo(fp, what, valp)
406 SM_FILE_T *fp;
407 int what;
408 void *valp;
409 {
410 switch(what)
411 {
412 case SM_IO_WHAT_MODE:
413 return sm_strsetmode(fp, (int *) valp);
414 default:
415 errno = EINVAL;
416 return -1;
417 }
418 }
419
420 /*
421 ** SM_STRGETINFO -- get info for the file
422 **
423 ** Currently only SM_IO_WHAT_MODE is supported for 'what'.
424 **
425 ** Parameters:
426 ** fp -- the file pointer
427 ** what -- type of information requested
428 ** valp -- location to return information in
429 **
430 ** Results:
431 ** Failure: -1 and sets errno
432 ** Success: sm_strgetmode() return [0 (zero)]
433 */
434
435 int
sm_strgetinfo(fp,what,valp)436 sm_strgetinfo(fp, what, valp)
437 SM_FILE_T *fp;
438 int what;
439 void *valp;
440 {
441 switch(what)
442 {
443 case SM_IO_WHAT_MODE:
444 return sm_strgetmode(fp, (int *) valp);
445 default:
446 errno = EINVAL;
447 return -1;
448 }
449 }
450
451 /*
452 ** SM_STRIO_INIT -- initializes a write-only string type
453 **
454 ** Original comments below. This function does not appear to be used anywhere.
455 ** The same functionality can be done by changing the mode of the file.
456 ** ------------
457 ** sm_strio_init initializes an SM_FILE_T structure as a write-only file
458 ** that writes into the specified buffer:
459 ** - Use sm_io_putc, sm_io_fprintf, etc, to write into the buffer.
460 ** Attempts to write more than size-1 characters into the buffer will fail
461 ** silently (no error is reported).
462 ** - Use sm_io_fflush to nul terminate the string in the buffer
463 ** (the write pointer is not advanced).
464 ** No memory is allocated either by sm_strio_init or by sm_io_{putc,write} etc.
465 **
466 ** Parameters:
467 ** fp -- file pointer
468 ** buf -- memory location for stored data
469 ** size -- size of 'buf'
470 **
471 ** Results:
472 ** none.
473 */
474
475 void
sm_strio_init(fp,buf,size)476 sm_strio_init(fp, buf, size)
477 SM_FILE_T *fp;
478 char *buf;
479 size_t size;
480 {
481 fp->sm_magic = SmFileMagic;
482 fp->f_flags = SMWR | SMSTR;
483 fp->f_file = -1;
484 fp->f_bf.smb_base = fp->f_p = (unsigned char *) buf;
485 fp->f_bf.smb_size = fp->f_w = (size ? size - 1 : 0);
486 fp->f_lbfsize = 0;
487 fp->f_r = 0;
488 fp->f_read = NULL;
489 fp->f_seek = NULL;
490 fp->f_getinfo = NULL;
491 fp->f_setinfo = NULL;
492 }
493