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>
16SM_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
28static int	sm_strsetmode __P((SM_FILE_T*, const int *));
29static int	sm_strgetmode __P((SM_FILE_T*, int *));
30
31/*
32**  Cookie structure for the "strio" file type
33*/
34
35struct 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
45typedef 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
58static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t));
59
60static bool
61sm_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
91ssize_t
92sm_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
124ssize_t
125sm_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
163off_t
164sm_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
172reseek:
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
216int
217sm_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
291int
292sm_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
319static int
320sm_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
362static int
363sm_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
402int
403sm_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
433int
434sm_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
473void
474sm_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