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