xref: /illumos-gate/usr/src/cmd/sendmail/libsm/strio.c (revision 141040e8a310da49386b596573e5dde5580572ec)
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
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
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
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
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
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
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
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
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
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
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
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