14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #include	"sfhdr.h"
23*8462SApril.Chin@Sun.COM static char*	Version = "\n@(#)$Id: sfio (AT&T Research) 2008-07-17 $\0\n";
244887Schin 
254887Schin /*	Functions to set a given stream to some desired mode
264887Schin **
274887Schin **	Written by Kiem-Phong Vo.
284887Schin **
294887Schin **	Modifications:
304887Schin **		06/27/1990 (first version)
314887Schin **		01/06/1991
324887Schin **		07/08/1991
334887Schin **		06/18/1992
344887Schin **		02/02/1993
354887Schin **		05/25/1993
364887Schin **		02/07/1994
374887Schin **		05/21/1996
384887Schin **		08/01/1997
394887Schin **		08/01/1998 (extended formatting)
404887Schin **		09/09/1999 (thread-safe)
414887Schin **		02/01/2001 (adaptive buffering)
424887Schin **		05/31/2002 (multi-byte handling in sfvprintf/vscanf)
434887Schin **		09/06/2002 (SF_IOINTR flag)
444887Schin **		11/15/2002 (%#c for sfvprintf)
454887Schin **		05/31/2003 (sfsetbuf(f,f,align_size) to set alignment for data)
464887Schin **			   (%I1d is fixed to handle "signed char" correctly)
474887Schin **		01/01/2004 Porting issues to various platforms resolved.
48*8462SApril.Chin@Sun.COM **		06/01/2008 Allowing notify() at entering/exiting thread-safe routines.
494887Schin */
504887Schin 
514887Schin /* the below is for protecting the application from SIGPIPE */
524887Schin #if _PACKAGE_ast
534887Schin #include		<sig.h>
544887Schin #include		<wait.h>
554887Schin #define Sfsignal_f	Sig_handler_t
564887Schin #else
574887Schin #include		<signal.h>
584887Schin typedef void(*		Sfsignal_f)_ARG_((int));
594887Schin #endif
604887Schin static int		_Sfsigp = 0; /* # of streams needing SIGPIPE protection */
614887Schin 
624887Schin /* done at exiting time */
634887Schin #if __STD_C
644887Schin static void _sfcleanup(void)
654887Schin #else
664887Schin static void _sfcleanup()
674887Schin #endif
684887Schin {
694887Schin 	reg Sfpool_t*	p;
704887Schin 	reg Sfio_t*	f;
714887Schin 	reg int		n;
724887Schin 	reg int		pool;
734887Schin 
744887Schin 	f = (Sfio_t*)Version; /* shut compiler warning */
754887Schin 
764887Schin 	/* set this so that no more buffering is allowed for write streams */
774887Schin 	_Sfexiting = 1001;
784887Schin 
794887Schin 	sfsync(NIL(Sfio_t*));
804887Schin 
814887Schin 	for(p = &_Sfpool; p; p = p->next)
824887Schin 	{	for(n = 0; n < p->n_sf; ++n)
834887Schin 		{	if(!(f = p->sf[n]) || SFFROZEN(f) )
844887Schin 				continue;
854887Schin 
864887Schin 			SFLOCK(f,0);
874887Schin 			SFMTXLOCK(f);
884887Schin 
894887Schin 			/* let application know that we are leaving */
904887Schin 			(void)SFRAISE(f, SF_ATEXIT, NIL(Void_t*));
914887Schin 
924887Schin 			if(f->flags&SF_STRING)
934887Schin 				continue;
944887Schin 
954887Schin 			/* from now on, write streams are unbuffered */
964887Schin 			pool = f->mode&SF_POOL;
974887Schin 			f->mode &= ~SF_POOL;
984887Schin 			if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE))
994887Schin 				(void)_sfmode(f,SF_WRITE,1);
1004887Schin 			if(((f->bits&SF_MMAP) && f->data) ||
1014887Schin 			   ((f->mode&SF_WRITE) && f->next == f->data) )
1024887Schin 				(void)SFSETBUF(f,NIL(Void_t*),0);
1034887Schin 			f->mode |= pool;
1044887Schin 
1054887Schin 			SFMTXUNLOCK(f);
1064887Schin 			SFOPEN(f,0);
1074887Schin 		}
1084887Schin 	}
1094887Schin }
1104887Schin 
1114887Schin /* put into discrete pool */
1124887Schin #if __STD_C
1134887Schin int _sfsetpool(Sfio_t* f)
1144887Schin #else
1154887Schin int _sfsetpool(f)
1164887Schin Sfio_t*	f;
1174887Schin #endif
1184887Schin {
1194887Schin 	reg Sfpool_t*	p;
1204887Schin 	reg Sfio_t**	array;
1214887Schin 	reg int		n, rv;
1224887Schin 
1234887Schin 	if(!_Sfcleanup)
1244887Schin 	{	_Sfcleanup = _sfcleanup;
1254887Schin 		(void)atexit(_sfcleanup);
1264887Schin 	}
1274887Schin 
1284887Schin 	if(!(p = f->pool) )
1294887Schin 		p = f->pool = &_Sfpool;
1304887Schin 
131*8462SApril.Chin@Sun.COM 	POOLMTXENTER(p);
1324887Schin 
1334887Schin 	rv = -1;
1344887Schin 
1354887Schin 	if(p->n_sf >= p->s_sf)
1364887Schin 	{	if(p->s_sf == 0) /* initialize pool array */
1374887Schin 		{	p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
1384887Schin 			p->sf = p->array;
1394887Schin 		}
1404887Schin 		else	/* allocate a larger array */
1414887Schin 		{	n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
1424887Schin 			if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
1434887Schin 				goto done;
1444887Schin 
1454887Schin 			/* move old array to new one */
1464887Schin 			memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*));
1474887Schin 			if(p->sf != p->array)
1484887Schin 				free((Void_t*)p->sf);
1494887Schin 
1504887Schin 			p->sf = array;
1514887Schin 			p->s_sf = n;
1524887Schin 		}
1534887Schin 	}
1544887Schin 
1554887Schin 	/* always add at end of array because if this was done during some sort
1564887Schin 	   of walk thru all streams, we'll want the new stream to be seen.
1574887Schin 	*/
1584887Schin 	p->sf[p->n_sf++] = f;
1594887Schin 	rv = 0;
1604887Schin 
1614887Schin done:
1624887Schin 	POOLMTXRETURN(p, rv);
1634887Schin }
1644887Schin 
1654887Schin /* create an auxiliary buffer for sfgetr/sfreserve/sfputr */
1664887Schin #if __STD_C
1674887Schin Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size)
1684887Schin #else
1694887Schin Sfrsrv_t* _sfrsrv(f,size)
1704887Schin reg Sfio_t*	f;
1714887Schin reg ssize_t	size;
1724887Schin #endif
1734887Schin {
1744887Schin 	Sfrsrv_t	*rsrv, *rs;
1754887Schin 
1764887Schin 	/* make buffer if nothing yet */
1774887Schin 	size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
1784887Schin 	if(!(rsrv = f->rsrv) || size > rsrv->size)
1794887Schin 	{	if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
1804887Schin 			size = -1;
1814887Schin 		else
1824887Schin 		{	if(rsrv)
1834887Schin 			{	if(rsrv->slen > 0)
1844887Schin 					memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen);
1854887Schin 				free(rsrv);
1864887Schin 			}
1874887Schin 			f->rsrv = rsrv = rs;
1884887Schin 			rsrv->size = size;
1894887Schin 			rsrv->slen = 0;
1904887Schin 		}
1914887Schin 	}
1924887Schin 
1934887Schin 	if(rsrv && size > 0)
1944887Schin 		rsrv->slen = 0;
1954887Schin 
1964887Schin 	return size >= 0 ? rsrv : NIL(Sfrsrv_t*);
1974887Schin }
1984887Schin 
1994887Schin #ifdef SIGPIPE
2004887Schin #if __STD_C
2014887Schin static void ignoresig(int sig)
2024887Schin #else
2034887Schin static void ignoresig(sig)
2044887Schin int sig;
2054887Schin #endif
2064887Schin {
2074887Schin 	signal(sig, ignoresig);
2084887Schin }
2094887Schin #endif
2104887Schin 
2114887Schin #if __STD_C
2124887Schin int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio)
2134887Schin #else
2144887Schin int _sfpopen(f, fd, pid, stdio)
2154887Schin reg Sfio_t*	f;
2164887Schin int		fd;
2174887Schin int		pid;
2184887Schin int		stdio;	/* stdio popen() does not reset SIGPIPE handler */
2194887Schin #endif
2204887Schin {
2214887Schin 	reg Sfproc_t*	p;
2224887Schin 
2234887Schin 	if(f->proc)
2244887Schin 		return 0;
2254887Schin 
2264887Schin 	if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) )
2274887Schin 		return -1;
2284887Schin 
2294887Schin 	p->pid = pid;
2304887Schin 	p->size = p->ndata = 0;
2314887Schin 	p->rdata = NIL(uchar*);
2324887Schin 	p->file = fd;
2334887Schin 	p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0;
2344887Schin 
2354887Schin #ifdef SIGPIPE	/* protect from broken pipe signal */
2364887Schin 	if(p->sigp)
2374887Schin 	{	Sfsignal_f	handler;
2384887Schin 
2394887Schin 		(void)vtmtxlock(_Sfmutex);
2404887Schin 		if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL &&
2414887Schin 		    handler != ignoresig)
2424887Schin 			signal(SIGPIPE, handler); /* honor user handler */
2434887Schin 		_Sfsigp += 1;
2444887Schin 		(void)vtmtxunlock(_Sfmutex);
2454887Schin 	}
2464887Schin #endif
2474887Schin 
2484887Schin 	return 0;
2494887Schin }
2504887Schin 
2514887Schin #if __STD_C
2524887Schin int _sfpclose(reg Sfio_t* f)
2534887Schin #else
2544887Schin int _sfpclose(f)
2554887Schin reg Sfio_t*	f;	/* stream to close */
2564887Schin #endif
2574887Schin {
2584887Schin 	Sfproc_t*	p;
2594887Schin 	int		pid, status;
2604887Schin 
2614887Schin 	if(!(p = f->proc))
2624887Schin 		return -1;
2634887Schin 	f->proc = NIL(Sfproc_t*);
2644887Schin 
2654887Schin 	if(p->rdata)
2664887Schin 		free(p->rdata);
2674887Schin 
2684887Schin 	if(p->pid < 0)
2694887Schin 		status = 0;
2704887Schin 	else
2714887Schin 	{	/* close the associated stream */
2724887Schin 		if(p->file >= 0)
2734887Schin 			CLOSE(p->file);
2744887Schin 
2754887Schin 		/* wait for process termination */
2764887Schin #if _PACKAGE_ast
2774887Schin 		sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
2784887Schin #endif
2794887Schin 		while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR)
2804887Schin 			;
2814887Schin 		if(pid == -1)
2824887Schin 			status = -1;
2834887Schin #if _PACKAGE_ast
2844887Schin 		sigcritical(0);
2854887Schin #endif
2864887Schin 
2874887Schin #ifdef SIGPIPE
2884887Schin 		(void)vtmtxlock(_Sfmutex);
2894887Schin 		if(p->sigp && (_Sfsigp -= 1) <= 0)
2904887Schin 		{	Sfsignal_f	handler;
2914887Schin 			if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL &&
2924887Schin 			   handler != ignoresig)
2934887Schin 				signal(SIGPIPE,handler); /* honor user handler */
2944887Schin 			_Sfsigp = 0;
2954887Schin 		}
2964887Schin 		(void)vtmtxunlock(_Sfmutex);
2974887Schin #endif
2984887Schin 	}
2994887Schin 
3004887Schin 	free(p);
3014887Schin 	return status;
3024887Schin }
3034887Schin 
3044887Schin #if __STD_C
3054887Schin static int _sfpmode(Sfio_t* f, int type)
3064887Schin #else
3074887Schin static int _sfpmode(f,type)
3084887Schin Sfio_t*	f;
3094887Schin int	type;
3104887Schin #endif
3114887Schin {
3124887Schin 	Sfproc_t*	p;
3134887Schin 
3144887Schin 	if(!(p = f->proc) )
3154887Schin 		return -1;
3164887Schin 
3174887Schin 	if(type == SF_WRITE)
3184887Schin 	{	/* save unread data */
3194887Schin 		p->ndata = f->endb-f->next;
3204887Schin 		if(p->ndata > p->size)
3214887Schin 		{	if(p->rdata)
3224887Schin 				free((char*)p->rdata);
3234887Schin 			if((p->rdata = (uchar*)malloc(p->ndata)) )
3244887Schin 				p->size = p->ndata;
3254887Schin 			else
3264887Schin 			{	p->size = 0;
3274887Schin 				return -1;
3284887Schin 			}
3294887Schin 		}
3304887Schin 		if(p->ndata > 0)
3314887Schin 			memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
3324887Schin 		f->endb = f->data;
3334887Schin 	}
3344887Schin 	else
3354887Schin 	{	/* restore read data */
3364887Schin 		if(p->ndata > f->size)	/* may lose data!!! */
3374887Schin 			p->ndata = f->size;
3384887Schin 		if(p->ndata > 0)
3394887Schin 		{	memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
3404887Schin 			f->endb = f->data+p->ndata;
3414887Schin 			p->ndata = 0;
3424887Schin 		}
3434887Schin 	}
3444887Schin 
3454887Schin 	/* switch file descriptor */
3464887Schin 	if(p->pid >= 0)
3474887Schin 	{	type = f->file;
3484887Schin 		f->file = p->file;
3494887Schin 		p->file = type;
3504887Schin 	}
3514887Schin 
3524887Schin 	return 0;
3534887Schin }
3544887Schin 
3554887Schin #if __STD_C
3564887Schin int _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
3574887Schin #else
3584887Schin int _sfmode(f, wanted, local)
3594887Schin reg Sfio_t*	f;	/* change r/w mode and sync file pointer for this stream */
3604887Schin reg int		wanted;	/* desired mode */
3614887Schin reg int		local;	/* a local call */
3624887Schin #endif
3634887Schin {
3644887Schin 	reg int	n;
3654887Schin 	Sfoff_t	addr;
3664887Schin 	reg int	rv = 0;
3674887Schin 
3684887Schin 	SFONCE();	/* initialize mutexes */
3694887Schin 
3704887Schin 	if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */
3714887Schin 	{	wanted &= ~SF_SYNCED;
3724887Schin 		if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
3734887Schin 		{	f->next = f->endb = f->endr = f->data;
3744887Schin 			f->mode &= ~SF_SYNCED;
3754887Schin 		}
3764887Schin 	}
3774887Schin 
3784887Schin 	if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
3794887Schin 	{	if(local || !f->disc || !f->disc->exceptf)
3804887Schin 		{	local = 1;
3814887Schin 			goto err_notify;
3824887Schin 		}
3834887Schin 
3844887Schin 		for(;;)
3854887Schin 		{	if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0)
3864887Schin 				return rv;
3874887Schin 			if((!local && SFFROZEN(f)) ||
3884887Schin 			   (!(f->flags&SF_STRING) && f->file < 0) )
3894887Schin 			{	if(rv == 0)
3904887Schin 				{	local = 1;
3914887Schin 					goto err_notify;
3924887Schin 				}
3934887Schin 				else	continue;
3944887Schin 			}
3954887Schin 			else	break;
3964887Schin 		}
3974887Schin 	}
3984887Schin 
3994887Schin 	if(f->mode&SF_GETR)
4004887Schin 	{	f->mode &= ~SF_GETR;
4014887Schin #ifdef MAP_TYPE
4024887Schin 		if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) )
4034887Schin 		{	/* turn off mmap to avoid page faulting */
4044887Schin 			sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
4054887Schin 			f->tiny[0] = 0;
4064887Schin 		}
4074887Schin 		else
4084887Schin #endif
4094887Schin 		if(f->getr)
4104887Schin 		{	f->next[-1] = f->getr;
4114887Schin 			f->getr = 0;
4124887Schin 		}
4134887Schin 	}
4144887Schin 
4154887Schin 	if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
4164887Schin 		(*_Sfstdsync)(f);
4174887Schin 
4184887Schin 	if(f->disc == _Sfudisc && wanted == SF_WRITE &&
4194887Schin 	   sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 )
4204887Schin 	{	local = 1;
4214887Schin 		goto err_notify;
4224887Schin 	}
4234887Schin 
4244887Schin 	if(f->mode&SF_POOL)
4254887Schin 	{	/* move to head of pool */
4264887Schin 		if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
4274887Schin 		{	local = 1;
4284887Schin 			goto err_notify;
4294887Schin 		}
4304887Schin 		f->mode &= ~SF_POOL;
4314887Schin 	}
4324887Schin 
4334887Schin 	SFLOCK(f,local);
4344887Schin 
4354887Schin 	/* buffer initialization */
4364887Schin 	wanted &= SF_RDWR;
4374887Schin 	if(f->mode&SF_INIT)
4384887Schin 	{
4394887Schin 		if(!f->pool && _sfsetpool(f) < 0)
4404887Schin 		{	rv = -1;
4414887Schin 			goto done;
4424887Schin 		}
4434887Schin 
4444887Schin 		if(wanted == 0)
4454887Schin 			goto done;
4464887Schin 
4474887Schin 		if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) )
4484887Schin 			goto err_notify;
4494887Schin 
4504887Schin 		if((f->flags&SF_STRING) && f->size >= 0 && f->data)
4514887Schin 		{	f->mode &= ~SF_INIT;
4524887Schin 			f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ?
4534887Schin 					f->size : 0;
4544887Schin 			f->here = 0;
4554887Schin 			f->endb = f->data + f->size;
4564887Schin 			f->next = f->endr = f->endw = f->data;
4574887Schin 			if(f->mode&SF_READ)
4584887Schin 				f->endr = f->endb;
4594887Schin 			else	f->endw = f->endb;
4604887Schin 		}
4614887Schin 		else
4624887Schin 		{	n = f->flags;
4634887Schin 			(void)SFSETBUF(f,f->data,f->size);
4644887Schin 			f->flags |= (n&SF_MALLOC);
4654887Schin 		}
4664887Schin 	}
4674887Schin 
4684887Schin 	if(wanted == (int)SFMODE(f,1))
4694887Schin 		goto done;
4704887Schin 
4714887Schin 	switch(SFMODE(f,1))
4724887Schin 	{
4734887Schin 	case SF_WRITE: /* switching to SF_READ */
4744887Schin 		if(wanted == 0 || wanted == SF_WRITE)
4754887Schin 			break;
4764887Schin 		if(!(f->flags&SF_READ) )
4774887Schin 			goto err_notify;
4784887Schin 		else if(f->flags&SF_STRING)
4794887Schin 		{	SFSTRSIZE(f);
4804887Schin 			f->endb = f->data+f->extent;
4814887Schin 			f->mode = SF_READ;
4824887Schin 			break;
4834887Schin 		}
4844887Schin 
4854887Schin 		/* reset buffer */
4864887Schin 		if(f->next > f->data && SFFLSBUF(f,-1) < 0)
4874887Schin 			goto err_notify;
4884887Schin 
4894887Schin 		if(f->size == 0)
4904887Schin 		{	/* unbuffered */
4914887Schin 			f->data = f->tiny;
4924887Schin 			f->size = sizeof(f->tiny);
4934887Schin 		}
4944887Schin 		f->next = f->endr = f->endw = f->endb = f->data;
4954887Schin 		f->mode = SF_READ|SF_LOCK;
4964887Schin 
4974887Schin 		/* restore saved read data for coprocess */
4984887Schin 		if(f->proc && _sfpmode(f,wanted) < 0)
4994887Schin 			goto err_notify;
5004887Schin 
5014887Schin 		break;
5024887Schin 
5034887Schin 	case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
5044887Schin 		if(wanted != SF_WRITE)
5054887Schin 		{	/* just reset the pointers */
5064887Schin 			f->mode = SF_READ|SF_LOCK;
5074887Schin 
5084887Schin 			/* see if must go with new physical location */
5094887Schin 			if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
5104887Schin 			   (addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here)
5114887Schin 			{
5124887Schin #ifdef MAP_TYPE
5134887Schin 				if((f->bits&SF_MMAP) && f->data)
5144887Schin 				{	SFMUNMAP(f,f->data,f->endb-f->data);
5154887Schin 					f->data = NIL(uchar*);
5164887Schin 				}
5174887Schin #endif
5184887Schin 				f->endb = f->endr = f->endw = f->next = f->data;
5194887Schin 				f->here = addr;
5204887Schin 			}
5214887Schin 			else
5224887Schin 			{	addr = f->here + (f->endb - f->next);
5234887Schin 				if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
5244887Schin 					goto err_notify;
5254887Schin 				f->here = addr;
5264887Schin 			}
5274887Schin 
5284887Schin 			break;
5294887Schin 		}
5304887Schin 		/* fall thru */
5314887Schin 
5324887Schin 	case SF_READ: /* switching to SF_WRITE */
5334887Schin 		if(wanted != SF_WRITE)
5344887Schin 			break;
5354887Schin 		else if(!(f->flags&SF_WRITE))
5364887Schin 			goto err_notify;
5374887Schin 		else if(f->flags&SF_STRING)
5384887Schin 		{	f->endb = f->data+f->size;
5394887Schin 			f->mode = SF_WRITE|SF_LOCK;
5404887Schin 			break;
5414887Schin 		}
5424887Schin 
5434887Schin 		/* save unread data before switching mode */
5444887Schin 		if(f->proc && _sfpmode(f,wanted) < 0)
5454887Schin 			goto err_notify;
5464887Schin 
5474887Schin 		/* reset buffer and seek pointer */
5484887Schin 		if(!(f->mode&SF_SYNCED) )
5494887Schin 		{	n = f->endb - f->next;
5504887Schin 			if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) )
5514887Schin 			{	/* reset file pointer */
5524887Schin 				addr = f->here - n;
5534887Schin 				if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
5544887Schin 					goto err_notify;
5554887Schin 				f->here = addr;
5564887Schin 			}
5574887Schin 		}
5584887Schin 
5594887Schin 		f->mode = SF_WRITE|SF_LOCK;
5604887Schin #ifdef MAP_TYPE
5614887Schin 		if(f->bits&SF_MMAP)
5624887Schin 		{	if(f->data)
5634887Schin 				SFMUNMAP(f,f->data,f->endb-f->data);
5644887Schin 			(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
5654887Schin 		}
5664887Schin #endif
5674887Schin 		if(f->data == f->tiny)
5684887Schin 		{	f->endb = f->data = f->next = NIL(uchar*);
5694887Schin 			f->size = 0;
5704887Schin 		}
5714887Schin 		else	f->endb = (f->next = f->data) + f->size;
5724887Schin 
5734887Schin 		break;
5744887Schin 
5754887Schin 	default: /* unknown case */
5764887Schin 	err_notify:
5774887Schin 		if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR)
5784887Schin 			wanted = SF_READ;
5794887Schin 
5804887Schin 		/* set errno for operations that access wrong stream type */
5814887Schin 		if(wanted != (f->mode&SF_RDWR) && f->file >= 0)
5824887Schin 			errno = EBADF;
5834887Schin 
5844887Schin 		if(_Sfnotify) /* notify application of the error */
585*8462SApril.Chin@Sun.COM 			(*_Sfnotify)(f, wanted, (void*)((long)f->file));
5864887Schin 
5874887Schin 		rv = -1;
5884887Schin 		break;
5894887Schin 	}
5904887Schin 
5914887Schin done:
5924887Schin 	SFOPEN(f,local);
5934887Schin 	return rv;
5944887Schin }
595