190792Sgshapiro/*
2261194Sgshapiro * Copyright (c) 2000-2002, 2004, 2005 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *      All rights reserved.
490792Sgshapiro * Copyright (c) 1990, 1993
590792Sgshapiro *	The Regents of the University of California.  All rights reserved.
690792Sgshapiro *
790792Sgshapiro * This code is derived from software contributed to Berkeley by
890792Sgshapiro * Chris Torek.
990792Sgshapiro *
1090792Sgshapiro * By using this file, you agree to the terms and conditions set
1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of
1290792Sgshapiro * the sendmail distribution.
1390792Sgshapiro */
1490792Sgshapiro
1590792Sgshapiro#include <sm/gen.h>
16266527SgshapiroSM_IDSTR(id, "@(#)$Id: strio.c,v 1.45 2013-11-22 20:51:43 ca Exp $")
1790792Sgshapiro#include <stdlib.h>
1890792Sgshapiro#include <unistd.h>
1990792Sgshapiro#include <fcntl.h>
2090792Sgshapiro#include <string.h>
2190792Sgshapiro#include <errno.h>
2290792Sgshapiro#include <sm/rpool.h>
2390792Sgshapiro#include <sm/io.h>
2490792Sgshapiro#include <sm/heap.h>
2590792Sgshapiro#include <sm/conf.h>
2690792Sgshapiro#include "local.h"
2790792Sgshapiro
28141858Sgshapirostatic int	sm_strsetmode __P((SM_FILE_T*, const int *));
29141858Sgshapirostatic int	sm_strgetmode __P((SM_FILE_T*, int *));
30141858Sgshapiro
3190792Sgshapiro/*
3290792Sgshapiro**  Cookie structure for the "strio" file type
3390792Sgshapiro*/
3490792Sgshapiro
3590792Sgshapirostruct sm_str_obj
3690792Sgshapiro{
3794334Sgshapiro	char		*strio_base;
3894334Sgshapiro	char		*strio_end;
3994334Sgshapiro	size_t		strio_size;
4094334Sgshapiro	size_t		strio_offset;
4194334Sgshapiro	int		strio_flags;
4294334Sgshapiro	const void	*strio_rpool;
4390792Sgshapiro};
4490792Sgshapiro
4590792Sgshapirotypedef struct sm_str_obj SM_STR_OBJ_T;
4690792Sgshapiro
4790792Sgshapiro/*
4890792Sgshapiro**  SM_STRGROW -- increase storage space for string
4990792Sgshapiro**
5090792Sgshapiro**	Parameters:
5190792Sgshapiro**		s -- current cookie
5290792Sgshapiro**		size -- new storage size request
5390792Sgshapiro**
5490792Sgshapiro**	Returns:
5590792Sgshapiro**		true iff successful.
5690792Sgshapiro*/
5790792Sgshapiro
5890792Sgshapirostatic bool sm_strgrow __P((SM_STR_OBJ_T *, size_t));
5990792Sgshapiro
6090792Sgshapirostatic bool
6190792Sgshapirosm_strgrow(s, size)
6290792Sgshapiro	SM_STR_OBJ_T *s;
6390792Sgshapiro	size_t size;
6490792Sgshapiro{
6590792Sgshapiro	register void *p;
6690792Sgshapiro
6790792Sgshapiro	if (s->strio_size >= size)
6890792Sgshapiro		return true;
6990792Sgshapiro	p = sm_realloc(s->strio_base, size);
7090792Sgshapiro	if (p == NULL)
7190792Sgshapiro		return false;
7290792Sgshapiro	s->strio_base = p;
7390792Sgshapiro	s->strio_end = s->strio_base + size;
7490792Sgshapiro	s->strio_size = size;
7590792Sgshapiro	return true;
7690792Sgshapiro}
7790792Sgshapiro
7890792Sgshapiro/*
7990792Sgshapiro**  SM_STRREAD -- read a portion of the string
8090792Sgshapiro**
8190792Sgshapiro**	Parameters:
8290792Sgshapiro**		fp -- the file pointer
8390792Sgshapiro**		buf -- location to place read data
8490792Sgshapiro**		n -- number of bytes to read
8590792Sgshapiro**
8690792Sgshapiro**	Returns:
8790792Sgshapiro**		Failure: -1 and sets errno
8890792Sgshapiro**		Success: >=0, number of bytes read
8990792Sgshapiro*/
9090792Sgshapiro
9190792Sgshapirossize_t
9290792Sgshapirosm_strread(fp, buf, n)
9390792Sgshapiro	SM_FILE_T *fp;
9490792Sgshapiro	char *buf;
9590792Sgshapiro	size_t n;
9690792Sgshapiro{
9790792Sgshapiro	register SM_STR_OBJ_T *s = fp->f_cookie;
9890792Sgshapiro	int len;
9990792Sgshapiro
10090792Sgshapiro	if (!(s->strio_flags & SMRD) && !(s->strio_flags & SMRW))
10190792Sgshapiro	{
10290792Sgshapiro		errno = EBADF;
10390792Sgshapiro		return -1;
10490792Sgshapiro	}
10590792Sgshapiro	len = SM_MIN(s->strio_size - s->strio_offset, n);
10690792Sgshapiro	(void) memmove(buf, s->strio_base + s->strio_offset, len);
10790792Sgshapiro	s->strio_offset += len;
10890792Sgshapiro	return len;
10990792Sgshapiro}
11090792Sgshapiro
11190792Sgshapiro/*
11290792Sgshapiro**  SM_STRWRITE -- write a portion of the string
11390792Sgshapiro**
11490792Sgshapiro**	Parameters:
11590792Sgshapiro**		fp -- the file pointer
11694334Sgshapiro**		buf -- location of data for writing
11790792Sgshapiro**		n -- number of bytes to write
11890792Sgshapiro**
11990792Sgshapiro**	Returns:
12090792Sgshapiro**		Failure: -1 and sets errno
12190792Sgshapiro**		Success: >=0, number of bytes written
12290792Sgshapiro*/
12390792Sgshapiro
12490792Sgshapirossize_t
12590792Sgshapirosm_strwrite(fp, buf, n)
12690792Sgshapiro	SM_FILE_T *fp;
12790792Sgshapiro	char const *buf;
12890792Sgshapiro	size_t n;
12990792Sgshapiro{
13090792Sgshapiro	register SM_STR_OBJ_T *s = fp->f_cookie;
13190792Sgshapiro
13290792Sgshapiro	if (!(s->strio_flags & SMWR) && !(s->strio_flags & SMRW))
13390792Sgshapiro	{
13490792Sgshapiro		errno = EBADF;
13590792Sgshapiro		return -1;
13690792Sgshapiro	}
13790792Sgshapiro	if (n + s->strio_offset > s->strio_size)
13890792Sgshapiro	{
13990792Sgshapiro		if (!sm_strgrow(s, n + s->strio_offset))
14090792Sgshapiro			return 0;
14190792Sgshapiro	}
14290792Sgshapiro	(void) memmove(s->strio_base + s->strio_offset, buf, n);
14390792Sgshapiro	s->strio_offset += n;
14490792Sgshapiro	return n;
14590792Sgshapiro}
14690792Sgshapiro
14790792Sgshapiro/*
14890792Sgshapiro**  SM_STRSEEK -- position the offset pointer for the string
14990792Sgshapiro**
15090792Sgshapiro**	Only SM_IO_SEEK_SET, SM_IO_SEEK_CUR and SM_IO_SEEK_END are valid
15190792Sgshapiro**	values for whence.
15290792Sgshapiro**
15390792Sgshapiro**	Parameters:
15490792Sgshapiro**		fp -- the file pointer
15590792Sgshapiro**		offset -- number of bytes offset from "base"
15690792Sgshapiro**		whence -- determines "base" for 'offset'
15790792Sgshapiro**
15890792Sgshapiro**	Returns:
15990792Sgshapiro**		Failure: -1 and sets errno
16090792Sgshapiro**		Success: >=0, number of bytes read
16190792Sgshapiro*/
16290792Sgshapiro
16390792Sgshapirooff_t
16490792Sgshapirosm_strseek(fp, offset, whence)
16590792Sgshapiro	SM_FILE_T *fp;
16690792Sgshapiro	off_t offset;
16790792Sgshapiro	int whence;
16890792Sgshapiro{
16990792Sgshapiro	register off_t ret;
17090792Sgshapiro	register SM_STR_OBJ_T *s = fp->f_cookie;
17190792Sgshapiro
17290792Sgshapiroreseek:
17390792Sgshapiro	switch (whence)
17490792Sgshapiro	{
17590792Sgshapiro	  case SM_IO_SEEK_SET:
17690792Sgshapiro		ret = offset;
17790792Sgshapiro		break;
17890792Sgshapiro	  case SM_IO_SEEK_CUR:
17990792Sgshapiro		ret = s->strio_offset + offset;
18090792Sgshapiro		break;
18190792Sgshapiro	  case SM_IO_SEEK_END:
18290792Sgshapiro		ret = s->strio_size;
18390792Sgshapiro		break;
18490792Sgshapiro	  default:
18590792Sgshapiro		errno = EINVAL;
18690792Sgshapiro		return -1;
18790792Sgshapiro	}
18890792Sgshapiro	if (ret < 0 || ret > (off_t)(size_t)(-1))	/* XXX ugly */
18990792Sgshapiro		return -1;
19090792Sgshapiro	if ((size_t) ret > s->strio_size)
19190792Sgshapiro	{
19290792Sgshapiro		if (sm_strgrow(s, (size_t)ret))
19390792Sgshapiro			goto reseek;
19490792Sgshapiro
19590792Sgshapiro		/* errno set by sm_strgrow */
19690792Sgshapiro		return -1;
19790792Sgshapiro	}
19890792Sgshapiro	s->strio_offset = (size_t) ret;
19990792Sgshapiro	return ret;
20090792Sgshapiro}
20190792Sgshapiro
20290792Sgshapiro/*
20390792Sgshapiro**  SM_STROPEN -- open a string file type
20490792Sgshapiro**
20590792Sgshapiro**	Parameters:
20690792Sgshapiro**		fp -- file pointer open to be associated with
20794334Sgshapiro**		info -- initial contents (NULL for none)
20894334Sgshapiro**		flags -- flags for methods of access (was mode)
20990792Sgshapiro**		rpool -- resource pool to use memory from (if applicable)
21090792Sgshapiro**
21190792Sgshapiro**	Results:
21290792Sgshapiro**		Success: 0 (zero)
21390792Sgshapiro**		Failure: -1 and sets errno
21490792Sgshapiro*/
21590792Sgshapiro
21690792Sgshapiroint
21790792Sgshapirosm_stropen(fp, info, flags, rpool)
21890792Sgshapiro	SM_FILE_T *fp;
21990792Sgshapiro	const void *info;
22090792Sgshapiro	int flags;
22190792Sgshapiro	const void *rpool;
22290792Sgshapiro{
22390792Sgshapiro	register SM_STR_OBJ_T *s;
22490792Sgshapiro
22590792Sgshapiro#if SM_RPOOL
22690792Sgshapiro	s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T));
22790792Sgshapiro#else /* SM_RPOOL */
22890792Sgshapiro	s = sm_malloc(sizeof(SM_STR_OBJ_T));
22990792Sgshapiro	if (s == NULL)
23090792Sgshapiro		return -1;
23190792Sgshapiro#endif /* SM_RPOOL */
23290792Sgshapiro
23390792Sgshapiro	fp->f_cookie = s;
23494334Sgshapiro	s->strio_rpool = rpool;
23590792Sgshapiro	s->strio_offset = 0;
23694334Sgshapiro	s->strio_size = 0;
23794334Sgshapiro	s->strio_base = NULL;
23890792Sgshapiro	s->strio_end = 0;
23994334Sgshapiro
24094334Sgshapiro	switch (flags)
24190792Sgshapiro	{
24290792Sgshapiro	  case SM_IO_RDWR:
24390792Sgshapiro		s->strio_flags = SMRW;
24490792Sgshapiro		break;
24590792Sgshapiro	  case SM_IO_RDONLY:
24690792Sgshapiro		s->strio_flags = SMRD;
24790792Sgshapiro		break;
24890792Sgshapiro	  case SM_IO_WRONLY:
24990792Sgshapiro		s->strio_flags = SMWR;
25090792Sgshapiro		break;
25190792Sgshapiro	  case SM_IO_APPEND:
25294334Sgshapiro		if (s->strio_rpool == NULL)
25394334Sgshapiro			sm_free(s);
25494334Sgshapiro		errno = EINVAL;
25590792Sgshapiro		return -1;
25690792Sgshapiro	  default:
25794334Sgshapiro		if (s->strio_rpool == NULL)
25894334Sgshapiro			sm_free(s);
25990792Sgshapiro		errno = EINVAL;
26090792Sgshapiro		return -1;
26190792Sgshapiro	}
26294334Sgshapiro
26394334Sgshapiro	if (info != NULL)
26494334Sgshapiro	{
26594334Sgshapiro		s->strio_base = sm_strdup_x(info);
26694334Sgshapiro		if (s->strio_base == NULL)
26794334Sgshapiro		{
26894334Sgshapiro			int save_errno = errno;
26994334Sgshapiro
27094334Sgshapiro			if (s->strio_rpool == NULL)
27194334Sgshapiro				sm_free(s);
27294334Sgshapiro			errno = save_errno;
27394334Sgshapiro			return -1;
27494334Sgshapiro		}
27594334Sgshapiro		s->strio_size = strlen(info);
27694334Sgshapiro		s->strio_end = s->strio_base + s->strio_size;
27794334Sgshapiro	}
27890792Sgshapiro	return 0;
27990792Sgshapiro}
28090792Sgshapiro
28190792Sgshapiro/*
28290792Sgshapiro**  SM_STRCLOSE -- close the string file type and free resources
28390792Sgshapiro**
28490792Sgshapiro**	Parameters:
28590792Sgshapiro**		fp -- file pointer
28690792Sgshapiro**
28790792Sgshapiro**	Results:
28890792Sgshapiro**		Success: 0 (zero)
28990792Sgshapiro*/
29090792Sgshapiro
29190792Sgshapiroint
29290792Sgshapirosm_strclose(fp)
29390792Sgshapiro	SM_FILE_T *fp;
29490792Sgshapiro{
29590792Sgshapiro	SM_STR_OBJ_T *s = fp->f_cookie;
29690792Sgshapiro
29790792Sgshapiro#if !SM_RPOOL
29890792Sgshapiro	sm_free(s->strio_base);
29990792Sgshapiro	s->strio_base = NULL;
30090792Sgshapiro#endif /* !SM_RPOOL */
30190792Sgshapiro	return 0;
30290792Sgshapiro}
30390792Sgshapiro
30490792Sgshapiro/*
30590792Sgshapiro**  SM_STRSETMODE -- set mode info for the file
30690792Sgshapiro**
30790792Sgshapiro**	 Note: changing the mode can be a safe way to have the "parent"
30890792Sgshapiro**	 set up a string that the "child" is not to modify
30990792Sgshapiro**
31090792Sgshapiro**	Parameters:
31190792Sgshapiro**		fp -- the file pointer
31290792Sgshapiro**		mode -- location of new mode to set
31390792Sgshapiro**
31490792Sgshapiro**	Results:
31590792Sgshapiro**		Success: 0 (zero)
31690792Sgshapiro**		Failure: -1 and sets errno
31790792Sgshapiro*/
31890792Sgshapiro
319141858Sgshapirostatic int
32090792Sgshapirosm_strsetmode(fp, mode)
32190792Sgshapiro	SM_FILE_T *fp;
32290792Sgshapiro	const int *mode;
32390792Sgshapiro{
32490792Sgshapiro	register SM_STR_OBJ_T *s = fp->f_cookie;
32590792Sgshapiro	int flags;
32690792Sgshapiro
32790792Sgshapiro	switch (*mode)
32890792Sgshapiro	{
32990792Sgshapiro	  case SM_IO_RDWR:
33090792Sgshapiro		flags = SMRW;
33190792Sgshapiro		break;
33290792Sgshapiro	  case SM_IO_RDONLY:
33390792Sgshapiro		flags = SMRD;
33490792Sgshapiro		break;
33590792Sgshapiro	  case SM_IO_WRONLY:
33690792Sgshapiro		flags = SMWR;
33790792Sgshapiro		break;
33890792Sgshapiro	  case SM_IO_APPEND:
33990792Sgshapiro		errno = EINVAL;
34090792Sgshapiro		return -1;
34190792Sgshapiro	  default:
34290792Sgshapiro		errno = EINVAL;
34390792Sgshapiro		return -1;
34490792Sgshapiro	}
34590792Sgshapiro	s->strio_flags &= ~SMMODEMASK;
34690792Sgshapiro	s->strio_flags |= flags;
34790792Sgshapiro	return 0;
34890792Sgshapiro}
34990792Sgshapiro
35090792Sgshapiro/*
35190792Sgshapiro**  SM_STRGETMODE -- get mode info for the file
35290792Sgshapiro**
35390792Sgshapiro**	Parameters:
35490792Sgshapiro**		fp -- the file pointer
35590792Sgshapiro**		mode -- location to store current mode
35690792Sgshapiro**
35790792Sgshapiro**	Results:
35890792Sgshapiro**		Success: 0 (zero)
35990792Sgshapiro**		Failure: -1 and sets errno
36090792Sgshapiro*/
36190792Sgshapiro
362157001Sgshapirostatic int
36390792Sgshapirosm_strgetmode(fp, mode)
36490792Sgshapiro	SM_FILE_T *fp;
36590792Sgshapiro	int *mode;
36690792Sgshapiro{
36790792Sgshapiro	register SM_STR_OBJ_T *s = fp->f_cookie;
36890792Sgshapiro
36990792Sgshapiro	switch (s->strio_flags & SMMODEMASK)
37090792Sgshapiro	{
37190792Sgshapiro	  case SMRW:
37290792Sgshapiro		*mode = SM_IO_RDWR;
37390792Sgshapiro		break;
37490792Sgshapiro	  case SMRD:
37590792Sgshapiro		*mode = SM_IO_RDONLY;
37690792Sgshapiro		break;
37790792Sgshapiro	  case SMWR:
37890792Sgshapiro		*mode = SM_IO_WRONLY;
37990792Sgshapiro		break;
38090792Sgshapiro	  default:
38190792Sgshapiro		errno = EINVAL;
38290792Sgshapiro		return -1;
38390792Sgshapiro	}
38490792Sgshapiro	return 0;
38590792Sgshapiro}
38690792Sgshapiro
38790792Sgshapiro/*
38890792Sgshapiro**  SM_STRSETINFO -- set info for the file
38990792Sgshapiro**
39090792Sgshapiro**	Currently only SM_IO_WHAT_MODE is supported for 'what'.
39190792Sgshapiro**
39290792Sgshapiro**	Parameters:
39390792Sgshapiro**		fp -- the file pointer
39490792Sgshapiro**		what -- type of information to set
39590792Sgshapiro**		valp -- location to data for doing set
39690792Sgshapiro**
39790792Sgshapiro**	Results:
39890792Sgshapiro**		Failure: -1 and sets errno
39990792Sgshapiro**		Success: sm_strsetmode() return [0 (zero)]
40090792Sgshapiro*/
40190792Sgshapiro
40290792Sgshapiroint
40390792Sgshapirosm_strsetinfo(fp, what, valp)
40490792Sgshapiro	SM_FILE_T *fp;
40590792Sgshapiro	int what;
40690792Sgshapiro	void *valp;
40790792Sgshapiro{
40890792Sgshapiro	switch(what)
40990792Sgshapiro	{
41090792Sgshapiro	  case SM_IO_WHAT_MODE:
41190792Sgshapiro		return sm_strsetmode(fp, (int *) valp);
41290792Sgshapiro	  default:
41390792Sgshapiro		errno = EINVAL;
41490792Sgshapiro		return -1;
41590792Sgshapiro	}
41690792Sgshapiro}
41790792Sgshapiro
41890792Sgshapiro/*
41990792Sgshapiro**  SM_STRGETINFO -- get info for the file
42090792Sgshapiro**
42190792Sgshapiro**	Currently only SM_IO_WHAT_MODE is supported for 'what'.
42290792Sgshapiro**
42390792Sgshapiro**	Parameters:
42490792Sgshapiro**		fp -- the file pointer
42590792Sgshapiro**		what -- type of information requested
42690792Sgshapiro**		valp -- location to return information in
42790792Sgshapiro**
42890792Sgshapiro**	Results:
42990792Sgshapiro**		Failure: -1 and sets errno
43090792Sgshapiro**		Success: sm_strgetmode() return [0 (zero)]
43190792Sgshapiro*/
43290792Sgshapiro
43390792Sgshapiroint
43490792Sgshapirosm_strgetinfo(fp, what, valp)
43590792Sgshapiro	SM_FILE_T *fp;
43690792Sgshapiro	int what;
43790792Sgshapiro	void *valp;
43890792Sgshapiro{
43990792Sgshapiro	switch(what)
44090792Sgshapiro	{
44190792Sgshapiro	  case SM_IO_WHAT_MODE:
44290792Sgshapiro		return sm_strgetmode(fp, (int *) valp);
44390792Sgshapiro	  default:
44490792Sgshapiro		errno = EINVAL;
44590792Sgshapiro		return -1;
44690792Sgshapiro	}
44790792Sgshapiro}
44890792Sgshapiro
44990792Sgshapiro/*
45090792Sgshapiro**  SM_STRIO_INIT -- initializes a write-only string type
45190792Sgshapiro**
45290792Sgshapiro**  Original comments below. This function does not appear to be used anywhere.
45390792Sgshapiro**  The same functionality can be done by changing the mode of the file.
45490792Sgshapiro**  ------------
45590792Sgshapiro** sm_strio_init initializes an SM_FILE_T structure as a write-only file
45690792Sgshapiro** that writes into the specified buffer:
45790792Sgshapiro** - Use sm_io_putc, sm_io_fprintf, etc, to write into the buffer.
45890792Sgshapiro**   Attempts to write more than size-1 characters into the buffer will fail
45990792Sgshapiro**   silently (no error is reported).
46090792Sgshapiro** - Use sm_io_fflush to nul terminate the string in the buffer
46190792Sgshapiro**   (the write pointer is not advanced).
46290792Sgshapiro** No memory is allocated either by sm_strio_init or by sm_io_{putc,write} etc.
46390792Sgshapiro**
46490792Sgshapiro**	Parameters:
46590792Sgshapiro**		fp -- file pointer
46690792Sgshapiro**		buf -- memory location for stored data
46790792Sgshapiro**		size -- size of 'buf'
46890792Sgshapiro**
46990792Sgshapiro**	Results:
47090792Sgshapiro**		none.
47190792Sgshapiro*/
47290792Sgshapiro
47390792Sgshapirovoid
47490792Sgshapirosm_strio_init(fp, buf, size)
47590792Sgshapiro	SM_FILE_T *fp;
47690792Sgshapiro	char *buf;
47790792Sgshapiro	size_t size;
47890792Sgshapiro{
47990792Sgshapiro	fp->sm_magic = SmFileMagic;
48090792Sgshapiro	fp->f_flags = SMWR | SMSTR;
48190792Sgshapiro	fp->f_file = -1;
48290792Sgshapiro	fp->f_bf.smb_base = fp->f_p = (unsigned char *) buf;
48390792Sgshapiro	fp->f_bf.smb_size = fp->f_w = (size ? size - 1 : 0);
48490792Sgshapiro	fp->f_lbfsize = 0;
48590792Sgshapiro	fp->f_r = 0;
48690792Sgshapiro	fp->f_read = NULL;
48790792Sgshapiro	fp->f_seek = NULL;
48890792Sgshapiro	fp->f_getinfo = NULL;
48990792Sgshapiro	fp->f_setinfo = NULL;
49090792Sgshapiro}
491