strio.c revision 95154
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>
16SM_IDSTR(id, "@(#)$Id: strio.c,v 1.1.1.2 2002/04/10 03:04:56 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
32struct 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
42typedef 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
55static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t));
56
57static bool
58sm_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
88ssize_t
89sm_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
121ssize_t
122sm_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
160off_t
161sm_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
169reseek:
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
213int
214sm_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
288int
289sm_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
316int
317sm_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
359int
360sm_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
399int
400sm_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
430int
431sm_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
470void
471sm_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