xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfmove.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 /*	Move data from one stream to another.
254887Schin **	This code is written so that it'll work even in the presence
264887Schin **	of stacking streams, pool, and discipline.
274887Schin **	If you must change it, be gentle.
284887Schin **
294887Schin **	Written by Kiem-Phong Vo.
304887Schin */
314887Schin #define MAX_SSIZE	((ssize_t)((~((size_t)0)) >> 1))
324887Schin 
334887Schin #if __STD_C
sfmove(Sfio_t * fr,Sfio_t * fw,Sfoff_t n,reg int rc)344887Schin Sfoff_t sfmove(Sfio_t* fr, Sfio_t* fw, Sfoff_t n, reg int rc)
354887Schin #else
364887Schin Sfoff_t sfmove(fr,fw,n,rc)
374887Schin Sfio_t*	fr;	/* moving data from this stream */
384887Schin Sfio_t*	fw;	/* moving data to this stream */
394887Schin Sfoff_t		n;	/* number of bytes/records to move. <0 for unbounded move */
404887Schin reg int		rc;	/* record separator */
414887Schin #endif
424887Schin {
434887Schin 	reg uchar	*cp, *next;
444887Schin 	reg ssize_t	r, w;
454887Schin 	reg uchar	*endb;
464887Schin 	reg int		direct;
474887Schin 	Sfoff_t		n_move, sk, cur;
484887Schin 	uchar		*rbuf = NIL(uchar*);
494887Schin 	ssize_t		rsize = 0;
508462SApril.Chin@Sun.COM 	SFMTXDECL(fr);
518462SApril.Chin@Sun.COM 	SFMTXDECL2(fw);
524887Schin 
538462SApril.Chin@Sun.COM 	SFMTXENTER(fr, (Sfoff_t)0);
544887Schin 	if(fw)
558462SApril.Chin@Sun.COM 		SFMTXBEGIN2(fw, (Sfoff_t)0);
564887Schin 
574887Schin 	for(n_move = 0; n != 0; )
584887Schin 	{
594887Schin 		if(rc >= 0) /* moving records, let sfgetr() deal with record reading */
604887Schin 		{	if(!(cp = (uchar*)sfgetr(fr,rc,0)) )
614887Schin 				n = 0;
624887Schin 			else
634887Schin 			{	r = sfvalue(fr);
644887Schin 				if(fw && (w = SFWRITE(fw, cp, r)) != r)
654887Schin 				{	if(fr->extent >= 0 )
664887Schin 						(void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
674887Schin 					if(fw->extent >= 0 && w > 0)
684887Schin 						(void)SFSEEK(fw,(Sfoff_t)(-w),SEEK_CUR);
694887Schin 					n = 0;
704887Schin 				}
714887Schin 				else
724887Schin 				{	n_move += 1;
734887Schin 					if(n > 0)
744887Schin 						n -= 1;
754887Schin 				}
764887Schin 			}
774887Schin 			continue;
784887Schin 		}
794887Schin 
804887Schin 		/* get the streams into the right mode */
814887Schin 		if(fr->mode != SF_READ && _sfmode(fr,SF_READ,0) < 0)
824887Schin 			break;
834887Schin 
844887Schin 		SFLOCK(fr,0);
854887Schin 
864887Schin 		/* flush the write buffer as necessary to make room */
874887Schin 		if(fw)
884887Schin 		{	if(fw->mode != SF_WRITE && _sfmode(fw,SF_WRITE,0) < 0 )
894887Schin 				break;
904887Schin 			SFLOCK(fw,0);
914887Schin 			if(fw->next >= fw->endb ||
924887Schin 			   (fw->next > fw->data && fr->extent < 0 &&
934887Schin 			    (fw->extent < 0 || (fw->flags&SF_SHARE)) ) )
944887Schin 				if(SFFLSBUF(fw,-1) < 0 )
954887Schin 					break;
964887Schin 		}
974887Schin 		else if((cur = SFSEEK(fr, (Sfoff_t)0, SEEK_CUR)) >= 0 )
984887Schin 		{	sk = n > 0 ? SFSEEK(fr, n, SEEK_CUR) : SFSEEK(fr, 0, SEEK_END);
994887Schin 			if(sk > cur) /* safe to skip over data in current stream */
1004887Schin 			{	n_move += sk - cur;
1014887Schin 				if(n > 0)
1024887Schin 					n -= sk - cur;
1034887Schin 				continue;
1044887Schin 			}
1054887Schin 			/* else: stream unstacking may happen below */
1064887Schin 		}
1074887Schin 
1084887Schin 		/* about to move all, set map to a large amount */
1094887Schin 		if(n < 0 && (fr->bits&SF_MMAP) && !(fr->bits&SF_MVSIZE) )
1104887Schin 		{	SFMVSET(fr);
1114887Schin 			fr->bits |= SF_SEQUENTIAL; /* sequentially access data */
1124887Schin 		}
1134887Schin 
1144887Schin 		/* try reading a block of data */
1154887Schin 		direct = 0;
1164887Schin 		if((r = fr->endb - (next = fr->next)) <= 0)
1174887Schin 		{	/* amount of data remained to be read */
1184887Schin 			if((w = n > MAX_SSIZE ? MAX_SSIZE : (ssize_t)n) < 0)
1194887Schin 			{	if(fr->extent < 0)
1204887Schin 					w = fr->data == fr->tiny ? SF_GRAIN : fr->size;
1214887Schin 				else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE)
1224887Schin 					w = SF_NMAP*SF_PAGE;
1234887Schin 				else	w = (ssize_t)(fr->extent-fr->here);
1244887Schin 			}
1254887Schin 
1264887Schin 			/* use a decent buffer for data transfer but make sure
1274887Schin 			   that if we overread, the left over can be retrieved
1284887Schin 			*/
1294887Schin 			if(!(fr->flags&SF_STRING) && !(fr->bits&SF_MMAP) &&
1304887Schin 			   (n < 0 || fr->extent >= 0) )
1314887Schin 			{	reg ssize_t maxw = 4*(_Sfpage > 0 ? _Sfpage : SF_PAGE);
1324887Schin 
1334887Schin 				/* direct transfer to a seekable write stream */
1344887Schin 				if(fw && fw->extent >= 0 && w <= (fw->endb-fw->next) )
1354887Schin 				{	w = fw->endb - (next = fw->next);
1364887Schin 					direct = SF_WRITE;
1374887Schin 				}
1384887Schin 				else if(w > fr->size && maxw > fr->size)
1394887Schin 				{	/* making our own buffer */
1404887Schin 					if(w >= maxw)
1414887Schin 						w = maxw;
1424887Schin 					else	w = ((w+fr->size-1)/fr->size)*fr->size;
1434887Schin 					if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) )
1444887Schin 						rsize = w;
1454887Schin 					if(rbuf)
1464887Schin 					{	next = rbuf;
1474887Schin 						w = rsize;
1484887Schin 						direct = SF_STRING;
1494887Schin 					}
1504887Schin 				}
1514887Schin 			}
1524887Schin 
1534887Schin 			if(!direct)
1544887Schin 			{	/* make sure we don't read too far ahead */
1554887Schin 				if(n > 0 && fr->extent < 0 && (fr->flags&SF_SHARE) )
1564887Schin 				{	if((Sfoff_t)(r = fr->size) > n)
1574887Schin 						r = (ssize_t)n;
1584887Schin 				}
1594887Schin 				else	r = -1;
1604887Schin 				if((r = SFFILBUF(fr,r)) <= 0)
1614887Schin 					break;
1624887Schin 				next = fr->next;
1634887Schin 			}
1644887Schin 			else
1654887Schin 			{	/* actual amount to be read */
1664887Schin 				if(n > 0 && n < w)
1674887Schin 					w = (ssize_t)n;
1684887Schin 
1694887Schin 				if((r = SFRD(fr,next,w,fr->disc)) > 0)
1704887Schin 					fr->next = fr->endb = fr->endr = fr->data;
1714887Schin 				else if(r == 0)
1724887Schin 					break;		/* eof */
1734887Schin 				else	goto again;	/* popped stack */
1744887Schin 			}
1754887Schin 		}
1764887Schin 
1774887Schin 		/* compute the extent of data to be moved */
1784887Schin 		endb = next+r;
1794887Schin 		if(n > 0)
1804887Schin 		{	if(r > n)
1814887Schin 				r = (ssize_t)n;
1824887Schin 			n -= r;
1834887Schin 		}
1844887Schin 		n_move += r;
1854887Schin 		cp = next+r;
1864887Schin 
1874887Schin 		if(!direct)
1884887Schin 			fr->next += r;
1894887Schin 		else if((w = endb-cp) > 0)
1904887Schin 		{	/* move left-over to read stream */
1914887Schin 			if(w > fr->size)
1924887Schin 				w = fr->size;
1934887Schin 			memcpy((Void_t*)fr->data,(Void_t*)cp,w);
1944887Schin 			fr->endb = fr->data+w;
1954887Schin 			if((w = endb - (cp+w)) > 0)
1964887Schin 				(void)SFSK(fr,(Sfoff_t)(-w),SEEK_CUR,fr->disc);
1974887Schin 		}
1984887Schin 
1994887Schin 		if(fw)
2004887Schin 		{	if(direct == SF_WRITE)
2014887Schin 				fw->next += r;
2024887Schin 			else if(r <= (fw->endb-fw->next) )
2034887Schin 			{	memcpy((Void_t*)fw->next,(Void_t*)next,r);
2044887Schin 				fw->next += r;
2054887Schin 			}
2064887Schin 			else if((w = SFWRITE(fw,(Void_t*)next,r)) != r)
2074887Schin 			{	/* a write error happened */
2084887Schin 				if(w > 0)
2094887Schin 				{	r -= w;
2104887Schin 					n_move -= r;
2114887Schin 				}
2124887Schin 				if(fr->extent >= 0)
2134887Schin 					(void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
2144887Schin 				break;
2154887Schin 			}
2164887Schin 		}
2174887Schin 
2184887Schin 	again:
2194887Schin 		SFOPEN(fr,0);
2204887Schin 		if(fw)
2214887Schin 			SFOPEN(fw,0);
2224887Schin 	}
2234887Schin 
2244887Schin 	if(n < 0 && (fr->bits&SF_MMAP) && (fr->bits&SF_MVSIZE))
2254887Schin 	{	/* back to normal access mode */
2264887Schin 		SFMVUNSET(fr);
2274887Schin 		if((fr->bits&SF_SEQUENTIAL) && (fr->data))
2284887Schin 			SFMMSEQOFF(fr,fr->data,fr->endb-fr->data);
2294887Schin 		fr->bits &= ~SF_SEQUENTIAL;
2304887Schin 	}
2314887Schin 
2324887Schin 	if(rbuf)
2334887Schin 		free(rbuf);
2344887Schin 
2354887Schin 	if(fw)
2364887Schin 	{	SFOPEN(fw,0);
2378462SApril.Chin@Sun.COM 		SFMTXEND2(fw);
2384887Schin 	}
2394887Schin 
2408462SApril.Chin@Sun.COM 	SFOPEN(fr,0);
2414887Schin 	SFMTXRETURN(fr, n_move);
2424887Schin }
243