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