xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfwr.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"
234887Schin 
244887Schin /*	Write with discipline.
254887Schin **
264887Schin **	Written by Kiem-Phong Vo.
274887Schin */
284887Schin 
294887Schin /* hole preserving writes */
304887Schin #if __STD_C
sfoutput(Sfio_t * f,char * buf,size_t n)318462SApril.Chin@Sun.COM static ssize_t sfoutput(Sfio_t* f, char* buf, size_t n)
324887Schin #else
334887Schin static ssize_t sfoutput(f,buf,n)
344887Schin Sfio_t*		f;
358462SApril.Chin@Sun.COM char*		buf;
368462SApril.Chin@Sun.COM size_t		n;
374887Schin #endif
384887Schin {	reg char	*sp, *wbuf, *endbuf;
394887Schin 	reg ssize_t	s, w, wr;
404887Schin 
414887Schin 	s = w = 0;
424887Schin 	wbuf = buf;
434887Schin 	endbuf = buf+n;
444887Schin 	while(n > 0)
454887Schin 	{	if((ssize_t)n < _Sfpage) /* no hole possible */
464887Schin 		{	buf += n;
474887Schin 			s = n = 0;
484887Schin 		}
494887Schin 		else while((ssize_t)n >= _Sfpage)
504887Schin 		{	/* see if a hole of 0's starts here */
514887Schin 			sp = buf+1;
524887Schin 			if(buf[0] == 0 && buf[_Sfpage-1] == 0)
534887Schin 			{	/* check byte at a time until int-aligned */
544887Schin 				while(((ulong)sp)%sizeof(int))
554887Schin 				{	if(*sp != 0)
564887Schin 						goto chk_hole;
574887Schin 					sp += 1;
584887Schin 				}
594887Schin 
604887Schin 				/* check using int to speed up */
614887Schin 				while(sp < endbuf)
624887Schin 				{	if(*((int*)sp) != 0)
634887Schin 						goto chk_hole;
644887Schin 					sp += sizeof(int);
654887Schin 				}
664887Schin 
674887Schin 				/* check the remaining bytes */
684887Schin 				if(sp > endbuf)
694887Schin 				{	sp -= sizeof(int);
704887Schin 					while(sp < endbuf)
714887Schin 					{	if(*sp != 0)
724887Schin 							goto chk_hole;
734887Schin 						sp += 1;
744887Schin 					}
754887Schin 				}
764887Schin 			}
774887Schin 
784887Schin 		chk_hole:
794887Schin 			if((s = sp-buf) >= _Sfpage) /* found a hole */
804887Schin 				break;
814887Schin 
824887Schin 			/* skip a dirty page */
834887Schin 			n -= _Sfpage;
844887Schin 			buf += _Sfpage;
854887Schin 		}
864887Schin 
874887Schin 		/* write out current dirty pages */
884887Schin 		if(buf > wbuf)
894887Schin 		{	if((ssize_t)n < _Sfpage)
904887Schin 			{	buf = endbuf;
914887Schin 				n = s = 0;
924887Schin 			}
934887Schin 			if((wr = syswritef(f->file,wbuf,buf-wbuf)) > 0)
944887Schin 			{	w += wr;
954887Schin 				f->bits &= ~SF_HOLE;
964887Schin 			}
974887Schin 			if(wr != (buf-wbuf))
984887Schin 				break;
994887Schin 			wbuf = buf;
1004887Schin 		}
1014887Schin 
1024887Schin 		/* seek to a rounded boundary within the hole */
1034887Schin 		if(s >= _Sfpage)
1044887Schin 		{	s = (s/_Sfpage)*_Sfpage;
1054887Schin 			if(SFSK(f,(Sfoff_t)s,SEEK_CUR,NIL(Sfdisc_t*)) < 0)
1064887Schin 				break;
1074887Schin 			w += s;
1084887Schin 			n -= s;
1094887Schin 			wbuf = (buf += s);
1104887Schin 			f->bits |= SF_HOLE;
1114887Schin 
1124887Schin 			if(n > 0)
1134887Schin 			{	/* next page must be dirty */
1144887Schin 				s = (ssize_t)n <= _Sfpage ? 1 : _Sfpage;
1154887Schin 				buf += s;
1164887Schin 				n -= s;
1174887Schin 			}
1184887Schin 		}
1194887Schin 	}
1204887Schin 
1214887Schin 	return w > 0 ? w : -1;
1224887Schin }
1234887Schin 
1244887Schin #if __STD_C
sfwr(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)1258462SApril.Chin@Sun.COM ssize_t sfwr(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
1264887Schin #else
1274887Schin ssize_t sfwr(f,buf,n,disc)
1288462SApril.Chin@Sun.COM Sfio_t*		f;
1298462SApril.Chin@Sun.COM Void_t*		buf;
1308462SApril.Chin@Sun.COM size_t		n;
1318462SApril.Chin@Sun.COM Sfdisc_t*	disc;
1324887Schin #endif
1334887Schin {
1344887Schin 	reg ssize_t	w;
1354887Schin 	reg Sfdisc_t*	dc;
1364887Schin 	reg int		local, oerrno;
1378462SApril.Chin@Sun.COM 	SFMTXDECL(f);
1384887Schin 
1398462SApril.Chin@Sun.COM 	SFMTXENTER(f,(ssize_t)(-1));
1404887Schin 
1414887Schin 	GETLOCAL(f,local);
1424887Schin 	if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
1434887Schin 	{	if(f->mode != SF_WRITE && _sfmode(f,SF_WRITE,0) < 0 )
1444887Schin 			SFMTXRETURN(f, (ssize_t)(-1));
1454887Schin 		if(f->next > f->data && SFSYNC(f) < 0 )
1464887Schin 			SFMTXRETURN(f, (ssize_t)(-1));
1474887Schin 	}
1484887Schin 
1494887Schin 	for(;;)
1504887Schin 	{	/* stream locked by sfsetfd() */
1514887Schin 		if(!(f->flags&SF_STRING) && f->file < 0)
1524887Schin 			SFMTXRETURN(f,(ssize_t)0);
1534887Schin 
1544887Schin 		/* clear current error states */
1554887Schin 		f->flags &= ~(SF_EOF|SF_ERROR);
1564887Schin 
1574887Schin 		dc = disc;
1584887Schin 		if(f->flags&SF_STRING)	/* total required buffer */
1594887Schin 			w = n + (f->next - f->data);
1604887Schin 		else
1614887Schin 		{	/* warn that a write is about to happen */
1624887Schin 			SFDISC(f,dc,writef);
1634887Schin 			if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
1644887Schin 			{	reg int	rv;
1654887Schin 				if(local)
1664887Schin 					SETLOCAL(f);
1674887Schin 				if((rv = _sfexcept(f,SF_WRITE,n,dc)) > 0)
1684887Schin 					n = rv;
1694887Schin 				else if(rv < 0)
1704887Schin 				{	f->flags |= SF_ERROR;
1714887Schin 					SFMTXRETURN(f, rv);
1724887Schin 				}
1734887Schin 			}
1744887Schin 
1754887Schin 			if(f->extent >= 0)
1764887Schin 			{	/* make sure we are at the right place to write */
1774887Schin 				if(f->flags&SF_APPENDWR)
1784887Schin 				{	if(f->here != f->extent || (f->flags&SF_SHARE))
1794887Schin 					{	f->here = SFSK(f,(Sfoff_t)0,SEEK_END,dc);
1804887Schin 						f->extent = f->here;
1814887Schin 					}
1824887Schin 				}
1834887Schin 				else if((f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC))
1844887Schin 					f->here = SFSK(f,f->here,SEEK_SET,dc);
1854887Schin 			}
1864887Schin 
1874887Schin 			oerrno = errno;
1884887Schin 			errno = 0;
1894887Schin 
1904887Schin 			if(dc && dc->writef)
1914887Schin 			{	SFDCWR(f,buf,n,dc,w);
1924887Schin 			}
1934887Schin 			else if(SFISNULL(f))
1944887Schin 				w = n;
1954887Schin 			else if(f->flags&SF_WHOLE)
1964887Schin 				goto do_write;
1974887Schin 			else if((ssize_t)n >= _Sfpage &&
1984887Schin 				!(f->flags&(SF_SHARE|SF_APPENDWR)) &&
1994887Schin 				f->here == f->extent && (f->here%_Sfpage) == 0)
2004887Schin 			{	if((w = sfoutput(f,(char*)buf,n)) <= 0)
2014887Schin 					goto do_write;
2024887Schin 			}
2034887Schin 			else
2044887Schin 			{
2054887Schin 			do_write:
2064887Schin 				if((w = syswritef(f->file,buf,n)) > 0)
2074887Schin 					f->bits &= ~SF_HOLE;
2084887Schin 			}
2094887Schin 
2104887Schin 			if(errno == 0)
2114887Schin 				errno = oerrno;
2124887Schin 
2134887Schin 			if(w > 0)
2144887Schin 			{	if(!(f->bits&SF_DCDOWN) )
2154887Schin 				{	if((f->flags&(SF_APPENDWR|SF_PUBLIC)) && f->extent >= 0 )
2164887Schin 						f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
2174887Schin 					else	f->here += w;
2184887Schin 					if(f->extent >= 0 && f->here > f->extent)
2194887Schin 						f->extent = f->here;
2204887Schin 				}
2214887Schin 
2224887Schin 				SFMTXRETURN(f, (ssize_t)w);
2234887Schin 			}
2244887Schin 		}
2254887Schin 
2264887Schin 		if(local)
2274887Schin 			SETLOCAL(f);
2284887Schin 		switch(_sfexcept(f,SF_WRITE,w,dc))
2294887Schin 		{
2304887Schin 		case SF_ECONT :
2314887Schin 			goto do_continue;
2324887Schin 		case SF_EDONE :
2334887Schin 			w = local ? 0 : w;
2344887Schin 			SFMTXRETURN(f, (ssize_t)w);
2354887Schin 		case SF_EDISC :
2364887Schin 			if(!local && !(f->flags&SF_STRING))
2374887Schin 				goto do_continue;
2384887Schin 			/* else fall thru */
2394887Schin 		case SF_ESTACK :
2404887Schin 			SFMTXRETURN(f, (ssize_t)(-1));
2414887Schin 		}
2424887Schin 
2434887Schin 	do_continue:
2444887Schin 		for(dc = f->disc; dc; dc = dc->disc)
2454887Schin 			if(dc == disc)
2464887Schin 				break;
2474887Schin 		disc = dc;
2484887Schin 	}
2494887Schin }
250