xref: /freebsd/contrib/sendmail/libsm/strio.c (revision b1f9167f94059fd55c630891d359bcff987bd7eb)
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
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
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
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
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
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 /* SM_RPOOL */
228 	s = sm_malloc(sizeof(SM_STR_OBJ_T));
229 	if (s == NULL)
230 		return -1;
231 #endif /* SM_RPOOL */
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 = 0;
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
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 /* !SM_RPOOL */
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
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
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
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
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
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