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