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