xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfsetbuf.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 #if defined(__STDPP__directive) && defined(__STDPP__hide)
234887Schin __STDPP__directive pragma pp:hide getpagesize
244887Schin #else
254887Schin #define getpagesize	______getpagesize
264887Schin #endif
274887Schin 
284887Schin #include	"sfhdr.h"
294887Schin 
304887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide)
314887Schin __STDPP__directive pragma pp:nohide getpagesize
324887Schin #else
334887Schin #undef	getpagesize
344887Schin #endif
354887Schin 
364887Schin #if _lib_getpagesize
374887Schin _BEGIN_EXTERNS_
384887Schin extern int	getpagesize _ARG_((void));
394887Schin _END_EXTERNS_
404887Schin #endif
414887Schin 
424887Schin /*	Set a (new) buffer for a stream.
434887Schin **	If size < 0, it is assigned a suitable value depending on the
444887Schin **	kind of stream. The actual buffer size allocated is dependent
454887Schin **	on how much memory is available.
464887Schin **
474887Schin **	Written by Kiem-Phong Vo.
484887Schin */
494887Schin 
504887Schin #if !_sys_stat
514887Schin struct stat
524887Schin {	int	st_mode;
534887Schin 	int	st_size;
544887Schin };
554887Schin #undef sysfstatf
564887Schin #define sysfstatf(fd,st)	(-1)
574887Schin #endif /*_sys_stat*/
584887Schin 
setlinemode()594887Schin static int setlinemode()
604887Schin {	char*			astsfio;
614887Schin 	char*			endw;
624887Schin 
634887Schin 	static int		modes = -1;
644887Schin 	static const char	sf_line[] = "SF_LINE";
654887Schin 	static const char	sf_wcwidth[] = "SF_WCWIDTH";
664887Schin 
674887Schin #define ISSEPAR(c)	((c) == ',' || (c) == ' ' || (c) == '\t')
684887Schin 	if (modes < 0)
694887Schin 	{	modes = 0;
704887Schin 		if(astsfio = getenv("_AST_SFIO_OPTIONS"))
714887Schin 		{	for(; *astsfio != 0; astsfio = endw)
724887Schin 			{	while(ISSEPAR(*astsfio) )
734887Schin 					*astsfio++;
744887Schin 				for(endw = astsfio; *endw && !ISSEPAR(*endw); ++endw)
754887Schin 					;
764887Schin 				if((endw-astsfio) == (sizeof(sf_line)-1) &&
774887Schin 				   strncmp(astsfio,sf_line,endw-astsfio) == 0)
784887Schin 				{	if ((modes |= SF_LINE) == (SF_LINE|SF_WCWIDTH))
794887Schin 						break;
804887Schin 				}
814887Schin 				else if((endw-astsfio) == (sizeof(sf_wcwidth)-1) &&
824887Schin 				   strncmp(astsfio,sf_wcwidth,endw-astsfio) == 0)
834887Schin 				{	if ((modes |= SF_WCWIDTH) == (SF_LINE|SF_WCWIDTH))
844887Schin 						break;
854887Schin 				}
864887Schin 			}
874887Schin 		}
884887Schin 	}
894887Schin 	return modes;
904887Schin }
914887Schin 
924887Schin #if __STD_C
sfsetbuf(Sfio_t * f,Void_t * buf,size_t size)938462SApril.Chin@Sun.COM Void_t* sfsetbuf(Sfio_t* f, Void_t* buf, size_t size)
944887Schin #else
954887Schin Void_t* sfsetbuf(f,buf,size)
968462SApril.Chin@Sun.COM Sfio_t*	f;	/* stream to be buffered */
978462SApril.Chin@Sun.COM Void_t*	buf;	/* new buffer */
988462SApril.Chin@Sun.COM size_t	size;	/* buffer size, -1 for default size */
994887Schin #endif
1004887Schin {
1014887Schin 	int		sf_malloc, oflags, init, okmmap, local;
1024887Schin 	ssize_t		bufsize, blksz;
1034887Schin 	Sfdisc_t*	disc;
1044887Schin 	sfstat_t	st;
1054887Schin 	uchar*		obuf = NIL(uchar*);
1064887Schin 	ssize_t		osize = 0;
1078462SApril.Chin@Sun.COM 	SFMTXDECL(f);
1084887Schin 
1094887Schin 	SFONCE();
1104887Schin 
1118462SApril.Chin@Sun.COM 	SFMTXENTER(f,NIL(Void_t*));
1124887Schin 
1134887Schin 	GETLOCAL(f,local);
1144887Schin 
1154887Schin 	if(size == 0 && buf)
1164887Schin 	{	/* special case to get buffer info */
1174887Schin 		_Sfi = f->val = (f->bits&SF_MMAP) ? (f->endb-f->data) : f->size;
1184887Schin 		SFMTXRETURN(f, (Void_t*)f->data);
1194887Schin 	}
1204887Schin 
1214887Schin 	/* cleanup actions already done, don't allow write buffering any more */
1224887Schin 	if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE))
1234887Schin 	{	buf = NIL(Void_t*);
1244887Schin 		size = 0;
1254887Schin 	}
1264887Schin 
1274887Schin 	if((init = f->mode&SF_INIT) )
1284887Schin 	{	if(!f->pool && _sfsetpool(f) < 0)
1294887Schin 			SFMTXRETURN(f, NIL(Void_t*));
1304887Schin 	}
1314887Schin 	else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0)
1324887Schin 		SFMTXRETURN(f, NIL(Void_t*));
1334887Schin 
1344887Schin 	if(init)
1354887Schin 		f->mode = (f->mode&SF_RDWR)|SF_LOCK;
1364887Schin 	else
1374887Schin 	{	int	rv;
1384887Schin 
1394887Schin 		/* make sure there is no hidden read data */
1404887Schin 		if(f->proc && (f->flags&SF_READ) && (f->mode&SF_WRITE) &&
1414887Schin 		   _sfmode(f,SF_READ,local) < 0)
1424887Schin 			SFMTXRETURN(f, NIL(Void_t*));
1434887Schin 
1444887Schin 		/* synchronize first */
1454887Schin 		SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local);
1464887Schin 		if(rv < 0)
1474887Schin 			SFMTXRETURN(f, NIL(Void_t*));
1484887Schin 
1494887Schin 		/* turn off the SF_SYNCED bit because buffer is changing */
1504887Schin 		f->mode &= ~SF_SYNCED;
1514887Schin 	}
1524887Schin 
1534887Schin 	SFLOCK(f,local);
1544887Schin 
1554887Schin 	if((Sfio_t*)buf != f)
1564887Schin 		blksz = -1;
1574887Schin 	else /* setting alignment size only */
1584887Schin 	{	blksz = (ssize_t)size;
1594887Schin 
1604887Schin 		if(!init) /* stream already initialized */
1614887Schin 		{	obuf = f->data;
1624887Schin 			osize = f->size;
1634887Schin 			goto done;
1644887Schin 		}
1654887Schin 		else /* initialize stream as if in the default case */
1664887Schin 		{	buf = NIL(Void_t*);
1674887Schin 			size = (size_t)SF_UNBOUND;
1684887Schin 		}
1694887Schin 	}
1704887Schin 
1714887Schin 	bufsize = 0;
1724887Schin 	oflags = f->flags;
1734887Schin 
1744887Schin 	/* see if memory mapping is possible (see sfwrite for SF_BOTH) */
1754887Schin 	okmmap = (buf || (f->flags&SF_STRING) || (f->flags&SF_RDWR) == SF_RDWR) ? 0 : 1;
1764887Schin 
1774887Schin 	/* save old buffer info */
1784887Schin #ifdef MAP_TYPE
1794887Schin 	if(f->bits&SF_MMAP)
1804887Schin 	{	if(f->data)
1814887Schin 		{	SFMUNMAP(f,f->data,f->endb-f->data);
1824887Schin 			f->data = NIL(uchar*);
1834887Schin 		}
1844887Schin 	} else
1854887Schin #endif
1864887Schin 	if(f->data == f->tiny)
1874887Schin 	{	f->data = NIL(uchar*);
1884887Schin 		f->size = 0;
1894887Schin 	}
1904887Schin 	obuf  = f->data;
1914887Schin 	osize = f->size;
1924887Schin 
1934887Schin 	f->flags &= ~SF_MALLOC;
1944887Schin 	f->bits  &= ~SF_MMAP;
1954887Schin 
1964887Schin 	/* pure read/string streams must have a valid string */
1974887Schin 	if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR &&
1984887Schin 	   (size == (size_t)SF_UNBOUND || !buf))
1994887Schin 		size = 0;
2004887Schin 
2014887Schin 	/* set disc to the first discipline with a seekf */
2024887Schin 	for(disc = f->disc; disc; disc = disc->disc)
2034887Schin 		if(disc->seekf)
2044887Schin 			break;
2054887Schin 
2064887Schin 	if((init || local) && !(f->flags&SF_STRING))
2074887Schin 	{	/* ASSERT(f->file >= 0) */
2084887Schin 		st.st_mode = 0;
2094887Schin 
2104887Schin 		/* if has discipline, set size by discipline if possible */
2114887Schin 		if(!_sys_stat || disc)
2124887Schin 		{	if((f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,disc)) < 0)
2134887Schin 				goto unseekable;
2144887Schin 			else
2154887Schin 			{	Sfoff_t	e;
2164887Schin 				if((e = SFSK(f,(Sfoff_t)0,SEEK_END,disc)) >= 0)
2174887Schin 					f->extent = e > f->here ? e : f->here;
2184887Schin 				(void)SFSK(f,f->here,SEEK_SET,disc);
2194887Schin 				goto setbuf;
2204887Schin 			}
2214887Schin 		}
2224887Schin 
2234887Schin 		/* get file descriptor status */
2244887Schin 		if(sysfstatf((int)f->file,&st) < 0)
2254887Schin 			f->here = -1;
2264887Schin 		else
2274887Schin 		{
2284887Schin #if _sys_stat && _stat_blksize	/* preferred io block size */
2294887Schin 			f->blksz = (size_t)st.st_blksize;
2304887Schin #endif
2314887Schin 			bufsize = 64 * 1024;
2324887Schin 			if(S_ISDIR(st.st_mode) || (Sfoff_t)st.st_size < (Sfoff_t)SF_GRAIN)
2334887Schin 				okmmap = 0;
2344887Schin 			if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2354887Schin 				f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc);
2364887Schin 			else	f->here = -1;
2374887Schin 
2384887Schin #if O_TEXT /* no memory mapping with O_TEXT because read()/write() alter data stream */
2394887Schin 			if(okmmap && f->here >= 0 &&
2404887Schin 			   (sysfcntlf((int)f->file,F_GETFL,0) & O_TEXT) )
2414887Schin 				okmmap = 0;
2424887Schin #endif
2434887Schin 		}
2444887Schin 
2454887Schin 		if(init)
2464887Schin 			f->flags |= setlinemode();
2474887Schin 
2484887Schin 		if(f->here >= 0)
2494887Schin 		{	f->extent = (Sfoff_t)st.st_size;
2504887Schin 
2514887Schin 			/* seekable std-devices are share-public by default */
2524887Schin 			if(f == sfstdin || f == sfstdout || f == sfstderr)
2534887Schin 				f->flags |= SF_SHARE|SF_PUBLIC;
2544887Schin 		}
2554887Schin 		else
2564887Schin 		{
2574887Schin 		unseekable:
2584887Schin 			f->extent = -1;
2594887Schin 			f->here = 0;
2604887Schin 
2614887Schin 			if(init)
2624887Schin 			{	if(S_ISCHR(st.st_mode) )
2634887Schin 				{	int oerrno = errno;
2644887Schin 
2654887Schin 					bufsize = SF_GRAIN;
2664887Schin 
2674887Schin 					/* set line mode for terminals */
2684887Schin 					if(!(f->flags&(SF_LINE|SF_WCWIDTH)) && isatty(f->file))
2694887Schin 						f->flags |= SF_LINE|SF_WCWIDTH;
2704887Schin #if _sys_stat
2714887Schin 					else	/* special case /dev/null */
2724887Schin 					{	reg int	dev, ino;
2734887Schin 						dev = (int)st.st_dev;
2744887Schin 						ino = (int)st.st_ino;
2754887Schin 						if(sysstatf(DEVNULL,&st) >= 0 &&
2764887Schin 						   dev == (int)st.st_dev &&
2774887Schin 						   ino == (int)st.st_ino)
2784887Schin 							SFSETNULL(f);
2794887Schin 					}
2804887Schin #endif
2814887Schin 					errno = oerrno;
2824887Schin 				}
2834887Schin 
2844887Schin 				/* initialize side buffer for r+w unseekable streams */
2854887Schin 				if(!f->proc && (f->bits&SF_BOTH) )
2864887Schin 					(void)_sfpopen(f,-1,-1,1);
2874887Schin 			}
2884887Schin 		}
2894887Schin 
2904887Schin 		/* set page size, this is also the desired default buffer size */
2914887Schin 		if(_Sfpage <= 0)
2924887Schin 		{
2934887Schin #if _lib_getpagesize
2944887Schin 			if((_Sfpage = (size_t)getpagesize()) <= 0)
2954887Schin #endif
2964887Schin 				_Sfpage = SF_PAGE;
2974887Schin 		}
2984887Schin 	}
2994887Schin 
3004887Schin #ifdef MAP_TYPE
3014887Schin 	if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 )
3024887Schin 	{	/* see if we can try memory mapping */
3034887Schin 		if(!disc)
3044887Schin 			for(disc = f->disc; disc; disc = disc->disc)
3054887Schin 				if(disc->readf)
3064887Schin 					break;
3074887Schin 		if(!disc)
3084887Schin 		{	f->bits |= SF_MMAP;
3094887Schin 			if(size == (size_t)SF_UNBOUND)
3104887Schin 			{	if(bufsize > _Sfpage)
3114887Schin 					size = bufsize * SF_NMAP;
3124887Schin 				else	size = _Sfpage * SF_NMAP;
3134887Schin 				if(size > 256*1024)
3144887Schin 					size = 256*1024;
3154887Schin 			}
3164887Schin 		}
3174887Schin 	}
3184887Schin #endif
3194887Schin 
3204887Schin 	/* get buffer space */
3214887Schin setbuf:
3224887Schin 	if(size == (size_t)SF_UNBOUND)
3234887Schin 	{	/* define a default size suitable for block transfer */
3244887Schin 		if(init && osize > 0)
3254887Schin 			size = osize;
3264887Schin 		else if(f == sfstderr && (f->mode&SF_WRITE))
3274887Schin 			size = 0;
3284887Schin 		else if(f->flags&SF_STRING )
3294887Schin 			size = SF_GRAIN;
3304887Schin 		else if((f->flags&SF_READ) && !(f->bits&SF_BOTH) &&
3314887Schin 			f->extent > 0 && f->extent < (Sfoff_t)_Sfpage )
3324887Schin 			size = (((size_t)f->extent + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
3334887Schin 		else if((ssize_t)(size = _Sfpage) < bufsize)
3344887Schin 			size = bufsize;
3354887Schin 
3364887Schin 		buf = NIL(Void_t*);
3374887Schin 	}
3384887Schin 
3394887Schin 	sf_malloc = 0;
3404887Schin 	if(size > 0 && !buf && !(f->bits&SF_MMAP))
3414887Schin 	{	/* try to allocate a buffer */
3424887Schin 		if(obuf && size == (size_t)osize && init)
3434887Schin 		{	buf = (Void_t*)obuf;
3444887Schin 			obuf = NIL(uchar*);
3454887Schin 			sf_malloc = (oflags&SF_MALLOC);
3464887Schin 		}
3474887Schin 		if(!buf)
3484887Schin 		{	/* do allocation */
3494887Schin 			while(!buf && size > 0)
3504887Schin 			{	if((buf = (Void_t*)malloc(size)) )
3514887Schin 					break;
3524887Schin 				else	size /= 2;
3534887Schin 			}
3544887Schin 			if(size > 0)
3554887Schin 				sf_malloc = SF_MALLOC;
3564887Schin 		}
3574887Schin 	}
3584887Schin 
3594887Schin 	if(size == 0 && !(f->flags&SF_STRING) && !(f->bits&SF_MMAP) && (f->mode&SF_READ))
3604887Schin 	{	/* use the internal buffer */
3614887Schin 		size = sizeof(f->tiny);
3624887Schin 		buf = (Void_t*)f->tiny;
3634887Schin 	}
3644887Schin 
3654887Schin 	/* set up new buffer */
3664887Schin 	f->size = size;
3674887Schin 	f->next = f->data = f->endr = f->endw = (uchar*)buf;
3684887Schin 	f->endb = (f->mode&SF_READ) ? f->data : f->data+size;
3694887Schin 	if(f->flags&SF_STRING)
3704887Schin 	{	/* these fields are used to test actual size - see sfseek() */
3714887Schin 		f->extent = (!sf_malloc &&
3724887Schin 			     ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ) ? size : 0;
3734887Schin 		f->here = 0;
3744887Schin 
3754887Schin 		/* read+string stream should have all data available */
3764887Schin 		if((f->mode&SF_READ) && !sf_malloc)
3774887Schin 			f->endb = f->data+size;
3784887Schin 	}
3794887Schin 
3804887Schin 	f->flags = (f->flags & ~SF_MALLOC)|sf_malloc;
3814887Schin 
3824887Schin 	if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC))
3834887Schin 	{	free((Void_t*)obuf);
3844887Schin 		obuf = NIL(uchar*);
3854887Schin 	}
3864887Schin 
3874887Schin done:
3884887Schin 	_Sfi = f->val = obuf ? osize : 0;
3894887Schin 
3904887Schin 	/* blksz is used for aligning disk block boundary while reading data to
3914887Schin 	** optimize data transfer from disk (eg, via direct I/O). blksz can be
3924887Schin 	** at most f->size/2 so that data movement in buffer can be optimized.
3934887Schin 	** blksz should also be a power-of-2 for optimal disk seeks.
3944887Schin 	*/
3954887Schin 	if(blksz <= 0 || (blksz & (blksz-1)) != 0 )
3964887Schin 		blksz = SF_GRAIN;
3974887Schin 	while(blksz > f->size/2)
3984887Schin 		blksz /= 2;
3994887Schin 	f->blksz = blksz;
4004887Schin 
4014887Schin 	SFOPEN(f,local);
4024887Schin 
4034887Schin 	SFMTXRETURN(f, (Void_t*)obuf);
4044887Schin }
405